| author | |
| committer | |
| log | f32f7a937fa7150aaba450b1282bba9f01918807 |
| tree | ecb462e15546a50b2e948b8f2907872dd39a2dc6 |
| parent | 1411df4e2705e677003e6e5b5cbe1ca30bf637d7 |
| parent | 8c6fa982cd0a02775264b616c37da9907cc603bb |
| signature |
234 files changed, 13794 insertions(+), 10517 deletions(-)
.builds/freebsd.yml+8-8| ... | @@ -12,28 +12,28 @@ tasks: | ... | @@ -12,28 +12,28 @@ tasks: |
| 12 | ninja install | 12 | ninja install |
| 13 | - test: | | 13 | - test: | |
| 14 | cd zig/build | 14 | cd zig/build |
| 15 | bin/zig test ../test/behavior.zig | 15 | bin/zig test ../test/stage1/behavior.zig |
| 16 | bin/zig test ../std/special/compiler_rt/index.zig | 16 | bin/zig test ../std/special/compiler_rt/index.zig |
| 17 | 17 | ||
| 18 | bin/zig test ../test/behavior.zig --library c | 18 | bin/zig test ../test/stage1/behavior.zig --library c |
| 19 | bin/zig test ../std/special/compiler_rt/index.zig --library c | 19 | bin/zig test ../std/special/compiler_rt/index.zig --library c |
| 20 | 20 | ||
| 21 | bin/zig test ../test/behavior.zig --release-fast | 21 | bin/zig test ../test/stage1/behavior.zig --release-fast |
| 22 | bin/zig test ../std/special/compiler_rt/index.zig --release-fast | 22 | bin/zig test ../std/special/compiler_rt/index.zig --release-fast |
| 23 | 23 | ||
| 24 | bin/zig test ../test/behavior.zig --release-fast --library c | 24 | bin/zig test ../test/stage1/behavior.zig --release-fast --library c |
| 25 | bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c | 25 | bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c |
| 26 | 26 | ||
| 27 | bin/zig test ../test/behavior.zig --release-small --library c | 27 | bin/zig test ../test/stage1/behavior.zig --release-small --library c |
| 28 | bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c | 28 | bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c |
| 29 | 29 | ||
| 30 | bin/zig test ../test/behavior.zig --release-small | 30 | bin/zig test ../test/stage1/behavior.zig --release-small |
| 31 | bin/zig test ../std/special/compiler_rt/index.zig --release-small | 31 | bin/zig test ../std/special/compiler_rt/index.zig --release-small |
| 32 | 32 | ||
| 33 | bin/zig test ../test/behavior.zig --release-safe | 33 | bin/zig test ../test/stage1/behavior.zig --release-safe |
| 34 | bin/zig test ../std/special/compiler_rt/index.zig --release-safe | 34 | bin/zig test ../std/special/compiler_rt/index.zig --release-safe |
| 35 | 35 | ||
| 36 | bin/zig test ../test/behavior.zig --release-safe --library c | 36 | bin/zig test ../test/stage1/behavior.zig --release-safe --library c |
| 37 | bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c | 37 | bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c |
| 38 | # TODO enable all tests | 38 | # TODO enable all tests |
| 39 | #bin/zig build --build-file ../build.zig test | 39 | #bin/zig build --build-file ../build.zig test |
CMakeLists.txt+16-15| ... | @@ -454,10 +454,10 @@ set(ZIG_STD_FILES | ... | @@ -454,10 +454,10 @@ set(ZIG_STD_FILES |
| 454 | "crypto/hmac.zig" | 454 | "crypto/hmac.zig" |
| 455 | "crypto/index.zig" | 455 | "crypto/index.zig" |
| 456 | "crypto/md5.zig" | 456 | "crypto/md5.zig" |
| 457 | "crypto/poly1305.zig" | ||
| 457 | "crypto/sha1.zig" | 458 | "crypto/sha1.zig" |
| 458 | "crypto/sha2.zig" | 459 | "crypto/sha2.zig" |
| 459 | "crypto/sha3.zig" | 460 | "crypto/sha3.zig" |
| 460 | "crypto/poly1305.zig" | ||
| 461 | "crypto/x25519.zig" | 461 | "crypto/x25519.zig" |
| 462 | "cstr.zig" | 462 | "cstr.zig" |
| 463 | "debug/failing_allocator.zig" | 463 | "debug/failing_allocator.zig" |
| ... | @@ -566,9 +566,9 @@ set(ZIG_STD_FILES | ... | @@ -566,9 +566,9 @@ set(ZIG_STD_FILES |
| 566 | "math/tan.zig" | 566 | "math/tan.zig" |
| 567 | "math/tanh.zig" | 567 | "math/tanh.zig" |
| 568 | "math/trunc.zig" | 568 | "math/trunc.zig" |
| 569 | "mem.zig" | ||
| 569 | "meta/index.zig" | 570 | "meta/index.zig" |
| 570 | "meta/trait.zig" | 571 | "meta/trait.zig" |
| 571 | "mem.zig" | ||
| 572 | "mutex.zig" | 572 | "mutex.zig" |
| 573 | "net.zig" | 573 | "net.zig" |
| 574 | "os/child_process.zig" | 574 | "os/child_process.zig" |
| ... | @@ -576,16 +576,16 @@ set(ZIG_STD_FILES | ... | @@ -576,16 +576,16 @@ set(ZIG_STD_FILES |
| 576 | "os/darwin/errno.zig" | 576 | "os/darwin/errno.zig" |
| 577 | "os/epoch.zig" | 577 | "os/epoch.zig" |
| 578 | "os/file.zig" | 578 | "os/file.zig" |
| 579 | "os/freebsd/errno.zig" | ||
| 580 | "os/freebsd/index.zig" | ||
| 579 | "os/get_app_data_dir.zig" | 581 | "os/get_app_data_dir.zig" |
| 580 | "os/get_user_id.zig" | 582 | "os/get_user_id.zig" |
| 581 | "os/index.zig" | 583 | "os/index.zig" |
| 584 | "os/linux/arm64.zig" | ||
| 582 | "os/linux/errno.zig" | 585 | "os/linux/errno.zig" |
| 583 | "os/linux/index.zig" | 586 | "os/linux/index.zig" |
| 584 | "os/linux/vdso.zig" | 587 | "os/linux/vdso.zig" |
| 585 | "os/linux/x86_64.zig" | 588 | "os/linux/x86_64.zig" |
| 586 | "os/linux/arm64.zig" | ||
| 587 | "os/freebsd/errno.zig" | ||
| 588 | "os/freebsd/index.zig" | ||
| 589 | "os/path.zig" | 589 | "os/path.zig" |
| 590 | "os/time.zig" | 590 | "os/time.zig" |
| 591 | "os/uefi.zig" | 591 | "os/uefi.zig" |
| ... | @@ -612,6 +612,16 @@ set(ZIG_STD_FILES | ... | @@ -612,6 +612,16 @@ set(ZIG_STD_FILES |
| 612 | "special/compiler_rt/comparetf2.zig" | 612 | "special/compiler_rt/comparetf2.zig" |
| 613 | "special/compiler_rt/divti3.zig" | 613 | "special/compiler_rt/divti3.zig" |
| 614 | "special/compiler_rt/extendXfYf2.zig" | 614 | "special/compiler_rt/extendXfYf2.zig" |
| 615 | "special/compiler_rt/fixdfdi.zig" | ||
| 616 | "special/compiler_rt/fixdfsi.zig" | ||
| 617 | "special/compiler_rt/fixdfti.zig" | ||
| 618 | "special/compiler_rt/fixint.zig" | ||
| 619 | "special/compiler_rt/fixsfdi.zig" | ||
| 620 | "special/compiler_rt/fixsfsi.zig" | ||
| 621 | "special/compiler_rt/fixsfti.zig" | ||
| 622 | "special/compiler_rt/fixtfdi.zig" | ||
| 623 | "special/compiler_rt/fixtfsi.zig" | ||
| 624 | "special/compiler_rt/fixtfti.zig" | ||
| 615 | "special/compiler_rt/fixuint.zig" | 625 | "special/compiler_rt/fixuint.zig" |
| 616 | "special/compiler_rt/fixunsdfdi.zig" | 626 | "special/compiler_rt/fixunsdfdi.zig" |
| 617 | "special/compiler_rt/fixunsdfsi.zig" | 627 | "special/compiler_rt/fixunsdfsi.zig" |
| ... | @@ -622,16 +632,6 @@ set(ZIG_STD_FILES | ... | @@ -622,16 +632,6 @@ set(ZIG_STD_FILES |
| 622 | "special/compiler_rt/fixunstfdi.zig" | 632 | "special/compiler_rt/fixunstfdi.zig" |
| 623 | "special/compiler_rt/fixunstfsi.zig" | 633 | "special/compiler_rt/fixunstfsi.zig" |
| 624 | "special/compiler_rt/fixunstfti.zig" | 634 | "special/compiler_rt/fixunstfti.zig" |
| 625 | "special/compiler_rt/fixint.zig" | ||
| 626 | "special/compiler_rt/fixdfdi.zig" | ||
| 627 | "special/compiler_rt/fixdfsi.zig" | ||
| 628 | "special/compiler_rt/fixdfti.zig" | ||
| 629 | "special/compiler_rt/fixsfdi.zig" | ||
| 630 | "special/compiler_rt/fixsfsi.zig" | ||
| 631 | "special/compiler_rt/fixsfti.zig" | ||
| 632 | "special/compiler_rt/fixtfdi.zig" | ||
| 633 | "special/compiler_rt/fixtfsi.zig" | ||
| 634 | "special/compiler_rt/fixtfti.zig" | ||
| 635 | "special/compiler_rt/floattidf.zig" | 635 | "special/compiler_rt/floattidf.zig" |
| 636 | "special/compiler_rt/floattisf.zig" | 636 | "special/compiler_rt/floattisf.zig" |
| 637 | "special/compiler_rt/floattitf.zig" | 637 | "special/compiler_rt/floattitf.zig" |
| ... | @@ -656,6 +656,7 @@ set(ZIG_STD_FILES | ... | @@ -656,6 +656,7 @@ set(ZIG_STD_FILES |
| 656 | "special/panic.zig" | 656 | "special/panic.zig" |
| 657 | "special/test_runner.zig" | 657 | "special/test_runner.zig" |
| 658 | "spinlock.zig" | 658 | "spinlock.zig" |
| 659 | "statically_initialized_mutex.zig" | ||
| 659 | "unicode.zig" | 660 | "unicode.zig" |
| 660 | "zig/ast.zig" | 661 | "zig/ast.zig" |
| 661 | "zig/index.zig" | 662 | "zig/index.zig" |
build.zig+10-11| ... | @@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void { |
| 104 | } | 104 | } |
| 105 | const modes = chosen_modes[0..chosen_mode_index]; | 105 | const modes = chosen_modes[0..chosen_mode_index]; |
| 106 | 106 | ||
| 107 | test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes)); | 107 | test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes)); |
| 108 | 108 | ||
| 109 | test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes)); | 109 | test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes)); |
| 110 | 110 | ||
| ... | @@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { | ... | @@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 189 | const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" }); | 189 | const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" }); |
| 190 | 190 | ||
| 191 | var result = LibraryDep{ | 191 | var result = LibraryDep{ |
| 192 | .prefix = mem.split(prefix_output, " \r\n").next().?, | 192 | .prefix = mem.tokenize(prefix_output, " \r\n").next().?, |
| 193 | .libs = ArrayList([]const u8).init(b.allocator), | 193 | .libs = ArrayList([]const u8).init(b.allocator), |
| 194 | .system_libs = ArrayList([]const u8).init(b.allocator), | 194 | .system_libs = ArrayList([]const u8).init(b.allocator), |
| 195 | .includes = ArrayList([]const u8).init(b.allocator), | 195 | .includes = ArrayList([]const u8).init(b.allocator), |
| 196 | .libdirs = ArrayList([]const u8).init(b.allocator), | 196 | .libdirs = ArrayList([]const u8).init(b.allocator), |
| 197 | }; | 197 | }; |
| 198 | { | 198 | { |
| 199 | var it = mem.split(libs_output, " \r\n"); | 199 | var it = mem.tokenize(libs_output, " \r\n"); |
| 200 | while (it.next()) |lib_arg| { | 200 | while (it.next()) |lib_arg| { |
| 201 | if (mem.startsWith(u8, lib_arg, "-l")) { | 201 | if (mem.startsWith(u8, lib_arg, "-l")) { |
| 202 | try result.system_libs.append(lib_arg[2..]); | 202 | try result.system_libs.append(lib_arg[2..]); |
| ... | @@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { | ... | @@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | { | 212 | { |
| 213 | var it = mem.split(includes_output, " \r\n"); | 213 | var it = mem.tokenize(includes_output, " \r\n"); |
| 214 | while (it.next()) |include_arg| { | 214 | while (it.next()) |include_arg| { |
| 215 | if (mem.startsWith(u8, include_arg, "-I")) { | 215 | if (mem.startsWith(u8, include_arg, "-I")) { |
| 216 | try result.includes.append(include_arg[2..]); | 216 | try result.includes.append(include_arg[2..]); |
| ... | @@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { | ... | @@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 220 | } | 220 | } |
| 221 | } | 221 | } |
| 222 | { | 222 | { |
| 223 | var it = mem.split(libdir_output, " \r\n"); | 223 | var it = mem.tokenize(libdir_output, " \r\n"); |
| 224 | while (it.next()) |libdir| { | 224 | while (it.next()) |libdir| { |
| 225 | if (mem.startsWith(u8, libdir, "-L")) { | 225 | if (mem.startsWith(u8, libdir, "-L")) { |
| 226 | try result.libdirs.append(libdir[2..]); | 226 | try result.libdirs.append(libdir[2..]); |
| ... | @@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { | ... | @@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { | 235 | pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { |
| 236 | var it = mem.split(stdlib_files, ";"); | 236 | var it = mem.tokenize(stdlib_files, ";"); |
| 237 | while (it.next()) |stdlib_file| { | 237 | while (it.next()) |stdlib_file| { |
| 238 | const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable; | 238 | const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable; |
| 239 | const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable; | 239 | const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable; |
| ... | @@ -242,7 +242,7 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { | ... | @@ -242,7 +242,7 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { | 244 | pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { |
| 245 | var it = mem.split(c_header_files, ";"); | 245 | var it = mem.tokenize(c_header_files, ";"); |
| 246 | while (it.next()) |c_header_file| { | 246 | while (it.next()) |c_header_file| { |
| 247 | const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable; | 247 | const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable; |
| 248 | const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable; | 248 | const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable; |
| ... | @@ -277,7 +277,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { | ... | @@ -277,7 +277,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 277 | addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp"); | 277 | addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp"); |
| 278 | if (ctx.lld_include_dir.len != 0) { | 278 | if (ctx.lld_include_dir.len != 0) { |
| 279 | exe.addIncludeDir(ctx.lld_include_dir); | 279 | exe.addIncludeDir(ctx.lld_include_dir); |
| 280 | var it = mem.split(ctx.lld_libraries, ";"); | 280 | var it = mem.tokenize(ctx.lld_libraries, ";"); |
| 281 | while (it.next()) |lib| { | 281 | while (it.next()) |lib| { |
| 282 | exe.addObjectFile(lib); | 282 | exe.addObjectFile(lib); |
| 283 | } | 283 | } |
| ... | @@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { | ... | @@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 299 | } else if (exe.target.isFreeBSD()) { | 299 | } else if (exe.target.isFreeBSD()) { |
| 300 | try addCxxKnownPath(b, ctx, exe, "libc++.a", null); | 300 | try addCxxKnownPath(b, ctx, exe, "libc++.a", null); |
| 301 | exe.linkSystemLibrary("pthread"); | 301 | exe.linkSystemLibrary("pthread"); |
| 302 | } | 302 | } else if (exe.target.isDarwin()) { |
| 303 | else if (exe.target.isDarwin()) { | ||
| 304 | if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { | 303 | if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { |
| 305 | // Compiler is GCC. | 304 | // Compiler is GCC. |
| 306 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); | 305 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); |
| ... | @@ -335,7 +334,7 @@ fn addCxxKnownPath( | ... | @@ -335,7 +334,7 @@ fn addCxxKnownPath( |
| 335 | ctx.cxx_compiler, | 334 | ctx.cxx_compiler, |
| 336 | b.fmt("-print-file-name={}", objname), | 335 | b.fmt("-print-file-name={}", objname), |
| 337 | }); | 336 | }); |
| 338 | const path_unpadded = mem.split(path_padded, "\r\n").next().?; | 337 | const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?; |
| 339 | if (mem.eql(u8, path_unpadded, objname)) { | 338 | if (mem.eql(u8, path_unpadded, objname)) { |
| 340 | if (errtxt) |msg| { | 339 | if (errtxt) |msg| { |
| 341 | warn("{}", msg); | 340 | warn("{}", msg); |
doc/langref.html.in+60-6| ... | @@ -1531,6 +1531,29 @@ test "array initialization with function calls" { | ... | @@ -1531,6 +1531,29 @@ test "array initialization with function calls" { |
| 1531 | {#code_end#} | 1531 | {#code_end#} |
| 1532 | {#see_also|for|Slices#} | 1532 | {#see_also|for|Slices#} |
| 1533 | {#header_close#} | 1533 | {#header_close#} |
| 1534 | |||
| 1535 | {#header_open|Vectors#} | ||
| 1536 | <p> | ||
| 1537 | A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on | ||
| 1538 | in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin | ||
| 1539 | function {#link|@Vector#}. | ||
| 1540 | </p> | ||
| 1541 | <p> | ||
| 1542 | TODO talk about C ABI interop | ||
| 1543 | </p> | ||
| 1544 | {#header_open|SIMD#} | ||
| 1545 | <p> | ||
| 1546 | TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the | ||
| 1547 | docs with: | ||
| 1548 | * What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector? | ||
| 1549 | * How to convert to/from vectors/arrays | ||
| 1550 | * How to access individual elements from vectors, how to loop over the elements | ||
| 1551 | * "shuffle" | ||
| 1552 | * Advice on writing high perf software, how to abstract the best way | ||
| 1553 | </p> | ||
| 1554 | {#header_close#} | ||
| 1555 | {#header_close#} | ||
| 1556 | |||
| 1534 | {#header_open|Pointers#} | 1557 | {#header_open|Pointers#} |
| 1535 | <p> | 1558 | <p> |
| 1536 | Zig has two kinds of pointers: | 1559 | Zig has two kinds of pointers: |
| ... | @@ -4327,7 +4350,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 { | ... | @@ -4327,7 +4350,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 { |
| 4327 | <p> | 4350 | <p> |
| 4328 | For example, if we were to introduce another function to the above snippet: | 4351 | For example, if we were to introduce another function to the above snippet: |
| 4329 | </p> | 4352 | </p> |
| 4330 | {#code_begin|test_err|unable to evaluate constant expression#} | 4353 | {#code_begin|test_err|values of type 'type' must be comptime known#} |
| 4331 | fn max(comptime T: type, a: T, b: T) T { | 4354 | fn max(comptime T: type, a: T, b: T) T { |
| 4332 | return if (a > b) a else b; | 4355 | return if (a > b) a else b; |
| 4333 | } | 4356 | } |
| ... | @@ -5905,13 +5928,13 @@ fn add(a: i32, b: i32) i32 { return a + b; } | ... | @@ -5905,13 +5928,13 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 5905 | This function is a low level intrinsic with no safety mechanisms. Most code | 5928 | This function is a low level intrinsic with no safety mechanisms. Most code |
| 5906 | should not use this function, instead using something like this: | 5929 | should not use this function, instead using something like this: |
| 5907 | </p> | 5930 | </p> |
| 5908 | <pre>{#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre> | 5931 | <pre>{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre> |
| 5909 | <p> | 5932 | <p> |
| 5910 | The optimizer is intelligent enough to turn the above snippet into a memcpy. | 5933 | The optimizer is intelligent enough to turn the above snippet into a memcpy. |
| 5911 | </p> | 5934 | </p> |
| 5912 | <p>There is also a standard library function for this:</p> | 5935 | <p>There is also a standard library function for this:</p> |
| 5913 | <pre>{#syntax#}const mem = @import("std").mem; | 5936 | <pre>{#syntax#}const mem = @import("std").mem; |
| 5914 | mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre> | 5937 | mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre> |
| 5915 | {#header_close#} | 5938 | {#header_close#} |
| 5916 | 5939 | ||
| 5917 | {#header_open|@memset#} | 5940 | {#header_open|@memset#} |
| ... | @@ -5923,7 +5946,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre> | ... | @@ -5923,7 +5946,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre> |
| 5923 | This function is a low level intrinsic with no safety mechanisms. Most | 5946 | This function is a low level intrinsic with no safety mechanisms. Most |
| 5924 | code should not use this function, instead using something like this: | 5947 | code should not use this function, instead using something like this: |
| 5925 | </p> | 5948 | </p> |
| 5926 | <pre>{#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}</pre> | 5949 | <pre>{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}</pre> |
| 5927 | <p> | 5950 | <p> |
| 5928 | The optimizer is intelligent enough to turn the above snippet into a memset. | 5951 | The optimizer is intelligent enough to turn the above snippet into a memset. |
| 5929 | </p> | 5952 | </p> |
| ... | @@ -6592,9 +6615,10 @@ pub const TypeInfo = union(TypeId) { | ... | @@ -6592,9 +6615,10 @@ pub const TypeInfo = union(TypeId) { |
| 6592 | {#header_close#} | 6615 | {#header_close#} |
| 6593 | 6616 | ||
| 6594 | {#header_open|@typeName#} | 6617 | {#header_open|@typeName#} |
| 6595 | <pre>{#syntax#}@typeName(T: type) []u8{#endsyntax#}</pre> | 6618 | <pre>{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}</pre> |
| 6596 | <p> | 6619 | <p> |
| 6597 | This function returns the string representation of a type. | 6620 | This function returns the string representation of a type, as |
| 6621 | an array. It is equivalent to a string literal of the type name. | ||
| 6598 | </p> | 6622 | </p> |
| 6599 | 6623 | ||
| 6600 | {#header_close#} | 6624 | {#header_close#} |
| ... | @@ -6606,6 +6630,17 @@ pub const TypeInfo = union(TypeId) { | ... | @@ -6606,6 +6630,17 @@ pub const TypeInfo = union(TypeId) { |
| 6606 | expression passed as an argument. The expression is evaluated. | 6630 | expression passed as an argument. The expression is evaluated. |
| 6607 | </p> | 6631 | </p> |
| 6608 | 6632 | ||
| 6633 | {#header_close#} | ||
| 6634 | |||
| 6635 | {#header_open|@Vector#} | ||
| 6636 | <pre>{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}</pre> | ||
| 6637 | <p> | ||
| 6638 | This function returns a vector type for {#link|SIMD#}. | ||
| 6639 | </p> | ||
| 6640 | <p> | ||
| 6641 | {#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a | ||
| 6642 | {#link|pointer|Pointers#}. | ||
| 6643 | </p> | ||
| 6609 | {#header_close#} | 6644 | {#header_close#} |
| 6610 | {#header_close#} | 6645 | {#header_close#} |
| 6611 | 6646 | ||
| ... | @@ -6679,6 +6714,25 @@ pub fn build(b: *Builder) void { | ... | @@ -6679,6 +6714,25 @@ pub fn build(b: *Builder) void { |
| 6679 | {#header_close#} | 6714 | {#header_close#} |
| 6680 | {#see_also|Compile Variables|Zig Build System|Undefined Behavior#} | 6715 | {#see_also|Compile Variables|Zig Build System|Undefined Behavior#} |
| 6681 | {#header_close#} | 6716 | {#header_close#} |
| 6717 | |||
| 6718 | {#header_open|Single Threaded Builds#} | ||
| 6719 | <p>Zig has a compile option <code>--single-threaded</code> which has the following effects: | ||
| 6720 | <ul> | ||
| 6721 | <li>{#link|@atomicLoad#} is emitted as a normal load.</li> | ||
| 6722 | <li>{#link|@atomicRmw#} is emitted as a normal memory load, modify, store.</li> | ||
| 6723 | <li>{#link|@fence#} becomes a no-op.</li> | ||
| 6724 | <li>Variables which have Thread Local Storage instead become globals. TODO thread local variables | ||
| 6725 | are not implemented yet.</li> | ||
| 6726 | <li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead. | ||
| 6727 | TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li> | ||
| 6728 | <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#} | ||
| 6729 | and therefore various userland APIs which read this variable become more efficient. | ||
| 6730 | For example {#syntax#}std.Mutex{#endsyntax#} becomes | ||
| 6731 | an empty data structure and all of its functions become no-ops.</li> | ||
| 6732 | </ul> | ||
| 6733 | </p> | ||
| 6734 | {#header_close#} | ||
| 6735 | |||
| 6682 | {#header_open|Undefined Behavior#} | 6736 | {#header_open|Undefined Behavior#} |
| 6683 | <p> | 6737 | <p> |
| 6684 | Zig has many instances of undefined behavior. If undefined behavior is | 6738 | Zig has many instances of undefined behavior. If undefined behavior is |
src-self-hosted/compilation.zig+43-29| ... | @@ -83,10 +83,11 @@ pub const ZigCompiler = struct { | ... | @@ -83,10 +83,11 @@ pub const ZigCompiler = struct { |
| 83 | const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; | 83 | const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; |
| 84 | errdefer c.LLVMContextDispose(context_ref); | 84 | errdefer c.LLVMContextDispose(context_ref); |
| 85 | 85 | ||
| 86 | const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{ | 86 | const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node); |
| 87 | node.* = std.atomic.Stack(llvm.ContextRef).Node{ | ||
| 87 | .next = undefined, | 88 | .next = undefined, |
| 88 | .data = context_ref, | 89 | .data = context_ref, |
| 89 | }); | 90 | }; |
| 90 | errdefer self.loop.allocator.destroy(node); | 91 | errdefer self.loop.allocator.destroy(node); |
| 91 | 92 | ||
| 92 | return LlvmHandle{ .node = node }; | 93 | return LlvmHandle{ .node = node }; |
| ... | @@ -596,7 +597,8 @@ pub const Compilation = struct { | ... | @@ -596,7 +597,8 @@ pub const Compilation = struct { |
| 596 | } | 597 | } |
| 597 | 598 | ||
| 598 | fn initTypes(comp: *Compilation) !void { | 599 | fn initTypes(comp: *Compilation) !void { |
| 599 | comp.meta_type = try comp.arena().create(Type.MetaType{ | 600 | comp.meta_type = try comp.arena().create(Type.MetaType); |
| 601 | comp.meta_type.* = Type.MetaType{ | ||
| 600 | .base = Type{ | 602 | .base = Type{ |
| 601 | .name = "type", | 603 | .name = "type", |
| 602 | .base = Value{ | 604 | .base = Value{ |
| ... | @@ -608,12 +610,13 @@ pub const Compilation = struct { | ... | @@ -608,12 +610,13 @@ pub const Compilation = struct { |
| 608 | .abi_alignment = Type.AbiAlignment.init(comp.loop), | 610 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 609 | }, | 611 | }, |
| 610 | .value = undefined, | 612 | .value = undefined, |
| 611 | }); | 613 | }; |
| 612 | comp.meta_type.value = &comp.meta_type.base; | 614 | comp.meta_type.value = &comp.meta_type.base; |
| 613 | comp.meta_type.base.base.typ = &comp.meta_type.base; | 615 | comp.meta_type.base.base.typ = &comp.meta_type.base; |
| 614 | assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null); | 616 | assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null); |
| 615 | 617 | ||
| 616 | comp.void_type = try comp.arena().create(Type.Void{ | 618 | comp.void_type = try comp.arena().create(Type.Void); |
| 619 | comp.void_type.* = Type.Void{ | ||
| 617 | .base = Type{ | 620 | .base = Type{ |
| 618 | .name = "void", | 621 | .name = "void", |
| 619 | .base = Value{ | 622 | .base = Value{ |
| ... | @@ -624,10 +627,11 @@ pub const Compilation = struct { | ... | @@ -624,10 +627,11 @@ pub const Compilation = struct { |
| 624 | .id = builtin.TypeId.Void, | 627 | .id = builtin.TypeId.Void, |
| 625 | .abi_alignment = Type.AbiAlignment.init(comp.loop), | 628 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 626 | }, | 629 | }, |
| 627 | }); | 630 | }; |
| 628 | assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null); | 631 | assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null); |
| 629 | 632 | ||
| 630 | comp.noreturn_type = try comp.arena().create(Type.NoReturn{ | 633 | comp.noreturn_type = try comp.arena().create(Type.NoReturn); |
| 634 | comp.noreturn_type.* = Type.NoReturn{ | ||
| 631 | .base = Type{ | 635 | .base = Type{ |
| 632 | .name = "noreturn", | 636 | .name = "noreturn", |
| 633 | .base = Value{ | 637 | .base = Value{ |
| ... | @@ -638,10 +642,11 @@ pub const Compilation = struct { | ... | @@ -638,10 +642,11 @@ pub const Compilation = struct { |
| 638 | .id = builtin.TypeId.NoReturn, | 642 | .id = builtin.TypeId.NoReturn, |
| 639 | .abi_alignment = Type.AbiAlignment.init(comp.loop), | 643 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 640 | }, | 644 | }, |
| 641 | }); | 645 | }; |
| 642 | assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null); | 646 | assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null); |
| 643 | 647 | ||
| 644 | comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{ | 648 | comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt); |
| 649 | comp.comptime_int_type.* = Type.ComptimeInt{ | ||
| 645 | .base = Type{ | 650 | .base = Type{ |
| 646 | .name = "comptime_int", | 651 | .name = "comptime_int", |
| 647 | .base = Value{ | 652 | .base = Value{ |
| ... | @@ -652,10 +657,11 @@ pub const Compilation = struct { | ... | @@ -652,10 +657,11 @@ pub const Compilation = struct { |
| 652 | .id = builtin.TypeId.ComptimeInt, | 657 | .id = builtin.TypeId.ComptimeInt, |
| 653 | .abi_alignment = Type.AbiAlignment.init(comp.loop), | 658 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 654 | }, | 659 | }, |
| 655 | }); | 660 | }; |
| 656 | assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null); | 661 | assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null); |
| 657 | 662 | ||
| 658 | comp.bool_type = try comp.arena().create(Type.Bool{ | 663 | comp.bool_type = try comp.arena().create(Type.Bool); |
| 664 | comp.bool_type.* = Type.Bool{ | ||
| 659 | .base = Type{ | 665 | .base = Type{ |
| 660 | .name = "bool", | 666 | .name = "bool", |
| 661 | .base = Value{ | 667 | .base = Value{ |
| ... | @@ -666,45 +672,50 @@ pub const Compilation = struct { | ... | @@ -666,45 +672,50 @@ pub const Compilation = struct { |
| 666 | .id = builtin.TypeId.Bool, | 672 | .id = builtin.TypeId.Bool, |
| 667 | .abi_alignment = Type.AbiAlignment.init(comp.loop), | 673 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 668 | }, | 674 | }, |
| 669 | }); | 675 | }; |
| 670 | assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null); | 676 | assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null); |
| 671 | 677 | ||
| 672 | comp.void_value = try comp.arena().create(Value.Void{ | 678 | comp.void_value = try comp.arena().create(Value.Void); |
| 679 | comp.void_value.* = Value.Void{ | ||
| 673 | .base = Value{ | 680 | .base = Value{ |
| 674 | .id = Value.Id.Void, | 681 | .id = Value.Id.Void, |
| 675 | .typ = &Type.Void.get(comp).base, | 682 | .typ = &Type.Void.get(comp).base, |
| 676 | .ref_count = std.atomic.Int(usize).init(1), | 683 | .ref_count = std.atomic.Int(usize).init(1), |
| 677 | }, | 684 | }, |
| 678 | }); | 685 | }; |
| 679 | 686 | ||
| 680 | comp.true_value = try comp.arena().create(Value.Bool{ | 687 | comp.true_value = try comp.arena().create(Value.Bool); |
| 688 | comp.true_value.* = Value.Bool{ | ||
| 681 | .base = Value{ | 689 | .base = Value{ |
| 682 | .id = Value.Id.Bool, | 690 | .id = Value.Id.Bool, |
| 683 | .typ = &Type.Bool.get(comp).base, | 691 | .typ = &Type.Bool.get(comp).base, |
| 684 | .ref_count = std.atomic.Int(usize).init(1), | 692 | .ref_count = std.atomic.Int(usize).init(1), |
| 685 | }, | 693 | }, |
| 686 | .x = true, | 694 | .x = true, |
| 687 | }); | 695 | }; |
| 688 | 696 | ||
| 689 | comp.false_value = try comp.arena().create(Value.Bool{ | 697 | comp.false_value = try comp.arena().create(Value.Bool); |
| 698 | comp.false_value.* = Value.Bool{ | ||
| 690 | .base = Value{ | 699 | .base = Value{ |
| 691 | .id = Value.Id.Bool, | 700 | .id = Value.Id.Bool, |
| 692 | .typ = &Type.Bool.get(comp).base, | 701 | .typ = &Type.Bool.get(comp).base, |
| 693 | .ref_count = std.atomic.Int(usize).init(1), | 702 | .ref_count = std.atomic.Int(usize).init(1), |
| 694 | }, | 703 | }, |
| 695 | .x = false, | 704 | .x = false, |
| 696 | }); | 705 | }; |
| 697 | 706 | ||
| 698 | comp.noreturn_value = try comp.arena().create(Value.NoReturn{ | 707 | comp.noreturn_value = try comp.arena().create(Value.NoReturn); |
| 708 | comp.noreturn_value.* = Value.NoReturn{ | ||
| 699 | .base = Value{ | 709 | .base = Value{ |
| 700 | .id = Value.Id.NoReturn, | 710 | .id = Value.Id.NoReturn, |
| 701 | .typ = &Type.NoReturn.get(comp).base, | 711 | .typ = &Type.NoReturn.get(comp).base, |
| 702 | .ref_count = std.atomic.Int(usize).init(1), | 712 | .ref_count = std.atomic.Int(usize).init(1), |
| 703 | }, | 713 | }, |
| 704 | }); | 714 | }; |
| 705 | 715 | ||
| 706 | for (CInt.list) |cint, i| { | 716 | for (CInt.list) |cint, i| { |
| 707 | const c_int_type = try comp.arena().create(Type.Int{ | 717 | const c_int_type = try comp.arena().create(Type.Int); |
| 718 | c_int_type.* = Type.Int{ | ||
| 708 | .base = Type{ | 719 | .base = Type{ |
| 709 | .name = cint.zig_name, | 720 | .name = cint.zig_name, |
| 710 | .base = Value{ | 721 | .base = Value{ |
| ... | @@ -720,11 +731,12 @@ pub const Compilation = struct { | ... | @@ -720,11 +731,12 @@ pub const Compilation = struct { |
| 720 | .bit_count = comp.target.cIntTypeSizeInBits(cint.id), | 731 | .bit_count = comp.target.cIntTypeSizeInBits(cint.id), |
| 721 | }, | 732 | }, |
| 722 | .garbage_node = undefined, | 733 | .garbage_node = undefined, |
| 723 | }); | 734 | }; |
| 724 | comp.c_int_types[i] = c_int_type; | 735 | comp.c_int_types[i] = c_int_type; |
| 725 | assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null); | 736 | assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null); |
| 726 | } | 737 | } |
| 727 | comp.u8_type = try comp.arena().create(Type.Int{ | 738 | comp.u8_type = try comp.arena().create(Type.Int); |
| 739 | comp.u8_type.* = Type.Int{ | ||
| 728 | .base = Type{ | 740 | .base = Type{ |
| 729 | .name = "u8", | 741 | .name = "u8", |
| 730 | .base = Value{ | 742 | .base = Value{ |
| ... | @@ -740,7 +752,7 @@ pub const Compilation = struct { | ... | @@ -740,7 +752,7 @@ pub const Compilation = struct { |
| 740 | .bit_count = 8, | 752 | .bit_count = 8, |
| 741 | }, | 753 | }, |
| 742 | .garbage_node = undefined, | 754 | .garbage_node = undefined, |
| 743 | }); | 755 | }; |
| 744 | assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null); | 756 | assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null); |
| 745 | } | 757 | } |
| 746 | 758 | ||
| ... | @@ -829,7 +841,7 @@ pub const Compilation = struct { | ... | @@ -829,7 +841,7 @@ pub const Compilation = struct { |
| 829 | }; | 841 | }; |
| 830 | errdefer self.gpa().free(source_code); | 842 | errdefer self.gpa().free(source_code); |
| 831 | 843 | ||
| 832 | const tree = try self.gpa().createOne(ast.Tree); | 844 | const tree = try self.gpa().create(ast.Tree); |
| 833 | tree.* = try std.zig.parse(self.gpa(), source_code); | 845 | tree.* = try std.zig.parse(self.gpa(), source_code); |
| 834 | errdefer { | 846 | errdefer { |
| 835 | tree.deinit(); | 847 | tree.deinit(); |
| ... | @@ -925,7 +937,8 @@ pub const Compilation = struct { | ... | @@ -925,7 +937,8 @@ pub const Compilation = struct { |
| 925 | } | 937 | } |
| 926 | } else { | 938 | } else { |
| 927 | // add new decl | 939 | // add new decl |
| 928 | const fn_decl = try self.gpa().create(Decl.Fn{ | 940 | const fn_decl = try self.gpa().create(Decl.Fn); |
| 941 | fn_decl.* = Decl.Fn{ | ||
| 929 | .base = Decl{ | 942 | .base = Decl{ |
| 930 | .id = Decl.Id.Fn, | 943 | .id = Decl.Id.Fn, |
| 931 | .name = name, | 944 | .name = name, |
| ... | @@ -936,7 +949,7 @@ pub const Compilation = struct { | ... | @@ -936,7 +949,7 @@ pub const Compilation = struct { |
| 936 | }, | 949 | }, |
| 937 | .value = Decl.Fn.Val{ .Unresolved = {} }, | 950 | .value = Decl.Fn.Val{ .Unresolved = {} }, |
| 938 | .fn_proto = fn_proto, | 951 | .fn_proto = fn_proto, |
| 939 | }); | 952 | }; |
| 940 | tree_scope.base.ref(); | 953 | tree_scope.base.ref(); |
| 941 | errdefer self.gpa().destroy(fn_decl); | 954 | errdefer self.gpa().destroy(fn_decl); |
| 942 | 955 | ||
| ... | @@ -1140,12 +1153,13 @@ pub const Compilation = struct { | ... | @@ -1140,12 +1153,13 @@ pub const Compilation = struct { |
| 1140 | } | 1153 | } |
| 1141 | } | 1154 | } |
| 1142 | 1155 | ||
| 1143 | const link_lib = try self.gpa().create(LinkLib{ | 1156 | const link_lib = try self.gpa().create(LinkLib); |
| 1157 | link_lib.* = LinkLib{ | ||
| 1144 | .name = name, | 1158 | .name = name, |
| 1145 | .path = null, | 1159 | .path = null, |
| 1146 | .provided_explicitly = provided_explicitly, | 1160 | .provided_explicitly = provided_explicitly, |
| 1147 | .symbols = ArrayList([]u8).init(self.gpa()), | 1161 | .symbols = ArrayList([]u8).init(self.gpa()), |
| 1148 | }); | 1162 | }; |
| 1149 | try self.link_libs_list.append(link_lib); | 1163 | try self.link_libs_list.append(link_lib); |
| 1150 | if (is_libc) { | 1164 | if (is_libc) { |
| 1151 | self.libc_link_lib = link_lib; | 1165 | self.libc_link_lib = link_lib; |
src-self-hosted/errmsg.zig+12-8| ... | @@ -118,7 +118,8 @@ pub const Msg = struct { | ... | @@ -118,7 +118,8 @@ pub const Msg = struct { |
| 118 | const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); | 118 | const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); |
| 119 | errdefer comp.gpa().free(realpath); | 119 | errdefer comp.gpa().free(realpath); |
| 120 | 120 | ||
| 121 | const msg = try comp.gpa().create(Msg{ | 121 | const msg = try comp.gpa().create(Msg); |
| 122 | msg.* = Msg{ | ||
| 122 | .text = text, | 123 | .text = text, |
| 123 | .realpath = realpath, | 124 | .realpath = realpath, |
| 124 | .data = Data{ | 125 | .data = Data{ |
| ... | @@ -128,7 +129,7 @@ pub const Msg = struct { | ... | @@ -128,7 +129,7 @@ pub const Msg = struct { |
| 128 | .span = span, | 129 | .span = span, |
| 129 | }, | 130 | }, |
| 130 | }, | 131 | }, |
| 131 | }); | 132 | }; |
| 132 | tree_scope.base.ref(); | 133 | tree_scope.base.ref(); |
| 133 | return msg; | 134 | return msg; |
| 134 | } | 135 | } |
| ... | @@ -139,13 +140,14 @@ pub const Msg = struct { | ... | @@ -139,13 +140,14 @@ pub const Msg = struct { |
| 139 | const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath); | 140 | const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath); |
| 140 | errdefer comp.gpa().free(realpath_copy); | 141 | errdefer comp.gpa().free(realpath_copy); |
| 141 | 142 | ||
| 142 | const msg = try comp.gpa().create(Msg{ | 143 | const msg = try comp.gpa().create(Msg); |
| 144 | msg.* = Msg{ | ||
| 143 | .text = text, | 145 | .text = text, |
| 144 | .realpath = realpath_copy, | 146 | .realpath = realpath_copy, |
| 145 | .data = Data{ | 147 | .data = Data{ |
| 146 | .Cli = Cli{ .allocator = comp.gpa() }, | 148 | .Cli = Cli{ .allocator = comp.gpa() }, |
| 147 | }, | 149 | }, |
| 148 | }); | 150 | }; |
| 149 | return msg; | 151 | return msg; |
| 150 | } | 152 | } |
| 151 | 153 | ||
| ... | @@ -164,7 +166,8 @@ pub const Msg = struct { | ... | @@ -164,7 +166,8 @@ pub const Msg = struct { |
| 164 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | 166 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; |
| 165 | try parse_error.render(&tree_scope.tree.tokens, out_stream); | 167 | try parse_error.render(&tree_scope.tree.tokens, out_stream); |
| 166 | 168 | ||
| 167 | const msg = try comp.gpa().create(Msg{ | 169 | const msg = try comp.gpa().create(Msg); |
| 170 | msg.* = Msg{ | ||
| 168 | .text = undefined, | 171 | .text = undefined, |
| 169 | .realpath = realpath_copy, | 172 | .realpath = realpath_copy, |
| 170 | .data = Data{ | 173 | .data = Data{ |
| ... | @@ -177,7 +180,7 @@ pub const Msg = struct { | ... | @@ -177,7 +180,7 @@ pub const Msg = struct { |
| 177 | }, | 180 | }, |
| 178 | }, | 181 | }, |
| 179 | }, | 182 | }, |
| 180 | }); | 183 | }; |
| 181 | tree_scope.base.ref(); | 184 | tree_scope.base.ref(); |
| 182 | msg.text = text_buf.toOwnedSlice(); | 185 | msg.text = text_buf.toOwnedSlice(); |
| 183 | return msg; | 186 | return msg; |
| ... | @@ -203,7 +206,8 @@ pub const Msg = struct { | ... | @@ -203,7 +206,8 @@ pub const Msg = struct { |
| 203 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | 206 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; |
| 204 | try parse_error.render(&tree.tokens, out_stream); | 207 | try parse_error.render(&tree.tokens, out_stream); |
| 205 | 208 | ||
| 206 | const msg = try allocator.create(Msg{ | 209 | const msg = try allocator.create(Msg); |
| 210 | msg.* = Msg{ | ||
| 207 | .text = undefined, | 211 | .text = undefined, |
| 208 | .realpath = realpath_copy, | 212 | .realpath = realpath_copy, |
| 209 | .data = Data{ | 213 | .data = Data{ |
| ... | @@ -216,7 +220,7 @@ pub const Msg = struct { | ... | @@ -216,7 +220,7 @@ pub const Msg = struct { |
| 216 | }, | 220 | }, |
| 217 | }, | 221 | }, |
| 218 | }, | 222 | }, |
| 219 | }); | 223 | }; |
| 220 | msg.text = text_buf.toOwnedSlice(); | 224 | msg.text = text_buf.toOwnedSlice(); |
| 221 | errdefer allocator.destroy(msg); | 225 | errdefer allocator.destroy(msg); |
| 222 | 226 |
src-self-hosted/ir.zig+9-6| ... | @@ -1021,12 +1021,13 @@ pub const Builder = struct { | ... | @@ -1021,12 +1021,13 @@ pub const Builder = struct { |
| 1021 | pub const Error = Analyze.Error; | 1021 | pub const Error = Analyze.Error; |
| 1022 | 1022 | ||
| 1023 | pub fn init(comp: *Compilation, tree_scope: *Scope.AstTree, begin_scope: ?*Scope) !Builder { | 1023 | pub fn init(comp: *Compilation, tree_scope: *Scope.AstTree, begin_scope: ?*Scope) !Builder { |
| 1024 | const code = try comp.gpa().create(Code{ | 1024 | const code = try comp.gpa().create(Code); |
| 1025 | code.* = Code{ | ||
| 1025 | .basic_block_list = undefined, | 1026 | .basic_block_list = undefined, |
| 1026 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), | 1027 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| 1027 | .return_type = null, | 1028 | .return_type = null, |
| 1028 | .tree_scope = tree_scope, | 1029 | .tree_scope = tree_scope, |
| 1029 | }); | 1030 | }; |
| 1030 | code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); | 1031 | code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); |
| 1031 | errdefer code.destroy(comp.gpa()); | 1032 | errdefer code.destroy(comp.gpa()); |
| 1032 | 1033 | ||
| ... | @@ -1052,7 +1053,8 @@ pub const Builder = struct { | ... | @@ -1052,7 +1053,8 @@ pub const Builder = struct { |
| 1052 | 1053 | ||
| 1053 | /// No need to clean up resources thanks to the arena allocator. | 1054 | /// No need to clean up resources thanks to the arena allocator. |
| 1054 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { | 1055 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { |
| 1055 | const basic_block = try self.arena().create(BasicBlock{ | 1056 | const basic_block = try self.arena().create(BasicBlock); |
| 1057 | basic_block.* = BasicBlock{ | ||
| 1056 | .ref_count = 0, | 1058 | .ref_count = 0, |
| 1057 | .name_hint = name_hint, | 1059 | .name_hint = name_hint, |
| 1058 | .debug_id = self.next_debug_id, | 1060 | .debug_id = self.next_debug_id, |
| ... | @@ -1063,7 +1065,7 @@ pub const Builder = struct { | ... | @@ -1063,7 +1065,7 @@ pub const Builder = struct { |
| 1063 | .ref_instruction = null, | 1065 | .ref_instruction = null, |
| 1064 | .llvm_block = undefined, | 1066 | .llvm_block = undefined, |
| 1065 | .llvm_exit_block = undefined, | 1067 | .llvm_exit_block = undefined, |
| 1066 | }); | 1068 | }; |
| 1067 | self.next_debug_id += 1; | 1069 | self.next_debug_id += 1; |
| 1068 | return basic_block; | 1070 | return basic_block; |
| 1069 | } | 1071 | } |
| ... | @@ -1774,7 +1776,8 @@ pub const Builder = struct { | ... | @@ -1774,7 +1776,8 @@ pub const Builder = struct { |
| 1774 | params: I.Params, | 1776 | params: I.Params, |
| 1775 | is_generated: bool, | 1777 | is_generated: bool, |
| 1776 | ) !*Inst { | 1778 | ) !*Inst { |
| 1777 | const inst = try self.arena().create(I{ | 1779 | const inst = try self.arena().create(I); |
| 1780 | inst.* = I{ | ||
| 1778 | .base = Inst{ | 1781 | .base = Inst{ |
| 1779 | .id = Inst.typeToId(I), | 1782 | .id = Inst.typeToId(I), |
| 1780 | .is_generated = is_generated, | 1783 | .is_generated = is_generated, |
| ... | @@ -1793,7 +1796,7 @@ pub const Builder = struct { | ... | @@ -1793,7 +1796,7 @@ pub const Builder = struct { |
| 1793 | .owner_bb = self.current_basic_block, | 1796 | .owner_bb = self.current_basic_block, |
| 1794 | }, | 1797 | }, |
| 1795 | .params = params, | 1798 | .params = params, |
| 1796 | }); | 1799 | }; |
| 1797 | 1800 | ||
| 1798 | // Look at the params and ref() other instructions | 1801 | // Look at the params and ref() other instructions |
| 1799 | comptime var i = 0; | 1802 | comptime var i = 0; |
src-self-hosted/libc_installation.zig+4-4| ... | @@ -57,10 +57,10 @@ pub const LibCInstallation = struct { | ... | @@ -57,10 +57,10 @@ pub const LibCInstallation = struct { |
| 57 | const contents = try std.io.readFileAlloc(allocator, libc_file); | 57 | const contents = try std.io.readFileAlloc(allocator, libc_file); |
| 58 | defer allocator.free(contents); | 58 | defer allocator.free(contents); |
| 59 | 59 | ||
| 60 | var it = std.mem.split(contents, "\n"); | 60 | var it = std.mem.tokenize(contents, "\n"); |
| 61 | while (it.next()) |line| { | 61 | while (it.next()) |line| { |
| 62 | if (line.len == 0 or line[0] == '#') continue; | 62 | if (line.len == 0 or line[0] == '#') continue; |
| 63 | var line_it = std.mem.split(line, "="); | 63 | var line_it = std.mem.separate(line, "="); |
| 64 | const name = line_it.next() orelse { | 64 | const name = line_it.next() orelse { |
| 65 | try stderr.print("missing equal sign after field name\n"); | 65 | try stderr.print("missing equal sign after field name\n"); |
| 66 | return error.ParseError; | 66 | return error.ParseError; |
| ... | @@ -213,7 +213,7 @@ pub const LibCInstallation = struct { | ... | @@ -213,7 +213,7 @@ pub const LibCInstallation = struct { |
| 213 | }, | 213 | }, |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | var it = std.mem.split(exec_result.stderr, "\n\r"); | 216 | var it = std.mem.tokenize(exec_result.stderr, "\n\r"); |
| 217 | var search_paths = std.ArrayList([]const u8).init(loop.allocator); | 217 | var search_paths = std.ArrayList([]const u8).init(loop.allocator); |
| 218 | defer search_paths.deinit(); | 218 | defer search_paths.deinit(); |
| 219 | while (it.next()) |line| { | 219 | while (it.next()) |line| { |
| ... | @@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo | ... | @@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo |
| 410 | return error.CCompilerCrashed; | 410 | return error.CCompilerCrashed; |
| 411 | }, | 411 | }, |
| 412 | } | 412 | } |
| 413 | var it = std.mem.split(exec_result.stdout, "\n\r"); | 413 | var it = std.mem.tokenize(exec_result.stdout, "\n\r"); |
| 414 | const line = it.next() orelse return error.LibCRuntimeNotFound; | 414 | const line = it.next() orelse return error.LibCRuntimeNotFound; |
| 415 | const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound; | 415 | const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound; |
| 416 | 416 |
src-self-hosted/main.zig+4-3| ... | @@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 351 | const root_name = if (provided_name) |n| n else blk: { | 351 | const root_name = if (provided_name) |n| n else blk: { |
| 352 | if (root_source_file) |file| { | 352 | if (root_source_file) |file| { |
| 353 | const basename = os.path.basename(file); | 353 | const basename = os.path.basename(file); |
| 354 | var it = mem.split(basename, "."); | 354 | var it = mem.separate(basename, "."); |
| 355 | break :blk it.next() orelse basename; | 355 | break :blk it.next() orelse basename; |
| 356 | } else { | 356 | } else { |
| 357 | try stderr.write("--name [name] not provided and unable to infer\n"); | 357 | try stderr.write("--name [name] not provided and unable to infer\n"); |
| ... | @@ -944,12 +944,13 @@ const CliPkg = struct { | ... | @@ -944,12 +944,13 @@ const CliPkg = struct { |
| 944 | parent: ?*CliPkg, | 944 | parent: ?*CliPkg, |
| 945 | 945 | ||
| 946 | pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg { | 946 | pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg { |
| 947 | var pkg = try allocator.create(CliPkg{ | 947 | var pkg = try allocator.create(CliPkg); |
| 948 | pkg.* = CliPkg{ | ||
| 948 | .name = name, | 949 | .name = name, |
| 949 | .path = path, | 950 | .path = path, |
| 950 | .children = ArrayList(*CliPkg).init(allocator), | 951 | .children = ArrayList(*CliPkg).init(allocator), |
| 951 | .parent = parent, | 952 | .parent = parent, |
| 952 | }); | 953 | }; |
| 953 | return pkg; | 954 | return pkg; |
| 954 | } | 955 | } |
| 955 | 956 |
src-self-hosted/package.zig+4-2| ... | @@ -15,11 +15,13 @@ pub const Package = struct { | ... | @@ -15,11 +15,13 @@ pub const Package = struct { |
| 15 | /// makes internal copies of root_src_dir and root_src_path | 15 | /// makes internal copies of root_src_dir and root_src_path |
| 16 | /// allocator should be an arena allocator because Package never frees anything | 16 | /// allocator should be an arena allocator because Package never frees anything |
| 17 | pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package { | 17 | pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package { |
| 18 | return allocator.create(Package{ | 18 | const ptr = try allocator.create(Package); |
| 19 | ptr.* = Package{ | ||
| 19 | .root_src_dir = try Buffer.init(allocator, root_src_dir), | 20 | .root_src_dir = try Buffer.init(allocator, root_src_dir), |
| 20 | .root_src_path = try Buffer.init(allocator, root_src_path), | 21 | .root_src_path = try Buffer.init(allocator, root_src_path), |
| 21 | .table = Table.init(allocator), | 22 | .table = Table.init(allocator), |
| 22 | }); | 23 | }; |
| 24 | return ptr; | ||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | pub fn add(self: *Package, name: []const u8, package: *Package) !void { | 27 | pub fn add(self: *Package, name: []const u8, package: *Package) !void { |
src-self-hosted/scope.zig+9-9| ... | @@ -120,7 +120,7 @@ pub const Scope = struct { | ... | @@ -120,7 +120,7 @@ pub const Scope = struct { |
| 120 | /// Creates a Root scope with 1 reference | 120 | /// Creates a Root scope with 1 reference |
| 121 | /// Takes ownership of realpath | 121 | /// Takes ownership of realpath |
| 122 | pub fn create(comp: *Compilation, realpath: []u8) !*Root { | 122 | pub fn create(comp: *Compilation, realpath: []u8) !*Root { |
| 123 | const self = try comp.gpa().createOne(Root); | 123 | const self = try comp.gpa().create(Root); |
| 124 | self.* = Root{ | 124 | self.* = Root{ |
| 125 | .base = Scope{ | 125 | .base = Scope{ |
| 126 | .id = Id.Root, | 126 | .id = Id.Root, |
| ... | @@ -150,7 +150,7 @@ pub const Scope = struct { | ... | @@ -150,7 +150,7 @@ pub const Scope = struct { |
| 150 | /// Creates a scope with 1 reference | 150 | /// Creates a scope with 1 reference |
| 151 | /// Takes ownership of tree, will deinit and destroy when done. | 151 | /// Takes ownership of tree, will deinit and destroy when done. |
| 152 | pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree { | 152 | pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree { |
| 153 | const self = try comp.gpa().createOne(AstTree); | 153 | const self = try comp.gpa().create(AstTree); |
| 154 | self.* = AstTree{ | 154 | self.* = AstTree{ |
| 155 | .base = undefined, | 155 | .base = undefined, |
| 156 | .tree = tree, | 156 | .tree = tree, |
| ... | @@ -182,7 +182,7 @@ pub const Scope = struct { | ... | @@ -182,7 +182,7 @@ pub const Scope = struct { |
| 182 | 182 | ||
| 183 | /// Creates a Decls scope with 1 reference | 183 | /// Creates a Decls scope with 1 reference |
| 184 | pub fn create(comp: *Compilation, parent: *Scope) !*Decls { | 184 | pub fn create(comp: *Compilation, parent: *Scope) !*Decls { |
| 185 | const self = try comp.gpa().createOne(Decls); | 185 | const self = try comp.gpa().create(Decls); |
| 186 | self.* = Decls{ | 186 | self.* = Decls{ |
| 187 | .base = undefined, | 187 | .base = undefined, |
| 188 | .table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())), | 188 | .table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())), |
| ... | @@ -235,7 +235,7 @@ pub const Scope = struct { | ... | @@ -235,7 +235,7 @@ pub const Scope = struct { |
| 235 | 235 | ||
| 236 | /// Creates a Block scope with 1 reference | 236 | /// Creates a Block scope with 1 reference |
| 237 | pub fn create(comp: *Compilation, parent: *Scope) !*Block { | 237 | pub fn create(comp: *Compilation, parent: *Scope) !*Block { |
| 238 | const self = try comp.gpa().createOne(Block); | 238 | const self = try comp.gpa().create(Block); |
| 239 | self.* = Block{ | 239 | self.* = Block{ |
| 240 | .base = undefined, | 240 | .base = undefined, |
| 241 | .incoming_values = undefined, | 241 | .incoming_values = undefined, |
| ... | @@ -262,7 +262,7 @@ pub const Scope = struct { | ... | @@ -262,7 +262,7 @@ pub const Scope = struct { |
| 262 | /// Creates a FnDef scope with 1 reference | 262 | /// Creates a FnDef scope with 1 reference |
| 263 | /// Must set the fn_val later | 263 | /// Must set the fn_val later |
| 264 | pub fn create(comp: *Compilation, parent: *Scope) !*FnDef { | 264 | pub fn create(comp: *Compilation, parent: *Scope) !*FnDef { |
| 265 | const self = try comp.gpa().createOne(FnDef); | 265 | const self = try comp.gpa().create(FnDef); |
| 266 | self.* = FnDef{ | 266 | self.* = FnDef{ |
| 267 | .base = undefined, | 267 | .base = undefined, |
| 268 | .fn_val = null, | 268 | .fn_val = null, |
| ... | @@ -281,7 +281,7 @@ pub const Scope = struct { | ... | @@ -281,7 +281,7 @@ pub const Scope = struct { |
| 281 | 281 | ||
| 282 | /// Creates a CompTime scope with 1 reference | 282 | /// Creates a CompTime scope with 1 reference |
| 283 | pub fn create(comp: *Compilation, parent: *Scope) !*CompTime { | 283 | pub fn create(comp: *Compilation, parent: *Scope) !*CompTime { |
| 284 | const self = try comp.gpa().createOne(CompTime); | 284 | const self = try comp.gpa().create(CompTime); |
| 285 | self.* = CompTime{ .base = undefined }; | 285 | self.* = CompTime{ .base = undefined }; |
| 286 | self.base.init(Id.CompTime, parent); | 286 | self.base.init(Id.CompTime, parent); |
| 287 | return self; | 287 | return self; |
| ... | @@ -309,7 +309,7 @@ pub const Scope = struct { | ... | @@ -309,7 +309,7 @@ pub const Scope = struct { |
| 309 | kind: Kind, | 309 | kind: Kind, |
| 310 | defer_expr_scope: *DeferExpr, | 310 | defer_expr_scope: *DeferExpr, |
| 311 | ) !*Defer { | 311 | ) !*Defer { |
| 312 | const self = try comp.gpa().createOne(Defer); | 312 | const self = try comp.gpa().create(Defer); |
| 313 | self.* = Defer{ | 313 | self.* = Defer{ |
| 314 | .base = undefined, | 314 | .base = undefined, |
| 315 | .defer_expr_scope = defer_expr_scope, | 315 | .defer_expr_scope = defer_expr_scope, |
| ... | @@ -333,7 +333,7 @@ pub const Scope = struct { | ... | @@ -333,7 +333,7 @@ pub const Scope = struct { |
| 333 | 333 | ||
| 334 | /// Creates a DeferExpr scope with 1 reference | 334 | /// Creates a DeferExpr scope with 1 reference |
| 335 | pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr { | 335 | pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr { |
| 336 | const self = try comp.gpa().createOne(DeferExpr); | 336 | const self = try comp.gpa().create(DeferExpr); |
| 337 | self.* = DeferExpr{ | 337 | self.* = DeferExpr{ |
| 338 | .base = undefined, | 338 | .base = undefined, |
| 339 | .expr_node = expr_node, | 339 | .expr_node = expr_node, |
| ... | @@ -398,7 +398,7 @@ pub const Scope = struct { | ... | @@ -398,7 +398,7 @@ pub const Scope = struct { |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var { | 400 | fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var { |
| 401 | const self = try comp.gpa().createOne(Var); | 401 | const self = try comp.gpa().create(Var); |
| 402 | self.* = Var{ | 402 | self.* = Var{ |
| 403 | .base = undefined, | 403 | .base = undefined, |
| 404 | .name = name, | 404 | .name = name, |
src-self-hosted/type.zig+26-7| ... | @@ -44,6 +44,7 @@ pub const Type = struct { | ... | @@ -44,6 +44,7 @@ pub const Type = struct { |
| 44 | Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp), | 44 | Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp), |
| 45 | Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp), | 45 | Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp), |
| 46 | Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp), | 46 | Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp), |
| 47 | Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp), | ||
| 47 | } | 48 | } |
| 48 | } | 49 | } |
| 49 | 50 | ||
| ... | @@ -77,6 +78,7 @@ pub const Type = struct { | ... | @@ -77,6 +78,7 @@ pub const Type = struct { |
| 77 | Id.ArgTuple => unreachable, | 78 | Id.ArgTuple => unreachable, |
| 78 | Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context), | 79 | Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context), |
| 79 | Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context), | 80 | Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context), |
| 81 | Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context), | ||
| 80 | } | 82 | } |
| 81 | } | 83 | } |
| 82 | 84 | ||
| ... | @@ -103,6 +105,7 @@ pub const Type = struct { | ... | @@ -103,6 +105,7 @@ pub const Type = struct { |
| 103 | Id.Enum, | 105 | Id.Enum, |
| 104 | Id.Fn, | 106 | Id.Fn, |
| 105 | Id.Promise, | 107 | Id.Promise, |
| 108 | Id.Vector, | ||
| 106 | => return false, | 109 | => return false, |
| 107 | 110 | ||
| 108 | Id.Struct => @panic("TODO"), | 111 | Id.Struct => @panic("TODO"), |
| ... | @@ -135,6 +138,7 @@ pub const Type = struct { | ... | @@ -135,6 +138,7 @@ pub const Type = struct { |
| 135 | Id.Float, | 138 | Id.Float, |
| 136 | Id.Fn, | 139 | Id.Fn, |
| 137 | Id.Promise, | 140 | Id.Promise, |
| 141 | Id.Vector, | ||
| 138 | => return true, | 142 | => return true, |
| 139 | 143 | ||
| 140 | Id.Pointer => { | 144 | Id.Pointer => { |
| ... | @@ -409,7 +413,7 @@ pub const Type = struct { | ... | @@ -409,7 +413,7 @@ pub const Type = struct { |
| 409 | key.ref(); | 413 | key.ref(); |
| 410 | errdefer key.deref(comp); | 414 | errdefer key.deref(comp); |
| 411 | 415 | ||
| 412 | const self = try comp.gpa().createOne(Fn); | 416 | const self = try comp.gpa().create(Fn); |
| 413 | self.* = Fn{ | 417 | self.* = Fn{ |
| 414 | .base = undefined, | 418 | .base = undefined, |
| 415 | .key = key, | 419 | .key = key, |
| ... | @@ -611,11 +615,12 @@ pub const Type = struct { | ... | @@ -611,11 +615,12 @@ pub const Type = struct { |
| 611 | } | 615 | } |
| 612 | } | 616 | } |
| 613 | 617 | ||
| 614 | const self = try comp.gpa().create(Int{ | 618 | const self = try comp.gpa().create(Int); |
| 619 | self.* = Int{ | ||
| 615 | .base = undefined, | 620 | .base = undefined, |
| 616 | .key = key, | 621 | .key = key, |
| 617 | .garbage_node = undefined, | 622 | .garbage_node = undefined, |
| 618 | }); | 623 | }; |
| 619 | errdefer comp.gpa().destroy(self); | 624 | errdefer comp.gpa().destroy(self); |
| 620 | 625 | ||
| 621 | const u_or_i = "ui"[@boolToInt(key.is_signed)]; | 626 | const u_or_i = "ui"[@boolToInt(key.is_signed)]; |
| ... | @@ -777,11 +782,12 @@ pub const Type = struct { | ... | @@ -777,11 +782,12 @@ pub const Type = struct { |
| 777 | } | 782 | } |
| 778 | } | 783 | } |
| 779 | 784 | ||
| 780 | const self = try comp.gpa().create(Pointer{ | 785 | const self = try comp.gpa().create(Pointer); |
| 786 | self.* = Pointer{ | ||
| 781 | .base = undefined, | 787 | .base = undefined, |
| 782 | .key = normal_key, | 788 | .key = normal_key, |
| 783 | .garbage_node = undefined, | 789 | .garbage_node = undefined, |
| 784 | }); | 790 | }; |
| 785 | errdefer comp.gpa().destroy(self); | 791 | errdefer comp.gpa().destroy(self); |
| 786 | 792 | ||
| 787 | const size_str = switch (self.key.size) { | 793 | const size_str = switch (self.key.size) { |
| ... | @@ -875,11 +881,12 @@ pub const Type = struct { | ... | @@ -875,11 +881,12 @@ pub const Type = struct { |
| 875 | } | 881 | } |
| 876 | } | 882 | } |
| 877 | 883 | ||
| 878 | const self = try comp.gpa().create(Array{ | 884 | const self = try comp.gpa().create(Array); |
| 885 | self.* = Array{ | ||
| 879 | .base = undefined, | 886 | .base = undefined, |
| 880 | .key = key, | 887 | .key = key, |
| 881 | .garbage_node = undefined, | 888 | .garbage_node = undefined, |
| 882 | }); | 889 | }; |
| 883 | errdefer comp.gpa().destroy(self); | 890 | errdefer comp.gpa().destroy(self); |
| 884 | 891 | ||
| 885 | const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name); | 892 | const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name); |
| ... | @@ -902,6 +909,18 @@ pub const Type = struct { | ... | @@ -902,6 +909,18 @@ pub const Type = struct { |
| 902 | } | 909 | } |
| 903 | }; | 910 | }; |
| 904 | 911 | ||
| 912 | pub const Vector = struct { | ||
| 913 | base: Type, | ||
| 914 | |||
| 915 | pub fn destroy(self: *Vector, comp: *Compilation) void { | ||
| 916 | comp.gpa().destroy(self); | ||
| 917 | } | ||
| 918 | |||
| 919 | pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { | ||
| 920 | @panic("TODO"); | ||
| 921 | } | ||
| 922 | }; | ||
| 923 | |||
| 905 | pub const ComptimeFloat = struct { | 924 | pub const ComptimeFloat = struct { |
| 906 | base: Type, | 925 | base: Type, |
| 907 | 926 |
src-self-hosted/value.zig+21-14| ... | @@ -135,14 +135,15 @@ pub const Value = struct { | ... | @@ -135,14 +135,15 @@ pub const Value = struct { |
| 135 | symbol_name: Buffer, | 135 | symbol_name: Buffer, |
| 136 | 136 | ||
| 137 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto { | 137 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto { |
| 138 | const self = try comp.gpa().create(FnProto{ | 138 | const self = try comp.gpa().create(FnProto); |
| 139 | self.* = FnProto{ | ||
| 139 | .base = Value{ | 140 | .base = Value{ |
| 140 | .id = Value.Id.FnProto, | 141 | .id = Value.Id.FnProto, |
| 141 | .typ = &fn_type.base, | 142 | .typ = &fn_type.base, |
| 142 | .ref_count = std.atomic.Int(usize).init(1), | 143 | .ref_count = std.atomic.Int(usize).init(1), |
| 143 | }, | 144 | }, |
| 144 | .symbol_name = symbol_name, | 145 | .symbol_name = symbol_name, |
| 145 | }); | 146 | }; |
| 146 | fn_type.base.base.ref(); | 147 | fn_type.base.base.ref(); |
| 147 | return self; | 148 | return self; |
| 148 | } | 149 | } |
| ... | @@ -190,14 +191,16 @@ pub const Value = struct { | ... | @@ -190,14 +191,16 @@ pub const Value = struct { |
| 190 | /// Creates a Fn value with 1 ref | 191 | /// Creates a Fn value with 1 ref |
| 191 | /// Takes ownership of symbol_name | 192 | /// Takes ownership of symbol_name |
| 192 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn { | 193 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn { |
| 193 | const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{ | 194 | const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node); |
| 195 | link_set_node.* = Compilation.FnLinkSet.Node{ | ||
| 194 | .data = null, | 196 | .data = null, |
| 195 | .next = undefined, | 197 | .next = undefined, |
| 196 | .prev = undefined, | 198 | .prev = undefined, |
| 197 | }); | 199 | }; |
| 198 | errdefer comp.gpa().destroy(link_set_node); | 200 | errdefer comp.gpa().destroy(link_set_node); |
| 199 | 201 | ||
| 200 | const self = try comp.gpa().create(Fn{ | 202 | const self = try comp.gpa().create(Fn); |
| 203 | self.* = Fn{ | ||
| 201 | .base = Value{ | 204 | .base = Value{ |
| 202 | .id = Value.Id.Fn, | 205 | .id = Value.Id.Fn, |
| 203 | .typ = &fn_type.base, | 206 | .typ = &fn_type.base, |
| ... | @@ -209,7 +212,7 @@ pub const Value = struct { | ... | @@ -209,7 +212,7 @@ pub const Value = struct { |
| 209 | .symbol_name = symbol_name, | 212 | .symbol_name = symbol_name, |
| 210 | .containing_object = Buffer.initNull(comp.gpa()), | 213 | .containing_object = Buffer.initNull(comp.gpa()), |
| 211 | .link_set_node = link_set_node, | 214 | .link_set_node = link_set_node, |
| 212 | }); | 215 | }; |
| 213 | fn_type.base.base.ref(); | 216 | fn_type.base.base.ref(); |
| 214 | fndef_scope.fn_val = self; | 217 | fndef_scope.fn_val = self; |
| 215 | fndef_scope.base.ref(); | 218 | fndef_scope.base.ref(); |
| ... | @@ -353,7 +356,8 @@ pub const Value = struct { | ... | @@ -353,7 +356,8 @@ pub const Value = struct { |
| 353 | var ptr_type_consumed = false; | 356 | var ptr_type_consumed = false; |
| 354 | errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); | 357 | errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); |
| 355 | 358 | ||
| 356 | const self = try comp.gpa().create(Value.Ptr{ | 359 | const self = try comp.gpa().create(Value.Ptr); |
| 360 | self.* = Value.Ptr{ | ||
| 357 | .base = Value{ | 361 | .base = Value{ |
| 358 | .id = Value.Id.Ptr, | 362 | .id = Value.Id.Ptr, |
| 359 | .typ = &ptr_type.base, | 363 | .typ = &ptr_type.base, |
| ... | @@ -366,7 +370,7 @@ pub const Value = struct { | ... | @@ -366,7 +370,7 @@ pub const Value = struct { |
| 366 | }, | 370 | }, |
| 367 | }, | 371 | }, |
| 368 | .mut = Mut.CompTimeConst, | 372 | .mut = Mut.CompTimeConst, |
| 369 | }); | 373 | }; |
| 370 | ptr_type_consumed = true; | 374 | ptr_type_consumed = true; |
| 371 | errdefer comp.gpa().destroy(self); | 375 | errdefer comp.gpa().destroy(self); |
| 372 | 376 | ||
| ... | @@ -430,14 +434,15 @@ pub const Value = struct { | ... | @@ -430,14 +434,15 @@ pub const Value = struct { |
| 430 | }) catch unreachable); | 434 | }) catch unreachable); |
| 431 | errdefer array_type.base.base.deref(comp); | 435 | errdefer array_type.base.base.deref(comp); |
| 432 | 436 | ||
| 433 | const self = try comp.gpa().create(Value.Array{ | 437 | const self = try comp.gpa().create(Value.Array); |
| 438 | self.* = Value.Array{ | ||
| 434 | .base = Value{ | 439 | .base = Value{ |
| 435 | .id = Value.Id.Array, | 440 | .id = Value.Id.Array, |
| 436 | .typ = &array_type.base, | 441 | .typ = &array_type.base, |
| 437 | .ref_count = std.atomic.Int(usize).init(1), | 442 | .ref_count = std.atomic.Int(usize).init(1), |
| 438 | }, | 443 | }, |
| 439 | .special = Special{ .OwnedBuffer = buffer }, | 444 | .special = Special{ .OwnedBuffer = buffer }, |
| 440 | }); | 445 | }; |
| 441 | errdefer comp.gpa().destroy(self); | 446 | errdefer comp.gpa().destroy(self); |
| 442 | 447 | ||
| 443 | return self; | 448 | return self; |
| ... | @@ -509,14 +514,15 @@ pub const Value = struct { | ... | @@ -509,14 +514,15 @@ pub const Value = struct { |
| 509 | big_int: std.math.big.Int, | 514 | big_int: std.math.big.Int, |
| 510 | 515 | ||
| 511 | pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int { | 516 | pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int { |
| 512 | const self = try comp.gpa().create(Value.Int{ | 517 | const self = try comp.gpa().create(Value.Int); |
| 518 | self.* = Value.Int{ | ||
| 513 | .base = Value{ | 519 | .base = Value{ |
| 514 | .id = Value.Id.Int, | 520 | .id = Value.Id.Int, |
| 515 | .typ = typ, | 521 | .typ = typ, |
| 516 | .ref_count = std.atomic.Int(usize).init(1), | 522 | .ref_count = std.atomic.Int(usize).init(1), |
| 517 | }, | 523 | }, |
| 518 | .big_int = undefined, | 524 | .big_int = undefined, |
| 519 | }); | 525 | }; |
| 520 | typ.base.ref(); | 526 | typ.base.ref(); |
| 521 | errdefer comp.gpa().destroy(self); | 527 | errdefer comp.gpa().destroy(self); |
| 522 | 528 | ||
| ... | @@ -557,14 +563,15 @@ pub const Value = struct { | ... | @@ -557,14 +563,15 @@ pub const Value = struct { |
| 557 | old.base.typ.base.ref(); | 563 | old.base.typ.base.ref(); |
| 558 | errdefer old.base.typ.base.deref(comp); | 564 | errdefer old.base.typ.base.deref(comp); |
| 559 | 565 | ||
| 560 | const new = try comp.gpa().create(Value.Int{ | 566 | const new = try comp.gpa().create(Value.Int); |
| 567 | new.* = Value.Int{ | ||
| 561 | .base = Value{ | 568 | .base = Value{ |
| 562 | .id = Value.Id.Int, | 569 | .id = Value.Id.Int, |
| 563 | .typ = old.base.typ, | 570 | .typ = old.base.typ, |
| 564 | .ref_count = std.atomic.Int(usize).init(1), | 571 | .ref_count = std.atomic.Int(usize).init(1), |
| 565 | }, | 572 | }, |
| 566 | .big_int = undefined, | 573 | .big_int = undefined, |
| 567 | }); | 574 | }; |
| 568 | errdefer comp.gpa().destroy(new); | 575 | errdefer comp.gpa().destroy(new); |
| 569 | 576 | ||
| 570 | new.big_int = try old.big_int.clone(); | 577 | new.big_int = try old.big_int.clone(); |
src/all_types.hpp+152-50| ... | @@ -56,9 +56,6 @@ struct IrExecutable { | ... | @@ -56,9 +56,6 @@ struct IrExecutable { |
| 56 | size_t next_debug_id; | 56 | size_t next_debug_id; |
| 57 | size_t *backward_branch_count; | 57 | size_t *backward_branch_count; |
| 58 | size_t backward_branch_quota; | 58 | size_t backward_branch_quota; |
| 59 | bool invalid; | ||
| 60 | bool is_inline; | ||
| 61 | bool is_generic_instantiation; | ||
| 62 | ZigFn *fn_entry; | 59 | ZigFn *fn_entry; |
| 63 | Buf *c_import_buf; | 60 | Buf *c_import_buf; |
| 64 | AstNode *source_node; | 61 | AstNode *source_node; |
| ... | @@ -78,6 +75,10 @@ struct IrExecutable { | ... | @@ -78,6 +75,10 @@ struct IrExecutable { |
| 78 | IrBasicBlock *coro_suspend_block; | 75 | IrBasicBlock *coro_suspend_block; |
| 79 | IrBasicBlock *coro_final_cleanup_block; | 76 | IrBasicBlock *coro_final_cleanup_block; |
| 80 | ZigVar *coro_allocator_var; | 77 | ZigVar *coro_allocator_var; |
| 78 | |||
| 79 | bool invalid; | ||
| 80 | bool is_inline; | ||
| 81 | bool is_generic_instantiation; | ||
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| 83 | enum OutType { | 84 | enum OutType { |
| ... | @@ -90,6 +91,9 @@ enum OutType { | ... | @@ -90,6 +91,9 @@ enum OutType { |
| 90 | enum ConstParentId { | 91 | enum ConstParentId { |
| 91 | ConstParentIdNone, | 92 | ConstParentIdNone, |
| 92 | ConstParentIdStruct, | 93 | ConstParentIdStruct, |
| 94 | ConstParentIdErrUnionCode, | ||
| 95 | ConstParentIdErrUnionPayload, | ||
| 96 | ConstParentIdOptionalPayload, | ||
| 93 | ConstParentIdArray, | 97 | ConstParentIdArray, |
| 94 | ConstParentIdUnion, | 98 | ConstParentIdUnion, |
| 95 | ConstParentIdScalar, | 99 | ConstParentIdScalar, |
| ... | @@ -107,6 +111,15 @@ struct ConstParent { | ... | @@ -107,6 +111,15 @@ struct ConstParent { |
| 107 | ConstExprValue *struct_val; | 111 | ConstExprValue *struct_val; |
| 108 | size_t field_index; | 112 | size_t field_index; |
| 109 | } p_struct; | 113 | } p_struct; |
| 114 | struct { | ||
| 115 | ConstExprValue *err_union_val; | ||
| 116 | } p_err_union_code; | ||
| 117 | struct { | ||
| 118 | ConstExprValue *err_union_val; | ||
| 119 | } p_err_union_payload; | ||
| 120 | struct { | ||
| 121 | ConstExprValue *optional_val; | ||
| 122 | } p_optional_payload; | ||
| 110 | struct { | 123 | struct { |
| 111 | ConstExprValue *union_val; | 124 | ConstExprValue *union_val; |
| 112 | } p_union; | 125 | } p_union; |
| ... | @@ -118,13 +131,11 @@ struct ConstParent { | ... | @@ -118,13 +131,11 @@ struct ConstParent { |
| 118 | 131 | ||
| 119 | struct ConstStructValue { | 132 | struct ConstStructValue { |
| 120 | ConstExprValue *fields; | 133 | ConstExprValue *fields; |
| 121 | ConstParent parent; | ||
| 122 | }; | 134 | }; |
| 123 | 135 | ||
| 124 | struct ConstUnionValue { | 136 | struct ConstUnionValue { |
| 125 | BigInt tag; | 137 | BigInt tag; |
| 126 | ConstExprValue *payload; | 138 | ConstExprValue *payload; |
| 127 | ConstParent parent; | ||
| 128 | }; | 139 | }; |
| 129 | 140 | ||
| 130 | enum ConstArraySpecial { | 141 | enum ConstArraySpecial { |
| ... | @@ -138,7 +149,6 @@ struct ConstArrayValue { | ... | @@ -138,7 +149,6 @@ struct ConstArrayValue { |
| 138 | union { | 149 | union { |
| 139 | struct { | 150 | struct { |
| 140 | ConstExprValue *elements; | 151 | ConstExprValue *elements; |
| 141 | ConstParent parent; | ||
| 142 | } s_none; | 152 | } s_none; |
| 143 | Buf *s_buf; | 153 | Buf *s_buf; |
| 144 | } data; | 154 | } data; |
| ... | @@ -153,19 +163,29 @@ enum ConstPtrSpecial { | ... | @@ -153,19 +163,29 @@ enum ConstPtrSpecial { |
| 153 | ConstPtrSpecialBaseArray, | 163 | ConstPtrSpecialBaseArray, |
| 154 | // The pointer points to a field in an underlying struct. | 164 | // The pointer points to a field in an underlying struct. |
| 155 | ConstPtrSpecialBaseStruct, | 165 | ConstPtrSpecialBaseStruct, |
| 166 | // The pointer points to the error set field of an error union | ||
| 167 | ConstPtrSpecialBaseErrorUnionCode, | ||
| 168 | // The pointer points to the payload field of an error union | ||
| 169 | ConstPtrSpecialBaseErrorUnionPayload, | ||
| 170 | // The pointer points to the payload field of an optional | ||
| 171 | ConstPtrSpecialBaseOptionalPayload, | ||
| 156 | // This means that we did a compile-time pointer reinterpret and we cannot | 172 | // This means that we did a compile-time pointer reinterpret and we cannot |
| 157 | // understand the value of pointee at compile time. However, we will still | 173 | // understand the value of pointee at compile time. However, we will still |
| 158 | // emit a binary with a compile time known address. | 174 | // emit a binary with a compile time known address. |
| 159 | // In this case index is the numeric address value. | 175 | // In this case index is the numeric address value. |
| 160 | // We also use this for null pointer. We need the data layout for ConstCastOnly == true | ||
| 161 | // types to be the same, so all optionals of pointer types use x_ptr | ||
| 162 | // instead of x_optional | ||
| 163 | ConstPtrSpecialHardCodedAddr, | 176 | ConstPtrSpecialHardCodedAddr, |
| 164 | // This means that the pointer represents memory of assigning to _. | 177 | // This means that the pointer represents memory of assigning to _. |
| 165 | // That is, storing discards the data, and loading is invalid. | 178 | // That is, storing discards the data, and loading is invalid. |
| 166 | ConstPtrSpecialDiscard, | 179 | ConstPtrSpecialDiscard, |
| 167 | // This is actually a function. | 180 | // This is actually a function. |
| 168 | ConstPtrSpecialFunction, | 181 | ConstPtrSpecialFunction, |
| 182 | // This means the pointer is null. This is only allowed when the type is ?*T. | ||
| 183 | // We use this instead of ConstPtrSpecialHardCodedAddr because often we check | ||
| 184 | // for that value to avoid doing comptime work. | ||
| 185 | // We need the data layout for ConstCastOnly == true | ||
| 186 | // types to be the same, so all optionals of pointer types use x_ptr | ||
| 187 | // instead of x_optional. | ||
| 188 | ConstPtrSpecialNull, | ||
| 169 | }; | 189 | }; |
| 170 | 190 | ||
| 171 | enum ConstPtrMut { | 191 | enum ConstPtrMut { |
| ... | @@ -199,6 +219,15 @@ struct ConstPtrValue { | ... | @@ -199,6 +219,15 @@ struct ConstPtrValue { |
| 199 | ConstExprValue *struct_val; | 219 | ConstExprValue *struct_val; |
| 200 | size_t field_index; | 220 | size_t field_index; |
| 201 | } base_struct; | 221 | } base_struct; |
| 222 | struct { | ||
| 223 | ConstExprValue *err_union_val; | ||
| 224 | } base_err_union_code; | ||
| 225 | struct { | ||
| 226 | ConstExprValue *err_union_val; | ||
| 227 | } base_err_union_payload; | ||
| 228 | struct { | ||
| 229 | ConstExprValue *optional_val; | ||
| 230 | } base_optional_payload; | ||
| 202 | struct { | 231 | struct { |
| 203 | uint64_t addr; | 232 | uint64_t addr; |
| 204 | } hard_coded_addr; | 233 | } hard_coded_addr; |
| ... | @@ -209,7 +238,7 @@ struct ConstPtrValue { | ... | @@ -209,7 +238,7 @@ struct ConstPtrValue { |
| 209 | }; | 238 | }; |
| 210 | 239 | ||
| 211 | struct ConstErrValue { | 240 | struct ConstErrValue { |
| 212 | ErrorTableEntry *err; | 241 | ConstExprValue *error_set; |
| 213 | ConstExprValue *payload; | 242 | ConstExprValue *payload; |
| 214 | }; | 243 | }; |
| 215 | 244 | ||
| ... | @@ -265,6 +294,7 @@ struct ConstGlobalRefs { | ... | @@ -265,6 +294,7 @@ struct ConstGlobalRefs { |
| 265 | struct ConstExprValue { | 294 | struct ConstExprValue { |
| 266 | ZigType *type; | 295 | ZigType *type; |
| 267 | ConstValSpecial special; | 296 | ConstValSpecial special; |
| 297 | ConstParent parent; | ||
| 268 | ConstGlobalRefs *global_refs; | 298 | ConstGlobalRefs *global_refs; |
| 269 | 299 | ||
| 270 | union { | 300 | union { |
| ... | @@ -433,7 +463,7 @@ enum NodeType { | ... | @@ -433,7 +463,7 @@ enum NodeType { |
| 433 | NodeTypeArrayType, | 463 | NodeTypeArrayType, |
| 434 | NodeTypeErrorType, | 464 | NodeTypeErrorType, |
| 435 | NodeTypeIfErrorExpr, | 465 | NodeTypeIfErrorExpr, |
| 436 | NodeTypeTestExpr, | 466 | NodeTypeIfOptional, |
| 437 | NodeTypeErrorSetDecl, | 467 | NodeTypeErrorSetDecl, |
| 438 | NodeTypeCancel, | 468 | NodeTypeCancel, |
| 439 | NodeTypeResume, | 469 | NodeTypeResume, |
| ... | @@ -677,7 +707,7 @@ struct AstNodeUse { | ... | @@ -677,7 +707,7 @@ struct AstNodeUse { |
| 677 | AstNode *expr; | 707 | AstNode *expr; |
| 678 | 708 | ||
| 679 | TldResolution resolution; | 709 | TldResolution resolution; |
| 680 | IrInstruction *value; | 710 | ConstExprValue *value; |
| 681 | }; | 711 | }; |
| 682 | 712 | ||
| 683 | struct AstNodeIfBoolExpr { | 713 | struct AstNodeIfBoolExpr { |
| ... | @@ -1180,6 +1210,12 @@ struct ZigTypePromise { | ... | @@ -1180,6 +1210,12 @@ struct ZigTypePromise { |
| 1180 | ZigType *result_type; | 1210 | ZigType *result_type; |
| 1181 | }; | 1211 | }; |
| 1182 | 1212 | ||
| 1213 | struct ZigTypeVector { | ||
| 1214 | // The type must be a pointer, integer, or float | ||
| 1215 | ZigType *elem_type; | ||
| 1216 | uint32_t len; | ||
| 1217 | }; | ||
| 1218 | |||
| 1183 | enum ZigTypeId { | 1219 | enum ZigTypeId { |
| 1184 | ZigTypeIdInvalid, | 1220 | ZigTypeIdInvalid, |
| 1185 | ZigTypeIdMetaType, | 1221 | ZigTypeIdMetaType, |
| ... | @@ -1206,6 +1242,7 @@ enum ZigTypeId { | ... | @@ -1206,6 +1242,7 @@ enum ZigTypeId { |
| 1206 | ZigTypeIdArgTuple, | 1242 | ZigTypeIdArgTuple, |
| 1207 | ZigTypeIdOpaque, | 1243 | ZigTypeIdOpaque, |
| 1208 | ZigTypeIdPromise, | 1244 | ZigTypeIdPromise, |
| 1245 | ZigTypeIdVector, | ||
| 1209 | }; | 1246 | }; |
| 1210 | 1247 | ||
| 1211 | struct ZigType { | 1248 | struct ZigType { |
| ... | @@ -1232,6 +1269,7 @@ struct ZigType { | ... | @@ -1232,6 +1269,7 @@ struct ZigType { |
| 1232 | ZigTypeFn fn; | 1269 | ZigTypeFn fn; |
| 1233 | ZigTypeBoundFn bound_fn; | 1270 | ZigTypeBoundFn bound_fn; |
| 1234 | ZigTypePromise promise; | 1271 | ZigTypePromise promise; |
| 1272 | ZigTypeVector vector; | ||
| 1235 | } data; | 1273 | } data; |
| 1236 | 1274 | ||
| 1237 | // use these fields to make sure we don't duplicate type table entries for the same type | 1275 | // use these fields to make sure we don't duplicate type table entries for the same type |
| ... | @@ -1385,6 +1423,7 @@ enum BuiltinFnId { | ... | @@ -1385,6 +1423,7 @@ enum BuiltinFnId { |
| 1385 | BuiltinFnIdEnumToInt, | 1423 | BuiltinFnIdEnumToInt, |
| 1386 | BuiltinFnIdIntToEnum, | 1424 | BuiltinFnIdIntToEnum, |
| 1387 | BuiltinFnIdIntType, | 1425 | BuiltinFnIdIntType, |
| 1426 | BuiltinFnIdVectorType, | ||
| 1388 | BuiltinFnIdSetCold, | 1427 | BuiltinFnIdSetCold, |
| 1389 | BuiltinFnIdSetRuntimeSafety, | 1428 | BuiltinFnIdSetRuntimeSafety, |
| 1390 | BuiltinFnIdSetFloatMode, | 1429 | BuiltinFnIdSetFloatMode, |
| ... | @@ -1475,6 +1514,10 @@ struct TypeId { | ... | @@ -1475,6 +1514,10 @@ struct TypeId { |
| 1475 | ZigType *err_set_type; | 1514 | ZigType *err_set_type; |
| 1476 | ZigType *payload_type; | 1515 | ZigType *payload_type; |
| 1477 | } error_union; | 1516 | } error_union; |
| 1517 | struct { | ||
| 1518 | ZigType *elem_type; | ||
| 1519 | uint32_t len; | ||
| 1520 | } vector; | ||
| 1478 | } data; | 1521 | } data; |
| 1479 | }; | 1522 | }; |
| 1480 | 1523 | ||
| ... | @@ -1610,7 +1653,7 @@ struct CodeGen { | ... | @@ -1610,7 +1653,7 @@ struct CodeGen { |
| 1610 | HashMap<FnTypeId *, ZigType *, fn_type_id_hash, fn_type_id_eql> fn_type_table; | 1653 | HashMap<FnTypeId *, ZigType *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1611 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; | 1654 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; |
| 1612 | HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; | 1655 | HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; |
| 1613 | HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; | 1656 | HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; |
| 1614 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; | 1657 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; |
| 1615 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; | 1658 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1616 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; | 1659 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| ... | @@ -1760,6 +1803,7 @@ struct CodeGen { | ... | @@ -1760,6 +1803,7 @@ struct CodeGen { |
| 1760 | bool is_static; | 1803 | bool is_static; |
| 1761 | bool strip_debug_symbols; | 1804 | bool strip_debug_symbols; |
| 1762 | bool is_test_build; | 1805 | bool is_test_build; |
| 1806 | bool is_single_threaded; | ||
| 1763 | bool is_native_target; | 1807 | bool is_native_target; |
| 1764 | bool linker_rdynamic; | 1808 | bool linker_rdynamic; |
| 1765 | bool no_rosegment_workaround; | 1809 | bool no_rosegment_workaround; |
| ... | @@ -1802,10 +1846,9 @@ enum VarLinkage { | ... | @@ -1802,10 +1846,9 @@ enum VarLinkage { |
| 1802 | 1846 | ||
| 1803 | struct ZigVar { | 1847 | struct ZigVar { |
| 1804 | Buf name; | 1848 | Buf name; |
| 1805 | ConstExprValue *value; | 1849 | ConstExprValue *const_value; |
| 1850 | ZigType *var_type; | ||
| 1806 | LLVMValueRef value_ref; | 1851 | LLVMValueRef value_ref; |
| 1807 | bool src_is_const; | ||
| 1808 | bool gen_is_const; | ||
| 1809 | IrInstruction *is_comptime; | 1852 | IrInstruction *is_comptime; |
| 1810 | // which node is the declaration of the variable | 1853 | // which node is the declaration of the variable |
| 1811 | AstNode *decl_node; | 1854 | AstNode *decl_node; |
| ... | @@ -1815,17 +1858,21 @@ struct ZigVar { | ... | @@ -1815,17 +1858,21 @@ struct ZigVar { |
| 1815 | Scope *parent_scope; | 1858 | Scope *parent_scope; |
| 1816 | Scope *child_scope; | 1859 | Scope *child_scope; |
| 1817 | LLVMValueRef param_value_ref; | 1860 | LLVMValueRef param_value_ref; |
| 1818 | bool shadowable; | ||
| 1819 | size_t mem_slot_index; | 1861 | size_t mem_slot_index; |
| 1820 | IrExecutable *owner_exec; | 1862 | IrExecutable *owner_exec; |
| 1821 | size_t ref_count; | 1863 | size_t ref_count; |
| 1822 | VarLinkage linkage; | ||
| 1823 | uint32_t align_bytes; | ||
| 1824 | 1864 | ||
| 1825 | // In an inline loop, multiple variables may be created, | 1865 | // In an inline loop, multiple variables may be created, |
| 1826 | // In this case, a reference to a variable should follow | 1866 | // In this case, a reference to a variable should follow |
| 1827 | // this pointer to the redefined variable. | 1867 | // this pointer to the redefined variable. |
| 1828 | ZigVar *next_var; | 1868 | ZigVar *next_var; |
| 1869 | |||
| 1870 | uint32_t align_bytes; | ||
| 1871 | VarLinkage linkage; | ||
| 1872 | |||
| 1873 | bool shadowable; | ||
| 1874 | bool src_is_const; | ||
| 1875 | bool gen_is_const; | ||
| 1829 | }; | 1876 | }; |
| 1830 | 1877 | ||
| 1831 | struct ErrorTableEntry { | 1878 | struct ErrorTableEntry { |
| ... | @@ -1891,10 +1938,11 @@ struct ScopeBlock { | ... | @@ -1891,10 +1938,11 @@ struct ScopeBlock { |
| 1891 | ZigList<IrInstruction *> *incoming_values; | 1938 | ZigList<IrInstruction *> *incoming_values; |
| 1892 | ZigList<IrBasicBlock *> *incoming_blocks; | 1939 | ZigList<IrBasicBlock *> *incoming_blocks; |
| 1893 | 1940 | ||
| 1894 | bool safety_off; | ||
| 1895 | AstNode *safety_set_node; | 1941 | AstNode *safety_set_node; |
| 1896 | bool fast_math_on; | ||
| 1897 | AstNode *fast_math_set_node; | 1942 | AstNode *fast_math_set_node; |
| 1943 | |||
| 1944 | bool safety_off; | ||
| 1945 | bool fast_math_on; | ||
| 1898 | }; | 1946 | }; |
| 1899 | 1947 | ||
| 1900 | // This scope is created from every defer expression. | 1948 | // This scope is created from every defer expression. |
| ... | @@ -2030,8 +2078,19 @@ struct IrBasicBlock { | ... | @@ -2030,8 +2078,19 @@ struct IrBasicBlock { |
| 2030 | IrInstruction *must_be_comptime_source_instr; | 2078 | IrInstruction *must_be_comptime_source_instr; |
| 2031 | }; | 2079 | }; |
| 2032 | 2080 | ||
| 2081 | // These instructions are in transition to having "pass 1" instructions | ||
| 2082 | // and "pass 2" instructions. The pass 1 instructions are suffixed with Src | ||
| 2083 | // and pass 2 are suffixed with Gen. | ||
| 2084 | // Once all instructions are separated in this way, they'll have different | ||
| 2085 | // base types for better type safety. | ||
| 2086 | // Src instructions are generated by ir_gen_* functions in ir.cpp from AST. | ||
| 2087 | // ir_analyze_* functions consume Src instructions and produce Gen instructions. | ||
| 2088 | // ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. | ||
| 2089 | // Src instructions do not have type information; Gen instructions do. | ||
| 2033 | enum IrInstructionId { | 2090 | enum IrInstructionId { |
| 2034 | IrInstructionIdInvalid, | 2091 | IrInstructionIdInvalid, |
| 2092 | IrInstructionIdDeclVarSrc, | ||
| 2093 | IrInstructionIdDeclVarGen, | ||
| 2035 | IrInstructionIdBr, | 2094 | IrInstructionIdBr, |
| 2036 | IrInstructionIdCondBr, | 2095 | IrInstructionIdCondBr, |
| 2037 | IrInstructionIdSwitchBr, | 2096 | IrInstructionIdSwitchBr, |
| ... | @@ -2040,7 +2099,6 @@ enum IrInstructionId { | ... | @@ -2040,7 +2099,6 @@ enum IrInstructionId { |
| 2040 | IrInstructionIdPhi, | 2099 | IrInstructionIdPhi, |
| 2041 | IrInstructionIdUnOp, | 2100 | IrInstructionIdUnOp, |
| 2042 | IrInstructionIdBinOp, | 2101 | IrInstructionIdBinOp, |
| 2043 | IrInstructionIdDeclVar, | ||
| 2044 | IrInstructionIdLoadPtr, | 2102 | IrInstructionIdLoadPtr, |
| 2045 | IrInstructionIdStorePtr, | 2103 | IrInstructionIdStorePtr, |
| 2046 | IrInstructionIdFieldPtr, | 2104 | IrInstructionIdFieldPtr, |
| ... | @@ -2069,7 +2127,7 @@ enum IrInstructionId { | ... | @@ -2069,7 +2127,7 @@ enum IrInstructionId { |
| 2069 | IrInstructionIdAsm, | 2127 | IrInstructionIdAsm, |
| 2070 | IrInstructionIdSizeOf, | 2128 | IrInstructionIdSizeOf, |
| 2071 | IrInstructionIdTestNonNull, | 2129 | IrInstructionIdTestNonNull, |
| 2072 | IrInstructionIdUnwrapOptional, | 2130 | IrInstructionIdOptionalUnwrapPtr, |
| 2073 | IrInstructionIdOptionalWrap, | 2131 | IrInstructionIdOptionalWrap, |
| 2074 | IrInstructionIdUnionTag, | 2132 | IrInstructionIdUnionTag, |
| 2075 | IrInstructionIdClz, | 2133 | IrInstructionIdClz, |
| ... | @@ -2085,7 +2143,8 @@ enum IrInstructionId { | ... | @@ -2085,7 +2143,8 @@ enum IrInstructionId { |
| 2085 | IrInstructionIdCompileLog, | 2143 | IrInstructionIdCompileLog, |
| 2086 | IrInstructionIdErrName, | 2144 | IrInstructionIdErrName, |
| 2087 | IrInstructionIdEmbedFile, | 2145 | IrInstructionIdEmbedFile, |
| 2088 | IrInstructionIdCmpxchg, | 2146 | IrInstructionIdCmpxchgSrc, |
| 2147 | IrInstructionIdCmpxchgGen, | ||
| 2089 | IrInstructionIdFence, | 2148 | IrInstructionIdFence, |
| 2090 | IrInstructionIdTruncate, | 2149 | IrInstructionIdTruncate, |
| 2091 | IrInstructionIdIntCast, | 2150 | IrInstructionIdIntCast, |
| ... | @@ -2094,6 +2153,7 @@ enum IrInstructionId { | ... | @@ -2094,6 +2153,7 @@ enum IrInstructionId { |
| 2094 | IrInstructionIdFloatToInt, | 2153 | IrInstructionIdFloatToInt, |
| 2095 | IrInstructionIdBoolToInt, | 2154 | IrInstructionIdBoolToInt, |
| 2096 | IrInstructionIdIntType, | 2155 | IrInstructionIdIntType, |
| 2156 | IrInstructionIdVectorType, | ||
| 2097 | IrInstructionIdBoolNot, | 2157 | IrInstructionIdBoolNot, |
| 2098 | IrInstructionIdMemset, | 2158 | IrInstructionIdMemset, |
| 2099 | IrInstructionIdMemcpy, | 2159 | IrInstructionIdMemcpy, |
| ... | @@ -2114,7 +2174,8 @@ enum IrInstructionId { | ... | @@ -2114,7 +2174,8 @@ enum IrInstructionId { |
| 2114 | IrInstructionIdErrWrapPayload, | 2174 | IrInstructionIdErrWrapPayload, |
| 2115 | IrInstructionIdFnProto, | 2175 | IrInstructionIdFnProto, |
| 2116 | IrInstructionIdTestComptime, | 2176 | IrInstructionIdTestComptime, |
| 2117 | IrInstructionIdPtrCast, | 2177 | IrInstructionIdPtrCastSrc, |
| 2178 | IrInstructionIdPtrCastGen, | ||
| 2118 | IrInstructionIdBitCast, | 2179 | IrInstructionIdBitCast, |
| 2119 | IrInstructionIdWidenOrShorten, | 2180 | IrInstructionIdWidenOrShorten, |
| 2120 | IrInstructionIdIntToPtr, | 2181 | IrInstructionIdIntToPtr, |
| ... | @@ -2173,6 +2234,8 @@ enum IrInstructionId { | ... | @@ -2173,6 +2234,8 @@ enum IrInstructionId { |
| 2173 | IrInstructionIdToBytes, | 2234 | IrInstructionIdToBytes, |
| 2174 | IrInstructionIdFromBytes, | 2235 | IrInstructionIdFromBytes, |
| 2175 | IrInstructionIdCheckRuntimeScope, | 2236 | IrInstructionIdCheckRuntimeScope, |
| 2237 | IrInstructionIdVectorToArray, | ||
| 2238 | IrInstructionIdArrayToVector, | ||
| 2176 | }; | 2239 | }; |
| 2177 | 2240 | ||
| 2178 | struct IrInstruction { | 2241 | struct IrInstruction { |
| ... | @@ -2194,6 +2257,22 @@ struct IrInstruction { | ... | @@ -2194,6 +2257,22 @@ struct IrInstruction { |
| 2194 | bool is_gen; | 2257 | bool is_gen; |
| 2195 | }; | 2258 | }; |
| 2196 | 2259 | ||
| 2260 | struct IrInstructionDeclVarSrc { | ||
| 2261 | IrInstruction base; | ||
| 2262 | |||
| 2263 | ZigVar *var; | ||
| 2264 | IrInstruction *var_type; | ||
| 2265 | IrInstruction *align_value; | ||
| 2266 | IrInstruction *init_value; | ||
| 2267 | }; | ||
| 2268 | |||
| 2269 | struct IrInstructionDeclVarGen { | ||
| 2270 | IrInstruction base; | ||
| 2271 | |||
| 2272 | ZigVar *var; | ||
| 2273 | IrInstruction *init_value; | ||
| 2274 | }; | ||
| 2275 | |||
| 2197 | struct IrInstructionCondBr { | 2276 | struct IrInstructionCondBr { |
| 2198 | IrInstruction base; | 2277 | IrInstruction base; |
| 2199 | 2278 | ||
| ... | @@ -2302,20 +2381,11 @@ struct IrInstructionBinOp { | ... | @@ -2302,20 +2381,11 @@ struct IrInstructionBinOp { |
| 2302 | IrInstruction base; | 2381 | IrInstruction base; |
| 2303 | 2382 | ||
| 2304 | IrInstruction *op1; | 2383 | IrInstruction *op1; |
| 2305 | IrBinOp op_id; | ||
| 2306 | IrInstruction *op2; | 2384 | IrInstruction *op2; |
| 2385 | IrBinOp op_id; | ||
| 2307 | bool safety_check_on; | 2386 | bool safety_check_on; |
| 2308 | }; | 2387 | }; |
| 2309 | 2388 | ||
| 2310 | struct IrInstructionDeclVar { | ||
| 2311 | IrInstruction base; | ||
| 2312 | |||
| 2313 | ZigVar *var; | ||
| 2314 | IrInstruction *var_type; | ||
| 2315 | IrInstruction *align_value; | ||
| 2316 | IrInstruction *init_value; | ||
| 2317 | }; | ||
| 2318 | |||
| 2319 | struct IrInstructionLoadPtr { | 2389 | struct IrInstructionLoadPtr { |
| 2320 | IrInstruction base; | 2390 | IrInstruction base; |
| 2321 | 2391 | ||
| ... | @@ -2335,7 +2405,6 @@ struct IrInstructionFieldPtr { | ... | @@ -2335,7 +2405,6 @@ struct IrInstructionFieldPtr { |
| 2335 | IrInstruction *container_ptr; | 2405 | IrInstruction *container_ptr; |
| 2336 | Buf *field_name_buffer; | 2406 | Buf *field_name_buffer; |
| 2337 | IrInstruction *field_name_expr; | 2407 | IrInstruction *field_name_expr; |
| 2338 | bool is_const; | ||
| 2339 | }; | 2408 | }; |
| 2340 | 2409 | ||
| 2341 | struct IrInstructionStructFieldPtr { | 2410 | struct IrInstructionStructFieldPtr { |
| ... | @@ -2378,13 +2447,13 @@ struct IrInstructionCall { | ... | @@ -2378,13 +2447,13 @@ struct IrInstructionCall { |
| 2378 | ZigFn *fn_entry; | 2447 | ZigFn *fn_entry; |
| 2379 | size_t arg_count; | 2448 | size_t arg_count; |
| 2380 | IrInstruction **args; | 2449 | IrInstruction **args; |
| 2381 | bool is_comptime; | ||
| 2382 | LLVMValueRef tmp_ptr; | 2450 | LLVMValueRef tmp_ptr; |
| 2383 | FnInline fn_inline; | ||
| 2384 | bool is_async; | ||
| 2385 | 2451 | ||
| 2386 | IrInstruction *async_allocator; | 2452 | IrInstruction *async_allocator; |
| 2387 | IrInstruction *new_stack; | 2453 | IrInstruction *new_stack; |
| 2454 | FnInline fn_inline; | ||
| 2455 | bool is_async; | ||
| 2456 | bool is_comptime; | ||
| 2388 | }; | 2457 | }; |
| 2389 | 2458 | ||
| 2390 | struct IrInstructionConst { | 2459 | struct IrInstructionConst { |
| ... | @@ -2527,9 +2596,9 @@ struct IrInstructionSliceType { | ... | @@ -2527,9 +2596,9 @@ struct IrInstructionSliceType { |
| 2527 | IrInstruction base; | 2596 | IrInstruction base; |
| 2528 | 2597 | ||
| 2529 | IrInstruction *align_value; | 2598 | IrInstruction *align_value; |
| 2599 | IrInstruction *child_type; | ||
| 2530 | bool is_const; | 2600 | bool is_const; |
| 2531 | bool is_volatile; | 2601 | bool is_volatile; |
| 2532 | IrInstruction *child_type; | ||
| 2533 | }; | 2602 | }; |
| 2534 | 2603 | ||
| 2535 | struct IrInstructionAsm { | 2604 | struct IrInstructionAsm { |
| ... | @@ -2557,10 +2626,12 @@ struct IrInstructionTestNonNull { | ... | @@ -2557,10 +2626,12 @@ struct IrInstructionTestNonNull { |
| 2557 | IrInstruction *value; | 2626 | IrInstruction *value; |
| 2558 | }; | 2627 | }; |
| 2559 | 2628 | ||
| 2560 | struct IrInstructionUnwrapOptional { | 2629 | // Takes a pointer to an optional value, returns a pointer |
| 2630 | // to the payload. | ||
| 2631 | struct IrInstructionOptionalUnwrapPtr { | ||
| 2561 | IrInstruction base; | 2632 | IrInstruction base; |
| 2562 | 2633 | ||
| 2563 | IrInstruction *value; | 2634 | IrInstruction *base_ptr; |
| 2564 | bool safety_check_on; | 2635 | bool safety_check_on; |
| 2565 | }; | 2636 | }; |
| 2566 | 2637 | ||
| ... | @@ -2651,7 +2722,7 @@ struct IrInstructionEmbedFile { | ... | @@ -2651,7 +2722,7 @@ struct IrInstructionEmbedFile { |
| 2651 | IrInstruction *name; | 2722 | IrInstruction *name; |
| 2652 | }; | 2723 | }; |
| 2653 | 2724 | ||
| 2654 | struct IrInstructionCmpxchg { | 2725 | struct IrInstructionCmpxchgSrc { |
| 2655 | IrInstruction base; | 2726 | IrInstruction base; |
| 2656 | 2727 | ||
| 2657 | IrInstruction *type_value; | 2728 | IrInstruction *type_value; |
| ... | @@ -2661,14 +2732,19 @@ struct IrInstructionCmpxchg { | ... | @@ -2661,14 +2732,19 @@ struct IrInstructionCmpxchg { |
| 2661 | IrInstruction *success_order_value; | 2732 | IrInstruction *success_order_value; |
| 2662 | IrInstruction *failure_order_value; | 2733 | IrInstruction *failure_order_value; |
| 2663 | 2734 | ||
| 2664 | // if this instruction gets to runtime then we know these values: | ||
| 2665 | ZigType *type; | ||
| 2666 | AtomicOrder success_order; | ||
| 2667 | AtomicOrder failure_order; | ||
| 2668 | |||
| 2669 | bool is_weak; | 2735 | bool is_weak; |
| 2736 | }; | ||
| 2670 | 2737 | ||
| 2738 | struct IrInstructionCmpxchgGen { | ||
| 2739 | IrInstruction base; | ||
| 2740 | |||
| 2741 | IrInstruction *ptr; | ||
| 2742 | IrInstruction *cmp_value; | ||
| 2743 | IrInstruction *new_value; | ||
| 2671 | LLVMValueRef tmp_ptr; | 2744 | LLVMValueRef tmp_ptr; |
| 2745 | AtomicOrder success_order; | ||
| 2746 | AtomicOrder failure_order; | ||
| 2747 | bool is_weak; | ||
| 2672 | }; | 2748 | }; |
| 2673 | 2749 | ||
| 2674 | struct IrInstructionFence { | 2750 | struct IrInstructionFence { |
| ... | @@ -2748,6 +2824,13 @@ struct IrInstructionIntType { | ... | @@ -2748,6 +2824,13 @@ struct IrInstructionIntType { |
| 2748 | IrInstruction *bit_count; | 2824 | IrInstruction *bit_count; |
| 2749 | }; | 2825 | }; |
| 2750 | 2826 | ||
| 2827 | struct IrInstructionVectorType { | ||
| 2828 | IrInstruction base; | ||
| 2829 | |||
| 2830 | IrInstruction *len; | ||
| 2831 | IrInstruction *elem_type; | ||
| 2832 | }; | ||
| 2833 | |||
| 2751 | struct IrInstructionBoolNot { | 2834 | struct IrInstructionBoolNot { |
| 2752 | IrInstruction base; | 2835 | IrInstruction base; |
| 2753 | 2836 | ||
| ... | @@ -2851,7 +2934,7 @@ struct IrInstructionTestErr { | ... | @@ -2851,7 +2934,7 @@ struct IrInstructionTestErr { |
| 2851 | struct IrInstructionUnwrapErrCode { | 2934 | struct IrInstructionUnwrapErrCode { |
| 2852 | IrInstruction base; | 2935 | IrInstruction base; |
| 2853 | 2936 | ||
| 2854 | IrInstruction *value; | 2937 | IrInstruction *err_union; |
| 2855 | }; | 2938 | }; |
| 2856 | 2939 | ||
| 2857 | struct IrInstructionUnwrapErrPayload { | 2940 | struct IrInstructionUnwrapErrPayload { |
| ... | @@ -2899,13 +2982,19 @@ struct IrInstructionTestComptime { | ... | @@ -2899,13 +2982,19 @@ struct IrInstructionTestComptime { |
| 2899 | IrInstruction *value; | 2982 | IrInstruction *value; |
| 2900 | }; | 2983 | }; |
| 2901 | 2984 | ||
| 2902 | struct IrInstructionPtrCast { | 2985 | struct IrInstructionPtrCastSrc { |
| 2903 | IrInstruction base; | 2986 | IrInstruction base; |
| 2904 | 2987 | ||
| 2905 | IrInstruction *dest_type; | 2988 | IrInstruction *dest_type; |
| 2906 | IrInstruction *ptr; | 2989 | IrInstruction *ptr; |
| 2907 | }; | 2990 | }; |
| 2908 | 2991 | ||
| 2992 | struct IrInstructionPtrCastGen { | ||
| 2993 | IrInstruction base; | ||
| 2994 | |||
| 2995 | IrInstruction *ptr; | ||
| 2996 | }; | ||
| 2997 | |||
| 2909 | struct IrInstructionBitCast { | 2998 | struct IrInstructionBitCast { |
| 2910 | IrInstruction base; | 2999 | IrInstruction base; |
| 2911 | 3000 | ||
| ... | @@ -3276,6 +3365,19 @@ struct IrInstructionBitReverse { | ... | @@ -3276,6 +3365,19 @@ struct IrInstructionBitReverse { |
| 3276 | IrInstruction *op; | 3365 | IrInstruction *op; |
| 3277 | }; | 3366 | }; |
| 3278 | 3367 | ||
| 3368 | struct IrInstructionArrayToVector { | ||
| 3369 | IrInstruction base; | ||
| 3370 | |||
| 3371 | IrInstruction *array; | ||
| 3372 | }; | ||
| 3373 | |||
| 3374 | struct IrInstructionVectorToArray { | ||
| 3375 | IrInstruction base; | ||
| 3376 | |||
| 3377 | IrInstruction *vector; | ||
| 3378 | LLVMValueRef tmp_ptr; | ||
| 3379 | }; | ||
| 3380 | |||
| 3279 | static const size_t slice_ptr_index = 0; | 3381 | static const size_t slice_ptr_index = 0; |
| 3280 | static const size_t slice_len_index = 1; | 3382 | static const size_t slice_len_index = 1; |
| 3281 | 3383 |
src/analyze.cpp+361-151| ... | @@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) { | ... | @@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) { |
| 250 | case ZigTypeIdBoundFn: | 250 | case ZigTypeIdBoundFn: |
| 251 | case ZigTypeIdArgTuple: | 251 | case ZigTypeIdArgTuple: |
| 252 | case ZigTypeIdPromise: | 252 | case ZigTypeIdPromise: |
| 253 | case ZigTypeIdVector: | ||
| 253 | return nullptr; | 254 | return nullptr; |
| 254 | } | 255 | } |
| 255 | zig_unreachable(); | 256 | zig_unreachable(); |
| ... | @@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { | ... | @@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 311 | case ZigTypeIdBoundFn: | 312 | case ZigTypeIdBoundFn: |
| 312 | case ZigTypeIdArgTuple: | 313 | case ZigTypeIdArgTuple: |
| 313 | case ZigTypeIdPromise: | 314 | case ZigTypeIdPromise: |
| 315 | case ZigTypeIdVector: | ||
| 314 | return true; | 316 | return true; |
| 315 | } | 317 | } |
| 316 | zig_unreachable(); | 318 | zig_unreachable(); |
| ... | @@ -570,7 +572,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { | ... | @@ -570,7 +572,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| 570 | if (child_type->zero_bits) { | 572 | if (child_type->zero_bits) { |
| 571 | entry->type_ref = LLVMInt1Type(); | 573 | entry->type_ref = LLVMInt1Type(); |
| 572 | entry->di_type = g->builtin_types.entry_bool->di_type; | 574 | entry->di_type = g->builtin_types.entry_bool->di_type; |
| 573 | } else if (type_is_codegen_pointer(child_type)) { | 575 | } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { |
| 574 | assert(child_type->di_type); | 576 | assert(child_type->di_type); |
| 575 | // this is an optimization but also is necessary for calling C | 577 | // this is an optimization but also is necessary for calling C |
| 576 | // functions where all pointers are maybe pointers | 578 | // functions where all pointers are maybe pointers |
| ... | @@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { |
| 1055 | } | 1057 | } |
| 1056 | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { | 1058 | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| 1057 | X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); | 1059 | X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); |
| 1058 | if (abi_class == X64CABIClass_MEMORY) { | 1060 | return abi_class == X64CABIClass_MEMORY; |
| 1059 | return true; | ||
| 1060 | } | ||
| 1061 | zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", | ||
| 1062 | buf_ptr(&fn_type_id->return_type->name)); | ||
| 1063 | } else if (target_is_arm(&g->zig_target)) { | 1061 | } else if (target_is_arm(&g->zig_target)) { |
| 1064 | return type_size(g, fn_type_id->return_type) > 16; | 1062 | return type_size(g, fn_type_id->return_type) > 16; |
| 1065 | } | 1063 | } |
| ... | @@ -1278,7 +1276,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind | ... | @@ -1278,7 +1276,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind |
| 1278 | return entry; | 1276 | return entry; |
| 1279 | } | 1277 | } |
| 1280 | 1278 | ||
| 1281 | static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { | 1279 | static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, |
| 1280 | Buf *type_name) | ||
| 1281 | { | ||
| 1282 | size_t backward_branch_count = 0; | 1282 | size_t backward_branch_count = 0; |
| 1283 | return ir_eval_const_value(g, scope, node, type_entry, | 1283 | return ir_eval_const_value(g, scope, node, type_entry, |
| 1284 | &backward_branch_count, default_backward_branch_quota, | 1284 | &backward_branch_count, default_backward_branch_quota, |
| ... | @@ -1286,12 +1286,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod | ... | @@ -1286,12 +1286,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod |
| 1286 | } | 1286 | } |
| 1287 | 1287 | ||
| 1288 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { | 1288 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { |
| 1289 | IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); | 1289 | ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); |
| 1290 | if (result->value.type->id == ZigTypeIdInvalid) | 1290 | if (type_is_invalid(result->type)) |
| 1291 | return g->builtin_types.entry_invalid; | 1291 | return g->builtin_types.entry_invalid; |
| 1292 | 1292 | ||
| 1293 | assert(result->value.special != ConstValSpecialRuntime); | 1293 | assert(result->special != ConstValSpecialRuntime); |
| 1294 | return result->value.data.x_type; | 1294 | return result->data.x_type; |
| 1295 | } | 1295 | } |
| 1296 | 1296 | ||
| 1297 | ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | 1297 | ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| ... | @@ -1342,11 +1342,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou | ... | @@ -1342,11 +1342,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 1342 | } | 1342 | } |
| 1343 | 1343 | ||
| 1344 | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { | 1344 | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { |
| 1345 | IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); | 1345 | ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); |
| 1346 | if (type_is_invalid(align_result->value.type)) | 1346 | if (type_is_invalid(align_result->type)) |
| 1347 | return false; | 1347 | return false; |
| 1348 | 1348 | ||
| 1349 | uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); | 1349 | uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint); |
| 1350 | if (align_bytes == 0) { | 1350 | if (align_bytes == 0) { |
| 1351 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); | 1351 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 1352 | return false; | 1352 | return false; |
| ... | @@ -1364,12 +1364,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** | ... | @@ -1364,12 +1364,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1364 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, | 1364 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, |
| 1365 | PtrLenUnknown, 0, 0, 0); | 1365 | PtrLenUnknown, 0, 0, 0); |
| 1366 | ZigType *str_type = get_slice_type(g, ptr_type); | 1366 | ZigType *str_type = get_slice_type(g, ptr_type); |
| 1367 | IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); | 1367 | ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); |
| 1368 | if (type_is_invalid(instr->value.type)) | 1368 | if (type_is_invalid(result_val->type)) |
| 1369 | return false; | 1369 | return false; |
| 1370 | 1370 | ||
| 1371 | ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; | 1371 | ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index]; |
| 1372 | ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; | 1372 | ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index]; |
| 1373 | 1373 | ||
| 1374 | assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); | 1374 | assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 1375 | ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; | 1375 | ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; |
| ... | @@ -1422,6 +1422,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { | ... | @@ -1422,6 +1422,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { |
| 1422 | case ZigTypeIdPointer: | 1422 | case ZigTypeIdPointer: |
| 1423 | case ZigTypeIdArray: | 1423 | case ZigTypeIdArray: |
| 1424 | case ZigTypeIdFn: | 1424 | case ZigTypeIdFn: |
| 1425 | case ZigTypeIdVector: | ||
| 1425 | return true; | 1426 | return true; |
| 1426 | case ZigTypeIdStruct: | 1427 | case ZigTypeIdStruct: |
| 1427 | return type_entry->data.structure.layout == ContainerLayoutPacked; | 1428 | return type_entry->data.structure.layout == ContainerLayoutPacked; |
| ... | @@ -1470,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { | ... | @@ -1470,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { |
| 1470 | default: | 1471 | default: |
| 1471 | return false; | 1472 | return false; |
| 1472 | } | 1473 | } |
| 1474 | case ZigTypeIdVector: | ||
| 1475 | return type_allowed_in_extern(g, type_entry->data.vector.elem_type); | ||
| 1473 | case ZigTypeIdFloat: | 1476 | case ZigTypeIdFloat: |
| 1474 | return true; | 1477 | return true; |
| 1475 | case ZigTypeIdArray: | 1478 | case ZigTypeIdArray: |
| ... | @@ -1623,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc | ... | @@ -1623,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1623 | case ZigTypeIdUnion: | 1626 | case ZigTypeIdUnion: |
| 1624 | case ZigTypeIdFn: | 1627 | case ZigTypeIdFn: |
| 1625 | case ZigTypeIdPromise: | 1628 | case ZigTypeIdPromise: |
| 1629 | case ZigTypeIdVector: | ||
| 1626 | switch (type_requires_comptime(g, type_entry)) { | 1630 | switch (type_requires_comptime(g, type_entry)) { |
| 1627 | case ReqCompTimeNo: | 1631 | case ReqCompTimeNo: |
| 1628 | break; | 1632 | break; |
| ... | @@ -1718,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc | ... | @@ -1718,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1718 | case ZigTypeIdUnion: | 1722 | case ZigTypeIdUnion: |
| 1719 | case ZigTypeIdFn: | 1723 | case ZigTypeIdFn: |
| 1720 | case ZigTypeIdPromise: | 1724 | case ZigTypeIdPromise: |
| 1725 | case ZigTypeIdVector: | ||
| 1721 | switch (type_requires_comptime(g, fn_type_id.return_type)) { | 1726 | switch (type_requires_comptime(g, fn_type_id.return_type)) { |
| 1722 | case ReqCompTimeInvalid: | 1727 | case ReqCompTimeInvalid: |
| 1723 | return g->builtin_types.entry_invalid; | 1728 | return g->builtin_types.entry_invalid; |
| ... | @@ -2504,20 +2509,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -2504,20 +2509,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2504 | // In this first pass we resolve explicit tag values. | 2509 | // In this first pass we resolve explicit tag values. |
| 2505 | // In a second pass we will fill in the unspecified ones. | 2510 | // In a second pass we will fill in the unspecified ones. |
| 2506 | if (tag_value != nullptr) { | 2511 | if (tag_value != nullptr) { |
| 2507 | IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | 2512 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); |
| 2508 | if (result_inst->value.type->id == ZigTypeIdInvalid) { | 2513 | if (type_is_invalid(result->type)) { |
| 2509 | enum_type->data.enumeration.is_invalid = true; | 2514 | enum_type->data.enumeration.is_invalid = true; |
| 2510 | continue; | 2515 | continue; |
| 2511 | } | 2516 | } |
| 2512 | assert(result_inst->value.special != ConstValSpecialRuntime); | 2517 | assert(result->special != ConstValSpecialRuntime); |
| 2513 | assert(result_inst->value.type->id == ZigTypeIdInt || | 2518 | assert(result->type->id == ZigTypeIdInt || |
| 2514 | result_inst->value.type->id == ZigTypeIdComptimeInt); | 2519 | result->type->id == ZigTypeIdComptimeInt); |
| 2515 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | 2520 | auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); |
| 2516 | if (entry == nullptr) { | 2521 | if (entry == nullptr) { |
| 2517 | bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint); | 2522 | bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); |
| 2518 | } else { | 2523 | } else { |
| 2519 | Buf *val_buf = buf_alloc(); | 2524 | Buf *val_buf = buf_alloc(); |
| 2520 | bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); | 2525 | bigint_append_buf(val_buf, &result->data.x_bigint, 10); |
| 2521 | 2526 | ||
| 2522 | ErrorMsg *msg = add_node_error(g, tag_value, | 2527 | ErrorMsg *msg = add_node_error(g, tag_value, |
| 2523 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); | 2528 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); |
| ... | @@ -2944,19 +2949,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2944,19 +2949,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2944 | // In a second pass we will fill in the unspecified ones. | 2949 | // In a second pass we will fill in the unspecified ones. |
| 2945 | if (tag_value != nullptr) { | 2950 | if (tag_value != nullptr) { |
| 2946 | ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; | 2951 | ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; |
| 2947 | IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | 2952 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); |
| 2948 | if (result_inst->value.type->id == ZigTypeIdInvalid) { | 2953 | if (type_is_invalid(result->type)) { |
| 2949 | union_type->data.unionation.is_invalid = true; | 2954 | union_type->data.unionation.is_invalid = true; |
| 2950 | continue; | 2955 | continue; |
| 2951 | } | 2956 | } |
| 2952 | assert(result_inst->value.special != ConstValSpecialRuntime); | 2957 | assert(result->special != ConstValSpecialRuntime); |
| 2953 | assert(result_inst->value.type->id == ZigTypeIdInt); | 2958 | assert(result->type->id == ZigTypeIdInt); |
| 2954 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | 2959 | auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); |
| 2955 | if (entry == nullptr) { | 2960 | if (entry == nullptr) { |
| 2956 | bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint); | 2961 | bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); |
| 2957 | } else { | 2962 | } else { |
| 2958 | Buf *val_buf = buf_alloc(); | 2963 | Buf *val_buf = buf_alloc(); |
| 2959 | bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); | 2964 | bigint_append_buf(val_buf, &result->data.x_bigint, 10); |
| 2960 | 2965 | ||
| 2961 | ErrorMsg *msg = add_node_error(g, tag_value, | 2966 | ErrorMsg *msg = add_node_error(g, tag_value, |
| 2962 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); | 2967 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); |
| ... | @@ -3419,7 +3424,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { | ... | @@ -3419,7 +3424,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { |
| 3419 | resolve_top_level_decl(g, tld, false, tld->source_node); | 3424 | resolve_top_level_decl(g, tld, false, tld->source_node); |
| 3420 | assert(tld->id == TldIdVar); | 3425 | assert(tld->id == TldIdVar); |
| 3421 | TldVar *tld_var = (TldVar *)tld; | 3426 | TldVar *tld_var = (TldVar *)tld; |
| 3422 | tld_var->var->value = value; | 3427 | tld_var->var->const_value = value; |
| 3428 | tld_var->var->var_type = value->type; | ||
| 3423 | tld_var->var->align_bytes = get_abi_alignment(g, value->type); | 3429 | tld_var->var->align_bytes = get_abi_alignment(g, value->type); |
| 3424 | } | 3430 | } |
| 3425 | 3431 | ||
| ... | @@ -3513,7 +3519,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -3513,7 +3519,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3513 | case NodeTypeArrayType: | 3519 | case NodeTypeArrayType: |
| 3514 | case NodeTypeErrorType: | 3520 | case NodeTypeErrorType: |
| 3515 | case NodeTypeIfErrorExpr: | 3521 | case NodeTypeIfErrorExpr: |
| 3516 | case NodeTypeTestExpr: | 3522 | case NodeTypeIfOptional: |
| 3517 | case NodeTypeErrorSetDecl: | 3523 | case NodeTypeErrorSetDecl: |
| 3518 | case NodeTypeCancel: | 3524 | case NodeTypeCancel: |
| 3519 | case NodeTypeResume: | 3525 | case NodeTypeResume: |
| ... | @@ -3574,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry | ... | @@ -3574,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry |
| 3574 | case ZigTypeIdFn: | 3580 | case ZigTypeIdFn: |
| 3575 | case ZigTypeIdBoundFn: | 3581 | case ZigTypeIdBoundFn: |
| 3576 | case ZigTypeIdPromise: | 3582 | case ZigTypeIdPromise: |
| 3583 | case ZigTypeIdVector: | ||
| 3577 | return type_entry; | 3584 | return type_entry; |
| 3578 | } | 3585 | } |
| 3579 | zig_unreachable(); | 3586 | zig_unreachable(); |
| ... | @@ -3582,13 +3589,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry | ... | @@ -3582,13 +3589,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry |
| 3582 | // Set name to nullptr to make the variable anonymous (not visible to programmer). | 3589 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 3583 | // TODO merge with definition of add_local_var in ir.cpp | 3590 | // TODO merge with definition of add_local_var in ir.cpp |
| 3584 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, | 3591 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, |
| 3585 | bool is_const, ConstExprValue *value, Tld *src_tld) | 3592 | bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type) |
| 3586 | { | 3593 | { |
| 3587 | Error err; | 3594 | Error err; |
| 3588 | assert(value); | 3595 | assert(const_value != nullptr); |
| 3596 | assert(var_type != nullptr); | ||
| 3589 | 3597 | ||
| 3590 | ZigVar *variable_entry = allocate<ZigVar>(1); | 3598 | ZigVar *variable_entry = allocate<ZigVar>(1); |
| 3591 | variable_entry->value = value; | 3599 | variable_entry->const_value = const_value; |
| 3600 | variable_entry->var_type = var_type; | ||
| 3592 | variable_entry->parent_scope = parent_scope; | 3601 | variable_entry->parent_scope = parent_scope; |
| 3593 | variable_entry->shadowable = false; | 3602 | variable_entry->shadowable = false; |
| 3594 | variable_entry->mem_slot_index = SIZE_MAX; | 3603 | variable_entry->mem_slot_index = SIZE_MAX; |
| ... | @@ -3597,23 +3606,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3597,23 +3606,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3597 | assert(name); | 3606 | assert(name); |
| 3598 | buf_init_from_buf(&variable_entry->name, name); | 3607 | buf_init_from_buf(&variable_entry->name, name); |
| 3599 | 3608 | ||
| 3600 | if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) { | 3609 | if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { |
| 3601 | variable_entry->value->type = g->builtin_types.entry_invalid; | 3610 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 3602 | } else { | 3611 | } else { |
| 3603 | variable_entry->align_bytes = get_abi_alignment(g, value->type); | 3612 | variable_entry->align_bytes = get_abi_alignment(g, var_type); |
| 3604 | 3613 | ||
| 3605 | ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); | 3614 | ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); |
| 3606 | if (existing_var && !existing_var->shadowable) { | 3615 | if (existing_var && !existing_var->shadowable) { |
| 3607 | ErrorMsg *msg = add_node_error(g, source_node, | 3616 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3608 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 3617 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 3609 | add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); | 3618 | add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 3610 | variable_entry->value->type = g->builtin_types.entry_invalid; | 3619 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 3611 | } else { | 3620 | } else { |
| 3612 | ZigType *type; | 3621 | ZigType *type; |
| 3613 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { | 3622 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { |
| 3614 | add_node_error(g, source_node, | 3623 | add_node_error(g, source_node, |
| 3615 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | 3624 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); |
| 3616 | variable_entry->value->type = g->builtin_types.entry_invalid; | 3625 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 3617 | } else { | 3626 | } else { |
| 3618 | Scope *search_scope = nullptr; | 3627 | Scope *search_scope = nullptr; |
| 3619 | if (src_tld == nullptr) { | 3628 | if (src_tld == nullptr) { |
| ... | @@ -3627,7 +3636,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3627,7 +3636,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3627 | ErrorMsg *msg = add_node_error(g, source_node, | 3636 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3628 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 3637 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 3629 | add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); | 3638 | add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); |
| 3630 | variable_entry->value->type = g->builtin_types.entry_invalid; | 3639 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 3631 | } | 3640 | } |
| 3632 | } | 3641 | } |
| 3633 | } | 3642 | } |
| ... | @@ -3677,7 +3686,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3677,7 +3686,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3677 | linkage = VarLinkageInternal; | 3686 | linkage = VarLinkageInternal; |
| 3678 | } | 3687 | } |
| 3679 | 3688 | ||
| 3680 | IrInstruction *init_value = nullptr; | 3689 | ConstExprValue *init_value = nullptr; |
| 3681 | 3690 | ||
| 3682 | // TODO more validation for types that can't be used for export/extern variables | 3691 | // TODO more validation for types that can't be used for export/extern variables |
| 3683 | ZigType *implicit_type = nullptr; | 3692 | ZigType *implicit_type = nullptr; |
| ... | @@ -3686,7 +3695,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3686,7 +3695,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3686 | } else if (var_decl->expr) { | 3695 | } else if (var_decl->expr) { |
| 3687 | init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); | 3696 | init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); |
| 3688 | assert(init_value); | 3697 | assert(init_value); |
| 3689 | implicit_type = init_value->value.type; | 3698 | implicit_type = init_value->type; |
| 3690 | 3699 | ||
| 3691 | if (implicit_type->id == ZigTypeIdUnreachable) { | 3700 | if (implicit_type->id == ZigTypeIdUnreachable) { |
| 3692 | add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); | 3701 | add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); |
| ... | @@ -3704,7 +3713,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3704,7 +3713,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3704 | add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); | 3713 | add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); |
| 3705 | implicit_type = g->builtin_types.entry_invalid; | 3714 | implicit_type = g->builtin_types.entry_invalid; |
| 3706 | } | 3715 | } |
| 3707 | assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime); | 3716 | assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); |
| 3708 | } else if (linkage != VarLinkageExternal) { | 3717 | } else if (linkage != VarLinkageExternal) { |
| 3709 | add_node_error(g, source_node, buf_sprintf("variables must be initialized")); | 3718 | add_node_error(g, source_node, buf_sprintf("variables must be initialized")); |
| 3710 | implicit_type = g->builtin_types.entry_invalid; | 3719 | implicit_type = g->builtin_types.entry_invalid; |
| ... | @@ -3713,19 +3722,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3713,19 +3722,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3713 | ZigType *type = explicit_type ? explicit_type : implicit_type; | 3722 | ZigType *type = explicit_type ? explicit_type : implicit_type; |
| 3714 | assert(type != nullptr); // should have been caught by the parser | 3723 | assert(type != nullptr); // should have been caught by the parser |
| 3715 | 3724 | ||
| 3716 | ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type); | 3725 | ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type); |
| 3717 | 3726 | ||
| 3718 | tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, | 3727 | tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, |
| 3719 | is_const, init_val, &tld_var->base); | 3728 | is_const, init_val, &tld_var->base, type); |
| 3720 | tld_var->var->linkage = linkage; | 3729 | tld_var->var->linkage = linkage; |
| 3721 | 3730 | ||
| 3722 | if (implicit_type != nullptr && type_is_invalid(implicit_type)) { | 3731 | if (implicit_type != nullptr && type_is_invalid(implicit_type)) { |
| 3723 | tld_var->var->value->type = g->builtin_types.entry_invalid; | 3732 | tld_var->var->var_type = g->builtin_types.entry_invalid; |
| 3724 | } | 3733 | } |
| 3725 | 3734 | ||
| 3726 | if (var_decl->align_expr != nullptr) { | 3735 | if (var_decl->align_expr != nullptr) { |
| 3727 | if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { | 3736 | if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { |
| 3728 | tld_var->var->value->type = g->builtin_types.entry_invalid; | 3737 | tld_var->var->var_type = g->builtin_types.entry_invalid; |
| 3729 | } | 3738 | } |
| 3730 | } | 3739 | } |
| 3731 | 3740 | ||
| ... | @@ -3938,6 +3947,7 @@ static bool is_container(ZigType *type_entry) { | ... | @@ -3938,6 +3947,7 @@ static bool is_container(ZigType *type_entry) { |
| 3938 | case ZigTypeIdArgTuple: | 3947 | case ZigTypeIdArgTuple: |
| 3939 | case ZigTypeIdOpaque: | 3948 | case ZigTypeIdOpaque: |
| 3940 | case ZigTypeIdPromise: | 3949 | case ZigTypeIdPromise: |
| 3950 | case ZigTypeIdVector: | ||
| 3941 | return false; | 3951 | return false; |
| 3942 | } | 3952 | } |
| 3943 | zig_unreachable(); | 3953 | zig_unreachable(); |
| ... | @@ -3997,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { | ... | @@ -3997,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { |
| 3997 | case ZigTypeIdArgTuple: | 4007 | case ZigTypeIdArgTuple: |
| 3998 | case ZigTypeIdOpaque: | 4008 | case ZigTypeIdOpaque: |
| 3999 | case ZigTypeIdPromise: | 4009 | case ZigTypeIdPromise: |
| 4010 | case ZigTypeIdVector: | ||
| 4000 | zig_unreachable(); | 4011 | zig_unreachable(); |
| 4001 | } | 4012 | } |
| 4002 | } | 4013 | } |
| ... | @@ -4090,7 +4101,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -4090,7 +4101,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { |
| 4090 | } | 4101 | } |
| 4091 | 4102 | ||
| 4092 | ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, | 4103 | ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, |
| 4093 | param_name, true, create_const_runtime(param_type), nullptr); | 4104 | param_name, true, create_const_runtime(param_type), nullptr, param_type); |
| 4094 | var->src_arg_index = i; | 4105 | var->src_arg_index = i; |
| 4095 | fn_table_entry->child_scope = var->child_scope; | 4106 | fn_table_entry->child_scope = var->child_scope; |
| 4096 | var->shadowable = var->shadowable || is_var_args; | 4107 | var->shadowable = var->shadowable || is_var_args; |
| ... | @@ -4228,18 +4239,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * | ... | @@ -4228,18 +4239,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * |
| 4228 | preview_use_decl(g, src_use_node); | 4239 | preview_use_decl(g, src_use_node); |
| 4229 | } | 4240 | } |
| 4230 | 4241 | ||
| 4231 | IrInstruction *use_target_value = src_use_node->data.use.value; | 4242 | ConstExprValue *use_target_value = src_use_node->data.use.value; |
| 4232 | if (use_target_value->value.type->id == ZigTypeIdInvalid) { | 4243 | if (type_is_invalid(use_target_value->type)) { |
| 4233 | dst_use_node->owner->any_imports_failed = true; | 4244 | dst_use_node->owner->any_imports_failed = true; |
| 4234 | return; | 4245 | return; |
| 4235 | } | 4246 | } |
| 4236 | 4247 | ||
| 4237 | dst_use_node->data.use.resolution = TldResolutionOk; | 4248 | dst_use_node->data.use.resolution = TldResolutionOk; |
| 4238 | 4249 | ||
| 4239 | ConstExprValue *const_val = &use_target_value->value; | 4250 | assert(use_target_value->special != ConstValSpecialRuntime); |
| 4240 | assert(const_val->special != ConstValSpecialRuntime); | ||
| 4241 | 4251 | ||
| 4242 | ImportTableEntry *target_import = const_val->data.x_import; | 4252 | ImportTableEntry *target_import = use_target_value->data.x_import; |
| 4243 | assert(target_import); | 4253 | assert(target_import); |
| 4244 | 4254 | ||
| 4245 | if (target_import->any_imports_failed) { | 4255 | if (target_import->any_imports_failed) { |
| ... | @@ -4302,10 +4312,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { | ... | @@ -4302,10 +4312,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { |
| 4302 | } | 4312 | } |
| 4303 | 4313 | ||
| 4304 | node->data.use.resolution = TldResolutionResolving; | 4314 | node->data.use.resolution = TldResolutionResolving; |
| 4305 | IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, | 4315 | ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base, |
| 4306 | node->data.use.expr, g->builtin_types.entry_namespace, nullptr); | 4316 | node->data.use.expr, g->builtin_types.entry_namespace, nullptr); |
| 4307 | 4317 | ||
| 4308 | if (result->value.type->id == ZigTypeIdInvalid) | 4318 | if (type_is_invalid(result->type)) |
| 4309 | node->owner->any_imports_failed = true; | 4319 | node->owner->any_imports_failed = true; |
| 4310 | 4320 | ||
| 4311 | node->data.use.value = result; | 4321 | node->data.use.value = result; |
| ... | @@ -4447,6 +4457,42 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { | ... | @@ -4447,6 +4457,42 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 4447 | return new_entry; | 4457 | return new_entry; |
| 4448 | } | 4458 | } |
| 4449 | 4459 | ||
| 4460 | bool is_valid_vector_elem_type(ZigType *elem_type) { | ||
| 4461 | return elem_type->id == ZigTypeIdInt || | ||
| 4462 | elem_type->id == ZigTypeIdFloat || | ||
| 4463 | get_codegen_ptr_type(elem_type) != nullptr; | ||
| 4464 | } | ||
| 4465 | |||
| 4466 | ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { | ||
| 4467 | assert(is_valid_vector_elem_type(elem_type)); | ||
| 4468 | |||
| 4469 | TypeId type_id = {}; | ||
| 4470 | type_id.id = ZigTypeIdVector; | ||
| 4471 | type_id.data.vector.len = len; | ||
| 4472 | type_id.data.vector.elem_type = elem_type; | ||
| 4473 | |||
| 4474 | { | ||
| 4475 | auto entry = g->type_table.maybe_get(type_id); | ||
| 4476 | if (entry) | ||
| 4477 | return entry->value; | ||
| 4478 | } | ||
| 4479 | |||
| 4480 | ZigType *entry = new_type_table_entry(ZigTypeIdVector); | ||
| 4481 | entry->zero_bits = (len == 0) || !type_has_bits(elem_type); | ||
| 4482 | entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len); | ||
| 4483 | entry->data.vector.len = len; | ||
| 4484 | entry->data.vector.elem_type = elem_type; | ||
| 4485 | |||
| 4486 | buf_resize(&entry->name, 0); | ||
| 4487 | buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); | ||
| 4488 | |||
| 4489 | entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len, | ||
| 4490 | LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type); | ||
| 4491 | |||
| 4492 | g->type_table.put(type_id, entry); | ||
| 4493 | return entry; | ||
| 4494 | } | ||
| 4495 | |||
| 4450 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { | 4496 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { |
| 4451 | return &g->builtin_types.entry_c_int[c_int_type]; | 4497 | return &g->builtin_types.entry_c_int[c_int_type]; |
| 4452 | } | 4498 | } |
| ... | @@ -4478,6 +4524,7 @@ bool handle_is_ptr(ZigType *type_entry) { | ... | @@ -4478,6 +4524,7 @@ bool handle_is_ptr(ZigType *type_entry) { |
| 4478 | case ZigTypeIdFn: | 4524 | case ZigTypeIdFn: |
| 4479 | case ZigTypeIdEnum: | 4525 | case ZigTypeIdEnum: |
| 4480 | case ZigTypeIdPromise: | 4526 | case ZigTypeIdPromise: |
| 4527 | case ZigTypeIdVector: | ||
| 4481 | return false; | 4528 | return false; |
| 4482 | case ZigTypeIdArray: | 4529 | case ZigTypeIdArray: |
| 4483 | case ZigTypeIdStruct: | 4530 | case ZigTypeIdStruct: |
| ... | @@ -4486,7 +4533,8 @@ bool handle_is_ptr(ZigType *type_entry) { | ... | @@ -4486,7 +4533,8 @@ bool handle_is_ptr(ZigType *type_entry) { |
| 4486 | return type_has_bits(type_entry->data.error_union.payload_type); | 4533 | return type_has_bits(type_entry->data.error_union.payload_type); |
| 4487 | case ZigTypeIdOptional: | 4534 | case ZigTypeIdOptional: |
| 4488 | return type_has_bits(type_entry->data.maybe.child_type) && | 4535 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 4489 | !type_is_codegen_pointer(type_entry->data.maybe.child_type); | 4536 | !type_is_codegen_pointer(type_entry->data.maybe.child_type) && |
| 4537 | type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet; | ||
| 4490 | case ZigTypeIdUnion: | 4538 | case ZigTypeIdUnion: |
| 4491 | assert(type_entry->data.unionation.zero_bits_known); | 4539 | assert(type_entry->data.unionation.zero_bits_known); |
| 4492 | if (type_entry->data.unionation.gen_field_count == 0) | 4540 | if (type_entry->data.unionation.gen_field_count == 0) |
| ... | @@ -4732,6 +4780,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { | ... | @@ -4732,6 +4780,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { |
| 4732 | return true; | 4780 | return true; |
| 4733 | } | 4781 | } |
| 4734 | 4782 | ||
| 4783 | static uint32_t hash_const_val_error_set(ConstExprValue *const_val) { | ||
| 4784 | assert(const_val->data.x_err_set != nullptr); | ||
| 4785 | return const_val->data.x_err_set->value ^ 2630160122; | ||
| 4786 | } | ||
| 4787 | |||
| 4735 | static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { | 4788 | static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { |
| 4736 | uint32_t hash_val = 0; | 4789 | uint32_t hash_val = 0; |
| 4737 | switch (const_val->data.x_ptr.mut) { | 4790 | switch (const_val->data.x_ptr.mut) { |
| ... | @@ -4763,6 +4816,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { | ... | @@ -4763,6 +4816,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { |
| 4763 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); | 4816 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); |
| 4764 | hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); | 4817 | hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); |
| 4765 | return hash_val; | 4818 | return hash_val; |
| 4819 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 4820 | hash_val += (uint32_t)2994743799; | ||
| 4821 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val); | ||
| 4822 | return hash_val; | ||
| 4823 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 4824 | hash_val += (uint32_t)3456080131; | ||
| 4825 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val); | ||
| 4826 | return hash_val; | ||
| 4827 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 4828 | hash_val += (uint32_t)3163140517; | ||
| 4829 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val); | ||
| 4830 | return hash_val; | ||
| 4766 | case ConstPtrSpecialHardCodedAddr: | 4831 | case ConstPtrSpecialHardCodedAddr: |
| 4767 | hash_val += (uint32_t)4048518294; | 4832 | hash_val += (uint32_t)4048518294; |
| 4768 | hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); | 4833 | hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); |
| ... | @@ -4774,6 +4839,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { | ... | @@ -4774,6 +4839,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { |
| 4774 | hash_val += (uint32_t)2590901619; | 4839 | hash_val += (uint32_t)2590901619; |
| 4775 | hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); | 4840 | hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); |
| 4776 | return hash_val; | 4841 | return hash_val; |
| 4842 | case ConstPtrSpecialNull: | ||
| 4843 | hash_val += (uint32_t)1486246455; | ||
| 4844 | return hash_val; | ||
| 4777 | } | 4845 | } |
| 4778 | zig_unreachable(); | 4846 | zig_unreachable(); |
| 4779 | } | 4847 | } |
| ... | @@ -4872,7 +4940,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { | ... | @@ -4872,7 +4940,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 4872 | return 2709806591; | 4940 | return 2709806591; |
| 4873 | case ZigTypeIdOptional: | 4941 | case ZigTypeIdOptional: |
| 4874 | if (get_codegen_ptr_type(const_val->type) != nullptr) { | 4942 | if (get_codegen_ptr_type(const_val->type) != nullptr) { |
| 4875 | return hash_const_val(const_val) * 1992916303; | 4943 | return hash_const_val_ptr(const_val) * 1992916303; |
| 4944 | } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { | ||
| 4945 | return hash_const_val_error_set(const_val) * 3147031929; | ||
| 4876 | } else { | 4946 | } else { |
| 4877 | if (const_val->data.x_optional) { | 4947 | if (const_val->data.x_optional) { |
| 4878 | return hash_const_val(const_val->data.x_optional) * 1992916303; | 4948 | return hash_const_val(const_val->data.x_optional) * 1992916303; |
| ... | @@ -4884,10 +4954,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { | ... | @@ -4884,10 +4954,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 4884 | // TODO better hashing algorithm | 4954 | // TODO better hashing algorithm |
| 4885 | return 3415065496; | 4955 | return 3415065496; |
| 4886 | case ZigTypeIdErrorSet: | 4956 | case ZigTypeIdErrorSet: |
| 4887 | assert(const_val->data.x_err_set != nullptr); | 4957 | return hash_const_val_error_set(const_val); |
| 4888 | return const_val->data.x_err_set->value ^ 2630160122; | ||
| 4889 | case ZigTypeIdNamespace: | 4958 | case ZigTypeIdNamespace: |
| 4890 | return hash_ptr(const_val->data.x_import); | 4959 | return hash_ptr(const_val->data.x_import); |
| 4960 | case ZigTypeIdVector: | ||
| 4961 | // TODO better hashing algorithm | ||
| 4962 | return 3647867726; | ||
| 4891 | case ZigTypeIdBoundFn: | 4963 | case ZigTypeIdBoundFn: |
| 4892 | case ZigTypeIdInvalid: | 4964 | case ZigTypeIdInvalid: |
| 4893 | case ZigTypeIdUnreachable: | 4965 | case ZigTypeIdUnreachable: |
| ... | @@ -4940,6 +5012,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { | ... | @@ -4940,6 +5012,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { |
| 4940 | case ZigTypeIdBool: | 5012 | case ZigTypeIdBool: |
| 4941 | case ZigTypeIdUnreachable: | 5013 | case ZigTypeIdUnreachable: |
| 4942 | case ZigTypeIdInt: | 5014 | case ZigTypeIdInt: |
| 5015 | case ZigTypeIdVector: | ||
| 4943 | case ZigTypeIdFloat: | 5016 | case ZigTypeIdFloat: |
| 4944 | case ZigTypeIdComptimeFloat: | 5017 | case ZigTypeIdComptimeFloat: |
| 4945 | case ZigTypeIdComptimeInt: | 5018 | case ZigTypeIdComptimeInt: |
| ... | @@ -4987,7 +5060,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { | ... | @@ -4987,7 +5060,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { |
| 4987 | return can_mutate_comptime_var_state(value->data.x_optional); | 5060 | return can_mutate_comptime_var_state(value->data.x_optional); |
| 4988 | 5061 | ||
| 4989 | case ZigTypeIdErrorUnion: | 5062 | case ZigTypeIdErrorUnion: |
| 4990 | if (value->data.x_err_union.err != nullptr) | 5063 | if (value->data.x_err_union.error_set->data.x_err_set != nullptr) |
| 4991 | return false; | 5064 | return false; |
| 4992 | assert(value->data.x_err_union.payload != nullptr); | 5065 | assert(value->data.x_err_union.payload != nullptr); |
| 4993 | return can_mutate_comptime_var_state(value->data.x_err_union.payload); | 5066 | return can_mutate_comptime_var_state(value->data.x_err_union.payload); |
| ... | @@ -5023,6 +5096,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { | ... | @@ -5023,6 +5096,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { |
| 5023 | case ZigTypeIdErrorSet: | 5096 | case ZigTypeIdErrorSet: |
| 5024 | case ZigTypeIdEnum: | 5097 | case ZigTypeIdEnum: |
| 5025 | case ZigTypeIdPointer: | 5098 | case ZigTypeIdPointer: |
| 5099 | case ZigTypeIdVector: | ||
| 5026 | return true; | 5100 | return true; |
| 5027 | 5101 | ||
| 5028 | case ZigTypeIdArray: | 5102 | case ZigTypeIdArray: |
| ... | @@ -5048,9 +5122,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { | ... | @@ -5048,9 +5122,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { |
| 5048 | while (scope) { | 5122 | while (scope) { |
| 5049 | if (scope->id == ScopeIdVarDecl) { | 5123 | if (scope->id == ScopeIdVarDecl) { |
| 5050 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; | 5124 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; |
| 5051 | if (type_is_invalid(var_scope->var->value->type)) | 5125 | if (type_is_invalid(var_scope->var->var_type)) |
| 5052 | return false; | 5126 | return false; |
| 5053 | if (can_mutate_comptime_var_state(var_scope->var->value)) | 5127 | if (can_mutate_comptime_var_state(var_scope->var->const_value)) |
| 5054 | return false; | 5128 | return false; |
| 5055 | } else if (scope->id == ScopeIdFnDef) { | 5129 | } else if (scope->id == ScopeIdFnDef) { |
| 5056 | return true; | 5130 | return true; |
| ... | @@ -5068,7 +5142,7 @@ uint32_t fn_eval_hash(Scope* scope) { | ... | @@ -5068,7 +5142,7 @@ uint32_t fn_eval_hash(Scope* scope) { |
| 5068 | while (scope) { | 5142 | while (scope) { |
| 5069 | if (scope->id == ScopeIdVarDecl) { | 5143 | if (scope->id == ScopeIdVarDecl) { |
| 5070 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; | 5144 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; |
| 5071 | result += hash_const_val(var_scope->var->value); | 5145 | result += hash_const_val(var_scope->var->const_value); |
| 5072 | } else if (scope->id == ScopeIdFnDef) { | 5146 | } else if (scope->id == ScopeIdFnDef) { |
| 5073 | ScopeFnDef *fn_scope = (ScopeFnDef *)scope; | 5147 | ScopeFnDef *fn_scope = (ScopeFnDef *)scope; |
| 5074 | result += hash_ptr(fn_scope->fn_entry); | 5148 | result += hash_ptr(fn_scope->fn_entry); |
| ... | @@ -5092,10 +5166,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { | ... | @@ -5092,10 +5166,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { |
| 5092 | if (a->id == ScopeIdVarDecl) { | 5166 | if (a->id == ScopeIdVarDecl) { |
| 5093 | ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; | 5167 | ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; |
| 5094 | ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; | 5168 | ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; |
| 5095 | if (a_var_scope->var->value->type != b_var_scope->var->value->type) | 5169 | if (a_var_scope->var->var_type != b_var_scope->var->var_type) |
| 5096 | return false; | ||
| 5097 | if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value)) | ||
| 5098 | return false; | 5170 | return false; |
| 5171 | if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && | ||
| 5172 | b_var_scope->var->var_type == b_var_scope->var->const_value->type) | ||
| 5173 | { | ||
| 5174 | if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) | ||
| 5175 | return false; | ||
| 5176 | } else { | ||
| 5177 | zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); | ||
| 5178 | } | ||
| 5099 | } else if (a->id == ScopeIdFnDef) { | 5179 | } else if (a->id == ScopeIdFnDef) { |
| 5100 | ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; | 5180 | ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; |
| 5101 | ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; | 5181 | ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; |
| ... | @@ -5113,6 +5193,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { | ... | @@ -5113,6 +5193,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { |
| 5113 | return false; | 5193 | return false; |
| 5114 | } | 5194 | } |
| 5115 | 5195 | ||
| 5196 | // Whether the type has bits at runtime. | ||
| 5116 | bool type_has_bits(ZigType *type_entry) { | 5197 | bool type_has_bits(ZigType *type_entry) { |
| 5117 | assert(type_entry); | 5198 | assert(type_entry); |
| 5118 | assert(!type_is_invalid(type_entry)); | 5199 | assert(!type_is_invalid(type_entry)); |
| ... | @@ -5120,6 +5201,66 @@ bool type_has_bits(ZigType *type_entry) { | ... | @@ -5120,6 +5201,66 @@ bool type_has_bits(ZigType *type_entry) { |
| 5120 | return !type_entry->zero_bits; | 5201 | return !type_entry->zero_bits; |
| 5121 | } | 5202 | } |
| 5122 | 5203 | ||
| 5204 | // Whether you can infer the value based solely on the type. | ||
| 5205 | OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { | ||
| 5206 | assert(type_entry != nullptr); | ||
| 5207 | Error err; | ||
| 5208 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) | ||
| 5209 | return OnePossibleValueInvalid; | ||
| 5210 | switch (type_entry->id) { | ||
| 5211 | case ZigTypeIdInvalid: | ||
| 5212 | zig_unreachable(); | ||
| 5213 | case ZigTypeIdOpaque: | ||
| 5214 | case ZigTypeIdComptimeFloat: | ||
| 5215 | case ZigTypeIdComptimeInt: | ||
| 5216 | case ZigTypeIdMetaType: | ||
| 5217 | case ZigTypeIdNamespace: | ||
| 5218 | case ZigTypeIdBoundFn: | ||
| 5219 | case ZigTypeIdArgTuple: | ||
| 5220 | case ZigTypeIdOptional: | ||
| 5221 | case ZigTypeIdFn: | ||
| 5222 | case ZigTypeIdBool: | ||
| 5223 | case ZigTypeIdFloat: | ||
| 5224 | case ZigTypeIdPromise: | ||
| 5225 | case ZigTypeIdErrorUnion: | ||
| 5226 | return OnePossibleValueNo; | ||
| 5227 | case ZigTypeIdUndefined: | ||
| 5228 | case ZigTypeIdNull: | ||
| 5229 | case ZigTypeIdVoid: | ||
| 5230 | case ZigTypeIdUnreachable: | ||
| 5231 | return OnePossibleValueYes; | ||
| 5232 | case ZigTypeIdArray: | ||
| 5233 | if (type_entry->data.array.len == 0) | ||
| 5234 | return OnePossibleValueYes; | ||
| 5235 | return type_has_one_possible_value(g, type_entry->data.array.child_type); | ||
| 5236 | case ZigTypeIdStruct: | ||
| 5237 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { | ||
| 5238 | TypeStructField *field = &type_entry->data.structure.fields[i]; | ||
| 5239 | switch (type_has_one_possible_value(g, field->type_entry)) { | ||
| 5240 | case OnePossibleValueInvalid: | ||
| 5241 | return OnePossibleValueInvalid; | ||
| 5242 | case OnePossibleValueNo: | ||
| 5243 | return OnePossibleValueNo; | ||
| 5244 | case OnePossibleValueYes: | ||
| 5245 | continue; | ||
| 5246 | } | ||
| 5247 | } | ||
| 5248 | return OnePossibleValueYes; | ||
| 5249 | case ZigTypeIdErrorSet: | ||
| 5250 | case ZigTypeIdEnum: | ||
| 5251 | case ZigTypeIdInt: | ||
| 5252 | case ZigTypeIdVector: | ||
| 5253 | return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; | ||
| 5254 | case ZigTypeIdPointer: | ||
| 5255 | return type_has_one_possible_value(g, type_entry->data.pointer.child_type); | ||
| 5256 | case ZigTypeIdUnion: | ||
| 5257 | if (type_entry->data.unionation.src_field_count > 1) | ||
| 5258 | return OnePossibleValueNo; | ||
| 5259 | return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); | ||
| 5260 | } | ||
| 5261 | zig_unreachable(); | ||
| 5262 | } | ||
| 5263 | |||
| 5123 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { | 5264 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 5124 | Error err; | 5265 | Error err; |
| 5125 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) | 5266 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) |
| ... | @@ -5159,6 +5300,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { | ... | @@ -5159,6 +5300,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 5159 | case ZigTypeIdErrorSet: | 5300 | case ZigTypeIdErrorSet: |
| 5160 | case ZigTypeIdBool: | 5301 | case ZigTypeIdBool: |
| 5161 | case ZigTypeIdInt: | 5302 | case ZigTypeIdInt: |
| 5303 | case ZigTypeIdVector: | ||
| 5162 | case ZigTypeIdFloat: | 5304 | case ZigTypeIdFloat: |
| 5163 | case ZigTypeIdVoid: | 5305 | case ZigTypeIdVoid: |
| 5164 | case ZigTypeIdUnreachable: | 5306 | case ZigTypeIdUnreachable: |
| ... | @@ -5574,6 +5716,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { | ... | @@ -5574,6 +5716,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { |
| 5574 | if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) | 5716 | if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) |
| 5575 | return false; | 5717 | return false; |
| 5576 | return true; | 5718 | return true; |
| 5719 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 5720 | if (a->data.x_ptr.data.base_err_union_code.err_union_val != | ||
| 5721 | b->data.x_ptr.data.base_err_union_code.err_union_val && | ||
| 5722 | a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs != | ||
| 5723 | b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs) | ||
| 5724 | { | ||
| 5725 | return false; | ||
| 5726 | } | ||
| 5727 | return true; | ||
| 5728 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 5729 | if (a->data.x_ptr.data.base_err_union_payload.err_union_val != | ||
| 5730 | b->data.x_ptr.data.base_err_union_payload.err_union_val && | ||
| 5731 | a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs != | ||
| 5732 | b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs) | ||
| 5733 | { | ||
| 5734 | return false; | ||
| 5735 | } | ||
| 5736 | return true; | ||
| 5737 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 5738 | if (a->data.x_ptr.data.base_optional_payload.optional_val != | ||
| 5739 | b->data.x_ptr.data.base_optional_payload.optional_val && | ||
| 5740 | a->data.x_ptr.data.base_optional_payload.optional_val->global_refs != | ||
| 5741 | b->data.x_ptr.data.base_optional_payload.optional_val->global_refs) | ||
| 5742 | { | ||
| 5743 | return false; | ||
| 5744 | } | ||
| 5745 | return true; | ||
| 5577 | case ConstPtrSpecialHardCodedAddr: | 5746 | case ConstPtrSpecialHardCodedAddr: |
| 5578 | if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) | 5747 | if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) |
| 5579 | return false; | 5748 | return false; |
| ... | @@ -5582,10 +5751,34 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { | ... | @@ -5582,10 +5751,34 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { |
| 5582 | return true; | 5751 | return true; |
| 5583 | case ConstPtrSpecialFunction: | 5752 | case ConstPtrSpecialFunction: |
| 5584 | return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; | 5753 | return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; |
| 5754 | case ConstPtrSpecialNull: | ||
| 5755 | return true; | ||
| 5585 | } | 5756 | } |
| 5586 | zig_unreachable(); | 5757 | zig_unreachable(); |
| 5587 | } | 5758 | } |
| 5588 | 5759 | ||
| 5760 | static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprValue *b, size_t len) { | ||
| 5761 | assert(a->data.x_array.special != ConstArraySpecialUndef); | ||
| 5762 | assert(b->data.x_array.special != ConstArraySpecialUndef); | ||
| 5763 | if (a->data.x_array.special == ConstArraySpecialBuf && | ||
| 5764 | b->data.x_array.special == ConstArraySpecialBuf) | ||
| 5765 | { | ||
| 5766 | return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); | ||
| 5767 | } | ||
| 5768 | expand_undef_array(g, a); | ||
| 5769 | expand_undef_array(g, b); | ||
| 5770 | |||
| 5771 | ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; | ||
| 5772 | ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; | ||
| 5773 | |||
| 5774 | for (size_t i = 0; i < len; i += 1) { | ||
| 5775 | if (!const_values_equal(g, &a_elems[i], &b_elems[i])) | ||
| 5776 | return false; | ||
| 5777 | } | ||
| 5778 | |||
| 5779 | return true; | ||
| 5780 | } | ||
| 5781 | |||
| 5589 | bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { | 5782 | bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { |
| 5590 | assert(a->type->id == b->type->id); | 5783 | assert(a->type->id == b->type->id); |
| 5591 | assert(a->special == ConstValSpecialStatic); | 5784 | assert(a->special == ConstValSpecialStatic); |
| ... | @@ -5640,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { | ... | @@ -5640,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { |
| 5640 | case ZigTypeIdPointer: | 5833 | case ZigTypeIdPointer: |
| 5641 | case ZigTypeIdFn: | 5834 | case ZigTypeIdFn: |
| 5642 | return const_values_equal_ptr(a, b); | 5835 | return const_values_equal_ptr(a, b); |
| 5836 | case ZigTypeIdVector: | ||
| 5837 | assert(a->type->data.vector.len == b->type->data.vector.len); | ||
| 5838 | return const_values_equal_array(g, a, b, a->type->data.vector.len); | ||
| 5643 | case ZigTypeIdArray: { | 5839 | case ZigTypeIdArray: { |
| 5644 | assert(a->type->data.array.len == b->type->data.array.len); | 5840 | assert(a->type->data.array.len == b->type->data.array.len); |
| 5645 | assert(a->data.x_array.special != ConstArraySpecialUndef); | 5841 | return const_values_equal_array(g, a, b, a->type->data.array.len); |
| 5646 | assert(b->data.x_array.special != ConstArraySpecialUndef); | ||
| 5647 | if (a->data.x_array.special == ConstArraySpecialBuf && | ||
| 5648 | b->data.x_array.special == ConstArraySpecialBuf) | ||
| 5649 | { | ||
| 5650 | return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); | ||
| 5651 | } | ||
| 5652 | expand_undef_array(g, a); | ||
| 5653 | expand_undef_array(g, b); | ||
| 5654 | |||
| 5655 | size_t len = a->type->data.array.len; | ||
| 5656 | ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; | ||
| 5657 | ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; | ||
| 5658 | |||
| 5659 | for (size_t i = 0; i < len; ++i) { | ||
| 5660 | if (!const_values_equal(g, &a_elems[i], &b_elems[i])) | ||
| 5661 | return false; | ||
| 5662 | } | ||
| 5663 | |||
| 5664 | return true; | ||
| 5665 | } | 5842 | } |
| 5666 | case ZigTypeIdStruct: | 5843 | case ZigTypeIdStruct: |
| 5667 | for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { | 5844 | for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { |
| ... | @@ -5750,7 +5927,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v | ... | @@ -5750,7 +5927,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v |
| 5750 | } | 5927 | } |
| 5751 | } | 5928 | } |
| 5752 | 5929 | ||
| 5753 | void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { | 5930 | static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { |
| 5754 | assert(type_entry->id == ZigTypeIdPointer); | 5931 | assert(type_entry->id == ZigTypeIdPointer); |
| 5755 | 5932 | ||
| 5756 | if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { | 5933 | if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { |
| ... | @@ -5763,6 +5940,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy | ... | @@ -5763,6 +5940,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy |
| 5763 | zig_unreachable(); | 5940 | zig_unreachable(); |
| 5764 | case ConstPtrSpecialRef: | 5941 | case ConstPtrSpecialRef: |
| 5765 | case ConstPtrSpecialBaseStruct: | 5942 | case ConstPtrSpecialBaseStruct: |
| 5943 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 5944 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 5945 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 5766 | buf_appendf(buf, "*"); | 5946 | buf_appendf(buf, "*"); |
| 5767 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors | 5947 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors |
| 5768 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); | 5948 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); |
| ... | @@ -5790,6 +5970,51 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy | ... | @@ -5790,6 +5970,51 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy |
| 5790 | buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); | 5970 | buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); |
| 5791 | return; | 5971 | return; |
| 5792 | } | 5972 | } |
| 5973 | case ConstPtrSpecialNull: | ||
| 5974 | buf_append_str(buf, "null"); | ||
| 5975 | return; | ||
| 5976 | } | ||
| 5977 | zig_unreachable(); | ||
| 5978 | } | ||
| 5979 | |||
| 5980 | static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { | ||
| 5981 | if (const_val->data.x_err_set == nullptr) { | ||
| 5982 | buf_append_str(buf, "null"); | ||
| 5983 | } else { | ||
| 5984 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); | ||
| 5985 | } | ||
| 5986 | } | ||
| 5987 | |||
| 5988 | static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) { | ||
| 5989 | switch (const_val->data.x_array.special) { | ||
| 5990 | case ConstArraySpecialUndef: | ||
| 5991 | buf_append_str(buf, "undefined"); | ||
| 5992 | return; | ||
| 5993 | case ConstArraySpecialBuf: { | ||
| 5994 | Buf *array_buf = const_val->data.x_array.data.s_buf; | ||
| 5995 | buf_append_char(buf, '"'); | ||
| 5996 | for (size_t i = 0; i < buf_len(array_buf); i += 1) { | ||
| 5997 | uint8_t c = buf_ptr(array_buf)[i]; | ||
| 5998 | if (c == '"') { | ||
| 5999 | buf_append_str(buf, "\\\""); | ||
| 6000 | } else { | ||
| 6001 | buf_append_char(buf, c); | ||
| 6002 | } | ||
| 6003 | } | ||
| 6004 | buf_append_char(buf, '"'); | ||
| 6005 | return; | ||
| 6006 | } | ||
| 6007 | case ConstArraySpecialNone: { | ||
| 6008 | buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name)); | ||
| 6009 | for (uint64_t i = 0; i < len; i += 1) { | ||
| 6010 | if (i != 0) | ||
| 6011 | buf_appendf(buf, ","); | ||
| 6012 | ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; | ||
| 6013 | render_const_value(g, buf, child_value); | ||
| 6014 | } | ||
| 6015 | buf_appendf(buf, "}"); | ||
| 6016 | return; | ||
| 6017 | } | ||
| 5793 | } | 6018 | } |
| 5794 | zig_unreachable(); | 6019 | zig_unreachable(); |
| 5795 | } | 6020 | } |
| ... | @@ -5874,39 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5874,39 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5874 | } | 6099 | } |
| 5875 | case ZigTypeIdPointer: | 6100 | case ZigTypeIdPointer: |
| 5876 | return render_const_val_ptr(g, buf, const_val, type_entry); | 6101 | return render_const_val_ptr(g, buf, const_val, type_entry); |
| 6102 | case ZigTypeIdVector: | ||
| 6103 | return render_const_val_array(g, buf, const_val, type_entry->data.vector.len); | ||
| 5877 | case ZigTypeIdArray: | 6104 | case ZigTypeIdArray: |
| 5878 | switch (const_val->data.x_array.special) { | 6105 | return render_const_val_array(g, buf, const_val, type_entry->data.array.len); |
| 5879 | case ConstArraySpecialUndef: | ||
| 5880 | buf_append_str(buf, "undefined"); | ||
| 5881 | return; | ||
| 5882 | case ConstArraySpecialBuf: { | ||
| 5883 | Buf *array_buf = const_val->data.x_array.data.s_buf; | ||
| 5884 | buf_append_char(buf, '"'); | ||
| 5885 | for (size_t i = 0; i < buf_len(array_buf); i += 1) { | ||
| 5886 | uint8_t c = buf_ptr(array_buf)[i]; | ||
| 5887 | if (c == '"') { | ||
| 5888 | buf_append_str(buf, "\\\""); | ||
| 5889 | } else { | ||
| 5890 | buf_append_char(buf, c); | ||
| 5891 | } | ||
| 5892 | } | ||
| 5893 | buf_append_char(buf, '"'); | ||
| 5894 | return; | ||
| 5895 | } | ||
| 5896 | case ConstArraySpecialNone: { | ||
| 5897 | buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); | ||
| 5898 | uint64_t len = type_entry->data.array.len; | ||
| 5899 | for (uint64_t i = 0; i < len; i += 1) { | ||
| 5900 | if (i != 0) | ||
| 5901 | buf_appendf(buf, ","); | ||
| 5902 | ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; | ||
| 5903 | render_const_value(g, buf, child_value); | ||
| 5904 | } | ||
| 5905 | buf_appendf(buf, "}"); | ||
| 5906 | return; | ||
| 5907 | } | ||
| 5908 | } | ||
| 5909 | zig_unreachable(); | ||
| 5910 | case ZigTypeIdNull: | 6106 | case ZigTypeIdNull: |
| 5911 | { | 6107 | { |
| 5912 | buf_appendf(buf, "null"); | 6108 | buf_appendf(buf, "null"); |
| ... | @@ -5921,6 +6117,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5921,6 +6117,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5921 | { | 6117 | { |
| 5922 | if (get_codegen_ptr_type(const_val->type) != nullptr) | 6118 | if (get_codegen_ptr_type(const_val->type) != nullptr) |
| 5923 | return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); | 6119 | return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); |
| 6120 | if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) | ||
| 6121 | return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); | ||
| 5924 | if (const_val->data.x_optional) { | 6122 | if (const_val->data.x_optional) { |
| 5925 | render_const_value(g, buf, const_val->data.x_optional); | 6123 | render_const_value(g, buf, const_val->data.x_optional); |
| 5926 | } else { | 6124 | } else { |
| ... | @@ -5958,11 +6156,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5958,11 +6156,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5958 | case ZigTypeIdErrorUnion: | 6156 | case ZigTypeIdErrorUnion: |
| 5959 | { | 6157 | { |
| 5960 | buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); | 6158 | buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); |
| 5961 | if (const_val->data.x_err_union.err == nullptr) { | 6159 | ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; |
| 6160 | if (err_set == nullptr) { | ||
| 5962 | render_const_value(g, buf, const_val->data.x_err_union.payload); | 6161 | render_const_value(g, buf, const_val->data.x_err_union.payload); |
| 5963 | } else { | 6162 | } else { |
| 5964 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), | 6163 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), |
| 5965 | buf_ptr(&const_val->data.x_err_union.err->name)); | 6164 | buf_ptr(&err_set->name)); |
| 5966 | } | 6165 | } |
| 5967 | buf_appendf(buf, ")"); | 6166 | buf_appendf(buf, ")"); |
| 5968 | return; | 6167 | return; |
| ... | @@ -5977,10 +6176,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5977,10 +6176,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5977 | return; | 6176 | return; |
| 5978 | } | 6177 | } |
| 5979 | case ZigTypeIdErrorSet: | 6178 | case ZigTypeIdErrorSet: |
| 5980 | { | 6179 | return render_const_val_err_set(g, buf, const_val, type_entry); |
| 5981 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); | ||
| 5982 | return; | ||
| 5983 | } | ||
| 5984 | case ZigTypeIdArgTuple: | 6180 | case ZigTypeIdArgTuple: |
| 5985 | { | 6181 | { |
| 5986 | buf_appendf(buf, "(args value)"); | 6182 | buf_appendf(buf, "(args value)"); |
| ... | @@ -6065,6 +6261,8 @@ uint32_t type_id_hash(TypeId x) { | ... | @@ -6065,6 +6261,8 @@ uint32_t type_id_hash(TypeId x) { |
| 6065 | case ZigTypeIdInt: | 6261 | case ZigTypeIdInt: |
| 6066 | return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + | 6262 | return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + |
| 6067 | (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); | 6263 | (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); |
| 6264 | case ZigTypeIdVector: | ||
| 6265 | return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681); | ||
| 6068 | } | 6266 | } |
| 6069 | zig_unreachable(); | 6267 | zig_unreachable(); |
| 6070 | } | 6268 | } |
| ... | @@ -6113,6 +6311,9 @@ bool type_id_eql(TypeId a, TypeId b) { | ... | @@ -6113,6 +6311,9 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 6113 | case ZigTypeIdInt: | 6311 | case ZigTypeIdInt: |
| 6114 | return a.data.integer.is_signed == b.data.integer.is_signed && | 6312 | return a.data.integer.is_signed == b.data.integer.is_signed && |
| 6115 | a.data.integer.bit_count == b.data.integer.bit_count; | 6313 | a.data.integer.bit_count == b.data.integer.bit_count; |
| 6314 | case ZigTypeIdVector: | ||
| 6315 | return a.data.vector.elem_type == b.data.vector.elem_type && | ||
| 6316 | a.data.vector.len == b.data.vector.len; | ||
| 6116 | } | 6317 | } |
| 6117 | zig_unreachable(); | 6318 | zig_unreachable(); |
| 6118 | } | 6319 | } |
| ... | @@ -6171,24 +6372,34 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -6171,24 +6372,34 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6171 | 6372 | ||
| 6172 | // Canonicalize the array value as ConstArraySpecialNone | 6373 | // Canonicalize the array value as ConstArraySpecialNone |
| 6173 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { | 6374 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6174 | assert(const_val->type->id == ZigTypeIdArray); | 6375 | size_t elem_count; |
| 6376 | ZigType *elem_type; | ||
| 6377 | if (const_val->type->id == ZigTypeIdArray) { | ||
| 6378 | elem_count = const_val->type->data.array.len; | ||
| 6379 | elem_type = const_val->type->data.array.child_type; | ||
| 6380 | } else if (const_val->type->id == ZigTypeIdVector) { | ||
| 6381 | elem_count = const_val->type->data.vector.len; | ||
| 6382 | elem_type = const_val->type->data.vector.elem_type; | ||
| 6383 | } else { | ||
| 6384 | zig_unreachable(); | ||
| 6385 | } | ||
| 6386 | if (const_val->special == ConstValSpecialUndef) { | ||
| 6387 | const_val->special = ConstValSpecialStatic; | ||
| 6388 | const_val->data.x_array.special = ConstArraySpecialUndef; | ||
| 6389 | } | ||
| 6175 | switch (const_val->data.x_array.special) { | 6390 | switch (const_val->data.x_array.special) { |
| 6176 | case ConstArraySpecialNone: | 6391 | case ConstArraySpecialNone: |
| 6177 | return; | 6392 | return; |
| 6178 | case ConstArraySpecialUndef: { | 6393 | case ConstArraySpecialUndef: { |
| 6179 | const_val->data.x_array.special = ConstArraySpecialNone; | 6394 | const_val->data.x_array.special = ConstArraySpecialNone; |
| 6180 | size_t elem_count = const_val->type->data.array.len; | ||
| 6181 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); | 6395 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); |
| 6182 | for (size_t i = 0; i < elem_count; i += 1) { | 6396 | for (size_t i = 0; i < elem_count; i += 1) { |
| 6183 | ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; | 6397 | ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; |
| 6184 | element_val->type = const_val->type->data.array.child_type; | 6398 | element_val->type = elem_type; |
| 6185 | init_const_undefined(g, element_val); | 6399 | init_const_undefined(g, element_val); |
| 6186 | ConstParent *parent = get_const_val_parent(g, element_val); | 6400 | element_val->parent.id = ConstParentIdArray; |
| 6187 | if (parent != nullptr) { | 6401 | element_val->parent.data.p_array.array_val = const_val; |
| 6188 | parent->id = ConstParentIdArray; | 6402 | element_val->parent.data.p_array.elem_index = i; |
| 6189 | parent->data.p_array.array_val = const_val; | ||
| 6190 | parent->data.p_array.elem_index = i; | ||
| 6191 | } | ||
| 6192 | } | 6403 | } |
| 6193 | return; | 6404 | return; |
| 6194 | } | 6405 | } |
| ... | @@ -6199,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -6199,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6199 | g->string_literals_table.maybe_remove(buf); | 6410 | g->string_literals_table.maybe_remove(buf); |
| 6200 | 6411 | ||
| 6201 | const_val->data.x_array.special = ConstArraySpecialNone; | 6412 | const_val->data.x_array.special = ConstArraySpecialNone; |
| 6202 | size_t elem_count = const_val->type->data.array.len; | ||
| 6203 | assert(elem_count == buf_len(buf)); | 6413 | assert(elem_count == buf_len(buf)); |
| 6204 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); | 6414 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); |
| 6205 | for (size_t i = 0; i < elem_count; i += 1) { | 6415 | for (size_t i = 0; i < elem_count; i += 1) { |
| ... | @@ -6207,6 +6417,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -6207,6 +6417,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6207 | this_char->special = ConstValSpecialStatic; | 6417 | this_char->special = ConstValSpecialStatic; |
| 6208 | this_char->type = g->builtin_types.entry_u8; | 6418 | this_char->type = g->builtin_types.entry_u8; |
| 6209 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); | 6419 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); |
| 6420 | this_char->parent.id = ConstParentIdArray; | ||
| 6421 | this_char->parent.data.p_array.array_val = const_val; | ||
| 6422 | this_char->parent.data.p_array.elem_index = i; | ||
| 6210 | } | 6423 | } |
| 6211 | return; | 6424 | return; |
| 6212 | } | 6425 | } |
| ... | @@ -6214,18 +6427,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -6214,18 +6427,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6214 | zig_unreachable(); | 6427 | zig_unreachable(); |
| 6215 | } | 6428 | } |
| 6216 | 6429 | ||
| 6430 | // Deprecated. Reference the parent field directly. | ||
| 6217 | ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { | 6431 | ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 6218 | assert(value->type); | 6432 | return &value->parent; |
| 6219 | ZigType *type_entry = value->type; | ||
| 6220 | if (type_entry->id == ZigTypeIdArray) { | ||
| 6221 | expand_undef_array(g, value); | ||
| 6222 | return &value->data.x_array.data.s_none.parent; | ||
| 6223 | } else if (type_entry->id == ZigTypeIdStruct) { | ||
| 6224 | return &value->data.x_struct.parent; | ||
| 6225 | } else if (type_entry->id == ZigTypeIdUnion) { | ||
| 6226 | return &value->data.x_union.parent; | ||
| 6227 | } | ||
| 6228 | return nullptr; | ||
| 6229 | } | 6433 | } |
| 6230 | 6434 | ||
| 6231 | static const ZigTypeId all_type_ids[] = { | 6435 | static const ZigTypeId all_type_ids[] = { |
| ... | @@ -6253,6 +6457,7 @@ static const ZigTypeId all_type_ids[] = { | ... | @@ -6253,6 +6457,7 @@ static const ZigTypeId all_type_ids[] = { |
| 6253 | ZigTypeIdArgTuple, | 6457 | ZigTypeIdArgTuple, |
| 6254 | ZigTypeIdOpaque, | 6458 | ZigTypeIdOpaque, |
| 6255 | ZigTypeIdPromise, | 6459 | ZigTypeIdPromise, |
| 6460 | ZigTypeIdVector, | ||
| 6256 | }; | 6461 | }; |
| 6257 | 6462 | ||
| 6258 | ZigTypeId type_id_at_index(size_t index) { | 6463 | ZigTypeId type_id_at_index(size_t index) { |
| ... | @@ -6318,6 +6523,8 @@ size_t type_id_index(ZigType *entry) { | ... | @@ -6318,6 +6523,8 @@ size_t type_id_index(ZigType *entry) { |
| 6318 | return 22; | 6523 | return 22; |
| 6319 | case ZigTypeIdPromise: | 6524 | case ZigTypeIdPromise: |
| 6320 | return 23; | 6525 | return 23; |
| 6526 | case ZigTypeIdVector: | ||
| 6527 | return 24; | ||
| 6321 | } | 6528 | } |
| 6322 | zig_unreachable(); | 6529 | zig_unreachable(); |
| 6323 | } | 6530 | } |
| ... | @@ -6374,6 +6581,8 @@ const char *type_id_name(ZigTypeId id) { | ... | @@ -6374,6 +6581,8 @@ const char *type_id_name(ZigTypeId id) { |
| 6374 | return "Opaque"; | 6581 | return "Opaque"; |
| 6375 | case ZigTypeIdPromise: | 6582 | case ZigTypeIdPromise: |
| 6376 | return "Promise"; | 6583 | return "Promise"; |
| 6584 | case ZigTypeIdVector: | ||
| 6585 | return "Vector"; | ||
| 6377 | } | 6586 | } |
| 6378 | zig_unreachable(); | 6587 | zig_unreachable(); |
| 6379 | } | 6588 | } |
| ... | @@ -6453,7 +6662,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | ... | @@ -6453,7 +6662,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 6453 | resolve_top_level_decl(codegen, tld, false, nullptr); | 6662 | resolve_top_level_decl(codegen, tld, false, nullptr); |
| 6454 | assert(tld->id == TldIdVar); | 6663 | assert(tld->id == TldIdVar); |
| 6455 | TldVar *tld_var = (TldVar *)tld; | 6664 | TldVar *tld_var = (TldVar *)tld; |
| 6456 | ConstExprValue *var_value = tld_var->var->value; | 6665 | ConstExprValue *var_value = tld_var->var->const_value; |
| 6457 | assert(var_value != nullptr); | 6666 | assert(var_value != nullptr); |
| 6458 | return var_value; | 6667 | return var_value; |
| 6459 | } | 6668 | } |
| ... | @@ -6529,6 +6738,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { | ... | @@ -6529,6 +6738,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { |
| 6529 | case ZigTypeIdBool: | 6738 | case ZigTypeIdBool: |
| 6530 | return X64CABIClass_INTEGER; | 6739 | return X64CABIClass_INTEGER; |
| 6531 | case ZigTypeIdFloat: | 6740 | case ZigTypeIdFloat: |
| 6741 | case ZigTypeIdVector: | ||
| 6532 | return X64CABIClass_SSE; | 6742 | return X64CABIClass_SSE; |
| 6533 | case ZigTypeIdStruct: { | 6743 | case ZigTypeIdStruct: { |
| 6534 | // "If the size of an object is larger than four eightbytes, or it contains unaligned | 6744 | // "If the size of an object is larger than four eightbytes, or it contains unaligned |
src/analyze.hpp+10-1| ... | @@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons | ... | @@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 20 | uint64_t type_size(CodeGen *g, ZigType *type_entry); | 20 | uint64_t type_size(CodeGen *g, ZigType *type_entry); |
| 21 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); | 21 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); |
| 22 | ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); | 22 | ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
| 23 | ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); | ||
| 23 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); | 24 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
| 24 | ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); | 25 | ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); |
| 25 | ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); | 26 | ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); |
| ... | @@ -73,6 +74,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); | ... | @@ -73,6 +74,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); |
| 73 | bool is_ref(ZigType *type_entry); | 74 | bool is_ref(ZigType *type_entry); |
| 74 | bool is_array_ref(ZigType *type_entry); | 75 | bool is_array_ref(ZigType *type_entry); |
| 75 | bool is_container_ref(ZigType *type_entry); | 76 | bool is_container_ref(ZigType *type_entry); |
| 77 | bool is_valid_vector_elem_type(ZigType *elem_type); | ||
| 76 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); | 78 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 77 | void scan_import(CodeGen *g, ImportTableEntry *import); | 79 | void scan_import(CodeGen *g, ImportTableEntry *import); |
| 78 | void preview_use_decl(CodeGen *g, AstNode *node); | 80 | void preview_use_decl(CodeGen *g, AstNode *node); |
| ... | @@ -81,7 +83,7 @@ ZigFn *scope_fn_entry(Scope *scope); | ... | @@ -81,7 +83,7 @@ ZigFn *scope_fn_entry(Scope *scope); |
| 81 | ImportTableEntry *get_scope_import(Scope *scope); | 83 | ImportTableEntry *get_scope_import(Scope *scope); |
| 82 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); | 84 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); |
| 83 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, | 85 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, |
| 84 | bool is_const, ConstExprValue *init_value, Tld *src_tld); | 86 | bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); |
| 85 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); | 87 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); |
| 86 | ZigFn *create_fn(CodeGen *g, AstNode *proto_node); | 88 | ZigFn *create_fn(CodeGen *g, AstNode *proto_node); |
| 87 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); | 89 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); |
| ... | @@ -222,6 +224,13 @@ enum ReqCompTime { | ... | @@ -222,6 +224,13 @@ enum ReqCompTime { |
| 222 | }; | 224 | }; |
| 223 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); | 225 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); |
| 224 | 226 | ||
| 227 | enum OnePossibleValue { | ||
| 228 | OnePossibleValueInvalid, | ||
| 229 | OnePossibleValueNo, | ||
| 230 | OnePossibleValueYes, | ||
| 231 | }; | ||
| 232 | OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); | ||
| 233 | |||
| 225 | Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, | 234 | Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, |
| 226 | ConstExprValue *const_val, ZigType *wanted_type); | 235 | ConstExprValue *const_val, ZigType *wanted_type); |
| 227 | 236 |
src/ast_render.cpp+4-4| ... | @@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) { |
| 233 | return "ErrorType"; | 233 | return "ErrorType"; |
| 234 | case NodeTypeIfErrorExpr: | 234 | case NodeTypeIfErrorExpr: |
| 235 | return "IfErrorExpr"; | 235 | return "IfErrorExpr"; |
| 236 | case NodeTypeTestExpr: | 236 | case NodeTypeIfOptional: |
| 237 | return "TestExpr"; | 237 | return "IfOptional"; |
| 238 | case NodeTypeErrorSetDecl: | 238 | case NodeTypeErrorSetDecl: |
| 239 | return "ErrorSetDecl"; | 239 | return "ErrorSetDecl"; |
| 240 | case NodeTypeCancel: | 240 | case NodeTypeCancel: |
| ... | @@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { | ... | @@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { |
| 387 | if (node->data.if_err_expr.else_node) | 387 | if (node->data.if_err_expr.else_node) |
| 388 | return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); | 388 | return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); |
| 389 | return node->data.if_err_expr.then_node->type == NodeTypeBlock; | 389 | return node->data.if_err_expr.then_node->type == NodeTypeBlock; |
| 390 | case NodeTypeTestExpr: | 390 | case NodeTypeIfOptional: |
| 391 | if (node->data.test_expr.else_node) | 391 | if (node->data.test_expr.else_node) |
| 392 | return statement_terminates_without_semicolon(node->data.test_expr.else_node); | 392 | return statement_terminates_without_semicolon(node->data.test_expr.else_node); |
| 393 | return node->data.test_expr.then_node->type == NodeTypeBlock; | 393 | return node->data.test_expr.then_node->type == NodeTypeBlock; |
| ... | @@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 974 | } | 974 | } |
| 975 | break; | 975 | break; |
| 976 | } | 976 | } |
| 977 | case NodeTypeTestExpr: | 977 | case NodeTypeIfOptional: |
| 978 | { | 978 | { |
| 979 | fprintf(ar->f, "if ("); | 979 | fprintf(ar->f, "if ("); |
| 980 | render_node_grouped(ar, node->data.test_expr.target_node); | 980 | render_node_grouped(ar, node->data.test_expr.target_node); |
src/cache_hash.cpp+3-13| ... | @@ -222,14 +222,9 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents | ... | @@ -222,14 +222,9 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents |
| 222 | assert(chf->path != nullptr); | 222 | assert(chf->path != nullptr); |
| 223 | 223 | ||
| 224 | OsFile this_file; | 224 | OsFile this_file; |
| 225 | if ((err = os_file_open_r(chf->path, &this_file))) | 225 | if ((err = os_file_open_r(chf->path, &this_file, &chf->mtime))) |
| 226 | return err; | 226 | return err; |
| 227 | 227 | ||
| 228 | if ((err = os_file_mtime(this_file, &chf->mtime))) { | ||
| 229 | os_file_close(this_file); | ||
| 230 | return err; | ||
| 231 | } | ||
| 232 | |||
| 233 | if ((err = hash_file(chf->bin_digest, this_file, contents))) { | 228 | if ((err = hash_file(chf->bin_digest, this_file, contents))) { |
| 234 | os_file_close(this_file); | 229 | os_file_close(this_file); |
| 235 | return err; | 230 | return err; |
| ... | @@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { | ... | @@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { |
| 351 | 346 | ||
| 352 | // if the mtime matches we can trust the digest | 347 | // if the mtime matches we can trust the digest |
| 353 | OsFile this_file; | 348 | OsFile this_file; |
| 354 | if ((err = os_file_open_r(chf->path, &this_file))) { | 349 | OsTimeStamp actual_mtime; |
| 350 | if ((err = os_file_open_r(chf->path, &this_file, &actual_mtime))) { | ||
| 355 | fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); | 351 | fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); |
| 356 | os_file_close(ch->manifest_file); | 352 | os_file_close(ch->manifest_file); |
| 357 | return ErrorCacheUnavailable; | 353 | return ErrorCacheUnavailable; |
| 358 | } | 354 | } |
| 359 | OsTimeStamp actual_mtime; | ||
| 360 | if ((err = os_file_mtime(this_file, &actual_mtime))) { | ||
| 361 | os_file_close(this_file); | ||
| 362 | os_file_close(ch->manifest_file); | ||
| 363 | return err; | ||
| 364 | } | ||
| 365 | if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) { | 355 | if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) { |
| 366 | os_file_close(this_file); | 356 | os_file_close(this_file); |
| 367 | } else { | 357 | } else { |
src/codegen.cpp+396-104| ... | @@ -118,6 +118,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out | ... | @@ -118,6 +118,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 118 | g->string_literals_table.init(16); | 118 | g->string_literals_table.init(16); |
| 119 | g->type_info_cache.init(32); | 119 | g->type_info_cache.init(32); |
| 120 | g->is_test_build = false; | 120 | g->is_test_build = false; |
| 121 | g->is_single_threaded = false; | ||
| 121 | buf_resize(&g->global_asm, 0); | 122 | buf_resize(&g->global_asm, 0); |
| 122 | 123 | ||
| 123 | for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { | 124 | for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { |
| ... | @@ -313,6 +314,8 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char * | ... | @@ -313,6 +314,8 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char * |
| 313 | static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); | 314 | static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); |
| 314 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name); | 315 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name); |
| 315 | static void generate_error_name_table(CodeGen *g); | 316 | static void generate_error_name_table(CodeGen *g); |
| 317 | static bool value_is_all_undef(ConstExprValue *const_val); | ||
| 318 | static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr); | ||
| 316 | 319 | ||
| 317 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { | 320 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { |
| 318 | unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); | 321 | unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); |
| ... | @@ -461,6 +464,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag | ... | @@ -461,6 +464,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag |
| 461 | } | 464 | } |
| 462 | } | 465 | } |
| 463 | 466 | ||
| 467 | static bool cc_want_sret_attr(CallingConvention cc) { | ||
| 468 | switch (cc) { | ||
| 469 | case CallingConventionNaked: | ||
| 470 | zig_unreachable(); | ||
| 471 | case CallingConventionC: | ||
| 472 | case CallingConventionCold: | ||
| 473 | case CallingConventionStdcall: | ||
| 474 | return true; | ||
| 475 | case CallingConventionAsync: | ||
| 476 | case CallingConventionUnspecified: | ||
| 477 | return false; | ||
| 478 | } | ||
| 479 | zig_unreachable(); | ||
| 480 | } | ||
| 481 | |||
| 464 | static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | 482 | static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 465 | if (fn_table_entry->llvm_value) | 483 | if (fn_table_entry->llvm_value) |
| 466 | return fn_table_entry->llvm_value; | 484 | return fn_table_entry->llvm_value; |
| ... | @@ -598,9 +616,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -598,9 +616,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 598 | } else if (type_is_codegen_pointer(return_type)) { | 616 | } else if (type_is_codegen_pointer(return_type)) { |
| 599 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 617 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 600 | } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { | 618 | } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { |
| 601 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); | ||
| 602 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 619 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 603 | if (cc == CallingConventionC) { | 620 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); |
| 621 | if (cc_want_sret_attr(cc)) { | ||
| 604 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias"); | 622 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias"); |
| 605 | } | 623 | } |
| 606 | init_gen_i = 1; | 624 | init_gen_i = 1; |
| ... | @@ -1903,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { | ... | @@ -1903,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { |
| 1903 | } | 1921 | } |
| 1904 | 1922 | ||
| 1905 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { | 1923 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| 1906 | assert(alignment > 0); | ||
| 1907 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); | 1924 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); |
| 1908 | LLVMSetAlignment(result, alignment); | 1925 | LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment); |
| 1909 | return result; | 1926 | return result; |
| 1910 | } | 1927 | } |
| 1911 | 1928 | ||
| ... | @@ -1963,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ | ... | @@ -1963,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1963 | break; | 1980 | break; |
| 1964 | } | 1981 | } |
| 1965 | 1982 | ||
| 1966 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || | 1983 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector || |
| 1967 | ty->id == ZigTypeIdInt // TODO investigate if we need to change this | 1984 | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| 1968 | ) { | 1985 | ) { |
| 1969 | switch (fn_walk->id) { | 1986 | switch (fn_walk->id) { |
| ... | @@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { | ... | @@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2200 | assert(variable); | 2217 | assert(variable); |
| 2201 | assert(variable->value_ref); | 2218 | assert(variable->value_ref); |
| 2202 | 2219 | ||
| 2203 | if (!handle_is_ptr(variable->value->type)) { | 2220 | if (!handle_is_ptr(variable->var_type)) { |
| 2204 | clear_debug_source_node(g); | 2221 | clear_debug_source_node(g); |
| 2205 | gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref, | 2222 | gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), |
| 2206 | variable->align_bytes, false); | 2223 | variable->value_ref, variable->align_bytes, false); |
| 2207 | } | 2224 | } |
| 2208 | 2225 | ||
| 2209 | if (variable->decl_node) { | 2226 | if (variable->decl_node) { |
| ... | @@ -2643,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -2643,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2643 | } else { | 2660 | } else { |
| 2644 | return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); | 2661 | return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); |
| 2645 | } | 2662 | } |
| 2663 | } else if (type_entry->id == ZigTypeIdVector) { | ||
| 2664 | ZigType *elem_type = type_entry->data.vector.elem_type; | ||
| 2665 | if (elem_type->id == ZigTypeIdFloat) { | ||
| 2666 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | ||
| 2667 | return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); | ||
| 2668 | } else if (elem_type->id == ZigTypeIdPointer) { | ||
| 2669 | zig_panic("TODO codegen for pointers in vectors"); | ||
| 2670 | } else if (elem_type->id == ZigTypeIdInt) { | ||
| 2671 | bool is_wrapping = (op_id == IrBinOpAddWrap); | ||
| 2672 | if (is_wrapping) { | ||
| 2673 | return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); | ||
| 2674 | } else if (want_runtime_safety) { | ||
| 2675 | zig_panic("TODO runtime safety for vector integer addition"); | ||
| 2676 | } else if (elem_type->data.integral.is_signed) { | ||
| 2677 | return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); | ||
| 2678 | } else { | ||
| 2679 | return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); | ||
| 2680 | } | ||
| 2681 | } else { | ||
| 2682 | zig_unreachable(); | ||
| 2683 | } | ||
| 2646 | } else { | 2684 | } else { |
| 2647 | zig_unreachable(); | 2685 | zig_unreachable(); |
| 2648 | } | 2686 | } |
| ... | @@ -2961,7 +2999,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, | ... | @@ -2961,7 +2999,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 2961 | } | 2999 | } |
| 2962 | 3000 | ||
| 2963 | static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, | 3001 | static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, |
| 2964 | IrInstructionPtrCast *instruction) | 3002 | IrInstructionPtrCastGen *instruction) |
| 2965 | { | 3003 | { |
| 2966 | ZigType *wanted_type = instruction->base.value.type; | 3004 | ZigType *wanted_type = instruction->base.value.type; |
| 2967 | if (!type_has_bits(wanted_type)) { | 3005 | if (!type_has_bits(wanted_type)) { |
| ... | @@ -3149,11 +3187,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -3149,11 +3187,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI |
| 3149 | } | 3187 | } |
| 3150 | 3188 | ||
| 3151 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, | 3189 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 3152 | IrInstructionDeclVar *decl_var_instruction) | 3190 | IrInstructionDeclVarGen *decl_var_instruction) |
| 3153 | { | 3191 | { |
| 3154 | ZigVar *var = decl_var_instruction->var; | 3192 | ZigVar *var = decl_var_instruction->var; |
| 3155 | 3193 | ||
| 3156 | if (!type_has_bits(var->value->type)) | 3194 | if (!type_has_bits(var->var_type)) |
| 3157 | return nullptr; | 3195 | return nullptr; |
| 3158 | 3196 | ||
| 3159 | if (var->ref_count == 0 && g->build_mode != BuildModeDebug) | 3197 | if (var->ref_count == 0 && g->build_mode != BuildModeDebug) |
| ... | @@ -3161,34 +3199,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, | ... | @@ -3161,34 +3199,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 3161 | 3199 | ||
| 3162 | IrInstruction *init_value = decl_var_instruction->init_value; | 3200 | IrInstruction *init_value = decl_var_instruction->init_value; |
| 3163 | 3201 | ||
| 3164 | bool have_init_expr = false; | 3202 | bool have_init_expr = !value_is_all_undef(&init_value->value); |
| 3165 | |||
| 3166 | ConstExprValue *const_val = &init_value->value; | ||
| 3167 | if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) | ||
| 3168 | have_init_expr = true; | ||
| 3169 | 3203 | ||
| 3170 | if (have_init_expr) { | 3204 | if (have_init_expr) { |
| 3171 | assert(var->value->type == init_value->value.type); | 3205 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, |
| 3172 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, | ||
| 3173 | PtrLenSingle, var->align_bytes, 0, 0); | 3206 | PtrLenSingle, var->align_bytes, 0, 0); |
| 3174 | LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); | 3207 | LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); |
| 3175 | gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); | 3208 | gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); |
| 3176 | } else { | 3209 | } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { |
| 3177 | bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); | 3210 | uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes; |
| 3178 | if (want_safe) { | 3211 | gen_undef_init(g, align_bytes, var->var_type, var->value_ref); |
| 3179 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 3180 | uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref); | ||
| 3181 | assert(size_bytes > 0); | ||
| 3182 | |||
| 3183 | assert(var->align_bytes > 0); | ||
| 3184 | |||
| 3185 | // memset uninitialized memory to 0xa | ||
| 3186 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | ||
| 3187 | LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); | ||
| 3188 | LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, ""); | ||
| 3189 | LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); | ||
| 3190 | ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false); | ||
| 3191 | } | ||
| 3192 | } | 3212 | } |
| 3193 | 3213 | ||
| 3194 | gen_var_debug_decl(g, var); | 3214 | gen_var_debug_decl(g, var); |
| ... | @@ -3225,21 +3245,81 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -3225,21 +3245,81 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3225 | return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); | 3245 | return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); |
| 3226 | } | 3246 | } |
| 3227 | 3247 | ||
| 3228 | static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { | 3248 | static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { |
| 3229 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); | 3249 | switch (const_val->data.x_array.special) { |
| 3230 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | 3250 | case ConstArraySpecialUndef: |
| 3251 | return true; | ||
| 3252 | case ConstArraySpecialBuf: | ||
| 3253 | return false; | ||
| 3254 | case ConstArraySpecialNone: | ||
| 3255 | for (size_t i = 0; i < len; i += 1) { | ||
| 3256 | if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) | ||
| 3257 | return false; | ||
| 3258 | } | ||
| 3259 | return true; | ||
| 3260 | } | ||
| 3261 | zig_unreachable(); | ||
| 3262 | } | ||
| 3231 | 3263 | ||
| 3232 | assert(instruction->ptr->value.type->id == ZigTypeIdPointer); | 3264 | static bool value_is_all_undef(ConstExprValue *const_val) { |
| 3233 | ZigType *ptr_type = instruction->ptr->value.type; | 3265 | switch (const_val->special) { |
| 3266 | case ConstValSpecialRuntime: | ||
| 3267 | return false; | ||
| 3268 | case ConstValSpecialUndef: | ||
| 3269 | return true; | ||
| 3270 | case ConstValSpecialStatic: | ||
| 3271 | if (const_val->type->id == ZigTypeIdStruct) { | ||
| 3272 | for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { | ||
| 3273 | if (!value_is_all_undef(&const_val->data.x_struct.fields[i])) | ||
| 3274 | return false; | ||
| 3275 | } | ||
| 3276 | return true; | ||
| 3277 | } else if (const_val->type->id == ZigTypeIdArray) { | ||
| 3278 | return value_is_all_undef_array(const_val, const_val->type->data.array.len); | ||
| 3279 | } else if (const_val->type->id == ZigTypeIdVector) { | ||
| 3280 | return value_is_all_undef_array(const_val, const_val->type->data.vector.len); | ||
| 3281 | } else { | ||
| 3282 | return false; | ||
| 3283 | } | ||
| 3284 | } | ||
| 3285 | zig_unreachable(); | ||
| 3286 | } | ||
| 3287 | |||
| 3288 | static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) { | ||
| 3289 | assert(type_has_bits(value_type)); | ||
| 3290 | uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref); | ||
| 3291 | assert(size_bytes > 0); | ||
| 3292 | assert(ptr_align_bytes > 0); | ||
| 3293 | // memset uninitialized memory to 0xaa | ||
| 3294 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | ||
| 3295 | LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); | ||
| 3296 | LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); | ||
| 3297 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 3298 | LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); | ||
| 3299 | ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); | ||
| 3300 | } | ||
| 3234 | 3301 | ||
| 3235 | gen_assign_raw(g, ptr, ptr_type, value); | 3302 | static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { |
| 3303 | ZigType *ptr_type = instruction->ptr->value.type; | ||
| 3304 | assert(ptr_type->id == ZigTypeIdPointer); | ||
| 3305 | if (!type_has_bits(ptr_type)) | ||
| 3306 | return nullptr; | ||
| 3236 | 3307 | ||
| 3308 | bool have_init_expr = !value_is_all_undef(&instruction->value->value); | ||
| 3309 | if (have_init_expr) { | ||
| 3310 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); | ||
| 3311 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | ||
| 3312 | gen_assign_raw(g, ptr, ptr_type, value); | ||
| 3313 | } else if (ir_want_runtime_safety(g, &instruction->base)) { | ||
| 3314 | gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type, | ||
| 3315 | ir_llvm_value(g, instruction->ptr)); | ||
| 3316 | } | ||
| 3237 | return nullptr; | 3317 | return nullptr; |
| 3238 | } | 3318 | } |
| 3239 | 3319 | ||
| 3240 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { | 3320 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3241 | ZigVar *var = instruction->var; | 3321 | ZigVar *var = instruction->var; |
| 3242 | if (type_has_bits(var->value->type)) { | 3322 | if (type_has_bits(var->var_type)) { |
| 3243 | assert(var->value_ref); | 3323 | assert(var->value_ref); |
| 3244 | return var->value_ref; | 3324 | return var->value_ref; |
| 3245 | } else { | 3325 | } else { |
| ... | @@ -3553,7 +3633,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab | ... | @@ -3553,7 +3633,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab |
| 3553 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | 3633 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3554 | } | 3634 | } |
| 3555 | 3635 | ||
| 3556 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, ""); | 3636 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, |
| 3637 | union_type->data.unionation.gen_union_index, ""); | ||
| 3557 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | 3638 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); |
| 3558 | return bitcasted_union_field_ptr; | 3639 | return bitcasted_union_field_ptr; |
| 3559 | } | 3640 | } |
| ... | @@ -3715,8 +3796,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR | ... | @@ -3715,8 +3796,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR |
| 3715 | if (child_type->zero_bits) { | 3796 | if (child_type->zero_bits) { |
| 3716 | return maybe_handle; | 3797 | return maybe_handle; |
| 3717 | } else { | 3798 | } else { |
| 3718 | bool maybe_is_ptr = type_is_codegen_pointer(child_type); | 3799 | bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; |
| 3719 | if (maybe_is_ptr) { | 3800 | if (is_scalar) { |
| 3720 | return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); | 3801 | return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); |
| 3721 | } else { | 3802 | } else { |
| 3722 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); | 3803 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); |
| ... | @@ -3731,17 +3812,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable | ... | @@ -3731,17 +3812,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable |
| 3731 | return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value)); | 3812 | return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value)); |
| 3732 | } | 3813 | } |
| 3733 | 3814 | ||
| 3734 | static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, | 3815 | static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, |
| 3735 | IrInstructionUnwrapOptional *instruction) | 3816 | IrInstructionOptionalUnwrapPtr *instruction) |
| 3736 | { | 3817 | { |
| 3737 | ZigType *ptr_type = instruction->value->value.type; | 3818 | ZigType *ptr_type = instruction->base_ptr->value.type; |
| 3738 | assert(ptr_type->id == ZigTypeIdPointer); | 3819 | assert(ptr_type->id == ZigTypeIdPointer); |
| 3739 | ZigType *maybe_type = ptr_type->data.pointer.child_type; | 3820 | ZigType *maybe_type = ptr_type->data.pointer.child_type; |
| 3740 | assert(maybe_type->id == ZigTypeIdOptional); | 3821 | assert(maybe_type->id == ZigTypeIdOptional); |
| 3741 | ZigType *child_type = maybe_type->data.maybe.child_type; | 3822 | ZigType *child_type = maybe_type->data.maybe.child_type; |
| 3742 | LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); | 3823 | LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); |
| 3743 | LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); | ||
| 3744 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { | 3824 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { |
| 3825 | LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); | ||
| 3745 | LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); | 3826 | LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); |
| 3746 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); | 3827 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); |
| 3747 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); | 3828 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); |
| ... | @@ -3755,8 +3836,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, | ... | @@ -3755,8 +3836,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, |
| 3755 | if (child_type->zero_bits) { | 3836 | if (child_type->zero_bits) { |
| 3756 | return nullptr; | 3837 | return nullptr; |
| 3757 | } else { | 3838 | } else { |
| 3758 | bool maybe_is_ptr = type_is_codegen_pointer(child_type); | 3839 | bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; |
| 3759 | if (maybe_is_ptr) { | 3840 | if (is_scalar) { |
| 3760 | return maybe_ptr; | 3841 | return maybe_ptr; |
| 3761 | } else { | 3842 | } else { |
| 3762 | LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); | 3843 | LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); |
| ... | @@ -4174,7 +4255,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) | ... | @@ -4174,7 +4255,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) |
| 4174 | zig_unreachable(); | 4255 | zig_unreachable(); |
| 4175 | } | 4256 | } |
| 4176 | 4257 | ||
| 4177 | static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) { | 4258 | static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) { |
| 4178 | LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); | 4259 | LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); |
| 4179 | LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); | 4260 | LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); |
| 4180 | LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); | 4261 | LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); |
| ... | @@ -4189,18 +4270,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn | ... | @@ -4189,18 +4270,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn |
| 4189 | assert(maybe_type->id == ZigTypeIdOptional); | 4270 | assert(maybe_type->id == ZigTypeIdOptional); |
| 4190 | ZigType *child_type = maybe_type->data.maybe.child_type; | 4271 | ZigType *child_type = maybe_type->data.maybe.child_type; |
| 4191 | 4272 | ||
| 4192 | if (type_is_codegen_pointer(child_type)) { | 4273 | if (!handle_is_ptr(maybe_type)) { |
| 4193 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); | 4274 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 4194 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); | 4275 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); |
| 4195 | return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); | 4276 | return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); |
| 4196 | } | 4277 | } |
| 4197 | 4278 | ||
| 4198 | assert(instruction->tmp_ptr != nullptr); | 4279 | assert(instruction->tmp_ptr != nullptr); |
| 4199 | assert(type_has_bits(instruction->type)); | 4280 | assert(type_has_bits(child_type)); |
| 4200 | 4281 | ||
| 4201 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); | 4282 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 4202 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); | 4283 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); |
| 4203 | gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val); | 4284 | gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); |
| 4204 | 4285 | ||
| 4205 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); | 4286 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); |
| 4206 | LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); | 4287 | LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); |
| ... | @@ -4351,6 +4432,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -4351,6 +4432,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst |
| 4351 | assert(array_type->data.structure.is_slice); | 4432 | assert(array_type->data.structure.is_slice); |
| 4352 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); | 4433 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 4353 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); | 4434 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 4435 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); | ||
| 4354 | 4436 | ||
| 4355 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index; | 4437 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index; |
| 4356 | assert(ptr_index != SIZE_MAX); | 4438 | assert(ptr_index != SIZE_MAX); |
| ... | @@ -4540,12 +4622,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -4540,12 +4622,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI |
| 4540 | return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); | 4622 | return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); |
| 4541 | } | 4623 | } |
| 4542 | 4624 | ||
| 4543 | static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { | 4625 | static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, |
| 4544 | ZigType *ptr_type = instruction->value->value.type; | 4626 | IrInstructionUnwrapErrCode *instruction) |
| 4627 | { | ||
| 4628 | ZigType *ptr_type = instruction->err_union->value.type; | ||
| 4545 | assert(ptr_type->id == ZigTypeIdPointer); | 4629 | assert(ptr_type->id == ZigTypeIdPointer); |
| 4546 | ZigType *err_union_type = ptr_type->data.pointer.child_type; | 4630 | ZigType *err_union_type = ptr_type->data.pointer.child_type; |
| 4547 | ZigType *payload_type = err_union_type->data.error_union.payload_type; | 4631 | ZigType *payload_type = err_union_type->data.error_union.payload_type; |
| 4548 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); | 4632 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union); |
| 4549 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); | 4633 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 4550 | 4634 | ||
| 4551 | if (type_has_bits(payload_type)) { | 4635 | if (type_has_bits(payload_type)) { |
| ... | @@ -4556,7 +4640,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab | ... | @@ -4556,7 +4640,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 4556 | } | 4640 | } |
| 4557 | } | 4641 | } |
| 4558 | 4642 | ||
| 4559 | static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { | 4643 | static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, |
| 4644 | IrInstructionUnwrapErrPayload *instruction) | ||
| 4645 | { | ||
| 4646 | bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && | ||
| 4647 | g->errors_by_index.length > 1; | ||
| 4648 | if (!want_safety && !type_has_bits(instruction->base.value.type)) | ||
| 4649 | return nullptr; | ||
| 4560 | ZigType *ptr_type = instruction->value->value.type; | 4650 | ZigType *ptr_type = instruction->value->value.type; |
| 4561 | assert(ptr_type->id == ZigTypeIdPointer); | 4651 | assert(ptr_type->id == ZigTypeIdPointer); |
| 4562 | ZigType *err_union_type = ptr_type->data.pointer.child_type; | 4652 | ZigType *err_union_type = ptr_type->data.pointer.child_type; |
| ... | @@ -4568,7 +4658,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -4568,7 +4658,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 4568 | return err_union_handle; | 4658 | return err_union_handle; |
| 4569 | } | 4659 | } |
| 4570 | 4660 | ||
| 4571 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { | 4661 | if (want_safety) { |
| 4572 | LLVMValueRef err_val; | 4662 | LLVMValueRef err_val; |
| 4573 | if (type_has_bits(payload_type)) { | 4663 | if (type_has_bits(payload_type)) { |
| 4574 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); | 4664 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| ... | @@ -4607,7 +4697,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I | ... | @@ -4607,7 +4697,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I |
| 4607 | } | 4697 | } |
| 4608 | 4698 | ||
| 4609 | LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); | 4699 | LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); |
| 4610 | if (type_is_codegen_pointer(child_type)) { | 4700 | if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { |
| 4611 | return payload_val; | 4701 | return payload_val; |
| 4612 | } | 4702 | } |
| 4613 | 4703 | ||
| ... | @@ -5109,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, | ... | @@ -5109,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, |
| 5109 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); | 5199 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); |
| 5110 | } | 5200 | } |
| 5111 | 5201 | ||
| 5202 | static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executable, | ||
| 5203 | IrInstructionVectorToArray *instruction) | ||
| 5204 | { | ||
| 5205 | ZigType *array_type = instruction->base.value.type; | ||
| 5206 | assert(array_type->id == ZigTypeIdArray); | ||
| 5207 | assert(handle_is_ptr(array_type)); | ||
| 5208 | assert(instruction->tmp_ptr); | ||
| 5209 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); | ||
| 5210 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, | ||
| 5211 | LLVMPointerType(instruction->vector->value.type->type_ref, 0), ""); | ||
| 5212 | gen_store_untyped(g, vector, casted_ptr, 0, false); | ||
| 5213 | return instruction->tmp_ptr; | ||
| 5214 | } | ||
| 5215 | |||
| 5216 | static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, | ||
| 5217 | IrInstructionArrayToVector *instruction) | ||
| 5218 | { | ||
| 5219 | ZigType *vector_type = instruction->base.value.type; | ||
| 5220 | assert(vector_type->id == ZigTypeIdVector); | ||
| 5221 | assert(!handle_is_ptr(vector_type)); | ||
| 5222 | LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); | ||
| 5223 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, | ||
| 5224 | LLVMPointerType(vector_type->type_ref, 0), ""); | ||
| 5225 | return gen_load_untyped(g, casted_ptr, 0, false, ""); | ||
| 5226 | } | ||
| 5227 | |||
| 5112 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { | 5228 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 5113 | AstNode *source_node = instruction->source_node; | 5229 | AstNode *source_node = instruction->source_node; |
| 5114 | Scope *scope = instruction->scope; | 5230 | Scope *scope = instruction->scope; |
| ... | @@ -5148,6 +5264,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5148,6 +5264,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5148 | case IrInstructionIdCUndef: | 5264 | case IrInstructionIdCUndef: |
| 5149 | case IrInstructionIdEmbedFile: | 5265 | case IrInstructionIdEmbedFile: |
| 5150 | case IrInstructionIdIntType: | 5266 | case IrInstructionIdIntType: |
| 5267 | case IrInstructionIdVectorType: | ||
| 5151 | case IrInstructionIdMemberCount: | 5268 | case IrInstructionIdMemberCount: |
| 5152 | case IrInstructionIdMemberType: | 5269 | case IrInstructionIdMemberType: |
| 5153 | case IrInstructionIdMemberName: | 5270 | case IrInstructionIdMemberName: |
| ... | @@ -5184,12 +5301,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5184,12 +5301,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5184 | case IrInstructionIdToBytes: | 5301 | case IrInstructionIdToBytes: |
| 5185 | case IrInstructionIdEnumToInt: | 5302 | case IrInstructionIdEnumToInt: |
| 5186 | case IrInstructionIdCheckRuntimeScope: | 5303 | case IrInstructionIdCheckRuntimeScope: |
| 5304 | case IrInstructionIdDeclVarSrc: | ||
| 5305 | case IrInstructionIdPtrCastSrc: | ||
| 5306 | case IrInstructionIdCmpxchgSrc: | ||
| 5187 | zig_unreachable(); | 5307 | zig_unreachable(); |
| 5188 | 5308 | ||
| 5309 | case IrInstructionIdDeclVarGen: | ||
| 5310 | return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); | ||
| 5189 | case IrInstructionIdReturn: | 5311 | case IrInstructionIdReturn: |
| 5190 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); | 5312 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| 5191 | case IrInstructionIdDeclVar: | ||
| 5192 | return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction); | ||
| 5193 | case IrInstructionIdBinOp: | 5313 | case IrInstructionIdBinOp: |
| 5194 | return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction); | 5314 | return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction); |
| 5195 | case IrInstructionIdCast: | 5315 | case IrInstructionIdCast: |
| ... | @@ -5220,8 +5340,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5220,8 +5340,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5220 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); | 5340 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 5221 | case IrInstructionIdTestNonNull: | 5341 | case IrInstructionIdTestNonNull: |
| 5222 | return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); | 5342 | return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); |
| 5223 | case IrInstructionIdUnwrapOptional: | 5343 | case IrInstructionIdOptionalUnwrapPtr: |
| 5224 | return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction); | 5344 | return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction); |
| 5225 | case IrInstructionIdClz: | 5345 | case IrInstructionIdClz: |
| 5226 | return ir_render_clz(g, executable, (IrInstructionClz *)instruction); | 5346 | return ir_render_clz(g, executable, (IrInstructionClz *)instruction); |
| 5227 | case IrInstructionIdCtz: | 5347 | case IrInstructionIdCtz: |
| ... | @@ -5236,8 +5356,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5236,8 +5356,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5236 | return ir_render_ref(g, executable, (IrInstructionRef *)instruction); | 5356 | return ir_render_ref(g, executable, (IrInstructionRef *)instruction); |
| 5237 | case IrInstructionIdErrName: | 5357 | case IrInstructionIdErrName: |
| 5238 | return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); | 5358 | return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); |
| 5239 | case IrInstructionIdCmpxchg: | 5359 | case IrInstructionIdCmpxchgGen: |
| 5240 | return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction); | 5360 | return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction); |
| 5241 | case IrInstructionIdFence: | 5361 | case IrInstructionIdFence: |
| 5242 | return ir_render_fence(g, executable, (IrInstructionFence *)instruction); | 5362 | return ir_render_fence(g, executable, (IrInstructionFence *)instruction); |
| 5243 | case IrInstructionIdTruncate: | 5363 | case IrInstructionIdTruncate: |
| ... | @@ -5278,8 +5398,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5278,8 +5398,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5278 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); | 5398 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 5279 | case IrInstructionIdUnionInit: | 5399 | case IrInstructionIdUnionInit: |
| 5280 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | 5400 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); |
| 5281 | case IrInstructionIdPtrCast: | 5401 | case IrInstructionIdPtrCastGen: |
| 5282 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); | 5402 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); |
| 5283 | case IrInstructionIdBitCast: | 5403 | case IrInstructionIdBitCast: |
| 5284 | return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); | 5404 | return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); |
| 5285 | case IrInstructionIdWidenOrShorten: | 5405 | case IrInstructionIdWidenOrShorten: |
| ... | @@ -5350,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5350,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5350 | return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); | 5470 | return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); |
| 5351 | case IrInstructionIdBitReverse: | 5471 | case IrInstructionIdBitReverse: |
| 5352 | return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); | 5472 | return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); |
| 5473 | case IrInstructionIdArrayToVector: | ||
| 5474 | return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); | ||
| 5475 | case IrInstructionIdVectorToArray: | ||
| 5476 | return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); | ||
| 5353 | } | 5477 | } |
| 5354 | zig_unreachable(); | 5478 | zig_unreachable(); |
| 5355 | } | 5479 | } |
| ... | @@ -5377,6 +5501,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { | ... | @@ -5377,6 +5501,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { |
| 5377 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); | 5501 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 5378 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); | 5502 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); |
| 5379 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val); | 5503 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val); |
| 5504 | static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val); | ||
| 5505 | static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val); | ||
| 5506 | static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val); | ||
| 5380 | 5507 | ||
| 5381 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { | 5508 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 5382 | switch (parent->id) { | 5509 | switch (parent->id) { |
| ... | @@ -5387,6 +5514,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent | ... | @@ -5387,6 +5514,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 5387 | case ConstParentIdStruct: | 5514 | case ConstParentIdStruct: |
| 5388 | return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, | 5515 | return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, |
| 5389 | parent->data.p_struct.field_index); | 5516 | parent->data.p_struct.field_index); |
| 5517 | case ConstParentIdErrUnionCode: | ||
| 5518 | return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val); | ||
| 5519 | case ConstParentIdErrUnionPayload: | ||
| 5520 | return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val); | ||
| 5521 | case ConstParentIdOptionalPayload: | ||
| 5522 | return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val); | ||
| 5390 | case ConstParentIdArray: | 5523 | case ConstParentIdArray: |
| 5391 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, | 5524 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 5392 | parent->data.p_array.elem_index); | 5525 | parent->data.p_array.elem_index); |
| ... | @@ -5402,7 +5535,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent | ... | @@ -5402,7 +5535,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 5402 | 5535 | ||
| 5403 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { | 5536 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { |
| 5404 | expand_undef_array(g, array_const_val); | 5537 | expand_undef_array(g, array_const_val); |
| 5405 | ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent; | 5538 | ConstParent *parent = &array_const_val->parent; |
| 5406 | LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); | 5539 | LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); |
| 5407 | 5540 | ||
| 5408 | LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); | 5541 | LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); |
| ... | @@ -5427,7 +5560,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar | ... | @@ -5427,7 +5560,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar |
| 5427 | } | 5560 | } |
| 5428 | 5561 | ||
| 5429 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { | 5562 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { |
| 5430 | ConstParent *parent = &struct_const_val->data.x_struct.parent; | 5563 | ConstParent *parent = &struct_const_val->parent; |
| 5431 | LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); | 5564 | LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); |
| 5432 | 5565 | ||
| 5433 | ZigType *u32 = g->builtin_types.entry_u32; | 5566 | ZigType *u32 = g->builtin_types.entry_u32; |
| ... | @@ -5438,8 +5571,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s | ... | @@ -5438,8 +5571,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 5438 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 5571 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 5439 | } | 5572 | } |
| 5440 | 5573 | ||
| 5574 | static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { | ||
| 5575 | ConstParent *parent = &err_union_const_val->parent; | ||
| 5576 | LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); | ||
| 5577 | |||
| 5578 | ZigType *u32 = g->builtin_types.entry_u32; | ||
| 5579 | LLVMValueRef indices[] = { | ||
| 5580 | LLVMConstNull(u32->type_ref), | ||
| 5581 | LLVMConstInt(u32->type_ref, err_union_err_index, false), | ||
| 5582 | }; | ||
| 5583 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | ||
| 5584 | } | ||
| 5585 | |||
| 5586 | static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { | ||
| 5587 | ConstParent *parent = &err_union_const_val->parent; | ||
| 5588 | LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); | ||
| 5589 | |||
| 5590 | ZigType *u32 = g->builtin_types.entry_u32; | ||
| 5591 | LLVMValueRef indices[] = { | ||
| 5592 | LLVMConstNull(u32->type_ref), | ||
| 5593 | LLVMConstInt(u32->type_ref, err_union_payload_index, false), | ||
| 5594 | }; | ||
| 5595 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | ||
| 5596 | } | ||
| 5597 | |||
| 5598 | static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) { | ||
| 5599 | ConstParent *parent = &optional_const_val->parent; | ||
| 5600 | LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent); | ||
| 5601 | |||
| 5602 | ZigType *u32 = g->builtin_types.entry_u32; | ||
| 5603 | LLVMValueRef indices[] = { | ||
| 5604 | LLVMConstNull(u32->type_ref), | ||
| 5605 | LLVMConstInt(u32->type_ref, maybe_child_index, false), | ||
| 5606 | }; | ||
| 5607 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | ||
| 5608 | } | ||
| 5609 | |||
| 5441 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { | 5610 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { |
| 5442 | ConstParent *parent = &union_const_val->data.x_union.parent; | 5611 | ConstParent *parent = &union_const_val->parent; |
| 5443 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); | 5612 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); |
| 5444 | 5613 | ||
| 5445 | ZigType *u32 = g->builtin_types.entry_u32; | 5614 | ZigType *u32 = g->builtin_types.entry_u32; |
| ... | @@ -5509,6 +5678,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con | ... | @@ -5509,6 +5678,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 5509 | } | 5678 | } |
| 5510 | case ZigTypeIdArray: | 5679 | case ZigTypeIdArray: |
| 5511 | zig_panic("TODO bit pack an array"); | 5680 | zig_panic("TODO bit pack an array"); |
| 5681 | case ZigTypeIdVector: | ||
| 5682 | zig_panic("TODO bit pack a vector"); | ||
| 5512 | case ZigTypeIdUnion: | 5683 | case ZigTypeIdUnion: |
| 5513 | zig_panic("TODO bit pack a union"); | 5684 | zig_panic("TODO bit pack a union"); |
| 5514 | case ZigTypeIdStruct: | 5685 | case ZigTypeIdStruct: |
| ... | @@ -5609,6 +5780,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con | ... | @@ -5609,6 +5780,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con |
| 5609 | render_const_val_global(g, const_val, ""); | 5780 | render_const_val_global(g, const_val, ""); |
| 5610 | return ptr_val; | 5781 | return ptr_val; |
| 5611 | } | 5782 | } |
| 5783 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 5784 | { | ||
| 5785 | render_const_val_global(g, const_val, name); | ||
| 5786 | ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; | ||
| 5787 | assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); | ||
| 5788 | if (err_union_const_val->type->zero_bits) { | ||
| 5789 | // make this a null pointer | ||
| 5790 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 5791 | const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), | ||
| 5792 | const_val->type->type_ref); | ||
| 5793 | render_const_val_global(g, const_val, ""); | ||
| 5794 | return const_val->global_refs->llvm_value; | ||
| 5795 | } | ||
| 5796 | LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); | ||
| 5797 | LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); | ||
| 5798 | const_val->global_refs->llvm_value = ptr_val; | ||
| 5799 | render_const_val_global(g, const_val, ""); | ||
| 5800 | return ptr_val; | ||
| 5801 | } | ||
| 5802 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 5803 | { | ||
| 5804 | render_const_val_global(g, const_val, name); | ||
| 5805 | ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; | ||
| 5806 | assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); | ||
| 5807 | if (err_union_const_val->type->zero_bits) { | ||
| 5808 | // make this a null pointer | ||
| 5809 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 5810 | const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), | ||
| 5811 | const_val->type->type_ref); | ||
| 5812 | render_const_val_global(g, const_val, ""); | ||
| 5813 | return const_val->global_refs->llvm_value; | ||
| 5814 | } | ||
| 5815 | LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); | ||
| 5816 | LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); | ||
| 5817 | const_val->global_refs->llvm_value = ptr_val; | ||
| 5818 | render_const_val_global(g, const_val, ""); | ||
| 5819 | return ptr_val; | ||
| 5820 | } | ||
| 5821 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 5822 | { | ||
| 5823 | render_const_val_global(g, const_val, name); | ||
| 5824 | ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; | ||
| 5825 | assert(optional_const_val->type->id == ZigTypeIdOptional); | ||
| 5826 | if (optional_const_val->type->zero_bits) { | ||
| 5827 | // make this a null pointer | ||
| 5828 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 5829 | const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), | ||
| 5830 | const_val->type->type_ref); | ||
| 5831 | render_const_val_global(g, const_val, ""); | ||
| 5832 | return const_val->global_refs->llvm_value; | ||
| 5833 | } | ||
| 5834 | LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); | ||
| 5835 | LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); | ||
| 5836 | const_val->global_refs->llvm_value = ptr_val; | ||
| 5837 | render_const_val_global(g, const_val, ""); | ||
| 5838 | return ptr_val; | ||
| 5839 | } | ||
| 5612 | case ConstPtrSpecialHardCodedAddr: | 5840 | case ConstPtrSpecialHardCodedAddr: |
| 5613 | { | 5841 | { |
| 5614 | render_const_val_global(g, const_val, name); | 5842 | render_const_val_global(g, const_val, name); |
| ... | @@ -5621,10 +5849,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con | ... | @@ -5621,10 +5849,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con |
| 5621 | } | 5849 | } |
| 5622 | case ConstPtrSpecialFunction: | 5850 | case ConstPtrSpecialFunction: |
| 5623 | return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); | 5851 | return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); |
| 5852 | case ConstPtrSpecialNull: | ||
| 5853 | return LLVMConstNull(const_val->type->type_ref); | ||
| 5624 | } | 5854 | } |
| 5625 | zig_unreachable(); | 5855 | zig_unreachable(); |
| 5626 | } | 5856 | } |
| 5627 | 5857 | ||
| 5858 | static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) { | ||
| 5859 | uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value; | ||
| 5860 | return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false); | ||
| 5861 | } | ||
| 5862 | |||
| 5628 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { | 5863 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { |
| 5629 | Error err; | 5864 | Error err; |
| 5630 | 5865 | ||
| ... | @@ -5644,9 +5879,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5644,9 +5879,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5644 | case ZigTypeIdInt: | 5879 | case ZigTypeIdInt: |
| 5645 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); | 5880 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); |
| 5646 | case ZigTypeIdErrorSet: | 5881 | case ZigTypeIdErrorSet: |
| 5647 | assert(const_val->data.x_err_set != nullptr); | 5882 | return gen_const_val_err_set(g, const_val, name); |
| 5648 | return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, | ||
| 5649 | const_val->data.x_err_set->value, false); | ||
| 5650 | case ZigTypeIdFloat: | 5883 | case ZigTypeIdFloat: |
| 5651 | switch (type_entry->data.floating.bit_count) { | 5884 | switch (type_entry->data.floating.bit_count) { |
| 5652 | case 16: | 5885 | case 16: |
| ... | @@ -5680,6 +5913,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5680,6 +5913,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5680 | return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); | 5913 | return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); |
| 5681 | } else if (type_is_codegen_pointer(child_type)) { | 5914 | } else if (type_is_codegen_pointer(child_type)) { |
| 5682 | return gen_const_val_ptr(g, const_val, name); | 5915 | return gen_const_val_ptr(g, const_val, name); |
| 5916 | } else if (child_type->id == ZigTypeIdErrorSet) { | ||
| 5917 | return gen_const_val_err_set(g, const_val, name); | ||
| 5683 | } else { | 5918 | } else { |
| 5684 | LLVMValueRef child_val; | 5919 | LLVMValueRef child_val; |
| 5685 | LLVMValueRef maybe_val; | 5920 | LLVMValueRef maybe_val; |
| ... | @@ -5816,7 +6051,33 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5816,7 +6051,33 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5816 | return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true); | 6051 | return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true); |
| 5817 | } | 6052 | } |
| 5818 | } | 6053 | } |
| 6054 | zig_unreachable(); | ||
| 5819 | } | 6055 | } |
| 6056 | case ZigTypeIdVector: { | ||
| 6057 | uint32_t len = type_entry->data.vector.len; | ||
| 6058 | switch (const_val->data.x_array.special) { | ||
| 6059 | case ConstArraySpecialUndef: | ||
| 6060 | return LLVMGetUndef(type_entry->type_ref); | ||
| 6061 | case ConstArraySpecialNone: { | ||
| 6062 | LLVMValueRef *values = allocate<LLVMValueRef>(len); | ||
| 6063 | for (uint64_t i = 0; i < len; i += 1) { | ||
| 6064 | ConstExprValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; | ||
| 6065 | values[i] = gen_const_val(g, elem_value, ""); | ||
| 6066 | } | ||
| 6067 | return LLVMConstVector(values, len); | ||
| 6068 | } | ||
| 6069 | case ConstArraySpecialBuf: { | ||
| 6070 | Buf *buf = const_val->data.x_array.data.s_buf; | ||
| 6071 | assert(buf_len(buf) == len); | ||
| 6072 | LLVMValueRef *values = allocate<LLVMValueRef>(len); | ||
| 6073 | for (uint64_t i = 0; i < len; i += 1) { | ||
| 6074 | values[i] = LLVMConstInt(g->builtin_types.entry_u8->type_ref, buf_ptr(buf)[i], false); | ||
| 6075 | } | ||
| 6076 | return LLVMConstVector(values, len); | ||
| 6077 | } | ||
| 6078 | } | ||
| 6079 | zig_unreachable(); | ||
| 6080 | } | ||
| 5820 | case ZigTypeIdUnion: | 6081 | case ZigTypeIdUnion: |
| 5821 | { | 6082 | { |
| 5822 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; | 6083 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; |
| ... | @@ -5914,7 +6175,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5914,7 +6175,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5914 | ZigType *err_set_type = type_entry->data.error_union.err_set_type; | 6175 | ZigType *err_set_type = type_entry->data.error_union.err_set_type; |
| 5915 | if (!type_has_bits(payload_type)) { | 6176 | if (!type_has_bits(payload_type)) { |
| 5916 | assert(type_has_bits(err_set_type)); | 6177 | assert(type_has_bits(err_set_type)); |
| 5917 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; | 6178 | ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; |
| 6179 | uint64_t value = (err_set == nullptr) ? 0 : err_set->value; | ||
| 5918 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); | 6180 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 5919 | } else if (!type_has_bits(err_set_type)) { | 6181 | } else if (!type_has_bits(err_set_type)) { |
| 5920 | assert(type_has_bits(payload_type)); | 6182 | assert(type_has_bits(payload_type)); |
| ... | @@ -5923,8 +6185,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5923,8 +6185,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5923 | LLVMValueRef err_tag_value; | 6185 | LLVMValueRef err_tag_value; |
| 5924 | LLVMValueRef err_payload_value; | 6186 | LLVMValueRef err_payload_value; |
| 5925 | bool make_unnamed_struct; | 6187 | bool make_unnamed_struct; |
| 5926 | if (const_val->data.x_err_union.err) { | 6188 | ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; |
| 5927 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); | 6189 | if (err_set != nullptr) { |
| 6190 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false); | ||
| 5928 | err_payload_value = LLVMConstNull(payload_type->type_ref); | 6191 | err_payload_value = LLVMConstNull(payload_type->type_ref); |
| 5929 | make_unnamed_struct = false; | 6192 | make_unnamed_struct = false; |
| 5930 | } else { | 6193 | } else { |
| ... | @@ -6130,10 +6393,13 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6130,10 +6393,13 @@ static void do_code_gen(CodeGen *g) { |
| 6130 | TldVar *tld_var = g->global_vars.at(i); | 6393 | TldVar *tld_var = g->global_vars.at(i); |
| 6131 | ZigVar *var = tld_var->var; | 6394 | ZigVar *var = tld_var->var; |
| 6132 | 6395 | ||
| 6133 | if (var->value->type->id == ZigTypeIdComptimeFloat) { | 6396 | if (var->var_type->id == ZigTypeIdComptimeFloat) { |
| 6134 | // Generate debug info for it but that's it. | 6397 | // Generate debug info for it but that's it. |
| 6135 | ConstExprValue *const_val = var->value; | 6398 | ConstExprValue *const_val = var->const_value; |
| 6136 | assert(const_val->special != ConstValSpecialRuntime); | 6399 | assert(const_val->special != ConstValSpecialRuntime); |
| 6400 | if (const_val->type != var->var_type) { | ||
| 6401 | zig_panic("TODO debug info for var with ptr casted value"); | ||
| 6402 | } | ||
| 6137 | ZigType *var_type = g->builtin_types.entry_f128; | 6403 | ZigType *var_type = g->builtin_types.entry_f128; |
| 6138 | ConstExprValue coerced_value; | 6404 | ConstExprValue coerced_value; |
| 6139 | coerced_value.special = ConstValSpecialStatic; | 6405 | coerced_value.special = ConstValSpecialStatic; |
| ... | @@ -6144,10 +6410,13 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6144,10 +6410,13 @@ static void do_code_gen(CodeGen *g) { |
| 6144 | continue; | 6410 | continue; |
| 6145 | } | 6411 | } |
| 6146 | 6412 | ||
| 6147 | if (var->value->type->id == ZigTypeIdComptimeInt) { | 6413 | if (var->var_type->id == ZigTypeIdComptimeInt) { |
| 6148 | // Generate debug info for it but that's it. | 6414 | // Generate debug info for it but that's it. |
| 6149 | ConstExprValue *const_val = var->value; | 6415 | ConstExprValue *const_val = var->const_value; |
| 6150 | assert(const_val->special != ConstValSpecialRuntime); | 6416 | assert(const_val->special != ConstValSpecialRuntime); |
| 6417 | if (const_val->type != var->var_type) { | ||
| 6418 | zig_panic("TODO debug info for var with ptr casted value"); | ||
| 6419 | } | ||
| 6151 | size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); | 6420 | size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); |
| 6152 | if (bits_needed < 8) { | 6421 | if (bits_needed < 8) { |
| 6153 | bits_needed = 8; | 6422 | bits_needed = 8; |
| ... | @@ -6158,7 +6427,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6158,7 +6427,7 @@ static void do_code_gen(CodeGen *g) { |
| 6158 | continue; | 6427 | continue; |
| 6159 | } | 6428 | } |
| 6160 | 6429 | ||
| 6161 | if (!type_has_bits(var->value->type)) | 6430 | if (!type_has_bits(var->var_type)) |
| 6162 | continue; | 6431 | continue; |
| 6163 | 6432 | ||
| 6164 | assert(var->decl_node); | 6433 | assert(var->decl_node); |
| ... | @@ -6167,9 +6436,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6167,9 +6436,9 @@ static void do_code_gen(CodeGen *g) { |
| 6167 | if (var->linkage == VarLinkageExternal) { | 6436 | if (var->linkage == VarLinkageExternal) { |
| 6168 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); | 6437 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); |
| 6169 | if (existing_llvm_var) { | 6438 | if (existing_llvm_var) { |
| 6170 | global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0)); | 6439 | global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0)); |
| 6171 | } else { | 6440 | } else { |
| 6172 | global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name)); | 6441 | global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name)); |
| 6173 | // TODO debug info for the extern variable | 6442 | // TODO debug info for the extern variable |
| 6174 | 6443 | ||
| 6175 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | 6444 | LLVMSetLinkage(global_value, LLVMExternalLinkage); |
| ... | @@ -6180,9 +6449,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6180,9 +6449,9 @@ static void do_code_gen(CodeGen *g) { |
| 6180 | } else { | 6449 | } else { |
| 6181 | bool exported = (var->linkage == VarLinkageExport); | 6450 | bool exported = (var->linkage == VarLinkageExport); |
| 6182 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); | 6451 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); |
| 6183 | render_const_val(g, var->value, mangled_name); | 6452 | render_const_val(g, var->const_value, mangled_name); |
| 6184 | render_const_val_global(g, var->value, mangled_name); | 6453 | render_const_val_global(g, var->const_value, mangled_name); |
| 6185 | global_value = var->value->global_refs->llvm_global; | 6454 | global_value = var->const_value->global_refs->llvm_global; |
| 6186 | 6455 | ||
| 6187 | if (exported) { | 6456 | if (exported) { |
| 6188 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | 6457 | LLVMSetLinkage(global_value, LLVMExternalLinkage); |
| ... | @@ -6194,8 +6463,10 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6194,8 +6463,10 @@ static void do_code_gen(CodeGen *g) { |
| 6194 | LLVMSetAlignment(global_value, var->align_bytes); | 6463 | LLVMSetAlignment(global_value, var->align_bytes); |
| 6195 | 6464 | ||
| 6196 | // TODO debug info for function pointers | 6465 | // TODO debug info for function pointers |
| 6197 | if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) { | 6466 | // Here we use const_value->type because that's the type of the llvm global, |
| 6198 | gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type); | 6467 | // which we const ptr cast upon use to whatever it needs to be. |
| 6468 | if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) { | ||
| 6469 | gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type); | ||
| 6199 | } | 6470 | } |
| 6200 | 6471 | ||
| 6201 | LLVMSetGlobalConstant(global_value, var->gen_is_const); | 6472 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| ... | @@ -6249,6 +6520,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6249,6 +6520,7 @@ static void do_code_gen(CodeGen *g) { |
| 6249 | IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); | 6520 | IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); |
| 6250 | LLVMValueRef *slot; | 6521 | LLVMValueRef *slot; |
| 6251 | ZigType *slot_type = instruction->value.type; | 6522 | ZigType *slot_type = instruction->value.type; |
| 6523 | uint32_t alignment_bytes = 0; | ||
| 6252 | if (instruction->id == IrInstructionIdCast) { | 6524 | if (instruction->id == IrInstructionIdCast) { |
| 6253 | IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; | 6525 | IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; |
| 6254 | slot = &cast_instruction->tmp_ptr; | 6526 | slot = &cast_instruction->tmp_ptr; |
| ... | @@ -6281,13 +6553,17 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6281,13 +6553,17 @@ static void do_code_gen(CodeGen *g) { |
| 6281 | } else if (instruction->id == IrInstructionIdErrWrapCode) { | 6553 | } else if (instruction->id == IrInstructionIdErrWrapCode) { |
| 6282 | IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; | 6554 | IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; |
| 6283 | slot = &err_wrap_code_instruction->tmp_ptr; | 6555 | slot = &err_wrap_code_instruction->tmp_ptr; |
| 6284 | } else if (instruction->id == IrInstructionIdCmpxchg) { | 6556 | } else if (instruction->id == IrInstructionIdCmpxchgGen) { |
| 6285 | IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction; | 6557 | IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; |
| 6286 | slot = &cmpxchg_instruction->tmp_ptr; | 6558 | slot = &cmpxchg_instruction->tmp_ptr; |
| 6559 | } else if (instruction->id == IrInstructionIdVectorToArray) { | ||
| 6560 | IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; | ||
| 6561 | alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); | ||
| 6562 | slot = &vector_to_array_instruction->tmp_ptr; | ||
| 6287 | } else { | 6563 | } else { |
| 6288 | zig_unreachable(); | 6564 | zig_unreachable(); |
| 6289 | } | 6565 | } |
| 6290 | *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type)); | 6566 | *slot = build_alloca(g, slot_type, "", alignment_bytes); |
| 6291 | } | 6567 | } |
| 6292 | 6568 | ||
| 6293 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); | 6569 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| ... | @@ -6304,12 +6580,12 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6304,12 +6580,12 @@ static void do_code_gen(CodeGen *g) { |
| 6304 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { | 6580 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 6305 | ZigVar *var = fn_table_entry->variable_list.at(var_i); | 6581 | ZigVar *var = fn_table_entry->variable_list.at(var_i); |
| 6306 | 6582 | ||
| 6307 | if (!type_has_bits(var->value->type)) { | 6583 | if (!type_has_bits(var->var_type)) { |
| 6308 | continue; | 6584 | continue; |
| 6309 | } | 6585 | } |
| 6310 | if (ir_get_var_is_comptime(var)) | 6586 | if (ir_get_var_is_comptime(var)) |
| 6311 | continue; | 6587 | continue; |
| 6312 | switch (type_requires_comptime(g, var->value->type)) { | 6588 | switch (type_requires_comptime(g, var->var_type)) { |
| 6313 | case ReqCompTimeInvalid: | 6589 | case ReqCompTimeInvalid: |
| 6314 | zig_unreachable(); | 6590 | zig_unreachable(); |
| 6315 | case ReqCompTimeYes: | 6591 | case ReqCompTimeYes: |
| ... | @@ -6319,11 +6595,11 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6319,11 +6595,11 @@ static void do_code_gen(CodeGen *g) { |
| 6319 | } | 6595 | } |
| 6320 | 6596 | ||
| 6321 | if (var->src_arg_index == SIZE_MAX) { | 6597 | if (var->src_arg_index == SIZE_MAX) { |
| 6322 | var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); | 6598 | var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); |
| 6323 | 6599 | ||
| 6324 | var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), | 6600 | var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| 6325 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), | 6601 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), |
| 6326 | var->value->type->di_type, !g->strip_debug_symbols, 0); | 6602 | var->var_type->di_type, !g->strip_debug_symbols, 0); |
| 6327 | 6603 | ||
| 6328 | } else if (is_c_abi) { | 6604 | } else if (is_c_abi) { |
| 6329 | fn_walk_var.data.vars.var = var; | 6605 | fn_walk_var.data.vars.var = var; |
| ... | @@ -6333,16 +6609,16 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6333,16 +6609,16 @@ static void do_code_gen(CodeGen *g) { |
| 6333 | ZigType *gen_type; | 6609 | ZigType *gen_type; |
| 6334 | FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; | 6610 | FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; |
| 6335 | 6611 | ||
| 6336 | if (handle_is_ptr(var->value->type)) { | 6612 | if (handle_is_ptr(var->var_type)) { |
| 6337 | if (gen_info->is_byval) { | 6613 | if (gen_info->is_byval) { |
| 6338 | gen_type = var->value->type; | 6614 | gen_type = var->var_type; |
| 6339 | } else { | 6615 | } else { |
| 6340 | gen_type = gen_info->type; | 6616 | gen_type = gen_info->type; |
| 6341 | } | 6617 | } |
| 6342 | var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index); | 6618 | var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index); |
| 6343 | } else { | 6619 | } else { |
| 6344 | gen_type = var->value->type; | 6620 | gen_type = var->var_type; |
| 6345 | var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); | 6621 | var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); |
| 6346 | } | 6622 | } |
| 6347 | if (var->decl_node) { | 6623 | if (var->decl_node) { |
| 6348 | var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), | 6624 | var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| ... | @@ -6742,6 +7018,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6742,6 +7018,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 6742 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); | 7018 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); |
| 6743 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); | 7019 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 6744 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int | 7020 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 7021 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); | ||
| 6745 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); | 7022 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); |
| 6746 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); | 7023 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); |
| 6747 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); | 7024 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); |
| ... | @@ -6967,6 +7244,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -6967,6 +7244,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 6967 | " ArgTuple: void,\n" | 7244 | " ArgTuple: void,\n" |
| 6968 | " Opaque: void,\n" | 7245 | " Opaque: void,\n" |
| 6969 | " Promise: Promise,\n" | 7246 | " Promise: Promise,\n" |
| 7247 | " Vector: Vector,\n" | ||
| 6970 | "\n\n" | 7248 | "\n\n" |
| 6971 | " pub const Int = struct {\n" | 7249 | " pub const Int = struct {\n" |
| 6972 | " is_signed: bool,\n" | 7250 | " is_signed: bool,\n" |
| ... | @@ -7085,6 +7363,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -7085,6 +7363,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7085 | " child: ?type,\n" | 7363 | " child: ?type,\n" |
| 7086 | " };\n" | 7364 | " };\n" |
| 7087 | "\n" | 7365 | "\n" |
| 7366 | " pub const Vector = struct {\n" | ||
| 7367 | " len: u32,\n" | ||
| 7368 | " child: type,\n" | ||
| 7369 | " };\n" | ||
| 7370 | "\n" | ||
| 7088 | " pub const Definition = struct {\n" | 7371 | " pub const Definition = struct {\n" |
| 7089 | " name: []const u8,\n" | 7372 | " name: []const u8,\n" |
| 7090 | " is_pub: bool,\n" | 7373 | " is_pub: bool,\n" |
| ... | @@ -7153,6 +7436,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -7153,6 +7436,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7153 | buf_appendf(contents, "pub const endian = %s;\n", endian_str); | 7436 | buf_appendf(contents, "pub const endian = %s;\n", endian_str); |
| 7154 | } | 7437 | } |
| 7155 | buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); | 7438 | buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); |
| 7439 | buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); | ||
| 7156 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); | 7440 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); |
| 7157 | buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch); | 7441 | buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch); |
| 7158 | buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ); | 7442 | buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ); |
| ... | @@ -7187,6 +7471,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { | ... | @@ -7187,6 +7471,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { |
| 7187 | cache_buf(&cache_hash, compiler_id); | 7471 | cache_buf(&cache_hash, compiler_id); |
| 7188 | cache_int(&cache_hash, g->build_mode); | 7472 | cache_int(&cache_hash, g->build_mode); |
| 7189 | cache_bool(&cache_hash, g->is_test_build); | 7473 | cache_bool(&cache_hash, g->is_test_build); |
| 7474 | cache_bool(&cache_hash, g->is_single_threaded); | ||
| 7190 | cache_int(&cache_hash, g->zig_target.arch.arch); | 7475 | cache_int(&cache_hash, g->zig_target.arch.arch); |
| 7191 | cache_int(&cache_hash, g->zig_target.arch.sub_arch); | 7476 | cache_int(&cache_hash, g->zig_target.arch.sub_arch); |
| 7192 | cache_int(&cache_hash, g->zig_target.vendor); | 7477 | cache_int(&cache_hash, g->zig_target.vendor); |
| ... | @@ -7458,9 +7743,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { | ... | @@ -7458,9 +7743,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { |
| 7458 | ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; | 7743 | ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; |
| 7459 | this_val->special = ConstValSpecialStatic; | 7744 | this_val->special = ConstValSpecialStatic; |
| 7460 | this_val->type = struct_type; | 7745 | this_val->type = struct_type; |
| 7461 | this_val->data.x_struct.parent.id = ConstParentIdArray; | 7746 | this_val->parent.id = ConstParentIdArray; |
| 7462 | this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array; | 7747 | this_val->parent.data.p_array.array_val = test_fn_array; |
| 7463 | this_val->data.x_struct.parent.data.p_array.elem_index = i; | 7748 | this_val->parent.data.p_array.elem_index = i; |
| 7464 | this_val->data.x_struct.fields = create_const_vals(2); | 7749 | this_val->data.x_struct.fields = create_const_vals(2); |
| 7465 | 7750 | ||
| 7466 | ConstExprValue *name_field = &this_val->data.x_struct.fields[0]; | 7751 | ConstExprValue *name_field = &this_val->data.x_struct.fields[0]; |
| ... | @@ -7656,6 +7941,9 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e | ... | @@ -7656,6 +7941,9 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e |
| 7656 | case ZigTypeIdArray: | 7941 | case ZigTypeIdArray: |
| 7657 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); | 7942 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); |
| 7658 | return; | 7943 | return; |
| 7944 | case ZigTypeIdVector: | ||
| 7945 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type); | ||
| 7946 | return; | ||
| 7659 | case ZigTypeIdOptional: | 7947 | case ZigTypeIdOptional: |
| 7660 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); | 7948 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); |
| 7661 | return; | 7949 | return; |
| ... | @@ -7787,6 +8075,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu | ... | @@ -7787,6 +8075,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu |
| 7787 | buf_appendf(out_buf, "%s", buf_ptr(child_buf)); | 8075 | buf_appendf(out_buf, "%s", buf_ptr(child_buf)); |
| 7788 | return; | 8076 | return; |
| 7789 | } | 8077 | } |
| 8078 | case ZigTypeIdVector: | ||
| 8079 | zig_panic("TODO implement get_c_type for vector types"); | ||
| 7790 | case ZigTypeIdErrorUnion: | 8080 | case ZigTypeIdErrorUnion: |
| 7791 | case ZigTypeIdErrorSet: | 8081 | case ZigTypeIdErrorSet: |
| 7792 | case ZigTypeIdFn: | 8082 | case ZigTypeIdFn: |
| ... | @@ -7952,6 +8242,7 @@ static void gen_h_file(CodeGen *g) { | ... | @@ -7952,6 +8242,7 @@ static void gen_h_file(CodeGen *g) { |
| 7952 | case ZigTypeIdOptional: | 8242 | case ZigTypeIdOptional: |
| 7953 | case ZigTypeIdFn: | 8243 | case ZigTypeIdFn: |
| 7954 | case ZigTypeIdPromise: | 8244 | case ZigTypeIdPromise: |
| 8245 | case ZigTypeIdVector: | ||
| 7955 | zig_unreachable(); | 8246 | zig_unreachable(); |
| 7956 | case ZigTypeIdEnum: | 8247 | case ZigTypeIdEnum: |
| 7957 | if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { | 8248 | if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { |
| ... | @@ -8099,6 +8390,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { | ... | @@ -8099,6 +8390,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 8099 | cache_bool(ch, g->is_static); | 8390 | cache_bool(ch, g->is_static); |
| 8100 | cache_bool(ch, g->strip_debug_symbols); | 8391 | cache_bool(ch, g->strip_debug_symbols); |
| 8101 | cache_bool(ch, g->is_test_build); | 8392 | cache_bool(ch, g->is_test_build); |
| 8393 | cache_bool(ch, g->is_single_threaded); | ||
| 8102 | cache_bool(ch, g->is_native_target); | 8394 | cache_bool(ch, g->is_native_target); |
| 8103 | cache_bool(ch, g->linker_rdynamic); | 8395 | cache_bool(ch, g->linker_rdynamic); |
| 8104 | cache_bool(ch, g->no_rosegment_workaround); | 8396 | cache_bool(ch, g->no_rosegment_workaround); |
src/ir.cpp+1228-834| ... | @@ -167,6 +167,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -167,6 +167,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 167 | ZigType *dest_type, IrInstruction *dest_type_src); | 167 | ZigType *dest_type, IrInstruction *dest_type_src); |
| 168 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); | 168 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); |
| 169 | static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); | 169 | static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); |
| 170 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); | ||
| 171 | static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); | ||
| 170 | 172 | ||
| 171 | static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { | 173 | static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { |
| 172 | assert(get_src_ptr_type(const_val->type) != nullptr); | 174 | assert(get_src_ptr_type(const_val->type) != nullptr); |
| ... | @@ -178,15 +180,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c | ... | @@ -178,15 +180,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c |
| 178 | case ConstPtrSpecialRef: | 180 | case ConstPtrSpecialRef: |
| 179 | result = const_val->data.x_ptr.data.ref.pointee; | 181 | result = const_val->data.x_ptr.data.ref.pointee; |
| 180 | break; | 182 | break; |
| 181 | case ConstPtrSpecialBaseArray: | 183 | case ConstPtrSpecialBaseArray: { |
| 182 | expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val); | 184 | ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val; |
| 183 | result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[ | 185 | expand_undef_array(g, array_val); |
| 184 | const_val->data.x_ptr.data.base_array.elem_index]; | 186 | result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; |
| 185 | break; | 187 | break; |
| 188 | } | ||
| 186 | case ConstPtrSpecialBaseStruct: | 189 | case ConstPtrSpecialBaseStruct: |
| 187 | result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ | 190 | result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ |
| 188 | const_val->data.x_ptr.data.base_struct.field_index]; | 191 | const_val->data.x_ptr.data.base_struct.field_index]; |
| 189 | break; | 192 | break; |
| 193 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 194 | result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set; | ||
| 195 | break; | ||
| 196 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 197 | result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload; | ||
| 198 | break; | ||
| 199 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 200 | result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional; | ||
| 201 | break; | ||
| 202 | case ConstPtrSpecialNull: | ||
| 203 | result = const_val; | ||
| 204 | break; | ||
| 190 | case ConstPtrSpecialHardCodedAddr: | 205 | case ConstPtrSpecialHardCodedAddr: |
| 191 | zig_unreachable(); | 206 | zig_unreachable(); |
| 192 | case ConstPtrSpecialDiscard: | 207 | case ConstPtrSpecialDiscard: |
| ... | @@ -198,6 +213,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c | ... | @@ -198,6 +213,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c |
| 198 | return result; | 213 | return result; |
| 199 | } | 214 | } |
| 200 | 215 | ||
| 216 | static bool is_opt_err_set(ZigType *ty) { | ||
| 217 | return ty->id == ZigTypeIdErrorSet || | ||
| 218 | (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); | ||
| 219 | } | ||
| 220 | |||
| 201 | static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { | 221 | static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { |
| 202 | if (a == b) | 222 | if (a == b) |
| 203 | return true; | 223 | return true; |
| ... | @@ -208,15 +228,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { | ... | @@ -208,15 +228,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { |
| 208 | if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) | 228 | if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) |
| 209 | return true; | 229 | return true; |
| 210 | 230 | ||
| 211 | return false; | 231 | if (is_opt_err_set(a) && is_opt_err_set(b)) |
| 212 | } | 232 | return true; |
| 213 | 233 | ||
| 214 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { | 234 | return false; |
| 215 | ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val); | ||
| 216 | if (const_val->type->id == ZigTypeIdPointer) { | ||
| 217 | assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type)); | ||
| 218 | } | ||
| 219 | return result; | ||
| 220 | } | 235 | } |
| 221 | 236 | ||
| 222 | static bool ir_should_inline(IrExecutable *exec, Scope *scope) { | 237 | static bool ir_should_inline(IrExecutable *exec, Scope *scope) { |
| ... | @@ -305,6 +320,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { | ... | @@ -305,6 +320,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { |
| 305 | return new_bb; | 320 | return new_bb; |
| 306 | } | 321 | } |
| 307 | 322 | ||
| 323 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) { | ||
| 324 | return IrInstructionIdDeclVarSrc; | ||
| 325 | } | ||
| 326 | |||
| 327 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) { | ||
| 328 | return IrInstructionIdDeclVarGen; | ||
| 329 | } | ||
| 330 | |||
| 308 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) { | 331 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) { |
| 309 | return IrInstructionIdCondBr; | 332 | return IrInstructionIdCondBr; |
| 310 | } | 333 | } |
| ... | @@ -337,10 +360,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { | ... | @@ -337,10 +360,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { |
| 337 | return IrInstructionIdBinOp; | 360 | return IrInstructionIdBinOp; |
| 338 | } | 361 | } |
| 339 | 362 | ||
| 340 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { | ||
| 341 | return IrInstructionIdDeclVar; | ||
| 342 | } | ||
| 343 | |||
| 344 | static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { | 363 | static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { |
| 345 | return IrInstructionIdExport; | 364 | return IrInstructionIdExport; |
| 346 | } | 365 | } |
| ... | @@ -449,8 +468,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { | ... | @@ -449,8 +468,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { |
| 449 | return IrInstructionIdTestNonNull; | 468 | return IrInstructionIdTestNonNull; |
| 450 | } | 469 | } |
| 451 | 470 | ||
| 452 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) { | 471 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) { |
| 453 | return IrInstructionIdUnwrapOptional; | 472 | return IrInstructionIdOptionalUnwrapPtr; |
| 454 | } | 473 | } |
| 455 | 474 | ||
| 456 | static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { | 475 | static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { |
| ... | @@ -517,8 +536,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) { | ... | @@ -517,8 +536,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) { |
| 517 | return IrInstructionIdEmbedFile; | 536 | return IrInstructionIdEmbedFile; |
| 518 | } | 537 | } |
| 519 | 538 | ||
| 520 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) { | 539 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) { |
| 521 | return IrInstructionIdCmpxchg; | 540 | return IrInstructionIdCmpxchgSrc; |
| 541 | } | ||
| 542 | |||
| 543 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) { | ||
| 544 | return IrInstructionIdCmpxchgGen; | ||
| 522 | } | 545 | } |
| 523 | 546 | ||
| 524 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { | 547 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { |
| ... | @@ -565,6 +588,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) { | ... | @@ -565,6 +588,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) { |
| 565 | return IrInstructionIdIntType; | 588 | return IrInstructionIdIntType; |
| 566 | } | 589 | } |
| 567 | 590 | ||
| 591 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { | ||
| 592 | return IrInstructionIdVectorType; | ||
| 593 | } | ||
| 594 | |||
| 568 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { | 595 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 569 | return IrInstructionIdBoolNot; | 596 | return IrInstructionIdBoolNot; |
| 570 | } | 597 | } |
| ... | @@ -649,8 +676,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) | ... | @@ -649,8 +676,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) |
| 649 | return IrInstructionIdTestComptime; | 676 | return IrInstructionIdTestComptime; |
| 650 | } | 677 | } |
| 651 | 678 | ||
| 652 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) { | 679 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) { |
| 653 | return IrInstructionIdPtrCast; | 680 | return IrInstructionIdPtrCastSrc; |
| 681 | } | ||
| 682 | |||
| 683 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { | ||
| 684 | return IrInstructionIdPtrCastGen; | ||
| 654 | } | 685 | } |
| 655 | 686 | ||
| 656 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { | 687 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { |
| ... | @@ -869,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop | ... | @@ -869,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop |
| 869 | return IrInstructionIdCheckRuntimeScope; | 900 | return IrInstructionIdCheckRuntimeScope; |
| 870 | } | 901 | } |
| 871 | 902 | ||
| 903 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorToArray *) { | ||
| 904 | return IrInstructionIdVectorToArray; | ||
| 905 | } | ||
| 906 | |||
| 907 | static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) { | ||
| 908 | return IrInstructionIdArrayToVector; | ||
| 909 | } | ||
| 910 | |||
| 872 | template<typename T> | 911 | template<typename T> |
| 873 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 912 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 874 | T *special_instruction = allocate<T>(1); | 913 | T *special_instruction = allocate<T>(1); |
| ... | @@ -915,7 +954,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so | ... | @@ -915,7 +954,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so |
| 915 | ir_ref_instruction(condition, irb->current_basic_block); | 954 | ir_ref_instruction(condition, irb->current_basic_block); |
| 916 | ir_ref_bb(then_block); | 955 | ir_ref_bb(then_block); |
| 917 | ir_ref_bb(else_block); | 956 | ir_ref_bb(else_block); |
| 918 | if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); | 957 | if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); |
| 919 | 958 | ||
| 920 | return &cond_br_instruction->base; | 959 | return &cond_br_instruction->base; |
| 921 | } | 960 | } |
| ... | @@ -931,16 +970,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou | ... | @@ -931,16 +970,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou |
| 931 | return &return_instruction->base; | 970 | return &return_instruction->base; |
| 932 | } | 971 | } |
| 933 | 972 | ||
| 934 | static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 935 | ZigType *type_entry) | ||
| 936 | { | ||
| 937 | assert(type_entry); | ||
| 938 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node); | ||
| 939 | const_instruction->base.value.type = type_entry; | ||
| 940 | const_instruction->base.value.special = ConstValSpecialStatic; | ||
| 941 | return &const_instruction->base; | ||
| 942 | } | ||
| 943 | |||
| 944 | static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 973 | static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 945 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); | 974 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 946 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_void; | 975 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_void; |
| ... | @@ -1188,14 +1217,11 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc | ... | @@ -1188,14 +1217,11 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc |
| 1188 | call_instruction->async_allocator = async_allocator; | 1217 | call_instruction->async_allocator = async_allocator; |
| 1189 | call_instruction->new_stack = new_stack; | 1218 | call_instruction->new_stack = new_stack; |
| 1190 | 1219 | ||
| 1191 | if (fn_ref) | 1220 | if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); |
| 1192 | ir_ref_instruction(fn_ref, irb->current_basic_block); | ||
| 1193 | for (size_t i = 0; i < arg_count; i += 1) | 1221 | for (size_t i = 0; i < arg_count; i += 1) |
| 1194 | ir_ref_instruction(args[i], irb->current_basic_block); | 1222 | ir_ref_instruction(args[i], irb->current_basic_block); |
| 1195 | if (async_allocator) | 1223 | if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block); |
| 1196 | ir_ref_instruction(async_allocator, irb->current_basic_block); | 1224 | if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); |
| 1197 | if (new_stack != nullptr) | ||
| 1198 | ir_ref_instruction(new_stack, irb->current_basic_block); | ||
| 1199 | 1225 | ||
| 1200 | return &call_instruction->base; | 1226 | return &call_instruction->base; |
| 1201 | } | 1227 | } |
| ... | @@ -1280,7 +1306,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, | ... | @@ -1280,7 +1306,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, |
| 1280 | container_init_list_instruction->item_count = item_count; | 1306 | container_init_list_instruction->item_count = item_count; |
| 1281 | container_init_list_instruction->items = items; | 1307 | container_init_list_instruction->items = items; |
| 1282 | 1308 | ||
| 1283 | ir_ref_instruction(container_type, irb->current_basic_block); | 1309 | if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block); |
| 1284 | for (size_t i = 0; i < item_count; i += 1) { | 1310 | for (size_t i = 0; i < item_count; i += 1) { |
| 1285 | ir_ref_instruction(items[i], irb->current_basic_block); | 1311 | ir_ref_instruction(items[i], irb->current_basic_block); |
| 1286 | } | 1312 | } |
| ... | @@ -1355,10 +1381,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -1355,10 +1381,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * |
| 1355 | return &instruction->base; | 1381 | return &instruction->base; |
| 1356 | } | 1382 | } |
| 1357 | 1383 | ||
| 1358 | static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1384 | static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1359 | ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value) | 1385 | ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value) |
| 1360 | { | 1386 | { |
| 1361 | IrInstructionDeclVar *decl_var_instruction = ir_build_instruction<IrInstructionDeclVar>(irb, scope, source_node); | 1387 | IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction<IrInstructionDeclVarSrc>(irb, scope, source_node); |
| 1362 | decl_var_instruction->base.value.special = ConstValSpecialStatic; | 1388 | decl_var_instruction->base.value.special = ConstValSpecialStatic; |
| 1363 | decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; | 1389 | decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; |
| 1364 | decl_var_instruction->var = var; | 1390 | decl_var_instruction->var = var; |
| ... | @@ -1366,13 +1392,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -1366,13 +1392,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s |
| 1366 | decl_var_instruction->align_value = align_value; | 1392 | decl_var_instruction->align_value = align_value; |
| 1367 | decl_var_instruction->init_value = init_value; | 1393 | decl_var_instruction->init_value = init_value; |
| 1368 | 1394 | ||
| 1369 | if (var_type) ir_ref_instruction(var_type, irb->current_basic_block); | 1395 | if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); |
| 1370 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); | 1396 | if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); |
| 1371 | ir_ref_instruction(init_value, irb->current_basic_block); | 1397 | ir_ref_instruction(init_value, irb->current_basic_block); |
| 1372 | 1398 | ||
| 1373 | return &decl_var_instruction->base; | 1399 | return &decl_var_instruction->base; |
| 1374 | } | 1400 | } |
| 1375 | 1401 | ||
| 1402 | static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 1403 | ZigVar *var, IrInstruction *init_value) | ||
| 1404 | { | ||
| 1405 | IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction<IrInstructionDeclVarGen>(&ira->new_irb, | ||
| 1406 | source_instruction->scope, source_instruction->source_node); | ||
| 1407 | decl_var_instruction->base.value.special = ConstValSpecialStatic; | ||
| 1408 | decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void; | ||
| 1409 | decl_var_instruction->var = var; | ||
| 1410 | decl_var_instruction->init_value = init_value; | ||
| 1411 | |||
| 1412 | ir_ref_instruction(init_value, ira->new_irb.current_basic_block); | ||
| 1413 | |||
| 1414 | return &decl_var_instruction->base; | ||
| 1415 | } | ||
| 1416 | |||
| 1376 | static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1417 | static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1377 | IrInstruction *name, IrInstruction *target, IrInstruction *linkage) | 1418 | IrInstruction *name, IrInstruction *target, IrInstruction *linkage) |
| 1378 | { | 1419 | { |
| ... | @@ -1542,14 +1583,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod | ... | @@ -1542,14 +1583,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod |
| 1542 | return &instruction->base; | 1583 | return &instruction->base; |
| 1543 | } | 1584 | } |
| 1544 | 1585 | ||
| 1545 | static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, | 1586 | static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1546 | bool safety_check_on) | 1587 | IrInstruction *base_ptr, bool safety_check_on) |
| 1547 | { | 1588 | { |
| 1548 | IrInstructionUnwrapOptional *instruction = ir_build_instruction<IrInstructionUnwrapOptional>(irb, scope, source_node); | 1589 | IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction<IrInstructionOptionalUnwrapPtr>(irb, scope, source_node); |
| 1549 | instruction->value = value; | 1590 | instruction->base_ptr = base_ptr; |
| 1550 | instruction->safety_check_on = safety_check_on; | 1591 | instruction->safety_check_on = safety_check_on; |
| 1551 | 1592 | ||
| 1552 | ir_ref_instruction(value, irb->current_basic_block); | 1593 | ir_ref_instruction(base_ptr, irb->current_basic_block); |
| 1553 | 1594 | ||
| 1554 | return &instruction->base; | 1595 | return &instruction->base; |
| 1555 | } | 1596 | } |
| ... | @@ -1765,13 +1806,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -1765,13 +1806,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode |
| 1765 | return &instruction->base; | 1806 | return &instruction->base; |
| 1766 | } | 1807 | } |
| 1767 | 1808 | ||
| 1768 | static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, | 1809 | static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1769 | IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, | 1810 | IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, |
| 1770 | IrInstruction *success_order_value, IrInstruction *failure_order_value, | 1811 | IrInstruction *success_order_value, IrInstruction *failure_order_value, |
| 1771 | bool is_weak, | 1812 | bool is_weak) |
| 1772 | ZigType *type, AtomicOrder success_order, AtomicOrder failure_order) | ||
| 1773 | { | 1813 | { |
| 1774 | IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node); | 1814 | IrInstructionCmpxchgSrc *instruction = ir_build_instruction<IrInstructionCmpxchgSrc>(irb, scope, source_node); |
| 1775 | instruction->type_value = type_value; | 1815 | instruction->type_value = type_value; |
| 1776 | instruction->ptr = ptr; | 1816 | instruction->ptr = ptr; |
| 1777 | instruction->cmp_value = cmp_value; | 1817 | instruction->cmp_value = cmp_value; |
| ... | @@ -1779,16 +1819,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so | ... | @@ -1779,16 +1819,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so |
| 1779 | instruction->success_order_value = success_order_value; | 1819 | instruction->success_order_value = success_order_value; |
| 1780 | instruction->failure_order_value = failure_order_value; | 1820 | instruction->failure_order_value = failure_order_value; |
| 1781 | instruction->is_weak = is_weak; | 1821 | instruction->is_weak = is_weak; |
| 1782 | instruction->type = type; | ||
| 1783 | instruction->success_order = success_order; | ||
| 1784 | instruction->failure_order = failure_order; | ||
| 1785 | 1822 | ||
| 1786 | if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block); | 1823 | ir_ref_instruction(type_value, irb->current_basic_block); |
| 1787 | ir_ref_instruction(ptr, irb->current_basic_block); | 1824 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 1788 | ir_ref_instruction(cmp_value, irb->current_basic_block); | 1825 | ir_ref_instruction(cmp_value, irb->current_basic_block); |
| 1789 | ir_ref_instruction(new_value, irb->current_basic_block); | 1826 | ir_ref_instruction(new_value, irb->current_basic_block); |
| 1790 | if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block); | 1827 | ir_ref_instruction(success_order_value, irb->current_basic_block); |
| 1791 | if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block); | 1828 | ir_ref_instruction(failure_order_value, irb->current_basic_block); |
| 1829 | |||
| 1830 | return &instruction->base; | ||
| 1831 | } | ||
| 1832 | |||
| 1833 | static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 1834 | IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, | ||
| 1835 | AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) | ||
| 1836 | { | ||
| 1837 | IrInstructionCmpxchgGen *instruction = ir_build_instruction<IrInstructionCmpxchgGen>(&ira->new_irb, | ||
| 1838 | source_instruction->scope, source_instruction->source_node); | ||
| 1839 | instruction->ptr = ptr; | ||
| 1840 | instruction->cmp_value = cmp_value; | ||
| 1841 | instruction->new_value = new_value; | ||
| 1842 | instruction->success_order = success_order; | ||
| 1843 | instruction->failure_order = failure_order; | ||
| 1844 | instruction->is_weak = is_weak; | ||
| 1845 | |||
| 1846 | ir_ref_instruction(ptr, ira->new_irb.current_basic_block); | ||
| 1847 | ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); | ||
| 1848 | ir_ref_instruction(new_value, ira->new_irb.current_basic_block); | ||
| 1792 | 1849 | ||
| 1793 | return &instruction->base; | 1850 | return &instruction->base; |
| 1794 | } | 1851 | } |
| ... | @@ -1909,6 +1966,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -1909,6 +1966,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 1909 | return &instruction->base; | 1966 | return &instruction->base; |
| 1910 | } | 1967 | } |
| 1911 | 1968 | ||
| 1969 | static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *len, | ||
| 1970 | IrInstruction *elem_type) | ||
| 1971 | { | ||
| 1972 | IrInstructionVectorType *instruction = ir_build_instruction<IrInstructionVectorType>(irb, scope, source_node); | ||
| 1973 | instruction->len = len; | ||
| 1974 | instruction->elem_type = elem_type; | ||
| 1975 | |||
| 1976 | ir_ref_instruction(len, irb->current_basic_block); | ||
| 1977 | ir_ref_instruction(elem_type, irb->current_basic_block); | ||
| 1978 | |||
| 1979 | return &instruction->base; | ||
| 1980 | } | ||
| 1981 | |||
| 1912 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { | 1982 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 1913 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); | 1983 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 1914 | instruction->value = value; | 1984 | instruction->value = value; |
| ... | @@ -2060,12 +2130,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -2060,12 +2130,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s |
| 2060 | } | 2130 | } |
| 2061 | 2131 | ||
| 2062 | static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2132 | static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2063 | IrInstruction *value) | 2133 | IrInstruction *err_union) |
| 2064 | { | 2134 | { |
| 2065 | IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node); | 2135 | IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node); |
| 2066 | instruction->value = value; | 2136 | instruction->err_union = err_union; |
| 2067 | 2137 | ||
| 2068 | ir_ref_instruction(value, irb->current_basic_block); | 2138 | ir_ref_instruction(err_union, irb->current_basic_block); |
| 2069 | 2139 | ||
| 2070 | return &instruction->base; | 2140 | return &instruction->base; |
| 2071 | } | 2141 | } |
| ... | @@ -2115,20 +2185,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -2115,20 +2185,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo |
| 2115 | return &instruction->base; | 2185 | return &instruction->base; |
| 2116 | } | 2186 | } |
| 2117 | 2187 | ||
| 2118 | static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2188 | static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2119 | IrInstruction *dest_type, IrInstruction *ptr) | 2189 | IrInstruction *dest_type, IrInstruction *ptr) |
| 2120 | { | 2190 | { |
| 2121 | IrInstructionPtrCast *instruction = ir_build_instruction<IrInstructionPtrCast>( | 2191 | IrInstructionPtrCastSrc *instruction = ir_build_instruction<IrInstructionPtrCastSrc>( |
| 2122 | irb, scope, source_node); | 2192 | irb, scope, source_node); |
| 2123 | instruction->dest_type = dest_type; | 2193 | instruction->dest_type = dest_type; |
| 2124 | instruction->ptr = ptr; | 2194 | instruction->ptr = ptr; |
| 2125 | 2195 | ||
| 2126 | if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); | 2196 | ir_ref_instruction(dest_type, irb->current_basic_block); |
| 2127 | ir_ref_instruction(ptr, irb->current_basic_block); | 2197 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 2128 | 2198 | ||
| 2129 | return &instruction->base; | 2199 | return &instruction->base; |
| 2130 | } | 2200 | } |
| 2131 | 2201 | ||
| 2202 | static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 2203 | ZigType *ptr_type, IrInstruction *ptr) | ||
| 2204 | { | ||
| 2205 | IrInstructionPtrCastGen *instruction = ir_build_instruction<IrInstructionPtrCastGen>( | ||
| 2206 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | ||
| 2207 | instruction->base.value.type = ptr_type; | ||
| 2208 | instruction->ptr = ptr; | ||
| 2209 | |||
| 2210 | ir_ref_instruction(ptr, ira->new_irb.current_basic_block); | ||
| 2211 | |||
| 2212 | return &instruction->base; | ||
| 2213 | } | ||
| 2214 | |||
| 2132 | static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2215 | static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2133 | IrInstruction *dest_type, IrInstruction *value) | 2216 | IrInstruction *dest_type, IrInstruction *value) |
| 2134 | { | 2217 | { |
| ... | @@ -2747,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, | ... | @@ -2747,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, |
| 2747 | return &instruction->base; | 2830 | return &instruction->base; |
| 2748 | } | 2831 | } |
| 2749 | 2832 | ||
| 2833 | static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 2834 | IrInstruction *vector, ZigType *result_type) | ||
| 2835 | { | ||
| 2836 | IrInstructionVectorToArray *instruction = ir_build_instruction<IrInstructionVectorToArray>(&ira->new_irb, | ||
| 2837 | source_instruction->scope, source_instruction->source_node); | ||
| 2838 | instruction->base.value.type = result_type; | ||
| 2839 | instruction->vector = vector; | ||
| 2840 | |||
| 2841 | ir_ref_instruction(vector, ira->new_irb.current_basic_block); | ||
| 2842 | |||
| 2843 | ir_add_alloca(ira, &instruction->base, result_type); | ||
| 2844 | |||
| 2845 | return &instruction->base; | ||
| 2846 | } | ||
| 2847 | |||
| 2848 | static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 2849 | IrInstruction *array, ZigType *result_type) | ||
| 2850 | { | ||
| 2851 | IrInstructionArrayToVector *instruction = ir_build_instruction<IrInstructionArrayToVector>(&ira->new_irb, | ||
| 2852 | source_instruction->scope, source_instruction->source_node); | ||
| 2853 | instruction->base.value.type = result_type; | ||
| 2854 | instruction->array = array; | ||
| 2855 | |||
| 2856 | ir_ref_instruction(array, ira->new_irb.current_basic_block); | ||
| 2857 | |||
| 2858 | return &instruction->base; | ||
| 2859 | } | ||
| 2860 | |||
| 2750 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2861 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2751 | results[ReturnKindUnconditional] = 0; | 2862 | results[ReturnKindUnconditional] = 0; |
| 2752 | results[ReturnKindError] = 0; | 2863 | results[ReturnKindError] = 0; |
| ... | @@ -2807,10 +2918,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o | ... | @@ -2807,10 +2918,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 2807 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; | 2918 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; |
| 2808 | IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); | 2919 | IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); |
| 2809 | if (defer_expr_value != irb->codegen->invalid_instruction) { | 2920 | if (defer_expr_value != irb->codegen->invalid_instruction) { |
| 2810 | if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) { | 2921 | if (defer_expr_value->value.type != nullptr && |
| 2922 | defer_expr_value->value.type->id == ZigTypeIdUnreachable) | ||
| 2923 | { | ||
| 2811 | is_noreturn = true; | 2924 | is_noreturn = true; |
| 2812 | } else { | 2925 | } else { |
| 2813 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value)); | 2926 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, |
| 2927 | defer_expr_value)); | ||
| 2814 | } | 2928 | } |
| 2815 | } | 2929 | } |
| 2816 | } | 2930 | } |
| ... | @@ -3065,7 +3179,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s | ... | @@ -3065,7 +3179,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 3065 | variable_entry->mem_slot_index = SIZE_MAX; | 3179 | variable_entry->mem_slot_index = SIZE_MAX; |
| 3066 | variable_entry->is_comptime = is_comptime; | 3180 | variable_entry->is_comptime = is_comptime; |
| 3067 | variable_entry->src_arg_index = SIZE_MAX; | 3181 | variable_entry->src_arg_index = SIZE_MAX; |
| 3068 | variable_entry->value = create_const_vals(1); | 3182 | variable_entry->const_value = create_const_vals(1); |
| 3069 | 3183 | ||
| 3070 | if (is_comptime != nullptr) { | 3184 | if (is_comptime != nullptr) { |
| 3071 | is_comptime->ref_count += 1; | 3185 | is_comptime->ref_count += 1; |
| ... | @@ -3080,20 +3194,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s | ... | @@ -3080,20 +3194,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 3080 | ErrorMsg *msg = add_node_error(codegen, node, | 3194 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3081 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 3195 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 3082 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); | 3196 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 3083 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3197 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 3084 | } else { | 3198 | } else { |
| 3085 | ZigType *type; | 3199 | ZigType *type; |
| 3086 | if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { | 3200 | if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { |
| 3087 | add_node_error(codegen, node, | 3201 | add_node_error(codegen, node, |
| 3088 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | 3202 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); |
| 3089 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3203 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 3090 | } else { | 3204 | } else { |
| 3091 | Tld *tld = find_decl(codegen, parent_scope, name); | 3205 | Tld *tld = find_decl(codegen, parent_scope, name); |
| 3092 | if (tld != nullptr) { | 3206 | if (tld != nullptr) { |
| 3093 | ErrorMsg *msg = add_node_error(codegen, node, | 3207 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3094 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 3208 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 3095 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); | 3209 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); |
| 3096 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3210 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 3097 | } | 3211 | } |
| 3098 | } | 3212 | } |
| 3099 | } | 3213 | } |
| ... | @@ -3156,7 +3270,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3156,7 +3270,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3156 | scope_block->incoming_blocks = &incoming_blocks; | 3270 | scope_block->incoming_blocks = &incoming_blocks; |
| 3157 | scope_block->incoming_values = &incoming_values; | 3271 | scope_block->incoming_values = &incoming_values; |
| 3158 | scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); | 3272 | scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); |
| 3159 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope)); | 3273 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, |
| 3274 | ir_should_inline(irb->exec, parent_scope)); | ||
| 3160 | } | 3275 | } |
| 3161 | 3276 | ||
| 3162 | bool is_continuation_unreachable = false; | 3277 | bool is_continuation_unreachable = false; |
| ... | @@ -3174,9 +3289,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3174,9 +3289,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3174 | // defer starts a new scope | 3289 | // defer starts a new scope |
| 3175 | child_scope = statement_node->data.defer.child_scope; | 3290 | child_scope = statement_node->data.defer.child_scope; |
| 3176 | assert(child_scope); | 3291 | assert(child_scope); |
| 3177 | } else if (statement_value->id == IrInstructionIdDeclVar) { | 3292 | } else if (statement_value->id == IrInstructionIdDeclVarSrc) { |
| 3178 | // variable declarations start a new scope | 3293 | // variable declarations start a new scope |
| 3179 | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; | 3294 | IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value; |
| 3180 | child_scope = decl_var_instruction->var->child_scope; | 3295 | child_scope = decl_var_instruction->var->child_scope; |
| 3181 | } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) { | 3296 | } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) { |
| 3182 | // this statement's value must be void | 3297 | // this statement's value must be void |
| ... | @@ -3331,7 +3446,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -3331,7 +3446,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod |
| 3331 | return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); | 3446 | return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); |
| 3332 | } | 3447 | } |
| 3333 | 3448 | ||
| 3334 | static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 3449 | static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 3335 | assert(node->type == NodeTypeBinOpExpr); | 3450 | assert(node->type == NodeTypeBinOpExpr); |
| 3336 | 3451 | ||
| 3337 | AstNode *op1_node = node->data.bin_op_expr.op1; | 3452 | AstNode *op1_node = node->data.bin_op_expr.op1; |
| ... | @@ -3365,7 +3480,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As | ... | @@ -3365,7 +3480,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As |
| 3365 | ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); | 3480 | ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); |
| 3366 | 3481 | ||
| 3367 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | 3482 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 3368 | IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false); | 3483 | IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); |
| 3369 | IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); | 3484 | IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); |
| 3370 | IrBasicBlock *after_ok_block = irb->current_basic_block; | 3485 | IrBasicBlock *after_ok_block = irb->current_basic_block; |
| 3371 | ir_build_br(irb, parent_scope, node, end_block, is_comptime); | 3486 | ir_build_br(irb, parent_scope, node, end_block, is_comptime); |
| ... | @@ -3483,7 +3598,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -3483,7 +3598,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 3483 | case BinOpTypeMergeErrorSets: | 3598 | case BinOpTypeMergeErrorSets: |
| 3484 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); | 3599 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); |
| 3485 | case BinOpTypeUnwrapOptional: | 3600 | case BinOpTypeUnwrapOptional: |
| 3486 | return ir_gen_maybe_ok_or(irb, scope, node); | 3601 | return ir_gen_orelse(irb, scope, node); |
| 3487 | case BinOpTypeErrorUnion: | 3602 | case BinOpTypeErrorUnion: |
| 3488 | return ir_gen_error_union(irb, scope, node); | 3603 | return ir_gen_error_union(irb, scope, node); |
| 3489 | } | 3604 | } |
| ... | @@ -3542,6 +3657,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3542,6 +3657,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3542 | buf_ptr(variable_name))); | 3657 | buf_ptr(variable_name))); |
| 3543 | return irb->codegen->invalid_instruction; | 3658 | return irb->codegen->invalid_instruction; |
| 3544 | } | 3659 | } |
| 3660 | assert(err == ErrorPrimitiveTypeNotFound); | ||
| 3545 | } else { | 3661 | } else { |
| 3546 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); | 3662 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); |
| 3547 | if (lval == LValPtr) { | 3663 | if (lval == LValPtr) { |
| ... | @@ -3904,9 +4020,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -3904,9 +4020,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 3904 | if (arg5_value == irb->codegen->invalid_instruction) | 4020 | if (arg5_value == irb->codegen->invalid_instruction) |
| 3905 | return arg5_value; | 4021 | return arg5_value; |
| 3906 | 4022 | ||
| 3907 | IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value, | 4023 | IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, |
| 3908 | arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), | 4024 | arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); |
| 3909 | nullptr, AtomicOrderUnordered, AtomicOrderUnordered); | ||
| 3910 | return ir_lval_wrap(irb, scope, cmpxchg, lval); | 4025 | return ir_lval_wrap(irb, scope, cmpxchg, lval); |
| 3911 | } | 4026 | } |
| 3912 | case BuiltinFnIdFence: | 4027 | case BuiltinFnIdFence: |
| ... | @@ -4169,6 +4284,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4169,6 +4284,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4169 | IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); | 4284 | IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); |
| 4170 | return ir_lval_wrap(irb, scope, int_type, lval); | 4285 | return ir_lval_wrap(irb, scope, int_type, lval); |
| 4171 | } | 4286 | } |
| 4287 | case BuiltinFnIdVectorType: | ||
| 4288 | { | ||
| 4289 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4290 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4291 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4292 | return arg0_value; | ||
| 4293 | |||
| 4294 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4295 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4296 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4297 | return arg1_value; | ||
| 4298 | |||
| 4299 | IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); | ||
| 4300 | return ir_lval_wrap(irb, scope, vector_type, lval); | ||
| 4301 | } | ||
| 4172 | case BuiltinFnIdMemcpy: | 4302 | case BuiltinFnIdMemcpy: |
| 4173 | { | 4303 | { |
| 4174 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4304 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -4346,7 +4476,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4346,7 +4476,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4346 | if (arg1_value == irb->codegen->invalid_instruction) | 4476 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4347 | return arg1_value; | 4477 | return arg1_value; |
| 4348 | 4478 | ||
| 4349 | IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value); | 4479 | IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); |
| 4350 | return ir_lval_wrap(irb, scope, ptr_cast, lval); | 4480 | return ir_lval_wrap(irb, scope, ptr_cast, lval); |
| 4351 | } | 4481 | } |
| 4352 | case BuiltinFnIdBitCast: | 4482 | case BuiltinFnIdBitCast: |
| ... | @@ -4784,7 +4914,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -4784,7 +4914,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 4784 | } | 4914 | } |
| 4785 | } | 4915 | } |
| 4786 | 4916 | ||
| 4787 | IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr); | 4917 | IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, |
| 4918 | is_async, async_allocator, nullptr); | ||
| 4788 | return ir_lval_wrap(irb, scope, fn_call, lval); | 4919 | return ir_lval_wrap(irb, scope, fn_call, lval); |
| 4789 | } | 4920 | } |
| 4790 | 4921 | ||
| ... | @@ -4793,7 +4924,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -4793,7 +4924,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 4793 | 4924 | ||
| 4794 | IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); | 4925 | IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); |
| 4795 | if (condition == irb->codegen->invalid_instruction) | 4926 | if (condition == irb->codegen->invalid_instruction) |
| 4796 | return condition; | 4927 | return irb->codegen->invalid_instruction; |
| 4797 | 4928 | ||
| 4798 | IrInstruction *is_comptime; | 4929 | IrInstruction *is_comptime; |
| 4799 | if (ir_should_inline(irb->exec, scope)) { | 4930 | if (ir_should_inline(irb->exec, scope)) { |
| ... | @@ -4816,7 +4947,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -4816,7 +4947,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 4816 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); | 4947 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); |
| 4817 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); | 4948 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); |
| 4818 | if (then_expr_result == irb->codegen->invalid_instruction) | 4949 | if (then_expr_result == irb->codegen->invalid_instruction) |
| 4819 | return then_expr_result; | 4950 | return irb->codegen->invalid_instruction; |
| 4820 | IrBasicBlock *after_then_block = irb->current_basic_block; | 4951 | IrBasicBlock *after_then_block = irb->current_basic_block; |
| 4821 | if (!instr_is_unreachable(then_expr_result)) | 4952 | if (!instr_is_unreachable(then_expr_result)) |
| 4822 | ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); | 4953 | ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); |
| ... | @@ -4826,7 +4957,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -4826,7 +4957,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 4826 | if (else_node) { | 4957 | if (else_node) { |
| 4827 | else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); | 4958 | else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); |
| 4828 | if (else_expr_result == irb->codegen->invalid_instruction) | 4959 | if (else_expr_result == irb->codegen->invalid_instruction) |
| 4829 | return else_expr_result; | 4960 | return irb->codegen->invalid_instruction; |
| 4830 | } else { | 4961 | } else { |
| 4831 | else_expr_result = ir_build_const_void(irb, scope, node); | 4962 | else_expr_result = ir_build_const_void(irb, scope, node); |
| 4832 | } | 4963 | } |
| ... | @@ -4927,7 +5058,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -4927,7 +5058,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 4927 | ptr_len, align_value, bit_offset_start, host_int_bytes); | 5058 | ptr_len, align_value, bit_offset_start, host_int_bytes); |
| 4928 | } | 5059 | } |
| 4929 | 5060 | ||
| 4930 | static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, | 5061 | static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, |
| 4931 | LVal lval) | 5062 | LVal lval) |
| 4932 | { | 5063 | { |
| 4933 | IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); | 5064 | IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); |
| ... | @@ -5053,11 +5184,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5053,11 +5184,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5053 | ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); | 5184 | ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); |
| 5054 | ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, | 5185 | ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, |
| 5055 | is_const, is_const, is_shadowable, is_comptime); | 5186 | is_const, is_const, is_shadowable, is_comptime); |
| 5056 | // we detect IrInstructionIdDeclVar in gen_block to make sure the next node | 5187 | // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node |
| 5057 | // is inside var->child_scope | 5188 | // is inside var->child_scope |
| 5058 | 5189 | ||
| 5059 | if (!is_extern && !variable_declaration->expr) { | 5190 | if (!is_extern && !variable_declaration->expr) { |
| 5060 | var->value->type = irb->codegen->builtin_types.entry_invalid; | 5191 | var->var_type = irb->codegen->builtin_types.entry_invalid; |
| 5061 | add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); | 5192 | add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); |
| 5062 | return irb->codegen->invalid_instruction; | 5193 | return irb->codegen->invalid_instruction; |
| 5063 | } | 5194 | } |
| ... | @@ -5084,7 +5215,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5084,7 +5215,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5084 | if (init_value == irb->codegen->invalid_instruction) | 5215 | if (init_value == irb->codegen->invalid_instruction) |
| 5085 | return init_value; | 5216 | return init_value; |
| 5086 | 5217 | ||
| 5087 | return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value); | 5218 | return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value); |
| 5088 | } | 5219 | } |
| 5089 | 5220 | ||
| 5090 | static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 5221 | static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | @@ -5140,7 +5271,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -5140,7 +5271,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 5140 | err_val_ptr, false); | 5271 | err_val_ptr, false); |
| 5141 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? | 5272 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 5142 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); | 5273 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); |
| 5143 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); | 5274 | ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); |
| 5144 | } | 5275 | } |
| 5145 | 5276 | ||
| 5146 | ZigList<IrInstruction *> incoming_values = {0}; | 5277 | ZigList<IrInstruction *> incoming_values = {0}; |
| ... | @@ -5180,7 +5311,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -5180,7 +5311,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 5180 | true, false, false, is_comptime); | 5311 | true, false, false, is_comptime); |
| 5181 | Scope *err_scope = err_var->child_scope; | 5312 | Scope *err_scope = err_var->child_scope; |
| 5182 | IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); | 5313 | IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); |
| 5183 | ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); | 5314 | ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); |
| 5184 | 5315 | ||
| 5185 | IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); | 5316 | IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); |
| 5186 | if (else_result == irb->codegen->invalid_instruction) | 5317 | if (else_result == irb->codegen->invalid_instruction) |
| ... | @@ -5220,10 +5351,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -5220,10 +5351,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 5220 | } | 5351 | } |
| 5221 | 5352 | ||
| 5222 | ir_set_cursor_at_end_and_append_block(irb, body_block); | 5353 | ir_set_cursor_at_end_and_append_block(irb, body_block); |
| 5223 | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false); | 5354 | IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); |
| 5224 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? | 5355 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 5225 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); | 5356 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); |
| 5226 | ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); | 5357 | ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); |
| 5227 | 5358 | ||
| 5228 | ZigList<IrInstruction *> incoming_values = {0}; | 5359 | ZigList<IrInstruction *> incoming_values = {0}; |
| 5229 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | 5360 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| ... | @@ -5380,7 +5511,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -5380,7 +5511,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5380 | Scope *child_scope = elem_var->child_scope; | 5511 | Scope *child_scope = elem_var->child_scope; |
| 5381 | 5512 | ||
| 5382 | IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); | 5513 | IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); |
| 5383 | ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); | 5514 | ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); |
| 5384 | IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); | 5515 | IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); |
| 5385 | 5516 | ||
| 5386 | AstNode *index_var_source_node; | 5517 | AstNode *index_var_source_node; |
| ... | @@ -5398,7 +5529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -5398,7 +5529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5398 | IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); | 5529 | IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); |
| 5399 | IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); | 5530 | IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); |
| 5400 | IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); | 5531 | IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); |
| 5401 | ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); | 5532 | ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); |
| 5402 | IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); | 5533 | IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); |
| 5403 | 5534 | ||
| 5404 | 5535 | ||
| ... | @@ -5622,8 +5753,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5622,8 +5753,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5622 | return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile); | 5753 | return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile); |
| 5623 | } | 5754 | } |
| 5624 | 5755 | ||
| 5625 | static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 5756 | static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5626 | assert(node->type == NodeTypeTestExpr); | 5757 | assert(node->type == NodeTypeIfOptional); |
| 5627 | 5758 | ||
| 5628 | Buf *var_symbol = node->data.test_expr.var_symbol; | 5759 | Buf *var_symbol = node->data.test_expr.var_symbol; |
| 5629 | AstNode *expr_node = node->data.test_expr.target_node; | 5760 | AstNode *expr_node = node->data.test_expr.target_node; |
| ... | @@ -5661,9 +5792,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no | ... | @@ -5661,9 +5792,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no |
| 5661 | ZigVar *var = ir_create_var(irb, node, subexpr_scope, | 5792 | ZigVar *var = ir_create_var(irb, node, subexpr_scope, |
| 5662 | var_symbol, is_const, is_const, is_shadowable, is_comptime); | 5793 | var_symbol, is_const, is_const, is_shadowable, is_comptime); |
| 5663 | 5794 | ||
| 5664 | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false); | 5795 | IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); |
| 5665 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); | 5796 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); |
| 5666 | ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); | 5797 | ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); |
| 5667 | var_scope = var->child_scope; | 5798 | var_scope = var->child_scope; |
| 5668 | } else { | 5799 | } else { |
| 5669 | var_scope = subexpr_scope; | 5800 | var_scope = subexpr_scope; |
| ... | @@ -5738,7 +5869,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -5738,7 +5869,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 5738 | 5869 | ||
| 5739 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); | 5870 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); |
| 5740 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); | 5871 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); |
| 5741 | ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); | 5872 | ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); |
| 5742 | var_scope = var->child_scope; | 5873 | var_scope = var->child_scope; |
| 5743 | } else { | 5874 | } else { |
| 5744 | var_scope = subexpr_scope; | 5875 | var_scope = subexpr_scope; |
| ... | @@ -5763,7 +5894,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -5763,7 +5894,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 5763 | err_symbol, is_const, is_const, is_shadowable, is_comptime); | 5894 | err_symbol, is_const, is_const, is_shadowable, is_comptime); |
| 5764 | 5895 | ||
| 5765 | IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); | 5896 | IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); |
| 5766 | ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); | 5897 | ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); |
| 5767 | err_var_scope = var->child_scope; | 5898 | err_var_scope = var->child_scope; |
| 5768 | } else { | 5899 | } else { |
| 5769 | err_var_scope = subexpr_scope; | 5900 | err_var_scope = subexpr_scope; |
| ... | @@ -5818,7 +5949,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit | ... | @@ -5818,7 +5949,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 5818 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); | 5949 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); |
| 5819 | } | 5950 | } |
| 5820 | IrInstruction *var_type = nullptr; // infer the type | 5951 | IrInstruction *var_type = nullptr; // infer the type |
| 5821 | ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); | 5952 | ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); |
| 5822 | } else { | 5953 | } else { |
| 5823 | child_scope = scope; | 5954 | child_scope = scope; |
| 5824 | } | 5955 | } |
| ... | @@ -6228,7 +6359,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -6228,7 +6359,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) |
| 6228 | return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); | 6359 | return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); |
| 6229 | } | 6360 | } |
| 6230 | 6361 | ||
| 6231 | static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 6362 | static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 6232 | assert(node->type == NodeTypeUnwrapErrorExpr); | 6363 | assert(node->type == NodeTypeUnwrapErrorExpr); |
| 6233 | 6364 | ||
| 6234 | AstNode *op1_node = node->data.unwrap_err_expr.op1; | 6365 | AstNode *op1_node = node->data.unwrap_err_expr.op1; |
| ... | @@ -6242,7 +6373,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN | ... | @@ -6242,7 +6373,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 6242 | add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); | 6373 | add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); |
| 6243 | return irb->codegen->invalid_instruction; | 6374 | return irb->codegen->invalid_instruction; |
| 6244 | } | 6375 | } |
| 6245 | return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone); | 6376 | return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone); |
| 6246 | } | 6377 | } |
| 6247 | 6378 | ||
| 6248 | 6379 | ||
| ... | @@ -6276,7 +6407,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN | ... | @@ -6276,7 +6407,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 6276 | is_const, is_const, is_shadowable, is_comptime); | 6407 | is_const, is_const, is_shadowable, is_comptime); |
| 6277 | err_scope = var->child_scope; | 6408 | err_scope = var->child_scope; |
| 6278 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); | 6409 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); |
| 6279 | ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val); | 6410 | ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val); |
| 6280 | } else { | 6411 | } else { |
| 6281 | err_scope = parent_scope; | 6412 | err_scope = parent_scope; |
| 6282 | } | 6413 | } |
| ... | @@ -6312,7 +6443,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o | ... | @@ -6312,7 +6443,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o |
| 6312 | ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; | 6443 | ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; |
| 6313 | if (need_comma) | 6444 | if (need_comma) |
| 6314 | buf_append_char(name, ','); | 6445 | buf_append_char(name, ','); |
| 6315 | render_const_value(codegen, name, var_scope->var->value); | 6446 | // TODO: const ptr reinterpret here to make the var type agree with the value? |
| 6447 | render_const_value(codegen, name, var_scope->var->const_value); | ||
| 6316 | return true; | 6448 | return true; |
| 6317 | } | 6449 | } |
| 6318 | 6450 | ||
| ... | @@ -6562,7 +6694,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -6562,7 +6694,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode |
| 6562 | IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 | 6694 | IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 |
| 6563 | 6695 | ||
| 6564 | // TODO relies on Zig not re-ordering fields | 6696 | // TODO relies on Zig not re-ordering fields |
| 6565 | IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); | 6697 | IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); |
| 6566 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); | 6698 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); |
| 6567 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); | 6699 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6568 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, | 6700 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| ... | @@ -6640,7 +6772,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -6640,7 +6772,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode |
| 6640 | get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); | 6772 | get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); |
| 6641 | 6773 | ||
| 6642 | // TODO relies on Zig not re-ordering fields | 6774 | // TODO relies on Zig not re-ordering fields |
| 6643 | IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); | 6775 | IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); |
| 6644 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); | 6776 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); |
| 6645 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); | 6777 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6646 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, | 6778 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| ... | @@ -6756,7 +6888,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -6756,7 +6888,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 6756 | IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); | 6888 | IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); |
| 6757 | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); | 6889 | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); |
| 6758 | ir_build_await_bookkeeping(irb, scope, node, promise_result_type); | 6890 | ir_build_await_bookkeeping(irb, scope, node, promise_result_type); |
| 6759 | ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); | 6891 | ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); |
| 6760 | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); | 6892 | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); |
| 6761 | ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); | 6893 | ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); |
| 6762 | IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); | 6894 | IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); |
| ... | @@ -7050,7 +7182,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -7050,7 +7182,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7050 | if (maybe_ptr == irb->codegen->invalid_instruction) | 7182 | if (maybe_ptr == irb->codegen->invalid_instruction) |
| 7051 | return irb->codegen->invalid_instruction; | 7183 | return irb->codegen->invalid_instruction; |
| 7052 | 7184 | ||
| 7053 | IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true); | 7185 | IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); |
| 7054 | if (lval == LValPtr) | 7186 | if (lval == LValPtr) |
| 7055 | return unwrapped_ptr; | 7187 | return unwrapped_ptr; |
| 7056 | 7188 | ||
| ... | @@ -7074,8 +7206,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -7074,8 +7206,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7074 | return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); | 7206 | return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); |
| 7075 | case NodeTypeIfErrorExpr: | 7207 | case NodeTypeIfErrorExpr: |
| 7076 | return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); | 7208 | return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); |
| 7077 | case NodeTypeTestExpr: | 7209 | case NodeTypeIfOptional: |
| 7078 | return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); | 7210 | return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); |
| 7079 | case NodeTypeSwitchExpr: | 7211 | case NodeTypeSwitchExpr: |
| 7080 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); | 7212 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); |
| 7081 | case NodeTypeCompTime: | 7213 | case NodeTypeCompTime: |
| ... | @@ -7093,7 +7225,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -7093,7 +7225,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7093 | case NodeTypeSliceExpr: | 7225 | case NodeTypeSliceExpr: |
| 7094 | return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); | 7226 | return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); |
| 7095 | case NodeTypeUnwrapErrorExpr: | 7227 | case NodeTypeUnwrapErrorExpr: |
| 7096 | return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); | 7228 | return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); |
| 7097 | case NodeTypeContainerDecl: | 7229 | case NodeTypeContainerDecl: |
| 7098 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); | 7230 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 7099 | case NodeTypeFnProto: | 7231 | case NodeTypeFnProto: |
| ... | @@ -7152,6 +7284,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7152,6 +7284,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7152 | ir_ref_bb(irb->current_basic_block); | 7284 | ir_ref_bb(irb->current_basic_block); |
| 7153 | 7285 | ||
| 7154 | ZigFn *fn_entry = exec_fn_entry(irb->exec); | 7286 | ZigFn *fn_entry = exec_fn_entry(irb->exec); |
| 7287 | |||
| 7155 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | 7288 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 7156 | IrInstruction *coro_id; | 7289 | IrInstruction *coro_id; |
| 7157 | IrInstruction *u8_ptr_type; | 7290 | IrInstruction *u8_ptr_type; |
| ... | @@ -7172,27 +7305,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7172,27 +7305,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7172 | ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); | 7305 | ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); |
| 7173 | IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); | 7306 | IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); |
| 7174 | // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa | 7307 | // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa |
| 7175 | ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); | 7308 | ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); |
| 7176 | coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); | 7309 | coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); |
| 7177 | 7310 | ||
| 7178 | ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | 7311 | ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 7179 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); | 7312 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); |
| 7180 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, | 7313 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, |
| 7181 | get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); | 7314 | get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); |
| 7182 | ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | 7315 | ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); |
| 7183 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); | 7316 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); |
| 7184 | 7317 | ||
| 7185 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, | 7318 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, |
| 7186 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); | 7319 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); |
| 7187 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); | 7320 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); |
| 7188 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); | 7321 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); |
| 7189 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | 7322 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 7190 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); | 7323 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); |
| 7191 | ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); | 7324 | ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); |
| 7192 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, | 7325 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, |
| 7193 | ImplicitAllocatorIdArg); | 7326 | ImplicitAllocatorIdArg); |
| 7194 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); | 7327 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); |
| 7195 | ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | 7328 | ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); |
| 7196 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); | 7329 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); |
| 7197 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); | 7330 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); |
| 7198 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); | 7331 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); |
| ... | @@ -7208,7 +7341,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7208,7 +7341,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7208 | ir_build_return(irb, coro_scope, node, undef); | 7341 | ir_build_return(irb, coro_scope, node, undef); |
| 7209 | 7342 | ||
| 7210 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); | 7343 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); |
| 7211 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); | 7344 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); |
| 7212 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); | 7345 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); |
| 7213 | 7346 | ||
| 7214 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); | 7347 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| ... | @@ -7286,8 +7419,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7286,8 +7419,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7286 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, | 7419 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, |
| 7287 | false, false, PtrLenUnknown, 0, 0, 0)); | 7420 | false, false, PtrLenUnknown, 0, 0, 0)); |
| 7288 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); | 7421 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 7289 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); | 7422 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); |
| 7290 | IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, | 7423 | IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, |
| 7291 | irb->exec->coro_result_field_ptr); | 7424 | irb->exec->coro_result_field_ptr); |
| 7292 | IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, | 7425 | IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, |
| 7293 | fn_entry->type_entry->data.fn.fn_type_id.return_type); | 7426 | fn_entry->type_entry->data.fn.fn_type_id.return_type); |
| ... | @@ -7303,7 +7436,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7303,7 +7436,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7303 | // Before we destroy the coroutine frame, we need to load the target promise into | 7436 | // Before we destroy the coroutine frame, we need to load the target promise into |
| 7304 | // a register or local variable which does not get spilled into the frame, | 7437 | // a register or local variable which does not get spilled into the frame, |
| 7305 | // otherwise llvm tries to access memory inside the destroyed frame. | 7438 | // otherwise llvm tries to access memory inside the destroyed frame. |
| 7306 | IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, | 7439 | IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, |
| 7307 | irb->exec->await_handle_var_ptr, false); | 7440 | irb->exec->await_handle_var_ptr, false); |
| 7308 | IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); | 7441 | IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); |
| 7309 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); | 7442 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| ... | @@ -7338,7 +7471,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7338,7 +7471,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7338 | IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, | 7471 | IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, |
| 7339 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, | 7472 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, |
| 7340 | false, false, PtrLenUnknown, 0, 0, 0)); | 7473 | false, false, PtrLenUnknown, 0, 0, 0)); |
| 7341 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); | 7474 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); |
| 7342 | IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); | 7475 | IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); |
| 7343 | IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); | 7476 | IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); |
| 7344 | IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); | 7477 | IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); |
| ... | @@ -7435,7 +7568,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal | ... | @@ -7435,7 +7568,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal |
| 7435 | return val; | 7568 | return val; |
| 7436 | } | 7569 | } |
| 7437 | 7570 | ||
| 7438 | static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { | 7571 | static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { |
| 7439 | IrBasicBlock *bb = exec->basic_block_list.at(0); | 7572 | IrBasicBlock *bb = exec->basic_block_list.at(0); |
| 7440 | for (size_t i = 0; i < bb->instruction_list.length; i += 1) { | 7573 | for (size_t i = 0; i < bb->instruction_list.length; i += 1) { |
| 7441 | IrInstruction *instruction = bb->instruction_list.at(i); | 7574 | IrInstruction *instruction = bb->instruction_list.at(i); |
| ... | @@ -7445,16 +7578,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) | ... | @@ -7445,16 +7578,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) |
| 7445 | if (value->value.special == ConstValSpecialRuntime) { | 7578 | if (value->value.special == ConstValSpecialRuntime) { |
| 7446 | exec_add_error_node(codegen, exec, value->source_node, | 7579 | exec_add_error_node(codegen, exec, value->source_node, |
| 7447 | buf_sprintf("unable to evaluate constant expression")); | 7580 | buf_sprintf("unable to evaluate constant expression")); |
| 7448 | return codegen->invalid_instruction; | 7581 | return &codegen->invalid_instruction->value; |
| 7449 | } | 7582 | } |
| 7450 | return value; | 7583 | return &value->value; |
| 7451 | } else if (ir_has_side_effects(instruction)) { | 7584 | } else if (ir_has_side_effects(instruction)) { |
| 7452 | exec_add_error_node(codegen, exec, instruction->source_node, | 7585 | exec_add_error_node(codegen, exec, instruction->source_node, |
| 7453 | buf_sprintf("unable to evaluate constant expression")); | 7586 | buf_sprintf("unable to evaluate constant expression")); |
| 7454 | return codegen->invalid_instruction; | 7587 | return &codegen->invalid_instruction->value; |
| 7455 | } | 7588 | } |
| 7456 | } | 7589 | } |
| 7457 | return codegen->invalid_instruction; | 7590 | return &codegen->invalid_instruction->value; |
| 7458 | } | 7591 | } |
| 7459 | 7592 | ||
| 7460 | static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { | 7593 | static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { |
| ... | @@ -8174,6 +8307,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc | ... | @@ -8174,6 +8307,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 8174 | 8307 | ||
| 8175 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); | 8308 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); |
| 8176 | bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); | 8309 | bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); |
| 8310 | assert(const_val_is_int || const_val_is_float); | ||
| 8177 | 8311 | ||
| 8178 | if (other_type->id == ZigTypeIdFloat) { | 8312 | if (other_type->id == ZigTypeIdFloat) { |
| 8179 | if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { | 8313 | if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { |
| ... | @@ -8768,13 +8902,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT | ... | @@ -8768,13 +8902,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 8768 | size_t errors_count = 0; | 8902 | size_t errors_count = 0; |
| 8769 | ZigType *err_set_type = nullptr; | 8903 | ZigType *err_set_type = nullptr; |
| 8770 | if (prev_inst->value.type->id == ZigTypeIdErrorSet) { | 8904 | if (prev_inst->value.type->id == ZigTypeIdErrorSet) { |
| 8905 | if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) { | ||
| 8906 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8907 | } | ||
| 8771 | if (type_is_global_error_set(prev_inst->value.type)) { | 8908 | if (type_is_global_error_set(prev_inst->value.type)) { |
| 8772 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | 8909 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; |
| 8773 | } else { | 8910 | } else { |
| 8774 | err_set_type = prev_inst->value.type; | 8911 | err_set_type = prev_inst->value.type; |
| 8775 | if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) { | ||
| 8776 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8777 | } | ||
| 8778 | update_errors_helper(ira->codegen, &errors, &errors_count); | 8912 | update_errors_helper(ira->codegen, &errors, &errors_count); |
| 8779 | 8913 | ||
| 8780 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | 8914 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { |
| ... | @@ -8933,6 +9067,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT | ... | @@ -8933,6 +9067,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 8933 | if (prev_type->id == ZigTypeIdArray) { | 9067 | if (prev_type->id == ZigTypeIdArray) { |
| 8934 | convert_to_const_slice = true; | 9068 | convert_to_const_slice = true; |
| 8935 | } | 9069 | } |
| 9070 | if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { | ||
| 9071 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9072 | } | ||
| 8936 | if (type_is_global_error_set(cur_type)) { | 9073 | if (type_is_global_error_set(cur_type)) { |
| 8937 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | 9074 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; |
| 8938 | continue; | 9075 | continue; |
| ... | @@ -8940,9 +9077,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT | ... | @@ -8940,9 +9077,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 8940 | if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { | 9077 | if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { |
| 8941 | continue; | 9078 | continue; |
| 8942 | } | 9079 | } |
| 8943 | if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { | ||
| 8944 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8945 | } | ||
| 8946 | 9080 | ||
| 8947 | update_errors_helper(ira->codegen, &errors, &errors_count); | 9081 | update_errors_helper(ira->codegen, &errors, &errors_count); |
| 8948 | 9082 | ||
| ... | @@ -9432,14 +9566,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -9432,14 +9566,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ |
| 9432 | } | 9566 | } |
| 9433 | return true; | 9567 | return true; |
| 9434 | } | 9568 | } |
| 9569 | |||
| 9570 | static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { | ||
| 9571 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | ||
| 9572 | old_instruction->scope, old_instruction->source_node); | ||
| 9573 | IrInstruction *new_instruction = &const_instruction->base; | ||
| 9574 | new_instruction->value.type = ty; | ||
| 9575 | new_instruction->value.special = ConstValSpecialStatic; | ||
| 9576 | return new_instruction; | ||
| 9577 | } | ||
| 9578 | |||
| 9435 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, | 9579 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 9436 | ZigType *wanted_type, CastOp cast_op, bool need_alloca) | 9580 | ZigType *wanted_type, CastOp cast_op, bool need_alloca) |
| 9437 | { | 9581 | { |
| 9438 | if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && | 9582 | if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && |
| 9439 | cast_op != CastOpResizeSlice) | 9583 | cast_op != CastOpResizeSlice) |
| 9440 | { | 9584 | { |
| 9441 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 9585 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 9442 | source_instr->source_node, wanted_type); | ||
| 9443 | if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type, | 9586 | if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type, |
| 9444 | &result->value, wanted_type)) | 9587 | &result->value, wanted_type)) |
| 9445 | { | 9588 | { |
| ... | @@ -9476,9 +9619,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, | ... | @@ -9476,9 +9619,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, |
| 9476 | if (pointee == nullptr) | 9619 | if (pointee == nullptr) |
| 9477 | return ira->codegen->invalid_instruction; | 9620 | return ira->codegen->invalid_instruction; |
| 9478 | if (pointee->special != ConstValSpecialRuntime) { | 9621 | if (pointee->special != ConstValSpecialRuntime) { |
| 9479 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 9622 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 9480 | source_instr->source_node, wanted_type); | ||
| 9481 | result->value.type = wanted_type; | ||
| 9482 | result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; | 9623 | result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; |
| 9483 | result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; | 9624 | result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; |
| 9484 | result->value.data.x_ptr.data.base_array.array_val = pointee; | 9625 | result->value.data.x_ptr.data.base_array.array_val = pointee; |
| ... | @@ -9517,8 +9658,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc | ... | @@ -9517,8 +9658,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc |
| 9517 | assert(is_slice(wanted_type)); | 9658 | assert(is_slice(wanted_type)); |
| 9518 | bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; | 9659 | bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; |
| 9519 | 9660 | ||
| 9520 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 9661 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 9521 | source_instr->source_node, wanted_type); | ||
| 9522 | init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); | 9662 | init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); |
| 9523 | result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = | 9663 | result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = |
| 9524 | value->value.data.x_ptr.mut; | 9664 | value->value.data.x_ptr.mut; |
| ... | @@ -9653,15 +9793,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction) | ... | @@ -9653,15 +9793,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction) |
| 9653 | return instruction; | 9793 | return instruction; |
| 9654 | } | 9794 | } |
| 9655 | 9795 | ||
| 9656 | static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { | ||
| 9657 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | ||
| 9658 | old_instruction->scope, old_instruction->source_node); | ||
| 9659 | IrInstruction *new_instruction = &const_instruction->base; | ||
| 9660 | new_instruction->value.type = ty; | ||
| 9661 | new_instruction->value.special = ConstValSpecialStatic; | ||
| 9662 | return new_instruction; | ||
| 9663 | } | ||
| 9664 | |||
| 9665 | static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { | 9796 | static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { |
| 9666 | IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type); | 9797 | IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type); |
| 9667 | result->value.data.x_type = ty; | 9798 | result->value.data.x_type = ty; |
| ... | @@ -9719,13 +9850,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un | ... | @@ -9719,13 +9850,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un |
| 9719 | zig_unreachable(); | 9850 | zig_unreachable(); |
| 9720 | } | 9851 | } |
| 9721 | 9852 | ||
| 9722 | IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | 9853 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 9723 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, | 9854 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, |
| 9724 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, | 9855 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 9725 | IrExecutable *parent_exec) | 9856 | IrExecutable *parent_exec) |
| 9726 | { | 9857 | { |
| 9727 | if (expected_type != nullptr && type_is_invalid(expected_type)) | 9858 | if (expected_type != nullptr && type_is_invalid(expected_type)) |
| 9728 | return codegen->invalid_instruction; | 9859 | return &codegen->invalid_instruction->value; |
| 9729 | 9860 | ||
| 9730 | IrExecutable *ir_executable = allocate<IrExecutable>(1); | 9861 | IrExecutable *ir_executable = allocate<IrExecutable>(1); |
| 9731 | ir_executable->source_node = source_node; | 9862 | ir_executable->source_node = source_node; |
| ... | @@ -9738,13 +9869,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node | ... | @@ -9738,13 +9869,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 9738 | ir_gen(codegen, node, scope, ir_executable); | 9869 | ir_gen(codegen, node, scope, ir_executable); |
| 9739 | 9870 | ||
| 9740 | if (ir_executable->invalid) | 9871 | if (ir_executable->invalid) |
| 9741 | return codegen->invalid_instruction; | 9872 | return &codegen->invalid_instruction->value; |
| 9742 | 9873 | ||
| 9743 | if (codegen->verbose_ir) { | 9874 | if (codegen->verbose_ir) { |
| 9744 | fprintf(stderr, "\nSource: "); | 9875 | fprintf(stderr, "\nSource: "); |
| 9745 | ast_render(codegen, stderr, node, 4); | 9876 | ast_render(codegen, stderr, node, 4); |
| 9746 | fprintf(stderr, "\n{ // (IR)\n"); | 9877 | fprintf(stderr, "\n{ // (IR)\n"); |
| 9747 | ir_print(codegen, stderr, ir_executable, 4); | 9878 | ir_print(codegen, stderr, ir_executable, 2); |
| 9748 | fprintf(stderr, "}\n"); | 9879 | fprintf(stderr, "}\n"); |
| 9749 | } | 9880 | } |
| 9750 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); | 9881 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); |
| ... | @@ -9760,11 +9891,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node | ... | @@ -9760,11 +9891,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 9760 | analyzed_executable->begin_scope = scope; | 9891 | analyzed_executable->begin_scope = scope; |
| 9761 | ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); | 9892 | ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); |
| 9762 | if (type_is_invalid(result_type)) | 9893 | if (type_is_invalid(result_type)) |
| 9763 | return codegen->invalid_instruction; | 9894 | return &codegen->invalid_instruction->value; |
| 9764 | 9895 | ||
| 9765 | if (codegen->verbose_ir) { | 9896 | if (codegen->verbose_ir) { |
| 9766 | fprintf(stderr, "{ // (analyzed)\n"); | 9897 | fprintf(stderr, "{ // (analyzed)\n"); |
| 9767 | ir_print(codegen, stderr, analyzed_executable, 4); | 9898 | ir_print(codegen, stderr, analyzed_executable, 2); |
| 9768 | fprintf(stderr, "}\n"); | 9899 | fprintf(stderr, "}\n"); |
| 9769 | } | 9900 | } |
| 9770 | 9901 | ||
| ... | @@ -9789,6 +9920,34 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { | ... | @@ -9789,6 +9920,34 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 9789 | return const_val->data.x_type; | 9920 | return const_val->data.x_type; |
| 9790 | } | 9921 | } |
| 9791 | 9922 | ||
| 9923 | static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, IrInstruction *op_source, IrInstruction *type_value) { | ||
| 9924 | if (type_is_invalid(type_value->value.type)) | ||
| 9925 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9926 | |||
| 9927 | if (type_value->value.type->id != ZigTypeIdMetaType) { | ||
| 9928 | ErrorMsg *msg = ir_add_error(ira, type_value, | ||
| 9929 | buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value.type->name))); | ||
| 9930 | add_error_note(ira->codegen, msg, op_source->source_node, | ||
| 9931 | buf_sprintf("`||` merges error sets; `or` performs boolean OR")); | ||
| 9932 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9933 | } | ||
| 9934 | |||
| 9935 | ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); | ||
| 9936 | if (!const_val) | ||
| 9937 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9938 | |||
| 9939 | assert(const_val->data.x_type != nullptr); | ||
| 9940 | ZigType *result_type = const_val->data.x_type; | ||
| 9941 | if (result_type->id != ZigTypeIdErrorSet) { | ||
| 9942 | ErrorMsg *msg = ir_add_error(ira, type_value, | ||
| 9943 | buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name))); | ||
| 9944 | add_error_note(ira->codegen, msg, op_source->source_node, | ||
| 9945 | buf_sprintf("`||` merges error sets; `or` performs boolean OR")); | ||
| 9946 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9947 | } | ||
| 9948 | return result_type; | ||
| 9949 | } | ||
| 9950 | |||
| 9792 | static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { | 9951 | static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 9793 | if (fn_value == ira->codegen->invalid_instruction) | 9952 | if (fn_value == ira->codegen->invalid_instruction) |
| 9794 | return nullptr; | 9953 | return nullptr; |
| ... | @@ -9810,7 +9969,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { | ... | @@ -9810,7 +9969,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 9810 | return const_val->data.x_ptr.data.fn.fn_entry; | 9969 | return const_val->data.x_ptr.data.fn.fn_entry; |
| 9811 | } | 9970 | } |
| 9812 | 9971 | ||
| 9813 | static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { | 9972 | static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 9973 | ZigType *wanted_type) | ||
| 9974 | { | ||
| 9814 | assert(wanted_type->id == ZigTypeIdOptional); | 9975 | assert(wanted_type->id == ZigTypeIdOptional); |
| 9815 | 9976 | ||
| 9816 | if (instr_is_comptime(value)) { | 9977 | if (instr_is_comptime(value)) { |
| ... | @@ -9826,7 +9987,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -9826,7 +9987,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc |
| 9826 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 9987 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9827 | source_instr->scope, source_instr->source_node); | 9988 | source_instr->scope, source_instr->source_node); |
| 9828 | const_instruction->base.value.special = ConstValSpecialStatic; | 9989 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 9829 | if (get_codegen_ptr_type(wanted_type) != nullptr) { | 9990 | if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) { |
| 9830 | copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); | 9991 | copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); |
| 9831 | } else { | 9992 | } else { |
| 9832 | const_instruction->base.value.data.x_optional = val; | 9993 | const_instruction->base.value.data.x_optional = val; |
| ... | @@ -9857,11 +10018,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction | ... | @@ -9857,11 +10018,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 9857 | if (!val) | 10018 | if (!val) |
| 9858 | return ira->codegen->invalid_instruction; | 10019 | return ira->codegen->invalid_instruction; |
| 9859 | 10020 | ||
| 10021 | ConstExprValue *err_set_val = create_const_vals(1); | ||
| 10022 | err_set_val->type = wanted_type->data.error_union.err_set_type; | ||
| 10023 | err_set_val->special = ConstValSpecialStatic; | ||
| 10024 | err_set_val->data.x_err_set = nullptr; | ||
| 10025 | |||
| 9860 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 10026 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9861 | source_instr->scope, source_instr->source_node); | 10027 | source_instr->scope, source_instr->source_node); |
| 9862 | const_instruction->base.value.type = wanted_type; | 10028 | const_instruction->base.value.type = wanted_type; |
| 9863 | const_instruction->base.value.special = ConstValSpecialStatic; | 10029 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 9864 | const_instruction->base.value.data.x_err_union.err = nullptr; | 10030 | const_instruction->base.value.data.x_err_union.error_set = err_set_val; |
| 9865 | const_instruction->base.value.data.x_err_union.payload = val; | 10031 | const_instruction->base.value.data.x_err_union.payload = val; |
| 9866 | return &const_instruction->base; | 10032 | return &const_instruction->base; |
| 9867 | } | 10033 | } |
| ... | @@ -9926,11 +10092,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so | ... | @@ -9926,11 +10092,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so |
| 9926 | if (!val) | 10092 | if (!val) |
| 9927 | return ira->codegen->invalid_instruction; | 10093 | return ira->codegen->invalid_instruction; |
| 9928 | 10094 | ||
| 10095 | ConstExprValue *err_set_val = create_const_vals(1); | ||
| 10096 | err_set_val->special = ConstValSpecialStatic; | ||
| 10097 | err_set_val->type = wanted_type->data.error_union.err_set_type; | ||
| 10098 | err_set_val->data.x_err_set = val->data.x_err_set; | ||
| 10099 | |||
| 9929 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 10100 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9930 | source_instr->scope, source_instr->source_node); | 10101 | source_instr->scope, source_instr->source_node); |
| 9931 | const_instruction->base.value.type = wanted_type; | 10102 | const_instruction->base.value.type = wanted_type; |
| 9932 | const_instruction->base.value.special = ConstValSpecialStatic; | 10103 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 9933 | const_instruction->base.value.data.x_err_union.err = val->data.x_err_set; | 10104 | const_instruction->base.value.data.x_err_union.error_set = err_set_val; |
| 9934 | const_instruction->base.value.data.x_err_union.payload = nullptr; | 10105 | const_instruction->base.value.data.x_err_union.payload = nullptr; |
| 9935 | return &const_instruction->base; | 10106 | return &const_instruction->base; |
| 9936 | } | 10107 | } |
| ... | @@ -9952,8 +10123,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so | ... | @@ -9952,8 +10123,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so |
| 9952 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node); | 10123 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node); |
| 9953 | const_instruction->base.value.special = ConstValSpecialStatic; | 10124 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 9954 | if (get_codegen_ptr_type(wanted_type) != nullptr) { | 10125 | if (get_codegen_ptr_type(wanted_type) != nullptr) { |
| 9955 | const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; | 10126 | const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull; |
| 9956 | const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; | 10127 | } else if (is_opt_err_set(wanted_type)) { |
| 10128 | const_instruction->base.value.data.x_err_set = nullptr; | ||
| 9957 | } else { | 10129 | } else { |
| 9958 | const_instruction->base.value.data.x_optional = nullptr; | 10130 | const_instruction->base.value.data.x_optional = nullptr; |
| 9959 | } | 10131 | } |
| ... | @@ -9986,7 +10158,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi | ... | @@ -9986,7 +10158,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 9986 | source_instruction->source_node, value, is_const, is_volatile); | 10158 | source_instruction->source_node, value, is_const, is_volatile); |
| 9987 | new_instruction->value.type = ptr_type; | 10159 | new_instruction->value.type = ptr_type; |
| 9988 | new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; | 10160 | new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; |
| 9989 | if (type_has_bits(ptr_type)) { | 10161 | if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { |
| 9990 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); | 10162 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 9991 | assert(fn_entry); | 10163 | assert(fn_entry); |
| 9992 | fn_entry->alloca_list.append(new_instruction); | 10164 | fn_entry->alloca_list.append(new_instruction); |
| ... | @@ -10012,20 +10184,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s | ... | @@ -10012,20 +10184,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s |
| 10012 | ZigType *array_type = array->value.type; | 10184 | ZigType *array_type = array->value.type; |
| 10013 | assert(array_type->id == ZigTypeIdArray); | 10185 | assert(array_type->id == ZigTypeIdArray); |
| 10014 | 10186 | ||
| 10015 | if (instr_is_comptime(array)) { | 10187 | if (instr_is_comptime(array) || array_type->data.array.len == 0) { |
| 10016 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10188 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10017 | source_instr->source_node, wanted_type); | ||
| 10018 | init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true); | 10189 | init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true); |
| 10019 | result->value.type = wanted_type; | 10190 | result->value.type = wanted_type; |
| 10020 | return result; | 10191 | return result; |
| 10021 | } | 10192 | } |
| 10022 | 10193 | ||
| 10023 | IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope, | 10194 | IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); |
| 10024 | source_instr->source_node, ira->codegen->builtin_types.entry_usize); | ||
| 10025 | init_const_usize(ira->codegen, &start->value, 0); | 10195 | init_const_usize(ira->codegen, &start->value, 0); |
| 10026 | 10196 | ||
| 10027 | IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope, | 10197 | IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); |
| 10028 | source_instr->source_node, ira->codegen->builtin_types.entry_usize); | ||
| 10029 | init_const_usize(ira->codegen, &end->value, array_type->data.array.len); | 10198 | init_const_usize(ira->codegen, &end->value, array_type->data.array.len); |
| 10030 | 10199 | ||
| 10031 | if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); | 10200 | if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); |
| ... | @@ -10064,8 +10233,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour | ... | @@ -10064,8 +10233,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour |
| 10064 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | 10233 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 10065 | if (!val) | 10234 | if (!val) |
| 10066 | return ira->codegen->invalid_instruction; | 10235 | return ira->codegen->invalid_instruction; |
| 10067 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10236 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10068 | source_instr->source_node, wanted_type); | ||
| 10069 | init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); | 10237 | init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); |
| 10070 | return result; | 10238 | return result; |
| 10071 | } | 10239 | } |
| ... | @@ -10075,8 +10243,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour | ... | @@ -10075,8 +10243,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour |
| 10075 | actual_type->data.enumeration.src_field_count == 1) | 10243 | actual_type->data.enumeration.src_field_count == 1) |
| 10076 | { | 10244 | { |
| 10077 | assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); | 10245 | assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); |
| 10078 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10246 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10079 | source_instr->source_node, wanted_type); | ||
| 10080 | init_const_bigint(&result->value, wanted_type, | 10247 | init_const_bigint(&result->value, wanted_type, |
| 10081 | &actual_type->data.enumeration.fields[0].value); | 10248 | &actual_type->data.enumeration.fields[0].value); |
| 10082 | return result; | 10249 | return result; |
| ... | @@ -10099,8 +10266,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou | ... | @@ -10099,8 +10266,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou |
| 10099 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | 10266 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 10100 | if (!val) | 10267 | if (!val) |
| 10101 | return ira->codegen->invalid_instruction; | 10268 | return ira->codegen->invalid_instruction; |
| 10102 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10269 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10103 | source_instr->source_node, wanted_type); | ||
| 10104 | result->value.special = ConstValSpecialStatic; | 10270 | result->value.special = ConstValSpecialStatic; |
| 10105 | result->value.type = wanted_type; | 10271 | result->value.type = wanted_type; |
| 10106 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag); | 10272 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag); |
| ... | @@ -10111,8 +10277,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou | ... | @@ -10111,8 +10277,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou |
| 10111 | if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && | 10277 | if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && |
| 10112 | wanted_type->data.enumeration.src_field_count == 1) | 10278 | wanted_type->data.enumeration.src_field_count == 1) |
| 10113 | { | 10279 | { |
| 10114 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10280 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10115 | source_instr->source_node, wanted_type); | ||
| 10116 | result->value.special = ConstValSpecialStatic; | 10281 | result->value.special = ConstValSpecialStatic; |
| 10117 | result->value.type = wanted_type; | 10282 | result->value.type = wanted_type; |
| 10118 | TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field; | 10283 | TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field; |
| ... | @@ -10129,8 +10294,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou | ... | @@ -10129,8 +10294,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou |
| 10129 | static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, | 10294 | static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, |
| 10130 | IrInstruction *target, ZigType *wanted_type) | 10295 | IrInstruction *target, ZigType *wanted_type) |
| 10131 | { | 10296 | { |
| 10132 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10297 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10133 | source_instr->source_node, wanted_type); | ||
| 10134 | init_const_undefined(ira->codegen, &result->value); | 10298 | init_const_undefined(ira->codegen, &result->value); |
| 10135 | return result; | 10299 | return result; |
| 10136 | } | 10300 | } |
| ... | @@ -10162,8 +10326,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so | ... | @@ -10162,8 +10326,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 10162 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); | 10326 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); |
| 10163 | return ira->codegen->invalid_instruction; | 10327 | return ira->codegen->invalid_instruction; |
| 10164 | } | 10328 | } |
| 10165 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10329 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10166 | source_instr->source_node, wanted_type); | ||
| 10167 | result->value.special = ConstValSpecialStatic; | 10330 | result->value.special = ConstValSpecialStatic; |
| 10168 | result->value.type = wanted_type; | 10331 | result->value.type = wanted_type; |
| 10169 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); | 10332 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); |
| ... | @@ -10218,8 +10381,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction | ... | @@ -10218,8 +10381,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction |
| 10218 | return ira->codegen->invalid_instruction; | 10381 | return ira->codegen->invalid_instruction; |
| 10219 | } | 10382 | } |
| 10220 | } | 10383 | } |
| 10221 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10384 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10222 | source_instr->source_node, wanted_type); | ||
| 10223 | result->value.type = wanted_type; | 10385 | result->value.type = wanted_type; |
| 10224 | if (wanted_type->id == ZigTypeIdInt) { | 10386 | if (wanted_type->id == ZigTypeIdInt) { |
| 10225 | bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); | 10387 | bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); |
| ... | @@ -10273,8 +10435,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour | ... | @@ -10273,8 +10435,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 10273 | return ira->codegen->invalid_instruction; | 10435 | return ira->codegen->invalid_instruction; |
| 10274 | } | 10436 | } |
| 10275 | 10437 | ||
| 10276 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10438 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10277 | source_instr->source_node, wanted_type); | ||
| 10278 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); | 10439 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); |
| 10279 | return result; | 10440 | return result; |
| 10280 | } | 10441 | } |
| ... | @@ -10292,8 +10453,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction | ... | @@ -10292,8 +10453,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction |
| 10292 | if (!val) | 10453 | if (!val) |
| 10293 | return ira->codegen->invalid_instruction; | 10454 | return ira->codegen->invalid_instruction; |
| 10294 | 10455 | ||
| 10295 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10456 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10296 | source_instr->source_node, wanted_type); | ||
| 10297 | if (wanted_type->id == ZigTypeIdComptimeFloat) { | 10457 | if (wanted_type->id == ZigTypeIdComptimeFloat) { |
| 10298 | float_init_float(&result->value, val); | 10458 | float_init_float(&result->value, val); |
| 10299 | } else if (wanted_type->id == ZigTypeIdComptimeInt) { | 10459 | } else if (wanted_type->id == ZigTypeIdComptimeInt) { |
| ... | @@ -10316,8 +10476,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -10316,8 +10476,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 10316 | if (!val) | 10476 | if (!val) |
| 10317 | return ira->codegen->invalid_instruction; | 10477 | return ira->codegen->invalid_instruction; |
| 10318 | 10478 | ||
| 10319 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10479 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10320 | source_instr->source_node, wanted_type); | ||
| 10321 | 10480 | ||
| 10322 | if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) { | 10481 | if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) { |
| 10323 | return ira->codegen->invalid_instruction; | 10482 | return ira->codegen->invalid_instruction; |
| ... | @@ -10381,12 +10540,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -10381,12 +10540,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 10381 | if (!val) | 10540 | if (!val) |
| 10382 | return ira->codegen->invalid_instruction; | 10541 | return ira->codegen->invalid_instruction; |
| 10383 | 10542 | ||
| 10384 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10543 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10385 | source_instr->source_node, wanted_type); | ||
| 10386 | 10544 | ||
| 10387 | ErrorTableEntry *err; | 10545 | ErrorTableEntry *err; |
| 10388 | if (err_type->id == ZigTypeIdErrorUnion) { | 10546 | if (err_type->id == ZigTypeIdErrorUnion) { |
| 10389 | err = val->data.x_err_union.err; | 10547 | err = val->data.x_err_union.error_set->data.x_err_set; |
| 10390 | } else if (err_type->id == ZigTypeIdErrorSet) { | 10548 | } else if (err_type->id == ZigTypeIdErrorSet) { |
| 10391 | err = val->data.x_err_set; | 10549 | err = val->data.x_err_set; |
| 10392 | } else { | 10550 | } else { |
| ... | @@ -10421,15 +10579,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -10421,15 +10579,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 10421 | return ira->codegen->invalid_instruction; | 10579 | return ira->codegen->invalid_instruction; |
| 10422 | } | 10580 | } |
| 10423 | if (err_set_type->data.error_set.err_count == 0) { | 10581 | if (err_set_type->data.error_set.err_count == 0) { |
| 10424 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10582 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10425 | source_instr->source_node, wanted_type); | ||
| 10426 | result->value.type = wanted_type; | ||
| 10427 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | 10583 | bigint_init_unsigned(&result->value.data.x_bigint, 0); |
| 10428 | return result; | 10584 | return result; |
| 10429 | } else if (err_set_type->data.error_set.err_count == 1) { | 10585 | } else if (err_set_type->data.error_set.err_count == 1) { |
| 10430 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 10586 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 10431 | source_instr->source_node, wanted_type); | ||
| 10432 | result->value.type = wanted_type; | ||
| 10433 | ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; | 10587 | ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; |
| 10434 | bigint_init_unsigned(&result->value.data.x_bigint, err->value); | 10588 | bigint_init_unsigned(&result->value.data.x_bigint, err->value); |
| 10435 | return result; | 10589 | return result; |
| ... | @@ -10476,8 +10630,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou | ... | @@ -10476,8 +10630,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou |
| 10476 | array_val->type = array_type; | 10630 | array_val->type = array_type; |
| 10477 | array_val->data.x_array.special = ConstArraySpecialNone; | 10631 | array_val->data.x_array.special = ConstArraySpecialNone; |
| 10478 | array_val->data.x_array.data.s_none.elements = pointee; | 10632 | array_val->data.x_array.data.s_none.elements = pointee; |
| 10479 | array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar; | 10633 | array_val->parent.id = ConstParentIdScalar; |
| 10480 | array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee; | 10634 | array_val->parent.data.p_scalar.scalar_val = pointee; |
| 10481 | 10635 | ||
| 10482 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 10636 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 10483 | source_instr->scope, source_instr->source_node); | 10637 | source_instr->scope, source_instr->source_node); |
| ... | @@ -10598,6 +10752,32 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa | ... | @@ -10598,6 +10752,32 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa |
| 10598 | } | 10752 | } |
| 10599 | } | 10753 | } |
| 10600 | 10754 | ||
| 10755 | static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 10756 | IrInstruction *array, ZigType *vector_type) | ||
| 10757 | { | ||
| 10758 | if (instr_is_comptime(array)) { | ||
| 10759 | // arrays and vectors have the same ConstExprValue representation | ||
| 10760 | IrInstruction *result = ir_const(ira, source_instr, vector_type); | ||
| 10761 | copy_const_val(&result->value, &array->value, false); | ||
| 10762 | result->value.type = vector_type; | ||
| 10763 | return result; | ||
| 10764 | } | ||
| 10765 | return ir_build_array_to_vector(ira, source_instr, array, vector_type); | ||
| 10766 | } | ||
| 10767 | |||
| 10768 | static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 10769 | IrInstruction *vector, ZigType *array_type) | ||
| 10770 | { | ||
| 10771 | if (instr_is_comptime(vector)) { | ||
| 10772 | // arrays and vectors have the same ConstExprValue representation | ||
| 10773 | IrInstruction *result = ir_const(ira, source_instr, array_type); | ||
| 10774 | copy_const_val(&result->value, &vector->value, false); | ||
| 10775 | result->value.type = array_type; | ||
| 10776 | return result; | ||
| 10777 | } | ||
| 10778 | return ir_build_vector_to_array(ira, source_instr, vector, array_type); | ||
| 10779 | } | ||
| 10780 | |||
| 10601 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, | 10781 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 10602 | ZigType *wanted_type, IrInstruction *value) | 10782 | ZigType *wanted_type, IrInstruction *value) |
| 10603 | { | 10783 | { |
| ... | @@ -10625,12 +10805,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10625,12 +10805,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10625 | if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, | 10805 | if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, |
| 10626 | false).id == ConstCastResultIdOk) | 10806 | false).id == ConstCastResultIdOk) |
| 10627 | { | 10807 | { |
| 10628 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | 10808 | return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); |
| 10629 | } else if (actual_type->id == ZigTypeIdComptimeInt || | 10809 | } else if (actual_type->id == ZigTypeIdComptimeInt || |
| 10630 | actual_type->id == ZigTypeIdComptimeFloat) | 10810 | actual_type->id == ZigTypeIdComptimeFloat) |
| 10631 | { | 10811 | { |
| 10632 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { | 10812 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { |
| 10633 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | 10813 | return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); |
| 10634 | } else { | 10814 | } else { |
| 10635 | return ira->codegen->invalid_instruction; | 10815 | return ira->codegen->invalid_instruction; |
| 10636 | } | 10816 | } |
| ... | @@ -10654,7 +10834,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10654,7 +10834,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10654 | wanted_child_type); | 10834 | wanted_child_type); |
| 10655 | if (type_is_invalid(cast1->value.type)) | 10835 | if (type_is_invalid(cast1->value.type)) |
| 10656 | return ira->codegen->invalid_instruction; | 10836 | return ira->codegen->invalid_instruction; |
| 10657 | return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); | 10837 | return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type); |
| 10658 | } | 10838 | } |
| 10659 | } | 10839 | } |
| 10660 | } | 10840 | } |
| ... | @@ -10707,6 +10887,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10707,6 +10887,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10707 | (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || | 10887 | (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || |
| 10708 | wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) | 10888 | wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) |
| 10709 | { | 10889 | { |
| 10890 | if (value->value.special == ConstValSpecialUndef) { | ||
| 10891 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | ||
| 10892 | result->value.special = ConstValSpecialUndef; | ||
| 10893 | return result; | ||
| 10894 | } | ||
| 10710 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { | 10895 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { |
| 10711 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { | 10896 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { |
| 10712 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | 10897 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| ... | @@ -10760,6 +10945,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10760,6 +10945,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10760 | 10945 | ||
| 10761 | 10946 | ||
| 10762 | // cast from [N]T to []const T | 10947 | // cast from [N]T to []const T |
| 10948 | // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this | ||
| 10763 | if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { | 10949 | if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { |
| 10764 | ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; | 10950 | ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; |
| 10765 | assert(ptr_type->id == ZigTypeIdPointer); | 10951 | assert(ptr_type->id == ZigTypeIdPointer); |
| ... | @@ -10772,6 +10958,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10772,6 +10958,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10772 | } | 10958 | } |
| 10773 | 10959 | ||
| 10774 | // cast from [N]T to ?[]const T | 10960 | // cast from [N]T to ?[]const T |
| 10961 | // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this | ||
| 10775 | if (wanted_type->id == ZigTypeIdOptional && | 10962 | if (wanted_type->id == ZigTypeIdOptional && |
| 10776 | is_slice(wanted_type->data.maybe.child_type) && | 10963 | is_slice(wanted_type->data.maybe.child_type) && |
| 10777 | actual_type->id == ZigTypeIdArray) | 10964 | actual_type->id == ZigTypeIdArray) |
| ... | @@ -10866,7 +11053,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10866,7 +11053,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10866 | } | 11053 | } |
| 10867 | } | 11054 | } |
| 10868 | 11055 | ||
| 10869 | // cast from error set to error union type | 11056 | // cast from E to E!T |
| 10870 | if (wanted_type->id == ZigTypeIdErrorUnion && | 11057 | if (wanted_type->id == ZigTypeIdErrorUnion && |
| 10871 | actual_type->id == ZigTypeIdErrorSet) | 11058 | actual_type->id == ZigTypeIdErrorSet) |
| 10872 | { | 11059 | { |
| ... | @@ -10979,6 +11166,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10979,6 +11166,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10979 | } | 11166 | } |
| 10980 | } | 11167 | } |
| 10981 | 11168 | ||
| 11169 | // cast from @Vector(N, T) to [N]T | ||
| 11170 | if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector && | ||
| 11171 | wanted_type->data.array.len == actual_type->data.vector.len && | ||
| 11172 | types_match_const_cast_only(ira, wanted_type->data.array.child_type, | ||
| 11173 | actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) | ||
| 11174 | { | ||
| 11175 | return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type); | ||
| 11176 | } | ||
| 11177 | |||
| 11178 | // cast from [N]T to @Vector(N, T) | ||
| 11179 | if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector && | ||
| 11180 | actual_type->data.array.len == wanted_type->data.vector.len && | ||
| 11181 | types_match_const_cast_only(ira, actual_type->data.array.child_type, | ||
| 11182 | wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) | ||
| 11183 | { | ||
| 11184 | return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); | ||
| 11185 | } | ||
| 10982 | 11186 | ||
| 10983 | // cast from undefined to anything | 11187 | // cast from undefined to anything |
| 10984 | if (actual_type->id == ZigTypeIdUndefined) { | 11188 | if (actual_type->id == ZigTypeIdUndefined) { |
| ... | @@ -11018,8 +11222,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc | ... | @@ -11018,8 +11222,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 11018 | ZigType *child_type = type_entry->data.pointer.child_type; | 11222 | ZigType *child_type = type_entry->data.pointer.child_type; |
| 11019 | // dereferencing a *u0 is comptime known to be 0 | 11223 | // dereferencing a *u0 is comptime known to be 0 |
| 11020 | if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) { | 11224 | if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) { |
| 11021 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, | 11225 | IrInstruction *result = ir_const(ira, source_instruction, child_type); |
| 11022 | source_instruction->source_node, child_type); | ||
| 11023 | init_const_unsigned_negative(&result->value, child_type, 0, false); | 11226 | init_const_unsigned_negative(&result->value, child_type, 0, false); |
| 11024 | return result; | 11227 | return result; |
| 11025 | } | 11228 | } |
| ... | @@ -11033,8 +11236,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc | ... | @@ -11033,8 +11236,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 11033 | { | 11236 | { |
| 11034 | ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); | 11237 | ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); |
| 11035 | if (pointee->special != ConstValSpecialRuntime) { | 11238 | if (pointee->special != ConstValSpecialRuntime) { |
| 11036 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, | 11239 | IrInstruction *result = ir_const(ira, source_instruction, child_type); |
| 11037 | source_instruction->source_node, child_type); | ||
| 11038 | 11240 | ||
| 11039 | if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, | 11241 | if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, |
| 11040 | &ptr->value))) | 11242 | &ptr->value))) |
| ... | @@ -11046,7 +11248,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc | ... | @@ -11046,7 +11248,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 11046 | } | 11248 | } |
| 11047 | } | 11249 | } |
| 11048 | } | 11250 | } |
| 11049 | // TODO if the instruction is a const ref instruction we can skip it | 11251 | // if the instruction is a const ref instruction we can skip it |
| 11252 | if (ptr->id == IrInstructionIdRef) { | ||
| 11253 | IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr); | ||
| 11254 | return ref_inst->value; | ||
| 11255 | } | ||
| 11050 | IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, | 11256 | IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, |
| 11051 | source_instruction->source_node, ptr); | 11257 | source_instruction->source_node, ptr); |
| 11052 | load_ptr_instruction->value.type = child_type; | 11258 | load_ptr_instruction->value.type = child_type; |
| ... | @@ -11293,8 +11499,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio | ... | @@ -11293,8 +11499,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio |
| 11293 | 11499 | ||
| 11294 | static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) { | 11500 | static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) { |
| 11295 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); | 11501 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); |
| 11296 | // TODO determine if we need to use copy_const_val here | 11502 | copy_const_val(&result->value, &instruction->base.value, true); |
| 11297 | result->value = instruction->base.value; | ||
| 11298 | return result; | 11503 | return result; |
| 11299 | } | 11504 | } |
| 11300 | 11505 | ||
| ... | @@ -11369,6 +11574,8 @@ static bool optional_value_is_null(ConstExprValue *val) { | ... | @@ -11369,6 +11574,8 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 11369 | if (get_codegen_ptr_type(val->type) != nullptr) { | 11574 | if (get_codegen_ptr_type(val->type) != nullptr) { |
| 11370 | return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && | 11575 | return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && |
| 11371 | val->data.x_ptr.data.hard_coded_addr.addr == 0; | 11576 | val->data.x_ptr.data.hard_coded_addr.addr == 0; |
| 11577 | } else if (is_opt_err_set(val->type)) { | ||
| 11578 | return val->data.x_err_set == nullptr; | ||
| 11372 | } else { | 11579 | } else { |
| 11373 | return val->data.x_optional == nullptr; | 11580 | return val->data.x_optional == nullptr; |
| 11374 | } | 11581 | } |
| ... | @@ -11523,6 +11730,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -11523,6 +11730,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11523 | case ZigTypeIdComptimeInt: | 11730 | case ZigTypeIdComptimeInt: |
| 11524 | case ZigTypeIdInt: | 11731 | case ZigTypeIdInt: |
| 11525 | case ZigTypeIdFloat: | 11732 | case ZigTypeIdFloat: |
| 11733 | case ZigTypeIdVector: | ||
| 11526 | operator_allowed = true; | 11734 | operator_allowed = true; |
| 11527 | break; | 11735 | break; |
| 11528 | 11736 | ||
| ... | @@ -11568,19 +11776,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -11568,19 +11776,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11568 | if (casted_op2 == ira->codegen->invalid_instruction) | 11776 | if (casted_op2 == ira->codegen->invalid_instruction) |
| 11569 | return ira->codegen->invalid_instruction; | 11777 | return ira->codegen->invalid_instruction; |
| 11570 | 11778 | ||
| 11571 | bool requires_comptime; | 11779 | bool one_possible_value; |
| 11572 | switch (type_requires_comptime(ira->codegen, resolved_type)) { | 11780 | switch (type_has_one_possible_value(ira->codegen, resolved_type)) { |
| 11573 | case ReqCompTimeYes: | 11781 | case OnePossibleValueInvalid: |
| 11574 | requires_comptime = true; | 11782 | return ira->codegen->invalid_instruction; |
| 11783 | case OnePossibleValueYes: | ||
| 11784 | one_possible_value = true; | ||
| 11575 | break; | 11785 | break; |
| 11576 | case ReqCompTimeNo: | 11786 | case OnePossibleValueNo: |
| 11577 | requires_comptime = false; | 11787 | one_possible_value = false; |
| 11578 | break; | 11788 | break; |
| 11579 | case ReqCompTimeInvalid: | ||
| 11580 | return ira->codegen->invalid_instruction; | ||
| 11581 | } | 11789 | } |
| 11582 | 11790 | ||
| 11583 | bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type); | ||
| 11584 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { | 11791 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { |
| 11585 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); | 11792 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); |
| 11586 | if (op1_val == nullptr) | 11793 | if (op1_val == nullptr) |
| ... | @@ -11654,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -11654,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11654 | return result; | 11861 | return result; |
| 11655 | } | 11862 | } |
| 11656 | 11863 | ||
| 11657 | static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | 11864 | static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry, |
| 11658 | IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) | 11865 | ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) |
| 11659 | { | 11866 | { |
| 11660 | bool is_int; | 11867 | bool is_int; |
| 11661 | bool is_float; | 11868 | bool is_float; |
| ... | @@ -11677,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | ... | @@ -11677,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11677 | if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || | 11884 | if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || |
| 11678 | op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) | 11885 | op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) |
| 11679 | { | 11886 | { |
| 11680 | return ErrorDivByZero; | 11887 | return ir_add_error(ira, source_instr, buf_sprintf("division by zero")); |
| 11681 | } | 11888 | } |
| 11682 | if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { | 11889 | if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { |
| 11683 | return ErrorNegativeDenominator; | 11890 | return ir_add_error(ira, source_instr, buf_sprintf("negative denominator")); |
| 11684 | } | 11891 | } |
| 11685 | 11892 | ||
| 11686 | switch (op_id) { | 11893 | switch (op_id) { |
| ... | @@ -11726,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | ... | @@ -11726,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11726 | BigInt orig_bigint; | 11933 | BigInt orig_bigint; |
| 11727 | bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); | 11934 | bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); |
| 11728 | if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { | 11935 | if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { |
| 11729 | return ErrorShiftedOutOneBits; | 11936 | return ir_add_error(ira, source_instr, buf_sprintf("exact shift shifted out 1 bits")); |
| 11730 | } | 11937 | } |
| 11731 | break; | 11938 | break; |
| 11732 | } | 11939 | } |
| ... | @@ -11794,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | ... | @@ -11794,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11794 | BigInt remainder; | 12001 | BigInt remainder; |
| 11795 | bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | 12002 | bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 11796 | if (bigint_cmp_zero(&remainder) != CmpEQ) { | 12003 | if (bigint_cmp_zero(&remainder) != CmpEQ) { |
| 11797 | return ErrorExactDivRemainder; | 12004 | return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); |
| 11798 | } | 12005 | } |
| 11799 | } else { | 12006 | } else { |
| 11800 | float_div_trunc(out_val, op1_val, op2_val); | 12007 | float_div_trunc(out_val, op1_val, op2_val); |
| 11801 | ConstExprValue remainder; | 12008 | ConstExprValue remainder; |
| 11802 | float_rem(&remainder, op1_val, op2_val); | 12009 | float_rem(&remainder, op1_val, op2_val); |
| 11803 | if (float_cmp_zero(&remainder) != CmpEQ) { | 12010 | if (float_cmp_zero(&remainder) != CmpEQ) { |
| 11804 | return ErrorExactDivRemainder; | 12011 | return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); |
| 11805 | } | 12012 | } |
| 11806 | } | 12013 | } |
| 11807 | break; | 12014 | break; |
| ... | @@ -11825,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | ... | @@ -11825,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11825 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, | 12032 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, |
| 11826 | type_entry->data.integral.is_signed)) | 12033 | type_entry->data.integral.is_signed)) |
| 11827 | { | 12034 | { |
| 11828 | return ErrorOverflow; | 12035 | return ir_add_error(ira, source_instr, buf_sprintf("operation caused overflow")); |
| 11829 | } | 12036 | } |
| 11830 | } | 12037 | } |
| 11831 | 12038 | ||
| 11832 | out_val->type = type_entry; | 12039 | out_val->type = type_entry; |
| 11833 | out_val->special = ConstValSpecialStatic; | 12040 | out_val->special = ConstValSpecialStatic; |
| 11834 | return 0; | 12041 | return nullptr; |
| 12042 | } | ||
| 12043 | |||
| 12044 | // This works on operands that have already been checked to be comptime known. | ||
| 12045 | static IrInstruction *ir_analyze_math_op(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 12046 | ZigType *type_entry, ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val) | ||
| 12047 | { | ||
| 12048 | IrInstruction *result_instruction = ir_const(ira, source_instr, type_entry); | ||
| 12049 | ConstExprValue *out_val = &result_instruction->value; | ||
| 12050 | if (type_entry->id == ZigTypeIdVector) { | ||
| 12051 | expand_undef_array(ira->codegen, op1_val); | ||
| 12052 | expand_undef_array(ira->codegen, op2_val); | ||
| 12053 | out_val->special = ConstValSpecialUndef; | ||
| 12054 | expand_undef_array(ira->codegen, out_val); | ||
| 12055 | size_t len = type_entry->data.vector.len; | ||
| 12056 | ZigType *scalar_type = type_entry->data.vector.elem_type; | ||
| 12057 | for (size_t i = 0; i < len; i += 1) { | ||
| 12058 | ConstExprValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i]; | ||
| 12059 | ConstExprValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; | ||
| 12060 | ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; | ||
| 12061 | assert(scalar_op1_val->type == scalar_type); | ||
| 12062 | assert(scalar_op2_val->type == scalar_type); | ||
| 12063 | assert(scalar_out_val->type == scalar_type); | ||
| 12064 | ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type, | ||
| 12065 | scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); | ||
| 12066 | if (msg != nullptr) { | ||
| 12067 | add_error_note(ira->codegen, msg, source_instr->source_node, | ||
| 12068 | buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); | ||
| 12069 | return ira->codegen->invalid_instruction; | ||
| 12070 | } | ||
| 12071 | } | ||
| 12072 | out_val->type = type_entry; | ||
| 12073 | out_val->special = ConstValSpecialStatic; | ||
| 12074 | } else { | ||
| 12075 | if (ir_eval_math_op_scalar(ira, source_instr, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) { | ||
| 12076 | return ira->codegen->invalid_instruction; | ||
| 12077 | } | ||
| 12078 | } | ||
| 12079 | return ir_implicit_cast(ira, result_instruction, type_entry); | ||
| 11835 | } | 12080 | } |
| 11836 | 12081 | ||
| 11837 | static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 12082 | static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| ... | @@ -11903,24 +12148,7 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b | ... | @@ -11903,24 +12148,7 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b |
| 11903 | if (op2_val == nullptr) | 12148 | if (op2_val == nullptr) |
| 11904 | return ira->codegen->invalid_instruction; | 12149 | return ira->codegen->invalid_instruction; |
| 11905 | 12150 | ||
| 11906 | IrInstruction *result_instruction = ir_const(ira, &bin_op_instruction->base, op1->value.type); | 12151 | return ir_analyze_math_op(ira, &bin_op_instruction->base, op1->value.type, op1_val, op_id, op2_val); |
| 11907 | |||
| 11908 | int err; | ||
| 11909 | if ((err = ir_eval_math_op(op1->value.type, op1_val, op_id, op2_val, &result_instruction->value))) { | ||
| 11910 | if (err == ErrorOverflow) { | ||
| 11911 | ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow")); | ||
| 11912 | return ira->codegen->invalid_instruction; | ||
| 11913 | } else if (err == ErrorShiftedOutOneBits) { | ||
| 11914 | ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits")); | ||
| 11915 | return ira->codegen->invalid_instruction; | ||
| 11916 | } else { | ||
| 11917 | zig_unreachable(); | ||
| 11918 | } | ||
| 11919 | return ira->codegen->invalid_instruction; | ||
| 11920 | } | ||
| 11921 | |||
| 11922 | ir_num_lit_fits_in_other_type(ira, result_instruction, op1->value.type, false); | ||
| 11923 | return result_instruction; | ||
| 11924 | } else if (op1->value.type->id == ZigTypeIdComptimeInt) { | 12152 | } else if (op1->value.type->id == ZigTypeIdComptimeInt) { |
| 11925 | ir_add_error(ira, &bin_op_instruction->base, | 12153 | ir_add_error(ira, &bin_op_instruction->base, |
| 11926 | buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); | 12154 | buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); |
| ... | @@ -11939,32 +12167,74 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b | ... | @@ -11939,32 +12167,74 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b |
| 11939 | return result; | 12167 | return result; |
| 11940 | } | 12168 | } |
| 11941 | 12169 | ||
| 11942 | static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { | 12170 | static bool ok_float_op(IrBinOp op) { |
| 11943 | IrInstruction *op1 = instruction->op1->child; | 12171 | switch (op) { |
| 11944 | if (type_is_invalid(op1->value.type)) | 12172 | case IrBinOpInvalid: |
| 11945 | return ira->codegen->invalid_instruction; | 12173 | zig_unreachable(); |
| 11946 | 12174 | case IrBinOpAdd: | |
| 11947 | IrInstruction *op2 = instruction->op2->child; | 12175 | case IrBinOpSub: |
| 11948 | if (type_is_invalid(op2->value.type)) | 12176 | case IrBinOpMult: |
| 11949 | return ira->codegen->invalid_instruction; | 12177 | case IrBinOpDivUnspecified: |
| 11950 | 12178 | case IrBinOpDivTrunc: | |
| 11951 | IrBinOp op_id = instruction->op_id; | 12179 | case IrBinOpDivFloor: |
| 11952 | 12180 | case IrBinOpDivExact: | |
| 11953 | // look for pointer math | 12181 | case IrBinOpRemRem: |
| 11954 | if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && | 12182 | case IrBinOpRemMod: |
| 11955 | (op_id == IrBinOpAdd || op_id == IrBinOpSub)) | 12183 | return true; |
| 11956 | { | ||
| 11957 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); | ||
| 11958 | if (casted_op2 == ira->codegen->invalid_instruction) | ||
| 11959 | return ira->codegen->invalid_instruction; | ||
| 11960 | |||
| 11961 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, | ||
| 11962 | instruction->base.source_node, op_id, op1, casted_op2, true); | ||
| 11963 | result->value.type = op1->value.type; | ||
| 11964 | return result; | ||
| 11965 | } | ||
| 11966 | 12184 | ||
| 11967 | IrInstruction *instructions[] = {op1, op2}; | 12185 | case IrBinOpBoolOr: |
| 12186 | case IrBinOpBoolAnd: | ||
| 12187 | case IrBinOpCmpEq: | ||
| 12188 | case IrBinOpCmpNotEq: | ||
| 12189 | case IrBinOpCmpLessThan: | ||
| 12190 | case IrBinOpCmpGreaterThan: | ||
| 12191 | case IrBinOpCmpLessOrEq: | ||
| 12192 | case IrBinOpCmpGreaterOrEq: | ||
| 12193 | case IrBinOpBinOr: | ||
| 12194 | case IrBinOpBinXor: | ||
| 12195 | case IrBinOpBinAnd: | ||
| 12196 | case IrBinOpBitShiftLeftLossy: | ||
| 12197 | case IrBinOpBitShiftLeftExact: | ||
| 12198 | case IrBinOpBitShiftRightLossy: | ||
| 12199 | case IrBinOpBitShiftRightExact: | ||
| 12200 | case IrBinOpAddWrap: | ||
| 12201 | case IrBinOpSubWrap: | ||
| 12202 | case IrBinOpMultWrap: | ||
| 12203 | case IrBinOpRemUnspecified: | ||
| 12204 | case IrBinOpArrayCat: | ||
| 12205 | case IrBinOpArrayMult: | ||
| 12206 | case IrBinOpMergeErrorSets: | ||
| 12207 | return false; | ||
| 12208 | } | ||
| 12209 | zig_unreachable(); | ||
| 12210 | } | ||
| 12211 | |||
| 12212 | static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { | ||
| 12213 | IrInstruction *op1 = instruction->op1->child; | ||
| 12214 | if (type_is_invalid(op1->value.type)) | ||
| 12215 | return ira->codegen->invalid_instruction; | ||
| 12216 | |||
| 12217 | IrInstruction *op2 = instruction->op2->child; | ||
| 12218 | if (type_is_invalid(op2->value.type)) | ||
| 12219 | return ira->codegen->invalid_instruction; | ||
| 12220 | |||
| 12221 | IrBinOp op_id = instruction->op_id; | ||
| 12222 | |||
| 12223 | // look for pointer math | ||
| 12224 | if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && | ||
| 12225 | (op_id == IrBinOpAdd || op_id == IrBinOpSub)) | ||
| 12226 | { | ||
| 12227 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); | ||
| 12228 | if (casted_op2 == ira->codegen->invalid_instruction) | ||
| 12229 | return ira->codegen->invalid_instruction; | ||
| 12230 | |||
| 12231 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, | ||
| 12232 | instruction->base.source_node, op_id, op1, casted_op2, true); | ||
| 12233 | result->value.type = op1->value.type; | ||
| 12234 | return result; | ||
| 12235 | } | ||
| 12236 | |||
| 12237 | IrInstruction *instructions[] = {op1, op2}; | ||
| 11968 | ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2); | 12238 | ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2); |
| 11969 | if (type_is_invalid(resolved_type)) | 12239 | if (type_is_invalid(resolved_type)) |
| 11970 | return ira->codegen->invalid_instruction; | 12240 | return ira->codegen->invalid_instruction; |
| ... | @@ -12076,21 +12346,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -12076,21 +12346,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 12076 | op_id = IrBinOpRemRem; | 12346 | op_id = IrBinOpRemRem; |
| 12077 | } | 12347 | } |
| 12078 | 12348 | ||
| 12349 | bool ok = false; | ||
| 12079 | if (is_int) { | 12350 | if (is_int) { |
| 12080 | // int | 12351 | ok = true; |
| 12081 | } else if (is_float && | 12352 | } else if (is_float && ok_float_op(op_id)) { |
| 12082 | (op_id == IrBinOpAdd || | 12353 | ok = true; |
| 12083 | op_id == IrBinOpSub || | 12354 | } else if (resolved_type->id == ZigTypeIdVector) { |
| 12084 | op_id == IrBinOpMult || | 12355 | ZigType *elem_type = resolved_type->data.vector.elem_type; |
| 12085 | op_id == IrBinOpDivUnspecified || | 12356 | if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) { |
| 12086 | op_id == IrBinOpDivTrunc || | 12357 | ok = true; |
| 12087 | op_id == IrBinOpDivFloor || | 12358 | } else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) { |
| 12088 | op_id == IrBinOpDivExact || | 12359 | ok = true; |
| 12089 | op_id == IrBinOpRemRem || | 12360 | } |
| 12090 | op_id == IrBinOpRemMod)) | 12361 | } |
| 12091 | { | 12362 | if (!ok) { |
| 12092 | // float | ||
| 12093 | } else { | ||
| 12094 | AstNode *source_node = instruction->base.source_node; | 12363 | AstNode *source_node = instruction->base.source_node; |
| 12095 | ir_add_error_node(ira, source_node, | 12364 | ir_add_error_node(ira, source_node, |
| 12096 | buf_sprintf("invalid operands to binary expression: '%s' and '%s'", | 12365 | buf_sprintf("invalid operands to binary expression: '%s' and '%s'", |
| ... | @@ -12125,30 +12394,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -12125,30 +12394,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 12125 | if (op2_val == nullptr) | 12394 | if (op2_val == nullptr) |
| 12126 | return ira->codegen->invalid_instruction; | 12395 | return ira->codegen->invalid_instruction; |
| 12127 | 12396 | ||
| 12128 | IrInstruction *result_instruction = ir_const(ira, &instruction->base, resolved_type); | 12397 | return ir_analyze_math_op(ira, &instruction->base, resolved_type, op1_val, op_id, op2_val); |
| 12129 | |||
| 12130 | int err; | ||
| 12131 | if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, &result_instruction->value))) { | ||
| 12132 | if (err == ErrorDivByZero) { | ||
| 12133 | ir_add_error(ira, &instruction->base, buf_sprintf("division by zero")); | ||
| 12134 | return ira->codegen->invalid_instruction; | ||
| 12135 | } else if (err == ErrorOverflow) { | ||
| 12136 | ir_add_error(ira, &instruction->base, buf_sprintf("operation caused overflow")); | ||
| 12137 | return ira->codegen->invalid_instruction; | ||
| 12138 | } else if (err == ErrorExactDivRemainder) { | ||
| 12139 | ir_add_error(ira, &instruction->base, buf_sprintf("exact division had a remainder")); | ||
| 12140 | return ira->codegen->invalid_instruction; | ||
| 12141 | } else if (err == ErrorNegativeDenominator) { | ||
| 12142 | ir_add_error(ira, &instruction->base, buf_sprintf("negative denominator")); | ||
| 12143 | return ira->codegen->invalid_instruction; | ||
| 12144 | } else { | ||
| 12145 | zig_unreachable(); | ||
| 12146 | } | ||
| 12147 | return ira->codegen->invalid_instruction; | ||
| 12148 | } | ||
| 12149 | |||
| 12150 | ir_num_lit_fits_in_other_type(ira, result_instruction, resolved_type, false); | ||
| 12151 | return result_instruction; | ||
| 12152 | } | 12398 | } |
| 12153 | 12399 | ||
| 12154 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, | 12400 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, |
| ... | @@ -12202,7 +12448,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i | ... | @@ -12202,7 +12448,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 12202 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; | 12448 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 12203 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; | 12449 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 12204 | ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; | 12450 | ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; |
| 12205 | op1_array_end = bigint_as_unsigned(&len_val->data.x_bigint); | 12451 | op1_array_end = op1_array_index + bigint_as_unsigned(&len_val->data.x_bigint); |
| 12206 | } else { | 12452 | } else { |
| 12207 | ir_add_error(ira, op1, | 12453 | ir_add_error(ira, op1, |
| 12208 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); | 12454 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); |
| ... | @@ -12212,13 +12458,9 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i | ... | @@ -12212,13 +12458,9 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 12212 | ConstExprValue *op2_array_val; | 12458 | ConstExprValue *op2_array_val; |
| 12213 | size_t op2_array_index; | 12459 | size_t op2_array_index; |
| 12214 | size_t op2_array_end; | 12460 | size_t op2_array_end; |
| 12461 | bool op2_type_valid; | ||
| 12215 | if (op2_type->id == ZigTypeIdArray) { | 12462 | if (op2_type->id == ZigTypeIdArray) { |
| 12216 | if (op2_type->data.array.child_type != child_type) { | 12463 | op2_type_valid = op2_type->data.array.child_type == child_type; |
| 12217 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", | ||
| 12218 | buf_ptr(&child_type->name), | ||
| 12219 | buf_ptr(&op2->value.type->name))); | ||
| 12220 | return ira->codegen->invalid_instruction; | ||
| 12221 | } | ||
| 12222 | op2_array_val = op2_val; | 12464 | op2_array_val = op2_val; |
| 12223 | op2_array_index = 0; | 12465 | op2_array_index = 0; |
| 12224 | op2_array_end = op2_array_val->type->data.array.len; | 12466 | op2_array_end = op2_array_val->type->data.array.len; |
| ... | @@ -12227,35 +12469,30 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i | ... | @@ -12227,35 +12469,30 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 12227 | op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && | 12469 | op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && |
| 12228 | op2_val->data.x_ptr.data.base_array.is_cstr) | 12470 | op2_val->data.x_ptr.data.base_array.is_cstr) |
| 12229 | { | 12471 | { |
| 12230 | if (child_type != ira->codegen->builtin_types.entry_u8) { | 12472 | op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8; |
| 12231 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", | ||
| 12232 | buf_ptr(&child_type->name), | ||
| 12233 | buf_ptr(&op2->value.type->name))); | ||
| 12234 | return ira->codegen->invalid_instruction; | ||
| 12235 | } | ||
| 12236 | op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; | 12473 | op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; |
| 12237 | op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; | 12474 | op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; |
| 12238 | op2_array_end = op2_array_val->type->data.array.len - 1; | 12475 | op2_array_end = op2_array_val->type->data.array.len - 1; |
| 12239 | } else if (is_slice(op2_type)) { | 12476 | } else if (is_slice(op2_type)) { |
| 12240 | ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; | 12477 | ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; |
| 12241 | if (ptr_type->data.pointer.child_type != child_type) { | 12478 | op2_type_valid = ptr_type->data.pointer.child_type == child_type; |
| 12242 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", | ||
| 12243 | buf_ptr(&child_type->name), | ||
| 12244 | buf_ptr(&op2->value.type->name))); | ||
| 12245 | return ira->codegen->invalid_instruction; | ||
| 12246 | } | ||
| 12247 | ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; | 12479 | ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; |
| 12248 | assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); | 12480 | assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 12249 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; | 12481 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 12250 | op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; | 12482 | op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 12251 | op2_array_end = op2_array_val->type->data.array.len; | ||
| 12252 | ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; | 12483 | ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; |
| 12253 | op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); | 12484 | op2_array_end = op2_array_index + bigint_as_unsigned(&len_val->data.x_bigint); |
| 12254 | } else { | 12485 | } else { |
| 12255 | ir_add_error(ira, op2, | 12486 | ir_add_error(ira, op2, |
| 12256 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); | 12487 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); |
| 12257 | return ira->codegen->invalid_instruction; | 12488 | return ira->codegen->invalid_instruction; |
| 12258 | } | 12489 | } |
| 12490 | if (!op2_type_valid) { | ||
| 12491 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", | ||
| 12492 | buf_ptr(&child_type->name), | ||
| 12493 | buf_ptr(&op2->value.type->name))); | ||
| 12494 | return ira->codegen->invalid_instruction; | ||
| 12495 | } | ||
| 12259 | 12496 | ||
| 12260 | // The type of result is populated in the following if blocks | 12497 | // The type of result is populated in the following if blocks |
| 12261 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); | 12498 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); |
| ... | @@ -12388,26 +12625,14 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -12388,26 +12625,14 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * |
| 12388 | } | 12625 | } |
| 12389 | 12626 | ||
| 12390 | static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { | 12627 | static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { |
| 12391 | ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child); | 12628 | ZigType *op1_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op1->child); |
| 12392 | if (type_is_invalid(op1_type)) | 12629 | if (type_is_invalid(op1_type)) |
| 12393 | return ira->codegen->invalid_instruction; | 12630 | return ira->codegen->invalid_instruction; |
| 12394 | 12631 | ||
| 12395 | if (op1_type->id != ZigTypeIdErrorSet) { | 12632 | ZigType *op2_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op2->child); |
| 12396 | ir_add_error(ira, instruction->op1, | ||
| 12397 | buf_sprintf("expected error set type, found '%s'", buf_ptr(&op1_type->name))); | ||
| 12398 | return ira->codegen->invalid_instruction; | ||
| 12399 | } | ||
| 12400 | |||
| 12401 | ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child); | ||
| 12402 | if (type_is_invalid(op2_type)) | 12633 | if (type_is_invalid(op2_type)) |
| 12403 | return ira->codegen->invalid_instruction; | 12634 | return ira->codegen->invalid_instruction; |
| 12404 | 12635 | ||
| 12405 | if (op2_type->id != ZigTypeIdErrorSet) { | ||
| 12406 | ir_add_error(ira, instruction->op2, | ||
| 12407 | buf_sprintf("expected error set type, found '%s'", buf_ptr(&op2_type->name))); | ||
| 12408 | return ira->codegen->invalid_instruction; | ||
| 12409 | } | ||
| 12410 | |||
| 12411 | if (type_is_global_error_set(op1_type) || | 12636 | if (type_is_global_error_set(op1_type) || |
| 12412 | type_is_global_error_set(op2_type)) | 12637 | type_is_global_error_set(op2_type)) |
| 12413 | { | 12638 | { |
| ... | @@ -12481,13 +12706,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio | ... | @@ -12481,13 +12706,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio |
| 12481 | zig_unreachable(); | 12706 | zig_unreachable(); |
| 12482 | } | 12707 | } |
| 12483 | 12708 | ||
| 12484 | static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { | 12709 | static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 12710 | IrInstructionDeclVarSrc *decl_var_instruction) | ||
| 12711 | { | ||
| 12485 | Error err; | 12712 | Error err; |
| 12486 | ZigVar *var = decl_var_instruction->var; | 12713 | ZigVar *var = decl_var_instruction->var; |
| 12487 | 12714 | ||
| 12488 | IrInstruction *init_value = decl_var_instruction->init_value->child; | 12715 | IrInstruction *init_value = decl_var_instruction->init_value->child; |
| 12489 | if (type_is_invalid(init_value->value.type)) { | 12716 | if (type_is_invalid(init_value->value.type)) { |
| 12490 | var->value->type = ira->codegen->builtin_types.entry_invalid; | 12717 | var->var_type = ira->codegen->builtin_types.entry_invalid; |
| 12491 | return ira->codegen->invalid_instruction; | 12718 | return ira->codegen->invalid_instruction; |
| 12492 | } | 12719 | } |
| 12493 | 12720 | ||
| ... | @@ -12498,7 +12725,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12498,7 +12725,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12498 | ZigType *proposed_type = ir_resolve_type(ira, var_type); | 12725 | ZigType *proposed_type = ir_resolve_type(ira, var_type); |
| 12499 | explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); | 12726 | explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); |
| 12500 | if (type_is_invalid(explicit_type)) { | 12727 | if (type_is_invalid(explicit_type)) { |
| 12501 | var->value->type = ira->codegen->builtin_types.entry_invalid; | 12728 | var->var_type = ira->codegen->builtin_types.entry_invalid; |
| 12502 | return ira->codegen->invalid_instruction; | 12729 | return ira->codegen->invalid_instruction; |
| 12503 | } | 12730 | } |
| 12504 | } | 12731 | } |
| ... | @@ -12523,7 +12750,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12523,7 +12750,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12523 | case ReqCompTimeInvalid: | 12750 | case ReqCompTimeInvalid: |
| 12524 | result_type = ira->codegen->builtin_types.entry_invalid; | 12751 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12525 | break; | 12752 | break; |
| 12526 | case ReqCompTimeYes: { | 12753 | case ReqCompTimeYes: |
| 12527 | var_class_requires_const = true; | 12754 | var_class_requires_const = true; |
| 12528 | if (!var->gen_is_const && !is_comptime_var) { | 12755 | if (!var->gen_is_const && !is_comptime_var) { |
| 12529 | ir_add_error_node(ira, source_node, | 12756 | ir_add_error_node(ira, source_node, |
| ... | @@ -12532,7 +12759,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12532,7 +12759,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12532 | result_type = ira->codegen->builtin_types.entry_invalid; | 12759 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12533 | } | 12760 | } |
| 12534 | break; | 12761 | break; |
| 12535 | } | ||
| 12536 | case ReqCompTimeNo: | 12762 | case ReqCompTimeNo: |
| 12537 | if (casted_init_value->value.special == ConstValSpecialStatic && | 12763 | if (casted_init_value->value.special == ConstValSpecialStatic && |
| 12538 | casted_init_value->value.type->id == ZigTypeIdFn && | 12764 | casted_init_value->value.type->id == ZigTypeIdFn && |
| ... | @@ -12551,7 +12777,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12551,7 +12777,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12551 | break; | 12777 | break; |
| 12552 | } | 12778 | } |
| 12553 | 12779 | ||
| 12554 | if (var->value->type != nullptr && !is_comptime_var) { | 12780 | if (var->var_type != nullptr && !is_comptime_var) { |
| 12555 | // This is at least the second time we've seen this variable declaration during analysis. | 12781 | // This is at least the second time we've seen this variable declaration during analysis. |
| 12556 | // This means that this is actually a different variable due to, e.g. an inline while loop. | 12782 | // This means that this is actually a different variable due to, e.g. an inline while loop. |
| 12557 | // We make a new variable so that it can hold a different type, and so the debug info can | 12783 | // We make a new variable so that it can hold a different type, and so the debug info can |
| ... | @@ -12573,8 +12799,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12573,8 +12799,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12573 | // This must be done after possibly creating a new variable above | 12799 | // This must be done after possibly creating a new variable above |
| 12574 | var->ref_count = 0; | 12800 | var->ref_count = 0; |
| 12575 | 12801 | ||
| 12576 | var->value->type = result_type; | 12802 | var->var_type = result_type; |
| 12577 | assert(var->value->type); | 12803 | assert(var->var_type); |
| 12578 | 12804 | ||
| 12579 | if (type_is_invalid(result_type)) { | 12805 | if (type_is_invalid(result_type)) { |
| 12580 | return ir_const_void(ira, &decl_var_instruction->base); | 12806 | return ir_const_void(ira, &decl_var_instruction->base); |
| ... | @@ -12582,13 +12808,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12582,13 +12808,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12582 | 12808 | ||
| 12583 | if (decl_var_instruction->align_value == nullptr) { | 12809 | if (decl_var_instruction->align_value == nullptr) { |
| 12584 | if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { | 12810 | if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { |
| 12585 | var->value->type = ira->codegen->builtin_types.entry_invalid; | 12811 | var->var_type = ira->codegen->builtin_types.entry_invalid; |
| 12586 | return ir_const_void(ira, &decl_var_instruction->base); | 12812 | return ir_const_void(ira, &decl_var_instruction->base); |
| 12587 | } | 12813 | } |
| 12588 | var->align_bytes = get_abi_alignment(ira->codegen, result_type); | 12814 | var->align_bytes = get_abi_alignment(ira->codegen, result_type); |
| 12589 | } else { | 12815 | } else { |
| 12590 | if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) { | 12816 | if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) { |
| 12591 | var->value->type = ira->codegen->builtin_types.entry_invalid; | 12817 | var->var_type = ira->codegen->builtin_types.entry_invalid; |
| 12592 | } | 12818 | } |
| 12593 | } | 12819 | } |
| 12594 | 12820 | ||
| ... | @@ -12605,7 +12831,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12605,7 +12831,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12605 | } else if (is_comptime_var) { | 12831 | } else if (is_comptime_var) { |
| 12606 | ir_add_error(ira, &decl_var_instruction->base, | 12832 | ir_add_error(ira, &decl_var_instruction->base, |
| 12607 | buf_sprintf("cannot store runtime value in compile time variable")); | 12833 | buf_sprintf("cannot store runtime value in compile time variable")); |
| 12608 | var->value->type = ira->codegen->builtin_types.entry_invalid; | 12834 | var->var_type = ira->codegen->builtin_types.entry_invalid; |
| 12609 | return ira->codegen->invalid_instruction; | 12835 | return ira->codegen->invalid_instruction; |
| 12610 | } | 12836 | } |
| 12611 | 12837 | ||
| ... | @@ -12613,11 +12839,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct | ... | @@ -12613,11 +12839,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12613 | if (fn_entry) | 12839 | if (fn_entry) |
| 12614 | fn_entry->variable_list.append(var); | 12840 | fn_entry->variable_list.append(var); |
| 12615 | 12841 | ||
| 12616 | IrInstruction *result = ir_build_var_decl(&ira->new_irb, | 12842 | return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); |
| 12617 | decl_var_instruction->base.scope, decl_var_instruction->base.source_node, | ||
| 12618 | var, var_type, nullptr, casted_init_value); | ||
| 12619 | result->value.type = ira->codegen->builtin_types.entry_void; | ||
| 12620 | return result; | ||
| 12621 | } | 12843 | } |
| 12622 | 12844 | ||
| 12623 | static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { | 12845 | static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { |
| ... | @@ -12739,6 +12961,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio | ... | @@ -12739,6 +12961,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 12739 | case ZigTypeIdPointer: | 12961 | case ZigTypeIdPointer: |
| 12740 | case ZigTypeIdArray: | 12962 | case ZigTypeIdArray: |
| 12741 | case ZigTypeIdBool: | 12963 | case ZigTypeIdBool: |
| 12964 | case ZigTypeIdVector: | ||
| 12742 | break; | 12965 | break; |
| 12743 | case ZigTypeIdMetaType: | 12966 | case ZigTypeIdMetaType: |
| 12744 | case ZigTypeIdVoid: | 12967 | case ZigTypeIdVoid: |
| ... | @@ -12773,6 +12996,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio | ... | @@ -12773,6 +12996,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 12773 | case ZigTypeIdOptional: | 12996 | case ZigTypeIdOptional: |
| 12774 | case ZigTypeIdErrorUnion: | 12997 | case ZigTypeIdErrorUnion: |
| 12775 | case ZigTypeIdErrorSet: | 12998 | case ZigTypeIdErrorSet: |
| 12999 | case ZigTypeIdVector: | ||
| 12776 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); | 13000 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); |
| 12777 | case ZigTypeIdNamespace: | 13001 | case ZigTypeIdNamespace: |
| 12778 | case ZigTypeIdBoundFn: | 13002 | case ZigTypeIdBoundFn: |
| ... | @@ -12947,7 +13171,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node | ... | @@ -12947,7 +13171,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node |
| 12947 | 13171 | ||
| 12948 | Buf *param_name = param_decl_node->data.param_decl.name; | 13172 | Buf *param_name = param_decl_node->data.param_decl.name; |
| 12949 | ZigVar *var = add_variable(ira->codegen, param_decl_node, | 13173 | ZigVar *var = add_variable(ira->codegen, param_decl_node, |
| 12950 | *exec_scope, param_name, true, arg_val, nullptr); | 13174 | *exec_scope, param_name, true, arg_val, nullptr, arg_val->type); |
| 12951 | *exec_scope = var->child_scope; | 13175 | *exec_scope = var->child_scope; |
| 12952 | *next_proto_i += 1; | 13176 | *next_proto_i += 1; |
| 12953 | 13177 | ||
| ... | @@ -13005,7 +13229,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod | ... | @@ -13005,7 +13229,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 13005 | if (!param_name) return false; | 13229 | if (!param_name) return false; |
| 13006 | if (!is_var_args) { | 13230 | if (!is_var_args) { |
| 13007 | ZigVar *var = add_variable(ira->codegen, param_decl_node, | 13231 | ZigVar *var = add_variable(ira->codegen, param_decl_node, |
| 13008 | *child_scope, param_name, true, arg_val, nullptr); | 13232 | *child_scope, param_name, true, arg_val, nullptr, arg_val->type); |
| 13009 | *child_scope = var->child_scope; | 13233 | *child_scope = var->child_scope; |
| 13010 | var->shadowable = !comptime_arg; | 13234 | var->shadowable = !comptime_arg; |
| 13011 | 13235 | ||
| ... | @@ -13059,9 +13283,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { | ... | @@ -13059,9 +13283,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { |
| 13059 | return fn_entry->variable_list.at(next_var_i); | 13283 | return fn_entry->variable_list.at(next_var_i); |
| 13060 | } | 13284 | } |
| 13061 | 13285 | ||
| 13062 | static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | 13286 | static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { |
| 13063 | ZigVar *var) | ||
| 13064 | { | ||
| 13065 | while (var->next_var != nullptr) { | 13287 | while (var->next_var != nullptr) { |
| 13066 | var = var->next_var; | 13288 | var = var->next_var; |
| 13067 | } | 13289 | } |
| ... | @@ -13070,14 +13292,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -13070,14 +13292,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13070 | assert(ira->codegen->errors.length != 0); | 13292 | assert(ira->codegen->errors.length != 0); |
| 13071 | return ira->codegen->invalid_instruction; | 13293 | return ira->codegen->invalid_instruction; |
| 13072 | } | 13294 | } |
| 13073 | if (var->value->type == nullptr || type_is_invalid(var->value->type)) | 13295 | if (var->var_type == nullptr || type_is_invalid(var->var_type)) |
| 13074 | return ira->codegen->invalid_instruction; | 13296 | return ira->codegen->invalid_instruction; |
| 13075 | 13297 | ||
| 13076 | bool comptime_var_mem = ir_get_var_is_comptime(var); | 13298 | bool comptime_var_mem = ir_get_var_is_comptime(var); |
| 13077 | 13299 | ||
| 13078 | ConstExprValue *mem_slot = nullptr; | 13300 | ConstExprValue *mem_slot = nullptr; |
| 13079 | if (var->value->special == ConstValSpecialStatic) { | 13301 | if (var->const_value->special == ConstValSpecialStatic) { |
| 13080 | mem_slot = var->value; | 13302 | mem_slot = var->const_value; |
| 13081 | } else { | 13303 | } else { |
| 13082 | if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { | 13304 | if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { |
| 13083 | // find the relevant exec_context | 13305 | // find the relevant exec_context |
| ... | @@ -13106,7 +13328,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -13106,7 +13328,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13106 | assert(!comptime_var_mem); | 13328 | assert(!comptime_var_mem); |
| 13107 | ptr_mut = ConstPtrMutRuntimeVar; | 13329 | ptr_mut = ConstPtrMutRuntimeVar; |
| 13108 | } | 13330 | } |
| 13109 | return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, | 13331 | return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, |
| 13110 | ptr_mut, is_const, is_volatile, var->align_bytes); | 13332 | ptr_mut, is_const, is_volatile, var->align_bytes); |
| 13111 | } | 13333 | } |
| 13112 | } | 13334 | } |
| ... | @@ -13117,7 +13339,7 @@ no_mem_slot: | ... | @@ -13117,7 +13339,7 @@ no_mem_slot: |
| 13117 | 13339 | ||
| 13118 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, | 13340 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, |
| 13119 | instruction->scope, instruction->source_node, var); | 13341 | instruction->scope, instruction->source_node, var); |
| 13120 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, | 13342 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, |
| 13121 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); | 13343 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); |
| 13122 | 13344 | ||
| 13123 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | 13345 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| ... | @@ -13126,6 +13348,96 @@ no_mem_slot: | ... | @@ -13126,6 +13348,96 @@ no_mem_slot: |
| 13126 | return var_ptr_instruction; | 13348 | return var_ptr_instruction; |
| 13127 | } | 13349 | } |
| 13128 | 13350 | ||
| 13351 | static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 13352 | IrInstruction *ptr, IrInstruction *uncasted_value) | ||
| 13353 | { | ||
| 13354 | if (ptr->value.type->id != ZigTypeIdPointer) { | ||
| 13355 | ir_add_error(ira, ptr, | ||
| 13356 | buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); | ||
| 13357 | return ira->codegen->invalid_instruction; | ||
| 13358 | } | ||
| 13359 | |||
| 13360 | if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { | ||
| 13361 | return ir_const_void(ira, source_instr); | ||
| 13362 | } | ||
| 13363 | |||
| 13364 | if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) { | ||
| 13365 | ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); | ||
| 13366 | return ira->codegen->invalid_instruction; | ||
| 13367 | } | ||
| 13368 | |||
| 13369 | ZigType *child_type = ptr->value.type->data.pointer.child_type; | ||
| 13370 | IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type); | ||
| 13371 | if (value == ira->codegen->invalid_instruction) | ||
| 13372 | return ira->codegen->invalid_instruction; | ||
| 13373 | |||
| 13374 | if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { | ||
| 13375 | if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { | ||
| 13376 | ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); | ||
| 13377 | return ira->codegen->invalid_instruction; | ||
| 13378 | } | ||
| 13379 | if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { | ||
| 13380 | if (instr_is_comptime(value)) { | ||
| 13381 | ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node); | ||
| 13382 | if (dest_val == nullptr) | ||
| 13383 | return ira->codegen->invalid_instruction; | ||
| 13384 | if (dest_val->special != ConstValSpecialRuntime) { | ||
| 13385 | // TODO this allows a value stored to have the original value modified and then | ||
| 13386 | // have that affect what should be a copy. We need some kind of advanced copy-on-write | ||
| 13387 | // system to make these two tests pass at the same time: | ||
| 13388 | // * "string literal used as comptime slice is memoized" | ||
| 13389 | // * "comptime modification of const struct field" - except modified to avoid | ||
| 13390 | // ConstPtrMutComptimeVar, thus defeating the logic below. | ||
| 13391 | bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; | ||
| 13392 | copy_const_val(dest_val, &value->value, same_global_refs); | ||
| 13393 | if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { | ||
| 13394 | switch (type_has_one_possible_value(ira->codegen, child_type)) { | ||
| 13395 | case OnePossibleValueInvalid: | ||
| 13396 | return ira->codegen->invalid_instruction; | ||
| 13397 | case OnePossibleValueNo: | ||
| 13398 | ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; | ||
| 13399 | break; | ||
| 13400 | case OnePossibleValueYes: | ||
| 13401 | break; | ||
| 13402 | } | ||
| 13403 | } | ||
| 13404 | return ir_const_void(ira, source_instr); | ||
| 13405 | } | ||
| 13406 | } | ||
| 13407 | ir_add_error(ira, source_instr, | ||
| 13408 | buf_sprintf("cannot store runtime value in compile time variable")); | ||
| 13409 | ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); | ||
| 13410 | dest_val->type = ira->codegen->builtin_types.entry_invalid; | ||
| 13411 | |||
| 13412 | return ira->codegen->invalid_instruction; | ||
| 13413 | } | ||
| 13414 | } | ||
| 13415 | |||
| 13416 | switch (type_requires_comptime(ira->codegen, child_type)) { | ||
| 13417 | case ReqCompTimeInvalid: | ||
| 13418 | return ira->codegen->invalid_instruction; | ||
| 13419 | case ReqCompTimeYes: | ||
| 13420 | switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) { | ||
| 13421 | case OnePossibleValueInvalid: | ||
| 13422 | return ira->codegen->invalid_instruction; | ||
| 13423 | case OnePossibleValueNo: | ||
| 13424 | ir_add_error(ira, source_instr, | ||
| 13425 | buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name))); | ||
| 13426 | return ira->codegen->invalid_instruction; | ||
| 13427 | case OnePossibleValueYes: | ||
| 13428 | return ir_const_void(ira, source_instr); | ||
| 13429 | } | ||
| 13430 | zig_unreachable(); | ||
| 13431 | case ReqCompTimeNo: | ||
| 13432 | break; | ||
| 13433 | } | ||
| 13434 | |||
| 13435 | IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, | ||
| 13436 | ptr, value); | ||
| 13437 | result->value.type = ira->codegen->builtin_types.entry_void; | ||
| 13438 | return result; | ||
| 13439 | } | ||
| 13440 | |||
| 13129 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 13441 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 13130 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, | 13442 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, |
| 13131 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) | 13443 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) |
| ... | @@ -13270,7 +13582,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13270,7 +13582,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13270 | } | 13582 | } |
| 13271 | 13583 | ||
| 13272 | bool cacheable = fn_eval_cacheable(exec_scope, return_type); | 13584 | bool cacheable = fn_eval_cacheable(exec_scope, return_type); |
| 13273 | IrInstruction *result = nullptr; | 13585 | ConstExprValue *result = nullptr; |
| 13274 | if (cacheable) { | 13586 | if (cacheable) { |
| 13275 | auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); | 13587 | auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); |
| 13276 | if (entry) | 13588 | if (entry) |
| ... | @@ -13286,18 +13598,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13286,18 +13598,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13286 | 13598 | ||
| 13287 | if (inferred_err_set_type != nullptr) { | 13599 | if (inferred_err_set_type != nullptr) { |
| 13288 | inferred_err_set_type->data.error_set.infer_fn = nullptr; | 13600 | inferred_err_set_type->data.error_set.infer_fn = nullptr; |
| 13289 | if (result->value.type->id == ZigTypeIdErrorUnion) { | 13601 | if (result->type->id == ZigTypeIdErrorUnion) { |
| 13290 | if (result->value.data.x_err_union.err != nullptr) { | 13602 | ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; |
| 13603 | if (err != nullptr) { | ||
| 13291 | inferred_err_set_type->data.error_set.err_count = 1; | 13604 | inferred_err_set_type->data.error_set.err_count = 1; |
| 13292 | inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1); | 13605 | inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1); |
| 13293 | inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err; | 13606 | inferred_err_set_type->data.error_set.errors[0] = err; |
| 13294 | } | 13607 | } |
| 13295 | ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type; | 13608 | ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type; |
| 13296 | inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; | 13609 | inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; |
| 13297 | inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; | 13610 | inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; |
| 13298 | } else if (result->value.type->id == ZigTypeIdErrorSet) { | 13611 | } else if (result->type->id == ZigTypeIdErrorSet) { |
| 13299 | inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count; | 13612 | inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; |
| 13300 | inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors; | 13613 | inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors; |
| 13301 | } | 13614 | } |
| 13302 | } | 13615 | } |
| 13303 | 13616 | ||
| ... | @@ -13305,13 +13618,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13305,13 +13618,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13305 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); | 13618 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); |
| 13306 | } | 13619 | } |
| 13307 | 13620 | ||
| 13308 | if (type_is_invalid(result->value.type)) | 13621 | if (type_is_invalid(result->type)) |
| 13309 | return ira->codegen->invalid_instruction; | 13622 | return ira->codegen->invalid_instruction; |
| 13310 | } | 13623 | } |
| 13311 | 13624 | ||
| 13312 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type); | 13625 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); |
| 13313 | // TODO should we use copy_const_val? | 13626 | copy_const_val(&new_instruction->value, result, true); |
| 13314 | new_instruction->value = result->value; | ||
| 13315 | new_instruction->value.type = return_type; | 13627 | new_instruction->value.type = return_type; |
| 13316 | return ir_finish_anal(ira, new_instruction); | 13628 | return ir_finish_anal(ira, new_instruction); |
| 13317 | } | 13629 | } |
| ... | @@ -13470,18 +13782,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13470,18 +13782,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13470 | ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, | 13782 | ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, |
| 13471 | first_var_arg, inst_fn_type_id.param_count); | 13783 | first_var_arg, inst_fn_type_id.param_count); |
| 13472 | ZigVar *var = add_variable(ira->codegen, param_decl_node, | 13784 | ZigVar *var = add_variable(ira->codegen, param_decl_node, |
| 13473 | impl_fn->child_scope, param_name, true, var_args_val, nullptr); | 13785 | impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type); |
| 13474 | impl_fn->child_scope = var->child_scope; | 13786 | impl_fn->child_scope = var->child_scope; |
| 13475 | } | 13787 | } |
| 13476 | 13788 | ||
| 13477 | if (fn_proto_node->data.fn_proto.align_expr != nullptr) { | 13789 | if (fn_proto_node->data.fn_proto.align_expr != nullptr) { |
| 13478 | IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, | 13790 | ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, |
| 13479 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), | 13791 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), |
| 13480 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, | 13792 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, |
| 13481 | nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); | 13793 | nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); |
| 13794 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | ||
| 13795 | impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); | ||
| 13796 | const_instruction->base.value = *align_result; | ||
| 13482 | 13797 | ||
| 13483 | uint32_t align_bytes = 0; | 13798 | uint32_t align_bytes = 0; |
| 13484 | ir_resolve_align(ira, align_result, &align_bytes); | 13799 | ir_resolve_align(ira, &const_instruction->base, &align_bytes); |
| 13485 | impl_fn->align_bytes = align_bytes; | 13800 | impl_fn->align_bytes = align_bytes; |
| 13486 | inst_fn_type_id.alignment = align_bytes; | 13801 | inst_fn_type_id.alignment = align_bytes; |
| 13487 | } | 13802 | } |
| ... | @@ -13559,12 +13874,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13559,12 +13874,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13559 | ira->codegen->fn_defs.append(impl_fn); | 13874 | ira->codegen->fn_defs.append(impl_fn); |
| 13560 | } | 13875 | } |
| 13561 | 13876 | ||
| 13562 | ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; | 13877 | FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; |
| 13563 | if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) { | 13878 | if (fn_type_can_fail(impl_fn_type_id)) { |
| 13564 | parent_fn_entry->calls_or_awaits_errorable_fn = true; | 13879 | parent_fn_entry->calls_or_awaits_errorable_fn = true; |
| 13565 | } | 13880 | } |
| 13566 | 13881 | ||
| 13567 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; | 13882 | size_t impl_param_count = impl_fn_type_id->param_count; |
| 13568 | if (call_instruction->is_async) { | 13883 | if (call_instruction->is_async) { |
| 13569 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | 13884 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, |
| 13570 | fn_ref, casted_args, impl_param_count, async_allocator_inst); | 13885 | fn_ref, casted_args, impl_param_count, async_allocator_inst); |
| ... | @@ -13577,9 +13892,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call | ... | @@ -13577,9 +13892,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13577 | call_instruction->base.scope, call_instruction->base.source_node, | 13892 | call_instruction->base.scope, call_instruction->base.source_node, |
| 13578 | impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, | 13893 | impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, |
| 13579 | call_instruction->is_async, nullptr, casted_new_stack); | 13894 | call_instruction->is_async, nullptr, casted_new_stack); |
| 13580 | new_call_instruction->value.type = return_type; | 13895 | new_call_instruction->value.type = impl_fn_type_id->return_type; |
| 13581 | 13896 | ||
| 13582 | ir_add_alloca(ira, new_call_instruction, return_type); | 13897 | ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type); |
| 13583 | 13898 | ||
| 13584 | return ir_finish_anal(ira, new_call_instruction); | 13899 | return ir_finish_anal(ira, new_call_instruction); |
| 13585 | } | 13900 | } |
| ... | @@ -13774,6 +14089,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source | ... | @@ -13774,6 +14089,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 13774 | switch (ptr_val->data.x_ptr.special) { | 14089 | switch (ptr_val->data.x_ptr.special) { |
| 13775 | case ConstPtrSpecialInvalid: | 14090 | case ConstPtrSpecialInvalid: |
| 13776 | zig_unreachable(); | 14091 | zig_unreachable(); |
| 14092 | case ConstPtrSpecialNull: | ||
| 14093 | if (dst_size == 0) | ||
| 14094 | return ErrorNone; | ||
| 14095 | opt_ir_add_error_node(ira, codegen, source_node, | ||
| 14096 | buf_sprintf("attempt to read %zu bytes from null pointer", | ||
| 14097 | dst_size)); | ||
| 14098 | return ErrorSemanticAnalyzeFail; | ||
| 13777 | case ConstPtrSpecialRef: { | 14099 | case ConstPtrSpecialRef: { |
| 13778 | opt_ir_add_error_node(ira, codegen, source_node, | 14100 | opt_ir_add_error_node(ira, codegen, source_node, |
| 13779 | buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", | 14101 | buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", |
| ... | @@ -13806,6 +14128,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source | ... | @@ -13806,6 +14128,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 13806 | return ErrorNone; | 14128 | return ErrorNone; |
| 13807 | } | 14129 | } |
| 13808 | case ConstPtrSpecialBaseStruct: | 14130 | case ConstPtrSpecialBaseStruct: |
| 14131 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 14132 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 14133 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 13809 | case ConstPtrSpecialDiscard: | 14134 | case ConstPtrSpecialDiscard: |
| 13810 | case ConstPtrSpecialHardCodedAddr: | 14135 | case ConstPtrSpecialHardCodedAddr: |
| 13811 | case ConstPtrSpecialFunction: | 14136 | case ConstPtrSpecialFunction: |
| ... | @@ -13830,6 +14155,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ | ... | @@ -13830,6 +14155,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ |
| 13830 | case ZigTypeIdVoid: | 14155 | case ZigTypeIdVoid: |
| 13831 | case ZigTypeIdBool: | 14156 | case ZigTypeIdBool: |
| 13832 | case ZigTypeIdInt: | 14157 | case ZigTypeIdInt: |
| 14158 | case ZigTypeIdVector: | ||
| 13833 | case ZigTypeIdFloat: | 14159 | case ZigTypeIdFloat: |
| 13834 | case ZigTypeIdPointer: | 14160 | case ZigTypeIdPointer: |
| 13835 | case ZigTypeIdArray: | 14161 | case ZigTypeIdArray: |
| ... | @@ -14001,9 +14327,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi | ... | @@ -14001,9 +14327,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi |
| 14001 | if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) | 14327 | if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) |
| 14002 | return ir_unreach_error(ira); | 14328 | return ir_unreach_error(ira); |
| 14003 | 14329 | ||
| 14004 | if (is_comptime || instr_is_comptime(condition)) { | 14330 | ZigType *bool_type = ira->codegen->builtin_types.entry_bool; |
| 14331 | IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); | ||
| 14332 | if (type_is_invalid(casted_condition->value.type)) | ||
| 14333 | return ir_unreach_error(ira); | ||
| 14334 | |||
| 14335 | if (is_comptime || instr_is_comptime(casted_condition)) { | ||
| 14005 | bool cond_is_true; | 14336 | bool cond_is_true; |
| 14006 | if (!ir_resolve_bool(ira, condition, &cond_is_true)) | 14337 | if (!ir_resolve_bool(ira, casted_condition, &cond_is_true)) |
| 14007 | return ir_unreach_error(ira); | 14338 | return ir_unreach_error(ira); |
| 14008 | 14339 | ||
| 14009 | IrBasicBlock *old_dest_block = cond_is_true ? | 14340 | IrBasicBlock *old_dest_block = cond_is_true ? |
| ... | @@ -14022,11 +14353,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi | ... | @@ -14022,11 +14353,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi |
| 14022 | return ir_finish_anal(ira, result); | 14353 | return ir_finish_anal(ira, result); |
| 14023 | } | 14354 | } |
| 14024 | 14355 | ||
| 14025 | ZigType *bool_type = ira->codegen->builtin_types.entry_bool; | ||
| 14026 | IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); | ||
| 14027 | if (casted_condition == ira->codegen->invalid_instruction) | ||
| 14028 | return ir_unreach_error(ira); | ||
| 14029 | |||
| 14030 | assert(cond_br_instruction->then_block != cond_br_instruction->else_block); | 14356 | assert(cond_br_instruction->then_block != cond_br_instruction->else_block); |
| 14031 | IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); | 14357 | IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); |
| 14032 | if (new_then_block == nullptr) | 14358 | if (new_then_block == nullptr) |
| ... | @@ -14065,8 +14391,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh | ... | @@ -14065,8 +14391,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh |
| 14065 | 14391 | ||
| 14066 | if (value->value.special != ConstValSpecialRuntime) { | 14392 | if (value->value.special != ConstValSpecialRuntime) { |
| 14067 | IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr); | 14393 | IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr); |
| 14068 | // TODO use copy_const_val? | 14394 | copy_const_val(&result->value, &value->value, true); |
| 14069 | result->value = value->value; | ||
| 14070 | return result; | 14395 | return result; |
| 14071 | } else { | 14396 | } else { |
| 14072 | return value; | 14397 | return value; |
| ... | @@ -14115,14 +14440,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh | ... | @@ -14115,14 +14440,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh |
| 14115 | if (type_is_invalid(resolved_type)) | 14440 | if (type_is_invalid(resolved_type)) |
| 14116 | return ira->codegen->invalid_instruction; | 14441 | return ira->codegen->invalid_instruction; |
| 14117 | 14442 | ||
| 14118 | if (resolved_type->id == ZigTypeIdComptimeFloat || | 14443 | switch (type_has_one_possible_value(ira->codegen, resolved_type)) { |
| 14119 | resolved_type->id == ZigTypeIdComptimeInt || | 14444 | case OnePossibleValueInvalid: |
| 14120 | resolved_type->id == ZigTypeIdNull || | 14445 | return ira->codegen->invalid_instruction; |
| 14121 | resolved_type->id == ZigTypeIdUndefined) | 14446 | case OnePossibleValueYes: |
| 14122 | { | 14447 | return ir_const(ira, &phi_instruction->base, resolved_type); |
| 14448 | case OnePossibleValueNo: | ||
| 14449 | break; | ||
| 14450 | } | ||
| 14451 | |||
| 14452 | switch (type_requires_comptime(ira->codegen, resolved_type)) { | ||
| 14453 | case ReqCompTimeInvalid: | ||
| 14454 | return ira->codegen->invalid_instruction; | ||
| 14455 | case ReqCompTimeYes: | ||
| 14123 | ir_add_error_node(ira, phi_instruction->base.source_node, | 14456 | ir_add_error_node(ira, phi_instruction->base.source_node, |
| 14124 | buf_sprintf("unable to infer expression type")); | 14457 | buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name))); |
| 14125 | return ira->codegen->invalid_instruction; | 14458 | return ira->codegen->invalid_instruction; |
| 14459 | case ReqCompTimeNo: | ||
| 14460 | break; | ||
| 14126 | } | 14461 | } |
| 14127 | 14462 | ||
| 14128 | bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); | 14463 | bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); |
| ... | @@ -14412,10 +14747,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct | ... | @@ -14412,10 +14747,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 14412 | } | 14747 | } |
| 14413 | case ConstPtrSpecialBaseStruct: | 14748 | case ConstPtrSpecialBaseStruct: |
| 14414 | zig_panic("TODO elem ptr on a const inner struct"); | 14749 | zig_panic("TODO elem ptr on a const inner struct"); |
| 14750 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 14751 | zig_panic("TODO elem ptr on a const inner error union code"); | ||
| 14752 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 14753 | zig_panic("TODO elem ptr on a const inner error union payload"); | ||
| 14754 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 14755 | zig_panic("TODO elem ptr on a const inner optional payload"); | ||
| 14415 | case ConstPtrSpecialHardCodedAddr: | 14756 | case ConstPtrSpecialHardCodedAddr: |
| 14416 | zig_unreachable(); | 14757 | zig_unreachable(); |
| 14417 | case ConstPtrSpecialFunction: | 14758 | case ConstPtrSpecialFunction: |
| 14418 | zig_panic("TODO element ptr of a function casted to a ptr"); | 14759 | zig_panic("TODO element ptr of a function casted to a ptr"); |
| 14760 | case ConstPtrSpecialNull: | ||
| 14761 | zig_panic("TODO elem ptr on a null pointer"); | ||
| 14419 | } | 14762 | } |
| 14420 | if (new_index >= mem_size) { | 14763 | if (new_index >= mem_size) { |
| 14421 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, | 14764 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| ... | @@ -14465,10 +14808,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct | ... | @@ -14465,10 +14808,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 14465 | } | 14808 | } |
| 14466 | case ConstPtrSpecialBaseStruct: | 14809 | case ConstPtrSpecialBaseStruct: |
| 14467 | zig_panic("TODO elem ptr on a slice backed by const inner struct"); | 14810 | zig_panic("TODO elem ptr on a slice backed by const inner struct"); |
| 14811 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 14812 | zig_panic("TODO elem ptr on a slice backed by const inner error union code"); | ||
| 14813 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 14814 | zig_panic("TODO elem ptr on a slice backed by const inner error union payload"); | ||
| 14815 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 14816 | zig_panic("TODO elem ptr on a slice backed by const optional payload"); | ||
| 14468 | case ConstPtrSpecialHardCodedAddr: | 14817 | case ConstPtrSpecialHardCodedAddr: |
| 14469 | zig_unreachable(); | 14818 | zig_unreachable(); |
| 14470 | case ConstPtrSpecialFunction: | 14819 | case ConstPtrSpecialFunction: |
| 14471 | zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); | 14820 | zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); |
| 14821 | case ConstPtrSpecialNull: | ||
| 14822 | zig_panic("TODO elem ptr on a slice has a null pointer"); | ||
| 14472 | } | 14823 | } |
| 14473 | return result; | 14824 | return result; |
| 14474 | } else if (array_type->id == ZigTypeIdArray) { | 14825 | } else if (array_type->id == ZigTypeIdArray) { |
| ... | @@ -15155,74 +15506,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -15155,74 +15506,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 15155 | } | 15506 | } |
| 15156 | } | 15507 | } |
| 15157 | 15508 | ||
| 15158 | static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { | 15509 | static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) { |
| 15159 | IrInstruction *ptr = load_ptr_instruction->ptr->child; | 15510 | IrInstruction *ptr = instruction->ptr->child; |
| 15160 | if (type_is_invalid(ptr->value.type)) | ||
| 15161 | return ira->codegen->invalid_instruction; | ||
| 15162 | return ir_get_deref(ira, &load_ptr_instruction->base, ptr); | ||
| 15163 | } | ||
| 15164 | |||
| 15165 | static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { | ||
| 15166 | IrInstruction *ptr = store_ptr_instruction->ptr->child; | ||
| 15167 | if (type_is_invalid(ptr->value.type)) | 15511 | if (type_is_invalid(ptr->value.type)) |
| 15168 | return ira->codegen->invalid_instruction; | 15512 | return ira->codegen->invalid_instruction; |
| 15169 | 15513 | ||
| 15170 | IrInstruction *value = store_ptr_instruction->value->child; | 15514 | IrInstruction *value = instruction->value->child; |
| 15171 | if (type_is_invalid(value->value.type)) | 15515 | if (type_is_invalid(value->value.type)) |
| 15172 | return ira->codegen->invalid_instruction; | 15516 | return ira->codegen->invalid_instruction; |
| 15173 | 15517 | ||
| 15174 | if (ptr->value.type->id != ZigTypeIdPointer) { | 15518 | return ir_analyze_store_ptr(ira, &instruction->base, ptr, value); |
| 15175 | ir_add_error(ira, ptr, | 15519 | } |
| 15176 | buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); | ||
| 15177 | return ira->codegen->invalid_instruction; | ||
| 15178 | } | ||
| 15179 | |||
| 15180 | if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { | ||
| 15181 | return ir_const_void(ira, &store_ptr_instruction->base); | ||
| 15182 | } | ||
| 15183 | |||
| 15184 | if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) { | ||
| 15185 | ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); | ||
| 15186 | return ira->codegen->invalid_instruction; | ||
| 15187 | } | ||
| 15188 | 15520 | ||
| 15189 | ZigType *child_type = ptr->value.type->data.pointer.child_type; | 15521 | static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) { |
| 15190 | IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type); | 15522 | IrInstruction *ptr = instruction->ptr->child; |
| 15191 | if (casted_value == ira->codegen->invalid_instruction) | 15523 | if (type_is_invalid(ptr->value.type)) |
| 15192 | return ira->codegen->invalid_instruction; | 15524 | return ira->codegen->invalid_instruction; |
| 15193 | 15525 | return ir_get_deref(ira, &instruction->base, ptr); | |
| 15194 | if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { | ||
| 15195 | if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { | ||
| 15196 | ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); | ||
| 15197 | return ira->codegen->invalid_instruction; | ||
| 15198 | } | ||
| 15199 | if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { | ||
| 15200 | if (instr_is_comptime(casted_value)) { | ||
| 15201 | ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node); | ||
| 15202 | if (dest_val == nullptr) | ||
| 15203 | return ira->codegen->invalid_instruction; | ||
| 15204 | if (dest_val->special != ConstValSpecialRuntime) { | ||
| 15205 | *dest_val = casted_value->value; | ||
| 15206 | if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { | ||
| 15207 | ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base; | ||
| 15208 | } | ||
| 15209 | return ir_const_void(ira, &store_ptr_instruction->base); | ||
| 15210 | } | ||
| 15211 | } | ||
| 15212 | ir_add_error(ira, &store_ptr_instruction->base, | ||
| 15213 | buf_sprintf("cannot store runtime value in compile time variable")); | ||
| 15214 | ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); | ||
| 15215 | dest_val->type = ira->codegen->builtin_types.entry_invalid; | ||
| 15216 | |||
| 15217 | return ira->codegen->invalid_instruction; | ||
| 15218 | } | ||
| 15219 | } | ||
| 15220 | |||
| 15221 | IrInstruction *result = ir_build_store_ptr(&ira->new_irb, | ||
| 15222 | store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node, | ||
| 15223 | ptr, casted_value); | ||
| 15224 | result->value.type = ira->codegen->builtin_types.entry_void; | ||
| 15225 | return result; | ||
| 15226 | } | 15526 | } |
| 15227 | 15527 | ||
| 15228 | static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { | 15528 | static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { |
| ... | @@ -15230,37 +15530,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio | ... | @@ -15230,37 +15530,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio |
| 15230 | ZigType *type_entry = expr_value->value.type; | 15530 | ZigType *type_entry = expr_value->value.type; |
| 15231 | if (type_is_invalid(type_entry)) | 15531 | if (type_is_invalid(type_entry)) |
| 15232 | return ira->codegen->invalid_instruction; | 15532 | return ira->codegen->invalid_instruction; |
| 15233 | switch (type_entry->id) { | 15533 | return ir_const_type(ira, &typeof_instruction->base, type_entry); |
| 15234 | case ZigTypeIdInvalid: | ||
| 15235 | zig_unreachable(); // handled above | ||
| 15236 | case ZigTypeIdComptimeFloat: | ||
| 15237 | case ZigTypeIdComptimeInt: | ||
| 15238 | case ZigTypeIdUndefined: | ||
| 15239 | case ZigTypeIdNull: | ||
| 15240 | case ZigTypeIdNamespace: | ||
| 15241 | case ZigTypeIdBoundFn: | ||
| 15242 | case ZigTypeIdMetaType: | ||
| 15243 | case ZigTypeIdVoid: | ||
| 15244 | case ZigTypeIdBool: | ||
| 15245 | case ZigTypeIdUnreachable: | ||
| 15246 | case ZigTypeIdInt: | ||
| 15247 | case ZigTypeIdFloat: | ||
| 15248 | case ZigTypeIdPointer: | ||
| 15249 | case ZigTypeIdArray: | ||
| 15250 | case ZigTypeIdStruct: | ||
| 15251 | case ZigTypeIdOptional: | ||
| 15252 | case ZigTypeIdErrorUnion: | ||
| 15253 | case ZigTypeIdErrorSet: | ||
| 15254 | case ZigTypeIdEnum: | ||
| 15255 | case ZigTypeIdUnion: | ||
| 15256 | case ZigTypeIdFn: | ||
| 15257 | case ZigTypeIdArgTuple: | ||
| 15258 | case ZigTypeIdOpaque: | ||
| 15259 | case ZigTypeIdPromise: | ||
| 15260 | return ir_const_type(ira, &typeof_instruction->base, type_entry); | ||
| 15261 | } | ||
| 15262 | |||
| 15263 | zig_unreachable(); | ||
| 15264 | } | 15534 | } |
| 15265 | 15535 | ||
| 15266 | static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, | 15536 | static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| ... | @@ -15499,6 +15769,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -15499,6 +15769,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 15499 | case ZigTypeIdNamespace: | 15769 | case ZigTypeIdNamespace: |
| 15500 | case ZigTypeIdBoundFn: | 15770 | case ZigTypeIdBoundFn: |
| 15501 | case ZigTypeIdPromise: | 15771 | case ZigTypeIdPromise: |
| 15772 | case ZigTypeIdVector: | ||
| 15502 | { | 15773 | { |
| 15503 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) | 15774 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) |
| 15504 | return ira->codegen->invalid_instruction; | 15775 | return ira->codegen->invalid_instruction; |
| ... | @@ -15619,6 +15890,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, | ... | @@ -15619,6 +15890,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 15619 | case ZigTypeIdNamespace: | 15890 | case ZigTypeIdNamespace: |
| 15620 | case ZigTypeIdBoundFn: | 15891 | case ZigTypeIdBoundFn: |
| 15621 | case ZigTypeIdPromise: | 15892 | case ZigTypeIdPromise: |
| 15893 | case ZigTypeIdVector: | ||
| 15622 | { | 15894 | { |
| 15623 | if ((err = ensure_complete_type(ira->codegen, child_type))) | 15895 | if ((err = ensure_complete_type(ira->codegen, child_type))) |
| 15624 | return ira->codegen->invalid_instruction; | 15896 | return ira->codegen->invalid_instruction; |
| ... | @@ -15685,6 +15957,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, | ... | @@ -15685,6 +15957,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 15685 | case ZigTypeIdUnion: | 15957 | case ZigTypeIdUnion: |
| 15686 | case ZigTypeIdFn: | 15958 | case ZigTypeIdFn: |
| 15687 | case ZigTypeIdPromise: | 15959 | case ZigTypeIdPromise: |
| 15960 | case ZigTypeIdVector: | ||
| 15688 | { | 15961 | { |
| 15689 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); | 15962 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| 15690 | return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); | 15963 | return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); |
| ... | @@ -15693,11 +15966,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, | ... | @@ -15693,11 +15966,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 15693 | zig_unreachable(); | 15966 | zig_unreachable(); |
| 15694 | } | 15967 | } |
| 15695 | 15968 | ||
| 15696 | static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { | 15969 | static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { |
| 15697 | IrInstruction *value = instruction->value->child; | ||
| 15698 | if (type_is_invalid(value->value.type)) | ||
| 15699 | return ira->codegen->invalid_instruction; | ||
| 15700 | |||
| 15701 | ZigType *type_entry = value->value.type; | 15970 | ZigType *type_entry = value->value.type; |
| 15702 | 15971 | ||
| 15703 | if (type_entry->id == ZigTypeIdOptional) { | 15972 | if (type_entry->id == ZigTypeIdOptional) { |
| ... | @@ -15706,60 +15975,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns | ... | @@ -15706,60 +15975,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns |
| 15706 | if (!maybe_val) | 15975 | if (!maybe_val) |
| 15707 | return ira->codegen->invalid_instruction; | 15976 | return ira->codegen->invalid_instruction; |
| 15708 | 15977 | ||
| 15709 | return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val)); | 15978 | return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val)); |
| 15710 | } | 15979 | } |
| 15711 | 15980 | ||
| 15712 | IrInstruction *result = ir_build_test_nonnull(&ira->new_irb, | 15981 | IrInstruction *result = ir_build_test_nonnull(&ira->new_irb, |
| 15713 | instruction->base.scope, instruction->base.source_node, value); | 15982 | source_inst->scope, source_inst->source_node, value); |
| 15714 | result->value.type = ira->codegen->builtin_types.entry_bool; | 15983 | result->value.type = ira->codegen->builtin_types.entry_bool; |
| 15715 | return result; | 15984 | return result; |
| 15716 | } else if (type_entry->id == ZigTypeIdNull) { | 15985 | } else if (type_entry->id == ZigTypeIdNull) { |
| 15717 | return ir_const_bool(ira, &instruction->base, false); | 15986 | return ir_const_bool(ira, source_inst, false); |
| 15718 | } else { | 15987 | } else { |
| 15719 | return ir_const_bool(ira, &instruction->base, true); | 15988 | return ir_const_bool(ira, source_inst, true); |
| 15720 | } | 15989 | } |
| 15721 | } | 15990 | } |
| 15722 | 15991 | ||
| 15723 | static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, | 15992 | static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { |
| 15724 | IrInstructionUnwrapOptional *unwrap_maybe_instruction) | 15993 | IrInstruction *value = instruction->value->child; |
| 15725 | { | ||
| 15726 | IrInstruction *value = unwrap_maybe_instruction->value->child; | ||
| 15727 | if (type_is_invalid(value->value.type)) | 15994 | if (type_is_invalid(value->value.type)) |
| 15728 | return ira->codegen->invalid_instruction; | 15995 | return ira->codegen->invalid_instruction; |
| 15729 | 15996 | ||
| 15730 | ZigType *ptr_type = value->value.type; | 15997 | return ir_analyze_test_non_null(ira, &instruction->base, value); |
| 15998 | } | ||
| 15999 | |||
| 16000 | static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 16001 | IrInstruction *base_ptr, bool safety_check_on) | ||
| 16002 | { | ||
| 16003 | ZigType *ptr_type = base_ptr->value.type; | ||
| 15731 | assert(ptr_type->id == ZigTypeIdPointer); | 16004 | assert(ptr_type->id == ZigTypeIdPointer); |
| 15732 | 16005 | ||
| 15733 | ZigType *type_entry = ptr_type->data.pointer.child_type; | 16006 | ZigType *type_entry = ptr_type->data.pointer.child_type; |
| 15734 | if (type_is_invalid(type_entry)) { | 16007 | if (type_is_invalid(type_entry)) |
| 15735 | return ira->codegen->invalid_instruction; | 16008 | return ira->codegen->invalid_instruction; |
| 15736 | } else if (type_entry->id != ZigTypeIdOptional) { | 16009 | |
| 15737 | ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node, | 16010 | if (type_entry->id != ZigTypeIdOptional) { |
| 16011 | ir_add_error_node(ira, base_ptr->source_node, | ||
| 15738 | buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); | 16012 | buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); |
| 15739 | return ira->codegen->invalid_instruction; | 16013 | return ira->codegen->invalid_instruction; |
| 15740 | } | 16014 | } |
| 16015 | |||
| 15741 | ZigType *child_type = type_entry->data.maybe.child_type; | 16016 | ZigType *child_type = type_entry->data.maybe.child_type; |
| 15742 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, | 16017 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 15743 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0); | 16018 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0); |
| 15744 | 16019 | ||
| 15745 | if (instr_is_comptime(value)) { | 16020 | if (instr_is_comptime(base_ptr)) { |
| 15746 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); | 16021 | ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); |
| 15747 | if (!val) | 16022 | if (!val) |
| 15748 | return ira->codegen->invalid_instruction; | 16023 | return ira->codegen->invalid_instruction; |
| 15749 | ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node); | 16024 | ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); |
| 15750 | if (maybe_val == nullptr) | 16025 | if (maybe_val == nullptr) |
| 15751 | return ira->codegen->invalid_instruction; | 16026 | return ira->codegen->invalid_instruction; |
| 15752 | 16027 | ||
| 15753 | if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { | 16028 | if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { |
| 15754 | if (optional_value_is_null(maybe_val)) { | 16029 | if (optional_value_is_null(maybe_val)) { |
| 15755 | ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); | 16030 | ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); |
| 15756 | return ira->codegen->invalid_instruction; | 16031 | return ira->codegen->invalid_instruction; |
| 15757 | } | 16032 | } |
| 15758 | IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type); | 16033 | IrInstruction *result = ir_const(ira, source_instr, result_type); |
| 15759 | ConstExprValue *out_val = &result->value; | 16034 | ConstExprValue *out_val = &result->value; |
| 15760 | out_val->data.x_ptr.special = ConstPtrSpecialRef; | 16035 | out_val->data.x_ptr.special = ConstPtrSpecialRef; |
| 15761 | out_val->data.x_ptr.mut = val->data.x_ptr.mut; | 16036 | out_val->data.x_ptr.mut = val->data.x_ptr.mut; |
| 15762 | if (type_is_codegen_pointer(child_type)) { | 16037 | if (types_have_same_zig_comptime_repr(type_entry, child_type)) { |
| 15763 | out_val->data.x_ptr.data.ref.pointee = maybe_val; | 16038 | out_val->data.x_ptr.data.ref.pointee = maybe_val; |
| 15764 | } else { | 16039 | } else { |
| 15765 | out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; | 16040 | out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; |
| ... | @@ -15768,13 +16043,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, | ... | @@ -15768,13 +16043,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, |
| 15768 | } | 16043 | } |
| 15769 | } | 16044 | } |
| 15770 | 16045 | ||
| 15771 | IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb, | 16046 | IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, |
| 15772 | unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node, | 16047 | source_instr->source_node, base_ptr, safety_check_on); |
| 15773 | value, unwrap_maybe_instruction->safety_check_on); | ||
| 15774 | result->value.type = result_type; | 16048 | result->value.type = result_type; |
| 15775 | return result; | 16049 | return result; |
| 15776 | } | 16050 | } |
| 15777 | 16051 | ||
| 16052 | static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, | ||
| 16053 | IrInstructionOptionalUnwrapPtr *instruction) | ||
| 16054 | { | ||
| 16055 | IrInstruction *base_ptr = instruction->base_ptr->child; | ||
| 16056 | if (type_is_invalid(base_ptr->value.type)) | ||
| 16057 | return ira->codegen->invalid_instruction; | ||
| 16058 | |||
| 16059 | return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); | ||
| 16060 | } | ||
| 16061 | |||
| 15778 | static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) { | 16062 | static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) { |
| 15779 | IrInstruction *value = ctz_instruction->value->child; | 16063 | IrInstruction *value = ctz_instruction->value->child; |
| 15780 | if (type_is_invalid(value->value.type)) { | 16064 | if (type_is_invalid(value->value.type)) { |
| ... | @@ -16075,9 +16359,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -16075,9 +16359,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16075 | return result; | 16359 | return result; |
| 16076 | } | 16360 | } |
| 16077 | 16361 | ||
| 16078 | IrInstruction *result = ir_build_load_ptr(&ira->new_irb, | 16362 | IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); |
| 16079 | switch_target_instruction->base.scope, switch_target_instruction->base.source_node, | ||
| 16080 | target_value_ptr); | ||
| 16081 | result->value.type = target_type; | 16363 | result->value.type = target_type; |
| 16082 | return result; | 16364 | return result; |
| 16083 | } | 16365 | } |
| ... | @@ -16107,8 +16389,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -16107,8 +16389,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16107 | return result; | 16389 | return result; |
| 16108 | } | 16390 | } |
| 16109 | 16391 | ||
| 16110 | IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | 16392 | IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); |
| 16111 | switch_target_instruction->base.source_node, target_value_ptr); | ||
| 16112 | union_value->value.type = target_type; | 16393 | union_value->value.type = target_type; |
| 16113 | 16394 | ||
| 16114 | IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, | 16395 | IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, |
| ... | @@ -16132,8 +16413,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -16132,8 +16413,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16132 | return result; | 16413 | return result; |
| 16133 | } | 16414 | } |
| 16134 | 16415 | ||
| 16135 | IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | 16416 | IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); |
| 16136 | switch_target_instruction->base.source_node, target_value_ptr); | ||
| 16137 | enum_value->value.type = target_type; | 16417 | enum_value->value.type = target_type; |
| 16138 | return enum_value; | 16418 | return enum_value; |
| 16139 | } | 16419 | } |
| ... | @@ -16147,6 +16427,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -16147,6 +16427,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16147 | case ZigTypeIdBoundFn: | 16427 | case ZigTypeIdBoundFn: |
| 16148 | case ZigTypeIdArgTuple: | 16428 | case ZigTypeIdArgTuple: |
| 16149 | case ZigTypeIdOpaque: | 16429 | case ZigTypeIdOpaque: |
| 16430 | case ZigTypeIdVector: | ||
| 16150 | ir_add_error(ira, &switch_target_instruction->base, | 16431 | ir_add_error(ira, &switch_target_instruction->base, |
| 16151 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); | 16432 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); |
| 16152 | return ira->codegen->invalid_instruction; | 16433 | return ira->codegen->invalid_instruction; |
| ... | @@ -16290,7 +16571,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI | ... | @@ -16290,7 +16571,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI |
| 16290 | Error err; | 16571 | Error err; |
| 16291 | assert(container_type->id == ZigTypeIdUnion); | 16572 | assert(container_type->id == ZigTypeIdUnion); |
| 16292 | 16573 | ||
| 16293 | if ((err = ensure_complete_type(ira->codegen, container_type))) | 16574 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) |
| 16294 | return ira->codegen->invalid_instruction; | 16575 | return ira->codegen->invalid_instruction; |
| 16295 | 16576 | ||
| 16296 | if (instr_field_count != 1) { | 16577 | if (instr_field_count != 1) { |
| ... | @@ -16322,7 +16603,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI | ... | @@ -16322,7 +16603,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI |
| 16322 | if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) | 16603 | if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) |
| 16323 | return ira->codegen->invalid_instruction; | 16604 | return ira->codegen->invalid_instruction; |
| 16324 | 16605 | ||
| 16325 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | 16606 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) |
| 16607 | || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; | ||
| 16326 | if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || | 16608 | if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || |
| 16327 | !type_has_bits(casted_field_value->value.type)) | 16609 | !type_has_bits(casted_field_value->value.type)) |
| 16328 | { | 16610 | { |
| ... | @@ -16334,12 +16616,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI | ... | @@ -16334,12 +16616,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI |
| 16334 | ConstExprValue *out_val = &result->value; | 16616 | ConstExprValue *out_val = &result->value; |
| 16335 | out_val->data.x_union.payload = field_val; | 16617 | out_val->data.x_union.payload = field_val; |
| 16336 | out_val->data.x_union.tag = type_field->enum_field->value; | 16618 | out_val->data.x_union.tag = type_field->enum_field->value; |
| 16337 | 16619 | out_val->parent.id = ConstParentIdUnion; | |
| 16338 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); | 16620 | out_val->parent.data.p_union.union_val = out_val; |
| 16339 | if (parent != nullptr) { | ||
| 16340 | parent->id = ConstParentIdUnion; | ||
| 16341 | parent->data.p_union.union_val = out_val; | ||
| 16342 | } | ||
| 16343 | 16621 | ||
| 16344 | return result; | 16622 | return result; |
| 16345 | } | 16623 | } |
| ... | @@ -16366,7 +16644,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc | ... | @@ -16366,7 +16644,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16366 | return ira->codegen->invalid_instruction; | 16644 | return ira->codegen->invalid_instruction; |
| 16367 | } | 16645 | } |
| 16368 | 16646 | ||
| 16369 | if ((err = ensure_complete_type(ira->codegen, container_type))) | 16647 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) |
| 16370 | return ira->codegen->invalid_instruction; | 16648 | return ira->codegen->invalid_instruction; |
| 16371 | 16649 | ||
| 16372 | size_t actual_field_count = container_type->data.structure.src_field_count; | 16650 | size_t actual_field_count = container_type->data.structure.src_field_count; |
| ... | @@ -16377,7 +16655,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc | ... | @@ -16377,7 +16655,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16377 | 16655 | ||
| 16378 | IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); | 16656 | IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); |
| 16379 | 16657 | ||
| 16380 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | 16658 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) |
| 16659 | || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; | ||
| 16381 | 16660 | ||
| 16382 | ConstExprValue const_val = {}; | 16661 | ConstExprValue const_val = {}; |
| 16383 | const_val.special = ConstValSpecialStatic; | 16662 | const_val.special = ConstValSpecialStatic; |
| ... | @@ -16445,9 +16724,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc | ... | @@ -16445,9 +16724,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16445 | if (const_val.special == ConstValSpecialStatic) { | 16724 | if (const_val.special == ConstValSpecialStatic) { |
| 16446 | IrInstruction *result = ir_const(ira, instruction, nullptr); | 16725 | IrInstruction *result = ir_const(ira, instruction, nullptr); |
| 16447 | ConstExprValue *out_val = &result->value; | 16726 | ConstExprValue *out_val = &result->value; |
| 16448 | // TODO copy_const_val? | 16727 | copy_const_val(out_val, &const_val, true); |
| 16449 | *out_val = const_val; | 16728 | out_val->type = container_type; |
| 16450 | result->value.type = container_type; | ||
| 16451 | 16729 | ||
| 16452 | for (size_t i = 0; i < instr_field_count; i += 1) { | 16730 | for (size_t i = 0; i < instr_field_count; i += 1) { |
| 16453 | ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; | 16731 | ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; |
| ... | @@ -16479,127 +16757,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc | ... | @@ -16479,127 +16757,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16479 | static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, | 16757 | static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 16480 | IrInstructionContainerInitList *instruction) | 16758 | IrInstructionContainerInitList *instruction) |
| 16481 | { | 16759 | { |
| 16482 | IrInstruction *container_type_value = instruction->container_type->child; | 16760 | ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); |
| 16483 | if (type_is_invalid(container_type_value->value.type)) | 16761 | if (type_is_invalid(container_type)) |
| 16484 | return ira->codegen->invalid_instruction; | 16762 | return ira->codegen->invalid_instruction; |
| 16485 | 16763 | ||
| 16486 | size_t elem_count = instruction->item_count; | 16764 | size_t elem_count = instruction->item_count; |
| 16487 | if (container_type_value->value.type->id == ZigTypeIdMetaType) { | ||
| 16488 | ZigType *container_type = ir_resolve_type(ira, container_type_value); | ||
| 16489 | if (type_is_invalid(container_type)) | ||
| 16490 | return ira->codegen->invalid_instruction; | ||
| 16491 | 16765 | ||
| 16492 | if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { | 16766 | if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { |
| 16493 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, | 16767 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, |
| 16494 | 0, nullptr); | 16768 | 0, nullptr); |
| 16495 | } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { | 16769 | } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { |
| 16496 | // array is same as slice init but we make a compile error if the length is wrong | 16770 | // array is same as slice init but we make a compile error if the length is wrong |
| 16497 | ZigType *child_type; | 16771 | ZigType *child_type; |
| 16498 | if (container_type->id == ZigTypeIdArray) { | 16772 | if (container_type->id == ZigTypeIdArray) { |
| 16499 | child_type = container_type->data.array.child_type; | 16773 | child_type = container_type->data.array.child_type; |
| 16500 | if (container_type->data.array.len != elem_count) { | 16774 | if (container_type->data.array.len != elem_count) { |
| 16501 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); | 16775 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); |
| 16502 | 16776 | ||
| 16503 | ir_add_error(ira, &instruction->base, | 16777 | ir_add_error(ira, &instruction->base, |
| 16504 | buf_sprintf("expected %s literal, found %s literal", | 16778 | buf_sprintf("expected %s literal, found %s literal", |
| 16505 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); | 16779 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); |
| 16506 | return ira->codegen->invalid_instruction; | 16780 | return ira->codegen->invalid_instruction; |
| 16507 | } | ||
| 16508 | } else { | ||
| 16509 | ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 16510 | assert(pointer_type->id == ZigTypeIdPointer); | ||
| 16511 | child_type = pointer_type->data.pointer.child_type; | ||
| 16512 | } | 16781 | } |
| 16782 | } else { | ||
| 16783 | ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 16784 | assert(pointer_type->id == ZigTypeIdPointer); | ||
| 16785 | child_type = pointer_type->data.pointer.child_type; | ||
| 16786 | } | ||
| 16513 | 16787 | ||
| 16514 | ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); | 16788 | ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); |
| 16515 | 16789 | ||
| 16516 | ConstExprValue const_val = {}; | 16790 | ConstExprValue const_val = {}; |
| 16517 | const_val.special = ConstValSpecialStatic; | 16791 | const_val.special = ConstValSpecialStatic; |
| 16518 | const_val.type = fixed_size_array_type; | 16792 | const_val.type = fixed_size_array_type; |
| 16519 | const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); | 16793 | const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); |
| 16520 | 16794 | ||
| 16521 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); | 16795 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); |
| 16522 | 16796 | ||
| 16523 | IrInstruction **new_items = allocate<IrInstruction *>(elem_count); | 16797 | IrInstruction **new_items = allocate<IrInstruction *>(elem_count); |
| 16524 | 16798 | ||
| 16525 | IrInstruction *first_non_const_instruction = nullptr; | 16799 | IrInstruction *first_non_const_instruction = nullptr; |
| 16526 | 16800 | ||
| 16527 | for (size_t i = 0; i < elem_count; i += 1) { | 16801 | for (size_t i = 0; i < elem_count; i += 1) { |
| 16528 | IrInstruction *arg_value = instruction->items[i]->child; | 16802 | IrInstruction *arg_value = instruction->items[i]->child; |
| 16529 | if (type_is_invalid(arg_value->value.type)) | 16803 | if (type_is_invalid(arg_value->value.type)) |
| 16530 | return ira->codegen->invalid_instruction; | 16804 | return ira->codegen->invalid_instruction; |
| 16531 | 16805 | ||
| 16532 | IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); | 16806 | IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); |
| 16533 | if (casted_arg == ira->codegen->invalid_instruction) | 16807 | if (casted_arg == ira->codegen->invalid_instruction) |
| 16534 | return ira->codegen->invalid_instruction; | 16808 | return ira->codegen->invalid_instruction; |
| 16535 | 16809 | ||
| 16536 | new_items[i] = casted_arg; | 16810 | new_items[i] = casted_arg; |
| 16537 | 16811 | ||
| 16538 | if (const_val.special == ConstValSpecialStatic) { | 16812 | if (const_val.special == ConstValSpecialStatic) { |
| 16539 | if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { | 16813 | if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { |
| 16540 | ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); | 16814 | ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); |
| 16541 | if (!elem_val) | 16815 | if (!elem_val) |
| 16542 | return ira->codegen->invalid_instruction; | 16816 | return ira->codegen->invalid_instruction; |
| 16543 | 16817 | ||
| 16544 | copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); | 16818 | copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); |
| 16545 | } else { | 16819 | } else { |
| 16546 | first_non_const_instruction = casted_arg; | 16820 | first_non_const_instruction = casted_arg; |
| 16547 | const_val.special = ConstValSpecialRuntime; | 16821 | const_val.special = ConstValSpecialRuntime; |
| 16548 | } | ||
| 16549 | } | 16822 | } |
| 16550 | } | 16823 | } |
| 16824 | } | ||
| 16551 | 16825 | ||
| 16552 | if (const_val.special == ConstValSpecialStatic) { | 16826 | if (const_val.special == ConstValSpecialStatic) { |
| 16553 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); | 16827 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); |
| 16554 | ConstExprValue *out_val = &result->value; | 16828 | ConstExprValue *out_val = &result->value; |
| 16555 | // TODO copy_const_val? | 16829 | copy_const_val(out_val, &const_val, true); |
| 16556 | *out_val = const_val; | 16830 | result->value.type = fixed_size_array_type; |
| 16557 | result->value.type = fixed_size_array_type; | 16831 | for (size_t i = 0; i < elem_count; i += 1) { |
| 16558 | for (size_t i = 0; i < elem_count; i += 1) { | 16832 | ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; |
| 16559 | ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; | 16833 | ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); |
| 16560 | ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); | 16834 | if (parent != nullptr) { |
| 16561 | if (parent != nullptr) { | 16835 | parent->id = ConstParentIdArray; |
| 16562 | parent->id = ConstParentIdArray; | 16836 | parent->data.p_array.array_val = out_val; |
| 16563 | parent->data.p_array.array_val = out_val; | 16837 | parent->data.p_array.elem_index = i; |
| 16564 | parent->data.p_array.elem_index = i; | ||
| 16565 | } | ||
| 16566 | } | 16838 | } |
| 16567 | return result; | ||
| 16568 | } | 16839 | } |
| 16840 | return result; | ||
| 16841 | } | ||
| 16569 | 16842 | ||
| 16570 | if (is_comptime) { | 16843 | if (is_comptime) { |
| 16571 | ir_add_error_node(ira, first_non_const_instruction->source_node, | 16844 | ir_add_error_node(ira, first_non_const_instruction->source_node, |
| 16572 | buf_sprintf("unable to evaluate constant expression")); | 16845 | buf_sprintf("unable to evaluate constant expression")); |
| 16573 | return ira->codegen->invalid_instruction; | 16846 | return ira->codegen->invalid_instruction; |
| 16574 | } | 16847 | } |
| 16575 | 16848 | ||
| 16576 | IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, | 16849 | IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, |
| 16577 | instruction->base.scope, instruction->base.source_node, | 16850 | instruction->base.scope, instruction->base.source_node, |
| 16578 | container_type_value, elem_count, new_items); | 16851 | nullptr, elem_count, new_items); |
| 16579 | new_instruction->value.type = fixed_size_array_type; | 16852 | new_instruction->value.type = fixed_size_array_type; |
| 16580 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); | 16853 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); |
| 16581 | return new_instruction; | 16854 | return new_instruction; |
| 16582 | } else if (container_type->id == ZigTypeIdVoid) { | 16855 | } else if (container_type->id == ZigTypeIdVoid) { |
| 16583 | if (elem_count != 0) { | 16856 | if (elem_count != 0) { |
| 16584 | ir_add_error_node(ira, instruction->base.source_node, | ||
| 16585 | buf_sprintf("void expression expects no arguments")); | ||
| 16586 | return ira->codegen->invalid_instruction; | ||
| 16587 | } | ||
| 16588 | return ir_const_void(ira, &instruction->base); | ||
| 16589 | } else { | ||
| 16590 | ir_add_error_node(ira, instruction->base.source_node, | 16857 | ir_add_error_node(ira, instruction->base.source_node, |
| 16591 | buf_sprintf("type '%s' does not support array initialization", | 16858 | buf_sprintf("void expression expects no arguments")); |
| 16592 | buf_ptr(&container_type->name))); | ||
| 16593 | return ira->codegen->invalid_instruction; | 16859 | return ira->codegen->invalid_instruction; |
| 16594 | } | 16860 | } |
| 16861 | return ir_const_void(ira, &instruction->base); | ||
| 16595 | } else { | 16862 | } else { |
| 16596 | ir_add_error(ira, container_type_value, | 16863 | ir_add_error_node(ira, instruction->base.source_node, |
| 16597 | buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name))); | 16864 | buf_sprintf("type '%s' does not support array initialization", |
| 16865 | buf_ptr(&container_type->name))); | ||
| 16598 | return ira->codegen->invalid_instruction; | 16866 | return ira->codegen->invalid_instruction; |
| 16599 | } | 16867 | } |
| 16600 | } | 16868 | } |
| 16601 | 16869 | ||
| 16602 | static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { | 16870 | static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, |
| 16871 | IrInstructionContainerInitFields *instruction) | ||
| 16872 | { | ||
| 16603 | IrInstruction *container_type_value = instruction->container_type->child; | 16873 | IrInstruction *container_type_value = instruction->container_type->child; |
| 16604 | ZigType *container_type = ir_resolve_type(ira, container_type_value); | 16874 | ZigType *container_type = ir_resolve_type(ira, container_type_value); |
| 16605 | if (type_is_invalid(container_type)) | 16875 | if (type_is_invalid(container_type)) |
| ... | @@ -16659,7 +16929,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct | ... | @@ -16659,7 +16929,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct |
| 16659 | if (type_is_invalid(value->value.type)) | 16929 | if (type_is_invalid(value->value.type)) |
| 16660 | return ira->codegen->invalid_instruction; | 16930 | return ira->codegen->invalid_instruction; |
| 16661 | 16931 | ||
| 16662 | IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type); | 16932 | IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set); |
| 16663 | if (type_is_invalid(casted_value->value.type)) | 16933 | if (type_is_invalid(casted_value->value.type)) |
| 16664 | return ira->codegen->invalid_instruction; | 16934 | return ira->codegen->invalid_instruction; |
| 16665 | 16935 | ||
| ... | @@ -16920,10 +17190,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig | ... | @@ -16920,10 +17190,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig |
| 16920 | 17190 | ||
| 16921 | ZigVar *var = tld->var; | 17191 | ZigVar *var = tld->var; |
| 16922 | 17192 | ||
| 16923 | if ((err = ensure_complete_type(ira->codegen, var->value->type))) | 17193 | if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) |
| 16924 | return ira->codegen->builtin_types.entry_invalid; | 17194 | return ira->codegen->builtin_types.entry_invalid; |
| 16925 | assert(var->value->type->id == ZigTypeIdMetaType); | 17195 | |
| 16926 | return var->value->data.x_type; | 17196 | assert(var->const_value->type->id == ZigTypeIdMetaType); |
| 17197 | return var->const_value->data.x_type; | ||
| 16927 | } | 17198 | } |
| 16928 | 17199 | ||
| 16929 | static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) { | 17200 | static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) { |
| ... | @@ -16978,7 +17249,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco | ... | @@ -16978,7 +17249,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco |
| 16978 | definition_array->special = ConstValSpecialStatic; | 17249 | definition_array->special = ConstValSpecialStatic; |
| 16979 | definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); | 17250 | definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); |
| 16980 | definition_array->data.x_array.special = ConstArraySpecialNone; | 17251 | definition_array->data.x_array.special = ConstArraySpecialNone; |
| 16981 | definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 16982 | definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); | 17252 | definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); |
| 16983 | init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); | 17253 | init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); |
| 16984 | 17254 | ||
| ... | @@ -17009,33 +17279,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco | ... | @@ -17009,33 +17279,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco |
| 17009 | inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; | 17279 | inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; |
| 17010 | inner_fields[2].special = ConstValSpecialStatic; | 17280 | inner_fields[2].special = ConstValSpecialStatic; |
| 17011 | inner_fields[2].type = type_info_definition_data_type; | 17281 | inner_fields[2].type = type_info_definition_data_type; |
| 17012 | inner_fields[2].data.x_union.parent.id = ConstParentIdStruct; | 17282 | inner_fields[2].parent.id = ConstParentIdStruct; |
| 17013 | inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; | 17283 | inner_fields[2].parent.data.p_struct.struct_val = definition_val; |
| 17014 | inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; | 17284 | inner_fields[2].parent.data.p_struct.field_index = 1; |
| 17015 | 17285 | ||
| 17016 | switch (curr_entry->value->id) { | 17286 | switch (curr_entry->value->id) { |
| 17017 | case TldIdVar: | 17287 | case TldIdVar: |
| 17018 | { | 17288 | { |
| 17019 | ZigVar *var = ((TldVar *)curr_entry->value)->var; | 17289 | ZigVar *var = ((TldVar *)curr_entry->value)->var; |
| 17020 | if ((err = ensure_complete_type(ira->codegen, var->value->type))) | 17290 | if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) |
| 17021 | return ErrorSemanticAnalyzeFail; | 17291 | return ErrorSemanticAnalyzeFail; |
| 17022 | 17292 | ||
| 17023 | if (var->value->type->id == ZigTypeIdMetaType) | 17293 | if (var->const_value->type->id == ZigTypeIdMetaType) { |
| 17024 | { | ||
| 17025 | // We have a variable of type 'type', so it's actually a type definition. | 17294 | // We have a variable of type 'type', so it's actually a type definition. |
| 17026 | // 0: Data.Type: type | 17295 | // 0: Data.Type: type |
| 17027 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); | 17296 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); |
| 17028 | inner_fields[2].data.x_union.payload = var->value; | 17297 | inner_fields[2].data.x_union.payload = var->const_value; |
| 17029 | } | 17298 | } else { |
| 17030 | else | ||
| 17031 | { | ||
| 17032 | // We have a variable of another type, so we store the type of the variable. | 17299 | // We have a variable of another type, so we store the type of the variable. |
| 17033 | // 1: Data.Var: type | 17300 | // 1: Data.Var: type |
| 17034 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); | 17301 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); |
| 17035 | 17302 | ||
| 17036 | ConstExprValue *payload = create_const_vals(1); | 17303 | ConstExprValue *payload = create_const_vals(1); |
| 17037 | payload->type = ira->codegen->builtin_types.entry_type; | 17304 | payload->type = ira->codegen->builtin_types.entry_type; |
| 17038 | payload->data.x_type = var->value->type; | 17305 | payload->data.x_type = var->const_value->type; |
| 17039 | 17306 | ||
| 17040 | inner_fields[2].data.x_union.payload = payload; | 17307 | inner_fields[2].data.x_union.payload = payload; |
| 17041 | } | 17308 | } |
| ... | @@ -17055,8 +17322,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco | ... | @@ -17055,8 +17322,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco |
| 17055 | ConstExprValue *fn_def_val = create_const_vals(1); | 17322 | ConstExprValue *fn_def_val = create_const_vals(1); |
| 17056 | fn_def_val->special = ConstValSpecialStatic; | 17323 | fn_def_val->special = ConstValSpecialStatic; |
| 17057 | fn_def_val->type = type_info_fn_def_type; | 17324 | fn_def_val->type = type_info_fn_def_type; |
| 17058 | fn_def_val->data.x_struct.parent.id = ConstParentIdUnion; | 17325 | fn_def_val->parent.id = ConstParentIdUnion; |
| 17059 | fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2]; | 17326 | fn_def_val->parent.data.p_union.union_val = &inner_fields[2]; |
| 17060 | 17327 | ||
| 17061 | ConstExprValue *fn_def_fields = create_const_vals(9); | 17328 | ConstExprValue *fn_def_fields = create_const_vals(9); |
| 17062 | fn_def_val->data.x_struct.fields = fn_def_fields; | 17329 | fn_def_val->data.x_struct.fields = fn_def_fields; |
| ... | @@ -17120,20 +17387,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco | ... | @@ -17120,20 +17387,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco |
| 17120 | fn_arg_name_array->type = get_array_type(ira->codegen, | 17387 | fn_arg_name_array->type = get_array_type(ira->codegen, |
| 17121 | get_slice_type(ira->codegen, u8_ptr), fn_arg_count); | 17388 | get_slice_type(ira->codegen, u8_ptr), fn_arg_count); |
| 17122 | fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; | 17389 | fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; |
| 17123 | fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17124 | fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); | 17390 | fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); |
| 17125 | 17391 | ||
| 17126 | init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); | 17392 | init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); |
| 17127 | 17393 | ||
| 17128 | for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) | 17394 | for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { |
| 17129 | { | ||
| 17130 | ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); | 17395 | ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); |
| 17131 | ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; | 17396 | ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; |
| 17132 | ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); | 17397 | ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); |
| 17133 | init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true); | 17398 | init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true); |
| 17134 | fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray; | 17399 | fn_arg_name_val->parent.id = ConstParentIdArray; |
| 17135 | fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array; | 17400 | fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array; |
| 17136 | fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; | 17401 | fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index; |
| 17137 | } | 17402 | } |
| 17138 | 17403 | ||
| 17139 | inner_fields[2].data.x_union.payload = fn_def_val; | 17404 | inner_fields[2].data.x_union.payload = fn_def_val; |
| ... | @@ -17354,6 +17619,27 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17354,6 +17619,27 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17354 | 17619 | ||
| 17355 | break; | 17620 | break; |
| 17356 | } | 17621 | } |
| 17622 | case ZigTypeIdVector: { | ||
| 17623 | result = create_const_vals(1); | ||
| 17624 | result->special = ConstValSpecialStatic; | ||
| 17625 | result->type = ir_type_info_get_type(ira, "Vector", nullptr); | ||
| 17626 | |||
| 17627 | ConstExprValue *fields = create_const_vals(2); | ||
| 17628 | result->data.x_struct.fields = fields; | ||
| 17629 | |||
| 17630 | // len: usize | ||
| 17631 | ensure_field_index(result->type, "len", 0); | ||
| 17632 | fields[0].special = ConstValSpecialStatic; | ||
| 17633 | fields[0].type = ira->codegen->builtin_types.entry_u32; | ||
| 17634 | bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len); | ||
| 17635 | // child: type | ||
| 17636 | ensure_field_index(result->type, "child", 1); | ||
| 17637 | fields[1].special = ConstValSpecialStatic; | ||
| 17638 | fields[1].type = ira->codegen->builtin_types.entry_type; | ||
| 17639 | fields[1].data.x_type = type_entry->data.vector.elem_type; | ||
| 17640 | |||
| 17641 | break; | ||
| 17642 | } | ||
| 17357 | case ZigTypeIdOptional: | 17643 | case ZigTypeIdOptional: |
| 17358 | { | 17644 | { |
| 17359 | result = create_const_vals(1); | 17645 | result = create_const_vals(1); |
| ... | @@ -17426,7 +17712,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17426,7 +17712,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17426 | enum_field_array->special = ConstValSpecialStatic; | 17712 | enum_field_array->special = ConstValSpecialStatic; |
| 17427 | enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); | 17713 | enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); |
| 17428 | enum_field_array->data.x_array.special = ConstArraySpecialNone; | 17714 | enum_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17429 | enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17430 | enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); | 17715 | enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); |
| 17431 | 17716 | ||
| 17432 | init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false); | 17717 | init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false); |
| ... | @@ -17436,9 +17721,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17436,9 +17721,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17436 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; | 17721 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; |
| 17437 | ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; | 17722 | ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; |
| 17438 | make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); | 17723 | make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); |
| 17439 | enum_field_val->data.x_struct.parent.id = ConstParentIdArray; | 17724 | enum_field_val->parent.id = ConstParentIdArray; |
| 17440 | enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array; | 17725 | enum_field_val->parent.data.p_array.array_val = enum_field_array; |
| 17441 | enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index; | 17726 | enum_field_val->parent.data.p_array.elem_index = enum_field_index; |
| 17442 | } | 17727 | } |
| 17443 | // defs: []TypeInfo.Definition | 17728 | // defs: []TypeInfo.Definition |
| 17444 | ensure_field_index(result->type, "defs", 3); | 17729 | ensure_field_index(result->type, "defs", 3); |
| ... | @@ -17465,7 +17750,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17465,7 +17750,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17465 | error_array->special = ConstValSpecialStatic; | 17750 | error_array->special = ConstValSpecialStatic; |
| 17466 | error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); | 17751 | error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); |
| 17467 | error_array->data.x_array.special = ConstArraySpecialNone; | 17752 | error_array->data.x_array.special = ConstArraySpecialNone; |
| 17468 | error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17469 | error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); | 17753 | error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); |
| 17470 | 17754 | ||
| 17471 | init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); | 17755 | init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); |
| ... | @@ -17489,9 +17773,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17489,9 +17773,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17489 | bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); | 17773 | bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); |
| 17490 | 17774 | ||
| 17491 | error_val->data.x_struct.fields = inner_fields; | 17775 | error_val->data.x_struct.fields = inner_fields; |
| 17492 | error_val->data.x_struct.parent.id = ConstParentIdArray; | 17776 | error_val->parent.id = ConstParentIdArray; |
| 17493 | error_val->data.x_struct.parent.data.p_array.array_val = error_array; | 17777 | error_val->parent.data.p_array.array_val = error_array; |
| 17494 | error_val->data.x_struct.parent.data.p_array.elem_index = error_index; | 17778 | error_val->parent.data.p_array.elem_index = error_index; |
| 17495 | } | 17779 | } |
| 17496 | 17780 | ||
| 17497 | break; | 17781 | break; |
| ... | @@ -17560,7 +17844,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17560,7 +17844,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17560 | union_field_array->special = ConstValSpecialStatic; | 17844 | union_field_array->special = ConstValSpecialStatic; |
| 17561 | union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); | 17845 | union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); |
| 17562 | union_field_array->data.x_array.special = ConstArraySpecialNone; | 17846 | union_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17563 | union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17564 | union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); | 17847 | union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); |
| 17565 | 17848 | ||
| 17566 | init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); | 17849 | init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); |
| ... | @@ -17593,9 +17876,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17593,9 +17876,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17593 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); | 17876 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); |
| 17594 | 17877 | ||
| 17595 | union_field_val->data.x_struct.fields = inner_fields; | 17878 | union_field_val->data.x_struct.fields = inner_fields; |
| 17596 | union_field_val->data.x_struct.parent.id = ConstParentIdArray; | 17879 | union_field_val->parent.id = ConstParentIdArray; |
| 17597 | union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array; | 17880 | union_field_val->parent.data.p_array.array_val = union_field_array; |
| 17598 | union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index; | 17881 | union_field_val->parent.data.p_array.elem_index = union_field_index; |
| 17599 | } | 17882 | } |
| 17600 | // defs: []TypeInfo.Definition | 17883 | // defs: []TypeInfo.Definition |
| 17601 | ensure_field_index(result->type, "defs", 3); | 17884 | ensure_field_index(result->type, "defs", 3); |
| ... | @@ -17635,7 +17918,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17635,7 +17918,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17635 | struct_field_array->special = ConstValSpecialStatic; | 17918 | struct_field_array->special = ConstValSpecialStatic; |
| 17636 | struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); | 17919 | struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); |
| 17637 | struct_field_array->data.x_array.special = ConstArraySpecialNone; | 17920 | struct_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17638 | struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17639 | struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); | 17921 | struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); |
| 17640 | 17922 | ||
| 17641 | init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); | 17923 | init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); |
| ... | @@ -17669,9 +17951,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17669,9 +17951,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17669 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); | 17951 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); |
| 17670 | 17952 | ||
| 17671 | struct_field_val->data.x_struct.fields = inner_fields; | 17953 | struct_field_val->data.x_struct.fields = inner_fields; |
| 17672 | struct_field_val->data.x_struct.parent.id = ConstParentIdArray; | 17954 | struct_field_val->parent.id = ConstParentIdArray; |
| 17673 | struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array; | 17955 | struct_field_val->parent.data.p_array.array_val = struct_field_array; |
| 17674 | struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index; | 17956 | struct_field_val->parent.data.p_array.elem_index = struct_field_index; |
| 17675 | } | 17957 | } |
| 17676 | // defs: []TypeInfo.Definition | 17958 | // defs: []TypeInfo.Definition |
| 17677 | ensure_field_index(result->type, "defs", 2); | 17959 | ensure_field_index(result->type, "defs", 2); |
| ... | @@ -17741,7 +18023,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17741,7 +18023,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17741 | fn_arg_array->special = ConstValSpecialStatic; | 18023 | fn_arg_array->special = ConstValSpecialStatic; |
| 17742 | fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); | 18024 | fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); |
| 17743 | fn_arg_array->data.x_array.special = ConstArraySpecialNone; | 18025 | fn_arg_array->data.x_array.special = ConstArraySpecialNone; |
| 17744 | fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | ||
| 17745 | fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); | 18026 | fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); |
| 17746 | 18027 | ||
| 17747 | init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false); | 18028 | init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false); |
| ... | @@ -17778,9 +18059,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE | ... | @@ -17778,9 +18059,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17778 | } | 18059 | } |
| 17779 | 18060 | ||
| 17780 | fn_arg_val->data.x_struct.fields = inner_fields; | 18061 | fn_arg_val->data.x_struct.fields = inner_fields; |
| 17781 | fn_arg_val->data.x_struct.parent.id = ConstParentIdArray; | 18062 | fn_arg_val->parent.id = ConstParentIdArray; |
| 17782 | fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array; | 18063 | fn_arg_val->parent.data.p_array.array_val = fn_arg_array; |
| 17783 | fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; | 18064 | fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; |
| 17784 | } | 18065 | } |
| 17785 | 18066 | ||
| 17786 | break; | 18067 | break; |
| ... | @@ -17824,8 +18105,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, | ... | @@ -17824,8 +18105,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, |
| 17824 | 18105 | ||
| 17825 | if (payload != nullptr) { | 18106 | if (payload != nullptr) { |
| 17826 | assert(payload->type->id == ZigTypeIdStruct); | 18107 | assert(payload->type->id == ZigTypeIdStruct); |
| 17827 | payload->data.x_struct.parent.id = ConstParentIdUnion; | 18108 | payload->parent.id = ConstParentIdUnion; |
| 17828 | payload->data.x_struct.parent.data.p_union.union_val = out_val; | 18109 | payload->parent.data.p_union.union_val = out_val; |
| 17829 | } | 18110 | } |
| 17830 | 18111 | ||
| 17831 | return result; | 18112 | return result; |
| ... | @@ -17897,10 +18178,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct | ... | @@ -17897,10 +18178,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct |
| 17897 | 18178 | ||
| 17898 | // Execute the C import block like an inline function | 18179 | // Execute the C import block like an inline function |
| 17899 | ZigType *void_type = ira->codegen->builtin_types.entry_void; | 18180 | ZigType *void_type = ira->codegen->builtin_types.entry_void; |
| 17900 | IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, | 18181 | ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, |
| 17901 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, | 18182 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, |
| 17902 | &cimport_scope->buf, block_node, nullptr, nullptr); | 18183 | &cimport_scope->buf, block_node, nullptr, nullptr); |
| 17903 | if (type_is_invalid(cimport_result->value.type)) | 18184 | if (type_is_invalid(cimport_result->type)) |
| 17904 | return ira->codegen->invalid_instruction; | 18185 | return ira->codegen->invalid_instruction; |
| 17905 | 18186 | ||
| 17906 | find_libc_include_path(ira->codegen); | 18187 | find_libc_include_path(ira->codegen); |
| ... | @@ -18050,7 +18331,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru | ... | @@ -18050,7 +18331,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru |
| 18050 | return result; | 18331 | return result; |
| 18051 | } | 18332 | } |
| 18052 | 18333 | ||
| 18053 | static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { | 18334 | static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) { |
| 18054 | ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); | 18335 | ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); |
| 18055 | if (type_is_invalid(operand_type)) | 18336 | if (type_is_invalid(operand_type)) |
| 18056 | return ira->codegen->invalid_instruction; | 18337 | return ira->codegen->invalid_instruction; |
| ... | @@ -18122,9 +18403,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi | ... | @@ -18122,9 +18403,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi |
| 18122 | zig_panic("TODO compile-time execution of cmpxchg"); | 18403 | zig_panic("TODO compile-time execution of cmpxchg"); |
| 18123 | } | 18404 | } |
| 18124 | 18405 | ||
| 18125 | IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node, | 18406 | IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, |
| 18126 | nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak, | 18407 | casted_ptr, casted_cmp_value, casted_new_value, |
| 18127 | operand_type, success_order, failure_order); | 18408 | success_order, failure_order, instruction->is_weak); |
| 18128 | result->value.type = get_optional_type(ira->codegen, operand_type); | 18409 | result->value.type = get_optional_type(ira->codegen, operand_type); |
| 18129 | ir_add_alloca(ira, result, result->value.type); | 18410 | ir_add_alloca(ira, result, result->value.type); |
| 18130 | return result; | 18411 | return result; |
| ... | @@ -18296,18 +18577,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst | ... | @@ -18296,18 +18577,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst |
| 18296 | return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type); | 18577 | return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type); |
| 18297 | } | 18578 | } |
| 18298 | 18579 | ||
| 18299 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { | ||
| 18300 | Error err; | ||
| 18301 | |||
| 18302 | if (ty->id == ZigTypeIdPointer) { | ||
| 18303 | if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown))) | ||
| 18304 | return err; | ||
| 18305 | } | ||
| 18306 | |||
| 18307 | *result_align = get_ptr_align(ira->codegen, ty); | ||
| 18308 | return ErrorNone; | ||
| 18309 | } | ||
| 18310 | |||
| 18311 | static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { | 18580 | static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { |
| 18312 | Error err; | 18581 | Error err; |
| 18313 | 18582 | ||
| ... | @@ -18426,6 +18695,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct | ... | @@ -18426,6 +18695,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct |
| 18426 | return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); | 18695 | return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); |
| 18427 | } | 18696 | } |
| 18428 | 18697 | ||
| 18698 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { | ||
| 18699 | Error err; | ||
| 18700 | |||
| 18701 | ZigType *ptr_type = get_src_ptr_type(ty); | ||
| 18702 | assert(ptr_type != nullptr); | ||
| 18703 | if (ptr_type->id == ZigTypeIdPointer) { | ||
| 18704 | if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) | ||
| 18705 | return err; | ||
| 18706 | } | ||
| 18707 | |||
| 18708 | *result_align = get_ptr_align(ira->codegen, ty); | ||
| 18709 | return ErrorNone; | ||
| 18710 | } | ||
| 18711 | |||
| 18429 | static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { | 18712 | static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { |
| 18430 | ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); | 18713 | ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); |
| 18431 | if (type_is_invalid(dest_type)) | 18714 | if (type_is_invalid(dest_type)) |
| ... | @@ -18532,6 +18815,27 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct | ... | @@ -18532,6 +18815,27 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct |
| 18532 | return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count)); | 18815 | return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count)); |
| 18533 | } | 18816 | } |
| 18534 | 18817 | ||
| 18818 | static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstructionVectorType *instruction) { | ||
| 18819 | uint64_t len; | ||
| 18820 | if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) | ||
| 18821 | return ira->codegen->invalid_instruction; | ||
| 18822 | |||
| 18823 | ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); | ||
| 18824 | if (type_is_invalid(elem_type)) | ||
| 18825 | return ira->codegen->invalid_instruction; | ||
| 18826 | |||
| 18827 | if (!is_valid_vector_elem_type(elem_type)) { | ||
| 18828 | ir_add_error(ira, instruction->elem_type, | ||
| 18829 | buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", | ||
| 18830 | buf_ptr(&elem_type->name))); | ||
| 18831 | return ira->codegen->invalid_instruction; | ||
| 18832 | } | ||
| 18833 | |||
| 18834 | ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); | ||
| 18835 | |||
| 18836 | return ir_const_type(ira, &instruction->base, vector_type); | ||
| 18837 | } | ||
| 18838 | |||
| 18535 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { | 18839 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| 18536 | IrInstruction *value = instruction->value->child; | 18840 | IrInstruction *value = instruction->value->child; |
| 18537 | if (type_is_invalid(value->value.type)) | 18841 | if (type_is_invalid(value->value.type)) |
| ... | @@ -18630,10 +18934,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio | ... | @@ -18630,10 +18934,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio |
| 18630 | } | 18934 | } |
| 18631 | case ConstPtrSpecialBaseStruct: | 18935 | case ConstPtrSpecialBaseStruct: |
| 18632 | zig_panic("TODO memset on const inner struct"); | 18936 | zig_panic("TODO memset on const inner struct"); |
| 18937 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 18938 | zig_panic("TODO memset on const inner error union code"); | ||
| 18939 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 18940 | zig_panic("TODO memset on const inner error union payload"); | ||
| 18941 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 18942 | zig_panic("TODO memset on const inner optional payload"); | ||
| 18633 | case ConstPtrSpecialHardCodedAddr: | 18943 | case ConstPtrSpecialHardCodedAddr: |
| 18634 | zig_unreachable(); | 18944 | zig_unreachable(); |
| 18635 | case ConstPtrSpecialFunction: | 18945 | case ConstPtrSpecialFunction: |
| 18636 | zig_panic("TODO memset on ptr cast from function"); | 18946 | zig_panic("TODO memset on ptr cast from function"); |
| 18947 | case ConstPtrSpecialNull: | ||
| 18948 | zig_panic("TODO memset on null ptr"); | ||
| 18637 | } | 18949 | } |
| 18638 | 18950 | ||
| 18639 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | 18951 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); |
| ... | @@ -18745,10 +19057,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio | ... | @@ -18745,10 +19057,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 18745 | } | 19057 | } |
| 18746 | case ConstPtrSpecialBaseStruct: | 19058 | case ConstPtrSpecialBaseStruct: |
| 18747 | zig_panic("TODO memcpy on const inner struct"); | 19059 | zig_panic("TODO memcpy on const inner struct"); |
| 19060 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 19061 | zig_panic("TODO memcpy on const inner error union code"); | ||
| 19062 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 19063 | zig_panic("TODO memcpy on const inner error union payload"); | ||
| 19064 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 19065 | zig_panic("TODO memcpy on const inner optional payload"); | ||
| 18748 | case ConstPtrSpecialHardCodedAddr: | 19066 | case ConstPtrSpecialHardCodedAddr: |
| 18749 | zig_unreachable(); | 19067 | zig_unreachable(); |
| 18750 | case ConstPtrSpecialFunction: | 19068 | case ConstPtrSpecialFunction: |
| 18751 | zig_panic("TODO memcpy on ptr cast from function"); | 19069 | zig_panic("TODO memcpy on ptr cast from function"); |
| 19070 | case ConstPtrSpecialNull: | ||
| 19071 | zig_panic("TODO memcpy on null ptr"); | ||
| 18752 | } | 19072 | } |
| 18753 | 19073 | ||
| 18754 | if (dest_start + count > dest_end) { | 19074 | if (dest_start + count > dest_end) { |
| ... | @@ -18781,10 +19101,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio | ... | @@ -18781,10 +19101,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 18781 | } | 19101 | } |
| 18782 | case ConstPtrSpecialBaseStruct: | 19102 | case ConstPtrSpecialBaseStruct: |
| 18783 | zig_panic("TODO memcpy on const inner struct"); | 19103 | zig_panic("TODO memcpy on const inner struct"); |
| 19104 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 19105 | zig_panic("TODO memcpy on const inner error union code"); | ||
| 19106 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 19107 | zig_panic("TODO memcpy on const inner error union payload"); | ||
| 19108 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 19109 | zig_panic("TODO memcpy on const inner optional payload"); | ||
| 18784 | case ConstPtrSpecialHardCodedAddr: | 19110 | case ConstPtrSpecialHardCodedAddr: |
| 18785 | zig_unreachable(); | 19111 | zig_unreachable(); |
| 18786 | case ConstPtrSpecialFunction: | 19112 | case ConstPtrSpecialFunction: |
| 18787 | zig_panic("TODO memcpy on ptr cast from function"); | 19113 | zig_panic("TODO memcpy on ptr cast from function"); |
| 19114 | case ConstPtrSpecialNull: | ||
| 19115 | zig_panic("TODO memcpy on null ptr"); | ||
| 18788 | } | 19116 | } |
| 18789 | 19117 | ||
| 18790 | if (src_start + count > src_end) { | 19118 | if (src_start + count > src_end) { |
| ... | @@ -18812,9 +19140,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18812,9 +19140,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18812 | if (type_is_invalid(ptr_ptr->value.type)) | 19140 | if (type_is_invalid(ptr_ptr->value.type)) |
| 18813 | return ira->codegen->invalid_instruction; | 19141 | return ira->codegen->invalid_instruction; |
| 18814 | 19142 | ||
| 18815 | ZigType *ptr_type = ptr_ptr->value.type; | 19143 | ZigType *ptr_ptr_type = ptr_ptr->value.type; |
| 18816 | assert(ptr_type->id == ZigTypeIdPointer); | 19144 | assert(ptr_ptr_type->id == ZigTypeIdPointer); |
| 18817 | ZigType *array_type = ptr_type->data.pointer.child_type; | 19145 | ZigType *array_type = ptr_ptr_type->data.pointer.child_type; |
| 18818 | 19146 | ||
| 18819 | IrInstruction *start = instruction->start->child; | 19147 | IrInstruction *start = instruction->start->child; |
| 18820 | if (type_is_invalid(start->value.type)) | 19148 | if (type_is_invalid(start->value.type)) |
| ... | @@ -18843,10 +19171,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18843,10 +19171,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18843 | bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && | 19171 | bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && |
| 18844 | ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; | 19172 | ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; |
| 18845 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, | 19173 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, |
| 18846 | ptr_type->data.pointer.is_const || is_comptime_const, | 19174 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, |
| 18847 | ptr_type->data.pointer.is_volatile, | 19175 | ptr_ptr_type->data.pointer.is_volatile, |
| 18848 | PtrLenUnknown, | 19176 | PtrLenUnknown, |
| 18849 | ptr_type->data.pointer.explicit_alignment, 0, 0); | 19177 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0); |
| 18850 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | 19178 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 18851 | } else if (array_type->id == ZigTypeIdPointer) { | 19179 | } else if (array_type->id == ZigTypeIdPointer) { |
| 18852 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { | 19180 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| ... | @@ -18944,6 +19272,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18944,6 +19272,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18944 | break; | 19272 | break; |
| 18945 | case ConstPtrSpecialBaseStruct: | 19273 | case ConstPtrSpecialBaseStruct: |
| 18946 | zig_panic("TODO slice const inner struct"); | 19274 | zig_panic("TODO slice const inner struct"); |
| 19275 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 19276 | zig_panic("TODO slice const inner error union code"); | ||
| 19277 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 19278 | zig_panic("TODO slice const inner error union payload"); | ||
| 19279 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 19280 | zig_panic("TODO slice const inner optional payload"); | ||
| 18947 | case ConstPtrSpecialHardCodedAddr: | 19281 | case ConstPtrSpecialHardCodedAddr: |
| 18948 | array_val = nullptr; | 19282 | array_val = nullptr; |
| 18949 | abs_offset = 0; | 19283 | abs_offset = 0; |
| ... | @@ -18951,6 +19285,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18951,6 +19285,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18951 | break; | 19285 | break; |
| 18952 | case ConstPtrSpecialFunction: | 19286 | case ConstPtrSpecialFunction: |
| 18953 | zig_panic("TODO slice of ptr cast from function"); | 19287 | zig_panic("TODO slice of ptr cast from function"); |
| 19288 | case ConstPtrSpecialNull: | ||
| 19289 | zig_panic("TODO slice of null ptr"); | ||
| 18954 | } | 19290 | } |
| 18955 | } else if (is_slice(array_type)) { | 19291 | } else if (is_slice(array_type)) { |
| 18956 | ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); | 19292 | ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); |
| ... | @@ -18981,6 +19317,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18981,6 +19317,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18981 | break; | 19317 | break; |
| 18982 | case ConstPtrSpecialBaseStruct: | 19318 | case ConstPtrSpecialBaseStruct: |
| 18983 | zig_panic("TODO slice const inner struct"); | 19319 | zig_panic("TODO slice const inner struct"); |
| 19320 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 19321 | zig_panic("TODO slice const inner error union code"); | ||
| 19322 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 19323 | zig_panic("TODO slice const inner error union payload"); | ||
| 19324 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 19325 | zig_panic("TODO slice const inner optional payload"); | ||
| 18984 | case ConstPtrSpecialHardCodedAddr: | 19326 | case ConstPtrSpecialHardCodedAddr: |
| 18985 | array_val = nullptr; | 19327 | array_val = nullptr; |
| 18986 | abs_offset = 0; | 19328 | abs_offset = 0; |
| ... | @@ -18988,6 +19330,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -18988,6 +19330,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18988 | break; | 19330 | break; |
| 18989 | case ConstPtrSpecialFunction: | 19331 | case ConstPtrSpecialFunction: |
| 18990 | zig_panic("TODO slice of slice cast from function"); | 19332 | zig_panic("TODO slice of slice cast from function"); |
| 19333 | case ConstPtrSpecialNull: | ||
| 19334 | zig_panic("TODO slice of null"); | ||
| 18991 | } | 19335 | } |
| 18992 | } else { | 19336 | } else { |
| 18993 | zig_unreachable(); | 19337 | zig_unreachable(); |
| ... | @@ -19053,6 +19397,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -19053,6 +19397,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 19053 | zig_unreachable(); | 19397 | zig_unreachable(); |
| 19054 | case ConstPtrSpecialBaseStruct: | 19398 | case ConstPtrSpecialBaseStruct: |
| 19055 | zig_panic("TODO"); | 19399 | zig_panic("TODO"); |
| 19400 | case ConstPtrSpecialBaseErrorUnionCode: | ||
| 19401 | zig_panic("TODO"); | ||
| 19402 | case ConstPtrSpecialBaseErrorUnionPayload: | ||
| 19403 | zig_panic("TODO"); | ||
| 19404 | case ConstPtrSpecialBaseOptionalPayload: | ||
| 19405 | zig_panic("TODO"); | ||
| 19056 | case ConstPtrSpecialHardCodedAddr: | 19406 | case ConstPtrSpecialHardCodedAddr: |
| 19057 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, | 19407 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, |
| 19058 | parent_ptr->type->data.pointer.child_type, | 19408 | parent_ptr->type->data.pointer.child_type, |
| ... | @@ -19061,6 +19411,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -19061,6 +19411,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 19061 | break; | 19411 | break; |
| 19062 | case ConstPtrSpecialFunction: | 19412 | case ConstPtrSpecialFunction: |
| 19063 | zig_panic("TODO"); | 19413 | zig_panic("TODO"); |
| 19414 | case ConstPtrSpecialNull: | ||
| 19415 | zig_panic("TODO"); | ||
| 19064 | } | 19416 | } |
| 19065 | 19417 | ||
| 19066 | ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; | 19418 | ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; |
| ... | @@ -19287,6 +19639,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct | ... | @@ -19287,6 +19639,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct |
| 19287 | case ZigTypeIdEnum: | 19639 | case ZigTypeIdEnum: |
| 19288 | case ZigTypeIdUnion: | 19640 | case ZigTypeIdUnion: |
| 19289 | case ZigTypeIdFn: | 19641 | case ZigTypeIdFn: |
| 19642 | case ZigTypeIdVector: | ||
| 19290 | { | 19643 | { |
| 19291 | uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); | 19644 | uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); |
| 19292 | return ir_const_unsigned(ira, &instruction->base, align_in_bytes); | 19645 | return ir_const_unsigned(ira, &instruction->base, align_in_bytes); |
| ... | @@ -19416,7 +19769,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct | ... | @@ -19416,7 +19769,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct |
| 19416 | return ira->codegen->invalid_instruction; | 19769 | return ira->codegen->invalid_instruction; |
| 19417 | 19770 | ||
| 19418 | if (err_union_val->special != ConstValSpecialRuntime) { | 19771 | if (err_union_val->special != ConstValSpecialRuntime) { |
| 19419 | return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr)); | 19772 | ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; |
| 19773 | return ir_const_bool(ira, &instruction->base, (err != nullptr)); | ||
| 19420 | } | 19774 | } |
| 19421 | } | 19775 | } |
| 19422 | 19776 | ||
| ... | @@ -19442,48 +19796,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct | ... | @@ -19442,48 +19796,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct |
| 19442 | } | 19796 | } |
| 19443 | } | 19797 | } |
| 19444 | 19798 | ||
| 19445 | static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, | 19799 | static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { |
| 19446 | IrInstructionUnwrapErrCode *instruction) | 19800 | IrInstruction *base_ptr = instruction->err_union->child; |
| 19447 | { | 19801 | if (type_is_invalid(base_ptr->value.type)) |
| 19448 | IrInstruction *value = instruction->value->child; | ||
| 19449 | if (type_is_invalid(value->value.type)) | ||
| 19450 | return ira->codegen->invalid_instruction; | 19802 | return ira->codegen->invalid_instruction; |
| 19451 | ZigType *ptr_type = value->value.type; | 19803 | ZigType *ptr_type = base_ptr->value.type; |
| 19452 | 19804 | ||
| 19453 | // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. | 19805 | // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. |
| 19454 | assert(ptr_type->id == ZigTypeIdPointer); | 19806 | assert(ptr_type->id == ZigTypeIdPointer); |
| 19455 | 19807 | ||
| 19456 | ZigType *type_entry = ptr_type->data.pointer.child_type; | 19808 | ZigType *type_entry = ptr_type->data.pointer.child_type; |
| 19457 | if (type_is_invalid(type_entry)) { | 19809 | if (type_is_invalid(type_entry)) |
| 19458 | return ira->codegen->invalid_instruction; | 19810 | return ira->codegen->invalid_instruction; |
| 19459 | } else if (type_entry->id == ZigTypeIdErrorUnion) { | ||
| 19460 | if (instr_is_comptime(value)) { | ||
| 19461 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); | ||
| 19462 | if (!ptr_val) | ||
| 19463 | return ira->codegen->invalid_instruction; | ||
| 19464 | ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); | ||
| 19465 | if (err_union_val == nullptr) | ||
| 19466 | return ira->codegen->invalid_instruction; | ||
| 19467 | if (err_union_val->special != ConstValSpecialRuntime) { | ||
| 19468 | ErrorTableEntry *err = err_union_val->data.x_err_union.err; | ||
| 19469 | assert(err); | ||
| 19470 | 19811 | ||
| 19471 | IrInstruction *result = ir_const(ira, &instruction->base, | 19812 | if (type_entry->id != ZigTypeIdErrorUnion) { |
| 19472 | type_entry->data.error_union.err_set_type); | 19813 | ir_add_error(ira, base_ptr, |
| 19473 | result->value.data.x_err_set = err; | ||
| 19474 | return result; | ||
| 19475 | } | ||
| 19476 | } | ||
| 19477 | |||
| 19478 | IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, | ||
| 19479 | instruction->base.scope, instruction->base.source_node, value); | ||
| 19480 | result->value.type = type_entry->data.error_union.err_set_type; | ||
| 19481 | return result; | ||
| 19482 | } else { | ||
| 19483 | ir_add_error(ira, value, | ||
| 19484 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); | 19814 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| 19485 | return ira->codegen->invalid_instruction; | 19815 | return ira->codegen->invalid_instruction; |
| 19486 | } | 19816 | } |
| 19817 | |||
| 19818 | if (instr_is_comptime(base_ptr)) { | ||
| 19819 | ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); | ||
| 19820 | if (!ptr_val) | ||
| 19821 | return ira->codegen->invalid_instruction; | ||
| 19822 | ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); | ||
| 19823 | if (err_union_val == nullptr) | ||
| 19824 | return ira->codegen->invalid_instruction; | ||
| 19825 | if (err_union_val->special != ConstValSpecialRuntime) { | ||
| 19826 | ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; | ||
| 19827 | assert(err); | ||
| 19828 | |||
| 19829 | IrInstruction *result = ir_const(ira, &instruction->base, | ||
| 19830 | type_entry->data.error_union.err_set_type); | ||
| 19831 | result->value.data.x_err_set = err; | ||
| 19832 | return result; | ||
| 19833 | } | ||
| 19834 | } | ||
| 19835 | |||
| 19836 | IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, | ||
| 19837 | instruction->base.scope, instruction->base.source_node, base_ptr); | ||
| 19838 | result->value.type = type_entry->data.error_union.err_set_type; | ||
| 19839 | return result; | ||
| 19487 | } | 19840 | } |
| 19488 | 19841 | ||
| 19489 | static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, | 19842 | static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| ... | @@ -19499,48 +19852,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, | ... | @@ -19499,48 +19852,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| 19499 | assert(ptr_type->id == ZigTypeIdPointer); | 19852 | assert(ptr_type->id == ZigTypeIdPointer); |
| 19500 | 19853 | ||
| 19501 | ZigType *type_entry = ptr_type->data.pointer.child_type; | 19854 | ZigType *type_entry = ptr_type->data.pointer.child_type; |
| 19502 | if (type_is_invalid(type_entry)) { | 19855 | if (type_is_invalid(type_entry)) |
| 19503 | return ira->codegen->invalid_instruction; | 19856 | return ira->codegen->invalid_instruction; |
| 19504 | } else if (type_entry->id == ZigTypeIdErrorUnion) { | ||
| 19505 | ZigType *payload_type = type_entry->data.error_union.payload_type; | ||
| 19506 | if (type_is_invalid(payload_type)) { | ||
| 19507 | return ira->codegen->invalid_instruction; | ||
| 19508 | } | ||
| 19509 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, | ||
| 19510 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | ||
| 19511 | PtrLenSingle, 0, 0, 0); | ||
| 19512 | if (instr_is_comptime(value)) { | ||
| 19513 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); | ||
| 19514 | if (!ptr_val) | ||
| 19515 | return ira->codegen->invalid_instruction; | ||
| 19516 | ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); | ||
| 19517 | if (err_union_val == nullptr) | ||
| 19518 | return ira->codegen->invalid_instruction; | ||
| 19519 | if (err_union_val->special != ConstValSpecialRuntime) { | ||
| 19520 | ErrorTableEntry *err = err_union_val->data.x_err_union.err; | ||
| 19521 | if (err != nullptr) { | ||
| 19522 | ir_add_error(ira, &instruction->base, | ||
| 19523 | buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); | ||
| 19524 | return ira->codegen->invalid_instruction; | ||
| 19525 | } | ||
| 19526 | 19857 | ||
| 19527 | IrInstruction *result = ir_const(ira, &instruction->base, result_type); | 19858 | if (type_entry->id != ZigTypeIdErrorUnion) { |
| 19528 | result->value.data.x_ptr.special = ConstPtrSpecialRef; | ||
| 19529 | result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; | ||
| 19530 | return result; | ||
| 19531 | } | ||
| 19532 | } | ||
| 19533 | |||
| 19534 | IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, | ||
| 19535 | instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); | ||
| 19536 | result->value.type = result_type; | ||
| 19537 | return result; | ||
| 19538 | } else { | ||
| 19539 | ir_add_error(ira, value, | 19859 | ir_add_error(ira, value, |
| 19540 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); | 19860 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| 19541 | return ira->codegen->invalid_instruction; | 19861 | return ira->codegen->invalid_instruction; |
| 19542 | } | 19862 | } |
| 19543 | 19863 | ||
| 19864 | ZigType *payload_type = type_entry->data.error_union.payload_type; | ||
| 19865 | if (type_is_invalid(payload_type)) | ||
| 19866 | return ira->codegen->invalid_instruction; | ||
| 19867 | |||
| 19868 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, | ||
| 19869 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | ||
| 19870 | PtrLenSingle, 0, 0, 0); | ||
| 19871 | if (instr_is_comptime(value)) { | ||
| 19872 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); | ||
| 19873 | if (!ptr_val) | ||
| 19874 | return ira->codegen->invalid_instruction; | ||
| 19875 | ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); | ||
| 19876 | if (err_union_val == nullptr) | ||
| 19877 | return ira->codegen->invalid_instruction; | ||
| 19878 | if (err_union_val->special != ConstValSpecialRuntime) { | ||
| 19879 | ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; | ||
| 19880 | if (err != nullptr) { | ||
| 19881 | ir_add_error(ira, &instruction->base, | ||
| 19882 | buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); | ||
| 19883 | return ira->codegen->invalid_instruction; | ||
| 19884 | } | ||
| 19885 | |||
| 19886 | IrInstruction *result = ir_const(ira, &instruction->base, result_type); | ||
| 19887 | result->value.data.x_ptr.special = ConstPtrSpecialRef; | ||
| 19888 | result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; | ||
| 19889 | return result; | ||
| 19890 | } | ||
| 19891 | } | ||
| 19892 | |||
| 19893 | IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, | ||
| 19894 | instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); | ||
| 19895 | result->value.type = result_type; | ||
| 19896 | return result; | ||
| 19544 | } | 19897 | } |
| 19545 | 19898 | ||
| 19546 | static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { | 19899 | static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { |
| ... | @@ -19957,7 +20310,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 | ... | @@ -19957,7 +20310,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 |
| 19957 | return ira->codegen->invalid_instruction; | 20310 | return ira->codegen->invalid_instruction; |
| 19958 | } | 20311 | } |
| 19959 | 20312 | ||
| 19960 | IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type); | 20313 | IrInstruction *result = ir_const(ira, target, result_type); |
| 19961 | copy_const_val(&result->value, val, false); | 20314 | copy_const_val(&result->value, val, false); |
| 19962 | result->value.type = result_type; | 20315 | result->value.type = result_type; |
| 19963 | return result; | 20316 | return result; |
| ... | @@ -20005,8 +20358,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -20005,8 +20358,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20005 | if (!val) | 20358 | if (!val) |
| 20006 | return ira->codegen->invalid_instruction; | 20359 | return ira->codegen->invalid_instruction; |
| 20007 | 20360 | ||
| 20008 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, | 20361 | IrInstruction *result = ir_const(ira, source_instr, dest_type); |
| 20009 | dest_type); | ||
| 20010 | copy_const_val(&result->value, val, false); | 20362 | copy_const_val(&result->value, val, false); |
| 20011 | result->value.type = dest_type; | 20363 | result->value.type = dest_type; |
| 20012 | return result; | 20364 | return result; |
| ... | @@ -20029,9 +20381,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -20029,9 +20381,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20029 | return ira->codegen->invalid_instruction; | 20381 | return ira->codegen->invalid_instruction; |
| 20030 | } | 20382 | } |
| 20031 | 20383 | ||
| 20032 | IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope, | 20384 | IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); |
| 20033 | source_instr->source_node, nullptr, ptr); | ||
| 20034 | casted_ptr->value.type = dest_type; | ||
| 20035 | 20385 | ||
| 20036 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { | 20386 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { |
| 20037 | ErrorMsg *msg = ir_add_error(ira, source_instr, | 20387 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| ... | @@ -20057,7 +20407,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -20057,7 +20407,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20057 | return result; | 20407 | return result; |
| 20058 | } | 20408 | } |
| 20059 | 20409 | ||
| 20060 | static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { | 20410 | static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) { |
| 20061 | IrInstruction *dest_type_value = instruction->dest_type->child; | 20411 | IrInstruction *dest_type_value = instruction->dest_type->child; |
| 20062 | ZigType *dest_type = ir_resolve_type(ira, dest_type_value); | 20412 | ZigType *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20063 | if (type_is_invalid(dest_type)) | 20413 | if (type_is_invalid(dest_type)) |
| ... | @@ -20071,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct | ... | @@ -20071,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct |
| 20071 | return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); | 20421 | return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); |
| 20072 | } | 20422 | } |
| 20073 | 20423 | ||
| 20424 | static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { | ||
| 20425 | size_t buf_i = 0; | ||
| 20426 | // TODO optimize the buf case | ||
| 20427 | expand_undef_array(codegen, val); | ||
| 20428 | for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { | ||
| 20429 | ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; | ||
| 20430 | buf_write_value_bytes(codegen, &buf[buf_i], elem); | ||
| 20431 | buf_i += type_size(codegen, elem->type); | ||
| 20432 | } | ||
| 20433 | } | ||
| 20434 | |||
| 20074 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { | 20435 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { |
| 20075 | if (val->special == ConstValSpecialUndef) | 20436 | if (val->special == ConstValSpecialUndef) |
| 20076 | val->special = ConstValSpecialStatic; | 20437 | val->special = ConstValSpecialStatic; |
| ... | @@ -20116,17 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue | ... | @@ -20116,17 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 20116 | zig_unreachable(); | 20477 | zig_unreachable(); |
| 20117 | } | 20478 | } |
| 20118 | case ZigTypeIdArray: | 20479 | case ZigTypeIdArray: |
| 20119 | { | 20480 | return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); |
| 20120 | size_t buf_i = 0; | 20481 | case ZigTypeIdVector: |
| 20121 | // TODO optimize the buf case | 20482 | return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); |
| 20122 | expand_undef_array(codegen, val); | ||
| 20123 | for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { | ||
| 20124 | ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; | ||
| 20125 | buf_write_value_bytes(codegen, &buf[buf_i], elem); | ||
| 20126 | buf_i += type_size(codegen, elem->type); | ||
| 20127 | } | ||
| 20128 | } | ||
| 20129 | return; | ||
| 20130 | case ZigTypeIdStruct: | 20483 | case ZigTypeIdStruct: |
| 20131 | zig_panic("TODO buf_write_value_bytes struct type"); | 20484 | zig_panic("TODO buf_write_value_bytes struct type"); |
| 20132 | case ZigTypeIdOptional: | 20485 | case ZigTypeIdOptional: |
| ... | @@ -20143,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue | ... | @@ -20143,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 20143 | zig_unreachable(); | 20496 | zig_unreachable(); |
| 20144 | } | 20497 | } |
| 20145 | 20498 | ||
| 20499 | static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, | ||
| 20500 | ConstExprValue *val, ZigType *elem_type, size_t len) | ||
| 20501 | { | ||
| 20502 | Error err; | ||
| 20503 | uint64_t elem_size = type_size(codegen, elem_type); | ||
| 20504 | |||
| 20505 | switch (val->data.x_array.special) { | ||
| 20506 | case ConstArraySpecialNone: | ||
| 20507 | val->data.x_array.data.s_none.elements = create_const_vals(len); | ||
| 20508 | for (size_t i = 0; i < len; i++) { | ||
| 20509 | ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; | ||
| 20510 | elem->special = ConstValSpecialStatic; | ||
| 20511 | elem->type = elem_type; | ||
| 20512 | if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) | ||
| 20513 | return err; | ||
| 20514 | } | ||
| 20515 | return ErrorNone; | ||
| 20516 | case ConstArraySpecialUndef: | ||
| 20517 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); | ||
| 20518 | case ConstArraySpecialBuf: | ||
| 20519 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); | ||
| 20520 | } | ||
| 20521 | zig_unreachable(); | ||
| 20522 | } | ||
| 20523 | |||
| 20146 | static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { | 20524 | static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { |
| 20147 | Error err; | 20525 | Error err; |
| 20148 | assert(val->special == ConstValSpecialStatic); | 20526 | assert(val->special == ConstValSpecialStatic); |
| ... | @@ -20181,29 +20559,27 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou | ... | @@ -20181,29 +20559,27 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 20181 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); | 20559 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); |
| 20182 | return ErrorNone; | 20560 | return ErrorNone; |
| 20183 | } | 20561 | } |
| 20184 | case ZigTypeIdArray: { | 20562 | case ZigTypeIdArray: |
| 20185 | uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); | 20563 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, |
| 20186 | size_t len = val->type->data.array.len; | 20564 | val->type->data.array.len); |
| 20187 | 20565 | case ZigTypeIdVector: | |
| 20188 | switch (val->data.x_array.special) { | 20566 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, |
| 20189 | case ConstArraySpecialNone: | 20567 | val->type->data.vector.len); |
| 20190 | val->data.x_array.data.s_none.elements = create_const_vals(len); | 20568 | case ZigTypeIdEnum: |
| 20191 | for (size_t i = 0; i < len; i++) { | 20569 | switch (val->type->data.enumeration.layout) { |
| 20192 | ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; | 20570 | case ContainerLayoutAuto: |
| 20193 | elem->special = ConstValSpecialStatic; | 20571 | zig_panic("TODO buf_read_value_bytes enum auto"); |
| 20194 | elem->type = val->type->data.array.child_type; | 20572 | case ContainerLayoutPacked: |
| 20195 | if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) | 20573 | zig_panic("TODO buf_read_value_bytes enum packed"); |
| 20196 | return err; | 20574 | case ContainerLayoutExtern: { |
| 20197 | } | 20575 | ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; |
| 20198 | break; | 20576 | assert(tag_int_type->id == ZigTypeIdInt); |
| 20199 | case ConstArraySpecialUndef: | 20577 | bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, |
| 20200 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); | 20578 | codegen->is_big_endian, tag_int_type->data.integral.is_signed); |
| 20201 | case ConstArraySpecialBuf: | 20579 | return ErrorNone; |
| 20202 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); | 20580 | } |
| 20203 | } | 20581 | } |
| 20204 | 20582 | zig_unreachable(); | |
| 20205 | return ErrorNone; | ||
| 20206 | } | ||
| 20207 | case ZigTypeIdStruct: | 20583 | case ZigTypeIdStruct: |
| 20208 | switch (val->type->data.structure.layout) { | 20584 | switch (val->type->data.structure.layout) { |
| 20209 | case ContainerLayoutAuto: { | 20585 | case ContainerLayoutAuto: { |
| ... | @@ -20242,8 +20618,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou | ... | @@ -20242,8 +20618,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 20242 | zig_panic("TODO buf_read_value_bytes error union"); | 20618 | zig_panic("TODO buf_read_value_bytes error union"); |
| 20243 | case ZigTypeIdErrorSet: | 20619 | case ZigTypeIdErrorSet: |
| 20244 | zig_panic("TODO buf_read_value_bytes pure error type"); | 20620 | zig_panic("TODO buf_read_value_bytes pure error type"); |
| 20245 | case ZigTypeIdEnum: | ||
| 20246 | zig_panic("TODO buf_read_value_bytes enum type"); | ||
| 20247 | case ZigTypeIdFn: | 20621 | case ZigTypeIdFn: |
| 20248 | zig_panic("TODO buf_read_value_bytes fn type"); | 20622 | zig_panic("TODO buf_read_value_bytes fn type"); |
| 20249 | case ZigTypeIdUnion: | 20623 | case ZigTypeIdUnion: |
| ... | @@ -20264,10 +20638,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct | ... | @@ -20264,10 +20638,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct |
| 20264 | if (type_is_invalid(src_type)) | 20638 | if (type_is_invalid(src_type)) |
| 20265 | return ira->codegen->invalid_instruction; | 20639 | return ira->codegen->invalid_instruction; |
| 20266 | 20640 | ||
| 20267 | if ((err = ensure_complete_type(ira->codegen, dest_type))) | 20641 | if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) |
| 20268 | return ira->codegen->invalid_instruction; | 20642 | return ira->codegen->invalid_instruction; |
| 20269 | 20643 | ||
| 20270 | if ((err = ensure_complete_type(ira->codegen, src_type))) | 20644 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) |
| 20271 | return ira->codegen->invalid_instruction; | 20645 | return ira->codegen->invalid_instruction; |
| 20272 | 20646 | ||
| 20273 | if (get_codegen_ptr_type(src_type) != nullptr) { | 20647 | if (get_codegen_ptr_type(src_type) != nullptr) { |
| ... | @@ -20330,6 +20704,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct | ... | @@ -20330,6 +20704,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct |
| 20330 | return ira->codegen->invalid_instruction; | 20704 | return ira->codegen->invalid_instruction; |
| 20331 | } | 20705 | } |
| 20332 | 20706 | ||
| 20707 | uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); | ||
| 20708 | uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); | ||
| 20709 | if (dest_size_bits != src_size_bits) { | ||
| 20710 | ir_add_error(ira, &instruction->base, | ||
| 20711 | buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", | ||
| 20712 | buf_ptr(&dest_type->name), dest_size_bits, | ||
| 20713 | buf_ptr(&src_type->name), src_size_bits)); | ||
| 20714 | return ira->codegen->invalid_instruction; | ||
| 20715 | } | ||
| 20716 | |||
| 20333 | if (instr_is_comptime(value)) { | 20717 | if (instr_is_comptime(value)) { |
| 20334 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); | 20718 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); |
| 20335 | if (!val) | 20719 | if (!val) |
| ... | @@ -20410,8 +20794,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, | ... | @@ -20410,8 +20794,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 20410 | case TldIdContainer: | 20794 | case TldIdContainer: |
| 20411 | case TldIdCompTime: | 20795 | case TldIdCompTime: |
| 20412 | zig_unreachable(); | 20796 | zig_unreachable(); |
| 20413 | case TldIdVar: | 20797 | case TldIdVar: { |
| 20414 | { | ||
| 20415 | TldVar *tld_var = (TldVar *)tld; | 20798 | TldVar *tld_var = (TldVar *)tld; |
| 20416 | ZigVar *var = tld_var->var; | 20799 | ZigVar *var = tld_var->var; |
| 20417 | 20800 | ||
| ... | @@ -20429,8 +20812,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, | ... | @@ -20429,8 +20812,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 20429 | return ir_get_deref(ira, &instruction->base, var_ptr); | 20812 | return ir_get_deref(ira, &instruction->base, var_ptr); |
| 20430 | } | 20813 | } |
| 20431 | } | 20814 | } |
| 20432 | case TldIdFn: | 20815 | case TldIdFn: { |
| 20433 | { | ||
| 20434 | TldFn *tld_fn = (TldFn *)tld; | 20816 | TldFn *tld_fn = (TldFn *)tld; |
| 20435 | ZigFn *fn_entry = tld_fn->fn_entry; | 20817 | ZigFn *fn_entry = tld_fn->fn_entry; |
| 20436 | assert(fn_entry->type_entry); | 20818 | assert(fn_entry->type_entry); |
| ... | @@ -20476,8 +20858,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru | ... | @@ -20476,8 +20858,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru |
| 20476 | if (!val) | 20858 | if (!val) |
| 20477 | return ira->codegen->invalid_instruction; | 20859 | return ira->codegen->invalid_instruction; |
| 20478 | if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { | 20860 | if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { |
| 20479 | IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, | 20861 | IrInstruction *result = ir_const(ira, &instruction->base, usize); |
| 20480 | instruction->base.source_node, usize); | ||
| 20481 | bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); | 20862 | bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); |
| 20482 | result->value.type = usize; | 20863 | result->value.type = usize; |
| 20483 | return result; | 20864 | return result; |
| ... | @@ -21315,6 +21696,11 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21315,6 +21696,11 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21315 | case IrInstructionIdErrWrapCode: | 21696 | case IrInstructionIdErrWrapCode: |
| 21316 | case IrInstructionIdErrWrapPayload: | 21697 | case IrInstructionIdErrWrapPayload: |
| 21317 | case IrInstructionIdCast: | 21698 | case IrInstructionIdCast: |
| 21699 | case IrInstructionIdDeclVarGen: | ||
| 21700 | case IrInstructionIdPtrCastGen: | ||
| 21701 | case IrInstructionIdCmpxchgGen: | ||
| 21702 | case IrInstructionIdArrayToVector: | ||
| 21703 | case IrInstructionIdVectorToArray: | ||
| 21318 | zig_unreachable(); | 21704 | zig_unreachable(); |
| 21319 | 21705 | ||
| 21320 | case IrInstructionIdReturn: | 21706 | case IrInstructionIdReturn: |
| ... | @@ -21325,8 +21711,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21325,8 +21711,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21325 | return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); | 21711 | return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); |
| 21326 | case IrInstructionIdBinOp: | 21712 | case IrInstructionIdBinOp: |
| 21327 | return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); | 21713 | return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); |
| 21328 | case IrInstructionIdDeclVar: | 21714 | case IrInstructionIdDeclVarSrc: |
| 21329 | return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); | 21715 | return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction); |
| 21330 | case IrInstructionIdLoadPtr: | 21716 | case IrInstructionIdLoadPtr: |
| 21331 | return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); | 21717 | return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); |
| 21332 | case IrInstructionIdStorePtr: | 21718 | case IrInstructionIdStorePtr: |
| ... | @@ -21371,8 +21757,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21371,8 +21757,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21371 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); | 21757 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| 21372 | case IrInstructionIdTestNonNull: | 21758 | case IrInstructionIdTestNonNull: |
| 21373 | return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); | 21759 | return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); |
| 21374 | case IrInstructionIdUnwrapOptional: | 21760 | case IrInstructionIdOptionalUnwrapPtr: |
| 21375 | return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction); | 21761 | return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction); |
| 21376 | case IrInstructionIdClz: | 21762 | case IrInstructionIdClz: |
| 21377 | return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); | 21763 | return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); |
| 21378 | case IrInstructionIdCtz: | 21764 | case IrInstructionIdCtz: |
| ... | @@ -21413,8 +21799,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21413,8 +21799,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21413 | return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); | 21799 | return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); |
| 21414 | case IrInstructionIdEmbedFile: | 21800 | case IrInstructionIdEmbedFile: |
| 21415 | return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction); | 21801 | return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction); |
| 21416 | case IrInstructionIdCmpxchg: | 21802 | case IrInstructionIdCmpxchgSrc: |
| 21417 | return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction); | 21803 | return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction); |
| 21418 | case IrInstructionIdFence: | 21804 | case IrInstructionIdFence: |
| 21419 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); | 21805 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); |
| 21420 | case IrInstructionIdTruncate: | 21806 | case IrInstructionIdTruncate: |
| ... | @@ -21437,6 +21823,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21437,6 +21823,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21437 | return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction); | 21823 | return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction); |
| 21438 | case IrInstructionIdIntType: | 21824 | case IrInstructionIdIntType: |
| 21439 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); | 21825 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); |
| 21826 | case IrInstructionIdVectorType: | ||
| 21827 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); | ||
| 21440 | case IrInstructionIdBoolNot: | 21828 | case IrInstructionIdBoolNot: |
| 21441 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); | 21829 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 21442 | case IrInstructionIdMemset: | 21830 | case IrInstructionIdMemset: |
| ... | @@ -21481,8 +21869,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21481,8 +21869,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21481 | return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); | 21869 | return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); |
| 21482 | case IrInstructionIdPanic: | 21870 | case IrInstructionIdPanic: |
| 21483 | return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); | 21871 | return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); |
| 21484 | case IrInstructionIdPtrCast: | 21872 | case IrInstructionIdPtrCastSrc: |
| 21485 | return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction); | 21873 | return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); |
| 21486 | case IrInstructionIdBitCast: | 21874 | case IrInstructionIdBitCast: |
| 21487 | return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); | 21875 | return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); |
| 21488 | case IrInstructionIdIntToPtr: | 21876 | case IrInstructionIdIntToPtr: |
| ... | @@ -21666,7 +22054,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21666,7 +22054,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21666 | case IrInstructionIdBr: | 22054 | case IrInstructionIdBr: |
| 21667 | case IrInstructionIdCondBr: | 22055 | case IrInstructionIdCondBr: |
| 21668 | case IrInstructionIdSwitchBr: | 22056 | case IrInstructionIdSwitchBr: |
| 21669 | case IrInstructionIdDeclVar: | 22057 | case IrInstructionIdDeclVarSrc: |
| 22058 | case IrInstructionIdDeclVarGen: | ||
| 21670 | case IrInstructionIdStorePtr: | 22059 | case IrInstructionIdStorePtr: |
| 21671 | case IrInstructionIdCall: | 22060 | case IrInstructionIdCall: |
| 21672 | case IrInstructionIdReturn: | 22061 | case IrInstructionIdReturn: |
| ... | @@ -21681,7 +22070,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21681,7 +22070,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21681 | case IrInstructionIdCInclude: | 22070 | case IrInstructionIdCInclude: |
| 21682 | case IrInstructionIdCDefine: | 22071 | case IrInstructionIdCDefine: |
| 21683 | case IrInstructionIdCUndef: | 22072 | case IrInstructionIdCUndef: |
| 21684 | case IrInstructionIdCmpxchg: | ||
| 21685 | case IrInstructionIdFence: | 22073 | case IrInstructionIdFence: |
| 21686 | case IrInstructionIdMemset: | 22074 | case IrInstructionIdMemset: |
| 21687 | case IrInstructionIdMemcpy: | 22075 | case IrInstructionIdMemcpy: |
| ... | @@ -21709,6 +22097,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21709,6 +22097,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21709 | case IrInstructionIdMergeErrRetTraces: | 22097 | case IrInstructionIdMergeErrRetTraces: |
| 21710 | case IrInstructionIdMarkErrRetTracePtr: | 22098 | case IrInstructionIdMarkErrRetTracePtr: |
| 21711 | case IrInstructionIdAtomicRmw: | 22099 | case IrInstructionIdAtomicRmw: |
| 22100 | case IrInstructionIdCmpxchgGen: | ||
| 22101 | case IrInstructionIdCmpxchgSrc: | ||
| 21712 | return true; | 22102 | return true; |
| 21713 | 22103 | ||
| 21714 | case IrInstructionIdPhi: | 22104 | case IrInstructionIdPhi: |
| ... | @@ -21734,7 +22124,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21734,7 +22124,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21734 | case IrInstructionIdSliceType: | 22124 | case IrInstructionIdSliceType: |
| 21735 | case IrInstructionIdSizeOf: | 22125 | case IrInstructionIdSizeOf: |
| 21736 | case IrInstructionIdTestNonNull: | 22126 | case IrInstructionIdTestNonNull: |
| 21737 | case IrInstructionIdUnwrapOptional: | 22127 | case IrInstructionIdOptionalUnwrapPtr: |
| 21738 | case IrInstructionIdClz: | 22128 | case IrInstructionIdClz: |
| 21739 | case IrInstructionIdCtz: | 22129 | case IrInstructionIdCtz: |
| 21740 | case IrInstructionIdPopCount: | 22130 | case IrInstructionIdPopCount: |
| ... | @@ -21745,6 +22135,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21745,6 +22135,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21745 | case IrInstructionIdEmbedFile: | 22135 | case IrInstructionIdEmbedFile: |
| 21746 | case IrInstructionIdTruncate: | 22136 | case IrInstructionIdTruncate: |
| 21747 | case IrInstructionIdIntType: | 22137 | case IrInstructionIdIntType: |
| 22138 | case IrInstructionIdVectorType: | ||
| 21748 | case IrInstructionIdBoolNot: | 22139 | case IrInstructionIdBoolNot: |
| 21749 | case IrInstructionIdSlice: | 22140 | case IrInstructionIdSlice: |
| 21750 | case IrInstructionIdMemberCount: | 22141 | case IrInstructionIdMemberCount: |
| ... | @@ -21761,7 +22152,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21761,7 +22152,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21761 | case IrInstructionIdErrWrapPayload: | 22152 | case IrInstructionIdErrWrapPayload: |
| 21762 | case IrInstructionIdFnProto: | 22153 | case IrInstructionIdFnProto: |
| 21763 | case IrInstructionIdTestComptime: | 22154 | case IrInstructionIdTestComptime: |
| 21764 | case IrInstructionIdPtrCast: | 22155 | case IrInstructionIdPtrCastSrc: |
| 22156 | case IrInstructionIdPtrCastGen: | ||
| 21765 | case IrInstructionIdBitCast: | 22157 | case IrInstructionIdBitCast: |
| 21766 | case IrInstructionIdWidenOrShorten: | 22158 | case IrInstructionIdWidenOrShorten: |
| 21767 | case IrInstructionIdPtrToInt: | 22159 | case IrInstructionIdPtrToInt: |
| ... | @@ -21804,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21804,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21804 | case IrInstructionIdFromBytes: | 22196 | case IrInstructionIdFromBytes: |
| 21805 | case IrInstructionIdToBytes: | 22197 | case IrInstructionIdToBytes: |
| 21806 | case IrInstructionIdEnumToInt: | 22198 | case IrInstructionIdEnumToInt: |
| 22199 | case IrInstructionIdVectorToArray: | ||
| 22200 | case IrInstructionIdArrayToVector: | ||
| 21807 | return false; | 22201 | return false; |
| 21808 | 22202 | ||
| 21809 | case IrInstructionIdAsm: | 22203 | case IrInstructionIdAsm: |
src/ir.hpp+1-1| ... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
| 13 | bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); | 13 | bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); |
| 14 | bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); | 14 | bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); |
| 15 | 15 | ||
| 16 | IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | 16 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 17 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, | 17 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, |
| 18 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, | 18 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 19 | IrExecutable *parent_exec); | 19 | IrExecutable *parent_exec); |
src/ir_print.cpp+90-22| ... | @@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction | ... | @@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction |
| 172 | } | 172 | } |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) { | 175 | static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) { |
| 176 | const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; | 176 | const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; |
| 177 | const char *name = buf_ptr(&decl_var_instruction->var->name); | 177 | const char *name = buf_ptr(&decl_var_instruction->var->name); |
| 178 | if (decl_var_instruction->var_type) { | 178 | if (decl_var_instruction->var_type) { |
| ... | @@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { | ... | @@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { | 334 | static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { |
| 335 | fprintf(irp->f, "*"); | ||
| 336 | ir_print_other_instruction(irp, instruction->ptr); | 335 | ir_print_other_instruction(irp, instruction->ptr); |
| 336 | fprintf(irp->f, ".*"); | ||
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { | 339 | static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { |
| ... | @@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { | ... | @@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { |
| 479 | fprintf(irp->f, ")"); | 479 | fprintf(irp->f, ")"); |
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { | 482 | static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { |
| 483 | fprintf(irp->f, "*"); | ||
| 484 | ir_print_other_instruction(irp, instruction->value); | 483 | ir_print_other_instruction(irp, instruction->value); |
| 485 | fprintf(irp->f, " != null"); | 484 | fprintf(irp->f, " != null"); |
| 486 | } | 485 | } |
| 487 | 486 | ||
| 488 | static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) { | 487 | static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) { |
| 489 | fprintf(irp->f, "&??*"); | 488 | fprintf(irp->f, "&"); |
| 490 | ir_print_other_instruction(irp, instruction->value); | 489 | ir_print_other_instruction(irp, instruction->base_ptr); |
| 490 | fprintf(irp->f, ".*.?"); | ||
| 491 | if (!instruction->safety_check_on) { | 491 | if (!instruction->safety_check_on) { |
| 492 | fprintf(irp->f, " // no safety"); | 492 | fprintf(irp->f, " // no safety"); |
| 493 | } | 493 | } |
| ... | @@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio | ... | @@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio |
| 613 | fprintf(irp->f, ")"); | 613 | fprintf(irp->f, ")"); |
| 614 | } | 614 | } |
| 615 | 615 | ||
| 616 | static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { | 616 | static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) { |
| 617 | fprintf(irp->f, "@cmpxchg("); | 617 | fprintf(irp->f, "@cmpxchg("); |
| 618 | ir_print_other_instruction(irp, instruction->ptr); | 618 | ir_print_other_instruction(irp, instruction->ptr); |
| 619 | fprintf(irp->f, ", "); | 619 | fprintf(irp->f, ", "); |
| ... | @@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { | ... | @@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { |
| 627 | fprintf(irp->f, ")"); | 627 | fprintf(irp->f, ")"); |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { | ||
| 631 | fprintf(irp->f, "@cmpxchg("); | ||
| 632 | ir_print_other_instruction(irp, instruction->ptr); | ||
| 633 | fprintf(irp->f, ", "); | ||
| 634 | ir_print_other_instruction(irp, instruction->cmp_value); | ||
| 635 | fprintf(irp->f, ", "); | ||
| 636 | ir_print_other_instruction(irp, instruction->new_value); | ||
| 637 | fprintf(irp->f, ", TODO print atomic orders)"); | ||
| 638 | } | ||
| 639 | |||
| 630 | static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { | 640 | static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { |
| 631 | fprintf(irp->f, "@fence("); | 641 | fprintf(irp->f, "@fence("); |
| 632 | ir_print_other_instruction(irp, instruction->order_value); | 642 | ir_print_other_instruction(irp, instruction->order_value); |
| ... | @@ -709,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { | ... | @@ -709,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { |
| 709 | fprintf(irp->f, ")"); | 719 | fprintf(irp->f, ")"); |
| 710 | } | 720 | } |
| 711 | 721 | ||
| 722 | static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) { | ||
| 723 | fprintf(irp->f, "@Vector("); | ||
| 724 | ir_print_other_instruction(irp, instruction->len); | ||
| 725 | fprintf(irp->f, ", "); | ||
| 726 | ir_print_other_instruction(irp, instruction->elem_type); | ||
| 727 | fprintf(irp->f, ")"); | ||
| 728 | } | ||
| 729 | |||
| 712 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { | 730 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { |
| 713 | fprintf(irp->f, "! "); | 731 | fprintf(irp->f, "! "); |
| 714 | ir_print_other_instruction(irp, instruction->value); | 732 | ir_print_other_instruction(irp, instruction->value); |
| ... | @@ -820,13 +838,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { | ... | @@ -820,13 +838,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { |
| 820 | } | 838 | } |
| 821 | 839 | ||
| 822 | static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { | 840 | static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { |
| 823 | fprintf(irp->f, "@unwrapErrorCode("); | 841 | fprintf(irp->f, "UnwrapErrorCode("); |
| 824 | ir_print_other_instruction(irp, instruction->value); | 842 | ir_print_other_instruction(irp, instruction->err_union); |
| 825 | fprintf(irp->f, ")"); | 843 | fprintf(irp->f, ")"); |
| 826 | } | 844 | } |
| 827 | 845 | ||
| 828 | static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { | 846 | static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { |
| 829 | fprintf(irp->f, "@unwrapErrorPayload("); | 847 | fprintf(irp->f, "ErrorUnionFieldPayload("); |
| 830 | ir_print_other_instruction(irp, instruction->value); | 848 | ir_print_other_instruction(irp, instruction->value); |
| 831 | fprintf(irp->f, ")"); | 849 | fprintf(irp->f, ")"); |
| 832 | if (!instruction->safety_check_on) { | 850 | if (!instruction->safety_check_on) { |
| ... | @@ -879,7 +897,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst | ... | @@ -879,7 +897,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst |
| 879 | fprintf(irp->f, ")"); | 897 | fprintf(irp->f, ")"); |
| 880 | } | 898 | } |
| 881 | 899 | ||
| 882 | static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { | 900 | static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) { |
| 883 | fprintf(irp->f, "@ptrCast("); | 901 | fprintf(irp->f, "@ptrCast("); |
| 884 | if (instruction->dest_type) { | 902 | if (instruction->dest_type) { |
| 885 | ir_print_other_instruction(irp, instruction->dest_type); | 903 | ir_print_other_instruction(irp, instruction->dest_type); |
| ... | @@ -889,6 +907,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { | ... | @@ -889,6 +907,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { |
| 889 | fprintf(irp->f, ")"); | 907 | fprintf(irp->f, ")"); |
| 890 | } | 908 | } |
| 891 | 909 | ||
| 910 | static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) { | ||
| 911 | fprintf(irp->f, "@ptrCast("); | ||
| 912 | ir_print_other_instruction(irp, instruction->ptr); | ||
| 913 | fprintf(irp->f, ")"); | ||
| 914 | } | ||
| 915 | |||
| 892 | static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { | 916 | static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { |
| 893 | fprintf(irp->f, "@bitCast("); | 917 | fprintf(irp->f, "@bitCast("); |
| 894 | if (instruction->dest_type) { | 918 | if (instruction->dest_type) { |
| ... | @@ -900,7 +924,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { | ... | @@ -900,7 +924,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { |
| 900 | } | 924 | } |
| 901 | 925 | ||
| 902 | static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { | 926 | static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { |
| 903 | fprintf(irp->f, "@widenOrShorten("); | 927 | fprintf(irp->f, "WidenOrShorten("); |
| 904 | ir_print_other_instruction(irp, instruction->target); | 928 | ir_print_other_instruction(irp, instruction->target); |
| 905 | fprintf(irp->f, ")"); | 929 | fprintf(irp->f, ")"); |
| 906 | } | 930 | } |
| ... | @@ -948,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime | ... | @@ -948,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime |
| 948 | fprintf(irp->f, ")"); | 972 | fprintf(irp->f, ")"); |
| 949 | } | 973 | } |
| 950 | 974 | ||
| 975 | static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *instruction) { | ||
| 976 | fprintf(irp->f, "ArrayToVector("); | ||
| 977 | ir_print_other_instruction(irp, instruction->array); | ||
| 978 | fprintf(irp->f, ")"); | ||
| 979 | } | ||
| 980 | |||
| 981 | static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) { | ||
| 982 | fprintf(irp->f, "VectorToArray("); | ||
| 983 | ir_print_other_instruction(irp, instruction->vector); | ||
| 984 | fprintf(irp->f, ")"); | ||
| 985 | } | ||
| 986 | |||
| 951 | static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { | 987 | static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { |
| 952 | fprintf(irp->f, "inttoerr "); | 988 | fprintf(irp->f, "inttoerr "); |
| 953 | ir_print_other_instruction(irp, instruction->target); | 989 | ir_print_other_instruction(irp, instruction->target); |
| ... | @@ -1323,6 +1359,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { | ... | @@ -1323,6 +1359,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { |
| 1323 | fprintf(irp->f, ")"); | 1359 | fprintf(irp->f, ")"); |
| 1324 | } | 1360 | } |
| 1325 | 1361 | ||
| 1362 | static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) { | ||
| 1363 | ZigVar *var = decl_var_instruction->var; | ||
| 1364 | const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; | ||
| 1365 | const char *name = buf_ptr(&decl_var_instruction->var->name); | ||
| 1366 | fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), | ||
| 1367 | var->align_bytes); | ||
| 1368 | |||
| 1369 | ir_print_other_instruction(irp, decl_var_instruction->init_value); | ||
| 1370 | if (decl_var_instruction->var->is_comptime != nullptr) { | ||
| 1371 | fprintf(irp->f, " // comptime = "); | ||
| 1372 | ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime); | ||
| 1373 | } | ||
| 1374 | } | ||
| 1375 | |||
| 1326 | static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { | 1376 | static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { |
| 1327 | fprintf(irp->f, "@bswap("); | 1377 | fprintf(irp->f, "@bswap("); |
| 1328 | if (instruction->type != nullptr) { | 1378 | if (instruction->type != nullptr) { |
| ... | @@ -1361,8 +1411,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1361,8 +1411,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1361 | case IrInstructionIdBinOp: | 1411 | case IrInstructionIdBinOp: |
| 1362 | ir_print_bin_op(irp, (IrInstructionBinOp *)instruction); | 1412 | ir_print_bin_op(irp, (IrInstructionBinOp *)instruction); |
| 1363 | break; | 1413 | break; |
| 1364 | case IrInstructionIdDeclVar: | 1414 | case IrInstructionIdDeclVarSrc: |
| 1365 | ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction); | 1415 | ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction); |
| 1366 | break; | 1416 | break; |
| 1367 | case IrInstructionIdCast: | 1417 | case IrInstructionIdCast: |
| 1368 | ir_print_cast(irp, (IrInstructionCast *)instruction); | 1418 | ir_print_cast(irp, (IrInstructionCast *)instruction); |
| ... | @@ -1452,10 +1502,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1452,10 +1502,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1452 | ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); | 1502 | ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); |
| 1453 | break; | 1503 | break; |
| 1454 | case IrInstructionIdTestNonNull: | 1504 | case IrInstructionIdTestNonNull: |
| 1455 | ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction); | 1505 | ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction); |
| 1456 | break; | 1506 | break; |
| 1457 | case IrInstructionIdUnwrapOptional: | 1507 | case IrInstructionIdOptionalUnwrapPtr: |
| 1458 | ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction); | 1508 | ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction); |
| 1459 | break; | 1509 | break; |
| 1460 | case IrInstructionIdCtz: | 1510 | case IrInstructionIdCtz: |
| 1461 | ir_print_ctz(irp, (IrInstructionCtz *)instruction); | 1511 | ir_print_ctz(irp, (IrInstructionCtz *)instruction); |
| ... | @@ -1508,8 +1558,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1508,8 +1558,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1508 | case IrInstructionIdEmbedFile: | 1558 | case IrInstructionIdEmbedFile: |
| 1509 | ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction); | 1559 | ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction); |
| 1510 | break; | 1560 | break; |
| 1511 | case IrInstructionIdCmpxchg: | 1561 | case IrInstructionIdCmpxchgSrc: |
| 1512 | ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction); | 1562 | ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction); |
| 1563 | break; | ||
| 1564 | case IrInstructionIdCmpxchgGen: | ||
| 1565 | ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction); | ||
| 1513 | break; | 1566 | break; |
| 1514 | case IrInstructionIdFence: | 1567 | case IrInstructionIdFence: |
| 1515 | ir_print_fence(irp, (IrInstructionFence *)instruction); | 1568 | ir_print_fence(irp, (IrInstructionFence *)instruction); |
| ... | @@ -1544,6 +1597,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1544,6 +1597,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1544 | case IrInstructionIdIntType: | 1597 | case IrInstructionIdIntType: |
| 1545 | ir_print_int_type(irp, (IrInstructionIntType *)instruction); | 1598 | ir_print_int_type(irp, (IrInstructionIntType *)instruction); |
| 1546 | break; | 1599 | break; |
| 1600 | case IrInstructionIdVectorType: | ||
| 1601 | ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); | ||
| 1602 | break; | ||
| 1547 | case IrInstructionIdBoolNot: | 1603 | case IrInstructionIdBoolNot: |
| 1548 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); | 1604 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); |
| 1549 | break; | 1605 | break; |
| ... | @@ -1607,8 +1663,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1607,8 +1663,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1607 | case IrInstructionIdTestComptime: | 1663 | case IrInstructionIdTestComptime: |
| 1608 | ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); | 1664 | ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); |
| 1609 | break; | 1665 | break; |
| 1610 | case IrInstructionIdPtrCast: | 1666 | case IrInstructionIdPtrCastSrc: |
| 1611 | ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction); | 1667 | ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction); |
| 1668 | break; | ||
| 1669 | case IrInstructionIdPtrCastGen: | ||
| 1670 | ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); | ||
| 1612 | break; | 1671 | break; |
| 1613 | case IrInstructionIdBitCast: | 1672 | case IrInstructionIdBitCast: |
| 1614 | ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); | 1673 | ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); |
| ... | @@ -1775,6 +1834,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1775,6 +1834,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1775 | case IrInstructionIdCheckRuntimeScope: | 1834 | case IrInstructionIdCheckRuntimeScope: |
| 1776 | ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); | 1835 | ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); |
| 1777 | break; | 1836 | break; |
| 1837 | case IrInstructionIdDeclVarGen: | ||
| 1838 | ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction); | ||
| 1839 | break; | ||
| 1840 | case IrInstructionIdArrayToVector: | ||
| 1841 | ir_print_array_to_vector(irp, (IrInstructionArrayToVector *)instruction); | ||
| 1842 | break; | ||
| 1843 | case IrInstructionIdVectorToArray: | ||
| 1844 | ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); | ||
| 1845 | break; | ||
| 1778 | } | 1846 | } |
| 1779 | fprintf(irp->f, "\n"); | 1847 | fprintf(irp->f, "\n"); |
| 1780 | } | 1848 | } |
src/main.cpp+6| ... | @@ -59,6 +59,7 @@ static int print_full_usage(const char *arg0) { | ... | @@ -59,6 +59,7 @@ static int print_full_usage(const char *arg0) { |
| 59 | " --release-fast build with optimizations on and safety off\n" | 59 | " --release-fast build with optimizations on and safety off\n" |
| 60 | " --release-safe build with optimizations on and safety on\n" | 60 | " --release-safe build with optimizations on and safety on\n" |
| 61 | " --release-small build with size optimizations on and safety off\n" | 61 | " --release-small build with size optimizations on and safety off\n" |
| 62 | " --single-threaded source may assume it is only used single-threaded\n" | ||
| 62 | " --static output will be statically linked\n" | 63 | " --static output will be statically linked\n" |
| 63 | " --strip exclude debug symbols\n" | 64 | " --strip exclude debug symbols\n" |
| 64 | " --target-arch [name] specify target architecture\n" | 65 | " --target-arch [name] specify target architecture\n" |
| ... | @@ -393,6 +394,7 @@ int main(int argc, char **argv) { | ... | @@ -393,6 +394,7 @@ int main(int argc, char **argv) { |
| 393 | bool no_rosegment_workaround = false; | 394 | bool no_rosegment_workaround = false; |
| 394 | bool system_linker_hack = false; | 395 | bool system_linker_hack = false; |
| 395 | TargetSubsystem subsystem = TargetSubsystemAuto; | 396 | TargetSubsystem subsystem = TargetSubsystemAuto; |
| 397 | bool is_single_threaded = false; | ||
| 396 | 398 | ||
| 397 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { | 399 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { |
| 398 | Buf zig_exe_path_buf = BUF_INIT; | 400 | Buf zig_exe_path_buf = BUF_INIT; |
| ... | @@ -550,6 +552,8 @@ int main(int argc, char **argv) { | ... | @@ -550,6 +552,8 @@ int main(int argc, char **argv) { |
| 550 | disable_pic = true; | 552 | disable_pic = true; |
| 551 | } else if (strcmp(arg, "--system-linker-hack") == 0) { | 553 | } else if (strcmp(arg, "--system-linker-hack") == 0) { |
| 552 | system_linker_hack = true; | 554 | system_linker_hack = true; |
| 555 | } else if (strcmp(arg, "--single-threaded") == 0) { | ||
| 556 | is_single_threaded = true; | ||
| 553 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { | 557 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { |
| 554 | test_exec_args.append(nullptr); | 558 | test_exec_args.append(nullptr); |
| 555 | } else if (arg[1] == 'L' && arg[2] != 0) { | 559 | } else if (arg[1] == 'L' && arg[2] != 0) { |
| ... | @@ -816,6 +820,7 @@ int main(int argc, char **argv) { | ... | @@ -816,6 +820,7 @@ int main(int argc, char **argv) { |
| 816 | switch (cmd) { | 820 | switch (cmd) { |
| 817 | case CmdBuiltin: { | 821 | case CmdBuiltin: { |
| 818 | CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); | 822 | CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); |
| 823 | g->is_single_threaded = is_single_threaded; | ||
| 819 | Buf *builtin_source = codegen_generate_builtin_source(g); | 824 | Buf *builtin_source = codegen_generate_builtin_source(g); |
| 820 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { | 825 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { |
| 821 | fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); | 826 | fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); |
| ... | @@ -889,6 +894,7 @@ int main(int argc, char **argv) { | ... | @@ -889,6 +894,7 @@ int main(int argc, char **argv) { |
| 889 | codegen_set_out_name(g, buf_out_name); | 894 | codegen_set_out_name(g, buf_out_name); |
| 890 | codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); | 895 | codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); |
| 891 | codegen_set_is_test(g, cmd == CmdTest); | 896 | codegen_set_is_test(g, cmd == CmdTest); |
| 897 | g->is_single_threaded = is_single_threaded; | ||
| 892 | codegen_set_linker_script(g, linker_script); | 898 | codegen_set_linker_script(g, linker_script); |
| 893 | if (each_lib_rpath) | 899 | if (each_lib_rpath) |
| 894 | codegen_set_each_lib_rpath(g, each_lib_rpath); | 900 | codegen_set_each_lib_rpath(g, each_lib_rpath); |
src/os.cpp+31-31| ... | @@ -1808,7 +1808,7 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { | ... | @@ -1808,7 +1808,7 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { |
| 1808 | #endif | 1808 | #endif |
| 1809 | } | 1809 | } |
| 1810 | 1810 | ||
| 1811 | Error os_file_open_r(Buf *full_path, OsFile *out_file) { | 1811 | Error os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime) { |
| 1812 | #if defined(ZIG_OS_WINDOWS) | 1812 | #if defined(ZIG_OS_WINDOWS) |
| 1813 | // TODO use CreateFileW | 1813 | // TODO use CreateFileW |
| 1814 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); | 1814 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); |
| ... | @@ -1834,8 +1834,18 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { | ... | @@ -1834,8 +1834,18 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { |
| 1834 | return ErrorUnexpected; | 1834 | return ErrorUnexpected; |
| 1835 | } | 1835 | } |
| 1836 | } | 1836 | } |
| 1837 | |||
| 1838 | *out_file = result; | 1837 | *out_file = result; |
| 1838 | |||
| 1839 | if (mtime != nullptr) { | ||
| 1840 | FILETIME last_write_time; | ||
| 1841 | if (!GetFileTime(result, nullptr, nullptr, &last_write_time)) { | ||
| 1842 | CloseHandle(result); | ||
| 1843 | return ErrorUnexpected; | ||
| 1844 | } | ||
| 1845 | mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; | ||
| 1846 | mtime->nsec = 0; | ||
| 1847 | } | ||
| 1848 | |||
| 1839 | return ErrorNone; | 1849 | return ErrorNone; |
| 1840 | #else | 1850 | #else |
| 1841 | for (;;) { | 1851 | for (;;) { |
| ... | @@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { | ... | @@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { |
| 1858 | return ErrorFileSystem; | 1868 | return ErrorFileSystem; |
| 1859 | } | 1869 | } |
| 1860 | } | 1870 | } |
| 1871 | struct stat statbuf; | ||
| 1872 | if (fstat(fd, &statbuf) == -1) { | ||
| 1873 | close(fd); | ||
| 1874 | return ErrorFileSystem; | ||
| 1875 | } | ||
| 1876 | if (S_ISDIR(statbuf.st_mode)) { | ||
| 1877 | close(fd); | ||
| 1878 | return ErrorIsDir; | ||
| 1879 | } | ||
| 1861 | *out_file = fd; | 1880 | *out_file = fd; |
| 1881 | |||
| 1882 | if (mtime != nullptr) { | ||
| 1883 | #if defined(ZIG_OS_DARWIN) | ||
| 1884 | mtime->sec = statbuf.st_mtimespec.tv_sec; | ||
| 1885 | mtime->nsec = statbuf.st_mtimespec.tv_nsec; | ||
| 1886 | #else | ||
| 1887 | mtime->sec = statbuf.st_mtim.tv_sec; | ||
| 1888 | mtime->nsec = statbuf.st_mtim.tv_nsec; | ||
| 1889 | #endif | ||
| 1890 | } | ||
| 1862 | return ErrorNone; | 1891 | return ErrorNone; |
| 1863 | } | 1892 | } |
| 1864 | #endif | 1893 | #endif |
| ... | @@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | ... | @@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1948 | #endif | 1977 | #endif |
| 1949 | } | 1978 | } |
| 1950 | 1979 | ||
| 1951 | Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { | ||
| 1952 | #if defined(ZIG_OS_WINDOWS) | ||
| 1953 | FILETIME last_write_time; | ||
| 1954 | if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) | ||
| 1955 | return ErrorUnexpected; | ||
| 1956 | mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; | ||
| 1957 | mtime->nsec = 0; | ||
| 1958 | return ErrorNone; | ||
| 1959 | #elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) | ||
| 1960 | struct stat statbuf; | ||
| 1961 | if (fstat(file, &statbuf) == -1) | ||
| 1962 | return ErrorFileSystem; | ||
| 1963 | |||
| 1964 | mtime->sec = statbuf.st_mtim.tv_sec; | ||
| 1965 | mtime->nsec = statbuf.st_mtim.tv_nsec; | ||
| 1966 | return ErrorNone; | ||
| 1967 | #elif defined(ZIG_OS_DARWIN) | ||
| 1968 | struct stat statbuf; | ||
| 1969 | if (fstat(file, &statbuf) == -1) | ||
| 1970 | return ErrorFileSystem; | ||
| 1971 | |||
| 1972 | mtime->sec = statbuf.st_mtimespec.tv_sec; | ||
| 1973 | mtime->nsec = statbuf.st_mtimespec.tv_nsec; | ||
| 1974 | return ErrorNone; | ||
| 1975 | #else | ||
| 1976 | #error unimplemented | ||
| 1977 | #endif | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | Error os_file_read(OsFile file, void *ptr, size_t *len) { | 1980 | Error os_file_read(OsFile file, void *ptr, size_t *len) { |
| 1981 | #if defined(ZIG_OS_WINDOWS) | 1981 | #if defined(ZIG_OS_WINDOWS) |
| 1982 | DWORD amt_read; | 1982 | DWORD amt_read; |
src/os.hpp+1-2| ... | @@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path); | ... | @@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path); |
| 101 | Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); | 101 | Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); |
| 102 | Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); | 102 | Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); |
| 103 | 103 | ||
| 104 | Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file); | 104 | Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime); |
| 105 | Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); | 105 | Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); |
| 106 | Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime); | ||
| 107 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); | 106 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); |
| 108 | Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); | 107 | Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); |
| 109 | Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents); | 108 | Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents); |
src/parser.cpp+4-4| ... | @@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse | ... | @@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse |
| 381 | else_body = ast_expect(pc, body_parser); | 381 | else_body = ast_expect(pc, body_parser); |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | assert(res->type == NodeTypeTestExpr); | 384 | assert(res->type == NodeTypeIfOptional); |
| 385 | if (err_payload != nullptr) { | 385 | if (err_payload != nullptr) { |
| 386 | AstNodeTestExpr old = res->data.test_expr; | 386 | AstNodeTestExpr old = res->data.test_expr; |
| 387 | res->type = NodeTypeIfErrorExpr; | 387 | res->type = NodeTypeIfErrorExpr; |
| ... | @@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { | ... | @@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { |
| 990 | if (requires_semi && else_body == nullptr) | 990 | if (requires_semi && else_body == nullptr) |
| 991 | expect_token(pc, TokenIdSemicolon); | 991 | expect_token(pc, TokenIdSemicolon); |
| 992 | 992 | ||
| 993 | assert(res->type == NodeTypeTestExpr); | 993 | assert(res->type == NodeTypeIfOptional); |
| 994 | if (err_payload != nullptr) { | 994 | if (err_payload != nullptr) { |
| 995 | AstNodeTestExpr old = res->data.test_expr; | 995 | AstNodeTestExpr old = res->data.test_expr; |
| 996 | res->type = NodeTypeIfErrorExpr; | 996 | res->type = NodeTypeIfErrorExpr; |
| ... | @@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { | ... | @@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { |
| 2204 | Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc); | 2204 | Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc); |
| 2205 | 2205 | ||
| 2206 | PtrPayload payload; | 2206 | PtrPayload payload; |
| 2207 | AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first); | 2207 | AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); |
| 2208 | res->data.test_expr.target_node = condition; | 2208 | res->data.test_expr.target_node = condition; |
| 2209 | if (opt_payload.unwrap(&payload)) { | 2209 | if (opt_payload.unwrap(&payload)) { |
| 2210 | res->data.test_expr.var_symbol = token_buf(payload.payload); | 2210 | res->data.test_expr.var_symbol = token_buf(payload.payload); |
| ... | @@ -2999,7 +2999,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2999,7 +2999,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2999 | visit_field(&node->data.if_err_expr.then_node, visit, context); | 2999 | visit_field(&node->data.if_err_expr.then_node, visit, context); |
| 3000 | visit_field(&node->data.if_err_expr.else_node, visit, context); | 3000 | visit_field(&node->data.if_err_expr.else_node, visit, context); |
| 3001 | break; | 3001 | break; |
| 3002 | case NodeTypeTestExpr: | 3002 | case NodeTypeIfOptional: |
| 3003 | visit_field(&node->data.test_expr.target_node, visit, context); | 3003 | visit_field(&node->data.test_expr.target_node, visit, context); |
| 3004 | visit_field(&node->data.test_expr.then_node, visit, context); | 3004 | visit_field(&node->data.test_expr.then_node, visit, context); |
| 3005 | visit_field(&node->data.test_expr.else_node, visit, context); | 3005 | visit_field(&node->data.test_expr.else_node, visit, context); |
src/tokenizer.cpp+5-7| ... | @@ -248,13 +248,8 @@ ATTRIBUTE_PRINTF(2, 3) | ... | @@ -248,13 +248,8 @@ ATTRIBUTE_PRINTF(2, 3) |
| 248 | static void tokenize_error(Tokenize *t, const char *format, ...) { | 248 | static void tokenize_error(Tokenize *t, const char *format, ...) { |
| 249 | t->state = TokenizeStateError; | 249 | t->state = TokenizeStateError; |
| 250 | 250 | ||
| 251 | if (t->cur_tok) { | 251 | t->out->err_line = t->line; |
| 252 | t->out->err_line = t->cur_tok->start_line; | 252 | t->out->err_column = t->column; |
| 253 | t->out->err_column = t->cur_tok->start_column; | ||
| 254 | } else { | ||
| 255 | t->out->err_line = t->line; | ||
| 256 | t->out->err_column = t->column; | ||
| 257 | } | ||
| 258 | 253 | ||
| 259 | va_list ap; | 254 | va_list ap; |
| 260 | va_start(ap, format); | 255 | va_start(ap, format); |
| ... | @@ -886,6 +881,9 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -886,6 +881,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 886 | break; | 881 | break; |
| 887 | case TokenizeStateSawAmpersand: | 882 | case TokenizeStateSawAmpersand: |
| 888 | switch (c) { | 883 | switch (c) { |
| 884 | case '&': | ||
| 885 | tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); | ||
| 886 | break; | ||
| 889 | case '=': | 887 | case '=': |
| 890 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); | 888 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); |
| 891 | end_token(&t); | 889 | end_token(&t); |
src/zig_llvm.cpp+13| ... | @@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch | ... | @@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch |
| 263 | return reinterpret_cast<ZigLLVMDIType*>(di_type); | 263 | return reinterpret_cast<ZigLLVMDIType*>(di_type); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, | ||
| 267 | uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty) | ||
| 268 | { | ||
| 269 | SmallVector<Metadata *, 1> subrange; | ||
| 270 | subrange.push_back(reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateSubrange(0, Size)); | ||
| 271 | DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createVectorType( | ||
| 272 | Size, | ||
| 273 | AlignInBits, | ||
| 274 | reinterpret_cast<DIType*>(Ty), | ||
| 275 | reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(subrange)); | ||
| 276 | return reinterpret_cast<ZigLLVMDIType*>(di_type); | ||
| 277 | } | ||
| 278 | |||
| 266 | ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits, | 279 | ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits, |
| 267 | uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count) | 280 | uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count) |
| 268 | { | 281 | { |
src/zig_llvm.h+2| ... | @@ -191,6 +191,8 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB | ... | @@ -191,6 +191,8 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB |
| 191 | unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, | 191 | unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, |
| 192 | unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram); | 192 | unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram); |
| 193 | 193 | ||
| 194 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, | ||
| 195 | uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty); | ||
| 194 | 196 | ||
| 195 | ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); | 197 | ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); |
| 196 | 198 |
std/atomic/queue.zig+32-15| ... | @@ -170,20 +170,36 @@ test "std.atomic.Queue" { | ... | @@ -170,20 +170,36 @@ test "std.atomic.Queue" { |
| 170 | .get_count = 0, | 170 | .get_count = 0, |
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| 173 | var putters: [put_thread_count]*std.os.Thread = undefined; | 173 | if (builtin.single_threaded) { |
| 174 | for (putters) |*t| { | 174 | { |
| 175 | t.* = try std.os.spawnThread(&context, startPuts); | 175 | var i: usize = 0; |
| 176 | } | 176 | while (i < put_thread_count) : (i += 1) { |
| 177 | var getters: [put_thread_count]*std.os.Thread = undefined; | 177 | std.debug.assertOrPanic(startPuts(&context) == 0); |
| 178 | for (getters) |*t| { | 178 | } |
| 179 | t.* = try std.os.spawnThread(&context, startGets); | 179 | } |
| 180 | } | 180 | context.puts_done = 1; |
| 181 | { | ||
| 182 | var i: usize = 0; | ||
| 183 | while (i < put_thread_count) : (i += 1) { | ||
| 184 | std.debug.assertOrPanic(startGets(&context) == 0); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } else { | ||
| 188 | var putters: [put_thread_count]*std.os.Thread = undefined; | ||
| 189 | for (putters) |*t| { | ||
| 190 | t.* = try std.os.spawnThread(&context, startPuts); | ||
| 191 | } | ||
| 192 | var getters: [put_thread_count]*std.os.Thread = undefined; | ||
| 193 | for (getters) |*t| { | ||
| 194 | t.* = try std.os.spawnThread(&context, startGets); | ||
| 195 | } | ||
| 181 | 196 | ||
| 182 | for (putters) |t| | 197 | for (putters) |t| |
| 183 | t.wait(); | 198 | t.wait(); |
| 184 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | 199 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); |
| 185 | for (getters) |t| | 200 | for (getters) |t| |
| 186 | t.wait(); | 201 | t.wait(); |
| 202 | } | ||
| 187 | 203 | ||
| 188 | if (context.put_sum != context.get_sum) { | 204 | if (context.put_sum != context.get_sum) { |
| 189 | std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); | 205 | std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); |
| ... | @@ -205,11 +221,12 @@ fn startPuts(ctx: *Context) u8 { | ... | @@ -205,11 +221,12 @@ fn startPuts(ctx: *Context) u8 { |
| 205 | while (put_count != 0) : (put_count -= 1) { | 221 | while (put_count != 0) : (put_count -= 1) { |
| 206 | std.os.time.sleep(1); // let the os scheduler be our fuzz | 222 | std.os.time.sleep(1); // let the os scheduler be our fuzz |
| 207 | const x = @bitCast(i32, r.random.scalar(u32)); | 223 | const x = @bitCast(i32, r.random.scalar(u32)); |
| 208 | const node = ctx.allocator.create(Queue(i32).Node{ | 224 | const node = ctx.allocator.create(Queue(i32).Node) catch unreachable; |
| 225 | node.* = Queue(i32).Node{ | ||
| 209 | .prev = undefined, | 226 | .prev = undefined, |
| 210 | .next = undefined, | 227 | .next = undefined, |
| 211 | .data = x, | 228 | .data = x, |
| 212 | }) catch unreachable; | 229 | }; |
| 213 | ctx.queue.put(node); | 230 | ctx.queue.put(node); |
| 214 | _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); | 231 | _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); |
| 215 | } | 232 | } |
std/atomic/stack.zig+59-28| ... | @@ -4,10 +4,13 @@ const AtomicOrder = builtin.AtomicOrder; | ... | @@ -4,10 +4,13 @@ const AtomicOrder = builtin.AtomicOrder; |
| 4 | 4 | ||
| 5 | /// Many reader, many writer, non-allocating, thread-safe | 5 | /// Many reader, many writer, non-allocating, thread-safe |
| 6 | /// Uses a spinlock to protect push() and pop() | 6 | /// Uses a spinlock to protect push() and pop() |
| 7 | /// When building in single threaded mode, this is a simple linked list. | ||
| 7 | pub fn Stack(comptime T: type) type { | 8 | pub fn Stack(comptime T: type) type { |
| 8 | return struct { | 9 | return struct { |
| 9 | root: ?*Node, | 10 | root: ?*Node, |
| 10 | lock: u8, | 11 | lock: @typeOf(lock_init), |
| 12 | |||
| 13 | const lock_init = if (builtin.single_threaded) {} else u8(0); | ||
| 11 | 14 | ||
| 12 | pub const Self = @This(); | 15 | pub const Self = @This(); |
| 13 | 16 | ||
| ... | @@ -19,7 +22,7 @@ pub fn Stack(comptime T: type) type { | ... | @@ -19,7 +22,7 @@ pub fn Stack(comptime T: type) type { |
| 19 | pub fn init() Self { | 22 | pub fn init() Self { |
| 20 | return Self{ | 23 | return Self{ |
| 21 | .root = null, | 24 | .root = null, |
| 22 | .lock = 0, | 25 | .lock = lock_init, |
| 23 | }; | 26 | }; |
| 24 | } | 27 | } |
| 25 | 28 | ||
| ... | @@ -31,20 +34,31 @@ pub fn Stack(comptime T: type) type { | ... | @@ -31,20 +34,31 @@ pub fn Stack(comptime T: type) type { |
| 31 | } | 34 | } |
| 32 | 35 | ||
| 33 | pub fn push(self: *Self, node: *Node) void { | 36 | pub fn push(self: *Self, node: *Node) void { |
| 34 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} | 37 | if (builtin.single_threaded) { |
| 35 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | 38 | node.next = self.root; |
| 36 | 39 | self.root = node; | |
| 37 | node.next = self.root; | 40 | } else { |
| 38 | self.root = node; | 41 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} |
| 42 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | ||
| 43 | |||
| 44 | node.next = self.root; | ||
| 45 | self.root = node; | ||
| 46 | } | ||
| 39 | } | 47 | } |
| 40 | 48 | ||
| 41 | pub fn pop(self: *Self) ?*Node { | 49 | pub fn pop(self: *Self) ?*Node { |
| 42 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} | 50 | if (builtin.single_threaded) { |
| 43 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | 51 | const root = self.root orelse return null; |
| 44 | 52 | self.root = root.next; | |
| 45 | const root = self.root orelse return null; | 53 | return root; |
| 46 | self.root = root.next; | 54 | } else { |
| 47 | return root; | 55 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} |
| 56 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | ||
| 57 | |||
| 58 | const root = self.root orelse return null; | ||
| 59 | self.root = root.next; | ||
| 60 | return root; | ||
| 61 | } | ||
| 48 | } | 62 | } |
| 49 | 63 | ||
| 50 | pub fn isEmpty(self: *Self) bool { | 64 | pub fn isEmpty(self: *Self) bool { |
| ... | @@ -90,20 +104,36 @@ test "std.atomic.stack" { | ... | @@ -90,20 +104,36 @@ test "std.atomic.stack" { |
| 90 | .get_count = 0, | 104 | .get_count = 0, |
| 91 | }; | 105 | }; |
| 92 | 106 | ||
| 93 | var putters: [put_thread_count]*std.os.Thread = undefined; | 107 | if (builtin.single_threaded) { |
| 94 | for (putters) |*t| { | 108 | { |
| 95 | t.* = try std.os.spawnThread(&context, startPuts); | 109 | var i: usize = 0; |
| 96 | } | 110 | while (i < put_thread_count) : (i += 1) { |
| 97 | var getters: [put_thread_count]*std.os.Thread = undefined; | 111 | std.debug.assertOrPanic(startPuts(&context) == 0); |
| 98 | for (getters) |*t| { | 112 | } |
| 99 | t.* = try std.os.spawnThread(&context, startGets); | 113 | } |
| 100 | } | 114 | context.puts_done = 1; |
| 115 | { | ||
| 116 | var i: usize = 0; | ||
| 117 | while (i < put_thread_count) : (i += 1) { | ||
| 118 | std.debug.assertOrPanic(startGets(&context) == 0); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } else { | ||
| 122 | var putters: [put_thread_count]*std.os.Thread = undefined; | ||
| 123 | for (putters) |*t| { | ||
| 124 | t.* = try std.os.spawnThread(&context, startPuts); | ||
| 125 | } | ||
| 126 | var getters: [put_thread_count]*std.os.Thread = undefined; | ||
| 127 | for (getters) |*t| { | ||
| 128 | t.* = try std.os.spawnThread(&context, startGets); | ||
| 129 | } | ||
| 101 | 130 | ||
| 102 | for (putters) |t| | 131 | for (putters) |t| |
| 103 | t.wait(); | 132 | t.wait(); |
| 104 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | 133 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); |
| 105 | for (getters) |t| | 134 | for (getters) |t| |
| 106 | t.wait(); | 135 | t.wait(); |
| 136 | } | ||
| 107 | 137 | ||
| 108 | if (context.put_sum != context.get_sum) { | 138 | if (context.put_sum != context.get_sum) { |
| 109 | std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); | 139 | std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); |
| ... | @@ -125,10 +155,11 @@ fn startPuts(ctx: *Context) u8 { | ... | @@ -125,10 +155,11 @@ fn startPuts(ctx: *Context) u8 { |
| 125 | while (put_count != 0) : (put_count -= 1) { | 155 | while (put_count != 0) : (put_count -= 1) { |
| 126 | std.os.time.sleep(1); // let the os scheduler be our fuzz | 156 | std.os.time.sleep(1); // let the os scheduler be our fuzz |
| 127 | const x = @bitCast(i32, r.random.scalar(u32)); | 157 | const x = @bitCast(i32, r.random.scalar(u32)); |
| 128 | const node = ctx.allocator.create(Stack(i32).Node{ | 158 | const node = ctx.allocator.create(Stack(i32).Node) catch unreachable; |
| 159 | node.* = Stack(i32).Node{ | ||
| 129 | .next = undefined, | 160 | .next = undefined, |
| 130 | .data = x, | 161 | .data = x, |
| 131 | }) catch unreachable; | 162 | }; |
| 132 | ctx.stack.push(node); | 163 | ctx.stack.push(node); |
| 133 | _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); | 164 | _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); |
| 134 | } | 165 | } |
std/build.zig+39-23| ... | @@ -89,7 +89,7 @@ pub const Builder = struct { | ... | @@ -89,7 +89,7 @@ pub const Builder = struct { |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder { | 91 | pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder { |
| 92 | const env_map = allocator.createOne(BufMap) catch unreachable; | 92 | const env_map = allocator.create(BufMap) catch unreachable; |
| 93 | env_map.* = os.getEnvMap(allocator) catch unreachable; | 93 | env_map.* = os.getEnvMap(allocator) catch unreachable; |
| 94 | var self = Builder{ | 94 | var self = Builder{ |
| 95 | .zig_exe = zig_exe, | 95 | .zig_exe = zig_exe, |
| ... | @@ -170,7 +170,8 @@ pub const Builder = struct { | ... | @@ -170,7 +170,8 @@ pub const Builder = struct { |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | pub fn addTest(self: *Builder, root_src: []const u8) *TestStep { | 172 | pub fn addTest(self: *Builder, root_src: []const u8) *TestStep { |
| 173 | const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable; | 173 | const test_step = self.allocator.create(TestStep) catch unreachable; |
| 174 | test_step.* = TestStep.init(self, root_src); | ||
| 174 | return test_step; | 175 | return test_step; |
| 175 | } | 176 | } |
| 176 | 177 | ||
| ... | @@ -202,18 +203,21 @@ pub const Builder = struct { | ... | @@ -202,18 +203,21 @@ pub const Builder = struct { |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 204 | pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { | 205 | pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { |
| 205 | const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable; | 206 | const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; |
| 207 | write_file_step.* = WriteFileStep.init(self, file_path, data); | ||
| 206 | return write_file_step; | 208 | return write_file_step; |
| 207 | } | 209 | } |
| 208 | 210 | ||
| 209 | pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { | 211 | pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { |
| 210 | const data = self.fmt(format, args); | 212 | const data = self.fmt(format, args); |
| 211 | const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable; | 213 | const log_step = self.allocator.create(LogStep) catch unreachable; |
| 214 | log_step.* = LogStep.init(self, data); | ||
| 212 | return log_step; | 215 | return log_step; |
| 213 | } | 216 | } |
| 214 | 217 | ||
| 215 | pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { | 218 | pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { |
| 216 | const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable; | 219 | const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; |
| 220 | remove_dir_step.* = RemoveDirStep.init(self, dir_path); | ||
| 217 | return remove_dir_step; | 221 | return remove_dir_step; |
| 218 | } | 222 | } |
| 219 | 223 | ||
| ... | @@ -320,7 +324,7 @@ pub const Builder = struct { | ... | @@ -320,7 +324,7 @@ pub const Builder = struct { |
| 320 | 324 | ||
| 321 | fn processNixOSEnvVars(self: *Builder) void { | 325 | fn processNixOSEnvVars(self: *Builder) void { |
| 322 | if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { | 326 | if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { |
| 323 | var it = mem.split(nix_cflags_compile, " "); | 327 | var it = mem.tokenize(nix_cflags_compile, " "); |
| 324 | while (true) { | 328 | while (true) { |
| 325 | const word = it.next() orelse break; | 329 | const word = it.next() orelse break; |
| 326 | if (mem.eql(u8, word, "-isystem")) { | 330 | if (mem.eql(u8, word, "-isystem")) { |
| ... | @@ -338,7 +342,7 @@ pub const Builder = struct { | ... | @@ -338,7 +342,7 @@ pub const Builder = struct { |
| 338 | assert(err == error.EnvironmentVariableNotFound); | 342 | assert(err == error.EnvironmentVariableNotFound); |
| 339 | } | 343 | } |
| 340 | if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { | 344 | if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { |
| 341 | var it = mem.split(nix_ldflags, " "); | 345 | var it = mem.tokenize(nix_ldflags, " "); |
| 342 | while (true) { | 346 | while (true) { |
| 343 | const word = it.next() orelse break; | 347 | const word = it.next() orelse break; |
| 344 | if (mem.eql(u8, word, "-rpath")) { | 348 | if (mem.eql(u8, word, "-rpath")) { |
| ... | @@ -414,10 +418,11 @@ pub const Builder = struct { | ... | @@ -414,10 +418,11 @@ pub const Builder = struct { |
| 414 | } | 418 | } |
| 415 | 419 | ||
| 416 | pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { | 420 | pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { |
| 417 | const step_info = self.allocator.create(TopLevelStep{ | 421 | const step_info = self.allocator.create(TopLevelStep) catch unreachable; |
| 422 | step_info.* = TopLevelStep{ | ||
| 418 | .step = Step.initNoOp(name, self.allocator), | 423 | .step = Step.initNoOp(name, self.allocator), |
| 419 | .description = description, | 424 | .description = description, |
| 420 | }) catch unreachable; | 425 | }; |
| 421 | self.top_level_steps.append(step_info) catch unreachable; | 426 | self.top_level_steps.append(step_info) catch unreachable; |
| 422 | return &step_info.step; | 427 | return &step_info.step; |
| 423 | } | 428 | } |
| ... | @@ -616,7 +621,8 @@ pub const Builder = struct { | ... | @@ -616,7 +621,8 @@ pub const Builder = struct { |
| 616 | const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable; | 621 | const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable; |
| 617 | self.pushInstalledFile(full_dest_path); | 622 | self.pushInstalledFile(full_dest_path); |
| 618 | 623 | ||
| 619 | const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable; | 624 | const install_step = self.allocator.create(InstallFileStep) catch unreachable; |
| 625 | install_step.* = InstallFileStep.init(self, src_path, full_dest_path); | ||
| 620 | return install_step; | 626 | return install_step; |
| 621 | } | 627 | } |
| 622 | 628 | ||
| ... | @@ -683,7 +689,7 @@ pub const Builder = struct { | ... | @@ -683,7 +689,7 @@ pub const Builder = struct { |
| 683 | if (os.path.isAbsolute(name)) { | 689 | if (os.path.isAbsolute(name)) { |
| 684 | return name; | 690 | return name; |
| 685 | } | 691 | } |
| 686 | var it = mem.split(PATH, []u8{os.path.delimiter}); | 692 | var it = mem.tokenize(PATH, []u8{os.path.delimiter}); |
| 687 | while (it.next()) |path| { | 693 | while (it.next()) |path| { |
| 688 | const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); | 694 | const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); |
| 689 | if (os.path.real(self.allocator, full_path)) |real_path| { | 695 | if (os.path.real(self.allocator, full_path)) |real_path| { |
| ... | @@ -865,43 +871,51 @@ pub const LibExeObjStep = struct { | ... | @@ -865,43 +871,51 @@ pub const LibExeObjStep = struct { |
| 865 | }; | 871 | }; |
| 866 | 872 | ||
| 867 | pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { | 873 | pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { |
| 868 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable; | 874 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 875 | self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver); | ||
| 869 | return self; | 876 | return self; |
| 870 | } | 877 | } |
| 871 | 878 | ||
| 872 | pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep { | 879 | pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep { |
| 873 | const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable; | 880 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 881 | self.* = initC(builder, name, Kind.Lib, version, false); | ||
| 874 | return self; | 882 | return self; |
| 875 | } | 883 | } |
| 876 | 884 | ||
| 877 | pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { | 885 | pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { |
| 878 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable; | 886 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 887 | self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0)); | ||
| 879 | return self; | 888 | return self; |
| 880 | } | 889 | } |
| 881 | 890 | ||
| 882 | pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep { | 891 | pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep { |
| 883 | const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable; | 892 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 893 | self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true); | ||
| 884 | return self; | 894 | return self; |
| 885 | } | 895 | } |
| 886 | 896 | ||
| 887 | pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { | 897 | pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { |
| 888 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable; | 898 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 899 | self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); | ||
| 889 | return self; | 900 | return self; |
| 890 | } | 901 | } |
| 891 | 902 | ||
| 892 | pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { | 903 | pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { |
| 893 | const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable; | 904 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 905 | self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false); | ||
| 894 | self.object_src = src; | 906 | self.object_src = src; |
| 895 | return self; | 907 | return self; |
| 896 | } | 908 | } |
| 897 | 909 | ||
| 898 | pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { | 910 | pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { |
| 899 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable; | 911 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 912 | self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0)); | ||
| 900 | return self; | 913 | return self; |
| 901 | } | 914 | } |
| 902 | 915 | ||
| 903 | pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep { | 916 | pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep { |
| 904 | const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable; | 917 | const self = builder.allocator.create(LibExeObjStep) catch unreachable; |
| 918 | self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false); | ||
| 905 | return self; | 919 | return self; |
| 906 | } | 920 | } |
| 907 | 921 | ||
| ... | @@ -1914,13 +1928,14 @@ pub const CommandStep = struct { | ... | @@ -1914,13 +1928,14 @@ pub const CommandStep = struct { |
| 1914 | 1928 | ||
| 1915 | /// ::argv is copied. | 1929 | /// ::argv is copied. |
| 1916 | pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep { | 1930 | pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep { |
| 1917 | const self = builder.allocator.create(CommandStep{ | 1931 | const self = builder.allocator.create(CommandStep) catch unreachable; |
| 1932 | self.* = CommandStep{ | ||
| 1918 | .builder = builder, | 1933 | .builder = builder, |
| 1919 | .step = Step.init(argv[0], builder.allocator, make), | 1934 | .step = Step.init(argv[0], builder.allocator, make), |
| 1920 | .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable, | 1935 | .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable, |
| 1921 | .cwd = cwd, | 1936 | .cwd = cwd, |
| 1922 | .env_map = env_map, | 1937 | .env_map = env_map, |
| 1923 | }) catch unreachable; | 1938 | }; |
| 1924 | 1939 | ||
| 1925 | mem.copy([]const u8, self.argv, argv); | 1940 | mem.copy([]const u8, self.argv, argv); |
| 1926 | self.step.name = self.argv[0]; | 1941 | self.step.name = self.argv[0]; |
| ... | @@ -1949,12 +1964,13 @@ const InstallArtifactStep = struct { | ... | @@ -1949,12 +1964,13 @@ const InstallArtifactStep = struct { |
| 1949 | LibExeObjStep.Kind.Exe => builder.exe_dir, | 1964 | LibExeObjStep.Kind.Exe => builder.exe_dir, |
| 1950 | LibExeObjStep.Kind.Lib => builder.lib_dir, | 1965 | LibExeObjStep.Kind.Lib => builder.lib_dir, |
| 1951 | }; | 1966 | }; |
| 1952 | const self = builder.allocator.create(Self{ | 1967 | const self = builder.allocator.create(Self) catch unreachable; |
| 1968 | self.* = Self{ | ||
| 1953 | .builder = builder, | 1969 | .builder = builder, |
| 1954 | .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), | 1970 | .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), |
| 1955 | .artifact = artifact, | 1971 | .artifact = artifact, |
| 1956 | .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, | 1972 | .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, |
| 1957 | }) catch unreachable; | 1973 | }; |
| 1958 | self.step.dependOn(&artifact.step); | 1974 | self.step.dependOn(&artifact.step); |
| 1959 | builder.pushInstalledFile(self.dest_file); | 1975 | builder.pushInstalledFile(self.dest_file); |
| 1960 | if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { | 1976 | if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { |
std/c/darwin.zig+20-2| ... | @@ -73,8 +73,8 @@ pub const sockaddr_in6 = extern struct { | ... | @@ -73,8 +73,8 @@ pub const sockaddr_in6 = extern struct { |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | pub const timeval = extern struct { | 75 | pub const timeval = extern struct { |
| 76 | tv_sec: isize, | 76 | tv_sec: c_long, |
| 77 | tv_usec: isize, | 77 | tv_usec: i32, |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | pub const timezone = extern struct { | 80 | pub const timezone = extern struct { |
| ... | @@ -176,6 +176,24 @@ pub const kevent64_s = extern struct { | ... | @@ -176,6 +176,24 @@ pub const kevent64_s = extern struct { |
| 176 | ext: [2]u64, | 176 | ext: [2]u64, |
| 177 | }; | 177 | }; |
| 178 | 178 | ||
| 179 | pub const mach_port_t = c_uint; | ||
| 180 | pub const clock_serv_t = mach_port_t; | ||
| 181 | pub const clock_res_t = c_int; | ||
| 182 | pub const mach_port_name_t = natural_t; | ||
| 183 | pub const natural_t = c_uint; | ||
| 184 | pub const mach_timespec_t = extern struct { | ||
| 185 | tv_sec: c_uint, | ||
| 186 | tv_nsec: clock_res_t, | ||
| 187 | }; | ||
| 188 | pub const kern_return_t = c_int; | ||
| 189 | pub const host_t = mach_port_t; | ||
| 190 | pub const CALENDAR_CLOCK = 1; | ||
| 191 | |||
| 192 | pub extern fn mach_host_self() mach_port_t; | ||
| 193 | pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t; | ||
| 194 | pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t; | ||
| 195 | pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t; | ||
| 196 | |||
| 179 | // sys/types.h on macos uses #pragma pack() so these checks are | 197 | // sys/types.h on macos uses #pragma pack() so these checks are |
| 180 | // to make sure the struct is laid out the same. These values were | 198 | // to make sure the struct is laid out the same. These values were |
| 181 | // produced from C code using the offsetof macro. | 199 | // produced from C code using the offsetof macro. |
std/c/index.zig+1-1| ... | @@ -44,7 +44,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int; | ... | @@ -44,7 +44,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int; |
| 44 | pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; | 44 | pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 45 | pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; | 45 | pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; |
| 46 | pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; | 46 | pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; |
| 47 | pub extern "c" fn gettimeofday(tv: ?*timeval, tz: ?*timezone) c_int; | 47 | pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; |
| 48 | pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; | 48 | pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; |
| 49 | pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; | 49 | pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; |
| 50 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; | 50 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; |
std/debug/index.zig+4-3| ... | @@ -751,7 +751,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -751,7 +751,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { |
| 751 | const self_file = try os.openSelfExe(); | 751 | const self_file = try os.openSelfExe(); |
| 752 | defer self_file.close(); | 752 | defer self_file.close(); |
| 753 | 753 | ||
| 754 | const coff_obj = try allocator.createOne(coff.Coff); | 754 | const coff_obj = try allocator.create(coff.Coff); |
| 755 | coff_obj.* = coff.Coff{ | 755 | coff_obj.* = coff.Coff{ |
| 756 | .in_file = self_file, | 756 | .in_file = self_file, |
| 757 | .allocator = allocator, | 757 | .allocator = allocator, |
| ... | @@ -1036,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -1036,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1036 | } | 1036 | } |
| 1037 | } | 1037 | } |
| 1038 | } | 1038 | } |
| 1039 | const sentinel = try allocator.createOne(macho.nlist_64); | 1039 | const sentinel = try allocator.create(macho.nlist_64); |
| 1040 | sentinel.* = macho.nlist_64{ | 1040 | sentinel.* = macho.nlist_64{ |
| 1041 | .n_strx = 0, | 1041 | .n_strx = 0, |
| 1042 | .n_type = 36, | 1042 | .n_type = 36, |
| ... | @@ -1949,7 +1949,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { | ... | @@ -1949,7 +1949,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 1949 | 1949 | ||
| 1950 | try di.dwarf_seekable_stream.seekTo(compile_unit_pos); | 1950 | try di.dwarf_seekable_stream.seekTo(compile_unit_pos); |
| 1951 | 1951 | ||
| 1952 | const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64)); | 1952 | const compile_unit_die = try di.allocator().create(Die); |
| 1953 | compile_unit_die.* = try parseDie(di, abbrev_table, is_64); | ||
| 1953 | 1954 | ||
| 1954 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; | 1955 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; |
| 1955 | 1956 |
std/event/channel.zig+6-2| ... | @@ -54,7 +54,8 @@ pub fn Channel(comptime T: type) type { | ... | @@ -54,7 +54,8 @@ pub fn Channel(comptime T: type) type { |
| 54 | const buffer_nodes = try loop.allocator.alloc(T, capacity); | 54 | const buffer_nodes = try loop.allocator.alloc(T, capacity); |
| 55 | errdefer loop.allocator.free(buffer_nodes); | 55 | errdefer loop.allocator.free(buffer_nodes); |
| 56 | 56 | ||
| 57 | const self = try loop.allocator.create(SelfChannel{ | 57 | const self = try loop.allocator.create(SelfChannel); |
| 58 | self.* = SelfChannel{ | ||
| 58 | .loop = loop, | 59 | .loop = loop, |
| 59 | .buffer_len = 0, | 60 | .buffer_len = 0, |
| 60 | .buffer_nodes = buffer_nodes, | 61 | .buffer_nodes = buffer_nodes, |
| ... | @@ -66,7 +67,7 @@ pub fn Channel(comptime T: type) type { | ... | @@ -66,7 +67,7 @@ pub fn Channel(comptime T: type) type { |
| 66 | .or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(), | 67 | .or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(), |
| 67 | .get_count = 0, | 68 | .get_count = 0, |
| 68 | .put_count = 0, | 69 | .put_count = 0, |
| 69 | }); | 70 | }; |
| 70 | errdefer loop.allocator.destroy(self); | 71 | errdefer loop.allocator.destroy(self); |
| 71 | 72 | ||
| 72 | return self; | 73 | return self; |
| ... | @@ -319,6 +320,9 @@ pub fn Channel(comptime T: type) type { | ... | @@ -319,6 +320,9 @@ pub fn Channel(comptime T: type) type { |
| 319 | } | 320 | } |
| 320 | 321 | ||
| 321 | test "std.event.Channel" { | 322 | test "std.event.Channel" { |
| 323 | // https://github.com/ziglang/zig/issues/1908 | ||
| 324 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 325 | |||
| 322 | var da = std.heap.DirectAllocator.init(); | 326 | var da = std.heap.DirectAllocator.init(); |
| 323 | defer da.deinit(); | 327 | defer da.deinit(); |
| 324 | 328 |
std/event/fs.zig+27-30| ... | @@ -495,7 +495,7 @@ pub const CloseOperation = struct { | ... | @@ -495,7 +495,7 @@ pub const CloseOperation = struct { |
| 495 | }; | 495 | }; |
| 496 | 496 | ||
| 497 | pub fn start(loop: *Loop) (error{OutOfMemory}!*CloseOperation) { | 497 | pub fn start(loop: *Loop) (error{OutOfMemory}!*CloseOperation) { |
| 498 | const self = try loop.allocator.createOne(CloseOperation); | 498 | const self = try loop.allocator.create(CloseOperation); |
| 499 | self.* = CloseOperation{ | 499 | self.* = CloseOperation{ |
| 500 | .loop = loop, | 500 | .loop = loop, |
| 501 | .os_data = switch (builtin.os) { | 501 | .os_data = switch (builtin.os) { |
| ... | @@ -787,7 +787,7 @@ pub fn Watch(comptime V: type) type { | ... | @@ -787,7 +787,7 @@ pub fn Watch(comptime V: type) type { |
| 787 | }, | 787 | }, |
| 788 | 788 | ||
| 789 | builtin.Os.windows => { | 789 | builtin.Os.windows => { |
| 790 | const self = try loop.allocator.createOne(Self); | 790 | const self = try loop.allocator.create(Self); |
| 791 | errdefer loop.allocator.destroy(self); | 791 | errdefer loop.allocator.destroy(self); |
| 792 | self.* = Self{ | 792 | self.* = Self{ |
| 793 | .channel = channel, | 793 | .channel = channel, |
| ... | @@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type { | ... | @@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type { |
| 802 | }, | 802 | }, |
| 803 | 803 | ||
| 804 | builtin.Os.macosx, builtin.Os.freebsd => { | 804 | builtin.Os.macosx, builtin.Os.freebsd => { |
| 805 | const self = try loop.allocator.createOne(Self); | 805 | const self = try loop.allocator.create(Self); |
| 806 | errdefer loop.allocator.destroy(self); | 806 | errdefer loop.allocator.destroy(self); |
| 807 | 807 | ||
| 808 | self.* = Self{ | 808 | self.* = Self{ |
| ... | @@ -1068,7 +1068,7 @@ pub fn Watch(comptime V: type) type { | ... | @@ -1068,7 +1068,7 @@ pub fn Watch(comptime V: type) type { |
| 1068 | } | 1068 | } |
| 1069 | } else { | 1069 | } else { |
| 1070 | errdefer _ = self.os_data.dir_table.remove(dirname); | 1070 | errdefer _ = self.os_data.dir_table.remove(dirname); |
| 1071 | const dir = try self.channel.loop.allocator.createOne(OsData.Dir); | 1071 | const dir = try self.channel.loop.allocator.create(OsData.Dir); |
| 1072 | errdefer self.channel.loop.allocator.destroy(dir); | 1072 | errdefer self.channel.loop.allocator.destroy(dir); |
| 1073 | 1073 | ||
| 1074 | dir.* = OsData.Dir{ | 1074 | dir.* = OsData.Dir{ |
| ... | @@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type { | ... | @@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type { |
| 1307 | 1307 | ||
| 1308 | const test_tmp_dir = "std_event_fs_test"; | 1308 | const test_tmp_dir = "std_event_fs_test"; |
| 1309 | 1309 | ||
| 1310 | test "write a file, watch it, write it again" { | 1310 | // TODO this test is disabled until the coroutine rewrite is finished. |
| 1311 | if (builtin.os == builtin.Os.windows) { | 1311 | //test "write a file, watch it, write it again" { |
| 1312 | // TODO this test is disabled on windows until the coroutine rewrite is finished. | 1312 | // return error.SkipZigTest; |
| 1313 | // https://github.com/ziglang/zig/issues/1363 | 1313 | // var da = std.heap.DirectAllocator.init(); |
| 1314 | return error.SkipZigTest; | 1314 | // defer da.deinit(); |
| 1315 | } | 1315 | // |
| 1316 | var da = std.heap.DirectAllocator.init(); | 1316 | // const allocator = &da.allocator; |
| 1317 | defer da.deinit(); | 1317 | // |
| 1318 | 1318 | // // TODO move this into event loop too | |
| 1319 | const allocator = &da.allocator; | 1319 | // try os.makePath(allocator, test_tmp_dir); |
| 1320 | 1320 | // defer os.deleteTree(allocator, test_tmp_dir) catch {}; | |
| 1321 | // TODO move this into event loop too | 1321 | // |
| 1322 | try os.makePath(allocator, test_tmp_dir); | 1322 | // var loop: Loop = undefined; |
| 1323 | defer os.deleteTree(allocator, test_tmp_dir) catch {}; | 1323 | // try loop.initMultiThreaded(allocator); |
| 1324 | 1324 | // defer loop.deinit(); | |
| 1325 | var loop: Loop = undefined; | 1325 | // |
| 1326 | try loop.initMultiThreaded(allocator); | 1326 | // var result: anyerror!void = error.ResultNeverWritten; |
| 1327 | defer loop.deinit(); | 1327 | // const handle = try async<allocator> testFsWatchCantFail(&loop, &result); |
| 1328 | 1328 | // defer cancel handle; | |
| 1329 | var result: anyerror!void = error.ResultNeverWritten; | 1329 | // |
| 1330 | const handle = try async<allocator> testFsWatchCantFail(&loop, &result); | 1330 | // loop.run(); |
| 1331 | defer cancel handle; | 1331 | // return result; |
| 1332 | 1332 | //} | |
| 1333 | loop.run(); | ||
| 1334 | return result; | ||
| 1335 | } | ||
| 1336 | 1333 | ||
| 1337 | async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { | 1334 | async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { |
| 1338 | result.* = await (async testFsWatch(loop) catch unreachable); | 1335 | result.* = await (async testFsWatch(loop) catch unreachable); |
std/event/future.zig+3| ... | @@ -84,6 +84,9 @@ pub fn Future(comptime T: type) type { | ... | @@ -84,6 +84,9 @@ pub fn Future(comptime T: type) type { |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | test "std.event.Future" { | 86 | test "std.event.Future" { |
| 87 | // https://github.com/ziglang/zig/issues/1908 | ||
| 88 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 89 | |||
| 87 | var da = std.heap.DirectAllocator.init(); | 90 | var da = std.heap.DirectAllocator.init(); |
| 88 | defer da.deinit(); | 91 | defer da.deinit(); |
| 89 | 92 |
std/event/group.zig+6-2| ... | @@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type { |
| 42 | 42 | ||
| 43 | /// Add a promise to the group. Thread-safe. | 43 | /// Add a promise to the group. Thread-safe. |
| 44 | pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) { | 44 | pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) { |
| 45 | const node = try self.lock.loop.allocator.create(Stack.Node{ | 45 | const node = try self.lock.loop.allocator.create(Stack.Node); |
| 46 | node.* = Stack.Node{ | ||
| 46 | .next = undefined, | 47 | .next = undefined, |
| 47 | .data = handle, | 48 | .data = handle, |
| 48 | }); | 49 | }; |
| 49 | self.alloc_stack.push(node); | 50 | self.alloc_stack.push(node); |
| 50 | } | 51 | } |
| 51 | 52 | ||
| ... | @@ -121,6 +122,9 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -121,6 +122,9 @@ pub fn Group(comptime ReturnType: type) type { |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 123 | test "std.event.Group" { | 124 | test "std.event.Group" { |
| 125 | // https://github.com/ziglang/zig/issues/1908 | ||
| 126 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 127 | |||
| 124 | var da = std.heap.DirectAllocator.init(); | 128 | var da = std.heap.DirectAllocator.init(); |
| 125 | defer da.deinit(); | 129 | defer da.deinit(); |
| 126 | 130 |
std/event/lock.zig+3| ... | @@ -122,6 +122,9 @@ pub const Lock = struct { | ... | @@ -122,6 +122,9 @@ pub const Lock = struct { |
| 122 | }; | 122 | }; |
| 123 | 123 | ||
| 124 | test "std.event.Lock" { | 124 | test "std.event.Lock" { |
| 125 | // https://github.com/ziglang/zig/issues/1908 | ||
| 126 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 127 | |||
| 125 | var da = std.heap.DirectAllocator.init(); | 128 | var da = std.heap.DirectAllocator.init(); |
| 126 | defer da.deinit(); | 129 | defer da.deinit(); |
| 127 | 130 |
std/event/loop.zig+22| ... | @@ -97,6 +97,7 @@ pub const Loop = struct { | ... | @@ -97,6 +97,7 @@ pub const Loop = struct { |
| 97 | /// TODO copy elision / named return values so that the threads referencing *Loop | 97 | /// TODO copy elision / named return values so that the threads referencing *Loop |
| 98 | /// have the correct pointer value. | 98 | /// have the correct pointer value. |
| 99 | pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void { | 99 | pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void { |
| 100 | if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode"); | ||
| 100 | const core_count = try os.cpuCount(allocator); | 101 | const core_count = try os.cpuCount(allocator); |
| 101 | return self.initInternal(allocator, core_count); | 102 | return self.initInternal(allocator, core_count); |
| 102 | } | 103 | } |
| ... | @@ -201,6 +202,11 @@ pub const Loop = struct { | ... | @@ -201,6 +202,11 @@ pub const Loop = struct { |
| 201 | self.os_data.fs_thread.wait(); | 202 | self.os_data.fs_thread.wait(); |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 205 | if (builtin.single_threaded) { | ||
| 206 | assert(extra_thread_count == 0); | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | |||
| 204 | var extra_thread_index: usize = 0; | 210 | var extra_thread_index: usize = 0; |
| 205 | errdefer { | 211 | errdefer { |
| 206 | // writing 8 bytes to an eventfd cannot fail | 212 | // writing 8 bytes to an eventfd cannot fail |
| ... | @@ -301,6 +307,11 @@ pub const Loop = struct { | ... | @@ -301,6 +307,11 @@ pub const Loop = struct { |
| 301 | self.os_data.fs_thread.wait(); | 307 | self.os_data.fs_thread.wait(); |
| 302 | } | 308 | } |
| 303 | 309 | ||
| 310 | if (builtin.single_threaded) { | ||
| 311 | assert(extra_thread_count == 0); | ||
| 312 | return; | ||
| 313 | } | ||
| 314 | |||
| 304 | var extra_thread_index: usize = 0; | 315 | var extra_thread_index: usize = 0; |
| 305 | errdefer { | 316 | errdefer { |
| 306 | _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable; | 317 | _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable; |
| ... | @@ -338,6 +349,11 @@ pub const Loop = struct { | ... | @@ -338,6 +349,11 @@ pub const Loop = struct { |
| 338 | self.available_eventfd_resume_nodes.push(eventfd_node); | 349 | self.available_eventfd_resume_nodes.push(eventfd_node); |
| 339 | } | 350 | } |
| 340 | 351 | ||
| 352 | if (builtin.single_threaded) { | ||
| 353 | assert(extra_thread_count == 0); | ||
| 354 | return; | ||
| 355 | } | ||
| 356 | |||
| 341 | var extra_thread_index: usize = 0; | 357 | var extra_thread_index: usize = 0; |
| 342 | errdefer { | 358 | errdefer { |
| 343 | var i: usize = 0; | 359 | var i: usize = 0; |
| ... | @@ -845,6 +861,9 @@ pub const Loop = struct { | ... | @@ -845,6 +861,9 @@ pub const Loop = struct { |
| 845 | }; | 861 | }; |
| 846 | 862 | ||
| 847 | test "std.event.Loop - basic" { | 863 | test "std.event.Loop - basic" { |
| 864 | // https://github.com/ziglang/zig/issues/1908 | ||
| 865 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 866 | |||
| 848 | var da = std.heap.DirectAllocator.init(); | 867 | var da = std.heap.DirectAllocator.init(); |
| 849 | defer da.deinit(); | 868 | defer da.deinit(); |
| 850 | 869 | ||
| ... | @@ -858,6 +877,9 @@ test "std.event.Loop - basic" { | ... | @@ -858,6 +877,9 @@ test "std.event.Loop - basic" { |
| 858 | } | 877 | } |
| 859 | 878 | ||
| 860 | test "std.event.Loop - call" { | 879 | test "std.event.Loop - call" { |
| 880 | // https://github.com/ziglang/zig/issues/1908 | ||
| 881 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 882 | |||
| 861 | var da = std.heap.DirectAllocator.init(); | 883 | var da = std.heap.DirectAllocator.init(); |
| 862 | defer da.deinit(); | 884 | defer da.deinit(); |
| 863 | 885 |
std/event/net.zig+3| ... | @@ -269,6 +269,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File { | ... | @@ -269,6 +269,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File { |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | test "listen on a port, send bytes, receive bytes" { | 271 | test "listen on a port, send bytes, receive bytes" { |
| 272 | // https://github.com/ziglang/zig/issues/1908 | ||
| 273 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 274 | |||
| 272 | if (builtin.os != builtin.Os.linux) { | 275 | if (builtin.os != builtin.Os.linux) { |
| 273 | // TODO build abstractions for other operating systems | 276 | // TODO build abstractions for other operating systems |
| 274 | return error.SkipZigTest; | 277 | return error.SkipZigTest; |
std/event/rwlock.zig+3| ... | @@ -211,6 +211,9 @@ pub const RwLock = struct { | ... | @@ -211,6 +211,9 @@ pub const RwLock = struct { |
| 211 | }; | 211 | }; |
| 212 | 212 | ||
| 213 | test "std.event.RwLock" { | 213 | test "std.event.RwLock" { |
| 214 | // https://github.com/ziglang/zig/issues/1908 | ||
| 215 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 216 | |||
| 214 | var da = std.heap.DirectAllocator.init(); | 217 | var da = std.heap.DirectAllocator.init(); |
| 215 | defer da.deinit(); | 218 | defer da.deinit(); |
| 216 | 219 |
std/fmt/index.zig-2| ... | @@ -982,13 +982,11 @@ test "fmt.format" { | ... | @@ -982,13 +982,11 @@ test "fmt.format" { |
| 982 | context = BufPrintContext{ .remaining = buf1[0..] }; | 982 | context = BufPrintContext{ .remaining = buf1[0..] }; |
| 983 | try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); | 983 | try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); |
| 984 | res = buf1[0 .. buf1.len - context.remaining.len]; | 984 | res = buf1[0 .. buf1.len - context.remaining.len]; |
| 985 | debug.warn("{}\n", res); | ||
| 986 | assert(mem.eql(u8, res, "a")); | 985 | assert(mem.eql(u8, res, "a")); |
| 987 | 986 | ||
| 988 | context = BufPrintContext{ .remaining = buf1[0..] }; | 987 | context = BufPrintContext{ .remaining = buf1[0..] }; |
| 989 | try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); | 988 | try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); |
| 990 | res = buf1[0 .. buf1.len - context.remaining.len]; | 989 | res = buf1[0 .. buf1.len - context.remaining.len]; |
| 991 | debug.warn("{}\n", res); | ||
| 992 | assert(mem.eql(u8, res, "1100")); | 990 | assert(mem.eql(u8, res, "1100")); |
| 993 | } | 991 | } |
| 994 | { | 992 | { |
std/hash_map.zig+2| ... | @@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type | ... | @@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type |
| 508 | 508 | ||
| 509 | builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), | 509 | builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), |
| 510 | builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), | 510 | builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), |
| 511 | builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"), | ||
| 511 | builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), | 512 | builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), |
| 512 | builtin.TypeId.Union => @compileError("TODO auto hash for unions"), | 513 | builtin.TypeId.Union => @compileError("TODO auto hash for unions"), |
| 513 | builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), | 514 | builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), |
| ... | @@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { | ... | @@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { |
| 555 | builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), | 556 | builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), |
| 556 | builtin.TypeId.Union => @compileError("TODO auto eql for unions"), | 557 | builtin.TypeId.Union => @compileError("TODO auto eql for unions"), |
| 557 | builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"), | 558 | builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"), |
| 559 | builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"), | ||
| 558 | } | 560 | } |
| 559 | } | 561 | } |
std/heap.zig+2-1| ... | @@ -518,7 +518,8 @@ fn testAllocator(allocator: *mem.Allocator) !void { | ... | @@ -518,7 +518,8 @@ fn testAllocator(allocator: *mem.Allocator) !void { |
| 518 | var slice = try allocator.alloc(*i32, 100); | 518 | var slice = try allocator.alloc(*i32, 100); |
| 519 | assert(slice.len == 100); | 519 | assert(slice.len == 100); |
| 520 | for (slice) |*item, i| { | 520 | for (slice) |*item, i| { |
| 521 | item.* = try allocator.create(@intCast(i32, i)); | 521 | item.* = try allocator.create(i32); |
| 522 | item.*.* = @intCast(i32, i); | ||
| 522 | } | 523 | } |
| 523 | 524 | ||
| 524 | slice = try allocator.realloc(*i32, slice, 20000); | 525 | slice = try allocator.realloc(*i32, slice, 20000); |
std/index.zig+2| ... | @@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib; | ... | @@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 9 | pub const HashMap = @import("hash_map.zig").HashMap; | 9 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; | 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; |
| 11 | pub const Mutex = @import("mutex.zig").Mutex; | 11 | pub const Mutex = @import("mutex.zig").Mutex; |
| 12 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; | ||
| 12 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; | 13 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 13 | pub const SpinLock = @import("spinlock.zig").SpinLock; | 14 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 14 | 15 | ||
| ... | @@ -55,6 +56,7 @@ test "std" { | ... | @@ -55,6 +56,7 @@ test "std" { |
| 55 | _ = @import("hash_map.zig"); | 56 | _ = @import("hash_map.zig"); |
| 56 | _ = @import("linked_list.zig"); | 57 | _ = @import("linked_list.zig"); |
| 57 | _ = @import("mutex.zig"); | 58 | _ = @import("mutex.zig"); |
| 59 | _ = @import("statically_initialized_mutex.zig"); | ||
| 58 | _ = @import("segmented_list.zig"); | 60 | _ = @import("segmented_list.zig"); |
| 59 | _ = @import("spinlock.zig"); | 61 | _ = @import("spinlock.zig"); |
| 60 | 62 |
std/io.zig+654-13| ... | @@ -8,6 +8,8 @@ const debug = std.debug; | ... | @@ -8,6 +8,8 @@ const debug = std.debug; |
| 8 | const assert = debug.assert; | 8 | const assert = debug.assert; |
| 9 | const os = std.os; | 9 | const os = std.os; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const meta = std.meta; | ||
| 12 | const trait = meta.trait; | ||
| 11 | const Buffer = std.Buffer; | 13 | const Buffer = std.Buffer; |
| 12 | const fmt = std.fmt; | 14 | const fmt = std.fmt; |
| 13 | const File = std.os.File; | 15 | const File = std.os.File; |
| ... | @@ -463,6 +465,153 @@ pub const SliceInStream = struct { | ... | @@ -463,6 +465,153 @@ pub const SliceInStream = struct { |
| 463 | } | 465 | } |
| 464 | }; | 466 | }; |
| 465 | 467 | ||
| 468 | /// Creates a stream which allows for reading bit fields from another stream | ||
| 469 | pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { | ||
| 470 | return struct { | ||
| 471 | const Self = @This(); | ||
| 472 | |||
| 473 | in_stream: *Stream, | ||
| 474 | bit_buffer: u7, | ||
| 475 | bit_count: u3, | ||
| 476 | stream: Stream, | ||
| 477 | |||
| 478 | pub const Stream = InStream(Error); | ||
| 479 | const u8_bit_count = comptime meta.bitCount(u8); | ||
| 480 | const u7_bit_count = comptime meta.bitCount(u7); | ||
| 481 | const u4_bit_count = comptime meta.bitCount(u4); | ||
| 482 | |||
| 483 | pub fn init(in_stream: *Stream) Self { | ||
| 484 | return Self{ | ||
| 485 | .in_stream = in_stream, | ||
| 486 | .bit_buffer = 0, | ||
| 487 | .bit_count = 0, | ||
| 488 | .stream = Stream{ .readFn = read }, | ||
| 489 | }; | ||
| 490 | } | ||
| 491 | |||
| 492 | /// Reads `bits` bits from the stream and returns a specified unsigned int type | ||
| 493 | /// containing them in the least significant end, returning an error if the | ||
| 494 | /// specified number of bits could not be read. | ||
| 495 | pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U { | ||
| 496 | var n: usize = undefined; | ||
| 497 | const result = try self.readBits(U, bits, &n); | ||
| 498 | if (n < bits) return error.EndOfStream; | ||
| 499 | return result; | ||
| 500 | } | ||
| 501 | |||
| 502 | /// Reads `bits` bits from the stream and returns a specified unsigned int type | ||
| 503 | /// containing them in the least significant end. The number of bits successfully | ||
| 504 | /// read is placed in `out_bits`, as reaching the end of the stream is not an error. | ||
| 505 | pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U { | ||
| 506 | comptime assert(trait.isUnsignedInt(U)); | ||
| 507 | |||
| 508 | //by extending the buffer to a minimum of u8 we can cover a number of edge cases | ||
| 509 | // related to shifting and casting. | ||
| 510 | const u_bit_count = comptime meta.bitCount(U); | ||
| 511 | const buf_bit_count = bc: { | ||
| 512 | assert(u_bit_count >= bits); | ||
| 513 | break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; | ||
| 514 | }; | ||
| 515 | const Buf = @IntType(false, buf_bit_count); | ||
| 516 | const BufShift = math.Log2Int(Buf); | ||
| 517 | |||
| 518 | out_bits.* = usize(0); | ||
| 519 | if (U == u0 or bits == 0) return 0; | ||
| 520 | var out_buffer = Buf(0); | ||
| 521 | |||
| 522 | if (self.bit_count > 0) { | ||
| 523 | const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count; | ||
| 524 | const shift = u7_bit_count - n; | ||
| 525 | switch (endian) { | ||
| 526 | builtin.Endian.Big => { | ||
| 527 | out_buffer = Buf(self.bit_buffer >> shift); | ||
| 528 | self.bit_buffer <<= n; | ||
| 529 | }, | ||
| 530 | builtin.Endian.Little => { | ||
| 531 | const value = (self.bit_buffer << shift) >> shift; | ||
| 532 | out_buffer = Buf(value); | ||
| 533 | self.bit_buffer >>= n; | ||
| 534 | }, | ||
| 535 | } | ||
| 536 | self.bit_count -= n; | ||
| 537 | out_bits.* = n; | ||
| 538 | } | ||
| 539 | //at this point we know bit_buffer is empty | ||
| 540 | |||
| 541 | //copy bytes until we have enough bits, then leave the rest in bit_buffer | ||
| 542 | while (out_bits.* < bits) { | ||
| 543 | const n = bits - out_bits.*; | ||
| 544 | const next_byte = self.in_stream.readByte() catch |err| { | ||
| 545 | if (err == error.EndOfStream) { | ||
| 546 | return @intCast(U, out_buffer); | ||
| 547 | } | ||
| 548 | //@BUG: See #1810. Not sure if the bug is that I have to do this for some | ||
| 549 | // streams, or that I don't for streams with emtpy errorsets. | ||
| 550 | return @errSetCast(Error, err); | ||
| 551 | }; | ||
| 552 | |||
| 553 | switch (endian) { | ||
| 554 | builtin.Endian.Big => { | ||
| 555 | if (n >= u8_bit_count) { | ||
| 556 | out_buffer <<= @intCast(u3, u8_bit_count - 1); | ||
| 557 | out_buffer <<= 1; | ||
| 558 | out_buffer |= Buf(next_byte); | ||
| 559 | out_bits.* += u8_bit_count; | ||
| 560 | continue; | ||
| 561 | } | ||
| 562 | |||
| 563 | const shift = @intCast(u3, u8_bit_count - n); | ||
| 564 | out_buffer <<= @intCast(BufShift, n); | ||
| 565 | out_buffer |= Buf(next_byte >> shift); | ||
| 566 | out_bits.* += n; | ||
| 567 | self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1)); | ||
| 568 | self.bit_count = shift; | ||
| 569 | }, | ||
| 570 | builtin.Endian.Little => { | ||
| 571 | if (n >= u8_bit_count) { | ||
| 572 | out_buffer |= Buf(next_byte) << @intCast(BufShift, out_bits.*); | ||
| 573 | out_bits.* += u8_bit_count; | ||
| 574 | continue; | ||
| 575 | } | ||
| 576 | |||
| 577 | const shift = @intCast(u3, u8_bit_count - n); | ||
| 578 | const value = (next_byte << shift) >> shift; | ||
| 579 | out_buffer |= Buf(value) << @intCast(BufShift, out_bits.*); | ||
| 580 | out_bits.* += n; | ||
| 581 | self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n)); | ||
| 582 | self.bit_count = shift; | ||
| 583 | }, | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | return @intCast(U, out_buffer); | ||
| 588 | } | ||
| 589 | |||
| 590 | pub fn alignToByte(self: *Self) void { | ||
| 591 | self.bit_buffer = 0; | ||
| 592 | self.bit_count = 0; | ||
| 593 | } | ||
| 594 | |||
| 595 | pub fn read(self_stream: *Stream, buffer: []u8) Error!usize { | ||
| 596 | var self = @fieldParentPtr(Self, "stream", self_stream); | ||
| 597 | |||
| 598 | var out_bits: usize = undefined; | ||
| 599 | var out_bits_total = usize(0); | ||
| 600 | //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced | ||
| 601 | if (self.bit_count > 0) { | ||
| 602 | for (buffer) |*b, i| { | ||
| 603 | b.* = try self.readBits(u8, u8_bit_count, &out_bits); | ||
| 604 | out_bits_total += out_bits; | ||
| 605 | } | ||
| 606 | const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0); | ||
| 607 | return (out_bits_total / u8_bit_count) + incomplete_byte; | ||
| 608 | } | ||
| 609 | |||
| 610 | return self.in_stream.read(buffer); | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | } | ||
| 614 | |||
| 466 | /// This is a simple OutStream that writes to a slice, and returns an error | 615 | /// This is a simple OutStream that writes to a slice, and returns an error |
| 467 | /// when it runs out of space. | 616 | /// when it runs out of space. |
| 468 | pub const SliceOutStream = struct { | 617 | pub const SliceOutStream = struct { |
| ... | @@ -515,7 +664,7 @@ test "io.SliceOutStream" { | ... | @@ -515,7 +664,7 @@ test "io.SliceOutStream" { |
| 515 | const stream = &slice_stream.stream; | 664 | const stream = &slice_stream.stream; |
| 516 | 665 | ||
| 517 | try stream.print("{}{}!", "Hello", "World"); | 666 | try stream.print("{}{}!", "Hello", "World"); |
| 518 | debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); | 667 | debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); |
| 519 | } | 668 | } |
| 520 | 669 | ||
| 521 | var null_out_stream_state = NullOutStream.init(); | 670 | var null_out_stream_state = NullOutStream.init(); |
| ... | @@ -577,7 +726,7 @@ test "io.CountingOutStream" { | ... | @@ -577,7 +726,7 @@ test "io.CountingOutStream" { |
| 577 | 726 | ||
| 578 | const bytes = "yay" ** 10000; | 727 | const bytes = "yay" ** 10000; |
| 579 | stream.write(bytes) catch unreachable; | 728 | stream.write(bytes) catch unreachable; |
| 580 | debug.assert(counting_stream.bytes_written == bytes.len); | 729 | debug.assertOrPanic(counting_stream.bytes_written == bytes.len); |
| 581 | } | 730 | } |
| 582 | 731 | ||
| 583 | pub fn BufferedOutStream(comptime Error: type) type { | 732 | pub fn BufferedOutStream(comptime Error: type) type { |
| ... | @@ -656,6 +805,137 @@ pub const BufferOutStream = struct { | ... | @@ -656,6 +805,137 @@ pub const BufferOutStream = struct { |
| 656 | } | 805 | } |
| 657 | }; | 806 | }; |
| 658 | 807 | ||
| 808 | /// Creates a stream which allows for writing bit fields to another stream | ||
| 809 | pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { | ||
| 810 | return struct { | ||
| 811 | const Self = @This(); | ||
| 812 | |||
| 813 | out_stream: *Stream, | ||
| 814 | bit_buffer: u8, | ||
| 815 | bit_count: u4, | ||
| 816 | stream: Stream, | ||
| 817 | |||
| 818 | pub const Stream = OutStream(Error); | ||
| 819 | const u8_bit_count = comptime meta.bitCount(u8); | ||
| 820 | const u4_bit_count = comptime meta.bitCount(u4); | ||
| 821 | |||
| 822 | pub fn init(out_stream: *Stream) Self { | ||
| 823 | return Self{ | ||
| 824 | .out_stream = out_stream, | ||
| 825 | .bit_buffer = 0, | ||
| 826 | .bit_count = 0, | ||
| 827 | .stream = Stream{ .writeFn = write }, | ||
| 828 | }; | ||
| 829 | } | ||
| 830 | |||
| 831 | /// Write the specified number of bits to the stream from the least significant bits of | ||
| 832 | /// the specified unsigned int value. Bits will only be written to the stream when there | ||
| 833 | /// are enough to fill a byte. | ||
| 834 | pub fn writeBits(self: *Self, value: var, bits: usize) Error!void { | ||
| 835 | if (bits == 0) return; | ||
| 836 | |||
| 837 | const U = @typeOf(value); | ||
| 838 | comptime assert(trait.isUnsignedInt(U)); | ||
| 839 | |||
| 840 | //by extending the buffer to a minimum of u8 we can cover a number of edge cases | ||
| 841 | // related to shifting and casting. | ||
| 842 | const u_bit_count = comptime meta.bitCount(U); | ||
| 843 | const buf_bit_count = bc: { | ||
| 844 | assert(u_bit_count >= bits); | ||
| 845 | break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; | ||
| 846 | }; | ||
| 847 | const Buf = @IntType(false, buf_bit_count); | ||
| 848 | const BufShift = math.Log2Int(Buf); | ||
| 849 | |||
| 850 | const buf_value = @intCast(Buf, value); | ||
| 851 | |||
| 852 | const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count); | ||
| 853 | var in_buffer = switch (endian) { | ||
| 854 | builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits), | ||
| 855 | builtin.Endian.Little => buf_value, | ||
| 856 | }; | ||
| 857 | var in_bits = bits; | ||
| 858 | |||
| 859 | if (self.bit_count > 0) { | ||
| 860 | const bits_remaining = u8_bit_count - self.bit_count; | ||
| 861 | const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining); | ||
| 862 | switch (endian) { | ||
| 863 | builtin.Endian.Big => { | ||
| 864 | const shift = @intCast(BufShift, high_byte_shift + self.bit_count); | ||
| 865 | const v = @intCast(u8, in_buffer >> shift); | ||
| 866 | self.bit_buffer |= v; | ||
| 867 | in_buffer <<= n; | ||
| 868 | }, | ||
| 869 | builtin.Endian.Little => { | ||
| 870 | const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count); | ||
| 871 | self.bit_buffer |= v; | ||
| 872 | in_buffer >>= n; | ||
| 873 | }, | ||
| 874 | } | ||
| 875 | self.bit_count += n; | ||
| 876 | in_bits -= n; | ||
| 877 | |||
| 878 | //if we didn't fill the buffer, it's because bits < bits_remaining; | ||
| 879 | if (self.bit_count != u8_bit_count) return; | ||
| 880 | try self.out_stream.writeByte(self.bit_buffer); | ||
| 881 | self.bit_buffer = 0; | ||
| 882 | self.bit_count = 0; | ||
| 883 | } | ||
| 884 | //at this point we know bit_buffer is empty | ||
| 885 | |||
| 886 | //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer | ||
| 887 | while (in_bits >= u8_bit_count) { | ||
| 888 | switch (endian) { | ||
| 889 | builtin.Endian.Big => { | ||
| 890 | const v = @intCast(u8, in_buffer >> high_byte_shift); | ||
| 891 | try self.out_stream.writeByte(v); | ||
| 892 | in_buffer <<= @intCast(u3, u8_bit_count - 1); | ||
| 893 | in_buffer <<= 1; | ||
| 894 | }, | ||
| 895 | builtin.Endian.Little => { | ||
| 896 | const v = @truncate(u8, in_buffer); | ||
| 897 | try self.out_stream.writeByte(v); | ||
| 898 | in_buffer >>= @intCast(u3, u8_bit_count - 1); | ||
| 899 | in_buffer >>= 1; | ||
| 900 | }, | ||
| 901 | } | ||
| 902 | in_bits -= u8_bit_count; | ||
| 903 | } | ||
| 904 | |||
| 905 | if (in_bits > 0) { | ||
| 906 | self.bit_count = @intCast(u4, in_bits); | ||
| 907 | self.bit_buffer = switch (endian) { | ||
| 908 | builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift), | ||
| 909 | builtin.Endian.Little => @truncate(u8, in_buffer), | ||
| 910 | }; | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | /// Flush any remaining bits to the stream. | ||
| 915 | pub fn flushBits(self: *Self) !void { | ||
| 916 | if (self.bit_count == 0) return; | ||
| 917 | try self.out_stream.writeByte(self.bit_buffer); | ||
| 918 | self.bit_buffer = 0; | ||
| 919 | self.bit_count = 0; | ||
| 920 | } | ||
| 921 | |||
| 922 | pub fn write(self_stream: *Stream, buffer: []const u8) Error!void { | ||
| 923 | var self = @fieldParentPtr(Self, "stream", self_stream); | ||
| 924 | |||
| 925 | //@NOTE: I'm not sure this is a good idea, maybe flushBits should be forced | ||
| 926 | if (self.bit_count > 0) { | ||
| 927 | for (buffer) |b, i| | ||
| 928 | try self.writeBits(b, u8_bit_count); | ||
| 929 | return; | ||
| 930 | } | ||
| 931 | |||
| 932 | return self.out_stream.write(buffer); | ||
| 933 | } | ||
| 934 | }; | ||
| 935 | } | ||
| 936 | |||
| 937 | |||
| 938 | |||
| 659 | pub const BufferedAtomicFile = struct { | 939 | pub const BufferedAtomicFile = struct { |
| 660 | atomic_file: os.AtomicFile, | 940 | atomic_file: os.AtomicFile, |
| 661 | file_stream: os.File.OutStream, | 941 | file_stream: os.File.OutStream, |
| ... | @@ -664,12 +944,13 @@ pub const BufferedAtomicFile = struct { | ... | @@ -664,12 +944,13 @@ pub const BufferedAtomicFile = struct { |
| 664 | 944 | ||
| 665 | pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile { | 945 | pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile { |
| 666 | // TODO with well defined copy elision we don't need this allocation | 946 | // TODO with well defined copy elision we don't need this allocation |
| 667 | var self = try allocator.create(BufferedAtomicFile{ | 947 | var self = try allocator.create(BufferedAtomicFile); |
| 948 | self.* = BufferedAtomicFile{ | ||
| 668 | .atomic_file = undefined, | 949 | .atomic_file = undefined, |
| 669 | .file_stream = undefined, | 950 | .file_stream = undefined, |
| 670 | .buffered_stream = undefined, | 951 | .buffered_stream = undefined, |
| 671 | .allocator = allocator, | 952 | .allocator = allocator, |
| 672 | }); | 953 | }; |
| 673 | errdefer allocator.destroy(self); | 954 | errdefer allocator.destroy(self); |
| 674 | 955 | ||
| 675 | self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode); | 956 | self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode); |
| ... | @@ -696,11 +977,6 @@ pub const BufferedAtomicFile = struct { | ... | @@ -696,11 +977,6 @@ pub const BufferedAtomicFile = struct { |
| 696 | } | 977 | } |
| 697 | }; | 978 | }; |
| 698 | 979 | ||
| 699 | test "import io tests" { | ||
| 700 | comptime { | ||
| 701 | _ = @import("io_test.zig"); | ||
| 702 | } | ||
| 703 | } | ||
| 704 | 980 | ||
| 705 | pub fn readLine(buf: *std.Buffer) ![]u8 { | 981 | pub fn readLine(buf: *std.Buffer) ![]u8 { |
| 706 | var stdin = try getStdIn(); | 982 | var stdin = try getStdIn(); |
| ... | @@ -738,10 +1014,10 @@ test "io.readLineFrom" { | ... | @@ -738,10 +1014,10 @@ test "io.readLineFrom" { |
| 738 | ); | 1014 | ); |
| 739 | const stream = &mem_stream.stream; | 1015 | const stream = &mem_stream.stream; |
| 740 | 1016 | ||
| 741 | debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); | 1017 | debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); |
| 742 | debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); | 1018 | debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); |
| 743 | debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); | 1019 | debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); |
| 744 | debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); | 1020 | debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); |
| 745 | } | 1021 | } |
| 746 | 1022 | ||
| 747 | pub fn readLineSlice(slice: []u8) ![]u8 { | 1023 | pub fn readLineSlice(slice: []u8) ![]u8 { |
| ... | @@ -769,6 +1045,371 @@ test "io.readLineSliceFrom" { | ... | @@ -769,6 +1045,371 @@ test "io.readLineSliceFrom" { |
| 769 | ); | 1045 | ); |
| 770 | const stream = &mem_stream.stream; | 1046 | const stream = &mem_stream.stream; |
| 771 | 1047 | ||
| 772 | debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); | 1048 | debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); |
| 773 | debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); | 1049 | debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); |
| 774 | } | 1050 | } |
| 1051 | |||
| 1052 | /// Creates a deserializer that deserializes types from any stream. | ||
| 1053 | /// If `is_packed` is true, the data stream is treated as bit-packed, | ||
| 1054 | /// otherwise data is expected to be packed to the smallest byte. | ||
| 1055 | /// Types may implement a custom deserialization routine with a | ||
| 1056 | /// function named `deserialize` in the form of: | ||
| 1057 | /// pub fn deserialize(self: *Self, deserializer: var) !void | ||
| 1058 | /// which will be called when the deserializer is used to deserialize | ||
| 1059 | /// that type. It will pass a pointer to the type instance to deserialize | ||
| 1060 | /// into and a pointer to the deserializer struct. | ||
| 1061 | pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type { | ||
| 1062 | return struct { | ||
| 1063 | const Self = @This(); | ||
| 1064 | |||
| 1065 | in_stream: if (is_packed) BitInStream(endian, Stream.Error) else *Stream, | ||
| 1066 | |||
| 1067 | pub const Stream = InStream(Error); | ||
| 1068 | |||
| 1069 | pub fn init(in_stream: *Stream) Self { | ||
| 1070 | return Self{ .in_stream = switch (is_packed) { | ||
| 1071 | true => BitInStream(endian, Stream.Error).init(in_stream), | ||
| 1072 | else => in_stream, | ||
| 1073 | } }; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | pub fn alignToByte(self: *Self) void { | ||
| 1077 | if(!is_packed) return; | ||
| 1078 | self.in_stream.alignToByte(); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | //@BUG: inferred error issue. See: #1386 | ||
| 1082 | fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { | ||
| 1083 | comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); | ||
| 1084 | |||
| 1085 | const u8_bit_count = 8; | ||
| 1086 | const t_bit_count = comptime meta.bitCount(T); | ||
| 1087 | |||
| 1088 | const U = @IntType(false, t_bit_count); | ||
| 1089 | const Log2U = math.Log2Int(U); | ||
| 1090 | const int_size = @sizeOf(U); | ||
| 1091 | |||
| 1092 | if (is_packed) { | ||
| 1093 | const result = try self.in_stream.readBitsNoEof(U, t_bit_count); | ||
| 1094 | return @bitCast(T, result); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | var buffer: [int_size]u8 = undefined; | ||
| 1098 | const read_size = try self.in_stream.read(buffer[0..]); | ||
| 1099 | if (read_size < int_size) return error.EndOfStream; | ||
| 1100 | |||
| 1101 | if (int_size == 1) { | ||
| 1102 | if (t_bit_count == 8) return @bitCast(T, buffer[0]); | ||
| 1103 | const PossiblySignedByte = @IntType(T.is_signed, 8); | ||
| 1104 | return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | var result = U(0); | ||
| 1108 | for (buffer) |byte, i| { | ||
| 1109 | switch (endian) { | ||
| 1110 | builtin.Endian.Big => { | ||
| 1111 | result = (result << u8_bit_count) | byte; | ||
| 1112 | }, | ||
| 1113 | builtin.Endian.Little => { | ||
| 1114 | result |= U(byte) << @intCast(Log2U, u8_bit_count * i); | ||
| 1115 | }, | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | return @bitCast(T, result); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | //@TODO: Replace this with @unionInit or whatever when it is added | ||
| 1123 | // see: #1315 | ||
| 1124 | fn setTag(ptr: var, tag: var) void { | ||
| 1125 | const T = @typeOf(ptr); | ||
| 1126 | comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T)); | ||
| 1127 | const U = meta.Child(T); | ||
| 1128 | |||
| 1129 | const info = @typeInfo(U).Union; | ||
| 1130 | if (info.tag_type) |TagType| { | ||
| 1131 | comptime assert(TagType == @typeOf(tag)); | ||
| 1132 | |||
| 1133 | var ptr_tag = ptr: { | ||
| 1134 | if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr); | ||
| 1135 | const offset = comptime max: { | ||
| 1136 | var max_field_size: comptime_int = 0; | ||
| 1137 | for (info.fields) |field_info| { | ||
| 1138 | const field_size = @sizeOf(field_info.field_type); | ||
| 1139 | max_field_size = math.max(max_field_size, field_size); | ||
| 1140 | } | ||
| 1141 | break :max math.max(max_field_size, @alignOf(U)); | ||
| 1142 | }; | ||
| 1143 | break :ptr @intToPtr(*TagType, @ptrToInt(ptr) + offset); | ||
| 1144 | }; | ||
| 1145 | ptr_tag.* = tag; | ||
| 1146 | } | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | /// Deserializes and returns data of the specified type from the stream | ||
| 1150 | pub fn deserialize(self: *Self, comptime T: type) !T { | ||
| 1151 | var value: T = undefined; | ||
| 1152 | try self.deserializeInto(&value); | ||
| 1153 | return value; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | /// Deserializes data into the type pointed to by `ptr` | ||
| 1157 | pub fn deserializeInto(self: *Self, ptr: var) !void { | ||
| 1158 | const T = @typeOf(ptr); | ||
| 1159 | comptime assert(trait.is(builtin.TypeId.Pointer)(T)); | ||
| 1160 | |||
| 1161 | if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) { | ||
| 1162 | for (ptr) |*v| | ||
| 1163 | try self.deserializeInto(v); | ||
| 1164 | return; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | comptime assert(trait.isSingleItemPtr(T)); | ||
| 1168 | |||
| 1169 | const C = comptime meta.Child(T); | ||
| 1170 | const child_type_id = @typeId(C); | ||
| 1171 | |||
| 1172 | //custom deserializer: fn(self: *Self, deserializer: var) !void | ||
| 1173 | if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self); | ||
| 1174 | |||
| 1175 | if (comptime trait.isPacked(C) and !is_packed) { | ||
| 1176 | var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream); | ||
| 1177 | return packed_deserializer.deserializeInto(ptr); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | switch (child_type_id) { | ||
| 1181 | builtin.TypeId.Void => return, | ||
| 1182 | builtin.TypeId.Bool => ptr.* = (try self.deserializeInt(u1)) > 0, | ||
| 1183 | builtin.TypeId.Float, builtin.TypeId.Int => ptr.* = try self.deserializeInt(C), | ||
| 1184 | builtin.TypeId.Struct => { | ||
| 1185 | const info = @typeInfo(C).Struct; | ||
| 1186 | |||
| 1187 | inline for (info.fields) |*field_info| { | ||
| 1188 | const name = field_info.name; | ||
| 1189 | const FieldType = field_info.field_type; | ||
| 1190 | |||
| 1191 | if (FieldType == void or FieldType == u0) continue; | ||
| 1192 | |||
| 1193 | //it doesn't make any sense to read pointers | ||
| 1194 | if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { | ||
| 1195 | @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++ | ||
| 1196 | @typeName(C) ++ " because it " ++ "is of pointer-type " ++ | ||
| 1197 | @typeName(FieldType) ++ "."); | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | try self.deserializeInto(&@field(ptr, name)); | ||
| 1201 | } | ||
| 1202 | }, | ||
| 1203 | builtin.TypeId.Union => { | ||
| 1204 | const info = @typeInfo(C).Union; | ||
| 1205 | if (info.tag_type) |TagType| { | ||
| 1206 | //we avoid duplicate iteration over the enum tags | ||
| 1207 | // by getting the int directly and casting it without | ||
| 1208 | // safety. If it is bad, it will be caught anyway. | ||
| 1209 | const TagInt = @TagType(TagType); | ||
| 1210 | const tag = try self.deserializeInt(TagInt); | ||
| 1211 | |||
| 1212 | { | ||
| 1213 | @setRuntimeSafety(false); | ||
| 1214 | //See: #1315 | ||
| 1215 | setTag(ptr, @intToEnum(TagType, tag)); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | inline for (info.fields) |field_info| { | ||
| 1219 | if (field_info.enum_field.?.value == tag) { | ||
| 1220 | const name = field_info.name; | ||
| 1221 | const FieldType = field_info.field_type; | ||
| 1222 | @field(ptr, name) = FieldType(undefined); | ||
| 1223 | try self.deserializeInto(&@field(ptr, name)); | ||
| 1224 | return; | ||
| 1225 | } | ||
| 1226 | } | ||
| 1227 | //This is reachable if the enum data is bad | ||
| 1228 | return error.InvalidEnumTag; | ||
| 1229 | } | ||
| 1230 | @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++ | ||
| 1231 | " because it is an untagged union Use a custom deserialize()."); | ||
| 1232 | }, | ||
| 1233 | builtin.TypeId.Optional => { | ||
| 1234 | const OC = comptime meta.Child(C); | ||
| 1235 | const exists = (try self.deserializeInt(u1)) > 0; | ||
| 1236 | if (!exists) { | ||
| 1237 | ptr.* = null; | ||
| 1238 | return; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | //The way non-pointer optionals are implemented ensures a pointer to them | ||
| 1242 | // will point to the value. The flag is stored at the end of that data. | ||
| 1243 | var val_ptr = @ptrCast(*OC, ptr); | ||
| 1244 | try self.deserializeInto(val_ptr); | ||
| 1245 | //This bit ensures the null flag isn't set. Any actual copying should be | ||
| 1246 | // optimized out... I hope. | ||
| 1247 | ptr.* = val_ptr.*; | ||
| 1248 | }, | ||
| 1249 | builtin.TypeId.Enum => { | ||
| 1250 | var value = try self.deserializeInt(@TagType(C)); | ||
| 1251 | ptr.* = try meta.intToEnum(C, value); | ||
| 1252 | }, | ||
| 1253 | else => { | ||
| 1254 | @compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented)."); | ||
| 1255 | }, | ||
| 1256 | } | ||
| 1257 | } | ||
| 1258 | }; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /// Creates a serializer that serializes types to any stream. | ||
| 1262 | /// If `is_packed` is true, the data will be bit-packed into the stream. | ||
| 1263 | /// Note that the you must call `serializer.flush()` when you are done | ||
| 1264 | /// writing bit-packed data in order ensure any unwritten bits are committed. | ||
| 1265 | /// If `is_packed` is false, data is packed to the smallest byte. In the case | ||
| 1266 | /// of packed structs, the struct will written bit-packed and with the specified | ||
| 1267 | /// endianess, after which data will resume being written at the next byte boundary. | ||
| 1268 | /// Types may implement a custom serialization routine with a | ||
| 1269 | /// function named `serialize` in the form of: | ||
| 1270 | /// pub fn serialize(self: Self, serializer: var) !void | ||
| 1271 | /// which will be called when the serializer is used to serialize that type. It will | ||
| 1272 | /// pass a const pointer to the type instance to be serialized and a pointer | ||
| 1273 | /// to the serializer struct. | ||
| 1274 | pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type { | ||
| 1275 | return struct { | ||
| 1276 | const Self = @This(); | ||
| 1277 | |||
| 1278 | out_stream: if (is_packed) BitOutStream(endian, Stream.Error) else *Stream, | ||
| 1279 | |||
| 1280 | pub const Stream = OutStream(Error); | ||
| 1281 | |||
| 1282 | pub fn init(out_stream: *Stream) Self { | ||
| 1283 | return Self{ .out_stream = switch (is_packed) { | ||
| 1284 | true => BitOutStream(endian, Stream.Error).init(out_stream), | ||
| 1285 | else => out_stream, | ||
| 1286 | } }; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | /// Flushes any unwritten bits to the stream | ||
| 1290 | pub fn flush(self: *Self) Stream.Error!void { | ||
| 1291 | if (is_packed) return self.out_stream.flushBits(); | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | fn serializeInt(self: *Self, value: var) !void { | ||
| 1295 | const T = @typeOf(value); | ||
| 1296 | comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); | ||
| 1297 | |||
| 1298 | const t_bit_count = comptime meta.bitCount(T); | ||
| 1299 | const u8_bit_count = comptime meta.bitCount(u8); | ||
| 1300 | |||
| 1301 | const U = @IntType(false, t_bit_count); | ||
| 1302 | const Log2U = math.Log2Int(U); | ||
| 1303 | const int_size = @sizeOf(U); | ||
| 1304 | |||
| 1305 | const u_value = @bitCast(U, value); | ||
| 1306 | |||
| 1307 | if (is_packed) return self.out_stream.writeBits(u_value, t_bit_count); | ||
| 1308 | |||
| 1309 | var buffer: [int_size]u8 = undefined; | ||
| 1310 | if (int_size == 1) buffer[0] = u_value; | ||
| 1311 | |||
| 1312 | for (buffer) |*byte, i| { | ||
| 1313 | const idx = switch (endian) { | ||
| 1314 | builtin.Endian.Big => int_size - i - 1, | ||
| 1315 | builtin.Endian.Little => i, | ||
| 1316 | }; | ||
| 1317 | const shift = @intCast(Log2U, idx * u8_bit_count); | ||
| 1318 | const v = u_value >> shift; | ||
| 1319 | byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | try self.out_stream.write(buffer); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | /// Serializes the passed value into the stream | ||
| 1326 | pub fn serialize(self: *Self, value: var) !void { | ||
| 1327 | const T = comptime @typeOf(value); | ||
| 1328 | |||
| 1329 | if (comptime trait.isIndexable(T)) { | ||
| 1330 | for (value) |v| | ||
| 1331 | try self.serialize(v); | ||
| 1332 | return; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | //custom serializer: fn(self: Self, serializer: var) !void | ||
| 1336 | if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self); | ||
| 1337 | |||
| 1338 | if (comptime trait.isPacked(T) and !is_packed) { | ||
| 1339 | var packed_serializer = Serializer(endian, true, Error).init(self.out_stream); | ||
| 1340 | try packed_serializer.serialize(value); | ||
| 1341 | try packed_serializer.flush(); | ||
| 1342 | return; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | switch (@typeId(T)) { | ||
| 1346 | builtin.TypeId.Void => return, | ||
| 1347 | builtin.TypeId.Bool => try self.serializeInt(u1(@boolToInt(value))), | ||
| 1348 | builtin.TypeId.Float, builtin.TypeId.Int => try self.serializeInt(value), | ||
| 1349 | builtin.TypeId.Struct => { | ||
| 1350 | const info = @typeInfo(T); | ||
| 1351 | |||
| 1352 | inline for (info.Struct.fields) |*field_info| { | ||
| 1353 | const name = field_info.name; | ||
| 1354 | const FieldType = field_info.field_type; | ||
| 1355 | |||
| 1356 | if (FieldType == void or FieldType == u0) continue; | ||
| 1357 | |||
| 1358 | //It doesn't make sense to write pointers | ||
| 1359 | if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { | ||
| 1360 | @compileError("Will not " ++ "serialize field " ++ name ++ | ||
| 1361 | " of struct " ++ @typeName(T) ++ " because it " ++ | ||
| 1362 | "is of pointer-type " ++ @typeName(FieldType) ++ "."); | ||
| 1363 | } | ||
| 1364 | try self.serialize(@field(value, name)); | ||
| 1365 | } | ||
| 1366 | }, | ||
| 1367 | builtin.TypeId.Union => { | ||
| 1368 | const info = @typeInfo(T).Union; | ||
| 1369 | if (info.tag_type) |TagType| { | ||
| 1370 | const active_tag = meta.activeTag(value); | ||
| 1371 | try self.serialize(active_tag); | ||
| 1372 | //This inline loop is necessary because active_tag is a runtime | ||
| 1373 | // value, but @field requires a comptime value. Our alternative | ||
| 1374 | // is to check each field for a match | ||
| 1375 | inline for (info.fields) |field_info| { | ||
| 1376 | if (field_info.enum_field.?.value == @enumToInt(active_tag)) { | ||
| 1377 | const name = field_info.name; | ||
| 1378 | const FieldType = field_info.field_type; | ||
| 1379 | try self.serialize(@field(value, name)); | ||
| 1380 | return; | ||
| 1381 | } | ||
| 1382 | } | ||
| 1383 | unreachable; | ||
| 1384 | } | ||
| 1385 | @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++ | ||
| 1386 | " because it is an untagged union Use a custom serialize()."); | ||
| 1387 | }, | ||
| 1388 | builtin.TypeId.Optional => { | ||
| 1389 | if (value == null) { | ||
| 1390 | try self.serializeInt(u1(@boolToInt(false))); | ||
| 1391 | return; | ||
| 1392 | } | ||
| 1393 | try self.serializeInt(u1(@boolToInt(true))); | ||
| 1394 | |||
| 1395 | const OC = comptime meta.Child(T); | ||
| 1396 | |||
| 1397 | //The way non-pointer optionals are implemented ensures a pointer to them | ||
| 1398 | // will point to the value. The flag is stored at the end of that data. | ||
| 1399 | var val_ptr = @ptrCast(*const OC, &value); | ||
| 1400 | try self.serialize(val_ptr.*); | ||
| 1401 | }, | ||
| 1402 | builtin.TypeId.Enum => { | ||
| 1403 | try self.serializeInt(@enumToInt(value)); | ||
| 1404 | }, | ||
| 1405 | else => @compileError("Cannot serialize " ++ @tagName(@typeId(T)) ++ " types (unimplemented)."), | ||
| 1406 | } | ||
| 1407 | } | ||
| 1408 | }; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | test "import io tests" { | ||
| 1412 | comptime { | ||
| 1413 | _ = @import("io_test.zig"); | ||
| 1414 | } | ||
| 1415 | } |
std/io_test.zig+437| ... | @@ -1,5 +1,7 @@ | ... | @@ -1,5 +1,7 @@ |
| 1 | const std = @import("index.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const io = std.io; | 2 | const io = std.io; |
| 3 | const meta = std.meta; | ||
| 4 | const trait = std.trait; | ||
| 3 | const DefaultPrng = std.rand.DefaultPrng; | 5 | const DefaultPrng = std.rand.DefaultPrng; |
| 4 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 5 | const assertError = std.debug.assertError; | 7 | const assertError = std.debug.assertError; |
| ... | @@ -132,3 +134,438 @@ test "SliceOutStream" { | ... | @@ -132,3 +134,438 @@ test "SliceOutStream" { |
| 132 | assertError(ss.stream.write("Hello world!"), error.OutOfSpace); | 134 | assertError(ss.stream.write("Hello world!"), error.OutOfSpace); |
| 133 | assert(mem.eql(u8, ss.getWritten(), "Hello worl")); | 135 | assert(mem.eql(u8, ss.getWritten(), "Hello worl")); |
| 134 | } | 136 | } |
| 137 | |||
| 138 | test "BitInStream" { | ||
| 139 | const mem_be = []u8{ 0b11001101, 0b00001011 }; | ||
| 140 | const mem_le = []u8{ 0b00011101, 0b10010101 }; | ||
| 141 | |||
| 142 | var mem_in_be = io.SliceInStream.init(mem_be[0..]); | ||
| 143 | const InError = io.SliceInStream.Error; | ||
| 144 | var bit_stream_be = io.BitInStream(builtin.Endian.Big, InError).init(&mem_in_be.stream); | ||
| 145 | |||
| 146 | var out_bits: usize = undefined; | ||
| 147 | |||
| 148 | assert(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); | ||
| 149 | assert(out_bits == 1); | ||
| 150 | assert(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); | ||
| 151 | assert(out_bits == 2); | ||
| 152 | assert(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); | ||
| 153 | assert(out_bits == 3); | ||
| 154 | assert(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); | ||
| 155 | assert(out_bits == 4); | ||
| 156 | assert(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); | ||
| 157 | assert(out_bits == 5); | ||
| 158 | assert(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); | ||
| 159 | assert(out_bits == 1); | ||
| 160 | |||
| 161 | mem_in_be.pos = 0; | ||
| 162 | bit_stream_be.bit_count = 0; | ||
| 163 | assert(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); | ||
| 164 | assert(out_bits == 15); | ||
| 165 | |||
| 166 | mem_in_be.pos = 0; | ||
| 167 | bit_stream_be.bit_count = 0; | ||
| 168 | assert(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); | ||
| 169 | assert(out_bits == 16); | ||
| 170 | |||
| 171 | _ = try bit_stream_be.readBits(u0, 0, &out_bits); | ||
| 172 | |||
| 173 | assert(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); | ||
| 174 | assert(out_bits == 0); | ||
| 175 | assertError(bit_stream_be.readBitsNoEof(u1, 1), error.EndOfStream); | ||
| 176 | |||
| 177 | var mem_in_le = io.SliceInStream.init(mem_le[0..]); | ||
| 178 | var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream); | ||
| 179 | |||
| 180 | assert(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); | ||
| 181 | assert(out_bits == 1); | ||
| 182 | assert(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); | ||
| 183 | assert(out_bits == 2); | ||
| 184 | assert(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); | ||
| 185 | assert(out_bits == 3); | ||
| 186 | assert(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); | ||
| 187 | assert(out_bits == 4); | ||
| 188 | assert(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); | ||
| 189 | assert(out_bits == 5); | ||
| 190 | assert(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); | ||
| 191 | assert(out_bits == 1); | ||
| 192 | |||
| 193 | mem_in_le.pos = 0; | ||
| 194 | bit_stream_le.bit_count = 0; | ||
| 195 | assert(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); | ||
| 196 | assert(out_bits == 15); | ||
| 197 | |||
| 198 | mem_in_le.pos = 0; | ||
| 199 | bit_stream_le.bit_count = 0; | ||
| 200 | assert(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); | ||
| 201 | assert(out_bits == 16); | ||
| 202 | |||
| 203 | _ = try bit_stream_le.readBits(u0, 0, &out_bits); | ||
| 204 | |||
| 205 | assert(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); | ||
| 206 | assert(out_bits == 0); | ||
| 207 | assertError(bit_stream_le.readBitsNoEof(u1, 1), error.EndOfStream); | ||
| 208 | } | ||
| 209 | |||
| 210 | test "BitOutStream" { | ||
| 211 | var mem_be = []u8{0} ** 2; | ||
| 212 | var mem_le = []u8{0} ** 2; | ||
| 213 | |||
| 214 | var mem_out_be = io.SliceOutStream.init(mem_be[0..]); | ||
| 215 | const OutError = io.SliceOutStream.Error; | ||
| 216 | var bit_stream_be = io.BitOutStream(builtin.Endian.Big, OutError).init(&mem_out_be.stream); | ||
| 217 | |||
| 218 | try bit_stream_be.writeBits(u2(1), 1); | ||
| 219 | try bit_stream_be.writeBits(u5(2), 2); | ||
| 220 | try bit_stream_be.writeBits(u128(3), 3); | ||
| 221 | try bit_stream_be.writeBits(u8(4), 4); | ||
| 222 | try bit_stream_be.writeBits(u9(5), 5); | ||
| 223 | try bit_stream_be.writeBits(u1(1), 1); | ||
| 224 | |||
| 225 | assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); | ||
| 226 | |||
| 227 | mem_out_be.pos = 0; | ||
| 228 | |||
| 229 | try bit_stream_be.writeBits(u15(0b110011010000101), 15); | ||
| 230 | try bit_stream_be.flushBits(); | ||
| 231 | assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); | ||
| 232 | |||
| 233 | mem_out_be.pos = 0; | ||
| 234 | try bit_stream_be.writeBits(u32(0b110011010000101), 16); | ||
| 235 | assert(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); | ||
| 236 | |||
| 237 | try bit_stream_be.writeBits(u0(0), 0); | ||
| 238 | |||
| 239 | var mem_out_le = io.SliceOutStream.init(mem_le[0..]); | ||
| 240 | var bit_stream_le = io.BitOutStream(builtin.Endian.Little, OutError).init(&mem_out_le.stream); | ||
| 241 | |||
| 242 | try bit_stream_le.writeBits(u2(1), 1); | ||
| 243 | try bit_stream_le.writeBits(u5(2), 2); | ||
| 244 | try bit_stream_le.writeBits(u128(3), 3); | ||
| 245 | try bit_stream_le.writeBits(u8(4), 4); | ||
| 246 | try bit_stream_le.writeBits(u9(5), 5); | ||
| 247 | try bit_stream_le.writeBits(u1(1), 1); | ||
| 248 | |||
| 249 | assert(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); | ||
| 250 | |||
| 251 | mem_out_le.pos = 0; | ||
| 252 | try bit_stream_le.writeBits(u15(0b110011010000101), 15); | ||
| 253 | try bit_stream_le.flushBits(); | ||
| 254 | assert(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); | ||
| 255 | |||
| 256 | mem_out_le.pos = 0; | ||
| 257 | try bit_stream_le.writeBits(u32(0b1100110100001011), 16); | ||
| 258 | assert(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); | ||
| 259 | |||
| 260 | try bit_stream_le.writeBits(u0(0), 0); | ||
| 261 | } | ||
| 262 | |||
| 263 | test "BitStreams with File Stream" { | ||
| 264 | const tmp_file_name = "temp_test_file.txt"; | ||
| 265 | { | ||
| 266 | var file = try os.File.openWrite(tmp_file_name); | ||
| 267 | defer file.close(); | ||
| 268 | |||
| 269 | var file_out = file.outStream(); | ||
| 270 | var file_out_stream = &file_out.stream; | ||
| 271 | const OutError = os.File.WriteError; | ||
| 272 | var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream); | ||
| 273 | |||
| 274 | try bit_stream.writeBits(u2(1), 1); | ||
| 275 | try bit_stream.writeBits(u5(2), 2); | ||
| 276 | try bit_stream.writeBits(u128(3), 3); | ||
| 277 | try bit_stream.writeBits(u8(4), 4); | ||
| 278 | try bit_stream.writeBits(u9(5), 5); | ||
| 279 | try bit_stream.writeBits(u1(1), 1); | ||
| 280 | try bit_stream.flushBits(); | ||
| 281 | } | ||
| 282 | { | ||
| 283 | var file = try os.File.openRead(tmp_file_name); | ||
| 284 | defer file.close(); | ||
| 285 | |||
| 286 | var file_in = file.inStream(); | ||
| 287 | var file_in_stream = &file_in.stream; | ||
| 288 | const InError = os.File.ReadError; | ||
| 289 | var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream); | ||
| 290 | |||
| 291 | var out_bits: usize = undefined; | ||
| 292 | |||
| 293 | assert(1 == try bit_stream.readBits(u2, 1, &out_bits)); | ||
| 294 | assert(out_bits == 1); | ||
| 295 | assert(2 == try bit_stream.readBits(u5, 2, &out_bits)); | ||
| 296 | assert(out_bits == 2); | ||
| 297 | assert(3 == try bit_stream.readBits(u128, 3, &out_bits)); | ||
| 298 | assert(out_bits == 3); | ||
| 299 | assert(4 == try bit_stream.readBits(u8, 4, &out_bits)); | ||
| 300 | assert(out_bits == 4); | ||
| 301 | assert(5 == try bit_stream.readBits(u9, 5, &out_bits)); | ||
| 302 | assert(out_bits == 5); | ||
| 303 | assert(1 == try bit_stream.readBits(u1, 1, &out_bits)); | ||
| 304 | assert(out_bits == 1); | ||
| 305 | |||
| 306 | assertError(bit_stream.readBitsNoEof(u1, 1), error.EndOfStream); | ||
| 307 | } | ||
| 308 | try os.deleteFile(tmp_file_name); | ||
| 309 | } | ||
| 310 | |||
| 311 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { | ||
| 312 | //@NOTE: if this test is taking too long, reduce the maximum tested bitsize | ||
| 313 | const max_test_bitsize = 128; | ||
| 314 | |||
| 315 | const total_bytes = comptime blk: { | ||
| 316 | var bytes = 0; | ||
| 317 | comptime var i = 0; | ||
| 318 | while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0); | ||
| 319 | break :blk bytes * 2; | ||
| 320 | }; | ||
| 321 | |||
| 322 | var data_mem: [total_bytes]u8 = undefined; | ||
| 323 | var out = io.SliceOutStream.init(data_mem[0..]); | ||
| 324 | const OutError = io.SliceOutStream.Error; | ||
| 325 | var out_stream = &out.stream; | ||
| 326 | var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); | ||
| 327 | |||
| 328 | var in = io.SliceInStream.init(data_mem[0..]); | ||
| 329 | const InError = io.SliceInStream.Error; | ||
| 330 | var in_stream = &in.stream; | ||
| 331 | var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); | ||
| 332 | |||
| 333 | comptime var i = 0; | ||
| 334 | inline while (i <= max_test_bitsize) : (i += 1) { | ||
| 335 | const U = @IntType(false, i); | ||
| 336 | const S = @IntType(true, i); | ||
| 337 | try serializer.serializeInt(U(i)); | ||
| 338 | if (i != 0) try serializer.serializeInt(S(-1)) else try serializer.serialize(S(0)); | ||
| 339 | } | ||
| 340 | try serializer.flush(); | ||
| 341 | |||
| 342 | i = 0; | ||
| 343 | inline while (i <= max_test_bitsize) : (i += 1) { | ||
| 344 | const U = @IntType(false, i); | ||
| 345 | const S = @IntType(true, i); | ||
| 346 | const x = try deserializer.deserializeInt(U); | ||
| 347 | const y = try deserializer.deserializeInt(S); | ||
| 348 | assert(x == U(i)); | ||
| 349 | if (i != 0) assert(y == S(-1)) else assert(y == 0); | ||
| 350 | } | ||
| 351 | |||
| 352 | const u8_bit_count = comptime meta.bitCount(u8); | ||
| 353 | //0 + 1 + 2 + ... n = (n * (n + 1)) / 2 | ||
| 354 | //and we have each for unsigned and signed, so * 2 | ||
| 355 | const total_bits = (max_test_bitsize * (max_test_bitsize + 1)); | ||
| 356 | const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0); | ||
| 357 | const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; | ||
| 358 | |||
| 359 | assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); | ||
| 360 | } | ||
| 361 | |||
| 362 | test "Serializer/Deserializer Int" { | ||
| 363 | try testIntSerializerDeserializer(builtin.Endian.Big, false); | ||
| 364 | try testIntSerializerDeserializer(builtin.Endian.Little, false); | ||
| 365 | try testIntSerializerDeserializer(builtin.Endian.Big, true); | ||
| 366 | try testIntSerializerDeserializer(builtin.Endian.Little, true); | ||
| 367 | } | ||
| 368 | |||
| 369 | fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian, | ||
| 370 | comptime is_packed: bool) !void | ||
| 371 | { | ||
| 372 | const mem_size = (16*2 + 32*2 + 64*2 + 128*2) / comptime meta.bitCount(u8); | ||
| 373 | var data_mem: [mem_size]u8 = undefined; | ||
| 374 | |||
| 375 | var out = io.SliceOutStream.init(data_mem[0..]); | ||
| 376 | const OutError = io.SliceOutStream.Error; | ||
| 377 | var out_stream = &out.stream; | ||
| 378 | var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); | ||
| 379 | |||
| 380 | var in = io.SliceInStream.init(data_mem[0..]); | ||
| 381 | const InError = io.SliceInStream.Error; | ||
| 382 | var in_stream = &in.stream; | ||
| 383 | var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); | ||
| 384 | |||
| 385 | //@TODO: isInf/isNan not currently implemented for f128. | ||
| 386 | try serializer.serialize(std.math.nan(f16)); | ||
| 387 | try serializer.serialize(std.math.inf(f16)); | ||
| 388 | try serializer.serialize(std.math.nan(f32)); | ||
| 389 | try serializer.serialize(std.math.inf(f32)); | ||
| 390 | try serializer.serialize(std.math.nan(f64)); | ||
| 391 | try serializer.serialize(std.math.inf(f64)); | ||
| 392 | //try serializer.serialize(std.math.nan(f128)); | ||
| 393 | //try serializer.serialize(std.math.inf(f128)); | ||
| 394 | const nan_check_f16 = try deserializer.deserialize(f16); | ||
| 395 | const inf_check_f16 = try deserializer.deserialize(f16); | ||
| 396 | const nan_check_f32 = try deserializer.deserialize(f32); | ||
| 397 | const inf_check_f32 = try deserializer.deserialize(f32); | ||
| 398 | const nan_check_f64 = try deserializer.deserialize(f64); | ||
| 399 | const inf_check_f64 = try deserializer.deserialize(f64); | ||
| 400 | //const nan_check_f128 = try deserializer.deserialize(f128); | ||
| 401 | //const inf_check_f128 = try deserializer.deserialize(f128); | ||
| 402 | assert(std.math.isNan(nan_check_f16)); | ||
| 403 | assert(std.math.isInf(inf_check_f16)); | ||
| 404 | assert(std.math.isNan(nan_check_f32)); | ||
| 405 | assert(std.math.isInf(inf_check_f32)); | ||
| 406 | assert(std.math.isNan(nan_check_f64)); | ||
| 407 | assert(std.math.isInf(inf_check_f64)); | ||
| 408 | //assert(std.math.isNan(nan_check_f128)); | ||
| 409 | //assert(std.math.isInf(inf_check_f128)); | ||
| 410 | } | ||
| 411 | |||
| 412 | test "Serializer/Deserializer Int: Inf/NaN" { | ||
| 413 | try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, false); | ||
| 414 | try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, false); | ||
| 415 | try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, true); | ||
| 416 | try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true); | ||
| 417 | } | ||
| 418 | |||
| 419 | fn testAlternateSerializer(self: var, serializer: var) !void { | ||
| 420 | try serializer.serialize(self.f_f16); | ||
| 421 | } | ||
| 422 | |||
| 423 | fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { | ||
| 424 | const ColorType = enum(u4) { | ||
| 425 | RGB8 = 1, | ||
| 426 | RA16 = 2, | ||
| 427 | R32 = 3, | ||
| 428 | }; | ||
| 429 | |||
| 430 | const TagAlign = union(enum(u32)) { | ||
| 431 | A: u8, | ||
| 432 | B: u8, | ||
| 433 | C: u8, | ||
| 434 | }; | ||
| 435 | |||
| 436 | const Color = union(ColorType) { | ||
| 437 | RGB8: struct { | ||
| 438 | r: u8, | ||
| 439 | g: u8, | ||
| 440 | b: u8, | ||
| 441 | a: u8, | ||
| 442 | }, | ||
| 443 | RA16: struct { | ||
| 444 | r: u16, | ||
| 445 | a: u16, | ||
| 446 | }, | ||
| 447 | R32: u32, | ||
| 448 | }; | ||
| 449 | |||
| 450 | const PackedStruct = packed struct { | ||
| 451 | f_i3: i3, | ||
| 452 | f_u2: u2, | ||
| 453 | }; | ||
| 454 | |||
| 455 | |||
| 456 | |||
| 457 | //to test custom serialization | ||
| 458 | const Custom = struct { | ||
| 459 | f_f16: f16, | ||
| 460 | f_unused_u32: u32, | ||
| 461 | |||
| 462 | pub fn deserialize(self: *@This(), deserializer: var) !void { | ||
| 463 | try deserializer.deserializeInto(&self.f_f16); | ||
| 464 | self.f_unused_u32 = 47; | ||
| 465 | } | ||
| 466 | |||
| 467 | pub const serialize = testAlternateSerializer; | ||
| 468 | }; | ||
| 469 | |||
| 470 | const MyStruct = struct { | ||
| 471 | f_i3: i3, | ||
| 472 | f_u8: u8, | ||
| 473 | f_tag_align: TagAlign, | ||
| 474 | f_u24: u24, | ||
| 475 | f_i19: i19, | ||
| 476 | f_void: void, | ||
| 477 | f_f32: f32, | ||
| 478 | f_f128: f128, | ||
| 479 | f_packed_0: PackedStruct, | ||
| 480 | f_i7arr: [10]i7, | ||
| 481 | f_of64n: ?f64, | ||
| 482 | f_of64v: ?f64, | ||
| 483 | f_color_type: ColorType, | ||
| 484 | f_packed_1: PackedStruct, | ||
| 485 | f_custom: Custom, | ||
| 486 | f_color: Color, | ||
| 487 | }; | ||
| 488 | |||
| 489 | const my_inst = MyStruct{ | ||
| 490 | .f_i3 = -1, | ||
| 491 | .f_u8 = 8, | ||
| 492 | .f_tag_align = TagAlign{ .B = 148 }, | ||
| 493 | .f_u24 = 24, | ||
| 494 | .f_i19 = 19, | ||
| 495 | .f_void = {}, | ||
| 496 | .f_f32 = 32.32, | ||
| 497 | .f_f128 = 128.128, | ||
| 498 | .f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 }, | ||
| 499 | .f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 500 | .f_of64n = null, | ||
| 501 | .f_of64v = 64.64, | ||
| 502 | .f_color_type = ColorType.R32, | ||
| 503 | .f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 }, | ||
| 504 | .f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 }, | ||
| 505 | .f_color = Color{ .R32 = 123822 }, | ||
| 506 | }; | ||
| 507 | |||
| 508 | var data_mem: [@sizeOf(MyStruct)]u8 = undefined; | ||
| 509 | var out = io.SliceOutStream.init(data_mem[0..]); | ||
| 510 | const OutError = io.SliceOutStream.Error; | ||
| 511 | var out_stream = &out.stream; | ||
| 512 | var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); | ||
| 513 | |||
| 514 | var in = io.SliceInStream.init(data_mem[0..]); | ||
| 515 | const InError = io.SliceInStream.Error; | ||
| 516 | var in_stream = &in.stream; | ||
| 517 | var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); | ||
| 518 | |||
| 519 | try serializer.serialize(my_inst); | ||
| 520 | |||
| 521 | const my_copy = try deserializer.deserialize(MyStruct); | ||
| 522 | assert(meta.eql(my_copy, my_inst)); | ||
| 523 | } | ||
| 524 | |||
| 525 | test "Serializer/Deserializer generic" { | ||
| 526 | try testSerializerDeserializer(builtin.Endian.Big, false); | ||
| 527 | try testSerializerDeserializer(builtin.Endian.Little, false); | ||
| 528 | try testSerializerDeserializer(builtin.Endian.Big, true); | ||
| 529 | try testSerializerDeserializer(builtin.Endian.Little, true); | ||
| 530 | } | ||
| 531 | |||
| 532 | fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void { | ||
| 533 | const E = enum(u14) { | ||
| 534 | One = 1, | ||
| 535 | Two = 2, | ||
| 536 | }; | ||
| 537 | |||
| 538 | const A = struct { | ||
| 539 | e: E, | ||
| 540 | }; | ||
| 541 | |||
| 542 | const C = union(E) { | ||
| 543 | One: u14, | ||
| 544 | Two: f16, | ||
| 545 | }; | ||
| 546 | |||
| 547 | var data_mem: [4]u8 = undefined; | ||
| 548 | var out = io.SliceOutStream.init(data_mem[0..]); | ||
| 549 | const OutError = io.SliceOutStream.Error; | ||
| 550 | var out_stream = &out.stream; | ||
| 551 | var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); | ||
| 552 | |||
| 553 | var in = io.SliceInStream.init(data_mem[0..]); | ||
| 554 | const InError = io.SliceInStream.Error; | ||
| 555 | var in_stream = &in.stream; | ||
| 556 | var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); | ||
| 557 | |||
| 558 | try serializer.serialize(u14(3)); | ||
| 559 | assertError(deserializer.deserialize(A), error.InvalidEnumTag); | ||
| 560 | out.pos = 0; | ||
| 561 | try serializer.serialize(u14(3)); | ||
| 562 | try serializer.serialize(u14(88)); | ||
| 563 | assertError(deserializer.deserialize(C), error.InvalidEnumTag); | ||
| 564 | } | ||
| 565 | |||
| 566 | test "Deserializer bad data" { | ||
| 567 | try testBadData(builtin.Endian.Big, false); | ||
| 568 | try testBadData(builtin.Endian.Little, false); | ||
| 569 | try testBadData(builtin.Endian.Big, true); | ||
| 570 | try testBadData(builtin.Endian.Little, true); | ||
| 571 | } | ||
| \ No newline at end of file | |||
std/linked_list.zig+1-1| ... | @@ -190,7 +190,7 @@ pub fn LinkedList(comptime T: type) type { | ... | @@ -190,7 +190,7 @@ pub fn LinkedList(comptime T: type) type { |
| 190 | /// Returns: | 190 | /// Returns: |
| 191 | /// A pointer to the new node. | 191 | /// A pointer to the new node. |
| 192 | pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { | 192 | pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { |
| 193 | return allocator.create(Node(undefined)); | 193 | return allocator.create(Node); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | /// Deallocate a node. | 196 | /// Deallocate a node. |
std/mem.zig+132-25| ... | @@ -36,20 +36,9 @@ pub const Allocator = struct { | ... | @@ -36,20 +36,9 @@ pub const Allocator = struct { |
| 36 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` | 36 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` |
| 37 | freeFn: fn (self: *Allocator, old_mem: []u8) void, | 37 | freeFn: fn (self: *Allocator, old_mem: []u8) void, |
| 38 | 38 | ||
| 39 | /// Call `destroy` with the result | ||
| 40 | /// TODO this is deprecated. use createOne instead | ||
| 41 | pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { | ||
| 42 | const T = @typeOf(init); | ||
| 43 | if (@sizeOf(T) == 0) return &(T{}); | ||
| 44 | const slice = try self.alloc(T, 1); | ||
| 45 | const ptr = &slice[0]; | ||
| 46 | ptr.* = init; | ||
| 47 | return ptr; | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Call `destroy` with the result. | 39 | /// Call `destroy` with the result. |
| 51 | /// Returns undefined memory. | 40 | /// Returns undefined memory. |
| 52 | pub fn createOne(self: *Allocator, comptime T: type) Error!*T { | 41 | pub fn create(self: *Allocator, comptime T: type) Error!*T { |
| 53 | if (@sizeOf(T) == 0) return &(T{}); | 42 | if (@sizeOf(T) == 0) return &(T{}); |
| 54 | const slice = try self.alloc(T, 1); | 43 | const slice = try self.alloc(T, 1); |
| 55 | return &slice[0]; | 44 | return &slice[0]; |
| ... | @@ -700,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { | ... | @@ -700,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { |
| 700 | } | 689 | } |
| 701 | 690 | ||
| 702 | /// Returns an iterator that iterates over the slices of `buffer` that are not | 691 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
| 703 | /// any of the bytes in `split_bytes`. | 692 | /// any of the bytes in `delimiter_bytes`. |
| 704 | /// split(" abc def ghi ", " ") | 693 | /// tokenize(" abc def ghi ", " ") |
| 705 | /// Will return slices for "abc", "def", "ghi", null, in that order. | 694 | /// Will return slices for "abc", "def", "ghi", null, in that order. |
| 706 | pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { | 695 | /// If `buffer` is empty, the iterator will return null. |
| 696 | /// If `delimiter_bytes` does not exist in buffer, | ||
| 697 | /// the iterator will return `buffer`, null, in that order. | ||
| 698 | /// See also the related function `separate`. | ||
| 699 | pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator { | ||
| 700 | return TokenIterator{ | ||
| 701 | .index = 0, | ||
| 702 | .buffer = buffer, | ||
| 703 | .delimiter_bytes = delimiter_bytes, | ||
| 704 | }; | ||
| 705 | } | ||
| 706 | |||
| 707 | test "mem.tokenize" { | ||
| 708 | var it = tokenize(" abc def ghi ", " "); | ||
| 709 | assert(eql(u8, it.next().?, "abc")); | ||
| 710 | assert(eql(u8, it.next().?, "def")); | ||
| 711 | assert(eql(u8, it.next().?, "ghi")); | ||
| 712 | assert(it.next() == null); | ||
| 713 | |||
| 714 | it = tokenize("..\\bob", "\\"); | ||
| 715 | assert(eql(u8, it.next().?, "..")); | ||
| 716 | assert(eql(u8, "..", "..\\bob"[0..it.index])); | ||
| 717 | assert(eql(u8, it.next().?, "bob")); | ||
| 718 | assert(it.next() == null); | ||
| 719 | |||
| 720 | it = tokenize("//a/b", "/"); | ||
| 721 | assert(eql(u8, it.next().?, "a")); | ||
| 722 | assert(eql(u8, it.next().?, "b")); | ||
| 723 | assert(eql(u8, "//a/b", "//a/b"[0..it.index])); | ||
| 724 | assert(it.next() == null); | ||
| 725 | |||
| 726 | it = tokenize("|", "|"); | ||
| 727 | assert(it.next() == null); | ||
| 728 | |||
| 729 | it = tokenize("", "|"); | ||
| 730 | assert(it.next() == null); | ||
| 731 | |||
| 732 | it = tokenize("hello", ""); | ||
| 733 | assert(eql(u8, it.next().?, "hello")); | ||
| 734 | assert(it.next() == null); | ||
| 735 | |||
| 736 | it = tokenize("hello", " "); | ||
| 737 | assert(eql(u8, it.next().?, "hello")); | ||
| 738 | assert(it.next() == null); | ||
| 739 | } | ||
| 740 | |||
| 741 | test "mem.tokenize (multibyte)" { | ||
| 742 | var it = tokenize("a|b,c/d e", " /,|"); | ||
| 743 | assert(eql(u8, it.next().?, "a")); | ||
| 744 | assert(eql(u8, it.next().?, "b")); | ||
| 745 | assert(eql(u8, it.next().?, "c")); | ||
| 746 | assert(eql(u8, it.next().?, "d")); | ||
| 747 | assert(eql(u8, it.next().?, "e")); | ||
| 748 | assert(it.next() == null); | ||
| 749 | } | ||
| 750 | |||
| 751 | /// Returns an iterator that iterates over the slices of `buffer` that | ||
| 752 | /// are separated by bytes in `delimiter`. | ||
| 753 | /// separate("abc|def||ghi", "|") | ||
| 754 | /// will return slices for "abc", "def", "", "ghi", null, in that order. | ||
| 755 | /// If `delimiter` does not exist in buffer, | ||
| 756 | /// the iterator will return `buffer`, null, in that order. | ||
| 757 | /// The delimiter length must not be zero. | ||
| 758 | /// See also the related function `tokenize`. | ||
| 759 | /// It is planned to rename this function to `split` before 1.0.0, like this: | ||
| 760 | /// pub fn split(buffer: []const u8, delimiter: []const u8) SplitIterator { | ||
| 761 | pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { | ||
| 762 | assert(delimiter.len != 0); | ||
| 707 | return SplitIterator{ | 763 | return SplitIterator{ |
| 708 | .index = 0, | 764 | .index = 0, |
| 709 | .buffer = buffer, | 765 | .buffer = buffer, |
| 710 | .split_bytes = split_bytes, | 766 | .delimiter = delimiter, |
| 711 | }; | 767 | }; |
| 712 | } | 768 | } |
| 713 | 769 | ||
| 714 | test "mem.split" { | 770 | test "mem.separate" { |
| 715 | var it = split(" abc def ghi ", " "); | 771 | var it = separate("abc|def||ghi", "|"); |
| 716 | assert(eql(u8, it.next().?, "abc")); | 772 | assert(eql(u8, it.next().?, "abc")); |
| 717 | assert(eql(u8, it.next().?, "def")); | 773 | assert(eql(u8, it.next().?, "def")); |
| 774 | assert(eql(u8, it.next().?, "")); | ||
| 718 | assert(eql(u8, it.next().?, "ghi")); | 775 | assert(eql(u8, it.next().?, "ghi")); |
| 719 | assert(it.next() == null); | 776 | assert(it.next() == null); |
| 777 | |||
| 778 | it = separate("", "|"); | ||
| 779 | assert(eql(u8, it.next().?, "")); | ||
| 780 | assert(it.next() == null); | ||
| 781 | |||
| 782 | it = separate("|", "|"); | ||
| 783 | assert(eql(u8, it.next().?, "")); | ||
| 784 | assert(eql(u8, it.next().?, "")); | ||
| 785 | assert(it.next() == null); | ||
| 786 | |||
| 787 | it = separate("hello", " "); | ||
| 788 | assert(eql(u8, it.next().?, "hello")); | ||
| 789 | assert(it.next() == null); | ||
| 790 | } | ||
| 791 | |||
| 792 | test "mem.separate (multibyte)" { | ||
| 793 | var it = separate("a, b ,, c, d, e", ", "); | ||
| 794 | assert(eql(u8, it.next().?, "a")); | ||
| 795 | assert(eql(u8, it.next().?, "b ,")); | ||
| 796 | assert(eql(u8, it.next().?, "c")); | ||
| 797 | assert(eql(u8, it.next().?, "d")); | ||
| 798 | assert(eql(u8, it.next().?, "e")); | ||
| 799 | assert(it.next() == null); | ||
| 720 | } | 800 | } |
| 721 | 801 | ||
| 722 | pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { | 802 | pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { |
| ... | @@ -737,12 +817,13 @@ test "mem.endsWith" { | ... | @@ -737,12 +817,13 @@ test "mem.endsWith" { |
| 737 | assert(!endsWith(u8, "Bob", "Bo")); | 817 | assert(!endsWith(u8, "Bob", "Bo")); |
| 738 | } | 818 | } |
| 739 | 819 | ||
| 740 | pub const SplitIterator = struct { | 820 | pub const TokenIterator = struct { |
| 741 | buffer: []const u8, | 821 | buffer: []const u8, |
| 742 | split_bytes: []const u8, | 822 | delimiter_bytes: []const u8, |
| 743 | index: usize, | 823 | index: usize, |
| 744 | 824 | ||
| 745 | pub fn next(self: *SplitIterator) ?[]const u8 { | 825 | /// Returns a slice of the next token, or null if tokenization is complete. |
| 826 | pub fn next(self: *TokenIterator) ?[]const u8 { | ||
| 746 | // move to beginning of token | 827 | // move to beginning of token |
| 747 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} | 828 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 748 | const start = self.index; | 829 | const start = self.index; |
| ... | @@ -758,16 +839,16 @@ pub const SplitIterator = struct { | ... | @@ -758,16 +839,16 @@ pub const SplitIterator = struct { |
| 758 | } | 839 | } |
| 759 | 840 | ||
| 760 | /// Returns a slice of the remaining bytes. Does not affect iterator state. | 841 | /// Returns a slice of the remaining bytes. Does not affect iterator state. |
| 761 | pub fn rest(self: *const SplitIterator) []const u8 { | 842 | pub fn rest(self: TokenIterator) []const u8 { |
| 762 | // move to beginning of token | 843 | // move to beginning of token |
| 763 | var index: usize = self.index; | 844 | var index: usize = self.index; |
| 764 | while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} | 845 | while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} |
| 765 | return self.buffer[index..]; | 846 | return self.buffer[index..]; |
| 766 | } | 847 | } |
| 767 | 848 | ||
| 768 | fn isSplitByte(self: *const SplitIterator, byte: u8) bool { | 849 | fn isSplitByte(self: TokenIterator, byte: u8) bool { |
| 769 | for (self.split_bytes) |split_byte| { | 850 | for (self.delimiter_bytes) |delimiter_byte| { |
| 770 | if (byte == split_byte) { | 851 | if (byte == delimiter_byte) { |
| 771 | return true; | 852 | return true; |
| 772 | } | 853 | } |
| 773 | } | 854 | } |
| ... | @@ -775,6 +856,32 @@ pub const SplitIterator = struct { | ... | @@ -775,6 +856,32 @@ pub const SplitIterator = struct { |
| 775 | } | 856 | } |
| 776 | }; | 857 | }; |
| 777 | 858 | ||
| 859 | pub const SplitIterator = struct { | ||
| 860 | buffer: []const u8, | ||
| 861 | index: ?usize, | ||
| 862 | delimiter: []const u8, | ||
| 863 | |||
| 864 | /// Returns a slice of the next field, or null if splitting is complete. | ||
| 865 | pub fn next(self: *SplitIterator) ?[]const u8 { | ||
| 866 | const start = self.index orelse return null; | ||
| 867 | const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: { | ||
| 868 | self.index = delim_start + self.delimiter.len; | ||
| 869 | break :blk delim_start; | ||
| 870 | } else blk: { | ||
| 871 | self.index = null; | ||
| 872 | break :blk self.buffer.len; | ||
| 873 | }; | ||
| 874 | return self.buffer[start..end]; | ||
| 875 | } | ||
| 876 | |||
| 877 | /// Returns a slice of the remaining bytes. Does not affect iterator state. | ||
| 878 | pub fn rest(self: SplitIterator) []const u8 { | ||
| 879 | const end = self.buffer.len; | ||
| 880 | const start = self.index orelse end; | ||
| 881 | return self.buffer[start..end]; | ||
| 882 | } | ||
| 883 | }; | ||
| 884 | |||
| 778 | /// Naively combines a series of strings with a separator. | 885 | /// Naively combines a series of strings with a separator. |
| 779 | /// Allocates memory for the result, which must be freed by the caller. | 886 | /// Allocates memory for the result, which must be freed by the caller. |
| 780 | pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { | 887 | pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { |
std/meta/index.zig+35-3| ... | @@ -95,7 +95,7 @@ test "std.meta.stringToEnum" { | ... | @@ -95,7 +95,7 @@ test "std.meta.stringToEnum" { |
| 95 | debug.assert(null == stringToEnum(E1, "C")); | 95 | debug.assert(null == stringToEnum(E1, "C")); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | pub fn bitCount(comptime T: type) u32 { | 98 | pub fn bitCount(comptime T: type) comptime_int { |
| 99 | return switch (@typeInfo(T)) { | 99 | return switch (@typeInfo(T)) { |
| 100 | TypeId.Int => |info| info.bits, | 100 | TypeId.Int => |info| info.bits, |
| 101 | TypeId.Float => |info| info.bits, | 101 | TypeId.Float => |info| info.bits, |
| ... | @@ -108,7 +108,7 @@ test "std.meta.bitCount" { | ... | @@ -108,7 +108,7 @@ test "std.meta.bitCount" { |
| 108 | debug.assert(bitCount(f32) == 32); | 108 | debug.assert(bitCount(f32) == 32); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | pub fn alignment(comptime T: type) u29 { | 111 | pub fn alignment(comptime T: type) comptime_int { |
| 112 | //@alignOf works on non-pointer types | 112 | //@alignOf works on non-pointer types |
| 113 | const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T; | 113 | const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T; |
| 114 | return @typeInfo(P).Pointer.alignment; | 114 | return @typeInfo(P).Pointer.alignment; |
| ... | @@ -386,6 +386,33 @@ test "std.meta.activeTag" { | ... | @@ -386,6 +386,33 @@ test "std.meta.activeTag" { |
| 386 | debug.assert(activeTag(u) == UE.Float); | 386 | debug.assert(activeTag(u) == UE.Float); |
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | ///Given a tagged union type, and an enum, return the type of the union | ||
| 390 | /// field corresponding to the enum tag. | ||
| 391 | pub fn TagPayloadType(comptime U: type, tag: var) type { | ||
| 392 | const Tag = @typeOf(tag); | ||
| 393 | debug.assert(trait.is(builtin.TypeId.Union)(U)); | ||
| 394 | debug.assert(trait.is(builtin.TypeId.Enum)(Tag)); | ||
| 395 | |||
| 396 | const info = @typeInfo(U).Union; | ||
| 397 | |||
| 398 | inline for (info.fields) |field_info| { | ||
| 399 | if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type; | ||
| 400 | } | ||
| 401 | unreachable; | ||
| 402 | } | ||
| 403 | |||
| 404 | test "std.meta.TagPayloadType" { | ||
| 405 | const Event = union(enum) { | ||
| 406 | Moved: struct { | ||
| 407 | from: i32, | ||
| 408 | to: i32, | ||
| 409 | }, | ||
| 410 | }; | ||
| 411 | const MovedEvent = TagPayloadType(Event, Event.Moved); | ||
| 412 | var e: Event = undefined; | ||
| 413 | debug.assert(MovedEvent == @typeOf(e.Moved)); | ||
| 414 | } | ||
| 415 | |||
| 389 | ///Compares two of any type for equality. Containers are compared on a field-by-field basis, | 416 | ///Compares two of any type for equality. Containers are compared on a field-by-field basis, |
| 390 | /// where possible. Pointers are not followed. | 417 | /// where possible. Pointers are not followed. |
| 391 | pub fn eql(a: var, b: @typeOf(a)) bool { | 418 | pub fn eql(a: var, b: @typeOf(a)) bool { |
| ... | @@ -439,6 +466,11 @@ pub fn eql(a: var, b: @typeOf(a)) bool { | ... | @@ -439,6 +466,11 @@ pub fn eql(a: var, b: @typeOf(a)) bool { |
| 439 | builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len, | 466 | builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len, |
| 440 | } | 467 | } |
| 441 | }, | 468 | }, |
| 469 | builtin.TypeId.Optional => { | ||
| 470 | if(a == null and b == null) return true; | ||
| 471 | if(a == null or b == null) return false; | ||
| 472 | return eql(a.?, b.?); | ||
| 473 | }, | ||
| 442 | else => return a == b, | 474 | else => return a == b, |
| 443 | } | 475 | } |
| 444 | } | 476 | } |
| ... | @@ -452,7 +484,7 @@ test "std.meta.eql" { | ... | @@ -452,7 +484,7 @@ test "std.meta.eql" { |
| 452 | 484 | ||
| 453 | const U = union(enum) { | 485 | const U = union(enum) { |
| 454 | s: S, | 486 | s: S, |
| 455 | f: f32, | 487 | f: ?f32, |
| 456 | }; | 488 | }; |
| 457 | 489 | ||
| 458 | const s_1 = S{ | 490 | const s_1 = S{ |
std/meta/trait.zig+31| ... | @@ -231,6 +231,37 @@ test "std.meta.trait.isPacked" { | ... | @@ -231,6 +231,37 @@ test "std.meta.trait.isPacked" { |
| 231 | debug.assert(!isPacked(u8)); | 231 | debug.assert(!isPacked(u8)); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | /// | ||
| 235 | pub fn isUnsignedInt(comptime T: type) bool { | ||
| 236 | return switch (@typeId(T)) { | ||
| 237 | builtin.TypeId.Int => !@typeInfo(T).Int.is_signed, | ||
| 238 | else => false, | ||
| 239 | }; | ||
| 240 | } | ||
| 241 | |||
| 242 | test "isUnsignedInt" { | ||
| 243 | debug.assert(isUnsignedInt(u32) == true); | ||
| 244 | debug.assert(isUnsignedInt(comptime_int) == false); | ||
| 245 | debug.assert(isUnsignedInt(i64) == false); | ||
| 246 | debug.assert(isUnsignedInt(f64) == false); | ||
| 247 | } | ||
| 248 | |||
| 249 | /// | ||
| 250 | pub fn isSignedInt(comptime T: type) bool { | ||
| 251 | return switch (@typeId(T)) { | ||
| 252 | builtin.TypeId.ComptimeInt => true, | ||
| 253 | builtin.TypeId.Int => @typeInfo(T).Int.is_signed, | ||
| 254 | else => false, | ||
| 255 | }; | ||
| 256 | } | ||
| 257 | |||
| 258 | test "isSignedInt" { | ||
| 259 | debug.assert(isSignedInt(u32) == false); | ||
| 260 | debug.assert(isSignedInt(comptime_int) == true); | ||
| 261 | debug.assert(isSignedInt(i64) == true); | ||
| 262 | debug.assert(isSignedInt(f64) == false); | ||
| 263 | } | ||
| 264 | |||
| 234 | /// | 265 | /// |
| 235 | pub fn isSingleItemPtr(comptime T: type) bool { | 266 | pub fn isSingleItemPtr(comptime T: type) bool { |
| 236 | if (comptime is(builtin.TypeId.Pointer)(T)) { | 267 | if (comptime is(builtin.TypeId.Pointer)(T)) { |
std/mutex.zig+104-47| ... | @@ -5,74 +5,124 @@ const AtomicRmwOp = builtin.AtomicRmwOp; | ... | @@ -5,74 +5,124 @@ const AtomicRmwOp = builtin.AtomicRmwOp; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const SpinLock = std.SpinLock; | 6 | const SpinLock = std.SpinLock; |
| 7 | const linux = std.os.linux; | 7 | const linux = std.os.linux; |
| 8 | const windows = std.os.windows; | ||
| 8 | 9 | ||
| 9 | /// Lock may be held only once. If the same thread | 10 | /// Lock may be held only once. If the same thread |
| 10 | /// tries to acquire the same mutex twice, it deadlocks. | 11 | /// tries to acquire the same mutex twice, it deadlocks. |
| 12 | /// This type must be initialized at runtime, and then deinitialized when no | ||
| 13 | /// longer needed, to free resources. | ||
| 14 | /// If you need static initialization, use std.StaticallyInitializedMutex. | ||
| 11 | /// The Linux implementation is based on mutex3 from | 15 | /// The Linux implementation is based on mutex3 from |
| 12 | /// https://www.akkadia.org/drepper/futex.pdf | 16 | /// https://www.akkadia.org/drepper/futex.pdf |
| 13 | pub const Mutex = struct { | 17 | /// When an application is built in single threaded release mode, all the functions are |
| 14 | /// 0: unlocked | 18 | /// no-ops. In single threaded debug mode, there is deadlock detection. |
| 15 | /// 1: locked, no waiters | 19 | pub const Mutex = if (builtin.single_threaded) |
| 16 | /// 2: locked, one or more waiters | 20 | struct { |
| 17 | linux_lock: @typeOf(linux_lock_init), | 21 | lock: @typeOf(lock_init), |
| 18 | 22 | ||
| 19 | /// TODO better implementation than spin lock | 23 | const lock_init = if (std.debug.runtime_safety) false else {}; |
| 20 | spin_lock: @typeOf(spin_lock_init), | ||
| 21 | 24 | ||
| 22 | const linux_lock_init = if (builtin.os == builtin.Os.linux) i32(0) else {}; | 25 | pub const Held = struct { |
| 23 | const spin_lock_init = if (builtin.os != builtin.Os.linux) SpinLock.init() else {}; | 26 | mutex: *Mutex, |
| 24 | 27 | ||
| 25 | pub const Held = struct { | 28 | pub fn release(self: Held) void { |
| 26 | mutex: *Mutex, | 29 | if (std.debug.runtime_safety) { |
| 30 | self.mutex.lock = false; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | pub fn init() Mutex { | ||
| 35 | return Mutex{ .lock = lock_init }; | ||
| 36 | } | ||
| 37 | pub fn deinit(self: *Mutex) void {} | ||
| 27 | 38 | ||
| 28 | pub fn release(self: Held) void { | 39 | pub fn acquire(self: *Mutex) Held { |
| 29 | if (builtin.os == builtin.Os.linux) { | 40 | if (std.debug.runtime_safety and self.lock) { |
| 30 | const c = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); | 41 | @panic("deadlock detected"); |
| 42 | } | ||
| 43 | return Held{ .mutex = self }; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | else switch (builtin.os) { | ||
| 47 | builtin.Os.linux => struct { | ||
| 48 | /// 0: unlocked | ||
| 49 | /// 1: locked, no waiters | ||
| 50 | /// 2: locked, one or more waiters | ||
| 51 | lock: i32, | ||
| 52 | |||
| 53 | pub const Held = struct { | ||
| 54 | mutex: *Mutex, | ||
| 55 | |||
| 56 | pub fn release(self: Held) void { | ||
| 57 | const c = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); | ||
| 31 | if (c != 1) { | 58 | if (c != 1) { |
| 32 | _ = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); | 59 | _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); |
| 33 | const rc = linux.futex_wake(&self.mutex.linux_lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); | 60 | const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); |
| 34 | switch (linux.getErrno(rc)) { | 61 | switch (linux.getErrno(rc)) { |
| 35 | 0 => {}, | 62 | 0 => {}, |
| 36 | linux.EINVAL => unreachable, | 63 | linux.EINVAL => unreachable, |
| 37 | else => unreachable, | 64 | else => unreachable, |
| 38 | } | 65 | } |
| 39 | } | 66 | } |
| 40 | } else { | ||
| 41 | SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.spin_lock }); | ||
| 42 | } | 67 | } |
| 68 | }; | ||
| 69 | |||
| 70 | pub fn init() Mutex { | ||
| 71 | return Mutex{ .lock = 0 }; | ||
| 43 | } | 72 | } |
| 44 | }; | ||
| 45 | 73 | ||
| 46 | pub fn init() Mutex { | 74 | pub fn deinit(self: *Mutex) void {} |
| 47 | return Mutex{ | ||
| 48 | .linux_lock = linux_lock_init, | ||
| 49 | .spin_lock = spin_lock_init, | ||
| 50 | }; | ||
| 51 | } | ||
| 52 | 75 | ||
| 53 | pub fn acquire(self: *Mutex) Held { | 76 | pub fn acquire(self: *Mutex) Held { |
| 54 | if (builtin.os == builtin.Os.linux) { | 77 | var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse |
| 55 | var c = @cmpxchgWeak(i32, &self.linux_lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse | ||
| 56 | return Held{ .mutex = self }; | 78 | return Held{ .mutex = self }; |
| 57 | if (c != 2) | 79 | if (c != 2) |
| 58 | c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); | 80 | c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); |
| 59 | while (c != 0) { | 81 | while (c != 0) { |
| 60 | const rc = linux.futex_wait(&self.linux_lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); | 82 | const rc = linux.futex_wait(&self.lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); |
| 61 | switch (linux.getErrno(rc)) { | 83 | switch (linux.getErrno(rc)) { |
| 62 | 0, linux.EINTR, linux.EAGAIN => {}, | 84 | 0, linux.EINTR, linux.EAGAIN => {}, |
| 63 | linux.EINVAL => unreachable, | 85 | linux.EINVAL => unreachable, |
| 64 | else => unreachable, | 86 | else => unreachable, |
| 65 | } | 87 | } |
| 66 | c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); | 88 | c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); |
| 67 | } | 89 | } |
| 68 | } else { | 90 | return Held{ .mutex = self }; |
| 69 | _ = self.spin_lock.acquire(); | ||
| 70 | } | 91 | } |
| 71 | return Held{ .mutex = self }; | 92 | }, |
| 72 | } | 93 | // TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a |
| 94 | // better implementation of this. The problem is we need the init() function to have access to | ||
| 95 | // the address of the CRITICAL_SECTION, and then have it not move. | ||
| 96 | builtin.Os.windows => std.StaticallyInitializedMutex, | ||
| 97 | else => struct { | ||
| 98 | /// TODO better implementation than spin lock. | ||
| 99 | /// When changing this, one must also change the corresponding | ||
| 100 | /// std.StaticallyInitializedMutex code, since it aliases this type, | ||
| 101 | /// under the assumption that it works both statically and at runtime. | ||
| 102 | lock: SpinLock, | ||
| 103 | |||
| 104 | pub const Held = struct { | ||
| 105 | mutex: *Mutex, | ||
| 106 | |||
| 107 | pub fn release(self: Held) void { | ||
| 108 | SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.lock }); | ||
| 109 | } | ||
| 110 | }; | ||
| 111 | |||
| 112 | pub fn init() Mutex { | ||
| 113 | return Mutex{ .lock = SpinLock.init() }; | ||
| 114 | } | ||
| 115 | |||
| 116 | pub fn deinit(self: *Mutex) void {} | ||
| 117 | |||
| 118 | pub fn acquire(self: *Mutex) Held { | ||
| 119 | _ = self.lock.acquire(); | ||
| 120 | return Held{ .mutex = self }; | ||
| 121 | } | ||
| 122 | }, | ||
| 73 | }; | 123 | }; |
| 74 | 124 | ||
| 75 | const Context = struct { | 125 | const TestContext = struct { |
| 76 | mutex: *Mutex, | 126 | mutex: *Mutex, |
| 77 | data: i128, | 127 | data: i128, |
| 78 | 128 | ||
| ... | @@ -90,25 +140,32 @@ test "std.Mutex" { | ... | @@ -90,25 +140,32 @@ test "std.Mutex" { |
| 90 | var a = &fixed_buffer_allocator.allocator; | 140 | var a = &fixed_buffer_allocator.allocator; |
| 91 | 141 | ||
| 92 | var mutex = Mutex.init(); | 142 | var mutex = Mutex.init(); |
| 93 | var context = Context{ | 143 | defer mutex.deinit(); |
| 144 | |||
| 145 | var context = TestContext{ | ||
| 94 | .mutex = &mutex, | 146 | .mutex = &mutex, |
| 95 | .data = 0, | 147 | .data = 0, |
| 96 | }; | 148 | }; |
| 97 | 149 | ||
| 98 | const thread_count = 10; | 150 | if (builtin.single_threaded) { |
| 99 | var threads: [thread_count]*std.os.Thread = undefined; | 151 | worker(&context); |
| 100 | for (threads) |*t| { | 152 | std.debug.assertOrPanic(context.data == TestContext.incr_count); |
| 101 | t.* = try std.os.spawnThread(&context, worker); | 153 | } else { |
| 102 | } | 154 | const thread_count = 10; |
| 103 | for (threads) |t| | 155 | var threads: [thread_count]*std.os.Thread = undefined; |
| 104 | t.wait(); | 156 | for (threads) |*t| { |
| 157 | t.* = try std.os.spawnThread(&context, worker); | ||
| 158 | } | ||
| 159 | for (threads) |t| | ||
| 160 | t.wait(); | ||
| 105 | 161 | ||
| 106 | std.debug.assertOrPanic(context.data == thread_count * Context.incr_count); | 162 | std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); |
| 163 | } | ||
| 107 | } | 164 | } |
| 108 | 165 | ||
| 109 | fn worker(ctx: *Context) void { | 166 | fn worker(ctx: *TestContext) void { |
| 110 | var i: usize = 0; | 167 | var i: usize = 0; |
| 111 | while (i != Context.incr_count) : (i += 1) { | 168 | while (i != TestContext.incr_count) : (i += 1) { |
| 112 | const held = ctx.mutex.acquire(); | 169 | const held = ctx.mutex.acquire(); |
| 113 | defer held.release(); | 170 | defer held.release(); |
| 114 | 171 |
std/os/child_process.zig+4-3| ... | @@ -88,7 +88,8 @@ pub const ChildProcess = struct { | ... | @@ -88,7 +88,8 @@ pub const ChildProcess = struct { |
| 88 | /// First argument in argv is the executable. | 88 | /// First argument in argv is the executable. |
| 89 | /// On success must call deinit. | 89 | /// On success must call deinit. |
| 90 | pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess { | 90 | pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess { |
| 91 | const child = try allocator.create(ChildProcess{ | 91 | const child = try allocator.create(ChildProcess); |
| 92 | child.* = ChildProcess{ | ||
| 92 | .allocator = allocator, | 93 | .allocator = allocator, |
| 93 | .argv = argv, | 94 | .argv = argv, |
| 94 | .pid = undefined, | 95 | .pid = undefined, |
| ... | @@ -109,7 +110,7 @@ pub const ChildProcess = struct { | ... | @@ -109,7 +110,7 @@ pub const ChildProcess = struct { |
| 109 | .stdin_behavior = StdIo.Inherit, | 110 | .stdin_behavior = StdIo.Inherit, |
| 110 | .stdout_behavior = StdIo.Inherit, | 111 | .stdout_behavior = StdIo.Inherit, |
| 111 | .stderr_behavior = StdIo.Inherit, | 112 | .stderr_behavior = StdIo.Inherit, |
| 112 | }); | 113 | }; |
| 113 | errdefer allocator.destroy(child); | 114 | errdefer allocator.destroy(child); |
| 114 | return child; | 115 | return child; |
| 115 | } | 116 | } |
| ... | @@ -594,7 +595,7 @@ pub const ChildProcess = struct { | ... | @@ -594,7 +595,7 @@ pub const ChildProcess = struct { |
| 594 | const PATH = try os.getEnvVarOwned(self.allocator, "PATH"); | 595 | const PATH = try os.getEnvVarOwned(self.allocator, "PATH"); |
| 595 | defer self.allocator.free(PATH); | 596 | defer self.allocator.free(PATH); |
| 596 | 597 | ||
| 597 | var it = mem.split(PATH, ";"); | 598 | var it = mem.tokenize(PATH, ";"); |
| 598 | while (it.next()) |search_path| { | 599 | while (it.next()) |search_path| { |
| 599 | const joined_path = try os.path.join(self.allocator, search_path, app_name); | 600 | const joined_path = try os.path.join(self.allocator, search_path, app_name); |
| 600 | defer self.allocator.free(joined_path); | 601 | defer self.allocator.free(joined_path); |
std/os/index.zig+5-3| ... | @@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: | ... | @@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: |
| 608 | // +1 for the null terminating byte | 608 | // +1 for the null terminating byte |
| 609 | const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2); | 609 | const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2); |
| 610 | defer allocator.free(path_buf); | 610 | defer allocator.free(path_buf); |
| 611 | var it = mem.split(PATH, ":"); | 611 | var it = mem.tokenize(PATH, ":"); |
| 612 | var seen_eacces = false; | 612 | var seen_eacces = false; |
| 613 | var err: usize = undefined; | 613 | var err: usize = undefined; |
| 614 | while (it.next()) |search_path| { | 614 | while (it.next()) |search_path| { |
| ... | @@ -3013,6 +3013,7 @@ pub const SpawnThreadError = error{ | ... | @@ -3013,6 +3013,7 @@ pub const SpawnThreadError = error{ |
| 3013 | /// where T is u8, noreturn, void, or !void | 3013 | /// where T is u8, noreturn, void, or !void |
| 3014 | /// caller must call wait on the returned thread | 3014 | /// caller must call wait on the returned thread |
| 3015 | pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread { | 3015 | pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread { |
| 3016 | if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode"); | ||
| 3016 | // TODO compile-time call graph analysis to determine stack upper bound | 3017 | // TODO compile-time call graph analysis to determine stack upper bound |
| 3017 | // https://github.com/ziglang/zig/issues/157 | 3018 | // https://github.com/ziglang/zig/issues/157 |
| 3018 | const default_stack_size = 8 * 1024 * 1024; | 3019 | const default_stack_size = 8 * 1024 * 1024; |
| ... | @@ -3046,7 +3047,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread | ... | @@ -3046,7 +3047,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 3046 | const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory; | 3047 | const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory; |
| 3047 | errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0); | 3048 | errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0); |
| 3048 | const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count]; | 3049 | const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count]; |
| 3049 | const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext{ | 3050 | const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable; |
| 3051 | outer_context.* = WinThread.OuterContext{ | ||
| 3050 | .thread = Thread{ | 3052 | .thread = Thread{ |
| 3051 | .data = Thread.Data{ | 3053 | .data = Thread.Data{ |
| 3052 | .heap_handle = heap_handle, | 3054 | .heap_handle = heap_handle, |
| ... | @@ -3055,7 +3057,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread | ... | @@ -3055,7 +3057,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 3055 | }, | 3057 | }, |
| 3056 | }, | 3058 | }, |
| 3057 | .inner = context, | 3059 | .inner = context, |
| 3058 | }) catch unreachable; | 3060 | }; |
| 3059 | 3061 | ||
| 3060 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); | 3062 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); |
| 3061 | outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { | 3063 | outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { |
std/os/path.zig+18-14| ... | @@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { | ... | @@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { |
| 184 | return relative_path; | 184 | return relative_path; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | var it = mem.split(path, []u8{this_sep}); | 187 | var it = mem.tokenize(path, []u8{this_sep}); |
| 188 | _ = (it.next() orelse return relative_path); | 188 | _ = (it.next() orelse return relative_path); |
| 189 | _ = (it.next() orelse return relative_path); | 189 | _ = (it.next() orelse return relative_path); |
| 190 | return WindowsPath{ | 190 | return WindowsPath{ |
| ... | @@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { | ... | @@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { |
| 202 | return relative_path; | 202 | return relative_path; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | var it = mem.split(path, []u8{this_sep}); | 205 | var it = mem.tokenize(path, []u8{this_sep}); |
| 206 | _ = (it.next() orelse return relative_path); | 206 | _ = (it.next() orelse return relative_path); |
| 207 | _ = (it.next() orelse return relative_path); | 207 | _ = (it.next() orelse return relative_path); |
| 208 | return WindowsPath{ | 208 | return WindowsPath{ |
| ... | @@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { | ... | @@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { |
| 264 | const sep1 = ns1[0]; | 264 | const sep1 = ns1[0]; |
| 265 | const sep2 = ns2[0]; | 265 | const sep2 = ns2[0]; |
| 266 | 266 | ||
| 267 | var it1 = mem.split(ns1, []u8{sep1}); | 267 | var it1 = mem.tokenize(ns1, []u8{sep1}); |
| 268 | var it2 = mem.split(ns2, []u8{sep2}); | 268 | var it2 = mem.tokenize(ns2, []u8{sep2}); |
| 269 | 269 | ||
| 270 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. | 270 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. |
| 271 | return asciiEqlIgnoreCase(it1.next().?, it2.next().?); | 271 | return asciiEqlIgnoreCase(it1.next().?, it2.next().?); |
| ... | @@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 | ... | @@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 |
| 285 | const sep1 = p1[0]; | 285 | const sep1 = p1[0]; |
| 286 | const sep2 = p2[0]; | 286 | const sep2 = p2[0]; |
| 287 | 287 | ||
| 288 | var it1 = mem.split(p1, []u8{sep1}); | 288 | var it1 = mem.tokenize(p1, []u8{sep1}); |
| 289 | var it2 = mem.split(p2, []u8{sep2}); | 289 | var it2 = mem.tokenize(p2, []u8{sep2}); |
| 290 | 290 | ||
| 291 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. | 291 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. |
| 292 | return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?); | 292 | return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?); |
| ... | @@ -337,6 +337,8 @@ pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -337,6 +337,8 @@ pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 337 | /// If all paths are relative it uses the current working directory as a starting point. | 337 | /// If all paths are relative it uses the current working directory as a starting point. |
| 338 | /// Each drive has its own current working directory. | 338 | /// Each drive has its own current working directory. |
| 339 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. | 339 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. |
| 340 | /// Note: all usage of this function should be audited due to the existence of symlinks. | ||
| 341 | /// Without performing actual syscalls, resolving `..` could be incorrect. | ||
| 340 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 342 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 341 | if (paths.len == 0) { | 343 | if (paths.len == 0) { |
| 342 | assert(is_windows); // resolveWindows called on non windows can't use getCwd | 344 | assert(is_windows); // resolveWindows called on non windows can't use getCwd |
| ... | @@ -416,7 +418,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -416,7 +418,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 416 | }, | 418 | }, |
| 417 | WindowsPath.Kind.NetworkShare => { | 419 | WindowsPath.Kind.NetworkShare => { |
| 418 | result = try allocator.alloc(u8, max_size); | 420 | result = try allocator.alloc(u8, max_size); |
| 419 | var it = mem.split(paths[first_index], "/\\"); | 421 | var it = mem.tokenize(paths[first_index], "/\\"); |
| 420 | const server_name = it.next().?; | 422 | const server_name = it.next().?; |
| 421 | const other_name = it.next().?; | 423 | const other_name = it.next().?; |
| 422 | 424 | ||
| ... | @@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 483 | if (!correct_disk_designator) { | 485 | if (!correct_disk_designator) { |
| 484 | continue; | 486 | continue; |
| 485 | } | 487 | } |
| 486 | var it = mem.split(p[parsed.disk_designator.len..], "/\\"); | 488 | var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\"); |
| 487 | while (it.next()) |component| { | 489 | while (it.next()) |component| { |
| 488 | if (mem.eql(u8, component, ".")) { | 490 | if (mem.eql(u8, component, ".")) { |
| 489 | continue; | 491 | continue; |
| ... | @@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 516 | /// It resolves "." and "..". | 518 | /// It resolves "." and "..". |
| 517 | /// The result does not have a trailing path separator. | 519 | /// The result does not have a trailing path separator. |
| 518 | /// If all paths are relative it uses the current working directory as a starting point. | 520 | /// If all paths are relative it uses the current working directory as a starting point. |
| 521 | /// Note: all usage of this function should be audited due to the existence of symlinks. | ||
| 522 | /// Without performing actual syscalls, resolving `..` could be incorrect. | ||
| 519 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 523 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 520 | if (paths.len == 0) { | 524 | if (paths.len == 0) { |
| 521 | assert(!is_windows); // resolvePosix called on windows can't use getCwd | 525 | assert(!is_windows); // resolvePosix called on windows can't use getCwd |
| ... | @@ -550,7 +554,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -550,7 +554,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 550 | errdefer allocator.free(result); | 554 | errdefer allocator.free(result); |
| 551 | 555 | ||
| 552 | for (paths[first_index..]) |p, i| { | 556 | for (paths[first_index..]) |p, i| { |
| 553 | var it = mem.split(p, "/"); | 557 | var it = mem.tokenize(p, "/"); |
| 554 | while (it.next()) |component| { | 558 | while (it.next()) |component| { |
| 555 | if (mem.eql(u8, component, ".")) { | 559 | if (mem.eql(u8, component, ".")) { |
| 556 | continue; | 560 | continue; |
| ... | @@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) | ... | @@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) |
| 937 | return resolved_to; | 941 | return resolved_to; |
| 938 | } | 942 | } |
| 939 | 943 | ||
| 940 | var from_it = mem.split(resolved_from, "/\\"); | 944 | var from_it = mem.tokenize(resolved_from, "/\\"); |
| 941 | var to_it = mem.split(resolved_to, "/\\"); | 945 | var to_it = mem.tokenize(resolved_to, "/\\"); |
| 942 | while (true) { | 946 | while (true) { |
| 943 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); | 947 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); |
| 944 | const to_rest = to_it.rest(); | 948 | const to_rest = to_it.rest(); |
| ... | @@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) | ... | @@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) |
| 967 | // shave off the trailing slash | 971 | // shave off the trailing slash |
| 968 | result_index -= 1; | 972 | result_index -= 1; |
| 969 | 973 | ||
| 970 | var rest_it = mem.split(to_rest, "/\\"); | 974 | var rest_it = mem.tokenize(to_rest, "/\\"); |
| 971 | while (rest_it.next()) |to_component| { | 975 | while (rest_it.next()) |to_component| { |
| 972 | result[result_index] = '\\'; | 976 | result[result_index] = '\\'; |
| 973 | result_index += 1; | 977 | result_index += 1; |
| ... | @@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ | ... | @@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ |
| 988 | const resolved_to = try resolvePosix(allocator, [][]const u8{to}); | 992 | const resolved_to = try resolvePosix(allocator, [][]const u8{to}); |
| 989 | defer allocator.free(resolved_to); | 993 | defer allocator.free(resolved_to); |
| 990 | 994 | ||
| 991 | var from_it = mem.split(resolved_from, "/"); | 995 | var from_it = mem.tokenize(resolved_from, "/"); |
| 992 | var to_it = mem.split(resolved_to, "/"); | 996 | var to_it = mem.tokenize(resolved_to, "/"); |
| 993 | while (true) { | 997 | while (true) { |
| 994 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); | 998 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); |
| 995 | const to_rest = to_it.rest(); | 999 | const to_rest = to_it.rest(); |
std/os/test.zig+4| ... | @@ -40,6 +40,8 @@ fn testThreadIdFn(thread_id: *os.Thread.Id) void { | ... | @@ -40,6 +40,8 @@ fn testThreadIdFn(thread_id: *os.Thread.Id) void { |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | test "std.os.Thread.getCurrentId" { | 42 | test "std.os.Thread.getCurrentId" { |
| 43 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 44 | |||
| 43 | var thread_current_id: os.Thread.Id = undefined; | 45 | var thread_current_id: os.Thread.Id = undefined; |
| 44 | const thread = try os.spawnThread(&thread_current_id, testThreadIdFn); | 46 | const thread = try os.spawnThread(&thread_current_id, testThreadIdFn); |
| 45 | const thread_id = thread.handle(); | 47 | const thread_id = thread.handle(); |
| ... | @@ -53,6 +55,8 @@ test "std.os.Thread.getCurrentId" { | ... | @@ -53,6 +55,8 @@ test "std.os.Thread.getCurrentId" { |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | test "spawn threads" { | 57 | test "spawn threads" { |
| 58 | if (builtin.single_threaded) return error.SkipZigTest; | ||
| 59 | |||
| 56 | var shared_ctx: i32 = 1; | 60 | var shared_ctx: i32 = 1; |
| 57 | 61 | ||
| 58 | const thread1 = try std.os.spawnThread({}, start1); | 62 | const thread1 = try std.os.spawnThread({}, start1); |
std/os/time.zig+3-5| ... | @@ -79,14 +79,12 @@ fn milliTimestampWindows() u64 { | ... | @@ -79,14 +79,12 @@ fn milliTimestampWindows() u64 { |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | fn milliTimestampDarwin() u64 { | 81 | fn milliTimestampDarwin() u64 { |
| 82 | //Sources suggest MacOS 10.12 has support for | ||
| 83 | // posix clock_gettime. | ||
| 84 | var tv: darwin.timeval = undefined; | 82 | var tv: darwin.timeval = undefined; |
| 85 | var err = darwin.gettimeofday(&tv, null); | 83 | var err = darwin.gettimeofday(&tv, null); |
| 86 | debug.assert(err == 0); | 84 | debug.assert(err == 0); |
| 87 | const sec_ms = @intCast(u64, tv.tv_sec) * ms_per_s; | 85 | const sec_ms = tv.tv_sec * ms_per_s; |
| 88 | const usec_ms = @divFloor(@intCast(u64, tv.tv_usec), us_per_s / ms_per_s); | 86 | const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s); |
| 89 | return u64(sec_ms) + u64(usec_ms); | 87 | return @intCast(u64, sec_ms + usec_ms); |
| 90 | } | 88 | } |
| 91 | 89 | ||
| 92 | fn milliTimestampPosix() u64 { | 90 | fn milliTimestampPosix() u64 { |
std/os/windows/index.zig+1| ... | @@ -49,6 +49,7 @@ pub const UNICODE = false; | ... | @@ -49,6 +49,7 @@ pub const UNICODE = false; |
| 49 | pub const WCHAR = u16; | 49 | pub const WCHAR = u16; |
| 50 | pub const WORD = u16; | 50 | pub const WORD = u16; |
| 51 | pub const LARGE_INTEGER = i64; | 51 | pub const LARGE_INTEGER = i64; |
| 52 | pub const LONG = c_long; | ||
| 52 | 53 | ||
| 53 | pub const TRUE = 1; | 54 | pub const TRUE = 1; |
| 54 | pub const FALSE = 0; | 55 | pub const FALSE = 0; |
std/os/windows/kernel32.zig+47| ... | @@ -220,3 +220,50 @@ pub const FOREGROUND_BLUE = 1; | ... | @@ -220,3 +220,50 @@ pub const FOREGROUND_BLUE = 1; |
| 220 | pub const FOREGROUND_GREEN = 2; | 220 | pub const FOREGROUND_GREEN = 2; |
| 221 | pub const FOREGROUND_RED = 4; | 221 | pub const FOREGROUND_RED = 4; |
| 222 | pub const FOREGROUND_INTENSITY = 8; | 222 | pub const FOREGROUND_INTENSITY = 8; |
| 223 | |||
| 224 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | ||
| 225 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | ||
| 226 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | ||
| 227 | pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | ||
| 228 | |||
| 229 | pub const LIST_ENTRY = extern struct { | ||
| 230 | Flink: *LIST_ENTRY, | ||
| 231 | Blink: *LIST_ENTRY, | ||
| 232 | }; | ||
| 233 | |||
| 234 | pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { | ||
| 235 | Type: WORD, | ||
| 236 | CreatorBackTraceIndex: WORD, | ||
| 237 | CriticalSection: *RTL_CRITICAL_SECTION, | ||
| 238 | ProcessLocksList: LIST_ENTRY, | ||
| 239 | EntryCount: DWORD, | ||
| 240 | ContentionCount: DWORD, | ||
| 241 | Flags: DWORD, | ||
| 242 | CreatorBackTraceIndexHigh: WORD, | ||
| 243 | SpareWORD: WORD, | ||
| 244 | }; | ||
| 245 | |||
| 246 | pub const RTL_CRITICAL_SECTION = extern struct { | ||
| 247 | DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, | ||
| 248 | LockCount: LONG, | ||
| 249 | RecursionCount: LONG, | ||
| 250 | OwningThread: HANDLE, | ||
| 251 | LockSemaphore: HANDLE, | ||
| 252 | SpinCount: ULONG_PTR, | ||
| 253 | }; | ||
| 254 | |||
| 255 | pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; | ||
| 256 | pub const INIT_ONCE = RTL_RUN_ONCE; | ||
| 257 | pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; | ||
| 258 | |||
| 259 | pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; | ||
| 260 | |||
| 261 | pub const INIT_ONCE_FN = extern fn(InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL; | ||
| 262 | |||
| 263 | pub const RTL_RUN_ONCE = extern struct { | ||
| 264 | Ptr: ?*c_void, | ||
| 265 | }; | ||
| 266 | |||
| 267 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE { | ||
| 268 | .Ptr = null, | ||
| 269 | }; |
std/statically_initialized_mutex.zig created+110| ... | @@ -0,0 +1,110 @@ | ||
| 1 | const std = @import("index.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const AtomicOrder = builtin.AtomicOrder; | ||
| 4 | const AtomicRmwOp = builtin.AtomicRmwOp; | ||
| 5 | const assert = std.debug.assert; | ||
| 6 | const windows = std.os.windows; | ||
| 7 | |||
| 8 | /// Lock may be held only once. If the same thread | ||
| 9 | /// tries to acquire the same mutex twice, it deadlocks. | ||
| 10 | /// This type is intended to be initialized statically. If you don't | ||
| 11 | /// require static initialization, use std.Mutex. | ||
| 12 | /// On Windows, this mutex allocates resources when it is | ||
| 13 | /// first used, and the resources cannot be freed. | ||
| 14 | /// On Linux, this is an alias of std.Mutex. | ||
| 15 | pub const StaticallyInitializedMutex = switch(builtin.os) { | ||
| 16 | builtin.Os.linux => std.Mutex, | ||
| 17 | builtin.Os.windows => struct { | ||
| 18 | lock: windows.CRITICAL_SECTION, | ||
| 19 | init_once: windows.RTL_RUN_ONCE, | ||
| 20 | |||
| 21 | pub const Held = struct { | ||
| 22 | mutex: *StaticallyInitializedMutex, | ||
| 23 | |||
| 24 | pub fn release(self: Held) void { | ||
| 25 | windows.LeaveCriticalSection(&self.mutex.lock); | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | pub fn init() StaticallyInitializedMutex { | ||
| 30 | return StaticallyInitializedMutex { | ||
| 31 | .lock = undefined, | ||
| 32 | .init_once = windows.INIT_ONCE_STATIC_INIT, | ||
| 33 | }; | ||
| 34 | } | ||
| 35 | |||
| 36 | extern fn initCriticalSection( | ||
| 37 | InitOnce: *windows.RTL_RUN_ONCE, | ||
| 38 | Parameter: ?*c_void, | ||
| 39 | Context: ?*c_void, | ||
| 40 | ) windows.BOOL { | ||
| 41 | const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter)); | ||
| 42 | windows.InitializeCriticalSection(lock); | ||
| 43 | return windows.TRUE; | ||
| 44 | } | ||
| 45 | |||
| 46 | /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better | ||
| 47 | /// implementation of a runtime initialized mutex, remove this function. | ||
| 48 | pub fn deinit(self: *StaticallyInitializedMutex) void { | ||
| 49 | assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0); | ||
| 50 | windows.DeleteCriticalSection(&self.lock); | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn acquire(self: *StaticallyInitializedMutex) Held { | ||
| 54 | assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0); | ||
| 55 | windows.EnterCriticalSection(&self.lock); | ||
| 56 | return Held { .mutex = self }; | ||
| 57 | } | ||
| 58 | }, | ||
| 59 | else => std.Mutex, | ||
| 60 | }; | ||
| 61 | |||
| 62 | test "std.StaticallyInitializedMutex" { | ||
| 63 | const TestContext = struct { | ||
| 64 | data: i128, | ||
| 65 | |||
| 66 | const TestContext = @This(); | ||
| 67 | const incr_count = 10000; | ||
| 68 | |||
| 69 | var mutex = StaticallyInitializedMutex.init(); | ||
| 70 | |||
| 71 | fn worker(ctx: *TestContext) void { | ||
| 72 | var i: usize = 0; | ||
| 73 | while (i != TestContext.incr_count) : (i += 1) { | ||
| 74 | const held = mutex.acquire(); | ||
| 75 | defer held.release(); | ||
| 76 | |||
| 77 | ctx.data += 1; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | }; | ||
| 81 | |||
| 82 | var direct_allocator = std.heap.DirectAllocator.init(); | ||
| 83 | defer direct_allocator.deinit(); | ||
| 84 | |||
| 85 | var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024); | ||
| 86 | defer direct_allocator.allocator.free(plenty_of_memory); | ||
| 87 | |||
| 88 | var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory); | ||
| 89 | var a = &fixed_buffer_allocator.allocator; | ||
| 90 | |||
| 91 | |||
| 92 | var context = TestContext{ | ||
| 93 | .data = 0, | ||
| 94 | }; | ||
| 95 | |||
| 96 | if (builtin.single_threaded) { | ||
| 97 | TestContext.worker(&context); | ||
| 98 | std.debug.assertOrPanic(context.data == TestContext.incr_count); | ||
| 99 | } else { | ||
| 100 | const thread_count = 10; | ||
| 101 | var threads: [thread_count]*std.os.Thread = undefined; | ||
| 102 | for (threads) |*t| { | ||
| 103 | t.* = try std.os.spawnThread(&context, TestContext.worker); | ||
| 104 | } | ||
| 105 | for (threads) |t| | ||
| 106 | t.wait(); | ||
| 107 | |||
| 108 | std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); | ||
| 109 | } | ||
| 110 | } | ||
std/zig/parse.zig+226-150| ... | @@ -17,14 +17,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -17,14 +17,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 17 | defer stack.deinit(); | 17 | defer stack.deinit(); |
| 18 | 18 | ||
| 19 | const arena = &tree_arena.allocator; | 19 | const arena = &tree_arena.allocator; |
| 20 | const root_node = try arena.create(ast.Node.Root{ | 20 | const root_node = try arena.create(ast.Node.Root); |
| 21 | root_node.* = ast.Node.Root{ | ||
| 21 | .base = ast.Node{ .id = ast.Node.Id.Root }, | 22 | .base = ast.Node{ .id = ast.Node.Id.Root }, |
| 22 | .decls = ast.Node.Root.DeclList.init(arena), | 23 | .decls = ast.Node.Root.DeclList.init(arena), |
| 23 | .doc_comments = null, | 24 | .doc_comments = null, |
| 24 | .shebang = null, | 25 | .shebang = null, |
| 25 | // initialized when we get the eof token | 26 | // initialized when we get the eof token |
| 26 | .eof_token = undefined, | 27 | .eof_token = undefined, |
| 27 | }); | 28 | }; |
| 28 | 29 | ||
| 29 | var tree = ast.Tree{ | 30 | var tree = ast.Tree{ |
| 30 | .source = source, | 31 | .source = source, |
| ... | @@ -75,20 +76,22 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -75,20 +76,22 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 75 | Token.Id.Keyword_test => { | 76 | Token.Id.Keyword_test => { |
| 76 | stack.append(State.TopLevel) catch unreachable; | 77 | stack.append(State.TopLevel) catch unreachable; |
| 77 | 78 | ||
| 78 | const block = try arena.create(ast.Node.Block{ | 79 | const block = try arena.create(ast.Node.Block); |
| 80 | block.* = ast.Node.Block{ | ||
| 79 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 81 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 80 | .label = null, | 82 | .label = null, |
| 81 | .lbrace = undefined, | 83 | .lbrace = undefined, |
| 82 | .statements = ast.Node.Block.StatementList.init(arena), | 84 | .statements = ast.Node.Block.StatementList.init(arena), |
| 83 | .rbrace = undefined, | 85 | .rbrace = undefined, |
| 84 | }); | 86 | }; |
| 85 | const test_node = try arena.create(ast.Node.TestDecl{ | 87 | const test_node = try arena.create(ast.Node.TestDecl); |
| 88 | test_node.* = ast.Node.TestDecl{ | ||
| 86 | .base = ast.Node{ .id = ast.Node.Id.TestDecl }, | 89 | .base = ast.Node{ .id = ast.Node.Id.TestDecl }, |
| 87 | .doc_comments = comments, | 90 | .doc_comments = comments, |
| 88 | .test_token = token_index, | 91 | .test_token = token_index, |
| 89 | .name = undefined, | 92 | .name = undefined, |
| 90 | .body_node = &block.base, | 93 | .body_node = &block.base, |
| 91 | }); | 94 | }; |
| 92 | try root_node.decls.push(&test_node.base); | 95 | try root_node.decls.push(&test_node.base); |
| 93 | try stack.append(State{ .Block = block }); | 96 | try stack.append(State{ .Block = block }); |
| 94 | try stack.append(State{ | 97 | try stack.append(State{ |
| ... | @@ -119,19 +122,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -119,19 +122,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 119 | continue; | 122 | continue; |
| 120 | }, | 123 | }, |
| 121 | Token.Id.Keyword_comptime => { | 124 | Token.Id.Keyword_comptime => { |
| 122 | const block = try arena.create(ast.Node.Block{ | 125 | const block = try arena.create(ast.Node.Block); |
| 126 | block.* = ast.Node.Block{ | ||
| 123 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 127 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 124 | .label = null, | 128 | .label = null, |
| 125 | .lbrace = undefined, | 129 | .lbrace = undefined, |
| 126 | .statements = ast.Node.Block.StatementList.init(arena), | 130 | .statements = ast.Node.Block.StatementList.init(arena), |
| 127 | .rbrace = undefined, | 131 | .rbrace = undefined, |
| 128 | }); | 132 | }; |
| 129 | const node = try arena.create(ast.Node.Comptime{ | 133 | const node = try arena.create(ast.Node.Comptime); |
| 134 | node.* = ast.Node.Comptime{ | ||
| 130 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, | 135 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, |
| 131 | .comptime_token = token_index, | 136 | .comptime_token = token_index, |
| 132 | .expr = &block.base, | 137 | .expr = &block.base, |
| 133 | .doc_comments = comments, | 138 | .doc_comments = comments, |
| 134 | }); | 139 | }; |
| 135 | try root_node.decls.push(&node.base); | 140 | try root_node.decls.push(&node.base); |
| 136 | 141 | ||
| 137 | stack.append(State.TopLevel) catch unreachable; | 142 | stack.append(State.TopLevel) catch unreachable; |
| ... | @@ -235,14 +240,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -235,14 +240,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 235 | return tree; | 240 | return tree; |
| 236 | } | 241 | } |
| 237 | 242 | ||
| 238 | const node = try arena.create(ast.Node.Use{ | 243 | const node = try arena.create(ast.Node.Use); |
| 244 | node.* = ast.Node.Use{ | ||
| 239 | .base = ast.Node{ .id = ast.Node.Id.Use }, | 245 | .base = ast.Node{ .id = ast.Node.Id.Use }, |
| 240 | .use_token = token_index, | 246 | .use_token = token_index, |
| 241 | .visib_token = ctx.visib_token, | 247 | .visib_token = ctx.visib_token, |
| 242 | .expr = undefined, | 248 | .expr = undefined, |
| 243 | .semicolon_token = undefined, | 249 | .semicolon_token = undefined, |
| 244 | .doc_comments = ctx.comments, | 250 | .doc_comments = ctx.comments, |
| 245 | }); | 251 | }; |
| 246 | try ctx.decls.push(&node.base); | 252 | try ctx.decls.push(&node.base); |
| 247 | 253 | ||
| 248 | stack.append(State{ | 254 | stack.append(State{ |
| ... | @@ -276,7 +282,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -276,7 +282,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 276 | continue; | 282 | continue; |
| 277 | }, | 283 | }, |
| 278 | Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => { | 284 | Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => { |
| 279 | const fn_proto = try arena.create(ast.Node.FnProto{ | 285 | const fn_proto = try arena.create(ast.Node.FnProto); |
| 286 | fn_proto.* = ast.Node.FnProto{ | ||
| 280 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | 287 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 281 | .doc_comments = ctx.comments, | 288 | .doc_comments = ctx.comments, |
| 282 | .visib_token = ctx.visib_token, | 289 | .visib_token = ctx.visib_token, |
| ... | @@ -292,7 +299,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -292,7 +299,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 292 | .lib_name = ctx.lib_name, | 299 | .lib_name = ctx.lib_name, |
| 293 | .align_expr = null, | 300 | .align_expr = null, |
| 294 | .section_expr = null, | 301 | .section_expr = null, |
| 295 | }); | 302 | }; |
| 296 | try ctx.decls.push(&fn_proto.base); | 303 | try ctx.decls.push(&fn_proto.base); |
| 297 | stack.append(State{ .FnDef = fn_proto }) catch unreachable; | 304 | stack.append(State{ .FnDef = fn_proto }) catch unreachable; |
| 298 | try stack.append(State{ .FnProto = fn_proto }); | 305 | try stack.append(State{ .FnProto = fn_proto }); |
| ... | @@ -309,12 +316,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -309,12 +316,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 309 | continue; | 316 | continue; |
| 310 | }, | 317 | }, |
| 311 | Token.Id.Keyword_async => { | 318 | Token.Id.Keyword_async => { |
| 312 | const async_node = try arena.create(ast.Node.AsyncAttribute{ | 319 | const async_node = try arena.create(ast.Node.AsyncAttribute); |
| 320 | async_node.* = ast.Node.AsyncAttribute{ | ||
| 313 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, | 321 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, |
| 314 | .async_token = token_index, | 322 | .async_token = token_index, |
| 315 | .allocator_type = null, | 323 | .allocator_type = null, |
| 316 | .rangle_bracket = null, | 324 | .rangle_bracket = null, |
| 317 | }); | 325 | }; |
| 318 | fn_proto.async_attr = async_node; | 326 | fn_proto.async_attr = async_node; |
| 319 | 327 | ||
| 320 | try stack.append(State{ | 328 | try stack.append(State{ |
| ... | @@ -341,13 +349,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -341,13 +349,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 341 | }, | 349 | }, |
| 342 | State.TopLevelExternOrField => |ctx| { | 350 | State.TopLevelExternOrField => |ctx| { |
| 343 | if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| { | 351 | if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| { |
| 344 | const node = try arena.create(ast.Node.StructField{ | 352 | const node = try arena.create(ast.Node.StructField); |
| 353 | node.* = ast.Node.StructField{ | ||
| 345 | .base = ast.Node{ .id = ast.Node.Id.StructField }, | 354 | .base = ast.Node{ .id = ast.Node.Id.StructField }, |
| 346 | .doc_comments = ctx.comments, | 355 | .doc_comments = ctx.comments, |
| 347 | .visib_token = ctx.visib_token, | 356 | .visib_token = ctx.visib_token, |
| 348 | .name_token = identifier, | 357 | .name_token = identifier, |
| 349 | .type_expr = undefined, | 358 | .type_expr = undefined, |
| 350 | }); | 359 | }; |
| 351 | const node_ptr = try ctx.container_decl.fields_and_decls.addOne(); | 360 | const node_ptr = try ctx.container_decl.fields_and_decls.addOne(); |
| 352 | node_ptr.* = &node.base; | 361 | node_ptr.* = &node.base; |
| 353 | 362 | ||
| ... | @@ -391,7 +400,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -391,7 +400,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 391 | const token = nextToken(&tok_it, &tree); | 400 | const token = nextToken(&tok_it, &tree); |
| 392 | const token_index = token.index; | 401 | const token_index = token.index; |
| 393 | const token_ptr = token.ptr; | 402 | const token_ptr = token.ptr; |
| 394 | const node = try arena.create(ast.Node.ContainerDecl{ | 403 | const node = try arena.create(ast.Node.ContainerDecl); |
| 404 | node.* = ast.Node.ContainerDecl{ | ||
| 395 | .base = ast.Node{ .id = ast.Node.Id.ContainerDecl }, | 405 | .base = ast.Node{ .id = ast.Node.Id.ContainerDecl }, |
| 396 | .layout_token = ctx.layout_token, | 406 | .layout_token = ctx.layout_token, |
| 397 | .kind_token = switch (token_ptr.id) { | 407 | .kind_token = switch (token_ptr.id) { |
| ... | @@ -405,7 +415,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -405,7 +415,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 405 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), | 415 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), |
| 406 | .lbrace_token = undefined, | 416 | .lbrace_token = undefined, |
| 407 | .rbrace_token = undefined, | 417 | .rbrace_token = undefined, |
| 408 | }); | 418 | }; |
| 409 | ctx.opt_ctx.store(&node.base); | 419 | ctx.opt_ctx.store(&node.base); |
| 410 | 420 | ||
| 411 | stack.append(State{ .ContainerDecl = node }) catch unreachable; | 421 | stack.append(State{ .ContainerDecl = node }) catch unreachable; |
| ... | @@ -464,13 +474,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -464,13 +474,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 464 | Token.Id.Identifier => { | 474 | Token.Id.Identifier => { |
| 465 | switch (tree.tokens.at(container_decl.kind_token).id) { | 475 | switch (tree.tokens.at(container_decl.kind_token).id) { |
| 466 | Token.Id.Keyword_struct => { | 476 | Token.Id.Keyword_struct => { |
| 467 | const node = try arena.create(ast.Node.StructField{ | 477 | const node = try arena.create(ast.Node.StructField); |
| 478 | node.* = ast.Node.StructField{ | ||
| 468 | .base = ast.Node{ .id = ast.Node.Id.StructField }, | 479 | .base = ast.Node{ .id = ast.Node.Id.StructField }, |
| 469 | .doc_comments = comments, | 480 | .doc_comments = comments, |
| 470 | .visib_token = null, | 481 | .visib_token = null, |
| 471 | .name_token = token_index, | 482 | .name_token = token_index, |
| 472 | .type_expr = undefined, | 483 | .type_expr = undefined, |
| 473 | }); | 484 | }; |
| 474 | const node_ptr = try container_decl.fields_and_decls.addOne(); | 485 | const node_ptr = try container_decl.fields_and_decls.addOne(); |
| 475 | node_ptr.* = &node.base; | 486 | node_ptr.* = &node.base; |
| 476 | 487 | ||
| ... | @@ -485,13 +496,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -485,13 +496,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 485 | continue; | 496 | continue; |
| 486 | }, | 497 | }, |
| 487 | Token.Id.Keyword_union => { | 498 | Token.Id.Keyword_union => { |
| 488 | const node = try arena.create(ast.Node.UnionTag{ | 499 | const node = try arena.create(ast.Node.UnionTag); |
| 500 | node.* = ast.Node.UnionTag{ | ||
| 489 | .base = ast.Node{ .id = ast.Node.Id.UnionTag }, | 501 | .base = ast.Node{ .id = ast.Node.Id.UnionTag }, |
| 490 | .name_token = token_index, | 502 | .name_token = token_index, |
| 491 | .type_expr = null, | 503 | .type_expr = null, |
| 492 | .value_expr = null, | 504 | .value_expr = null, |
| 493 | .doc_comments = comments, | 505 | .doc_comments = comments, |
| 494 | }); | 506 | }; |
| 495 | try container_decl.fields_and_decls.push(&node.base); | 507 | try container_decl.fields_and_decls.push(&node.base); |
| 496 | 508 | ||
| 497 | try stack.append(State{ | 509 | try stack.append(State{ |
| ... | @@ -506,12 +518,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -506,12 +518,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 506 | continue; | 518 | continue; |
| 507 | }, | 519 | }, |
| 508 | Token.Id.Keyword_enum => { | 520 | Token.Id.Keyword_enum => { |
| 509 | const node = try arena.create(ast.Node.EnumTag{ | 521 | const node = try arena.create(ast.Node.EnumTag); |
| 522 | node.* = ast.Node.EnumTag{ | ||
| 510 | .base = ast.Node{ .id = ast.Node.Id.EnumTag }, | 523 | .base = ast.Node{ .id = ast.Node.Id.EnumTag }, |
| 511 | .name_token = token_index, | 524 | .name_token = token_index, |
| 512 | .value = null, | 525 | .value = null, |
| 513 | .doc_comments = comments, | 526 | .doc_comments = comments, |
| 514 | }); | 527 | }; |
| 515 | try container_decl.fields_and_decls.push(&node.base); | 528 | try container_decl.fields_and_decls.push(&node.base); |
| 516 | 529 | ||
| 517 | try stack.append(State{ | 530 | try stack.append(State{ |
| ... | @@ -593,7 +606,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -593,7 +606,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 593 | }, | 606 | }, |
| 594 | 607 | ||
| 595 | State.VarDecl => |ctx| { | 608 | State.VarDecl => |ctx| { |
| 596 | const var_decl = try arena.create(ast.Node.VarDecl{ | 609 | const var_decl = try arena.create(ast.Node.VarDecl); |
| 610 | var_decl.* = ast.Node.VarDecl{ | ||
| 597 | .base = ast.Node{ .id = ast.Node.Id.VarDecl }, | 611 | .base = ast.Node{ .id = ast.Node.Id.VarDecl }, |
| 598 | .doc_comments = ctx.comments, | 612 | .doc_comments = ctx.comments, |
| 599 | .visib_token = ctx.visib_token, | 613 | .visib_token = ctx.visib_token, |
| ... | @@ -609,7 +623,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -609,7 +623,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 609 | .name_token = undefined, | 623 | .name_token = undefined, |
| 610 | .eq_token = undefined, | 624 | .eq_token = undefined, |
| 611 | .semicolon_token = undefined, | 625 | .semicolon_token = undefined, |
| 612 | }); | 626 | }; |
| 613 | try ctx.list.push(&var_decl.base); | 627 | try ctx.list.push(&var_decl.base); |
| 614 | 628 | ||
| 615 | try stack.append(State{ .VarDeclAlign = var_decl }); | 629 | try stack.append(State{ .VarDeclAlign = var_decl }); |
| ... | @@ -708,13 +722,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -708,13 +722,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 708 | const token_ptr = token.ptr; | 722 | const token_ptr = token.ptr; |
| 709 | switch (token_ptr.id) { | 723 | switch (token_ptr.id) { |
| 710 | Token.Id.LBrace => { | 724 | Token.Id.LBrace => { |
| 711 | const block = try arena.create(ast.Node.Block{ | 725 | const block = try arena.create(ast.Node.Block); |
| 726 | block.* = ast.Node.Block{ | ||
| 712 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 727 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 713 | .label = null, | 728 | .label = null, |
| 714 | .lbrace = token_index, | 729 | .lbrace = token_index, |
| 715 | .statements = ast.Node.Block.StatementList.init(arena), | 730 | .statements = ast.Node.Block.StatementList.init(arena), |
| 716 | .rbrace = undefined, | 731 | .rbrace = undefined, |
| 717 | }); | 732 | }; |
| 718 | fn_proto.body_node = &block.base; | 733 | fn_proto.body_node = &block.base; |
| 719 | stack.append(State{ .Block = block }) catch unreachable; | 734 | stack.append(State{ .Block = block }) catch unreachable; |
| 720 | continue; | 735 | continue; |
| ... | @@ -770,10 +785,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -770,10 +785,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 770 | // TODO: this is a special case. Remove this when #760 is fixed | 785 | // TODO: this is a special case. Remove this when #760 is fixed |
| 771 | if (token_ptr.id == Token.Id.Keyword_anyerror) { | 786 | if (token_ptr.id == Token.Id.Keyword_anyerror) { |
| 772 | if (tok_it.peek().?.id == Token.Id.LBrace) { | 787 | if (tok_it.peek().?.id == Token.Id.LBrace) { |
| 773 | const error_type_node = try arena.create(ast.Node.ErrorType{ | 788 | const error_type_node = try arena.create(ast.Node.ErrorType); |
| 789 | error_type_node.* = ast.Node.ErrorType{ | ||
| 774 | .base = ast.Node{ .id = ast.Node.Id.ErrorType }, | 790 | .base = ast.Node{ .id = ast.Node.Id.ErrorType }, |
| 775 | .token = token_index, | 791 | .token = token_index, |
| 776 | }); | 792 | }; |
| 777 | fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base }; | 793 | fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base }; |
| 778 | continue; | 794 | continue; |
| 779 | } | 795 | } |
| ... | @@ -791,14 +807,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -791,14 +807,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 791 | if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| { | 807 | if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| { |
| 792 | continue; | 808 | continue; |
| 793 | } | 809 | } |
| 794 | const param_decl = try arena.create(ast.Node.ParamDecl{ | 810 | const param_decl = try arena.create(ast.Node.ParamDecl); |
| 811 | param_decl.* = ast.Node.ParamDecl{ | ||
| 795 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, | 812 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| 796 | .comptime_token = null, | 813 | .comptime_token = null, |
| 797 | .noalias_token = null, | 814 | .noalias_token = null, |
| 798 | .name_token = null, | 815 | .name_token = null, |
| 799 | .type_node = undefined, | 816 | .type_node = undefined, |
| 800 | .var_args_token = null, | 817 | .var_args_token = null, |
| 801 | }); | 818 | }; |
| 802 | try fn_proto.params.push(&param_decl.base); | 819 | try fn_proto.params.push(&param_decl.base); |
| 803 | 820 | ||
| 804 | stack.append(State{ | 821 | stack.append(State{ |
| ... | @@ -877,13 +894,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -877,13 +894,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 877 | const token_ptr = token.ptr; | 894 | const token_ptr = token.ptr; |
| 878 | switch (token_ptr.id) { | 895 | switch (token_ptr.id) { |
| 879 | Token.Id.LBrace => { | 896 | Token.Id.LBrace => { |
| 880 | const block = try arena.create(ast.Node.Block{ | 897 | const block = try arena.create(ast.Node.Block); |
| 898 | block.* = ast.Node.Block{ | ||
| 881 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 899 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 882 | .label = ctx.label, | 900 | .label = ctx.label, |
| 883 | .lbrace = token_index, | 901 | .lbrace = token_index, |
| 884 | .statements = ast.Node.Block.StatementList.init(arena), | 902 | .statements = ast.Node.Block.StatementList.init(arena), |
| 885 | .rbrace = undefined, | 903 | .rbrace = undefined, |
| 886 | }); | 904 | }; |
| 887 | ctx.opt_ctx.store(&block.base); | 905 | ctx.opt_ctx.store(&block.base); |
| 888 | stack.append(State{ .Block = block }) catch unreachable; | 906 | stack.append(State{ .Block = block }) catch unreachable; |
| 889 | continue; | 907 | continue; |
| ... | @@ -970,7 +988,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -970,7 +988,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 970 | } | 988 | } |
| 971 | }, | 989 | }, |
| 972 | State.While => |ctx| { | 990 | State.While => |ctx| { |
| 973 | const node = try arena.create(ast.Node.While{ | 991 | const node = try arena.create(ast.Node.While); |
| 992 | node.* = ast.Node.While{ | ||
| 974 | .base = ast.Node{ .id = ast.Node.Id.While }, | 993 | .base = ast.Node{ .id = ast.Node.Id.While }, |
| 975 | .label = ctx.label, | 994 | .label = ctx.label, |
| 976 | .inline_token = ctx.inline_token, | 995 | .inline_token = ctx.inline_token, |
| ... | @@ -980,7 +999,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -980,7 +999,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 980 | .continue_expr = null, | 999 | .continue_expr = null, |
| 981 | .body = undefined, | 1000 | .body = undefined, |
| 982 | .@"else" = null, | 1001 | .@"else" = null, |
| 983 | }); | 1002 | }; |
| 984 | ctx.opt_ctx.store(&node.base); | 1003 | ctx.opt_ctx.store(&node.base); |
| 985 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; | 1004 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; |
| 986 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); | 1005 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); |
| ... | @@ -999,7 +1018,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -999,7 +1018,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 999 | continue; | 1018 | continue; |
| 1000 | }, | 1019 | }, |
| 1001 | State.For => |ctx| { | 1020 | State.For => |ctx| { |
| 1002 | const node = try arena.create(ast.Node.For{ | 1021 | const node = try arena.create(ast.Node.For); |
| 1022 | node.* = ast.Node.For{ | ||
| 1003 | .base = ast.Node{ .id = ast.Node.Id.For }, | 1023 | .base = ast.Node{ .id = ast.Node.Id.For }, |
| 1004 | .label = ctx.label, | 1024 | .label = ctx.label, |
| 1005 | .inline_token = ctx.inline_token, | 1025 | .inline_token = ctx.inline_token, |
| ... | @@ -1008,7 +1028,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1008,7 +1028,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1008 | .payload = null, | 1028 | .payload = null, |
| 1009 | .body = undefined, | 1029 | .body = undefined, |
| 1010 | .@"else" = null, | 1030 | .@"else" = null, |
| 1011 | }); | 1031 | }; |
| 1012 | ctx.opt_ctx.store(&node.base); | 1032 | ctx.opt_ctx.store(&node.base); |
| 1013 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; | 1033 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; |
| 1014 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); | 1034 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); |
| ... | @@ -1020,12 +1040,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1020,12 +1040,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1020 | }, | 1040 | }, |
| 1021 | State.Else => |dest| { | 1041 | State.Else => |dest| { |
| 1022 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| { | 1042 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| { |
| 1023 | const node = try arena.create(ast.Node.Else{ | 1043 | const node = try arena.create(ast.Node.Else); |
| 1044 | node.* = ast.Node.Else{ | ||
| 1024 | .base = ast.Node{ .id = ast.Node.Id.Else }, | 1045 | .base = ast.Node{ .id = ast.Node.Id.Else }, |
| 1025 | .else_token = else_token, | 1046 | .else_token = else_token, |
| 1026 | .payload = null, | 1047 | .payload = null, |
| 1027 | .body = undefined, | 1048 | .body = undefined, |
| 1028 | }); | 1049 | }; |
| 1029 | dest.* = node; | 1050 | dest.* = node; |
| 1030 | 1051 | ||
| 1031 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable; | 1052 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable; |
| ... | @@ -1083,11 +1104,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1083,11 +1104,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1083 | continue; | 1104 | continue; |
| 1084 | }, | 1105 | }, |
| 1085 | Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => { | 1106 | Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => { |
| 1086 | const node = try arena.create(ast.Node.Defer{ | 1107 | const node = try arena.create(ast.Node.Defer); |
| 1108 | node.* = ast.Node.Defer{ | ||
| 1087 | .base = ast.Node{ .id = ast.Node.Id.Defer }, | 1109 | .base = ast.Node{ .id = ast.Node.Id.Defer }, |
| 1088 | .defer_token = token_index, | 1110 | .defer_token = token_index, |
| 1089 | .expr = undefined, | 1111 | .expr = undefined, |
| 1090 | }); | 1112 | }; |
| 1091 | const node_ptr = try block.statements.addOne(); | 1113 | const node_ptr = try block.statements.addOne(); |
| 1092 | node_ptr.* = &node.base; | 1114 | node_ptr.* = &node.base; |
| 1093 | 1115 | ||
| ... | @@ -1096,13 +1118,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1096,13 +1118,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1096 | continue; | 1118 | continue; |
| 1097 | }, | 1119 | }, |
| 1098 | Token.Id.LBrace => { | 1120 | Token.Id.LBrace => { |
| 1099 | const inner_block = try arena.create(ast.Node.Block{ | 1121 | const inner_block = try arena.create(ast.Node.Block); |
| 1122 | inner_block.* = ast.Node.Block{ | ||
| 1100 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 1123 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 1101 | .label = null, | 1124 | .label = null, |
| 1102 | .lbrace = token_index, | 1125 | .lbrace = token_index, |
| 1103 | .statements = ast.Node.Block.StatementList.init(arena), | 1126 | .statements = ast.Node.Block.StatementList.init(arena), |
| 1104 | .rbrace = undefined, | 1127 | .rbrace = undefined, |
| 1105 | }); | 1128 | }; |
| 1106 | try block.statements.push(&inner_block.base); | 1129 | try block.statements.push(&inner_block.base); |
| 1107 | 1130 | ||
| 1108 | stack.append(State{ .Block = inner_block }) catch unreachable; | 1131 | stack.append(State{ .Block = inner_block }) catch unreachable; |
| ... | @@ -1164,14 +1187,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1164,14 +1187,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1164 | continue; | 1187 | continue; |
| 1165 | } | 1188 | } |
| 1166 | 1189 | ||
| 1167 | const node = try arena.create(ast.Node.AsmOutput{ | 1190 | const node = try arena.create(ast.Node.AsmOutput); |
| 1191 | node.* = ast.Node.AsmOutput{ | ||
| 1168 | .base = ast.Node{ .id = ast.Node.Id.AsmOutput }, | 1192 | .base = ast.Node{ .id = ast.Node.Id.AsmOutput }, |
| 1169 | .lbracket = lbracket_index, | 1193 | .lbracket = lbracket_index, |
| 1170 | .symbolic_name = undefined, | 1194 | .symbolic_name = undefined, |
| 1171 | .constraint = undefined, | 1195 | .constraint = undefined, |
| 1172 | .kind = undefined, | 1196 | .kind = undefined, |
| 1173 | .rparen = undefined, | 1197 | .rparen = undefined, |
| 1174 | }); | 1198 | }; |
| 1175 | try items.push(node); | 1199 | try items.push(node); |
| 1176 | 1200 | ||
| 1177 | stack.append(State{ .AsmOutputItems = items }) catch unreachable; | 1201 | stack.append(State{ .AsmOutputItems = items }) catch unreachable; |
| ... | @@ -1218,14 +1242,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1218,14 +1242,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1218 | continue; | 1242 | continue; |
| 1219 | } | 1243 | } |
| 1220 | 1244 | ||
| 1221 | const node = try arena.create(ast.Node.AsmInput{ | 1245 | const node = try arena.create(ast.Node.AsmInput); |
| 1246 | node.* = ast.Node.AsmInput{ | ||
| 1222 | .base = ast.Node{ .id = ast.Node.Id.AsmInput }, | 1247 | .base = ast.Node{ .id = ast.Node.Id.AsmInput }, |
| 1223 | .lbracket = lbracket_index, | 1248 | .lbracket = lbracket_index, |
| 1224 | .symbolic_name = undefined, | 1249 | .symbolic_name = undefined, |
| 1225 | .constraint = undefined, | 1250 | .constraint = undefined, |
| 1226 | .expr = undefined, | 1251 | .expr = undefined, |
| 1227 | .rparen = undefined, | 1252 | .rparen = undefined, |
| 1228 | }); | 1253 | }; |
| 1229 | try items.push(node); | 1254 | try items.push(node); |
| 1230 | 1255 | ||
| 1231 | stack.append(State{ .AsmInputItems = items }) catch unreachable; | 1256 | stack.append(State{ .AsmInputItems = items }) catch unreachable; |
| ... | @@ -1283,12 +1308,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1283,12 +1308,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1283 | continue; | 1308 | continue; |
| 1284 | } | 1309 | } |
| 1285 | 1310 | ||
| 1286 | const node = try arena.create(ast.Node.FieldInitializer{ | 1311 | const node = try arena.create(ast.Node.FieldInitializer); |
| 1312 | node.* = ast.Node.FieldInitializer{ | ||
| 1287 | .base = ast.Node{ .id = ast.Node.Id.FieldInitializer }, | 1313 | .base = ast.Node{ .id = ast.Node.Id.FieldInitializer }, |
| 1288 | .period_token = undefined, | 1314 | .period_token = undefined, |
| 1289 | .name_token = undefined, | 1315 | .name_token = undefined, |
| 1290 | .expr = undefined, | 1316 | .expr = undefined, |
| 1291 | }); | 1317 | }; |
| 1292 | try list_state.list.push(&node.base); | 1318 | try list_state.list.push(&node.base); |
| 1293 | 1319 | ||
| 1294 | stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable; | 1320 | stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable; |
| ... | @@ -1390,13 +1416,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1390,13 +1416,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1390 | } | 1416 | } |
| 1391 | 1417 | ||
| 1392 | const comments = try eatDocComments(arena, &tok_it, &tree); | 1418 | const comments = try eatDocComments(arena, &tok_it, &tree); |
| 1393 | const node = try arena.create(ast.Node.SwitchCase{ | 1419 | const node = try arena.create(ast.Node.SwitchCase); |
| 1420 | node.* = ast.Node.SwitchCase{ | ||
| 1394 | .base = ast.Node{ .id = ast.Node.Id.SwitchCase }, | 1421 | .base = ast.Node{ .id = ast.Node.Id.SwitchCase }, |
| 1395 | .items = ast.Node.SwitchCase.ItemList.init(arena), | 1422 | .items = ast.Node.SwitchCase.ItemList.init(arena), |
| 1396 | .payload = null, | 1423 | .payload = null, |
| 1397 | .expr = undefined, | 1424 | .expr = undefined, |
| 1398 | .arrow_token = undefined, | 1425 | .arrow_token = undefined, |
| 1399 | }); | 1426 | }; |
| 1400 | try list_state.list.push(&node.base); | 1427 | try list_state.list.push(&node.base); |
| 1401 | try stack.append(State{ .SwitchCaseCommaOrEnd = list_state }); | 1428 | try stack.append(State{ .SwitchCaseCommaOrEnd = list_state }); |
| 1402 | try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } }); | 1429 | try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } }); |
| ... | @@ -1427,10 +1454,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1427,10 +1454,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1427 | const token_index = token.index; | 1454 | const token_index = token.index; |
| 1428 | const token_ptr = token.ptr; | 1455 | const token_ptr = token.ptr; |
| 1429 | if (token_ptr.id == Token.Id.Keyword_else) { | 1456 | if (token_ptr.id == Token.Id.Keyword_else) { |
| 1430 | const else_node = try arena.create(ast.Node.SwitchElse{ | 1457 | const else_node = try arena.create(ast.Node.SwitchElse); |
| 1458 | else_node.* = ast.Node.SwitchElse{ | ||
| 1431 | .base = ast.Node{ .id = ast.Node.Id.SwitchElse }, | 1459 | .base = ast.Node{ .id = ast.Node.Id.SwitchElse }, |
| 1432 | .token = token_index, | 1460 | .token = token_index, |
| 1433 | }); | 1461 | }; |
| 1434 | try switch_case.items.push(&else_node.base); | 1462 | try switch_case.items.push(&else_node.base); |
| 1435 | 1463 | ||
| 1436 | try stack.append(State{ | 1464 | try stack.append(State{ |
| ... | @@ -1537,7 +1565,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1537,7 +1565,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1537 | 1565 | ||
| 1538 | State.ExternType => |ctx| { | 1566 | State.ExternType => |ctx| { |
| 1539 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| { | 1567 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| { |
| 1540 | const fn_proto = try arena.create(ast.Node.FnProto{ | 1568 | const fn_proto = try arena.create(ast.Node.FnProto); |
| 1569 | fn_proto.* = ast.Node.FnProto{ | ||
| 1541 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | 1570 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 1542 | .doc_comments = ctx.comments, | 1571 | .doc_comments = ctx.comments, |
| 1543 | .visib_token = null, | 1572 | .visib_token = null, |
| ... | @@ -1553,7 +1582,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1553,7 +1582,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1553 | .lib_name = null, | 1582 | .lib_name = null, |
| 1554 | .align_expr = null, | 1583 | .align_expr = null, |
| 1555 | .section_expr = null, | 1584 | .section_expr = null, |
| 1556 | }); | 1585 | }; |
| 1557 | ctx.opt_ctx.store(&fn_proto.base); | 1586 | ctx.opt_ctx.store(&fn_proto.base); |
| 1558 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; | 1587 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 1559 | continue; | 1588 | continue; |
| ... | @@ -1711,12 +1740,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1711,12 +1740,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1711 | continue; | 1740 | continue; |
| 1712 | } | 1741 | } |
| 1713 | 1742 | ||
| 1714 | const node = try arena.create(ast.Node.Payload{ | 1743 | const node = try arena.create(ast.Node.Payload); |
| 1744 | node.* = ast.Node.Payload{ | ||
| 1715 | .base = ast.Node{ .id = ast.Node.Id.Payload }, | 1745 | .base = ast.Node{ .id = ast.Node.Id.Payload }, |
| 1716 | .lpipe = token_index, | 1746 | .lpipe = token_index, |
| 1717 | .error_symbol = undefined, | 1747 | .error_symbol = undefined, |
| 1718 | .rpipe = undefined, | 1748 | .rpipe = undefined, |
| 1719 | }); | 1749 | }; |
| 1720 | opt_ctx.store(&node.base); | 1750 | opt_ctx.store(&node.base); |
| 1721 | 1751 | ||
| 1722 | stack.append(State{ | 1752 | stack.append(State{ |
| ... | @@ -1747,13 +1777,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1747,13 +1777,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1747 | continue; | 1777 | continue; |
| 1748 | } | 1778 | } |
| 1749 | 1779 | ||
| 1750 | const node = try arena.create(ast.Node.PointerPayload{ | 1780 | const node = try arena.create(ast.Node.PointerPayload); |
| 1781 | node.* = ast.Node.PointerPayload{ | ||
| 1751 | .base = ast.Node{ .id = ast.Node.Id.PointerPayload }, | 1782 | .base = ast.Node{ .id = ast.Node.Id.PointerPayload }, |
| 1752 | .lpipe = token_index, | 1783 | .lpipe = token_index, |
| 1753 | .ptr_token = null, | 1784 | .ptr_token = null, |
| 1754 | .value_symbol = undefined, | 1785 | .value_symbol = undefined, |
| 1755 | .rpipe = undefined, | 1786 | .rpipe = undefined, |
| 1756 | }); | 1787 | }; |
| 1757 | opt_ctx.store(&node.base); | 1788 | opt_ctx.store(&node.base); |
| 1758 | 1789 | ||
| 1759 | try stack.append(State{ | 1790 | try stack.append(State{ |
| ... | @@ -1790,14 +1821,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1790,14 +1821,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1790 | continue; | 1821 | continue; |
| 1791 | } | 1822 | } |
| 1792 | 1823 | ||
| 1793 | const node = try arena.create(ast.Node.PointerIndexPayload{ | 1824 | const node = try arena.create(ast.Node.PointerIndexPayload); |
| 1825 | node.* = ast.Node.PointerIndexPayload{ | ||
| 1794 | .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload }, | 1826 | .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload }, |
| 1795 | .lpipe = token_index, | 1827 | .lpipe = token_index, |
| 1796 | .ptr_token = null, | 1828 | .ptr_token = null, |
| 1797 | .value_symbol = undefined, | 1829 | .value_symbol = undefined, |
| 1798 | .index_symbol = null, | 1830 | .index_symbol = null, |
| 1799 | .rpipe = undefined, | 1831 | .rpipe = undefined, |
| 1800 | }); | 1832 | }; |
| 1801 | opt_ctx.store(&node.base); | 1833 | opt_ctx.store(&node.base); |
| 1802 | 1834 | ||
| 1803 | stack.append(State{ | 1835 | stack.append(State{ |
| ... | @@ -1824,12 +1856,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1824,12 +1856,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1824 | const token_ptr = token.ptr; | 1856 | const token_ptr = token.ptr; |
| 1825 | switch (token_ptr.id) { | 1857 | switch (token_ptr.id) { |
| 1826 | Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => { | 1858 | Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => { |
| 1827 | const node = try arena.create(ast.Node.ControlFlowExpression{ | 1859 | const node = try arena.create(ast.Node.ControlFlowExpression); |
| 1860 | node.* = ast.Node.ControlFlowExpression{ | ||
| 1828 | .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression }, | 1861 | .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression }, |
| 1829 | .ltoken = token_index, | 1862 | .ltoken = token_index, |
| 1830 | .kind = undefined, | 1863 | .kind = undefined, |
| 1831 | .rhs = null, | 1864 | .rhs = null, |
| 1832 | }); | 1865 | }; |
| 1833 | opt_ctx.store(&node.base); | 1866 | opt_ctx.store(&node.base); |
| 1834 | 1867 | ||
| 1835 | stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable; | 1868 | stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable; |
| ... | @@ -1853,7 +1886,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1853,7 +1886,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1853 | continue; | 1886 | continue; |
| 1854 | }, | 1887 | }, |
| 1855 | Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => { | 1888 | Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => { |
| 1856 | const node = try arena.create(ast.Node.PrefixOp{ | 1889 | const node = try arena.create(ast.Node.PrefixOp); |
| 1890 | node.* = ast.Node.PrefixOp{ | ||
| 1857 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, | 1891 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 1858 | .op_token = token_index, | 1892 | .op_token = token_index, |
| 1859 | .op = switch (token_ptr.id) { | 1893 | .op = switch (token_ptr.id) { |
| ... | @@ -1863,7 +1897,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1863,7 +1897,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1863 | else => unreachable, | 1897 | else => unreachable, |
| 1864 | }, | 1898 | }, |
| 1865 | .rhs = undefined, | 1899 | .rhs = undefined, |
| 1866 | }); | 1900 | }; |
| 1867 | opt_ctx.store(&node.base); | 1901 | opt_ctx.store(&node.base); |
| 1868 | 1902 | ||
| 1869 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; | 1903 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; |
| ... | @@ -1887,13 +1921,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1887,13 +1921,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1887 | const lhs = opt_ctx.get() orelse continue; | 1921 | const lhs = opt_ctx.get() orelse continue; |
| 1888 | 1922 | ||
| 1889 | if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { | 1923 | if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { |
| 1890 | const node = try arena.create(ast.Node.InfixOp{ | 1924 | const node = try arena.create(ast.Node.InfixOp); |
| 1925 | node.* = ast.Node.InfixOp{ | ||
| 1891 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 1926 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1892 | .lhs = lhs, | 1927 | .lhs = lhs, |
| 1893 | .op_token = ellipsis3, | 1928 | .op_token = ellipsis3, |
| 1894 | .op = ast.Node.InfixOp.Op.Range, | 1929 | .op = ast.Node.InfixOp.Op.Range, |
| 1895 | .rhs = undefined, | 1930 | .rhs = undefined, |
| 1896 | }); | 1931 | }; |
| 1897 | opt_ctx.store(&node.base); | 1932 | opt_ctx.store(&node.base); |
| 1898 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; | 1933 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; |
| 1899 | continue; | 1934 | continue; |
| ... | @@ -1912,13 +1947,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1912,13 +1947,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1912 | const token_index = token.index; | 1947 | const token_index = token.index; |
| 1913 | const token_ptr = token.ptr; | 1948 | const token_ptr = token.ptr; |
| 1914 | if (tokenIdToAssignment(token_ptr.id)) |ass_id| { | 1949 | if (tokenIdToAssignment(token_ptr.id)) |ass_id| { |
| 1915 | const node = try arena.create(ast.Node.InfixOp{ | 1950 | const node = try arena.create(ast.Node.InfixOp); |
| 1951 | node.* = ast.Node.InfixOp{ | ||
| 1916 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 1952 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1917 | .lhs = lhs, | 1953 | .lhs = lhs, |
| 1918 | .op_token = token_index, | 1954 | .op_token = token_index, |
| 1919 | .op = ass_id, | 1955 | .op = ass_id, |
| 1920 | .rhs = undefined, | 1956 | .rhs = undefined, |
| 1921 | }); | 1957 | }; |
| 1922 | opt_ctx.store(&node.base); | 1958 | opt_ctx.store(&node.base); |
| 1923 | stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 1959 | stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 1924 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }); | 1960 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -1942,13 +1978,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1942,13 +1978,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1942 | const token_index = token.index; | 1978 | const token_index = token.index; |
| 1943 | const token_ptr = token.ptr; | 1979 | const token_ptr = token.ptr; |
| 1944 | if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| { | 1980 | if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| { |
| 1945 | const node = try arena.create(ast.Node.InfixOp{ | 1981 | const node = try arena.create(ast.Node.InfixOp); |
| 1982 | node.* = ast.Node.InfixOp{ | ||
| 1946 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 1983 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1947 | .lhs = lhs, | 1984 | .lhs = lhs, |
| 1948 | .op_token = token_index, | 1985 | .op_token = token_index, |
| 1949 | .op = unwrap_id, | 1986 | .op = unwrap_id, |
| 1950 | .rhs = undefined, | 1987 | .rhs = undefined, |
| 1951 | }); | 1988 | }; |
| 1952 | opt_ctx.store(&node.base); | 1989 | opt_ctx.store(&node.base); |
| 1953 | 1990 | ||
| 1954 | stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 1991 | stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| ... | @@ -1974,13 +2011,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1974,13 +2011,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1974 | const lhs = opt_ctx.get() orelse continue; | 2011 | const lhs = opt_ctx.get() orelse continue; |
| 1975 | 2012 | ||
| 1976 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| { | 2013 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| { |
| 1977 | const node = try arena.create(ast.Node.InfixOp{ | 2014 | const node = try arena.create(ast.Node.InfixOp); |
| 2015 | node.* = ast.Node.InfixOp{ | ||
| 1978 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2016 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1979 | .lhs = lhs, | 2017 | .lhs = lhs, |
| 1980 | .op_token = or_token, | 2018 | .op_token = or_token, |
| 1981 | .op = ast.Node.InfixOp.Op.BoolOr, | 2019 | .op = ast.Node.InfixOp.Op.BoolOr, |
| 1982 | .rhs = undefined, | 2020 | .rhs = undefined, |
| 1983 | }); | 2021 | }; |
| 1984 | opt_ctx.store(&node.base); | 2022 | opt_ctx.store(&node.base); |
| 1985 | stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2023 | stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 1986 | try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2024 | try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -1998,13 +2036,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -1998,13 +2036,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1998 | const lhs = opt_ctx.get() orelse continue; | 2036 | const lhs = opt_ctx.get() orelse continue; |
| 1999 | 2037 | ||
| 2000 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| { | 2038 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| { |
| 2001 | const node = try arena.create(ast.Node.InfixOp{ | 2039 | const node = try arena.create(ast.Node.InfixOp); |
| 2040 | node.* = ast.Node.InfixOp{ | ||
| 2002 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2041 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2003 | .lhs = lhs, | 2042 | .lhs = lhs, |
| 2004 | .op_token = and_token, | 2043 | .op_token = and_token, |
| 2005 | .op = ast.Node.InfixOp.Op.BoolAnd, | 2044 | .op = ast.Node.InfixOp.Op.BoolAnd, |
| 2006 | .rhs = undefined, | 2045 | .rhs = undefined, |
| 2007 | }); | 2046 | }; |
| 2008 | opt_ctx.store(&node.base); | 2047 | opt_ctx.store(&node.base); |
| 2009 | stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2048 | stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2010 | try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2049 | try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2025,13 +2064,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2025,13 +2064,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2025 | const token_index = token.index; | 2064 | const token_index = token.index; |
| 2026 | const token_ptr = token.ptr; | 2065 | const token_ptr = token.ptr; |
| 2027 | if (tokenIdToComparison(token_ptr.id)) |comp_id| { | 2066 | if (tokenIdToComparison(token_ptr.id)) |comp_id| { |
| 2028 | const node = try arena.create(ast.Node.InfixOp{ | 2067 | const node = try arena.create(ast.Node.InfixOp); |
| 2068 | node.* = ast.Node.InfixOp{ | ||
| 2029 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2069 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2030 | .lhs = lhs, | 2070 | .lhs = lhs, |
| 2031 | .op_token = token_index, | 2071 | .op_token = token_index, |
| 2032 | .op = comp_id, | 2072 | .op = comp_id, |
| 2033 | .rhs = undefined, | 2073 | .rhs = undefined, |
| 2034 | }); | 2074 | }; |
| 2035 | opt_ctx.store(&node.base); | 2075 | opt_ctx.store(&node.base); |
| 2036 | stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2076 | stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2037 | try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2077 | try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2052,13 +2092,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2052,13 +2092,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2052 | const lhs = opt_ctx.get() orelse continue; | 2092 | const lhs = opt_ctx.get() orelse continue; |
| 2053 | 2093 | ||
| 2054 | if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| { | 2094 | if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| { |
| 2055 | const node = try arena.create(ast.Node.InfixOp{ | 2095 | const node = try arena.create(ast.Node.InfixOp); |
| 2096 | node.* = ast.Node.InfixOp{ | ||
| 2056 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2097 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2057 | .lhs = lhs, | 2098 | .lhs = lhs, |
| 2058 | .op_token = pipe, | 2099 | .op_token = pipe, |
| 2059 | .op = ast.Node.InfixOp.Op.BitOr, | 2100 | .op = ast.Node.InfixOp.Op.BitOr, |
| 2060 | .rhs = undefined, | 2101 | .rhs = undefined, |
| 2061 | }); | 2102 | }; |
| 2062 | opt_ctx.store(&node.base); | 2103 | opt_ctx.store(&node.base); |
| 2063 | stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2104 | stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2064 | try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2105 | try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2076,13 +2117,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2076,13 +2117,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2076 | const lhs = opt_ctx.get() orelse continue; | 2117 | const lhs = opt_ctx.get() orelse continue; |
| 2077 | 2118 | ||
| 2078 | if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| { | 2119 | if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| { |
| 2079 | const node = try arena.create(ast.Node.InfixOp{ | 2120 | const node = try arena.create(ast.Node.InfixOp); |
| 2121 | node.* = ast.Node.InfixOp{ | ||
| 2080 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2122 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2081 | .lhs = lhs, | 2123 | .lhs = lhs, |
| 2082 | .op_token = caret, | 2124 | .op_token = caret, |
| 2083 | .op = ast.Node.InfixOp.Op.BitXor, | 2125 | .op = ast.Node.InfixOp.Op.BitXor, |
| 2084 | .rhs = undefined, | 2126 | .rhs = undefined, |
| 2085 | }); | 2127 | }; |
| 2086 | opt_ctx.store(&node.base); | 2128 | opt_ctx.store(&node.base); |
| 2087 | stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2129 | stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2088 | try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2130 | try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2100,13 +2142,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2100,13 +2142,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2100 | const lhs = opt_ctx.get() orelse continue; | 2142 | const lhs = opt_ctx.get() orelse continue; |
| 2101 | 2143 | ||
| 2102 | if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| { | 2144 | if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| { |
| 2103 | const node = try arena.create(ast.Node.InfixOp{ | 2145 | const node = try arena.create(ast.Node.InfixOp); |
| 2146 | node.* = ast.Node.InfixOp{ | ||
| 2104 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2147 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2105 | .lhs = lhs, | 2148 | .lhs = lhs, |
| 2106 | .op_token = ampersand, | 2149 | .op_token = ampersand, |
| 2107 | .op = ast.Node.InfixOp.Op.BitAnd, | 2150 | .op = ast.Node.InfixOp.Op.BitAnd, |
| 2108 | .rhs = undefined, | 2151 | .rhs = undefined, |
| 2109 | }); | 2152 | }; |
| 2110 | opt_ctx.store(&node.base); | 2153 | opt_ctx.store(&node.base); |
| 2111 | stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2154 | stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2112 | try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2155 | try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2127,13 +2170,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2127,13 +2170,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2127 | const token_index = token.index; | 2170 | const token_index = token.index; |
| 2128 | const token_ptr = token.ptr; | 2171 | const token_ptr = token.ptr; |
| 2129 | if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| { | 2172 | if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| { |
| 2130 | const node = try arena.create(ast.Node.InfixOp{ | 2173 | const node = try arena.create(ast.Node.InfixOp); |
| 2174 | node.* = ast.Node.InfixOp{ | ||
| 2131 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2175 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2132 | .lhs = lhs, | 2176 | .lhs = lhs, |
| 2133 | .op_token = token_index, | 2177 | .op_token = token_index, |
| 2134 | .op = bitshift_id, | 2178 | .op = bitshift_id, |
| 2135 | .rhs = undefined, | 2179 | .rhs = undefined, |
| 2136 | }); | 2180 | }; |
| 2137 | opt_ctx.store(&node.base); | 2181 | opt_ctx.store(&node.base); |
| 2138 | stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2182 | stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2139 | try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2183 | try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2157,13 +2201,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2157,13 +2201,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2157 | const token_index = token.index; | 2201 | const token_index = token.index; |
| 2158 | const token_ptr = token.ptr; | 2202 | const token_ptr = token.ptr; |
| 2159 | if (tokenIdToAddition(token_ptr.id)) |add_id| { | 2203 | if (tokenIdToAddition(token_ptr.id)) |add_id| { |
| 2160 | const node = try arena.create(ast.Node.InfixOp{ | 2204 | const node = try arena.create(ast.Node.InfixOp); |
| 2205 | node.* = ast.Node.InfixOp{ | ||
| 2161 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2206 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2162 | .lhs = lhs, | 2207 | .lhs = lhs, |
| 2163 | .op_token = token_index, | 2208 | .op_token = token_index, |
| 2164 | .op = add_id, | 2209 | .op = add_id, |
| 2165 | .rhs = undefined, | 2210 | .rhs = undefined, |
| 2166 | }); | 2211 | }; |
| 2167 | opt_ctx.store(&node.base); | 2212 | opt_ctx.store(&node.base); |
| 2168 | stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2213 | stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2169 | try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2214 | try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2187,13 +2232,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2187,13 +2232,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2187 | const token_index = token.index; | 2232 | const token_index = token.index; |
| 2188 | const token_ptr = token.ptr; | 2233 | const token_ptr = token.ptr; |
| 2189 | if (tokenIdToMultiply(token_ptr.id)) |mult_id| { | 2234 | if (tokenIdToMultiply(token_ptr.id)) |mult_id| { |
| 2190 | const node = try arena.create(ast.Node.InfixOp{ | 2235 | const node = try arena.create(ast.Node.InfixOp); |
| 2236 | node.* = ast.Node.InfixOp{ | ||
| 2191 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2237 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2192 | .lhs = lhs, | 2238 | .lhs = lhs, |
| 2193 | .op_token = token_index, | 2239 | .op_token = token_index, |
| 2194 | .op = mult_id, | 2240 | .op = mult_id, |
| 2195 | .rhs = undefined, | 2241 | .rhs = undefined, |
| 2196 | }); | 2242 | }; |
| 2197 | opt_ctx.store(&node.base); | 2243 | opt_ctx.store(&node.base); |
| 2198 | stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2244 | stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2199 | try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); | 2245 | try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2215,12 +2261,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2215,12 +2261,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2215 | const lhs = opt_ctx.get() orelse continue; | 2261 | const lhs = opt_ctx.get() orelse continue; |
| 2216 | 2262 | ||
| 2217 | if (tok_it.peek().?.id == Token.Id.Period) { | 2263 | if (tok_it.peek().?.id == Token.Id.Period) { |
| 2218 | const node = try arena.create(ast.Node.SuffixOp{ | 2264 | const node = try arena.create(ast.Node.SuffixOp); |
| 2265 | node.* = ast.Node.SuffixOp{ | ||
| 2219 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2266 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2220 | .lhs = lhs, | 2267 | .lhs = lhs, |
| 2221 | .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, | 2268 | .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, |
| 2222 | .rtoken = undefined, | 2269 | .rtoken = undefined, |
| 2223 | }); | 2270 | }; |
| 2224 | opt_ctx.store(&node.base); | 2271 | opt_ctx.store(&node.base); |
| 2225 | 2272 | ||
| 2226 | stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2273 | stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| ... | @@ -2234,12 +2281,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2234,12 +2281,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2234 | continue; | 2281 | continue; |
| 2235 | } | 2282 | } |
| 2236 | 2283 | ||
| 2237 | const node = try arena.create(ast.Node.SuffixOp{ | 2284 | const node = try arena.create(ast.Node.SuffixOp); |
| 2285 | node.* = ast.Node.SuffixOp{ | ||
| 2238 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2286 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2239 | .lhs = lhs, | 2287 | .lhs = lhs, |
| 2240 | .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, | 2288 | .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, |
| 2241 | .rtoken = undefined, | 2289 | .rtoken = undefined, |
| 2242 | }); | 2290 | }; |
| 2243 | opt_ctx.store(&node.base); | 2291 | opt_ctx.store(&node.base); |
| 2244 | stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2292 | stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2245 | try stack.append(State{ .IfToken = Token.Id.LBrace }); | 2293 | try stack.append(State{ .IfToken = Token.Id.LBrace }); |
| ... | @@ -2263,13 +2311,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2263,13 +2311,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2263 | const lhs = opt_ctx.get() orelse continue; | 2311 | const lhs = opt_ctx.get() orelse continue; |
| 2264 | 2312 | ||
| 2265 | if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| { | 2313 | if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| { |
| 2266 | const node = try arena.create(ast.Node.InfixOp{ | 2314 | const node = try arena.create(ast.Node.InfixOp); |
| 2315 | node.* = ast.Node.InfixOp{ | ||
| 2267 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2316 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2268 | .lhs = lhs, | 2317 | .lhs = lhs, |
| 2269 | .op_token = bang, | 2318 | .op_token = bang, |
| 2270 | .op = ast.Node.InfixOp.Op.ErrorUnion, | 2319 | .op = ast.Node.InfixOp.Op.ErrorUnion, |
| 2271 | .rhs = undefined, | 2320 | .rhs = undefined, |
| 2272 | }); | 2321 | }; |
| 2273 | opt_ctx.store(&node.base); | 2322 | opt_ctx.store(&node.base); |
| 2274 | stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable; | 2323 | stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2275 | try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } }); | 2324 | try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } }); |
| ... | @@ -2282,22 +2331,24 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2282,22 +2331,24 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2282 | const token_index = token.index; | 2331 | const token_index = token.index; |
| 2283 | const token_ptr = token.ptr; | 2332 | const token_ptr = token.ptr; |
| 2284 | if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| { | 2333 | if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| { |
| 2285 | var node = try arena.create(ast.Node.PrefixOp{ | 2334 | var node = try arena.create(ast.Node.PrefixOp); |
| 2335 | node.* = ast.Node.PrefixOp{ | ||
| 2286 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, | 2336 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2287 | .op_token = token_index, | 2337 | .op_token = token_index, |
| 2288 | .op = prefix_id, | 2338 | .op = prefix_id, |
| 2289 | .rhs = undefined, | 2339 | .rhs = undefined, |
| 2290 | }); | 2340 | }; |
| 2291 | opt_ctx.store(&node.base); | 2341 | opt_ctx.store(&node.base); |
| 2292 | 2342 | ||
| 2293 | // Treat '**' token as two pointer types | 2343 | // Treat '**' token as two pointer types |
| 2294 | if (token_ptr.id == Token.Id.AsteriskAsterisk) { | 2344 | if (token_ptr.id == Token.Id.AsteriskAsterisk) { |
| 2295 | const child = try arena.create(ast.Node.PrefixOp{ | 2345 | const child = try arena.create(ast.Node.PrefixOp); |
| 2346 | child.* = ast.Node.PrefixOp{ | ||
| 2296 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, | 2347 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2297 | .op_token = token_index, | 2348 | .op_token = token_index, |
| 2298 | .op = prefix_id, | 2349 | .op = prefix_id, |
| 2299 | .rhs = undefined, | 2350 | .rhs = undefined, |
| 2300 | }); | 2351 | }; |
| 2301 | node.rhs = &child.base; | 2352 | node.rhs = &child.base; |
| 2302 | node = child; | 2353 | node = child; |
| 2303 | } | 2354 | } |
| ... | @@ -2316,12 +2367,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2316,12 +2367,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2316 | 2367 | ||
| 2317 | State.SuffixOpExpressionBegin => |opt_ctx| { | 2368 | State.SuffixOpExpressionBegin => |opt_ctx| { |
| 2318 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| { | 2369 | if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| { |
| 2319 | const async_node = try arena.create(ast.Node.AsyncAttribute{ | 2370 | const async_node = try arena.create(ast.Node.AsyncAttribute); |
| 2371 | async_node.* = ast.Node.AsyncAttribute{ | ||
| 2320 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, | 2372 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, |
| 2321 | .async_token = async_token, | 2373 | .async_token = async_token, |
| 2322 | .allocator_type = null, | 2374 | .allocator_type = null, |
| 2323 | .rangle_bracket = null, | 2375 | .rangle_bracket = null, |
| 2324 | }); | 2376 | }; |
| 2325 | stack.append(State{ | 2377 | stack.append(State{ |
| 2326 | .AsyncEnd = AsyncEndCtx{ | 2378 | .AsyncEnd = AsyncEndCtx{ |
| 2327 | .ctx = opt_ctx, | 2379 | .ctx = opt_ctx, |
| ... | @@ -2347,7 +2399,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2347,7 +2399,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2347 | const token_ptr = token.ptr; | 2399 | const token_ptr = token.ptr; |
| 2348 | switch (token_ptr.id) { | 2400 | switch (token_ptr.id) { |
| 2349 | Token.Id.LParen => { | 2401 | Token.Id.LParen => { |
| 2350 | const node = try arena.create(ast.Node.SuffixOp{ | 2402 | const node = try arena.create(ast.Node.SuffixOp); |
| 2403 | node.* = ast.Node.SuffixOp{ | ||
| 2351 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2404 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2352 | .lhs = lhs, | 2405 | .lhs = lhs, |
| 2353 | .op = ast.Node.SuffixOp.Op{ | 2406 | .op = ast.Node.SuffixOp.Op{ |
| ... | @@ -2357,7 +2410,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2357,7 +2410,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2357 | }, | 2410 | }, |
| 2358 | }, | 2411 | }, |
| 2359 | .rtoken = undefined, | 2412 | .rtoken = undefined, |
| 2360 | }); | 2413 | }; |
| 2361 | opt_ctx.store(&node.base); | 2414 | opt_ctx.store(&node.base); |
| 2362 | 2415 | ||
| 2363 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2416 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| ... | @@ -2371,12 +2424,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2371,12 +2424,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2371 | continue; | 2424 | continue; |
| 2372 | }, | 2425 | }, |
| 2373 | Token.Id.LBracket => { | 2426 | Token.Id.LBracket => { |
| 2374 | const node = try arena.create(ast.Node.SuffixOp{ | 2427 | const node = try arena.create(ast.Node.SuffixOp); |
| 2428 | node.* = ast.Node.SuffixOp{ | ||
| 2375 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2429 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2376 | .lhs = lhs, | 2430 | .lhs = lhs, |
| 2377 | .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined }, | 2431 | .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined }, |
| 2378 | .rtoken = undefined, | 2432 | .rtoken = undefined, |
| 2379 | }); | 2433 | }; |
| 2380 | opt_ctx.store(&node.base); | 2434 | opt_ctx.store(&node.base); |
| 2381 | 2435 | ||
| 2382 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2436 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| ... | @@ -2386,34 +2440,37 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2386,34 +2440,37 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2386 | }, | 2440 | }, |
| 2387 | Token.Id.Period => { | 2441 | Token.Id.Period => { |
| 2388 | if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| { | 2442 | if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| { |
| 2389 | const node = try arena.create(ast.Node.SuffixOp{ | 2443 | const node = try arena.create(ast.Node.SuffixOp); |
| 2444 | node.* = ast.Node.SuffixOp{ | ||
| 2390 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2445 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2391 | .lhs = lhs, | 2446 | .lhs = lhs, |
| 2392 | .op = ast.Node.SuffixOp.Op.Deref, | 2447 | .op = ast.Node.SuffixOp.Op.Deref, |
| 2393 | .rtoken = asterisk_token, | 2448 | .rtoken = asterisk_token, |
| 2394 | }); | 2449 | }; |
| 2395 | opt_ctx.store(&node.base); | 2450 | opt_ctx.store(&node.base); |
| 2396 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2451 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2397 | continue; | 2452 | continue; |
| 2398 | } | 2453 | } |
| 2399 | if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| { | 2454 | if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| { |
| 2400 | const node = try arena.create(ast.Node.SuffixOp{ | 2455 | const node = try arena.create(ast.Node.SuffixOp); |
| 2456 | node.* = ast.Node.SuffixOp{ | ||
| 2401 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, | 2457 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2402 | .lhs = lhs, | 2458 | .lhs = lhs, |
| 2403 | .op = ast.Node.SuffixOp.Op.UnwrapOptional, | 2459 | .op = ast.Node.SuffixOp.Op.UnwrapOptional, |
| 2404 | .rtoken = question_token, | 2460 | .rtoken = question_token, |
| 2405 | }); | 2461 | }; |
| 2406 | opt_ctx.store(&node.base); | 2462 | opt_ctx.store(&node.base); |
| 2407 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2463 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2408 | continue; | 2464 | continue; |
| 2409 | } | 2465 | } |
| 2410 | const node = try arena.create(ast.Node.InfixOp{ | 2466 | const node = try arena.create(ast.Node.InfixOp); |
| 2467 | node.* = ast.Node.InfixOp{ | ||
| 2411 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2468 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2412 | .lhs = lhs, | 2469 | .lhs = lhs, |
| 2413 | .op_token = token_index, | 2470 | .op_token = token_index, |
| 2414 | .op = ast.Node.InfixOp.Op.Period, | 2471 | .op = ast.Node.InfixOp.Op.Period, |
| 2415 | .rhs = undefined, | 2472 | .rhs = undefined, |
| 2416 | }); | 2473 | }; |
| 2417 | opt_ctx.store(&node.base); | 2474 | opt_ctx.store(&node.base); |
| 2418 | 2475 | ||
| 2419 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; | 2476 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| ... | @@ -2467,11 +2524,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2467,11 +2524,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2467 | continue; | 2524 | continue; |
| 2468 | }, | 2525 | }, |
| 2469 | Token.Id.Keyword_promise => { | 2526 | Token.Id.Keyword_promise => { |
| 2470 | const node = try arena.create(ast.Node.PromiseType{ | 2527 | const node = try arena.create(ast.Node.PromiseType); |
| 2528 | node.* = ast.Node.PromiseType{ | ||
| 2471 | .base = ast.Node{ .id = ast.Node.Id.PromiseType }, | 2529 | .base = ast.Node{ .id = ast.Node.Id.PromiseType }, |
| 2472 | .promise_token = token.index, | 2530 | .promise_token = token.index, |
| 2473 | .result = null, | 2531 | .result = null, |
| 2474 | }); | 2532 | }; |
| 2475 | opt_ctx.store(&node.base); | 2533 | opt_ctx.store(&node.base); |
| 2476 | const next_token = nextToken(&tok_it, &tree); | 2534 | const next_token = nextToken(&tok_it, &tree); |
| 2477 | const next_token_index = next_token.index; | 2535 | const next_token_index = next_token.index; |
| ... | @@ -2493,12 +2551,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2493,12 +2551,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2493 | continue; | 2551 | continue; |
| 2494 | }, | 2552 | }, |
| 2495 | Token.Id.LParen => { | 2553 | Token.Id.LParen => { |
| 2496 | const node = try arena.create(ast.Node.GroupedExpression{ | 2554 | const node = try arena.create(ast.Node.GroupedExpression); |
| 2555 | node.* = ast.Node.GroupedExpression{ | ||
| 2497 | .base = ast.Node{ .id = ast.Node.Id.GroupedExpression }, | 2556 | .base = ast.Node{ .id = ast.Node.Id.GroupedExpression }, |
| 2498 | .lparen = token.index, | 2557 | .lparen = token.index, |
| 2499 | .expr = undefined, | 2558 | .expr = undefined, |
| 2500 | .rparen = undefined, | 2559 | .rparen = undefined, |
| 2501 | }); | 2560 | }; |
| 2502 | opt_ctx.store(&node.base); | 2561 | opt_ctx.store(&node.base); |
| 2503 | 2562 | ||
| 2504 | stack.append(State{ | 2563 | stack.append(State{ |
| ... | @@ -2511,12 +2570,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2511,12 +2570,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2511 | continue; | 2570 | continue; |
| 2512 | }, | 2571 | }, |
| 2513 | Token.Id.Builtin => { | 2572 | Token.Id.Builtin => { |
| 2514 | const node = try arena.create(ast.Node.BuiltinCall{ | 2573 | const node = try arena.create(ast.Node.BuiltinCall); |
| 2574 | node.* = ast.Node.BuiltinCall{ | ||
| 2515 | .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, | 2575 | .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, |
| 2516 | .builtin_token = token.index, | 2576 | .builtin_token = token.index, |
| 2517 | .params = ast.Node.BuiltinCall.ParamList.init(arena), | 2577 | .params = ast.Node.BuiltinCall.ParamList.init(arena), |
| 2518 | .rparen_token = undefined, | 2578 | .rparen_token = undefined, |
| 2519 | }); | 2579 | }; |
| 2520 | opt_ctx.store(&node.base); | 2580 | opt_ctx.store(&node.base); |
| 2521 | 2581 | ||
| 2522 | stack.append(State{ | 2582 | stack.append(State{ |
| ... | @@ -2530,12 +2590,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2530,12 +2590,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2530 | continue; | 2590 | continue; |
| 2531 | }, | 2591 | }, |
| 2532 | Token.Id.LBracket => { | 2592 | Token.Id.LBracket => { |
| 2533 | const node = try arena.create(ast.Node.PrefixOp{ | 2593 | const node = try arena.create(ast.Node.PrefixOp); |
| 2594 | node.* = ast.Node.PrefixOp{ | ||
| 2534 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, | 2595 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2535 | .op_token = token.index, | 2596 | .op_token = token.index, |
| 2536 | .op = undefined, | 2597 | .op = undefined, |
| 2537 | .rhs = undefined, | 2598 | .rhs = undefined, |
| 2538 | }); | 2599 | }; |
| 2539 | opt_ctx.store(&node.base); | 2600 | opt_ctx.store(&node.base); |
| 2540 | 2601 | ||
| 2541 | stack.append(State{ .SliceOrArrayType = node }) catch unreachable; | 2602 | stack.append(State{ .SliceOrArrayType = node }) catch unreachable; |
| ... | @@ -2593,7 +2654,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2593,7 +2654,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2593 | continue; | 2654 | continue; |
| 2594 | }, | 2655 | }, |
| 2595 | Token.Id.Keyword_fn => { | 2656 | Token.Id.Keyword_fn => { |
| 2596 | const fn_proto = try arena.create(ast.Node.FnProto{ | 2657 | const fn_proto = try arena.create(ast.Node.FnProto); |
| 2658 | fn_proto.* = ast.Node.FnProto{ | ||
| 2597 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | 2659 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 2598 | .doc_comments = null, | 2660 | .doc_comments = null, |
| 2599 | .visib_token = null, | 2661 | .visib_token = null, |
| ... | @@ -2609,13 +2671,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2609,13 +2671,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2609 | .lib_name = null, | 2671 | .lib_name = null, |
| 2610 | .align_expr = null, | 2672 | .align_expr = null, |
| 2611 | .section_expr = null, | 2673 | .section_expr = null, |
| 2612 | }); | 2674 | }; |
| 2613 | opt_ctx.store(&fn_proto.base); | 2675 | opt_ctx.store(&fn_proto.base); |
| 2614 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; | 2676 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 2615 | continue; | 2677 | continue; |
| 2616 | }, | 2678 | }, |
| 2617 | Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { | 2679 | Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { |
| 2618 | const fn_proto = try arena.create(ast.Node.FnProto{ | 2680 | const fn_proto = try arena.create(ast.Node.FnProto); |
| 2681 | fn_proto.* = ast.Node.FnProto{ | ||
| 2619 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | 2682 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 2620 | .doc_comments = null, | 2683 | .doc_comments = null, |
| 2621 | .visib_token = null, | 2684 | .visib_token = null, |
| ... | @@ -2631,7 +2694,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2631,7 +2694,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2631 | .lib_name = null, | 2694 | .lib_name = null, |
| 2632 | .align_expr = null, | 2695 | .align_expr = null, |
| 2633 | .section_expr = null, | 2696 | .section_expr = null, |
| 2634 | }); | 2697 | }; |
| 2635 | opt_ctx.store(&fn_proto.base); | 2698 | opt_ctx.store(&fn_proto.base); |
| 2636 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; | 2699 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 2637 | try stack.append(State{ | 2700 | try stack.append(State{ |
| ... | @@ -2643,7 +2706,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2643,7 +2706,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2643 | continue; | 2706 | continue; |
| 2644 | }, | 2707 | }, |
| 2645 | Token.Id.Keyword_asm => { | 2708 | Token.Id.Keyword_asm => { |
| 2646 | const node = try arena.create(ast.Node.Asm{ | 2709 | const node = try arena.create(ast.Node.Asm); |
| 2710 | node.* = ast.Node.Asm{ | ||
| 2647 | .base = ast.Node{ .id = ast.Node.Id.Asm }, | 2711 | .base = ast.Node{ .id = ast.Node.Id.Asm }, |
| 2648 | .asm_token = token.index, | 2712 | .asm_token = token.index, |
| 2649 | .volatile_token = null, | 2713 | .volatile_token = null, |
| ... | @@ -2652,7 +2716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2652,7 +2716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2652 | .inputs = ast.Node.Asm.InputList.init(arena), | 2716 | .inputs = ast.Node.Asm.InputList.init(arena), |
| 2653 | .clobbers = ast.Node.Asm.ClobberList.init(arena), | 2717 | .clobbers = ast.Node.Asm.ClobberList.init(arena), |
| 2654 | .rparen = undefined, | 2718 | .rparen = undefined, |
| 2655 | }); | 2719 | }; |
| 2656 | opt_ctx.store(&node.base); | 2720 | opt_ctx.store(&node.base); |
| 2657 | 2721 | ||
| 2658 | stack.append(State{ | 2722 | stack.append(State{ |
| ... | @@ -2701,13 +2765,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2701,13 +2765,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2701 | 2765 | ||
| 2702 | State.ErrorTypeOrSetDecl => |ctx| { | 2766 | State.ErrorTypeOrSetDecl => |ctx| { |
| 2703 | if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) { | 2767 | if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) { |
| 2704 | const node = try arena.create(ast.Node.InfixOp{ | 2768 | const node = try arena.create(ast.Node.InfixOp); |
| 2769 | node.* = ast.Node.InfixOp{ | ||
| 2705 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, | 2770 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2706 | .lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base, | 2771 | .lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base, |
| 2707 | .op_token = undefined, | 2772 | .op_token = undefined, |
| 2708 | .op = ast.Node.InfixOp.Op.Period, | 2773 | .op = ast.Node.InfixOp.Op.Period, |
| 2709 | .rhs = undefined, | 2774 | .rhs = undefined, |
| 2710 | }); | 2775 | }; |
| 2711 | ctx.opt_ctx.store(&node.base); | 2776 | ctx.opt_ctx.store(&node.base); |
| 2712 | stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; | 2777 | stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; |
| 2713 | try stack.append(State{ | 2778 | try stack.append(State{ |
| ... | @@ -2719,12 +2784,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2719,12 +2784,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2719 | continue; | 2784 | continue; |
| 2720 | } | 2785 | } |
| 2721 | 2786 | ||
| 2722 | const node = try arena.create(ast.Node.ErrorSetDecl{ | 2787 | const node = try arena.create(ast.Node.ErrorSetDecl); |
| 2788 | node.* = ast.Node.ErrorSetDecl{ | ||
| 2723 | .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl }, | 2789 | .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl }, |
| 2724 | .error_token = ctx.error_token, | 2790 | .error_token = ctx.error_token, |
| 2725 | .decls = ast.Node.ErrorSetDecl.DeclList.init(arena), | 2791 | .decls = ast.Node.ErrorSetDecl.DeclList.init(arena), |
| 2726 | .rbrace_token = undefined, | 2792 | .rbrace_token = undefined, |
| 2727 | }); | 2793 | }; |
| 2728 | ctx.opt_ctx.store(&node.base); | 2794 | ctx.opt_ctx.store(&node.base); |
| 2729 | 2795 | ||
| 2730 | stack.append(State{ | 2796 | stack.append(State{ |
| ... | @@ -2785,11 +2851,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { | ... | @@ -2785,11 +2851,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2785 | return tree; | 2851 | return tree; |
| 2786 | } | 2852 | } |
| 2787 | 2853 | ||
| 2788 | const node = try arena.create(ast.Node.ErrorTag{ | 2854 | const node = try arena.create(ast.Node.ErrorTag); |
| 2855 | node.* = ast.Node.ErrorTag{ | ||
| 2789 | .base = ast.Node{ .id = ast.Node.Id.ErrorTag }, | 2856 | .base = ast.Node{ .id = ast.Node.Id.ErrorTag }, |
| 2790 | .doc_comments = comments, | 2857 | .doc_comments = comments, |
| 2791 | .name_token = ident_token_index, | 2858 | .name_token = ident_token_index, |
| 2792 | }); | 2859 | }; |
| 2793 | node_ptr.* = &node.base; | 2860 | node_ptr.* = &node.base; |
| 2794 | continue; | 2861 | continue; |
| 2795 | }, | 2862 | }, |
| ... | @@ -3129,10 +3196,11 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as | ... | @@ -3129,10 +3196,11 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as |
| 3129 | if (result.*) |comment_node| { | 3196 | if (result.*) |comment_node| { |
| 3130 | break :blk comment_node; | 3197 | break :blk comment_node; |
| 3131 | } else { | 3198 | } else { |
| 3132 | const comment_node = try arena.create(ast.Node.DocComment{ | 3199 | const comment_node = try arena.create(ast.Node.DocComment); |
| 3200 | comment_node.* = ast.Node.DocComment{ | ||
| 3133 | .base = ast.Node{ .id = ast.Node.Id.DocComment }, | 3201 | .base = ast.Node{ .id = ast.Node.Id.DocComment }, |
| 3134 | .lines = ast.Node.DocComment.LineList.init(arena), | 3202 | .lines = ast.Node.DocComment.LineList.init(arena), |
| 3135 | }); | 3203 | }; |
| 3136 | result.* = comment_node; | 3204 | result.* = comment_node; |
| 3137 | break :blk comment_node; | 3205 | break :blk comment_node; |
| 3138 | } | 3206 | } |
| ... | @@ -3158,10 +3226,11 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato | ... | @@ -3158,10 +3226,11 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato |
| 3158 | return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base; | 3226 | return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base; |
| 3159 | }, | 3227 | }, |
| 3160 | Token.Id.MultilineStringLiteralLine => { | 3228 | Token.Id.MultilineStringLiteralLine => { |
| 3161 | const node = try arena.create(ast.Node.MultilineStringLiteral{ | 3229 | const node = try arena.create(ast.Node.MultilineStringLiteral); |
| 3230 | node.* = ast.Node.MultilineStringLiteral{ | ||
| 3162 | .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral }, | 3231 | .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral }, |
| 3163 | .lines = ast.Node.MultilineStringLiteral.LineList.init(arena), | 3232 | .lines = ast.Node.MultilineStringLiteral.LineList.init(arena), |
| 3164 | }); | 3233 | }; |
| 3165 | try node.lines.push(token_index); | 3234 | try node.lines.push(token_index); |
| 3166 | while (true) { | 3235 | while (true) { |
| 3167 | const multiline_str = nextToken(tok_it, tree); | 3236 | const multiline_str = nextToken(tok_it, tree); |
| ... | @@ -3186,25 +3255,27 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato | ... | @@ -3186,25 +3255,27 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato |
| 3186 | fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool { | 3255 | fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool { |
| 3187 | switch (token_ptr.id) { | 3256 | switch (token_ptr.id) { |
| 3188 | Token.Id.Keyword_suspend => { | 3257 | Token.Id.Keyword_suspend => { |
| 3189 | const node = try arena.create(ast.Node.Suspend{ | 3258 | const node = try arena.create(ast.Node.Suspend); |
| 3259 | node.* = ast.Node.Suspend{ | ||
| 3190 | .base = ast.Node{ .id = ast.Node.Id.Suspend }, | 3260 | .base = ast.Node{ .id = ast.Node.Id.Suspend }, |
| 3191 | .suspend_token = token_index, | 3261 | .suspend_token = token_index, |
| 3192 | .body = null, | 3262 | .body = null, |
| 3193 | }); | 3263 | }; |
| 3194 | ctx.store(&node.base); | 3264 | ctx.store(&node.base); |
| 3195 | 3265 | ||
| 3196 | stack.append(State{ .SuspendBody = node }) catch unreachable; | 3266 | stack.append(State{ .SuspendBody = node }) catch unreachable; |
| 3197 | return true; | 3267 | return true; |
| 3198 | }, | 3268 | }, |
| 3199 | Token.Id.Keyword_if => { | 3269 | Token.Id.Keyword_if => { |
| 3200 | const node = try arena.create(ast.Node.If{ | 3270 | const node = try arena.create(ast.Node.If); |
| 3271 | node.* = ast.Node.If{ | ||
| 3201 | .base = ast.Node{ .id = ast.Node.Id.If }, | 3272 | .base = ast.Node{ .id = ast.Node.Id.If }, |
| 3202 | .if_token = token_index, | 3273 | .if_token = token_index, |
| 3203 | .condition = undefined, | 3274 | .condition = undefined, |
| 3204 | .payload = null, | 3275 | .payload = null, |
| 3205 | .body = undefined, | 3276 | .body = undefined, |
| 3206 | .@"else" = null, | 3277 | .@"else" = null, |
| 3207 | }); | 3278 | }; |
| 3208 | ctx.store(&node.base); | 3279 | ctx.store(&node.base); |
| 3209 | 3280 | ||
| 3210 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; | 3281 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; |
| ... | @@ -3238,13 +3309,14 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti | ... | @@ -3238,13 +3309,14 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti |
| 3238 | return true; | 3309 | return true; |
| 3239 | }, | 3310 | }, |
| 3240 | Token.Id.Keyword_switch => { | 3311 | Token.Id.Keyword_switch => { |
| 3241 | const node = try arena.create(ast.Node.Switch{ | 3312 | const node = try arena.create(ast.Node.Switch); |
| 3313 | node.* = ast.Node.Switch{ | ||
| 3242 | .base = ast.Node{ .id = ast.Node.Id.Switch }, | 3314 | .base = ast.Node{ .id = ast.Node.Id.Switch }, |
| 3243 | .switch_token = token_index, | 3315 | .switch_token = token_index, |
| 3244 | .expr = undefined, | 3316 | .expr = undefined, |
| 3245 | .cases = ast.Node.Switch.CaseList.init(arena), | 3317 | .cases = ast.Node.Switch.CaseList.init(arena), |
| 3246 | .rbrace = undefined, | 3318 | .rbrace = undefined, |
| 3247 | }); | 3319 | }; |
| 3248 | ctx.store(&node.base); | 3320 | ctx.store(&node.base); |
| 3249 | 3321 | ||
| 3250 | stack.append(State{ | 3322 | stack.append(State{ |
| ... | @@ -3260,25 +3332,27 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti | ... | @@ -3260,25 +3332,27 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti |
| 3260 | return true; | 3332 | return true; |
| 3261 | }, | 3333 | }, |
| 3262 | Token.Id.Keyword_comptime => { | 3334 | Token.Id.Keyword_comptime => { |
| 3263 | const node = try arena.create(ast.Node.Comptime{ | 3335 | const node = try arena.create(ast.Node.Comptime); |
| 3336 | node.* = ast.Node.Comptime{ | ||
| 3264 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, | 3337 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, |
| 3265 | .comptime_token = token_index, | 3338 | .comptime_token = token_index, |
| 3266 | .expr = undefined, | 3339 | .expr = undefined, |
| 3267 | .doc_comments = null, | 3340 | .doc_comments = null, |
| 3268 | }); | 3341 | }; |
| 3269 | ctx.store(&node.base); | 3342 | ctx.store(&node.base); |
| 3270 | 3343 | ||
| 3271 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } }); | 3344 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } }); |
| 3272 | return true; | 3345 | return true; |
| 3273 | }, | 3346 | }, |
| 3274 | Token.Id.LBrace => { | 3347 | Token.Id.LBrace => { |
| 3275 | const block = try arena.create(ast.Node.Block{ | 3348 | const block = try arena.create(ast.Node.Block); |
| 3349 | block.* = ast.Node.Block{ | ||
| 3276 | .base = ast.Node{ .id = ast.Node.Id.Block }, | 3350 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 3277 | .label = null, | 3351 | .label = null, |
| 3278 | .lbrace = token_index, | 3352 | .lbrace = token_index, |
| 3279 | .statements = ast.Node.Block.StatementList.init(arena), | 3353 | .statements = ast.Node.Block.StatementList.init(arena), |
| 3280 | .rbrace = undefined, | 3354 | .rbrace = undefined, |
| 3281 | }); | 3355 | }; |
| 3282 | ctx.store(&block.base); | 3356 | ctx.store(&block.base); |
| 3283 | stack.append(State{ .Block = block }) catch unreachable; | 3357 | stack.append(State{ .Block = block }) catch unreachable; |
| 3284 | return true; | 3358 | return true; |
| ... | @@ -3412,10 +3486,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { | ... | @@ -3412,10 +3486,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { |
| 3412 | } | 3486 | } |
| 3413 | 3487 | ||
| 3414 | fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T { | 3488 | fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T { |
| 3415 | return arena.create(T{ | 3489 | const result = try arena.create(T); |
| 3490 | result.* = T{ | ||
| 3416 | .base = ast.Node{ .id = ast.Node.typeToId(T) }, | 3491 | .base = ast.Node{ .id = ast.Node.typeToId(T) }, |
| 3417 | .token = token_index, | 3492 | .token = token_index, |
| 3418 | }); | 3493 | }; |
| 3494 | return result; | ||
| 3419 | } | 3495 | } |
| 3420 | 3496 | ||
| 3421 | fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: OptionalCtx, comptime T: type, token_index: TokenIndex) !*T { | 3497 | fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: OptionalCtx, comptime T: type, token_index: TokenIndex) !*T { |
test/behavior.zig deleted-82| ... | @@ -1,82 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | |||
| 3 | comptime { | ||
| 4 | _ = @import("cases/align.zig"); | ||
| 5 | _ = @import("cases/alignof.zig"); | ||
| 6 | _ = @import("cases/array.zig"); | ||
| 7 | _ = @import("cases/asm.zig"); | ||
| 8 | _ = @import("cases/atomics.zig"); | ||
| 9 | _ = @import("cases/bitcast.zig"); | ||
| 10 | _ = @import("cases/bool.zig"); | ||
| 11 | _ = @import("cases/bswap.zig"); | ||
| 12 | _ = @import("cases/bitreverse.zig"); | ||
| 13 | _ = @import("cases/bugs/1076.zig"); | ||
| 14 | _ = @import("cases/bugs/1111.zig"); | ||
| 15 | _ = @import("cases/bugs/1277.zig"); | ||
| 16 | _ = @import("cases/bugs/1322.zig"); | ||
| 17 | _ = @import("cases/bugs/1381.zig"); | ||
| 18 | _ = @import("cases/bugs/1421.zig"); | ||
| 19 | _ = @import("cases/bugs/1442.zig"); | ||
| 20 | _ = @import("cases/bugs/1486.zig"); | ||
| 21 | _ = @import("cases/bugs/394.zig"); | ||
| 22 | _ = @import("cases/bugs/655.zig"); | ||
| 23 | _ = @import("cases/bugs/656.zig"); | ||
| 24 | _ = @import("cases/bugs/726.zig"); | ||
| 25 | _ = @import("cases/bugs/828.zig"); | ||
| 26 | _ = @import("cases/bugs/920.zig"); | ||
| 27 | _ = @import("cases/byval_arg_var.zig"); | ||
| 28 | _ = @import("cases/cancel.zig"); | ||
| 29 | _ = @import("cases/cast.zig"); | ||
| 30 | _ = @import("cases/const_slice_child.zig"); | ||
| 31 | _ = @import("cases/coroutine_await_struct.zig"); | ||
| 32 | _ = @import("cases/coroutines.zig"); | ||
| 33 | _ = @import("cases/defer.zig"); | ||
| 34 | _ = @import("cases/enum.zig"); | ||
| 35 | _ = @import("cases/enum_with_members.zig"); | ||
| 36 | _ = @import("cases/error.zig"); | ||
| 37 | _ = @import("cases/eval.zig"); | ||
| 38 | _ = @import("cases/field_parent_ptr.zig"); | ||
| 39 | _ = @import("cases/fn.zig"); | ||
| 40 | _ = @import("cases/fn_in_struct_in_comptime.zig"); | ||
| 41 | _ = @import("cases/for.zig"); | ||
| 42 | _ = @import("cases/generics.zig"); | ||
| 43 | _ = @import("cases/if.zig"); | ||
| 44 | _ = @import("cases/import.zig"); | ||
| 45 | _ = @import("cases/incomplete_struct_param_tld.zig"); | ||
| 46 | _ = @import("cases/inttoptr.zig"); | ||
| 47 | _ = @import("cases/ir_block_deps.zig"); | ||
| 48 | _ = @import("cases/math.zig"); | ||
| 49 | _ = @import("cases/merge_error_sets.zig"); | ||
| 50 | _ = @import("cases/misc.zig"); | ||
| 51 | _ = @import("cases/namespace_depends_on_compile_var/index.zig"); | ||
| 52 | _ = @import("cases/new_stack_call.zig"); | ||
| 53 | _ = @import("cases/null.zig"); | ||
| 54 | _ = @import("cases/optional.zig"); | ||
| 55 | _ = @import("cases/pointers.zig"); | ||
| 56 | _ = @import("cases/popcount.zig"); | ||
| 57 | _ = @import("cases/ptrcast.zig"); | ||
| 58 | _ = @import("cases/pub_enum/index.zig"); | ||
| 59 | _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); | ||
| 60 | _ = @import("cases/reflection.zig"); | ||
| 61 | _ = @import("cases/sizeof_and_typeof.zig"); | ||
| 62 | _ = @import("cases/slice.zig"); | ||
| 63 | _ = @import("cases/struct.zig"); | ||
| 64 | _ = @import("cases/struct_contains_null_ptr_itself.zig"); | ||
| 65 | _ = @import("cases/struct_contains_slice_of_itself.zig"); | ||
| 66 | _ = @import("cases/switch.zig"); | ||
| 67 | _ = @import("cases/switch_prong_err_enum.zig"); | ||
| 68 | _ = @import("cases/switch_prong_implicit_cast.zig"); | ||
| 69 | _ = @import("cases/syntax.zig"); | ||
| 70 | _ = @import("cases/this.zig"); | ||
| 71 | _ = @import("cases/truncate.zig"); | ||
| 72 | _ = @import("cases/try.zig"); | ||
| 73 | _ = @import("cases/type_info.zig"); | ||
| 74 | _ = @import("cases/undefined.zig"); | ||
| 75 | _ = @import("cases/underscore.zig"); | ||
| 76 | _ = @import("cases/union.zig"); | ||
| 77 | _ = @import("cases/var_args.zig"); | ||
| 78 | _ = @import("cases/void.zig"); | ||
| 79 | _ = @import("cases/while.zig"); | ||
| 80 | _ = @import("cases/widening.zig"); | ||
| 81 | _ = @import("cases/bit_shifting.zig"); | ||
| 82 | } | ||
test/cases/align.zig deleted-230| ... | @@ -1,230 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | var foo: u8 align(4) = 100; | ||
| 5 | |||
| 6 | test "global variable alignment" { | ||
| 7 | assert(@typeOf(&foo).alignment == 4); | ||
| 8 | assert(@typeOf(&foo) == *align(4) u8); | ||
| 9 | const slice = (*[1]u8)(&foo)[0..]; | ||
| 10 | assert(@typeOf(slice) == []align(4) u8); | ||
| 11 | } | ||
| 12 | |||
| 13 | fn derp() align(@sizeOf(usize) * 2) i32 { | ||
| 14 | return 1234; | ||
| 15 | } | ||
| 16 | fn noop1() align(1) void {} | ||
| 17 | fn noop4() align(4) void {} | ||
| 18 | |||
| 19 | test "function alignment" { | ||
| 20 | assert(derp() == 1234); | ||
| 21 | assert(@typeOf(noop1) == fn () align(1) void); | ||
| 22 | assert(@typeOf(noop4) == fn () align(4) void); | ||
| 23 | noop1(); | ||
| 24 | noop4(); | ||
| 25 | } | ||
| 26 | |||
| 27 | var baz: packed struct { | ||
| 28 | a: u32, | ||
| 29 | b: u32, | ||
| 30 | } = undefined; | ||
| 31 | |||
| 32 | test "packed struct alignment" { | ||
| 33 | assert(@typeOf(&baz.b) == *align(1) u32); | ||
| 34 | } | ||
| 35 | |||
| 36 | const blah: packed struct { | ||
| 37 | a: u3, | ||
| 38 | b: u3, | ||
| 39 | c: u2, | ||
| 40 | } = undefined; | ||
| 41 | |||
| 42 | test "bit field alignment" { | ||
| 43 | assert(@typeOf(&blah.b) == *align(1:3:1) const u3); | ||
| 44 | } | ||
| 45 | |||
| 46 | test "default alignment allows unspecified in type syntax" { | ||
| 47 | assert(*u32 == *align(@alignOf(u32)) u32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "implicitly decreasing pointer alignment" { | ||
| 51 | const a: u32 align(4) = 3; | ||
| 52 | const b: u32 align(8) = 4; | ||
| 53 | assert(addUnaligned(&a, &b) == 7); | ||
| 54 | } | ||
| 55 | |||
| 56 | fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { | ||
| 57 | return a.* + b.*; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "implicitly decreasing slice alignment" { | ||
| 61 | const a: u32 align(4) = 3; | ||
| 62 | const b: u32 align(8) = 4; | ||
| 63 | assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); | ||
| 64 | } | ||
| 65 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { | ||
| 66 | return a[0] + b[0]; | ||
| 67 | } | ||
| 68 | |||
| 69 | test "specifying alignment allows pointer cast" { | ||
| 70 | testBytesAlign(0x33); | ||
| 71 | } | ||
| 72 | fn testBytesAlign(b: u8) void { | ||
| 73 | var bytes align(4) = []u8{ | ||
| 74 | b, | ||
| 75 | b, | ||
| 76 | b, | ||
| 77 | b, | ||
| 78 | }; | ||
| 79 | const ptr = @ptrCast(*u32, &bytes[0]); | ||
| 80 | assert(ptr.* == 0x33333333); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "specifying alignment allows slice cast" { | ||
| 84 | testBytesAlignSlice(0x33); | ||
| 85 | } | ||
| 86 | fn testBytesAlignSlice(b: u8) void { | ||
| 87 | var bytes align(4) = []u8{ | ||
| 88 | b, | ||
| 89 | b, | ||
| 90 | b, | ||
| 91 | b, | ||
| 92 | }; | ||
| 93 | const slice: []u32 = @bytesToSlice(u32, bytes[0..]); | ||
| 94 | assert(slice[0] == 0x33333333); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "@alignCast pointers" { | ||
| 98 | var x: u32 align(4) = 1; | ||
| 99 | expectsOnly1(&x); | ||
| 100 | assert(x == 2); | ||
| 101 | } | ||
| 102 | fn expectsOnly1(x: *align(1) u32) void { | ||
| 103 | expects4(@alignCast(4, x)); | ||
| 104 | } | ||
| 105 | fn expects4(x: *align(4) u32) void { | ||
| 106 | x.* += 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | test "@alignCast slices" { | ||
| 110 | var array align(4) = []u32{ | ||
| 111 | 1, | ||
| 112 | 1, | ||
| 113 | }; | ||
| 114 | const slice = array[0..]; | ||
| 115 | sliceExpectsOnly1(slice); | ||
| 116 | assert(slice[0] == 2); | ||
| 117 | } | ||
| 118 | fn sliceExpectsOnly1(slice: []align(1) u32) void { | ||
| 119 | sliceExpects4(@alignCast(4, slice)); | ||
| 120 | } | ||
| 121 | fn sliceExpects4(slice: []align(4) u32) void { | ||
| 122 | slice[0] += 1; | ||
| 123 | } | ||
| 124 | |||
| 125 | test "implicitly decreasing fn alignment" { | ||
| 126 | testImplicitlyDecreaseFnAlign(alignedSmall, 1234); | ||
| 127 | testImplicitlyDecreaseFnAlign(alignedBig, 5678); | ||
| 128 | } | ||
| 129 | |||
| 130 | fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { | ||
| 131 | assert(ptr() == answer); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn alignedSmall() align(8) i32 { | ||
| 135 | return 1234; | ||
| 136 | } | ||
| 137 | fn alignedBig() align(16) i32 { | ||
| 138 | return 5678; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "@alignCast functions" { | ||
| 142 | assert(fnExpectsOnly1(simple4) == 0x19); | ||
| 143 | } | ||
| 144 | fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { | ||
| 145 | return fnExpects4(@alignCast(4, ptr)); | ||
| 146 | } | ||
| 147 | fn fnExpects4(ptr: fn () align(4) i32) i32 { | ||
| 148 | return ptr(); | ||
| 149 | } | ||
| 150 | fn simple4() align(4) i32 { | ||
| 151 | return 0x19; | ||
| 152 | } | ||
| 153 | |||
| 154 | test "generic function with align param" { | ||
| 155 | assert(whyWouldYouEverDoThis(1) == 0x1); | ||
| 156 | assert(whyWouldYouEverDoThis(4) == 0x1); | ||
| 157 | assert(whyWouldYouEverDoThis(8) == 0x1); | ||
| 158 | } | ||
| 159 | |||
| 160 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { | ||
| 161 | return 0x1; | ||
| 162 | } | ||
| 163 | |||
| 164 | test "@ptrCast preserves alignment of bigger source" { | ||
| 165 | var x: u32 align(16) = 1234; | ||
| 166 | const ptr = @ptrCast(*u8, &x); | ||
| 167 | assert(@typeOf(ptr) == *align(16) u8); | ||
| 168 | } | ||
| 169 | |||
| 170 | test "runtime known array index has best alignment possible" { | ||
| 171 | // take full advantage of over-alignment | ||
| 172 | var array align(4) = []u8{ 1, 2, 3, 4 }; | ||
| 173 | assert(@typeOf(&array[0]) == *align(4) u8); | ||
| 174 | assert(@typeOf(&array[1]) == *u8); | ||
| 175 | assert(@typeOf(&array[2]) == *align(2) u8); | ||
| 176 | assert(@typeOf(&array[3]) == *u8); | ||
| 177 | |||
| 178 | // because align is too small but we still figure out to use 2 | ||
| 179 | var bigger align(2) = []u64{ 1, 2, 3, 4 }; | ||
| 180 | assert(@typeOf(&bigger[0]) == *align(2) u64); | ||
| 181 | assert(@typeOf(&bigger[1]) == *align(2) u64); | ||
| 182 | assert(@typeOf(&bigger[2]) == *align(2) u64); | ||
| 183 | assert(@typeOf(&bigger[3]) == *align(2) u64); | ||
| 184 | |||
| 185 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | ||
| 186 | var smaller align(2) = []u32{ 1, 2, 3, 4 }; | ||
| 187 | comptime assert(@typeOf(smaller[0..]) == []align(2) u32); | ||
| 188 | comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32); | ||
| 189 | testIndex(smaller[0..].ptr, 0, *align(2) u32); | ||
| 190 | testIndex(smaller[0..].ptr, 1, *align(2) u32); | ||
| 191 | testIndex(smaller[0..].ptr, 2, *align(2) u32); | ||
| 192 | testIndex(smaller[0..].ptr, 3, *align(2) u32); | ||
| 193 | |||
| 194 | // has to use ABI alignment because index known at runtime only | ||
| 195 | testIndex2(array[0..].ptr, 0, *u8); | ||
| 196 | testIndex2(array[0..].ptr, 1, *u8); | ||
| 197 | testIndex2(array[0..].ptr, 2, *u8); | ||
| 198 | testIndex2(array[0..].ptr, 3, *u8); | ||
| 199 | } | ||
| 200 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { | ||
| 201 | comptime assert(@typeOf(&smaller[index]) == T); | ||
| 202 | } | ||
| 203 | fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { | ||
| 204 | comptime assert(@typeOf(&ptr[index]) == T); | ||
| 205 | } | ||
| 206 | |||
| 207 | test "alignstack" { | ||
| 208 | assert(fnWithAlignedStack() == 1234); | ||
| 209 | } | ||
| 210 | |||
| 211 | fn fnWithAlignedStack() i32 { | ||
| 212 | @setAlignStack(256); | ||
| 213 | return 1234; | ||
| 214 | } | ||
| 215 | |||
| 216 | test "alignment of structs" { | ||
| 217 | assert(@alignOf(struct { | ||
| 218 | a: i32, | ||
| 219 | b: *i32, | ||
| 220 | }) == @alignOf(usize)); | ||
| 221 | } | ||
| 222 | |||
| 223 | test "alignment of extern() void" { | ||
| 224 | var runtime_nothing = nothing; | ||
| 225 | const casted1 = @ptrCast(*const u8, runtime_nothing); | ||
| 226 | const casted2 = @ptrCast(extern fn () void, casted1); | ||
| 227 | casted2(); | ||
| 228 | } | ||
| 229 | |||
| 230 | extern fn nothing() void {} | ||
test/cases/alignof.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | const Foo = struct { | ||
| 7 | x: u32, | ||
| 8 | y: u32, | ||
| 9 | z: u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "@alignOf(T) before referencing T" { | ||
| 13 | comptime assert(@alignOf(Foo) != maxInt(usize)); | ||
| 14 | if (builtin.arch == builtin.Arch.x86_64) { | ||
| 15 | comptime assert(@alignOf(Foo) == 4); | ||
| 16 | } | ||
| 17 | } | ||
test/cases/array.zig deleted-173| ... | @@ -1,173 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | test "arrays" { | ||
| 5 | var array: [5]u32 = undefined; | ||
| 6 | |||
| 7 | var i: u32 = 0; | ||
| 8 | while (i < 5) { | ||
| 9 | array[i] = i + 1; | ||
| 10 | i = array[i]; | ||
| 11 | } | ||
| 12 | |||
| 13 | i = 0; | ||
| 14 | var accumulator = u32(0); | ||
| 15 | while (i < 5) { | ||
| 16 | accumulator += array[i]; | ||
| 17 | |||
| 18 | i += 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | assert(accumulator == 15); | ||
| 22 | assert(getArrayLen(array) == 5); | ||
| 23 | } | ||
| 24 | fn getArrayLen(a: []const u32) usize { | ||
| 25 | return a.len; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "void arrays" { | ||
| 29 | var array: [4]void = undefined; | ||
| 30 | array[0] = void{}; | ||
| 31 | array[1] = array[2]; | ||
| 32 | assert(@sizeOf(@typeOf(array)) == 0); | ||
| 33 | assert(array.len == 4); | ||
| 34 | } | ||
| 35 | |||
| 36 | test "array literal" { | ||
| 37 | const hex_mult = []u16{ | ||
| 38 | 4096, | ||
| 39 | 256, | ||
| 40 | 16, | ||
| 41 | 1, | ||
| 42 | }; | ||
| 43 | |||
| 44 | assert(hex_mult.len == 4); | ||
| 45 | assert(hex_mult[1] == 256); | ||
| 46 | } | ||
| 47 | |||
| 48 | test "array dot len const expr" { | ||
| 49 | assert(comptime x: { | ||
| 50 | break :x some_array.len == 4; | ||
| 51 | }); | ||
| 52 | } | ||
| 53 | |||
| 54 | const ArrayDotLenConstExpr = struct { | ||
| 55 | y: [some_array.len]u8, | ||
| 56 | }; | ||
| 57 | const some_array = []u8{ | ||
| 58 | 0, | ||
| 59 | 1, | ||
| 60 | 2, | ||
| 61 | 3, | ||
| 62 | }; | ||
| 63 | |||
| 64 | test "nested arrays" { | ||
| 65 | const array_of_strings = [][]const u8{ | ||
| 66 | "hello", | ||
| 67 | "this", | ||
| 68 | "is", | ||
| 69 | "my", | ||
| 70 | "thing", | ||
| 71 | }; | ||
| 72 | for (array_of_strings) |s, i| { | ||
| 73 | if (i == 0) assert(mem.eql(u8, s, "hello")); | ||
| 74 | if (i == 1) assert(mem.eql(u8, s, "this")); | ||
| 75 | if (i == 2) assert(mem.eql(u8, s, "is")); | ||
| 76 | if (i == 3) assert(mem.eql(u8, s, "my")); | ||
| 77 | if (i == 4) assert(mem.eql(u8, s, "thing")); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | var s_array: [8]Sub = undefined; | ||
| 82 | const Sub = struct { | ||
| 83 | b: u8, | ||
| 84 | }; | ||
| 85 | const Str = struct { | ||
| 86 | a: []Sub, | ||
| 87 | }; | ||
| 88 | test "set global var array via slice embedded in struct" { | ||
| 89 | var s = Str{ .a = s_array[0..] }; | ||
| 90 | |||
| 91 | s.a[0].b = 1; | ||
| 92 | s.a[1].b = 2; | ||
| 93 | s.a[2].b = 3; | ||
| 94 | |||
| 95 | assert(s_array[0].b == 1); | ||
| 96 | assert(s_array[1].b == 2); | ||
| 97 | assert(s_array[2].b == 3); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "array literal with specified size" { | ||
| 101 | var array = [2]u8{ | ||
| 102 | 1, | ||
| 103 | 2, | ||
| 104 | }; | ||
| 105 | assert(array[0] == 1); | ||
| 106 | assert(array[1] == 2); | ||
| 107 | } | ||
| 108 | |||
| 109 | test "array child property" { | ||
| 110 | var x: [5]i32 = undefined; | ||
| 111 | assert(@typeOf(x).Child == i32); | ||
| 112 | } | ||
| 113 | |||
| 114 | test "array len property" { | ||
| 115 | var x: [5]i32 = undefined; | ||
| 116 | assert(@typeOf(x).len == 5); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "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 | |||
| 128 | test "single-item pointer to array indexing and slicing" { | ||
| 129 | testSingleItemPtrArrayIndexSlice(); | ||
| 130 | comptime testSingleItemPtrArrayIndexSlice(); | ||
| 131 | } | ||
| 132 | |||
| 133 | fn testSingleItemPtrArrayIndexSlice() void { | ||
| 134 | var array = "aaaa"; | ||
| 135 | doSomeMangling(&array); | ||
| 136 | assert(mem.eql(u8, "azya", array)); | ||
| 137 | } | ||
| 138 | |||
| 139 | fn doSomeMangling(array: *[4]u8) void { | ||
| 140 | array[1] = 'z'; | ||
| 141 | array[2..3][0] = 'y'; | ||
| 142 | } | ||
| 143 | |||
| 144 | test "implicit cast single-item pointer" { | ||
| 145 | testImplicitCastSingleItemPtr(); | ||
| 146 | comptime testImplicitCastSingleItemPtr(); | ||
| 147 | } | ||
| 148 | |||
| 149 | fn testImplicitCastSingleItemPtr() void { | ||
| 150 | var byte: u8 = 100; | ||
| 151 | const slice = (*[1]u8)(&byte)[0..]; | ||
| 152 | slice[0] += 1; | ||
| 153 | assert(byte == 101); | ||
| 154 | } | ||
| 155 | |||
| 156 | fn testArrayByValAtComptime(b: [2]u8) u8 { | ||
| 157 | return b[0]; | ||
| 158 | } | ||
| 159 | |||
| 160 | test "comptime evalutating function that takes array by value" { | ||
| 161 | const arr = []u8{ 0, 1 }; | ||
| 162 | _ = comptime testArrayByValAtComptime(arr); | ||
| 163 | _ = comptime testArrayByValAtComptime(arr); | ||
| 164 | } | ||
| 165 | |||
| 166 | test "implicit comptime in array type size" { | ||
| 167 | var arr: [plusOne(10)]bool = undefined; | ||
| 168 | assert(arr.len == 11); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn plusOne(x: u32) u32 { | ||
| 172 | return x + 1; | ||
| 173 | } | ||
test/cases/asm.zig deleted-48| ... | @@ -1,48 +0,0 @@ | ||
| 1 | const config = @import("builtin"); | ||
| 2 | const assert = @import("std").debug.assert; | ||
| 3 | |||
| 4 | comptime { | ||
| 5 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { | ||
| 6 | asm volatile ( | ||
| 7 | \\.globl aoeu; | ||
| 8 | \\.type aoeu, @function; | ||
| 9 | \\.set aoeu, derp; | ||
| 10 | ); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "module level assembly" { | ||
| 15 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { | ||
| 16 | assert(aoeu() == 1234); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "output constraint modifiers" { | ||
| 21 | // This is only testing compilation. | ||
| 22 | var a: u32 = 3; | ||
| 23 | asm volatile ("" : [_]"=m,r"(a) : : ""); | ||
| 24 | asm volatile ("" : [_]"=r,m"(a) : : ""); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "alternative constraints" { | ||
| 28 | // Make sure we allow commas as a separator for alternative constraints. | ||
| 29 | var a: u32 = 3; | ||
| 30 | asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : ""); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "sized integer/float in asm input" { | ||
| 34 | asm volatile ("" : : [_]"m"(usize(3)) : ""); | ||
| 35 | asm volatile ("" : : [_]"m"(i15(-3)) : ""); | ||
| 36 | asm volatile ("" : : [_]"m"(u3(3)) : ""); | ||
| 37 | asm volatile ("" : : [_]"m"(i3(3)) : ""); | ||
| 38 | asm volatile ("" : : [_]"m"(u121(3)) : ""); | ||
| 39 | asm volatile ("" : : [_]"m"(i121(3)) : ""); | ||
| 40 | asm volatile ("" : : [_]"m"(f32(3.17)) : ""); | ||
| 41 | asm volatile ("" : : [_]"m"(f64(3.17)) : ""); | ||
| 42 | } | ||
| 43 | |||
| 44 | extern fn aoeu() i32; | ||
| 45 | |||
| 46 | export fn derp() i32 { | ||
| 47 | return 1234; | ||
| 48 | } | ||
test/cases/atomics.zig deleted-71| ... | @@ -1,71 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const AtomicRmwOp = builtin.AtomicRmwOp; | ||
| 5 | const AtomicOrder = builtin.AtomicOrder; | ||
| 6 | |||
| 7 | test "cmpxchg" { | ||
| 8 | var x: i32 = 1234; | ||
| 9 | if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 10 | assert(x1 == 1234); | ||
| 11 | } else { | ||
| 12 | @panic("cmpxchg should have failed"); | ||
| 13 | } | ||
| 14 | |||
| 15 | while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 16 | assert(x1 == 1234); | ||
| 17 | } | ||
| 18 | assert(x == 5678); | ||
| 19 | |||
| 20 | assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); | ||
| 21 | assert(x == 42); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "fence" { | ||
| 25 | var x: i32 = 1234; | ||
| 26 | @fence(AtomicOrder.SeqCst); | ||
| 27 | x = 5678; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "atomicrmw and atomicload" { | ||
| 31 | var data: u8 = 200; | ||
| 32 | testAtomicRmw(&data); | ||
| 33 | assert(data == 42); | ||
| 34 | testAtomicLoad(&data); | ||
| 35 | } | ||
| 36 | |||
| 37 | fn testAtomicRmw(ptr: *u8) void { | ||
| 38 | const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); | ||
| 39 | assert(prev_value == 200); | ||
| 40 | comptime { | ||
| 41 | var x: i32 = 1234; | ||
| 42 | const y: i32 = 12345; | ||
| 43 | assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); | ||
| 44 | assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | fn testAtomicLoad(ptr: *u8) void { | ||
| 49 | const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); | ||
| 50 | assert(x == 42); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "cmpxchg with ptr" { | ||
| 54 | var data1: i32 = 1234; | ||
| 55 | var data2: i32 = 5678; | ||
| 56 | var data3: i32 = 9101; | ||
| 57 | var x: *i32 = &data1; | ||
| 58 | if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 59 | assert(x1 == &data1); | ||
| 60 | } else { | ||
| 61 | @panic("cmpxchg should have failed"); | ||
| 62 | } | ||
| 63 | |||
| 64 | while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 65 | assert(x1 == &data1); | ||
| 66 | } | ||
| 67 | assert(x == &data3); | ||
| 68 | |||
| 69 | assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); | ||
| 70 | assert(x == &data2); | ||
| 71 | } | ||
test/cases/bit_shifting.zig deleted-88| ... | @@ -1,88 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { | ||
| 5 | assert(Key == @IntType(false, Key.bit_count)); | ||
| 6 | assert(Key.bit_count >= mask_bit_count); | ||
| 7 | const ShardKey = @IntType(false, mask_bit_count); | ||
| 8 | const shift_amount = Key.bit_count - ShardKey.bit_count; | ||
| 9 | return struct { | ||
| 10 | const Self = @This(); | ||
| 11 | shards: [1 << ShardKey.bit_count]?*Node, | ||
| 12 | |||
| 13 | pub fn create() Self { | ||
| 14 | return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) }; | ||
| 15 | } | ||
| 16 | |||
| 17 | fn getShardKey(key: Key) ShardKey { | ||
| 18 | // https://github.com/ziglang/zig/issues/1544 | ||
| 19 | // this special case is needed because you can't u32 >> 32. | ||
| 20 | if (ShardKey == u0) return 0; | ||
| 21 | |||
| 22 | // this can be u1 >> u0 | ||
| 23 | const shard_key = key >> shift_amount; | ||
| 24 | |||
| 25 | // TODO: https://github.com/ziglang/zig/issues/1544 | ||
| 26 | // This cast could be implicit if we teach the compiler that | ||
| 27 | // u32 >> 30 -> u2 | ||
| 28 | return @intCast(ShardKey, shard_key); | ||
| 29 | } | ||
| 30 | |||
| 31 | pub fn put(self: *Self, node: *Node) void { | ||
| 32 | const shard_key = Self.getShardKey(node.key); | ||
| 33 | node.next = self.shards[shard_key]; | ||
| 34 | self.shards[shard_key] = node; | ||
| 35 | } | ||
| 36 | |||
| 37 | pub fn get(self: *Self, key: Key) ?*Node { | ||
| 38 | const shard_key = Self.getShardKey(key); | ||
| 39 | var maybe_node = self.shards[shard_key]; | ||
| 40 | while (maybe_node) |node| : (maybe_node = node.next) { | ||
| 41 | if (node.key == key) return node; | ||
| 42 | } | ||
| 43 | return null; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub const Node = struct { | ||
| 47 | key: Key, | ||
| 48 | value: V, | ||
| 49 | next: ?*Node, | ||
| 50 | |||
| 51 | pub fn init(self: *Node, key: Key, value: V) void { | ||
| 52 | self.key = key; | ||
| 53 | self.value = value; | ||
| 54 | self.next = null; | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "sharded table" { | ||
| 61 | // realistic 16-way sharding | ||
| 62 | testShardedTable(u32, 4, 8); | ||
| 63 | |||
| 64 | testShardedTable(u5, 0, 32); // ShardKey == u0 | ||
| 65 | testShardedTable(u5, 2, 32); | ||
| 66 | testShardedTable(u5, 5, 32); | ||
| 67 | |||
| 68 | testShardedTable(u1, 0, 2); | ||
| 69 | testShardedTable(u1, 1, 2); // this does u1 >> u0 | ||
| 70 | |||
| 71 | testShardedTable(u0, 0, 1); | ||
| 72 | } | ||
| 73 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void { | ||
| 74 | const Table = ShardedTable(Key, mask_bit_count, void); | ||
| 75 | |||
| 76 | var table = Table.create(); | ||
| 77 | var node_buffer: [node_count]Table.Node = undefined; | ||
| 78 | for (node_buffer) |*node, i| { | ||
| 79 | const key = @intCast(Key, i); | ||
| 80 | assert(table.get(key) == null); | ||
| 81 | node.init(key, {}); | ||
| 82 | table.put(node); | ||
| 83 | } | ||
| 84 | |||
| 85 | for (node_buffer) |*node, i| { | ||
| 86 | assert(table.get(@intCast(Key, i)) == node); | ||
| 87 | } | ||
| 88 | } | ||
test/cases/bitcast.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | |||
| 5 | test "@bitCast i32 -> u32" { | ||
| 6 | testBitCast_i32_u32(); | ||
| 7 | comptime testBitCast_i32_u32(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitCast_i32_u32() void { | ||
| 11 | assert(conv(-1) == maxInt(u32)); | ||
| 12 | assert(conv2(maxInt(u32)) == -1); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn conv(x: i32) u32 { | ||
| 16 | return @bitCast(u32, x); | ||
| 17 | } | ||
| 18 | fn conv2(x: u32) i32 { | ||
| 19 | return @bitCast(i32, x); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "@bitCast extern enum to its integer type" { | ||
| 23 | const SOCK = extern enum { | ||
| 24 | A, | ||
| 25 | B, | ||
| 26 | |||
| 27 | fn testBitCastExternEnum() void { | ||
| 28 | var SOCK_DGRAM = @This().B; | ||
| 29 | var sock_dgram = @bitCast(c_int, SOCK_DGRAM); | ||
| 30 | assert(sock_dgram == 1); | ||
| 31 | } | ||
| 32 | }; | ||
| 33 | |||
| 34 | SOCK.testBitCastExternEnum(); | ||
| 35 | comptime SOCK.testBitCastExternEnum(); | ||
| 36 | } | ||
| 37 | |||
test/cases/bitreverse.zig deleted-81| ... | @@ -1,81 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const minInt = std.math.minInt; | ||
| 4 | |||
| 5 | test "@bitreverse" { | ||
| 6 | comptime testBitReverse(); | ||
| 7 | testBitReverse(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitReverse() void { | ||
| 11 | // using comptime_ints, unsigned | ||
| 12 | assert(@bitreverse(u0, 0) == 0); | ||
| 13 | assert(@bitreverse(u5, 0x12) == 0x9); | ||
| 14 | assert(@bitreverse(u8, 0x12) == 0x48); | ||
| 15 | assert(@bitreverse(u16, 0x1234) == 0x2c48); | ||
| 16 | assert(@bitreverse(u24, 0x123456) == 0x6a2c48); | ||
| 17 | assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); | ||
| 18 | assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); | ||
| 19 | assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); | ||
| 20 | assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); | ||
| 21 | assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); | ||
| 22 | assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 23 | |||
| 24 | // using runtime uints, unsigned | ||
| 25 | var num0: u0 = 0; | ||
| 26 | assert(@bitreverse(u0, num0) == 0); | ||
| 27 | var num5: u5 = 0x12; | ||
| 28 | assert(@bitreverse(u5, num5) == 0x9); | ||
| 29 | var num8: u8 = 0x12; | ||
| 30 | assert(@bitreverse(u8, num8) == 0x48); | ||
| 31 | var num16: u16 = 0x1234; | ||
| 32 | assert(@bitreverse(u16, num16) == 0x2c48); | ||
| 33 | var num24: u24 = 0x123456; | ||
| 34 | assert(@bitreverse(u24, num24) == 0x6a2c48); | ||
| 35 | var num32: u32 = 0x12345678; | ||
| 36 | assert(@bitreverse(u32, num32) == 0x1e6a2c48); | ||
| 37 | var num40: u40 = 0x123456789a; | ||
| 38 | assert(@bitreverse(u40, num40) == 0x591e6a2c48); | ||
| 39 | var num48: u48 = 0x123456789abc; | ||
| 40 | assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); | ||
| 41 | var num56: u56 = 0x123456789abcde; | ||
| 42 | assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); | ||
| 43 | var num64: u64 = 0x123456789abcdef1; | ||
| 44 | assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); | ||
| 45 | var num128: u128 = 0x123456789abcdef11121314151617181; | ||
| 46 | assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 47 | |||
| 48 | // using comptime_ints, signed, positive | ||
| 49 | assert(@bitreverse(i0, 0) == 0); | ||
| 50 | assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); | ||
| 51 | assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); | ||
| 52 | assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); | ||
| 53 | assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); | ||
| 54 | assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); | ||
| 55 | assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); | ||
| 56 | assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); | ||
| 57 | assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); | ||
| 58 | assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); | ||
| 59 | |||
| 60 | // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. | ||
| 61 | var neg5: i5 = minInt(i5) + 1; | ||
| 62 | assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); | ||
| 63 | var neg8: i8 = -18; | ||
| 64 | assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); | ||
| 65 | var neg16: i16 = -32694; | ||
| 66 | assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); | ||
| 67 | var neg24: i24 = -6773785; | ||
| 68 | assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); | ||
| 69 | var neg32: i32 = -16773785; | ||
| 70 | assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); | ||
| 71 | var neg40: i40 = minInt(i40) + 12345; | ||
| 72 | assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); | ||
| 73 | var neg48: i48 = minInt(i48) + 12345; | ||
| 74 | assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); | ||
| 75 | var neg56: i56 = minInt(i56) + 12345; | ||
| 76 | assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); | ||
| 77 | var neg64: i64 = minInt(i64) + 12345; | ||
| 78 | assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); | ||
| 79 | var neg128: i128 = minInt(i128) + 12345; | ||
| 80 | assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); | ||
| 81 | } | ||
test/cases/bool.zig deleted-35| ... | @@ -1,35 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "bool literals" { | ||
| 4 | assert(true); | ||
| 5 | assert(!false); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "cast bool to int" { | ||
| 9 | const t = true; | ||
| 10 | const f = false; | ||
| 11 | assert(@boolToInt(t) == u32(1)); | ||
| 12 | assert(@boolToInt(f) == u32(0)); | ||
| 13 | nonConstCastBoolToInt(t, f); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn nonConstCastBoolToInt(t: bool, f: bool) void { | ||
| 17 | assert(@boolToInt(t) == u32(1)); | ||
| 18 | assert(@boolToInt(f) == u32(0)); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "bool cmp" { | ||
| 22 | assert(testBoolCmp(true, false) == false); | ||
| 23 | } | ||
| 24 | fn testBoolCmp(a: bool, b: bool) bool { | ||
| 25 | return a == b; | ||
| 26 | } | ||
| 27 | |||
| 28 | const global_f = false; | ||
| 29 | const global_t = true; | ||
| 30 | const not_global_f = !global_f; | ||
| 31 | const not_global_t = !global_t; | ||
| 32 | test "compile time bool not" { | ||
| 33 | assert(not_global_f); | ||
| 34 | assert(!not_global_t); | ||
| 35 | } | ||
test/cases/bswap.zig deleted-32| ... | @@ -1,32 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | test "@bswap" { | ||
| 5 | comptime testByteSwap(); | ||
| 6 | testByteSwap(); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn testByteSwap() void { | ||
| 10 | assert(@bswap(u0, 0) == 0); | ||
| 11 | assert(@bswap(u8, 0x12) == 0x12); | ||
| 12 | assert(@bswap(u16, 0x1234) == 0x3412); | ||
| 13 | assert(@bswap(u24, 0x123456) == 0x563412); | ||
| 14 | assert(@bswap(u32, 0x12345678) == 0x78563412); | ||
| 15 | assert(@bswap(u40, 0x123456789a) == 0x9a78563412); | ||
| 16 | assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); | ||
| 17 | assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); | ||
| 18 | assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); | ||
| 19 | assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); | ||
| 20 | |||
| 21 | assert(@bswap(i0, 0) == 0); | ||
| 22 | assert(@bswap(i8, -50) == -50); | ||
| 23 | assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); | ||
| 24 | assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); | ||
| 25 | assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); | ||
| 26 | assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); | ||
| 27 | assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); | ||
| 28 | assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); | ||
| 29 | assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); | ||
| 30 | assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == | ||
| 31 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); | ||
| 32 | } | ||
test/cases/bugs/1076.zig deleted-16| ... | @@ -1,16 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | |||
| 5 | test "comptime code should not modify constant data" { | ||
| 6 | testCastPtrOfArrayToSliceAndPtr(); | ||
| 7 | comptime testCastPtrOfArrayToSliceAndPtr(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testCastPtrOfArrayToSliceAndPtr() void { | ||
| 11 | var array = "aoeu"; | ||
| 12 | const x: [*]u8 = &array; | ||
| 13 | x[0] += 1; | ||
| 14 | assert(mem.eql(u8, array[0..], "boeu")); | ||
| 15 | } | ||
| 16 | |||
test/cases/bugs/1111.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const Foo = extern enum { | ||
| 2 | Bar = -1, | ||
| 3 | }; | ||
| 4 | |||
| 5 | test "issue 1111 fixed" { | ||
| 6 | const v = Foo.Bar; | ||
| 7 | |||
| 8 | switch (v) { | ||
| 9 | Foo.Bar => return, | ||
| 10 | else => return, | ||
| 11 | } | ||
| 12 | } | ||
test/cases/bugs/1277.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const S = struct { | ||
| 4 | f: ?fn () i32, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const s = S{ .f = f }; | ||
| 8 | |||
| 9 | fn f() i32 { | ||
| 10 | return 1234; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "don't emit an LLVM global for a const function when it's in an optional in a struct" { | ||
| 14 | std.debug.assertOrPanic(s.f.?() == 1234); | ||
| 15 | } | ||
test/cases/bugs/1322.zig deleted-19| ... | @@ -1,19 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | c: C, | ||
| 5 | None, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = struct { | ||
| 9 | b: B, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const C = struct {}; | ||
| 13 | |||
| 14 | test "tagged union with all void fields but a meaningful tag" { | ||
| 15 | var a: A = A{ .b = B{ .c = C{} } }; | ||
| 16 | std.debug.assert(@TagType(B)(a.b) == @TagType(B).c); | ||
| 17 | a = A{ .b = B.None }; | ||
| 18 | std.debug.assert(@TagType(B)(a.b) == @TagType(B).None); | ||
| 19 | } | ||
test/cases/bugs/1381.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | D: u8, | ||
| 5 | E: u16, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = union(enum) { | ||
| 9 | B: B, | ||
| 10 | C: u8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "union that needs padding bytes inside an array" { | ||
| 14 | var as = []A{ | ||
| 15 | A{ .B = B{ .D = 1 } }, | ||
| 16 | A{ .B = B{ .D = 1 } }, | ||
| 17 | }; | ||
| 18 | |||
| 19 | const a = as[0].B; | ||
| 20 | std.debug.assertOrPanic(a.D == 1); | ||
| 21 | } | ||
test/cases/bugs/1421.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | |||
| 5 | const S = struct { | ||
| 6 | fn method() builtin.TypeInfo { | ||
| 7 | return @typeInfo(S); | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | test "functions with return type required to be comptime are generic" { | ||
| 12 | const ti = S.method(); | ||
| 13 | assert(builtin.TypeId(ti) == builtin.TypeId.Struct); | ||
| 14 | } | ||
test/cases/bugs/1442.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Union = union(enum) { | ||
| 4 | Text: []const u8, | ||
| 5 | Color: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | test "const error union field alignment" { | ||
| 9 | var union_or_err: anyerror!Union = Union{ .Color = 1234 }; | ||
| 10 | std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); | ||
| 11 | } | ||
test/cases/bugs/1486.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const ptr = &global; | ||
| 4 | var global: u64 = 123; | ||
| 5 | |||
| 6 | test "constant pointer to global variable causes runtime load" { | ||
| 7 | global = 1234; | ||
| 8 | assert(&global == ptr); | ||
| 9 | assert(ptr.* == 1234); | ||
| 10 | } | ||
| 11 | |||
test/cases/bugs/394.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | const E = union(enum) { | ||
| 2 | A: [9]u8, | ||
| 3 | B: u64, | ||
| 4 | }; | ||
| 5 | const S = struct { | ||
| 6 | x: u8, | ||
| 7 | y: E, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const assert = @import("std").debug.assert; | ||
| 11 | |||
| 12 | test "bug 394 fixed" { | ||
| 13 | const x = S{ | ||
| 14 | .x = 3, | ||
| 15 | .y = E{ .B = 1 }, | ||
| 16 | }; | ||
| 17 | assert(x.x == 3); | ||
| 18 | } | ||
test/cases/bugs/655.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const other_file = @import("655_other_file.zig"); | ||
| 3 | |||
| 4 | test "function with *const parameter with type dereferenced by namespace" { | ||
| 5 | const x: other_file.Integer = 1234; | ||
| 6 | comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer); | ||
| 7 | foo(&x); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn foo(x: *const other_file.Integer) void { | ||
| 11 | std.debug.assert(x.* == 1234); | ||
| 12 | } | ||
test/cases/bugs/655_other_file.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const Integer = u32; | ||
test/cases/bugs/656.zig deleted-31| ... | @@ -1,31 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const PrefixOp = union(enum) { | ||
| 4 | Return, | ||
| 5 | AddrOf: Value, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Value = struct { | ||
| 9 | align_expr: ?u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { | ||
| 13 | foo(false, true); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(a: bool, b: bool) void { | ||
| 17 | var prefix_op = PrefixOp{ | ||
| 18 | .AddrOf = Value{ .align_expr = 1234 }, | ||
| 19 | }; | ||
| 20 | if (a) {} else { | ||
| 21 | switch (prefix_op) { | ||
| 22 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 23 | if (b) {} | ||
| 24 | if (addr_of_info.align_expr) |align_expr| { | ||
| 25 | assert(align_expr == 1234); | ||
| 26 | } | ||
| 27 | }, | ||
| 28 | PrefixOp.Return => {}, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
test/cases/bugs/726.zig deleted-16| ... | @@ -1,16 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "@ptrCast from const to nullable" { | ||
| 4 | const c: u8 = 4; | ||
| 5 | var x: ?*const u8 = @ptrCast(?*const u8, &c); | ||
| 6 | assert(x.?.* == 4); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "@ptrCast from var in empty struct to nullable" { | ||
| 10 | const container = struct { | ||
| 11 | var c: u8 = 4; | ||
| 12 | }; | ||
| 13 | var x: ?*const u8 = @ptrCast(?*const u8, &container.c); | ||
| 14 | assert(x.?.* == 4); | ||
| 15 | } | ||
| 16 | |||
test/cases/bugs/828.zig deleted-33| ... | @@ -1,33 +0,0 @@ | ||
| 1 | const CountBy = struct { | ||
| 2 | a: usize, | ||
| 3 | |||
| 4 | const One = CountBy{ .a = 1 }; | ||
| 5 | |||
| 6 | pub fn counter(self: *const CountBy) Counter { | ||
| 7 | return Counter{ .i = 0 }; | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Counter = struct { | ||
| 12 | i: usize, | ||
| 13 | |||
| 14 | pub fn count(self: *Counter) bool { | ||
| 15 | self.i += 1; | ||
| 16 | return self.i <= 10; | ||
| 17 | } | ||
| 18 | }; | ||
| 19 | |||
| 20 | fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { | ||
| 21 | comptime { | ||
| 22 | var cnt = cb.counter(); | ||
| 23 | if (cnt.i != 0) @compileError("Counter instance reused!"); | ||
| 24 | while (cnt.count()) {} | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "comptime struct return should not return the same instance" { | ||
| 29 | //the first parameter must be passed by reference to trigger the bug | ||
| 30 | //a second parameter is required to trigger the bug | ||
| 31 | const ValA = constCount(&CountBy.One, 12); | ||
| 32 | const ValB = constCount(&CountBy.One, 15); | ||
| 33 | } | ||
test/cases/bugs/920.zig deleted-65| ... | @@ -1,65 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const Random = std.rand.Random; | ||
| 4 | |||
| 5 | const ZigTable = struct { | ||
| 6 | r: f64, | ||
| 7 | x: [257]f64, | ||
| 8 | f: [257]f64, | ||
| 9 | |||
| 10 | pdf: fn (f64) f64, | ||
| 11 | is_symmetric: bool, | ||
| 12 | zero_case: fn (*Random, f64) f64, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { | ||
| 16 | var tables: ZigTable = undefined; | ||
| 17 | |||
| 18 | tables.is_symmetric = is_symmetric; | ||
| 19 | tables.r = r; | ||
| 20 | tables.pdf = f; | ||
| 21 | tables.zero_case = zero_case; | ||
| 22 | |||
| 23 | tables.x[0] = v / f(r); | ||
| 24 | tables.x[1] = r; | ||
| 25 | |||
| 26 | for (tables.x[2..256]) |*entry, i| { | ||
| 27 | const last = tables.x[2 + i - 1]; | ||
| 28 | entry.* = f_inv(v / last + f(last)); | ||
| 29 | } | ||
| 30 | tables.x[256] = 0; | ||
| 31 | |||
| 32 | for (tables.f[0..]) |*entry, i| { | ||
| 33 | entry.* = f(tables.x[i]); | ||
| 34 | } | ||
| 35 | |||
| 36 | return tables; | ||
| 37 | } | ||
| 38 | |||
| 39 | const norm_r = 3.6541528853610088; | ||
| 40 | const norm_v = 0.00492867323399; | ||
| 41 | |||
| 42 | fn norm_f(x: f64) f64 { | ||
| 43 | return math.exp(-x * x / 2.0); | ||
| 44 | } | ||
| 45 | fn norm_f_inv(y: f64) f64 { | ||
| 46 | return math.sqrt(-2.0 * math.ln(y)); | ||
| 47 | } | ||
| 48 | fn norm_zero_case(random: *Random, u: f64) f64 { | ||
| 49 | return 0.0; | ||
| 50 | } | ||
| 51 | |||
| 52 | const NormalDist = blk: { | ||
| 53 | @setEvalBranchQuota(30000); | ||
| 54 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 55 | }; | ||
| 56 | |||
| 57 | test "bug 920 fixed" { | ||
| 58 | const NormalDist1 = blk: { | ||
| 59 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 60 | }; | ||
| 61 | |||
| 62 | for (NormalDist1.f) |_, i| { | ||
| 63 | std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]); | ||
| 64 | } | ||
| 65 | } | ||
test/cases/byval_arg_var.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var result: []const u8 = "wrong"; | ||
| 4 | |||
| 5 | test "aoeu" { | ||
| 6 | start(); | ||
| 7 | blowUpStack(10); | ||
| 8 | |||
| 9 | std.debug.assert(std.mem.eql(u8, result, "string literal")); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn start() void { | ||
| 13 | foo("string literal"); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(x: var) void { | ||
| 17 | bar(x); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn bar(x: var) void { | ||
| 21 | result = x; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn blowUpStack(x: u32) void { | ||
| 25 | if (x == 0) return; | ||
| 26 | blowUpStack(x - 1); | ||
| 27 | } | ||
test/cases/cancel.zig deleted-92| ... | @@ -1,92 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var defer_f1: bool = false; | ||
| 4 | var defer_f2: bool = false; | ||
| 5 | var defer_f3: bool = false; | ||
| 6 | |||
| 7 | test "cancel forwards" { | ||
| 8 | var da = std.heap.DirectAllocator.init(); | ||
| 9 | defer da.deinit(); | ||
| 10 | |||
| 11 | const p = async<&da.allocator> f1() catch unreachable; | ||
| 12 | cancel p; | ||
| 13 | std.debug.assert(defer_f1); | ||
| 14 | std.debug.assert(defer_f2); | ||
| 15 | std.debug.assert(defer_f3); | ||
| 16 | } | ||
| 17 | |||
| 18 | async fn f1() void { | ||
| 19 | defer { | ||
| 20 | defer_f1 = true; | ||
| 21 | } | ||
| 22 | await (async f2() catch unreachable); | ||
| 23 | } | ||
| 24 | |||
| 25 | async fn f2() void { | ||
| 26 | defer { | ||
| 27 | defer_f2 = true; | ||
| 28 | } | ||
| 29 | await (async f3() catch unreachable); | ||
| 30 | } | ||
| 31 | |||
| 32 | async fn f3() void { | ||
| 33 | defer { | ||
| 34 | defer_f3 = true; | ||
| 35 | } | ||
| 36 | suspend; | ||
| 37 | } | ||
| 38 | |||
| 39 | var defer_b1: bool = false; | ||
| 40 | var defer_b2: bool = false; | ||
| 41 | var defer_b3: bool = false; | ||
| 42 | var defer_b4: bool = false; | ||
| 43 | |||
| 44 | test "cancel backwards" { | ||
| 45 | var da = std.heap.DirectAllocator.init(); | ||
| 46 | defer da.deinit(); | ||
| 47 | |||
| 48 | const p = async<&da.allocator> b1() catch unreachable; | ||
| 49 | cancel p; | ||
| 50 | std.debug.assert(defer_b1); | ||
| 51 | std.debug.assert(defer_b2); | ||
| 52 | std.debug.assert(defer_b3); | ||
| 53 | std.debug.assert(defer_b4); | ||
| 54 | } | ||
| 55 | |||
| 56 | async fn b1() void { | ||
| 57 | defer { | ||
| 58 | defer_b1 = true; | ||
| 59 | } | ||
| 60 | await (async b2() catch unreachable); | ||
| 61 | } | ||
| 62 | |||
| 63 | var b4_handle: promise = undefined; | ||
| 64 | |||
| 65 | async fn b2() void { | ||
| 66 | const b3_handle = async b3() catch unreachable; | ||
| 67 | resume b4_handle; | ||
| 68 | cancel b4_handle; | ||
| 69 | defer { | ||
| 70 | defer_b2 = true; | ||
| 71 | } | ||
| 72 | const value = await b3_handle; | ||
| 73 | @panic("unreachable"); | ||
| 74 | } | ||
| 75 | |||
| 76 | async fn b3() i32 { | ||
| 77 | defer { | ||
| 78 | defer_b3 = true; | ||
| 79 | } | ||
| 80 | await (async b4() catch unreachable); | ||
| 81 | return 1234; | ||
| 82 | } | ||
| 83 | |||
| 84 | async fn b4() void { | ||
| 85 | defer { | ||
| 86 | defer_b4 = true; | ||
| 87 | } | ||
| 88 | suspend { | ||
| 89 | b4_handle = @handle(); | ||
| 90 | } | ||
| 91 | suspend; | ||
| 92 | } | ||
test/cases/cast.zig deleted-472| ... | @@ -1,472 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | test "int to ptr cast" { | ||
| 7 | const x = usize(13); | ||
| 8 | const y = @intToPtr(*u8, x); | ||
| 9 | const z = @ptrToInt(y); | ||
| 10 | assert(z == 13); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "integer literal to pointer cast" { | ||
| 14 | const vga_mem = @intToPtr(*u16, 0xB8000); | ||
| 15 | assert(@ptrToInt(vga_mem) == 0xB8000); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "pointer reinterpret const float to int" { | ||
| 19 | const float: f64 = 5.99999999999994648725e-01; | ||
| 20 | const float_ptr = &float; | ||
| 21 | const int_ptr = @ptrCast(*const i32, float_ptr); | ||
| 22 | const int_val = int_ptr.*; | ||
| 23 | assert(int_val == 858993411); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "implicitly cast indirect pointer to maybe-indirect pointer" { | ||
| 27 | const S = struct { | ||
| 28 | const Self = @This(); | ||
| 29 | x: u8, | ||
| 30 | fn constConst(p: *const *const Self) u8 { | ||
| 31 | return p.*.x; | ||
| 32 | } | ||
| 33 | fn maybeConstConst(p: ?*const *const Self) u8 { | ||
| 34 | return p.?.*.x; | ||
| 35 | } | ||
| 36 | fn constConstConst(p: *const *const *const Self) u8 { | ||
| 37 | return p.*.*.x; | ||
| 38 | } | ||
| 39 | fn maybeConstConstConst(p: ?*const *const *const Self) u8 { | ||
| 40 | return p.?.*.*.x; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | const s = S{ .x = 42 }; | ||
| 44 | const p = &s; | ||
| 45 | const q = &p; | ||
| 46 | const r = &q; | ||
| 47 | assert(42 == S.constConst(q)); | ||
| 48 | assert(42 == S.maybeConstConst(q)); | ||
| 49 | assert(42 == S.constConstConst(r)); | ||
| 50 | assert(42 == S.maybeConstConstConst(r)); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "explicit cast from integer to error type" { | ||
| 54 | testCastIntToErr(error.ItBroke); | ||
| 55 | comptime testCastIntToErr(error.ItBroke); | ||
| 56 | } | ||
| 57 | fn testCastIntToErr(err: anyerror) void { | ||
| 58 | const x = @errorToInt(err); | ||
| 59 | const y = @intToError(x); | ||
| 60 | assert(error.ItBroke == y); | ||
| 61 | } | ||
| 62 | |||
| 63 | test "peer resolve arrays of different size to const slice" { | ||
| 64 | assert(mem.eql(u8, boolToStr(true), "true")); | ||
| 65 | assert(mem.eql(u8, boolToStr(false), "false")); | ||
| 66 | comptime assert(mem.eql(u8, boolToStr(true), "true")); | ||
| 67 | comptime assert(mem.eql(u8, boolToStr(false), "false")); | ||
| 68 | } | ||
| 69 | fn boolToStr(b: bool) []const u8 { | ||
| 70 | return if (b) "true" else "false"; | ||
| 71 | } | ||
| 72 | |||
| 73 | test "peer resolve array and const slice" { | ||
| 74 | testPeerResolveArrayConstSlice(true); | ||
| 75 | comptime testPeerResolveArrayConstSlice(true); | ||
| 76 | } | ||
| 77 | fn testPeerResolveArrayConstSlice(b: bool) void { | ||
| 78 | const value1 = if (b) "aoeu" else ([]const u8)("zz"); | ||
| 79 | const value2 = if (b) ([]const u8)("zz") else "aoeu"; | ||
| 80 | assert(mem.eql(u8, value1, "aoeu")); | ||
| 81 | assert(mem.eql(u8, value2, "zz")); | ||
| 82 | } | ||
| 83 | |||
| 84 | test "implicitly cast from T to anyerror!?T" { | ||
| 85 | castToOptionalTypeError(1); | ||
| 86 | comptime castToOptionalTypeError(1); | ||
| 87 | } | ||
| 88 | const A = struct { | ||
| 89 | a: i32, | ||
| 90 | }; | ||
| 91 | fn castToOptionalTypeError(z: i32) void { | ||
| 92 | const x = i32(1); | ||
| 93 | const y: anyerror!?i32 = x; | ||
| 94 | assert((try y).? == 1); | ||
| 95 | |||
| 96 | const f = z; | ||
| 97 | const g: anyerror!?i32 = f; | ||
| 98 | |||
| 99 | const a = A{ .a = z }; | ||
| 100 | const b: anyerror!?A = a; | ||
| 101 | assert((b catch unreachable).?.a == 1); | ||
| 102 | } | ||
| 103 | |||
| 104 | test "implicitly cast from int to anyerror!?T" { | ||
| 105 | implicitIntLitToOptional(); | ||
| 106 | comptime implicitIntLitToOptional(); | ||
| 107 | } | ||
| 108 | fn implicitIntLitToOptional() void { | ||
| 109 | const f: ?i32 = 1; | ||
| 110 | const g: anyerror!?i32 = 1; | ||
| 111 | } | ||
| 112 | |||
| 113 | test "return null from fn() anyerror!?&T" { | ||
| 114 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 115 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 116 | assert((try a) == null and (try b) == null); | ||
| 117 | } | ||
| 118 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 119 | const a: ?*A = null; | ||
| 120 | return a; | ||
| 121 | } | ||
| 122 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 123 | return null; | ||
| 124 | } | ||
| 125 | |||
| 126 | test "peer type resolution: ?T and T" { | ||
| 127 | assert(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 128 | assert(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 129 | comptime { | ||
| 130 | assert(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 131 | assert(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { | ||
| 135 | if (c) { | ||
| 136 | return if (b) null else usize(0); | ||
| 137 | } | ||
| 138 | |||
| 139 | return usize(3); | ||
| 140 | } | ||
| 141 | |||
| 142 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 143 | assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 144 | assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 145 | comptime { | ||
| 146 | assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 147 | assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 151 | if (a) { | ||
| 152 | return []const u8{}; | ||
| 153 | } | ||
| 154 | |||
| 155 | return slice[0..1]; | ||
| 156 | } | ||
| 157 | |||
| 158 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 159 | assert(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 160 | comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 161 | } | ||
| 162 | |||
| 163 | fn castToOptionalSlice() ?[]const u8 { | ||
| 164 | return "hi"; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "implicitly cast from [0]T to anyerror![]T" { | ||
| 168 | testCastZeroArrayToErrSliceMut(); | ||
| 169 | comptime testCastZeroArrayToErrSliceMut(); | ||
| 170 | } | ||
| 171 | |||
| 172 | fn testCastZeroArrayToErrSliceMut() void { | ||
| 173 | assert((gimmeErrOrSlice() catch unreachable).len == 0); | ||
| 174 | } | ||
| 175 | |||
| 176 | fn gimmeErrOrSlice() anyerror![]u8 { | ||
| 177 | return []u8{}; | ||
| 178 | } | ||
| 179 | |||
| 180 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { | ||
| 181 | { | ||
| 182 | var data = "hi"; | ||
| 183 | const slice = data[0..]; | ||
| 184 | assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 185 | assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 186 | } | ||
| 187 | comptime { | ||
| 188 | var data = "hi"; | ||
| 189 | const slice = data[0..]; | ||
| 190 | assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 191 | assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { | ||
| 195 | if (a) { | ||
| 196 | return []u8{}; | ||
| 197 | } | ||
| 198 | |||
| 199 | return slice[0..1]; | ||
| 200 | } | ||
| 201 | |||
| 202 | test "resolve undefined with integer" { | ||
| 203 | testResolveUndefWithInt(true, 1234); | ||
| 204 | comptime testResolveUndefWithInt(true, 1234); | ||
| 205 | } | ||
| 206 | fn testResolveUndefWithInt(b: bool, x: i32) void { | ||
| 207 | const value = if (b) x else undefined; | ||
| 208 | if (b) { | ||
| 209 | assert(value == x); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | test "implicit cast from &const [N]T to []const T" { | ||
| 214 | testCastConstArrayRefToConstSlice(); | ||
| 215 | comptime testCastConstArrayRefToConstSlice(); | ||
| 216 | } | ||
| 217 | |||
| 218 | fn testCastConstArrayRefToConstSlice() void { | ||
| 219 | const blah = "aoeu"; | ||
| 220 | const const_array_ref = &blah; | ||
| 221 | assert(@typeOf(const_array_ref) == *const [4]u8); | ||
| 222 | const slice: []const u8 = const_array_ref; | ||
| 223 | assert(mem.eql(u8, slice, "aoeu")); | ||
| 224 | } | ||
| 225 | |||
| 226 | test "peer type resolution: error and [N]T" { | ||
| 227 | // TODO: implicit error!T to error!U where T can implicitly cast to U | ||
| 228 | //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 229 | //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 230 | assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 231 | comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 232 | } | ||
| 233 | |||
| 234 | //fn testPeerErrorAndArray(x: u8) error![]const u8 { | ||
| 235 | // return switch (x) { | ||
| 236 | // 0x00 => "OK", | ||
| 237 | // else => error.BadValue, | ||
| 238 | // }; | ||
| 239 | //} | ||
| 240 | fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { | ||
| 241 | return switch (x) { | ||
| 242 | 0x00 => "OK", | ||
| 243 | 0x01 => "OKK", | ||
| 244 | else => error.BadValue, | ||
| 245 | }; | ||
| 246 | } | ||
| 247 | |||
| 248 | test "@floatToInt" { | ||
| 249 | testFloatToInts(); | ||
| 250 | comptime testFloatToInts(); | ||
| 251 | } | ||
| 252 | |||
| 253 | fn testFloatToInts() void { | ||
| 254 | const x = i32(1e4); | ||
| 255 | assert(x == 10000); | ||
| 256 | const y = @floatToInt(i32, f32(1e4)); | ||
| 257 | assert(y == 10000); | ||
| 258 | expectFloatToInt(f16, 255.1, u8, 255); | ||
| 259 | expectFloatToInt(f16, 127.2, i8, 127); | ||
| 260 | expectFloatToInt(f16, -128.2, i8, -128); | ||
| 261 | expectFloatToInt(f32, 255.1, u8, 255); | ||
| 262 | expectFloatToInt(f32, 127.2, i8, 127); | ||
| 263 | expectFloatToInt(f32, -128.2, i8, -128); | ||
| 264 | expectFloatToInt(comptime_int, 1234, i16, 1234); | ||
| 265 | } | ||
| 266 | |||
| 267 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { | ||
| 268 | assert(@floatToInt(I, f) == i); | ||
| 269 | } | ||
| 270 | |||
| 271 | test "cast u128 to f128 and back" { | ||
| 272 | comptime testCast128(); | ||
| 273 | testCast128(); | ||
| 274 | } | ||
| 275 | |||
| 276 | fn testCast128() void { | ||
| 277 | assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 278 | } | ||
| 279 | |||
| 280 | fn cast128Int(x: f128) u128 { | ||
| 281 | return @bitCast(u128, x); | ||
| 282 | } | ||
| 283 | |||
| 284 | fn cast128Float(x: u128) f128 { | ||
| 285 | return @bitCast(f128, x); | ||
| 286 | } | ||
| 287 | |||
| 288 | test "const slice widen cast" { | ||
| 289 | const bytes align(4) = []u8{ | ||
| 290 | 0x12, | ||
| 291 | 0x12, | ||
| 292 | 0x12, | ||
| 293 | 0x12, | ||
| 294 | }; | ||
| 295 | |||
| 296 | const u32_value = @bytesToSlice(u32, bytes[0..])[0]; | ||
| 297 | assert(u32_value == 0x12121212); | ||
| 298 | |||
| 299 | assert(@bitCast(u32, bytes) == 0x12121212); | ||
| 300 | } | ||
| 301 | |||
| 302 | test "single-item pointer of array to slice and to unknown length pointer" { | ||
| 303 | testCastPtrOfArrayToSliceAndPtr(); | ||
| 304 | comptime testCastPtrOfArrayToSliceAndPtr(); | ||
| 305 | } | ||
| 306 | |||
| 307 | fn testCastPtrOfArrayToSliceAndPtr() void { | ||
| 308 | var array = "aoeu"; | ||
| 309 | const x: [*]u8 = &array; | ||
| 310 | x[0] += 1; | ||
| 311 | assert(mem.eql(u8, array[0..], "boeu")); | ||
| 312 | const y: []u8 = &array; | ||
| 313 | y[0] += 1; | ||
| 314 | assert(mem.eql(u8, array[0..], "coeu")); | ||
| 315 | } | ||
| 316 | |||
| 317 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | ||
| 318 | const window_name = [1][*]const u8{c"window name"}; | ||
| 319 | const x: [*]const ?[*]const u8 = &window_name; | ||
| 320 | assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); | ||
| 321 | } | ||
| 322 | |||
| 323 | test "@intCast comptime_int" { | ||
| 324 | const result = @intCast(i32, 1234); | ||
| 325 | assert(@typeOf(result) == i32); | ||
| 326 | assert(result == 1234); | ||
| 327 | } | ||
| 328 | |||
| 329 | test "@floatCast comptime_int and comptime_float" { | ||
| 330 | { | ||
| 331 | const result = @floatCast(f16, 1234); | ||
| 332 | assert(@typeOf(result) == f16); | ||
| 333 | assert(result == 1234.0); | ||
| 334 | } | ||
| 335 | { | ||
| 336 | const result = @floatCast(f16, 1234.0); | ||
| 337 | assert(@typeOf(result) == f16); | ||
| 338 | assert(result == 1234.0); | ||
| 339 | } | ||
| 340 | { | ||
| 341 | const result = @floatCast(f32, 1234); | ||
| 342 | assert(@typeOf(result) == f32); | ||
| 343 | assert(result == 1234.0); | ||
| 344 | } | ||
| 345 | { | ||
| 346 | const result = @floatCast(f32, 1234.0); | ||
| 347 | assert(@typeOf(result) == f32); | ||
| 348 | assert(result == 1234.0); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | test "comptime_int @intToFloat" { | ||
| 353 | { | ||
| 354 | const result = @intToFloat(f16, 1234); | ||
| 355 | assert(@typeOf(result) == f16); | ||
| 356 | assert(result == 1234.0); | ||
| 357 | } | ||
| 358 | { | ||
| 359 | const result = @intToFloat(f32, 1234); | ||
| 360 | assert(@typeOf(result) == f32); | ||
| 361 | assert(result == 1234.0); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | test "@bytesToSlice keeps pointer alignment" { | ||
| 366 | var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; | ||
| 367 | const numbers = @bytesToSlice(u32, bytes[0..]); | ||
| 368 | comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); | ||
| 369 | } | ||
| 370 | |||
| 371 | test "@intCast i32 to u7" { | ||
| 372 | var x: u128 = maxInt(u128); | ||
| 373 | var y: i32 = 120; | ||
| 374 | var z = x >> @intCast(u7, y); | ||
| 375 | assert(z == 0xff); | ||
| 376 | } | ||
| 377 | |||
| 378 | test "implicit cast undefined to optional" { | ||
| 379 | assert(MakeType(void).getNull() == null); | ||
| 380 | assert(MakeType(void).getNonNull() != null); | ||
| 381 | } | ||
| 382 | |||
| 383 | fn MakeType(comptime T: type) type { | ||
| 384 | return struct { | ||
| 385 | fn getNull() ?T { | ||
| 386 | return null; | ||
| 387 | } | ||
| 388 | |||
| 389 | fn getNonNull() ?T { | ||
| 390 | return T(undefined); | ||
| 391 | } | ||
| 392 | }; | ||
| 393 | } | ||
| 394 | |||
| 395 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 396 | var x: ?[*]u16 = null; | ||
| 397 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 398 | |||
| 399 | x = &y; | ||
| 400 | assert(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 401 | x.?[0] = 8; | ||
| 402 | y[3] = 6; | ||
| 403 | assert(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 404 | } | ||
| 405 | |||
| 406 | test "implicit cast from *T to ?*c_void" { | ||
| 407 | var a: u8 = 1; | ||
| 408 | incrementVoidPtrValue(&a); | ||
| 409 | std.debug.assert(a == 2); | ||
| 410 | } | ||
| 411 | |||
| 412 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 413 | @ptrCast(*u8, value.?).* += 1; | ||
| 414 | } | ||
| 415 | |||
| 416 | test "implicit cast from [*]T to ?*c_void" { | ||
| 417 | var a = []u8{ 3, 2, 1 }; | ||
| 418 | incrementVoidPtrArray(a[0..].ptr, 3); | ||
| 419 | assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); | ||
| 420 | } | ||
| 421 | |||
| 422 | fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { | ||
| 423 | var n: usize = 0; | ||
| 424 | while (n < len) : (n += 1) { | ||
| 425 | @ptrCast([*]u8, array.?)[n] += 1; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | test "*usize to *void" { | ||
| 430 | var i = usize(0); | ||
| 431 | var v = @ptrCast(*void, &i); | ||
| 432 | v.* = {}; | ||
| 433 | } | ||
| 434 | |||
| 435 | test "compile time int to ptr of function" { | ||
| 436 | foobar(FUNCTION_CONSTANT); | ||
| 437 | } | ||
| 438 | |||
| 439 | pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); | ||
| 440 | pub const PFN_void = extern fn (*c_void) void; | ||
| 441 | |||
| 442 | fn foobar(func: PFN_void) void { | ||
| 443 | std.debug.assert(@ptrToInt(func) == maxInt(usize)); | ||
| 444 | } | ||
| 445 | |||
| 446 | test "implicit ptr to *c_void" { | ||
| 447 | var a: u32 = 1; | ||
| 448 | var ptr: *c_void = &a; | ||
| 449 | var b: *u32 = @ptrCast(*u32, ptr); | ||
| 450 | assert(b.* == 1); | ||
| 451 | var ptr2: ?*c_void = &a; | ||
| 452 | var c: *u32 = @ptrCast(*u32, ptr2.?); | ||
| 453 | assert(c.* == 1); | ||
| 454 | } | ||
| 455 | |||
| 456 | test "@intCast to comptime_int" { | ||
| 457 | assert(@intCast(comptime_int, 0) == 0); | ||
| 458 | } | ||
| 459 | |||
| 460 | test "implicit cast comptime numbers to any type when the value fits" { | ||
| 461 | const a: u64 = 255; | ||
| 462 | var b: u8 = a; | ||
| 463 | assert(b == 255); | ||
| 464 | } | ||
| 465 | |||
| 466 | test "@intToEnum passed a comptime_int to an enum with one item" { | ||
| 467 | const E = enum { | ||
| 468 | A, | ||
| 469 | }; | ||
| 470 | const x = @intToEnum(E, 0); | ||
| 471 | assert(x == E.A); | ||
| 472 | } | ||
test/cases/const_slice_child.zig deleted-45| ... | @@ -1,45 +0,0 @@ | ||
| 1 | const debug = @import("std").debug; | ||
| 2 | const assert = debug.assert; | ||
| 3 | |||
| 4 | var argv: [*]const [*]const u8 = undefined; | ||
| 5 | |||
| 6 | test "const slice child" { | ||
| 7 | const strs = ([][*]const u8){ | ||
| 8 | c"one", | ||
| 9 | c"two", | ||
| 10 | c"three", | ||
| 11 | }; | ||
| 12 | // TODO this should implicitly cast | ||
| 13 | argv = @ptrCast([*]const [*]const u8, &strs); | ||
| 14 | bar(strs.len); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn foo(args: [][]const u8) void { | ||
| 18 | assert(args.len == 3); | ||
| 19 | assert(streql(args[0], "one")); | ||
| 20 | assert(streql(args[1], "two")); | ||
| 21 | assert(streql(args[2], "three")); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn bar(argc: usize) void { | ||
| 25 | const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable; | ||
| 26 | for (args) |_, i| { | ||
| 27 | const ptr = argv[i]; | ||
| 28 | args[i] = ptr[0..strlen(ptr)]; | ||
| 29 | } | ||
| 30 | foo(args); | ||
| 31 | } | ||
| 32 | |||
| 33 | fn strlen(ptr: [*]const u8) usize { | ||
| 34 | var count: usize = 0; | ||
| 35 | while (ptr[count] != 0) : (count += 1) {} | ||
| 36 | return count; | ||
| 37 | } | ||
| 38 | |||
| 39 | fn streql(a: []const u8, b: []const u8) bool { | ||
| 40 | if (a.len != b.len) return false; | ||
| 41 | for (a) |item, index| { | ||
| 42 | if (b[index] != item) return false; | ||
| 43 | } | ||
| 44 | return true; | ||
| 45 | } | ||
test/cases/coroutine_await_struct.zig deleted-47| ... | @@ -1,47 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | |||
| 5 | const Foo = struct { | ||
| 6 | x: i32, | ||
| 7 | }; | ||
| 8 | |||
| 9 | var await_a_promise: promise = undefined; | ||
| 10 | var await_final_result = Foo{ .x = 0 }; | ||
| 11 | |||
| 12 | test "coroutine await struct" { | ||
| 13 | var da = std.heap.DirectAllocator.init(); | ||
| 14 | defer da.deinit(); | ||
| 15 | |||
| 16 | await_seq('a'); | ||
| 17 | const p = async<&da.allocator> await_amain() catch unreachable; | ||
| 18 | await_seq('f'); | ||
| 19 | resume await_a_promise; | ||
| 20 | await_seq('i'); | ||
| 21 | assert(await_final_result.x == 1234); | ||
| 22 | assert(std.mem.eql(u8, await_points, "abcdefghi")); | ||
| 23 | } | ||
| 24 | async fn await_amain() void { | ||
| 25 | await_seq('b'); | ||
| 26 | const p = async await_another() catch unreachable; | ||
| 27 | await_seq('e'); | ||
| 28 | await_final_result = await p; | ||
| 29 | await_seq('h'); | ||
| 30 | } | ||
| 31 | async fn await_another() Foo { | ||
| 32 | await_seq('c'); | ||
| 33 | suspend { | ||
| 34 | await_seq('d'); | ||
| 35 | await_a_promise = @handle(); | ||
| 36 | } | ||
| 37 | await_seq('g'); | ||
| 38 | return Foo{ .x = 1234 }; | ||
| 39 | } | ||
| 40 | |||
| 41 | var await_points = []u8{0} ** "abcdefghi".len; | ||
| 42 | var await_seq_index: usize = 0; | ||
| 43 | |||
| 44 | fn await_seq(c: u8) void { | ||
| 45 | await_points[await_seq_index] = c; | ||
| 46 | await_seq_index += 1; | ||
| 47 | } | ||
test/cases/coroutines.zig deleted-258| ... | @@ -1,258 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | |||
| 5 | var x: i32 = 1; | ||
| 6 | |||
| 7 | test "create a coroutine and cancel it" { | ||
| 8 | var da = std.heap.DirectAllocator.init(); | ||
| 9 | defer da.deinit(); | ||
| 10 | |||
| 11 | const p = try async<&da.allocator> simpleAsyncFn(); | ||
| 12 | comptime assert(@typeOf(p) == promise->void); | ||
| 13 | cancel p; | ||
| 14 | assert(x == 2); | ||
| 15 | } | ||
| 16 | async fn simpleAsyncFn() void { | ||
| 17 | x += 1; | ||
| 18 | suspend; | ||
| 19 | x += 1; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "coroutine suspend, resume, cancel" { | ||
| 23 | var da = std.heap.DirectAllocator.init(); | ||
| 24 | defer da.deinit(); | ||
| 25 | |||
| 26 | seq('a'); | ||
| 27 | const p = try async<&da.allocator> testAsyncSeq(); | ||
| 28 | seq('c'); | ||
| 29 | resume p; | ||
| 30 | seq('f'); | ||
| 31 | cancel p; | ||
| 32 | seq('g'); | ||
| 33 | |||
| 34 | assert(std.mem.eql(u8, points, "abcdefg")); | ||
| 35 | } | ||
| 36 | async fn testAsyncSeq() void { | ||
| 37 | defer seq('e'); | ||
| 38 | |||
| 39 | seq('b'); | ||
| 40 | suspend; | ||
| 41 | seq('d'); | ||
| 42 | } | ||
| 43 | var points = []u8{0} ** "abcdefg".len; | ||
| 44 | var index: usize = 0; | ||
| 45 | |||
| 46 | fn seq(c: u8) void { | ||
| 47 | points[index] = c; | ||
| 48 | index += 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | test "coroutine suspend with block" { | ||
| 52 | var da = std.heap.DirectAllocator.init(); | ||
| 53 | defer da.deinit(); | ||
| 54 | |||
| 55 | const p = try async<&da.allocator> testSuspendBlock(); | ||
| 56 | std.debug.assert(!result); | ||
| 57 | resume a_promise; | ||
| 58 | std.debug.assert(result); | ||
| 59 | cancel p; | ||
| 60 | } | ||
| 61 | |||
| 62 | var a_promise: promise = undefined; | ||
| 63 | var result = false; | ||
| 64 | async fn testSuspendBlock() void { | ||
| 65 | suspend { | ||
| 66 | comptime assert(@typeOf(@handle()) == promise->void); | ||
| 67 | a_promise = @handle(); | ||
| 68 | } | ||
| 69 | |||
| 70 | //Test to make sure that @handle() works as advertised (issue #1296) | ||
| 71 | //var our_handle: promise = @handle(); | ||
| 72 | assert( a_promise == @handle() ); | ||
| 73 | |||
| 74 | result = true; | ||
| 75 | } | ||
| 76 | |||
| 77 | var await_a_promise: promise = undefined; | ||
| 78 | var await_final_result: i32 = 0; | ||
| 79 | |||
| 80 | test "coroutine await" { | ||
| 81 | var da = std.heap.DirectAllocator.init(); | ||
| 82 | defer da.deinit(); | ||
| 83 | |||
| 84 | await_seq('a'); | ||
| 85 | const p = async<&da.allocator> await_amain() catch unreachable; | ||
| 86 | await_seq('f'); | ||
| 87 | resume await_a_promise; | ||
| 88 | await_seq('i'); | ||
| 89 | assert(await_final_result == 1234); | ||
| 90 | assert(std.mem.eql(u8, await_points, "abcdefghi")); | ||
| 91 | } | ||
| 92 | async fn await_amain() void { | ||
| 93 | await_seq('b'); | ||
| 94 | const p = async await_another() catch unreachable; | ||
| 95 | await_seq('e'); | ||
| 96 | await_final_result = await p; | ||
| 97 | await_seq('h'); | ||
| 98 | } | ||
| 99 | async fn await_another() i32 { | ||
| 100 | await_seq('c'); | ||
| 101 | suspend { | ||
| 102 | await_seq('d'); | ||
| 103 | await_a_promise = @handle(); | ||
| 104 | } | ||
| 105 | await_seq('g'); | ||
| 106 | return 1234; | ||
| 107 | } | ||
| 108 | |||
| 109 | var await_points = []u8{0} ** "abcdefghi".len; | ||
| 110 | var await_seq_index: usize = 0; | ||
| 111 | |||
| 112 | fn await_seq(c: u8) void { | ||
| 113 | await_points[await_seq_index] = c; | ||
| 114 | await_seq_index += 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | var early_final_result: i32 = 0; | ||
| 118 | |||
| 119 | test "coroutine await early return" { | ||
| 120 | var da = std.heap.DirectAllocator.init(); | ||
| 121 | defer da.deinit(); | ||
| 122 | |||
| 123 | early_seq('a'); | ||
| 124 | const p = async<&da.allocator> early_amain() catch @panic("out of memory"); | ||
| 125 | early_seq('f'); | ||
| 126 | assert(early_final_result == 1234); | ||
| 127 | assert(std.mem.eql(u8, early_points, "abcdef")); | ||
| 128 | } | ||
| 129 | async fn early_amain() void { | ||
| 130 | early_seq('b'); | ||
| 131 | const p = async early_another() catch @panic("out of memory"); | ||
| 132 | early_seq('d'); | ||
| 133 | early_final_result = await p; | ||
| 134 | early_seq('e'); | ||
| 135 | } | ||
| 136 | async fn early_another() i32 { | ||
| 137 | early_seq('c'); | ||
| 138 | return 1234; | ||
| 139 | } | ||
| 140 | |||
| 141 | var early_points = []u8{0} ** "abcdef".len; | ||
| 142 | var early_seq_index: usize = 0; | ||
| 143 | |||
| 144 | fn early_seq(c: u8) void { | ||
| 145 | early_points[early_seq_index] = c; | ||
| 146 | early_seq_index += 1; | ||
| 147 | } | ||
| 148 | |||
| 149 | test "coro allocation failure" { | ||
| 150 | var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); | ||
| 151 | if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { | ||
| 152 | @panic("expected allocation failure"); | ||
| 153 | } else |err| switch (err) { | ||
| 154 | error.OutOfMemory => {}, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | async fn asyncFuncThatNeverGetsRun() void { | ||
| 158 | @panic("coro frame allocation should fail"); | ||
| 159 | } | ||
| 160 | |||
| 161 | test "async function with dot syntax" { | ||
| 162 | const S = struct { | ||
| 163 | var y: i32 = 1; | ||
| 164 | async fn foo() void { | ||
| 165 | y += 1; | ||
| 166 | suspend; | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | var da = std.heap.DirectAllocator.init(); | ||
| 170 | defer da.deinit(); | ||
| 171 | const p = try async<&da.allocator> S.foo(); | ||
| 172 | cancel p; | ||
| 173 | assert(S.y == 2); | ||
| 174 | } | ||
| 175 | |||
| 176 | test "async fn pointer in a struct field" { | ||
| 177 | var data: i32 = 1; | ||
| 178 | const Foo = struct { | ||
| 179 | bar: async<*std.mem.Allocator> fn (*i32) void, | ||
| 180 | }; | ||
| 181 | var foo = Foo{ .bar = simpleAsyncFn2 }; | ||
| 182 | var da = std.heap.DirectAllocator.init(); | ||
| 183 | defer da.deinit(); | ||
| 184 | const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; | ||
| 185 | assert(data == 2); | ||
| 186 | cancel p; | ||
| 187 | assert(data == 4); | ||
| 188 | } | ||
| 189 | async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { | ||
| 190 | defer y.* += 2; | ||
| 191 | y.* += 1; | ||
| 192 | suspend; | ||
| 193 | } | ||
| 194 | |||
| 195 | test "async fn with inferred error set" { | ||
| 196 | var da = std.heap.DirectAllocator.init(); | ||
| 197 | defer da.deinit(); | ||
| 198 | const p = (async<&da.allocator> failing()) catch unreachable; | ||
| 199 | resume p; | ||
| 200 | cancel p; | ||
| 201 | } | ||
| 202 | async fn failing() !void { | ||
| 203 | suspend; | ||
| 204 | return error.Fail; | ||
| 205 | } | ||
| 206 | |||
| 207 | test "error return trace across suspend points - early return" { | ||
| 208 | const p = nonFailing(); | ||
| 209 | resume p; | ||
| 210 | var da = std.heap.DirectAllocator.init(); | ||
| 211 | defer da.deinit(); | ||
| 212 | const p2 = try async<&da.allocator> printTrace(p); | ||
| 213 | cancel p2; | ||
| 214 | } | ||
| 215 | |||
| 216 | test "error return trace across suspend points - async return" { | ||
| 217 | const p = nonFailing(); | ||
| 218 | const p2 = try async<std.debug.global_allocator> printTrace(p); | ||
| 219 | resume p; | ||
| 220 | cancel p2; | ||
| 221 | } | ||
| 222 | |||
| 223 | // TODO https://github.com/ziglang/zig/issues/760 | ||
| 224 | fn nonFailing() promise->(anyerror!void) { | ||
| 225 | return async<std.debug.global_allocator> suspendThenFail() catch unreachable; | ||
| 226 | } | ||
| 227 | async fn suspendThenFail() anyerror!void { | ||
| 228 | suspend; | ||
| 229 | return error.Fail; | ||
| 230 | } | ||
| 231 | async fn printTrace(p: promise->(anyerror!void)) void { | ||
| 232 | (await p) catch |e| { | ||
| 233 | std.debug.assert(e == error.Fail); | ||
| 234 | if (@errorReturnTrace()) |trace| { | ||
| 235 | assert(trace.index == 1); | ||
| 236 | } else switch (builtin.mode) { | ||
| 237 | builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), | ||
| 238 | builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | } | ||
| 242 | |||
| 243 | test "break from suspend" { | ||
| 244 | var buf: [500]u8 = undefined; | ||
| 245 | var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; | ||
| 246 | var my_result: i32 = 1; | ||
| 247 | const p = try async<a> testBreakFromSuspend(&my_result); | ||
| 248 | cancel p; | ||
| 249 | std.debug.assert(my_result == 2); | ||
| 250 | } | ||
| 251 | async fn testBreakFromSuspend(my_result: *i32) void { | ||
| 252 | suspend { | ||
| 253 | resume @handle(); | ||
| 254 | } | ||
| 255 | my_result.* += 1; | ||
| 256 | suspend; | ||
| 257 | my_result.* += 1; | ||
| 258 | } | ||
test/cases/defer.zig deleted-78| ... | @@ -1,78 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | var result: [3]u8 = undefined; | ||
| 4 | var index: usize = undefined; | ||
| 5 | |||
| 6 | fn runSomeErrorDefers(x: bool) !bool { | ||
| 7 | index = 0; | ||
| 8 | defer { | ||
| 9 | result[index] = 'a'; | ||
| 10 | index += 1; | ||
| 11 | } | ||
| 12 | errdefer { | ||
| 13 | result[index] = 'b'; | ||
| 14 | index += 1; | ||
| 15 | } | ||
| 16 | defer { | ||
| 17 | result[index] = 'c'; | ||
| 18 | index += 1; | ||
| 19 | } | ||
| 20 | return if (x) x else error.FalseNotAllowed; | ||
| 21 | } | ||
| 22 | |||
| 23 | test "mixing normal and error defers" { | ||
| 24 | assert(runSomeErrorDefers(true) catch unreachable); | ||
| 25 | assert(result[0] == 'c'); | ||
| 26 | assert(result[1] == 'a'); | ||
| 27 | |||
| 28 | const ok = runSomeErrorDefers(false) catch |err| x: { | ||
| 29 | assert(err == error.FalseNotAllowed); | ||
| 30 | break :x true; | ||
| 31 | }; | ||
| 32 | assert(ok); | ||
| 33 | assert(result[0] == 'c'); | ||
| 34 | assert(result[1] == 'b'); | ||
| 35 | assert(result[2] == 'a'); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "break and continue inside loop inside defer expression" { | ||
| 39 | testBreakContInDefer(10); | ||
| 40 | comptime testBreakContInDefer(10); | ||
| 41 | } | ||
| 42 | |||
| 43 | fn testBreakContInDefer(x: usize) void { | ||
| 44 | defer { | ||
| 45 | var i: usize = 0; | ||
| 46 | while (i < x) : (i += 1) { | ||
| 47 | if (i < 5) continue; | ||
| 48 | if (i == 5) break; | ||
| 49 | } | ||
| 50 | assert(i == 5); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | test "defer and labeled break" { | ||
| 55 | var i = usize(0); | ||
| 56 | |||
| 57 | blk: { | ||
| 58 | defer i += 1; | ||
| 59 | break :blk; | ||
| 60 | } | ||
| 61 | |||
| 62 | assert(i == 1); | ||
| 63 | } | ||
| 64 | |||
| 65 | test "errdefer does not apply to fn inside fn" { | ||
| 66 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn testNestedFnErrDefer() anyerror!void { | ||
| 70 | var a: i32 = 0; | ||
| 71 | errdefer a += 1; | ||
| 72 | const S = struct { | ||
| 73 | fn baz() anyerror { | ||
| 74 | return error.Bad; | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | return S.baz(); | ||
| 78 | } | ||
test/cases/enum.zig deleted-894| ... | @@ -1,894 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | test "enum type" { | ||
| 5 | const foo1 = Foo{ .One = 13 }; | ||
| 6 | const foo2 = Foo{ | ||
| 7 | .Two = Point{ | ||
| 8 | .x = 1234, | ||
| 9 | .y = 5678, | ||
| 10 | }, | ||
| 11 | }; | ||
| 12 | const bar = Bar.B; | ||
| 13 | |||
| 14 | assert(bar == Bar.B); | ||
| 15 | assert(@memberCount(Foo) == 3); | ||
| 16 | assert(@memberCount(Bar) == 4); | ||
| 17 | assert(@sizeOf(Foo) == @sizeOf(FooNoVoid)); | ||
| 18 | assert(@sizeOf(Bar) == 1); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "enum as return value" { | ||
| 22 | switch (returnAnInt(13)) { | ||
| 23 | Foo.One => |value| assert(value == 13), | ||
| 24 | else => unreachable, | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | const Point = struct { | ||
| 29 | x: u64, | ||
| 30 | y: u64, | ||
| 31 | }; | ||
| 32 | const Foo = union(enum) { | ||
| 33 | One: i32, | ||
| 34 | Two: Point, | ||
| 35 | Three: void, | ||
| 36 | }; | ||
| 37 | const FooNoVoid = union(enum) { | ||
| 38 | One: i32, | ||
| 39 | Two: Point, | ||
| 40 | }; | ||
| 41 | const Bar = enum { | ||
| 42 | A, | ||
| 43 | B, | ||
| 44 | C, | ||
| 45 | D, | ||
| 46 | }; | ||
| 47 | |||
| 48 | fn returnAnInt(x: i32) Foo { | ||
| 49 | return Foo{ .One = x }; | ||
| 50 | } | ||
| 51 | |||
| 52 | test "constant enum with payload" { | ||
| 53 | var empty = AnEnumWithPayload{ .Empty = {} }; | ||
| 54 | var full = AnEnumWithPayload{ .Full = 13 }; | ||
| 55 | shouldBeEmpty(empty); | ||
| 56 | shouldBeNotEmpty(full); | ||
| 57 | } | ||
| 58 | |||
| 59 | fn shouldBeEmpty(x: AnEnumWithPayload) void { | ||
| 60 | switch (x) { | ||
| 61 | AnEnumWithPayload.Empty => {}, | ||
| 62 | else => unreachable, | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | fn shouldBeNotEmpty(x: AnEnumWithPayload) void { | ||
| 67 | switch (x) { | ||
| 68 | AnEnumWithPayload.Empty => unreachable, | ||
| 69 | else => {}, | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | const AnEnumWithPayload = union(enum) { | ||
| 74 | Empty: void, | ||
| 75 | Full: i32, | ||
| 76 | }; | ||
| 77 | |||
| 78 | const Number = enum { | ||
| 79 | Zero, | ||
| 80 | One, | ||
| 81 | Two, | ||
| 82 | Three, | ||
| 83 | Four, | ||
| 84 | }; | ||
| 85 | |||
| 86 | test "enum to int" { | ||
| 87 | shouldEqual(Number.Zero, 0); | ||
| 88 | shouldEqual(Number.One, 1); | ||
| 89 | shouldEqual(Number.Two, 2); | ||
| 90 | shouldEqual(Number.Three, 3); | ||
| 91 | shouldEqual(Number.Four, 4); | ||
| 92 | } | ||
| 93 | |||
| 94 | fn shouldEqual(n: Number, expected: u3) void { | ||
| 95 | assert(@enumToInt(n) == expected); | ||
| 96 | } | ||
| 97 | |||
| 98 | test "int to enum" { | ||
| 99 | testIntToEnumEval(3); | ||
| 100 | } | ||
| 101 | fn testIntToEnumEval(x: i32) void { | ||
| 102 | assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); | ||
| 103 | } | ||
| 104 | const IntToEnumNumber = enum { | ||
| 105 | Zero, | ||
| 106 | One, | ||
| 107 | Two, | ||
| 108 | Three, | ||
| 109 | Four, | ||
| 110 | }; | ||
| 111 | |||
| 112 | test "@tagName" { | ||
| 113 | assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 114 | comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 115 | } | ||
| 116 | |||
| 117 | fn testEnumTagNameBare(n: BareNumber) []const u8 { | ||
| 118 | return @tagName(n); | ||
| 119 | } | ||
| 120 | |||
| 121 | const BareNumber = enum { | ||
| 122 | One, | ||
| 123 | Two, | ||
| 124 | Three, | ||
| 125 | }; | ||
| 126 | |||
| 127 | test "enum alignment" { | ||
| 128 | comptime { | ||
| 129 | assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); | ||
| 130 | assert(@alignOf(AlignTestEnum) >= @alignOf(u64)); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | const AlignTestEnum = union(enum) { | ||
| 135 | A: [9]u8, | ||
| 136 | B: u64, | ||
| 137 | }; | ||
| 138 | |||
| 139 | const ValueCount1 = enum { | ||
| 140 | I0, | ||
| 141 | }; | ||
| 142 | const ValueCount2 = enum { | ||
| 143 | I0, | ||
| 144 | I1, | ||
| 145 | }; | ||
| 146 | const ValueCount256 = enum { | ||
| 147 | I0, | ||
| 148 | I1, | ||
| 149 | I2, | ||
| 150 | I3, | ||
| 151 | I4, | ||
| 152 | I5, | ||
| 153 | I6, | ||
| 154 | I7, | ||
| 155 | I8, | ||
| 156 | I9, | ||
| 157 | I10, | ||
| 158 | I11, | ||
| 159 | I12, | ||
| 160 | I13, | ||
| 161 | I14, | ||
| 162 | I15, | ||
| 163 | I16, | ||
| 164 | I17, | ||
| 165 | I18, | ||
| 166 | I19, | ||
| 167 | I20, | ||
| 168 | I21, | ||
| 169 | I22, | ||
| 170 | I23, | ||
| 171 | I24, | ||
| 172 | I25, | ||
| 173 | I26, | ||
| 174 | I27, | ||
| 175 | I28, | ||
| 176 | I29, | ||
| 177 | I30, | ||
| 178 | I31, | ||
| 179 | I32, | ||
| 180 | I33, | ||
| 181 | I34, | ||
| 182 | I35, | ||
| 183 | I36, | ||
| 184 | I37, | ||
| 185 | I38, | ||
| 186 | I39, | ||
| 187 | I40, | ||
| 188 | I41, | ||
| 189 | I42, | ||
| 190 | I43, | ||
| 191 | I44, | ||
| 192 | I45, | ||
| 193 | I46, | ||
| 194 | I47, | ||
| 195 | I48, | ||
| 196 | I49, | ||
| 197 | I50, | ||
| 198 | I51, | ||
| 199 | I52, | ||
| 200 | I53, | ||
| 201 | I54, | ||
| 202 | I55, | ||
| 203 | I56, | ||
| 204 | I57, | ||
| 205 | I58, | ||
| 206 | I59, | ||
| 207 | I60, | ||
| 208 | I61, | ||
| 209 | I62, | ||
| 210 | I63, | ||
| 211 | I64, | ||
| 212 | I65, | ||
| 213 | I66, | ||
| 214 | I67, | ||
| 215 | I68, | ||
| 216 | I69, | ||
| 217 | I70, | ||
| 218 | I71, | ||
| 219 | I72, | ||
| 220 | I73, | ||
| 221 | I74, | ||
| 222 | I75, | ||
| 223 | I76, | ||
| 224 | I77, | ||
| 225 | I78, | ||
| 226 | I79, | ||
| 227 | I80, | ||
| 228 | I81, | ||
| 229 | I82, | ||
| 230 | I83, | ||
| 231 | I84, | ||
| 232 | I85, | ||
| 233 | I86, | ||
| 234 | I87, | ||
| 235 | I88, | ||
| 236 | I89, | ||
| 237 | I90, | ||
| 238 | I91, | ||
| 239 | I92, | ||
| 240 | I93, | ||
| 241 | I94, | ||
| 242 | I95, | ||
| 243 | I96, | ||
| 244 | I97, | ||
| 245 | I98, | ||
| 246 | I99, | ||
| 247 | I100, | ||
| 248 | I101, | ||
| 249 | I102, | ||
| 250 | I103, | ||
| 251 | I104, | ||
| 252 | I105, | ||
| 253 | I106, | ||
| 254 | I107, | ||
| 255 | I108, | ||
| 256 | I109, | ||
| 257 | I110, | ||
| 258 | I111, | ||
| 259 | I112, | ||
| 260 | I113, | ||
| 261 | I114, | ||
| 262 | I115, | ||
| 263 | I116, | ||
| 264 | I117, | ||
| 265 | I118, | ||
| 266 | I119, | ||
| 267 | I120, | ||
| 268 | I121, | ||
| 269 | I122, | ||
| 270 | I123, | ||
| 271 | I124, | ||
| 272 | I125, | ||
| 273 | I126, | ||
| 274 | I127, | ||
| 275 | I128, | ||
| 276 | I129, | ||
| 277 | I130, | ||
| 278 | I131, | ||
| 279 | I132, | ||
| 280 | I133, | ||
| 281 | I134, | ||
| 282 | I135, | ||
| 283 | I136, | ||
| 284 | I137, | ||
| 285 | I138, | ||
| 286 | I139, | ||
| 287 | I140, | ||
| 288 | I141, | ||
| 289 | I142, | ||
| 290 | I143, | ||
| 291 | I144, | ||
| 292 | I145, | ||
| 293 | I146, | ||
| 294 | I147, | ||
| 295 | I148, | ||
| 296 | I149, | ||
| 297 | I150, | ||
| 298 | I151, | ||
| 299 | I152, | ||
| 300 | I153, | ||
| 301 | I154, | ||
| 302 | I155, | ||
| 303 | I156, | ||
| 304 | I157, | ||
| 305 | I158, | ||
| 306 | I159, | ||
| 307 | I160, | ||
| 308 | I161, | ||
| 309 | I162, | ||
| 310 | I163, | ||
| 311 | I164, | ||
| 312 | I165, | ||
| 313 | I166, | ||
| 314 | I167, | ||
| 315 | I168, | ||
| 316 | I169, | ||
| 317 | I170, | ||
| 318 | I171, | ||
| 319 | I172, | ||
| 320 | I173, | ||
| 321 | I174, | ||
| 322 | I175, | ||
| 323 | I176, | ||
| 324 | I177, | ||
| 325 | I178, | ||
| 326 | I179, | ||
| 327 | I180, | ||
| 328 | I181, | ||
| 329 | I182, | ||
| 330 | I183, | ||
| 331 | I184, | ||
| 332 | I185, | ||
| 333 | I186, | ||
| 334 | I187, | ||
| 335 | I188, | ||
| 336 | I189, | ||
| 337 | I190, | ||
| 338 | I191, | ||
| 339 | I192, | ||
| 340 | I193, | ||
| 341 | I194, | ||
| 342 | I195, | ||
| 343 | I196, | ||
| 344 | I197, | ||
| 345 | I198, | ||
| 346 | I199, | ||
| 347 | I200, | ||
| 348 | I201, | ||
| 349 | I202, | ||
| 350 | I203, | ||
| 351 | I204, | ||
| 352 | I205, | ||
| 353 | I206, | ||
| 354 | I207, | ||
| 355 | I208, | ||
| 356 | I209, | ||
| 357 | I210, | ||
| 358 | I211, | ||
| 359 | I212, | ||
| 360 | I213, | ||
| 361 | I214, | ||
| 362 | I215, | ||
| 363 | I216, | ||
| 364 | I217, | ||
| 365 | I218, | ||
| 366 | I219, | ||
| 367 | I220, | ||
| 368 | I221, | ||
| 369 | I222, | ||
| 370 | I223, | ||
| 371 | I224, | ||
| 372 | I225, | ||
| 373 | I226, | ||
| 374 | I227, | ||
| 375 | I228, | ||
| 376 | I229, | ||
| 377 | I230, | ||
| 378 | I231, | ||
| 379 | I232, | ||
| 380 | I233, | ||
| 381 | I234, | ||
| 382 | I235, | ||
| 383 | I236, | ||
| 384 | I237, | ||
| 385 | I238, | ||
| 386 | I239, | ||
| 387 | I240, | ||
| 388 | I241, | ||
| 389 | I242, | ||
| 390 | I243, | ||
| 391 | I244, | ||
| 392 | I245, | ||
| 393 | I246, | ||
| 394 | I247, | ||
| 395 | I248, | ||
| 396 | I249, | ||
| 397 | I250, | ||
| 398 | I251, | ||
| 399 | I252, | ||
| 400 | I253, | ||
| 401 | I254, | ||
| 402 | I255, | ||
| 403 | }; | ||
| 404 | const ValueCount257 = enum { | ||
| 405 | I0, | ||
| 406 | I1, | ||
| 407 | I2, | ||
| 408 | I3, | ||
| 409 | I4, | ||
| 410 | I5, | ||
| 411 | I6, | ||
| 412 | I7, | ||
| 413 | I8, | ||
| 414 | I9, | ||
| 415 | I10, | ||
| 416 | I11, | ||
| 417 | I12, | ||
| 418 | I13, | ||
| 419 | I14, | ||
| 420 | I15, | ||
| 421 | I16, | ||
| 422 | I17, | ||
| 423 | I18, | ||
| 424 | I19, | ||
| 425 | I20, | ||
| 426 | I21, | ||
| 427 | I22, | ||
| 428 | I23, | ||
| 429 | I24, | ||
| 430 | I25, | ||
| 431 | I26, | ||
| 432 | I27, | ||
| 433 | I28, | ||
| 434 | I29, | ||
| 435 | I30, | ||
| 436 | I31, | ||
| 437 | I32, | ||
| 438 | I33, | ||
| 439 | I34, | ||
| 440 | I35, | ||
| 441 | I36, | ||
| 442 | I37, | ||
| 443 | I38, | ||
| 444 | I39, | ||
| 445 | I40, | ||
| 446 | I41, | ||
| 447 | I42, | ||
| 448 | I43, | ||
| 449 | I44, | ||
| 450 | I45, | ||
| 451 | I46, | ||
| 452 | I47, | ||
| 453 | I48, | ||
| 454 | I49, | ||
| 455 | I50, | ||
| 456 | I51, | ||
| 457 | I52, | ||
| 458 | I53, | ||
| 459 | I54, | ||
| 460 | I55, | ||
| 461 | I56, | ||
| 462 | I57, | ||
| 463 | I58, | ||
| 464 | I59, | ||
| 465 | I60, | ||
| 466 | I61, | ||
| 467 | I62, | ||
| 468 | I63, | ||
| 469 | I64, | ||
| 470 | I65, | ||
| 471 | I66, | ||
| 472 | I67, | ||
| 473 | I68, | ||
| 474 | I69, | ||
| 475 | I70, | ||
| 476 | I71, | ||
| 477 | I72, | ||
| 478 | I73, | ||
| 479 | I74, | ||
| 480 | I75, | ||
| 481 | I76, | ||
| 482 | I77, | ||
| 483 | I78, | ||
| 484 | I79, | ||
| 485 | I80, | ||
| 486 | I81, | ||
| 487 | I82, | ||
| 488 | I83, | ||
| 489 | I84, | ||
| 490 | I85, | ||
| 491 | I86, | ||
| 492 | I87, | ||
| 493 | I88, | ||
| 494 | I89, | ||
| 495 | I90, | ||
| 496 | I91, | ||
| 497 | I92, | ||
| 498 | I93, | ||
| 499 | I94, | ||
| 500 | I95, | ||
| 501 | I96, | ||
| 502 | I97, | ||
| 503 | I98, | ||
| 504 | I99, | ||
| 505 | I100, | ||
| 506 | I101, | ||
| 507 | I102, | ||
| 508 | I103, | ||
| 509 | I104, | ||
| 510 | I105, | ||
| 511 | I106, | ||
| 512 | I107, | ||
| 513 | I108, | ||
| 514 | I109, | ||
| 515 | I110, | ||
| 516 | I111, | ||
| 517 | I112, | ||
| 518 | I113, | ||
| 519 | I114, | ||
| 520 | I115, | ||
| 521 | I116, | ||
| 522 | I117, | ||
| 523 | I118, | ||
| 524 | I119, | ||
| 525 | I120, | ||
| 526 | I121, | ||
| 527 | I122, | ||
| 528 | I123, | ||
| 529 | I124, | ||
| 530 | I125, | ||
| 531 | I126, | ||
| 532 | I127, | ||
| 533 | I128, | ||
| 534 | I129, | ||
| 535 | I130, | ||
| 536 | I131, | ||
| 537 | I132, | ||
| 538 | I133, | ||
| 539 | I134, | ||
| 540 | I135, | ||
| 541 | I136, | ||
| 542 | I137, | ||
| 543 | I138, | ||
| 544 | I139, | ||
| 545 | I140, | ||
| 546 | I141, | ||
| 547 | I142, | ||
| 548 | I143, | ||
| 549 | I144, | ||
| 550 | I145, | ||
| 551 | I146, | ||
| 552 | I147, | ||
| 553 | I148, | ||
| 554 | I149, | ||
| 555 | I150, | ||
| 556 | I151, | ||
| 557 | I152, | ||
| 558 | I153, | ||
| 559 | I154, | ||
| 560 | I155, | ||
| 561 | I156, | ||
| 562 | I157, | ||
| 563 | I158, | ||
| 564 | I159, | ||
| 565 | I160, | ||
| 566 | I161, | ||
| 567 | I162, | ||
| 568 | I163, | ||
| 569 | I164, | ||
| 570 | I165, | ||
| 571 | I166, | ||
| 572 | I167, | ||
| 573 | I168, | ||
| 574 | I169, | ||
| 575 | I170, | ||
| 576 | I171, | ||
| 577 | I172, | ||
| 578 | I173, | ||
| 579 | I174, | ||
| 580 | I175, | ||
| 581 | I176, | ||
| 582 | I177, | ||
| 583 | I178, | ||
| 584 | I179, | ||
| 585 | I180, | ||
| 586 | I181, | ||
| 587 | I182, | ||
| 588 | I183, | ||
| 589 | I184, | ||
| 590 | I185, | ||
| 591 | I186, | ||
| 592 | I187, | ||
| 593 | I188, | ||
| 594 | I189, | ||
| 595 | I190, | ||
| 596 | I191, | ||
| 597 | I192, | ||
| 598 | I193, | ||
| 599 | I194, | ||
| 600 | I195, | ||
| 601 | I196, | ||
| 602 | I197, | ||
| 603 | I198, | ||
| 604 | I199, | ||
| 605 | I200, | ||
| 606 | I201, | ||
| 607 | I202, | ||
| 608 | I203, | ||
| 609 | I204, | ||
| 610 | I205, | ||
| 611 | I206, | ||
| 612 | I207, | ||
| 613 | I208, | ||
| 614 | I209, | ||
| 615 | I210, | ||
| 616 | I211, | ||
| 617 | I212, | ||
| 618 | I213, | ||
| 619 | I214, | ||
| 620 | I215, | ||
| 621 | I216, | ||
| 622 | I217, | ||
| 623 | I218, | ||
| 624 | I219, | ||
| 625 | I220, | ||
| 626 | I221, | ||
| 627 | I222, | ||
| 628 | I223, | ||
| 629 | I224, | ||
| 630 | I225, | ||
| 631 | I226, | ||
| 632 | I227, | ||
| 633 | I228, | ||
| 634 | I229, | ||
| 635 | I230, | ||
| 636 | I231, | ||
| 637 | I232, | ||
| 638 | I233, | ||
| 639 | I234, | ||
| 640 | I235, | ||
| 641 | I236, | ||
| 642 | I237, | ||
| 643 | I238, | ||
| 644 | I239, | ||
| 645 | I240, | ||
| 646 | I241, | ||
| 647 | I242, | ||
| 648 | I243, | ||
| 649 | I244, | ||
| 650 | I245, | ||
| 651 | I246, | ||
| 652 | I247, | ||
| 653 | I248, | ||
| 654 | I249, | ||
| 655 | I250, | ||
| 656 | I251, | ||
| 657 | I252, | ||
| 658 | I253, | ||
| 659 | I254, | ||
| 660 | I255, | ||
| 661 | I256, | ||
| 662 | }; | ||
| 663 | |||
| 664 | test "enum sizes" { | ||
| 665 | comptime { | ||
| 666 | assert(@sizeOf(ValueCount1) == 0); | ||
| 667 | assert(@sizeOf(ValueCount2) == 1); | ||
| 668 | assert(@sizeOf(ValueCount256) == 1); | ||
| 669 | assert(@sizeOf(ValueCount257) == 2); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | const Small2 = enum(u2) { | ||
| 674 | One, | ||
| 675 | Two, | ||
| 676 | }; | ||
| 677 | const Small = enum(u2) { | ||
| 678 | One, | ||
| 679 | Two, | ||
| 680 | Three, | ||
| 681 | Four, | ||
| 682 | }; | ||
| 683 | |||
| 684 | test "set enum tag type" { | ||
| 685 | { | ||
| 686 | var x = Small.One; | ||
| 687 | x = Small.Two; | ||
| 688 | comptime assert(@TagType(Small) == u2); | ||
| 689 | } | ||
| 690 | { | ||
| 691 | var x = Small2.One; | ||
| 692 | x = Small2.Two; | ||
| 693 | comptime assert(@TagType(Small2) == u2); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | const A = enum(u3) { | ||
| 698 | One, | ||
| 699 | Two, | ||
| 700 | Three, | ||
| 701 | Four, | ||
| 702 | One2, | ||
| 703 | Two2, | ||
| 704 | Three2, | ||
| 705 | Four2, | ||
| 706 | }; | ||
| 707 | |||
| 708 | const B = enum(u3) { | ||
| 709 | One3, | ||
| 710 | Two3, | ||
| 711 | Three3, | ||
| 712 | Four3, | ||
| 713 | One23, | ||
| 714 | Two23, | ||
| 715 | Three23, | ||
| 716 | Four23, | ||
| 717 | }; | ||
| 718 | |||
| 719 | const C = enum(u2) { | ||
| 720 | One4, | ||
| 721 | Two4, | ||
| 722 | Three4, | ||
| 723 | Four4, | ||
| 724 | }; | ||
| 725 | |||
| 726 | const BitFieldOfEnums = packed struct { | ||
| 727 | a: A, | ||
| 728 | b: B, | ||
| 729 | c: C, | ||
| 730 | }; | ||
| 731 | |||
| 732 | const bit_field_1 = BitFieldOfEnums{ | ||
| 733 | .a = A.Two, | ||
| 734 | .b = B.Three3, | ||
| 735 | .c = C.Four4, | ||
| 736 | }; | ||
| 737 | |||
| 738 | test "bit field access with enum fields" { | ||
| 739 | var data = bit_field_1; | ||
| 740 | assert(getA(&data) == A.Two); | ||
| 741 | assert(getB(&data) == B.Three3); | ||
| 742 | assert(getC(&data) == C.Four4); | ||
| 743 | comptime assert(@sizeOf(BitFieldOfEnums) == 1); | ||
| 744 | |||
| 745 | data.b = B.Four3; | ||
| 746 | assert(data.b == B.Four3); | ||
| 747 | |||
| 748 | data.a = A.Three; | ||
| 749 | assert(data.a == A.Three); | ||
| 750 | assert(data.b == B.Four3); | ||
| 751 | } | ||
| 752 | |||
| 753 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 754 | return data.a; | ||
| 755 | } | ||
| 756 | |||
| 757 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 758 | return data.b; | ||
| 759 | } | ||
| 760 | |||
| 761 | fn getC(data: *const BitFieldOfEnums) C { | ||
| 762 | return data.c; | ||
| 763 | } | ||
| 764 | |||
| 765 | test "casting enum to its tag type" { | ||
| 766 | testCastEnumToTagType(Small2.Two); | ||
| 767 | comptime testCastEnumToTagType(Small2.Two); | ||
| 768 | } | ||
| 769 | |||
| 770 | fn testCastEnumToTagType(value: Small2) void { | ||
| 771 | assert(@enumToInt(value) == 1); | ||
| 772 | } | ||
| 773 | |||
| 774 | const MultipleChoice = enum(u32) { | ||
| 775 | A = 20, | ||
| 776 | B = 40, | ||
| 777 | C = 60, | ||
| 778 | D = 1000, | ||
| 779 | }; | ||
| 780 | |||
| 781 | test "enum with specified tag values" { | ||
| 782 | testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 783 | comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 784 | } | ||
| 785 | |||
| 786 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { | ||
| 787 | assert(@enumToInt(x) == 60); | ||
| 788 | assert(1234 == switch (x) { | ||
| 789 | MultipleChoice.A => 1, | ||
| 790 | MultipleChoice.B => 2, | ||
| 791 | MultipleChoice.C => u32(1234), | ||
| 792 | MultipleChoice.D => 4, | ||
| 793 | }); | ||
| 794 | } | ||
| 795 | |||
| 796 | const MultipleChoice2 = enum(u32) { | ||
| 797 | Unspecified1, | ||
| 798 | A = 20, | ||
| 799 | Unspecified2, | ||
| 800 | B = 40, | ||
| 801 | Unspecified3, | ||
| 802 | C = 60, | ||
| 803 | Unspecified4, | ||
| 804 | D = 1000, | ||
| 805 | Unspecified5, | ||
| 806 | }; | ||
| 807 | |||
| 808 | test "enum with specified and unspecified tag values" { | ||
| 809 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 810 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 811 | } | ||
| 812 | |||
| 813 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | ||
| 814 | assert(@enumToInt(x) == 1000); | ||
| 815 | assert(1234 == switch (x) { | ||
| 816 | MultipleChoice2.A => 1, | ||
| 817 | MultipleChoice2.B => 2, | ||
| 818 | MultipleChoice2.C => 3, | ||
| 819 | MultipleChoice2.D => u32(1234), | ||
| 820 | MultipleChoice2.Unspecified1 => 5, | ||
| 821 | MultipleChoice2.Unspecified2 => 6, | ||
| 822 | MultipleChoice2.Unspecified3 => 7, | ||
| 823 | MultipleChoice2.Unspecified4 => 8, | ||
| 824 | MultipleChoice2.Unspecified5 => 9, | ||
| 825 | }); | ||
| 826 | } | ||
| 827 | |||
| 828 | test "cast integer literal to enum" { | ||
| 829 | assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | ||
| 830 | assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | ||
| 831 | } | ||
| 832 | |||
| 833 | const EnumWithOneMember = enum { | ||
| 834 | Eof, | ||
| 835 | }; | ||
| 836 | |||
| 837 | fn doALoopThing(id: EnumWithOneMember) void { | ||
| 838 | while (true) { | ||
| 839 | if (id == EnumWithOneMember.Eof) { | ||
| 840 | break; | ||
| 841 | } | ||
| 842 | @compileError("above if condition should be comptime"); | ||
| 843 | } | ||
| 844 | } | ||
| 845 | |||
| 846 | test "comparison operator on enum with one member is comptime known" { | ||
| 847 | doALoopThing(EnumWithOneMember.Eof); | ||
| 848 | } | ||
| 849 | |||
| 850 | const State = enum { | ||
| 851 | Start, | ||
| 852 | }; | ||
| 853 | test "switch on enum with one member is comptime known" { | ||
| 854 | var state = State.Start; | ||
| 855 | switch (state) { | ||
| 856 | State.Start => return, | ||
| 857 | } | ||
| 858 | @compileError("analysis should not reach here"); | ||
| 859 | } | ||
| 860 | |||
| 861 | const EnumWithTagValues = enum(u4) { | ||
| 862 | A = 1 << 0, | ||
| 863 | B = 1 << 1, | ||
| 864 | C = 1 << 2, | ||
| 865 | D = 1 << 3, | ||
| 866 | }; | ||
| 867 | test "enum with tag values don't require parens" { | ||
| 868 | assert(@enumToInt(EnumWithTagValues.C) == 0b0100); | ||
| 869 | } | ||
| 870 | |||
| 871 | test "enum with 1 field but explicit tag type should still have the tag type" { | ||
| 872 | const Enum = enum(u8) { | ||
| 873 | B = 2, | ||
| 874 | }; | ||
| 875 | comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8)); | ||
| 876 | } | ||
| 877 | |||
| 878 | test "empty extern enum with members" { | ||
| 879 | const E = extern enum { | ||
| 880 | A, | ||
| 881 | B, | ||
| 882 | C, | ||
| 883 | }; | ||
| 884 | assert(@sizeOf(E) == @sizeOf(c_int)); | ||
| 885 | } | ||
| 886 | |||
| 887 | test "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/enum_with_members.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const fmt = @import("std").fmt; | ||
| 4 | |||
| 5 | const ET = union(enum) { | ||
| 6 | SINT: i32, | ||
| 7 | UINT: u32, | ||
| 8 | |||
| 9 | pub fn print(a: *const ET, buf: []u8) anyerror!usize { | ||
| 10 | return switch (a.*) { | ||
| 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | ||
| 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | |||
| 17 | test "enum with members" { | ||
| 18 | const a = ET{ .SINT = -42 }; | ||
| 19 | const b = ET{ .UINT = 42 }; | ||
| 20 | var buf: [20]u8 = undefined; | ||
| 21 | |||
| 22 | assert((a.print(buf[0..]) catch unreachable) == 3); | ||
| 23 | assert(mem.eql(u8, buf[0..3], "-42")); | ||
| 24 | |||
| 25 | assert((b.print(buf[0..]) catch unreachable) == 2); | ||
| 26 | assert(mem.eql(u8, buf[0..2], "42")); | ||
| 27 | } | ||
test/cases/error.zig deleted-245| ... | @@ -1,245 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | ||
| 4 | const builtin = @import("builtin"); | ||
| 5 | |||
| 6 | pub fn foo() anyerror!i32 { | ||
| 7 | const x = try bar(); | ||
| 8 | return x + 1; | ||
| 9 | } | ||
| 10 | |||
| 11 | pub fn bar() anyerror!i32 { | ||
| 12 | return 13; | ||
| 13 | } | ||
| 14 | |||
| 15 | pub fn baz() anyerror!i32 { | ||
| 16 | const y = foo() catch 1234; | ||
| 17 | return y + 1; | ||
| 18 | } | ||
| 19 | |||
| 20 | test "error wrapping" { | ||
| 21 | assert((baz() catch unreachable) == 15); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn gimmeItBroke() []const u8 { | ||
| 25 | return @errorName(error.ItBroke); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "@errorName" { | ||
| 29 | assert(mem.eql(u8, @errorName(error.AnError), "AnError")); | ||
| 30 | assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "error values" { | ||
| 34 | const a = @errorToInt(error.err1); | ||
| 35 | const b = @errorToInt(error.err2); | ||
| 36 | assert(a != b); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "redefinition of error values allowed" { | ||
| 40 | shouldBeNotEqual(error.AnError, error.SecondError); | ||
| 41 | } | ||
| 42 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { | ||
| 43 | if (a == b) unreachable; | ||
| 44 | } | ||
| 45 | |||
| 46 | test "error binary operator" { | ||
| 47 | const a = errBinaryOperatorG(true) catch 3; | ||
| 48 | const b = errBinaryOperatorG(false) catch 3; | ||
| 49 | assert(a == 3); | ||
| 50 | assert(b == 10); | ||
| 51 | } | ||
| 52 | fn errBinaryOperatorG(x: bool) anyerror!isize { | ||
| 53 | return if (x) error.ItBroke else isize(10); | ||
| 54 | } | ||
| 55 | |||
| 56 | test "unwrap simple value from error" { | ||
| 57 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; | ||
| 58 | assert(i == 13); | ||
| 59 | } | ||
| 60 | fn unwrapSimpleValueFromErrorDo() anyerror!isize { | ||
| 61 | return 13; | ||
| 62 | } | ||
| 63 | |||
| 64 | test "error return in assignment" { | ||
| 65 | doErrReturnInAssignment() catch unreachable; | ||
| 66 | } | ||
| 67 | |||
| 68 | fn doErrReturnInAssignment() anyerror!void { | ||
| 69 | var x: i32 = undefined; | ||
| 70 | x = try makeANonErr(); | ||
| 71 | } | ||
| 72 | |||
| 73 | fn makeANonErr() anyerror!i32 { | ||
| 74 | return 1; | ||
| 75 | } | ||
| 76 | |||
| 77 | test "error union type " { | ||
| 78 | testErrorUnionType(); | ||
| 79 | comptime testErrorUnionType(); | ||
| 80 | } | ||
| 81 | |||
| 82 | fn testErrorUnionType() void { | ||
| 83 | const x: anyerror!i32 = 1234; | ||
| 84 | if (x) |value| assert(value == 1234) else |_| unreachable; | ||
| 85 | assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); | ||
| 86 | assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); | ||
| 87 | assert(@typeOf(x).ErrorSet == anyerror); | ||
| 88 | } | ||
| 89 | |||
| 90 | test "error set type " { | ||
| 91 | testErrorSetType(); | ||
| 92 | comptime testErrorSetType(); | ||
| 93 | } | ||
| 94 | |||
| 95 | const MyErrSet = error{ | ||
| 96 | OutOfMemory, | ||
| 97 | FileNotFound, | ||
| 98 | }; | ||
| 99 | |||
| 100 | fn testErrorSetType() void { | ||
| 101 | assert(@memberCount(MyErrSet) == 2); | ||
| 102 | |||
| 103 | const a: MyErrSet!i32 = 5678; | ||
| 104 | const b: MyErrSet!i32 = MyErrSet.OutOfMemory; | ||
| 105 | |||
| 106 | if (a) |value| assert(value == 5678) else |err| switch (err) { | ||
| 107 | error.OutOfMemory => unreachable, | ||
| 108 | error.FileNotFound => unreachable, | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | test "explicit error set cast" { | ||
| 113 | testExplicitErrorSetCast(Set1.A); | ||
| 114 | comptime testExplicitErrorSetCast(Set1.A); | ||
| 115 | } | ||
| 116 | |||
| 117 | const Set1 = error{ | ||
| 118 | A, | ||
| 119 | B, | ||
| 120 | }; | ||
| 121 | const Set2 = error{ | ||
| 122 | A, | ||
| 123 | C, | ||
| 124 | }; | ||
| 125 | |||
| 126 | fn testExplicitErrorSetCast(set1: Set1) void { | ||
| 127 | var x = @errSetCast(Set2, set1); | ||
| 128 | var y = @errSetCast(Set1, x); | ||
| 129 | assert(y == error.A); | ||
| 130 | } | ||
| 131 | |||
| 132 | test "comptime test error for empty error set" { | ||
| 133 | testComptimeTestErrorEmptySet(1234); | ||
| 134 | comptime testComptimeTestErrorEmptySet(1234); | ||
| 135 | } | ||
| 136 | |||
| 137 | const EmptyErrorSet = error{}; | ||
| 138 | |||
| 139 | fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { | ||
| 140 | if (x) |v| assert(v == 1234) else |err| @compileError("bad"); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "syntax: optional operator in front of error union operator" { | ||
| 144 | comptime { | ||
| 145 | assert(?(anyerror!i32) == ?(anyerror!i32)); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | test "comptime err to int of error set with only 1 possible value" { | ||
| 150 | testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 151 | comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 152 | } | ||
| 153 | fn testErrToIntWithOnePossibleValue( | ||
| 154 | x: error{A}, | ||
| 155 | comptime value: u32, | ||
| 156 | ) void { | ||
| 157 | if (@errorToInt(x) != value) { | ||
| 158 | @compileError("bad"); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | test "error union peer type resolution" { | ||
| 163 | testErrorUnionPeerTypeResolution(1); | ||
| 164 | comptime testErrorUnionPeerTypeResolution(1); | ||
| 165 | } | ||
| 166 | |||
| 167 | fn testErrorUnionPeerTypeResolution(x: i32) void { | ||
| 168 | const y = switch (x) { | ||
| 169 | 1 => bar_1(), | ||
| 170 | 2 => baz_1(), | ||
| 171 | else => quux_1(), | ||
| 172 | }; | ||
| 173 | } | ||
| 174 | |||
| 175 | fn bar_1() anyerror { | ||
| 176 | return error.A; | ||
| 177 | } | ||
| 178 | |||
| 179 | fn baz_1() !i32 { | ||
| 180 | return error.B; | ||
| 181 | } | ||
| 182 | |||
| 183 | fn quux_1() !i32 { | ||
| 184 | return error.C; | ||
| 185 | } | ||
| 186 | |||
| 187 | test "error: fn returning empty error set can be passed as fn returning any error" { | ||
| 188 | entry(); | ||
| 189 | comptime entry(); | ||
| 190 | } | ||
| 191 | |||
| 192 | fn entry() void { | ||
| 193 | foo2(bar2); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn foo2(f: fn () anyerror!void) void { | ||
| 197 | const x = f(); | ||
| 198 | } | ||
| 199 | |||
| 200 | fn bar2() (error{}!void) {} | ||
| 201 | |||
| 202 | test "error: Zero sized error set returned with value payload crash" { | ||
| 203 | _ = foo3(0); | ||
| 204 | _ = comptime foo3(0); | ||
| 205 | } | ||
| 206 | |||
| 207 | const Error = error{}; | ||
| 208 | fn foo3(b: usize) Error!usize { | ||
| 209 | return b; | ||
| 210 | } | ||
| 211 | |||
| 212 | test "error: Infer error set from literals" { | ||
| 213 | _ = nullLiteral("n") catch |err| handleErrors(err); | ||
| 214 | _ = floatLiteral("n") catch |err| handleErrors(err); | ||
| 215 | _ = intLiteral("n") catch |err| handleErrors(err); | ||
| 216 | _ = comptime nullLiteral("n") catch |err| handleErrors(err); | ||
| 217 | _ = comptime floatLiteral("n") catch |err| handleErrors(err); | ||
| 218 | _ = comptime intLiteral("n") catch |err| handleErrors(err); | ||
| 219 | } | ||
| 220 | |||
| 221 | fn handleErrors(err: var) noreturn { | ||
| 222 | switch (err) { | ||
| 223 | error.T => {}, | ||
| 224 | } | ||
| 225 | |||
| 226 | unreachable; | ||
| 227 | } | ||
| 228 | |||
| 229 | fn nullLiteral(str: []const u8) !?i64 { | ||
| 230 | if (str[0] == 'n') return null; | ||
| 231 | |||
| 232 | return error.T; | ||
| 233 | } | ||
| 234 | |||
| 235 | fn floatLiteral(str: []const u8) !?f64 { | ||
| 236 | if (str[0] == 'n') return 1.0; | ||
| 237 | |||
| 238 | return error.T; | ||
| 239 | } | ||
| 240 | |||
| 241 | fn intLiteral(str: []const u8) !?i64 { | ||
| 242 | if (str[0] == 'n') return 1; | ||
| 243 | |||
| 244 | return error.T; | ||
| 245 | } | ||
test/cases/eval.zig deleted-782| ... | @@ -1,782 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | |||
| 5 | test "compile time recursion" { | ||
| 6 | assert(some_data.len == 21); | ||
| 7 | } | ||
| 8 | var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; | ||
| 9 | fn fibonacci(x: i32) i32 { | ||
| 10 | if (x <= 1) return 1; | ||
| 11 | return fibonacci(x - 1) + fibonacci(x - 2); | ||
| 12 | } | ||
| 13 | |||
| 14 | fn unwrapAndAddOne(blah: ?i32) i32 { | ||
| 15 | return blah.? + 1; | ||
| 16 | } | ||
| 17 | const should_be_1235 = unwrapAndAddOne(1234); | ||
| 18 | test "static add one" { | ||
| 19 | assert(should_be_1235 == 1235); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "inlined loop" { | ||
| 23 | comptime var i = 0; | ||
| 24 | comptime var sum = 0; | ||
| 25 | inline while (i <= 5) : (i += 1) | ||
| 26 | sum += i; | ||
| 27 | assert(sum == 15); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn gimme1or2(comptime a: bool) i32 { | ||
| 31 | const x: i32 = 1; | ||
| 32 | const y: i32 = 2; | ||
| 33 | comptime var z: i32 = if (a) x else y; | ||
| 34 | return z; | ||
| 35 | } | ||
| 36 | test "inline variable gets result of const if" { | ||
| 37 | assert(gimme1or2(true) == 1); | ||
| 38 | assert(gimme1or2(false) == 2); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "static function evaluation" { | ||
| 42 | assert(statically_added_number == 3); | ||
| 43 | } | ||
| 44 | const statically_added_number = staticAdd(1, 2); | ||
| 45 | fn staticAdd(a: i32, b: i32) i32 { | ||
| 46 | return a + b; | ||
| 47 | } | ||
| 48 | |||
| 49 | test "const expr eval on single expr blocks" { | ||
| 50 | assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 51 | } | ||
| 52 | |||
| 53 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { | ||
| 54 | const literal = 3; | ||
| 55 | |||
| 56 | const result = if (b) b: { | ||
| 57 | break :b literal; | ||
| 58 | } else b: { | ||
| 59 | break :b x; | ||
| 60 | }; | ||
| 61 | |||
| 62 | return result; | ||
| 63 | } | ||
| 64 | |||
| 65 | test "statically initialized list" { | ||
| 66 | assert(static_point_list[0].x == 1); | ||
| 67 | assert(static_point_list[0].y == 2); | ||
| 68 | assert(static_point_list[1].x == 3); | ||
| 69 | assert(static_point_list[1].y == 4); | ||
| 70 | } | ||
| 71 | const Point = struct { | ||
| 72 | x: i32, | ||
| 73 | y: i32, | ||
| 74 | }; | ||
| 75 | const static_point_list = []Point{ | ||
| 76 | makePoint(1, 2), | ||
| 77 | makePoint(3, 4), | ||
| 78 | }; | ||
| 79 | fn makePoint(x: i32, y: i32) Point { | ||
| 80 | return Point{ | ||
| 81 | .x = x, | ||
| 82 | .y = y, | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 86 | test "static eval list init" { | ||
| 87 | assert(static_vec3.data[2] == 1.0); | ||
| 88 | assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | ||
| 89 | } | ||
| 90 | const static_vec3 = vec3(0.0, 0.0, 1.0); | ||
| 91 | pub const Vec3 = struct { | ||
| 92 | data: [3]f32, | ||
| 93 | }; | ||
| 94 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | ||
| 95 | return Vec3{ .data = []f32{ | ||
| 96 | x, | ||
| 97 | y, | ||
| 98 | z, | ||
| 99 | } }; | ||
| 100 | } | ||
| 101 | |||
| 102 | test "constant expressions" { | ||
| 103 | var array: [array_size]u8 = undefined; | ||
| 104 | assert(@sizeOf(@typeOf(array)) == 20); | ||
| 105 | } | ||
| 106 | const array_size: u8 = 20; | ||
| 107 | |||
| 108 | test "constant struct with negation" { | ||
| 109 | assert(vertices[0].x == -0.6); | ||
| 110 | } | ||
| 111 | const Vertex = struct { | ||
| 112 | x: f32, | ||
| 113 | y: f32, | ||
| 114 | r: f32, | ||
| 115 | g: f32, | ||
| 116 | b: f32, | ||
| 117 | }; | ||
| 118 | const vertices = []Vertex{ | ||
| 119 | Vertex{ | ||
| 120 | .x = -0.6, | ||
| 121 | .y = -0.4, | ||
| 122 | .r = 1.0, | ||
| 123 | .g = 0.0, | ||
| 124 | .b = 0.0, | ||
| 125 | }, | ||
| 126 | Vertex{ | ||
| 127 | .x = 0.6, | ||
| 128 | .y = -0.4, | ||
| 129 | .r = 0.0, | ||
| 130 | .g = 1.0, | ||
| 131 | .b = 0.0, | ||
| 132 | }, | ||
| 133 | Vertex{ | ||
| 134 | .x = 0.0, | ||
| 135 | .y = 0.6, | ||
| 136 | .r = 0.0, | ||
| 137 | .g = 0.0, | ||
| 138 | .b = 1.0, | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | test "statically initialized struct" { | ||
| 143 | st_init_str_foo.x += 1; | ||
| 144 | assert(st_init_str_foo.x == 14); | ||
| 145 | } | ||
| 146 | const StInitStrFoo = struct { | ||
| 147 | x: i32, | ||
| 148 | y: bool, | ||
| 149 | }; | ||
| 150 | var st_init_str_foo = StInitStrFoo{ | ||
| 151 | .x = 13, | ||
| 152 | .y = true, | ||
| 153 | }; | ||
| 154 | |||
| 155 | test "statically initalized array literal" { | ||
| 156 | const y: [4]u8 = st_init_arr_lit_x; | ||
| 157 | assert(y[3] == 4); | ||
| 158 | } | ||
| 159 | const st_init_arr_lit_x = []u8{ | ||
| 160 | 1, | ||
| 161 | 2, | ||
| 162 | 3, | ||
| 163 | 4, | ||
| 164 | }; | ||
| 165 | |||
| 166 | test "const slice" { | ||
| 167 | comptime { | ||
| 168 | const a = "1234567890"; | ||
| 169 | assert(a.len == 10); | ||
| 170 | const b = a[1..2]; | ||
| 171 | assert(b.len == 1); | ||
| 172 | assert(b[0] == '2'); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | test "try to trick eval with runtime if" { | ||
| 177 | assert(testTryToTrickEvalWithRuntimeIf(true) == 10); | ||
| 178 | } | ||
| 179 | |||
| 180 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | ||
| 181 | comptime var i: usize = 0; | ||
| 182 | inline while (i < 10) : (i += 1) { | ||
| 183 | const result = if (b) false else true; | ||
| 184 | } | ||
| 185 | comptime { | ||
| 186 | return i; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | fn max(comptime T: type, a: T, b: T) T { | ||
| 191 | if (T == bool) { | ||
| 192 | return a or b; | ||
| 193 | } else if (a > b) { | ||
| 194 | return a; | ||
| 195 | } else { | ||
| 196 | return b; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | fn letsTryToCompareBools(a: bool, b: bool) bool { | ||
| 200 | return max(bool, a, b); | ||
| 201 | } | ||
| 202 | test "inlined block and runtime block phi" { | ||
| 203 | assert(letsTryToCompareBools(true, true)); | ||
| 204 | assert(letsTryToCompareBools(true, false)); | ||
| 205 | assert(letsTryToCompareBools(false, true)); | ||
| 206 | assert(!letsTryToCompareBools(false, false)); | ||
| 207 | |||
| 208 | comptime { | ||
| 209 | assert(letsTryToCompareBools(true, true)); | ||
| 210 | assert(letsTryToCompareBools(true, false)); | ||
| 211 | assert(letsTryToCompareBools(false, true)); | ||
| 212 | assert(!letsTryToCompareBools(false, false)); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | const CmdFn = struct { | ||
| 217 | name: []const u8, | ||
| 218 | func: fn (i32) i32, | ||
| 219 | }; | ||
| 220 | |||
| 221 | const cmd_fns = []CmdFn{ | ||
| 222 | CmdFn{ | ||
| 223 | .name = "one", | ||
| 224 | .func = one, | ||
| 225 | }, | ||
| 226 | CmdFn{ | ||
| 227 | .name = "two", | ||
| 228 | .func = two, | ||
| 229 | }, | ||
| 230 | CmdFn{ | ||
| 231 | .name = "three", | ||
| 232 | .func = three, | ||
| 233 | }, | ||
| 234 | }; | ||
| 235 | fn one(value: i32) i32 { | ||
| 236 | return value + 1; | ||
| 237 | } | ||
| 238 | fn two(value: i32) i32 { | ||
| 239 | return value + 2; | ||
| 240 | } | ||
| 241 | fn three(value: i32) i32 { | ||
| 242 | return value + 3; | ||
| 243 | } | ||
| 244 | |||
| 245 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | ||
| 246 | var result: i32 = start_value; | ||
| 247 | comptime var i = 0; | ||
| 248 | inline while (i < cmd_fns.len) : (i += 1) { | ||
| 249 | if (cmd_fns[i].name[0] == prefix_char) { | ||
| 250 | result = cmd_fns[i].func(result); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return result; | ||
| 254 | } | ||
| 255 | |||
| 256 | test "comptime iterate over fn ptr list" { | ||
| 257 | assert(performFn('t', 1) == 6); | ||
| 258 | assert(performFn('o', 0) == 1); | ||
| 259 | assert(performFn('w', 99) == 99); | ||
| 260 | } | ||
| 261 | |||
| 262 | test "eval @setRuntimeSafety at compile-time" { | ||
| 263 | const result = comptime fnWithSetRuntimeSafety(); | ||
| 264 | assert(result == 1234); | ||
| 265 | } | ||
| 266 | |||
| 267 | fn fnWithSetRuntimeSafety() i32 { | ||
| 268 | @setRuntimeSafety(true); | ||
| 269 | return 1234; | ||
| 270 | } | ||
| 271 | |||
| 272 | test "eval @setFloatMode at compile-time" { | ||
| 273 | const result = comptime fnWithFloatMode(); | ||
| 274 | assert(result == 1234.0); | ||
| 275 | } | ||
| 276 | |||
| 277 | fn fnWithFloatMode() f32 { | ||
| 278 | @setFloatMode(builtin.FloatMode.Strict); | ||
| 279 | return 1234.0; | ||
| 280 | } | ||
| 281 | |||
| 282 | const SimpleStruct = struct { | ||
| 283 | field: i32, | ||
| 284 | |||
| 285 | fn method(self: *const SimpleStruct) i32 { | ||
| 286 | return self.field + 3; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | |||
| 290 | var simple_struct = SimpleStruct{ .field = 1234 }; | ||
| 291 | |||
| 292 | const bound_fn = simple_struct.method; | ||
| 293 | |||
| 294 | test "call method on bound fn referring to var instance" { | ||
| 295 | assert(bound_fn() == 1237); | ||
| 296 | } | ||
| 297 | |||
| 298 | test "ptr to local array argument at comptime" { | ||
| 299 | comptime { | ||
| 300 | var bytes: [10]u8 = undefined; | ||
| 301 | modifySomeBytes(bytes[0..]); | ||
| 302 | assert(bytes[0] == 'a'); | ||
| 303 | assert(bytes[9] == 'b'); | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | fn modifySomeBytes(bytes: []u8) void { | ||
| 308 | bytes[0] = 'a'; | ||
| 309 | bytes[9] = 'b'; | ||
| 310 | } | ||
| 311 | |||
| 312 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | ||
| 313 | testCompTimeUIntComparisons(1234); | ||
| 314 | } | ||
| 315 | fn testCompTimeUIntComparisons(x: u32) void { | ||
| 316 | if (!(0 <= x)) { | ||
| 317 | @compileError("this condition should be comptime known"); | ||
| 318 | } | ||
| 319 | if (0 > x) { | ||
| 320 | @compileError("this condition should be comptime known"); | ||
| 321 | } | ||
| 322 | if (!(x >= 0)) { | ||
| 323 | @compileError("this condition should be comptime known"); | ||
| 324 | } | ||
| 325 | if (x < 0) { | ||
| 326 | @compileError("this condition should be comptime known"); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | test "const ptr to variable data changes at runtime" { | ||
| 331 | assert(foo_ref.name[0] == 'a'); | ||
| 332 | foo_ref.name = "b"; | ||
| 333 | assert(foo_ref.name[0] == 'b'); | ||
| 334 | } | ||
| 335 | |||
| 336 | const Foo = struct { | ||
| 337 | name: []const u8, | ||
| 338 | }; | ||
| 339 | |||
| 340 | var foo_contents = Foo{ .name = "a" }; | ||
| 341 | const foo_ref = &foo_contents; | ||
| 342 | |||
| 343 | test "create global array with for loop" { | ||
| 344 | assert(global_array[5] == 5 * 5); | ||
| 345 | assert(global_array[9] == 9 * 9); | ||
| 346 | } | ||
| 347 | |||
| 348 | const global_array = x: { | ||
| 349 | var result: [10]usize = undefined; | ||
| 350 | for (result) |*item, index| { | ||
| 351 | item.* = index * index; | ||
| 352 | } | ||
| 353 | break :x result; | ||
| 354 | }; | ||
| 355 | |||
| 356 | test "compile-time downcast when the bits fit" { | ||
| 357 | comptime { | ||
| 358 | const spartan_count: u16 = 255; | ||
| 359 | const byte = @intCast(u8, spartan_count); | ||
| 360 | assert(byte == 255); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | const hi1 = "hi"; | ||
| 365 | const hi2 = hi1; | ||
| 366 | test "const global shares pointer with other same one" { | ||
| 367 | assertEqualPtrs(&hi1[0], &hi2[0]); | ||
| 368 | comptime assert(&hi1[0] == &hi2[0]); | ||
| 369 | } | ||
| 370 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { | ||
| 371 | assert(ptr1 == ptr2); | ||
| 372 | } | ||
| 373 | |||
| 374 | test "@setEvalBranchQuota" { | ||
| 375 | comptime { | ||
| 376 | // 1001 for the loop and then 1 more for the assert fn call | ||
| 377 | @setEvalBranchQuota(1002); | ||
| 378 | var i = 0; | ||
| 379 | var sum = 0; | ||
| 380 | while (i < 1001) : (i += 1) { | ||
| 381 | sum += i; | ||
| 382 | } | ||
| 383 | assert(sum == 500500); | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | // TODO test "float literal at compile time not lossy" { | ||
| 388 | // TODO assert(16777216.0 + 1.0 == 16777217.0); | ||
| 389 | // TODO assert(9007199254740992.0 + 1.0 == 9007199254740993.0); | ||
| 390 | // TODO } | ||
| 391 | |||
| 392 | test "f32 at compile time is lossy" { | ||
| 393 | assert(f32(1 << 24) + 1 == 1 << 24); | ||
| 394 | } | ||
| 395 | |||
| 396 | test "f64 at compile time is lossy" { | ||
| 397 | assert(f64(1 << 53) + 1 == 1 << 53); | ||
| 398 | } | ||
| 399 | |||
| 400 | test "f128 at compile time is lossy" { | ||
| 401 | assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | ||
| 402 | } | ||
| 403 | |||
| 404 | // TODO need a better implementation of bigfloat_init_bigint | ||
| 405 | // assert(f128(1 << 113) == 10384593717069655257060992658440192); | ||
| 406 | |||
| 407 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | ||
| 408 | return struct { | ||
| 409 | pub const Node = struct {}; | ||
| 410 | }; | ||
| 411 | } | ||
| 412 | |||
| 413 | test "string literal used as comptime slice is memoized" { | ||
| 414 | const a = "link"; | ||
| 415 | const b = "link"; | ||
| 416 | comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | ||
| 417 | comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | ||
| 418 | } | ||
| 419 | |||
| 420 | test "comptime slice of undefined pointer of length 0" { | ||
| 421 | const slice1 = ([*]i32)(undefined)[0..0]; | ||
| 422 | assert(slice1.len == 0); | ||
| 423 | const slice2 = ([*]i32)(undefined)[100..100]; | ||
| 424 | assert(slice2.len == 0); | ||
| 425 | } | ||
| 426 | |||
| 427 | fn copyWithPartialInline(s: []u32, b: []u8) void { | ||
| 428 | comptime var i: usize = 0; | ||
| 429 | inline while (i < 4) : (i += 1) { | ||
| 430 | s[i] = 0; | ||
| 431 | s[i] |= u32(b[i * 4 + 0]) << 24; | ||
| 432 | s[i] |= u32(b[i * 4 + 1]) << 16; | ||
| 433 | s[i] |= u32(b[i * 4 + 2]) << 8; | ||
| 434 | s[i] |= u32(b[i * 4 + 3]) << 0; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | test "binary math operator in partially inlined function" { | ||
| 439 | var s: [4]u32 = undefined; | ||
| 440 | var b: [16]u8 = undefined; | ||
| 441 | |||
| 442 | for (b) |*r, i| | ||
| 443 | r.* = @intCast(u8, i + 1); | ||
| 444 | |||
| 445 | copyWithPartialInline(s[0..], b[0..]); | ||
| 446 | assert(s[0] == 0x1020304); | ||
| 447 | assert(s[1] == 0x5060708); | ||
| 448 | assert(s[2] == 0x90a0b0c); | ||
| 449 | assert(s[3] == 0xd0e0f10); | ||
| 450 | } | ||
| 451 | |||
| 452 | test "comptime function with the same args is memoized" { | ||
| 453 | comptime { | ||
| 454 | assert(MakeType(i32) == MakeType(i32)); | ||
| 455 | assert(MakeType(i32) != MakeType(f64)); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | fn MakeType(comptime T: type) type { | ||
| 460 | return struct { | ||
| 461 | field: T, | ||
| 462 | }; | ||
| 463 | } | ||
| 464 | |||
| 465 | test "comptime function with mutable pointer is not memoized" { | ||
| 466 | comptime { | ||
| 467 | var x: i32 = 1; | ||
| 468 | const ptr = &x; | ||
| 469 | increment(ptr); | ||
| 470 | increment(ptr); | ||
| 471 | assert(x == 3); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | fn increment(value: *i32) void { | ||
| 476 | value.* += 1; | ||
| 477 | } | ||
| 478 | |||
| 479 | fn generateTable(comptime T: type) [1010]T { | ||
| 480 | var res: [1010]T = undefined; | ||
| 481 | var i: usize = 0; | ||
| 482 | while (i < 1010) : (i += 1) { | ||
| 483 | res[i] = @intCast(T, i); | ||
| 484 | } | ||
| 485 | return res; | ||
| 486 | } | ||
| 487 | |||
| 488 | fn doesAlotT(comptime T: type, value: usize) T { | ||
| 489 | @setEvalBranchQuota(5000); | ||
| 490 | const table = comptime blk: { | ||
| 491 | break :blk generateTable(T); | ||
| 492 | }; | ||
| 493 | return table[value]; | ||
| 494 | } | ||
| 495 | |||
| 496 | test "@setEvalBranchQuota at same scope as generic function call" { | ||
| 497 | assert(doesAlotT(u32, 2) == 2); | ||
| 498 | } | ||
| 499 | |||
| 500 | test "comptime slice of slice preserves comptime var" { | ||
| 501 | comptime { | ||
| 502 | var buff: [10]u8 = undefined; | ||
| 503 | buff[0..][0..][0] = 1; | ||
| 504 | assert(buff[0..][0..][0] == 1); | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | test "comptime slice of pointer preserves comptime var" { | ||
| 509 | comptime { | ||
| 510 | var buff: [10]u8 = undefined; | ||
| 511 | var a = buff[0..].ptr; | ||
| 512 | a[0..1][0] = 1; | ||
| 513 | assert(buff[0..][0..][0] == 1); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | const SingleFieldStruct = struct { | ||
| 518 | x: i32, | ||
| 519 | |||
| 520 | fn read_x(self: *const SingleFieldStruct) i32 { | ||
| 521 | return self.x; | ||
| 522 | } | ||
| 523 | }; | ||
| 524 | test "const ptr to comptime mutable data is not memoized" { | ||
| 525 | comptime { | ||
| 526 | var foo = SingleFieldStruct{ .x = 1 }; | ||
| 527 | assert(foo.read_x() == 1); | ||
| 528 | foo.x = 2; | ||
| 529 | assert(foo.read_x() == 2); | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | test "array concat of slices gives slice" { | ||
| 534 | comptime { | ||
| 535 | var a: []const u8 = "aoeu"; | ||
| 536 | var b: []const u8 = "asdf"; | ||
| 537 | const c = a ++ b; | ||
| 538 | assert(std.mem.eql(u8, c, "aoeuasdf")); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | test "comptime shlWithOverflow" { | ||
| 543 | const ct_shifted: u64 = comptime amt: { | ||
| 544 | var amt = u64(0); | ||
| 545 | _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); | ||
| 546 | break :amt amt; | ||
| 547 | }; | ||
| 548 | |||
| 549 | const rt_shifted: u64 = amt: { | ||
| 550 | var amt = u64(0); | ||
| 551 | _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); | ||
| 552 | break :amt amt; | ||
| 553 | }; | ||
| 554 | |||
| 555 | assert(ct_shifted == rt_shifted); | ||
| 556 | } | ||
| 557 | |||
| 558 | test "runtime 128 bit integer division" { | ||
| 559 | var a: u128 = 152313999999999991610955792383; | ||
| 560 | var b: u128 = 10000000000000000000; | ||
| 561 | var c = a / b; | ||
| 562 | assert(c == 15231399999); | ||
| 563 | } | ||
| 564 | |||
| 565 | pub const Info = struct { | ||
| 566 | version: u8, | ||
| 567 | }; | ||
| 568 | |||
| 569 | pub const diamond_info = Info{ .version = 0 }; | ||
| 570 | |||
| 571 | test "comptime modification of const struct field" { | ||
| 572 | comptime { | ||
| 573 | var res = diamond_info; | ||
| 574 | res.version = 1; | ||
| 575 | assert(diamond_info.version == 0); | ||
| 576 | assert(res.version == 1); | ||
| 577 | } | ||
| 578 | } | ||
| 579 | |||
| 580 | test "pointer to type" { | ||
| 581 | comptime { | ||
| 582 | var T: type = i32; | ||
| 583 | assert(T == i32); | ||
| 584 | var ptr = &T; | ||
| 585 | assert(@typeOf(ptr) == *type); | ||
| 586 | ptr.* = f32; | ||
| 587 | assert(T == f32); | ||
| 588 | assert(*T == *f32); | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | test "slice of type" { | ||
| 593 | comptime { | ||
| 594 | var types_array = []type{ i32, f64, type }; | ||
| 595 | for (types_array) |T, i| { | ||
| 596 | switch (i) { | ||
| 597 | 0 => assert(T == i32), | ||
| 598 | 1 => assert(T == f64), | ||
| 599 | 2 => assert(T == type), | ||
| 600 | else => unreachable, | ||
| 601 | } | ||
| 602 | } | ||
| 603 | for (types_array[0..]) |T, i| { | ||
| 604 | switch (i) { | ||
| 605 | 0 => assert(T == i32), | ||
| 606 | 1 => assert(T == f64), | ||
| 607 | 2 => assert(T == type), | ||
| 608 | else => unreachable, | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | const Wrapper = struct { | ||
| 615 | T: type, | ||
| 616 | }; | ||
| 617 | |||
| 618 | fn wrap(comptime T: type) Wrapper { | ||
| 619 | return Wrapper{ .T = T }; | ||
| 620 | } | ||
| 621 | |||
| 622 | test "function which returns struct with type field causes implicit comptime" { | ||
| 623 | const ty = wrap(i32).T; | ||
| 624 | assert(ty == i32); | ||
| 625 | } | ||
| 626 | |||
| 627 | test "call method with comptime pass-by-non-copying-value self parameter" { | ||
| 628 | const S = struct { | ||
| 629 | a: u8, | ||
| 630 | |||
| 631 | fn b(comptime s: @This()) u8 { | ||
| 632 | return s.a; | ||
| 633 | } | ||
| 634 | }; | ||
| 635 | |||
| 636 | const s = S{ .a = 2 }; | ||
| 637 | var b = s.b(); | ||
| 638 | assert(b == 2); | ||
| 639 | } | ||
| 640 | |||
| 641 | test "@tagName of @typeId" { | ||
| 642 | const str = @tagName(@typeId(u8)); | ||
| 643 | assert(std.mem.eql(u8, str, "Int")); | ||
| 644 | } | ||
| 645 | |||
| 646 | test "setting backward branch quota just before a generic fn call" { | ||
| 647 | @setEvalBranchQuota(1001); | ||
| 648 | loopNTimes(1001); | ||
| 649 | } | ||
| 650 | |||
| 651 | fn loopNTimes(comptime n: usize) void { | ||
| 652 | comptime var i = 0; | ||
| 653 | inline while (i < n) : (i += 1) {} | ||
| 654 | } | ||
| 655 | |||
| 656 | test "variable inside inline loop that has different types on different iterations" { | ||
| 657 | testVarInsideInlineLoop(true, u32(42)); | ||
| 658 | } | ||
| 659 | |||
| 660 | fn testVarInsideInlineLoop(args: ...) void { | ||
| 661 | comptime var i = 0; | ||
| 662 | inline while (i < args.len) : (i += 1) { | ||
| 663 | const x = args[i]; | ||
| 664 | if (i == 0) assert(x); | ||
| 665 | if (i == 1) assert(x == 42); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | test "inline for with same type but different values" { | ||
| 670 | var res: usize = 0; | ||
| 671 | inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| { | ||
| 672 | var a: T = undefined; | ||
| 673 | res += a.len; | ||
| 674 | } | ||
| 675 | assert(res == 5); | ||
| 676 | } | ||
| 677 | |||
| 678 | test "refer to the type of a generic function" { | ||
| 679 | const Func = fn (type) void; | ||
| 680 | const f: Func = doNothingWithType; | ||
| 681 | f(i32); | ||
| 682 | } | ||
| 683 | |||
| 684 | fn doNothingWithType(comptime T: type) void {} | ||
| 685 | |||
| 686 | test "zero extend from u0 to u1" { | ||
| 687 | var zero_u0: u0 = 0; | ||
| 688 | var zero_u1: u1 = zero_u0; | ||
| 689 | assert(zero_u1 == 0); | ||
| 690 | } | ||
| 691 | |||
| 692 | test "bit shift a u1" { | ||
| 693 | var x: u1 = 1; | ||
| 694 | var y = x << 0; | ||
| 695 | assert(y == 1); | ||
| 696 | } | ||
| 697 | |||
| 698 | test "@intCast to a u0" { | ||
| 699 | var x: u8 = 0; | ||
| 700 | var y: u0 = @intCast(u0, x); | ||
| 701 | assert(y == 0); | ||
| 702 | } | ||
| 703 | |||
| 704 | test "@bytesToslice on a packed struct" { | ||
| 705 | const F = packed struct { | ||
| 706 | a: u8, | ||
| 707 | }; | ||
| 708 | |||
| 709 | var b = [1]u8{9}; | ||
| 710 | var f = @bytesToSlice(F, b); | ||
| 711 | assert(f[0].a == 9); | ||
| 712 | } | ||
| 713 | |||
| 714 | test "comptime pointer cast array and then slice" { | ||
| 715 | const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | ||
| 716 | |||
| 717 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | ||
| 718 | const sliceA: []const u8 = ptrA[0..2]; | ||
| 719 | |||
| 720 | const ptrB: [*]const u8 = &array; | ||
| 721 | const sliceB: []const u8 = ptrB[0..2]; | ||
| 722 | |||
| 723 | assert(sliceA[1] == 2); | ||
| 724 | assert(sliceB[1] == 2); | ||
| 725 | } | ||
| 726 | |||
| 727 | test "slice bounds in comptime concatenation" { | ||
| 728 | const bs = comptime blk: { | ||
| 729 | const b = c"11"; | ||
| 730 | break :blk b[0..1]; | ||
| 731 | }; | ||
| 732 | const str = "" ++ bs; | ||
| 733 | assert(str.len == 1); | ||
| 734 | assert(std.mem.eql(u8, str, "1")); | ||
| 735 | |||
| 736 | const str2 = bs ++ ""; | ||
| 737 | assert(str2.len == 1); | ||
| 738 | assert(std.mem.eql(u8, str2, "1")); | ||
| 739 | } | ||
| 740 | |||
| 741 | test "comptime bitwise operators" { | ||
| 742 | comptime { | ||
| 743 | assert(3 & 1 == 1); | ||
| 744 | assert(3 & -1 == 3); | ||
| 745 | assert(-3 & -1 == -3); | ||
| 746 | assert(3 | -1 == -1); | ||
| 747 | assert(-3 | -1 == -1); | ||
| 748 | assert(3 ^ -1 == -4); | ||
| 749 | assert(-3 ^ -1 == 2); | ||
| 750 | assert(~i8(-1) == 0); | ||
| 751 | assert(~i128(-1) == 0); | ||
| 752 | assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | ||
| 753 | assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | ||
| 754 | assert(~u128(0) == 0xffffffffffffffffffffffffffffffff); | ||
| 755 | } | ||
| 756 | } | ||
| 757 | |||
| 758 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | ||
| 759 | comptime { | ||
| 760 | assert(*align(1:0:2) u16 == *align(1) u16); | ||
| 761 | // TODO add parsing support for this syntax | ||
| 762 | //assert(*align(:0:2) u16 == *u16); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | test "array concatenation forces comptime" { | ||
| 767 | var a = oneItem(3) ++ oneItem(4); | ||
| 768 | assert(std.mem.eql(i32, a, []i32{3, 4})); | ||
| 769 | } | ||
| 770 | |||
| 771 | test "array multiplication forces comptime" { | ||
| 772 | var a = oneItem(3) ** scalar(2); | ||
| 773 | assert(std.mem.eql(i32, a, []i32{3, 3})); | ||
| 774 | } | ||
| 775 | |||
| 776 | fn oneItem(x: i32) [1]i32 { | ||
| 777 | return []i32{x}; | ||
| 778 | } | ||
| 779 | |||
| 780 | fn scalar(x: u32) u32 { | ||
| 781 | return x; | ||
| 782 | } | ||
test/cases/field_parent_ptr.zig deleted-41| ... | @@ -1,41 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "@fieldParentPtr non-first field" { | ||
| 4 | testParentFieldPtr(&foo.c); | ||
| 5 | comptime testParentFieldPtr(&foo.c); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "@fieldParentPtr first field" { | ||
| 9 | testParentFieldPtrFirst(&foo.a); | ||
| 10 | comptime testParentFieldPtrFirst(&foo.a); | ||
| 11 | } | ||
| 12 | |||
| 13 | const Foo = struct { | ||
| 14 | a: bool, | ||
| 15 | b: f32, | ||
| 16 | c: i32, | ||
| 17 | d: i32, | ||
| 18 | }; | ||
| 19 | |||
| 20 | const foo = Foo{ | ||
| 21 | .a = true, | ||
| 22 | .b = 0.123, | ||
| 23 | .c = 1234, | ||
| 24 | .d = -10, | ||
| 25 | }; | ||
| 26 | |||
| 27 | fn testParentFieldPtr(c: *const i32) void { | ||
| 28 | assert(c == &foo.c); | ||
| 29 | |||
| 30 | const base = @fieldParentPtr(Foo, "c", c); | ||
| 31 | assert(base == &foo); | ||
| 32 | assert(&base.c == c); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn testParentFieldPtrFirst(a: *const bool) void { | ||
| 36 | assert(a == &foo.a); | ||
| 37 | |||
| 38 | const base = @fieldParentPtr(Foo, "a", a); | ||
| 39 | assert(base == &foo); | ||
| 40 | assert(&base.a == a); | ||
| 41 | } | ||
test/cases/fn.zig deleted-207| ... | @@ -1,207 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "params" { | ||
| 4 | assert(testParamsAdd(22, 11) == 33); | ||
| 5 | } | ||
| 6 | fn testParamsAdd(a: i32, b: i32) i32 { | ||
| 7 | return a + b; | ||
| 8 | } | ||
| 9 | |||
| 10 | test "local variables" { | ||
| 11 | testLocVars(2); | ||
| 12 | } | ||
| 13 | fn testLocVars(b: i32) void { | ||
| 14 | const a: i32 = 1; | ||
| 15 | if (a + b != 3) unreachable; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "void parameters" { | ||
| 19 | voidFun(1, void{}, 2, {}); | ||
| 20 | } | ||
| 21 | fn voidFun(a: i32, b: void, c: i32, d: void) void { | ||
| 22 | const v = b; | ||
| 23 | const vv: void = if (a == 1) v else {}; | ||
| 24 | assert(a + c == 3); | ||
| 25 | return vv; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "mutable local variables" { | ||
| 29 | var zero: i32 = 0; | ||
| 30 | assert(zero == 0); | ||
| 31 | |||
| 32 | var i = i32(0); | ||
| 33 | while (i != 3) { | ||
| 34 | i += 1; | ||
| 35 | } | ||
| 36 | assert(i == 3); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "separate block scopes" { | ||
| 40 | { | ||
| 41 | const no_conflict: i32 = 5; | ||
| 42 | assert(no_conflict == 5); | ||
| 43 | } | ||
| 44 | |||
| 45 | const c = x: { | ||
| 46 | const no_conflict = i32(10); | ||
| 47 | break :x no_conflict; | ||
| 48 | }; | ||
| 49 | assert(c == 10); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "call function with empty string" { | ||
| 53 | acceptsString(""); | ||
| 54 | } | ||
| 55 | |||
| 56 | fn acceptsString(foo: []u8) void {} | ||
| 57 | |||
| 58 | fn @"weird function name"() i32 { | ||
| 59 | return 1234; | ||
| 60 | } | ||
| 61 | test "weird function name" { | ||
| 62 | assert(@"weird function name"() == 1234); | ||
| 63 | } | ||
| 64 | |||
| 65 | test "implicit cast function unreachable return" { | ||
| 66 | wantsFnWithVoid(fnWithUnreachable); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn wantsFnWithVoid(f: fn () void) void {} | ||
| 70 | |||
| 71 | fn fnWithUnreachable() noreturn { | ||
| 72 | unreachable; | ||
| 73 | } | ||
| 74 | |||
| 75 | test "function pointers" { | ||
| 76 | const fns = []@typeOf(fn1){ | ||
| 77 | fn1, | ||
| 78 | fn2, | ||
| 79 | fn3, | ||
| 80 | fn4, | ||
| 81 | }; | ||
| 82 | for (fns) |f, i| { | ||
| 83 | assert(f() == @intCast(u32, i) + 5); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | fn fn1() u32 { | ||
| 87 | return 5; | ||
| 88 | } | ||
| 89 | fn fn2() u32 { | ||
| 90 | return 6; | ||
| 91 | } | ||
| 92 | fn fn3() u32 { | ||
| 93 | return 7; | ||
| 94 | } | ||
| 95 | fn fn4() u32 { | ||
| 96 | return 8; | ||
| 97 | } | ||
| 98 | |||
| 99 | test "inline function call" { | ||
| 100 | assert(@inlineCall(add, 3, 9) == 12); | ||
| 101 | } | ||
| 102 | |||
| 103 | fn add(a: i32, b: i32) i32 { | ||
| 104 | return a + b; | ||
| 105 | } | ||
| 106 | |||
| 107 | test "number literal as an argument" { | ||
| 108 | numberLiteralArg(3); | ||
| 109 | comptime numberLiteralArg(3); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn numberLiteralArg(a: var) void { | ||
| 113 | assert(a == 3); | ||
| 114 | } | ||
| 115 | |||
| 116 | test "assign inline fn to const variable" { | ||
| 117 | const a = inlineFn; | ||
| 118 | a(); | ||
| 119 | } | ||
| 120 | |||
| 121 | inline fn inlineFn() void {} | ||
| 122 | |||
| 123 | test "pass by non-copying value" { | ||
| 124 | assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | ||
| 125 | } | ||
| 126 | |||
| 127 | const Point = struct { | ||
| 128 | x: i32, | ||
| 129 | y: i32, | ||
| 130 | }; | ||
| 131 | |||
| 132 | fn addPointCoords(pt: Point) i32 { | ||
| 133 | return pt.x + pt.y; | ||
| 134 | } | ||
| 135 | |||
| 136 | test "pass by non-copying value through var arg" { | ||
| 137 | assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); | ||
| 138 | } | ||
| 139 | |||
| 140 | fn addPointCoordsVar(pt: var) i32 { | ||
| 141 | comptime assert(@typeOf(pt) == Point); | ||
| 142 | return pt.x + pt.y; | ||
| 143 | } | ||
| 144 | |||
| 145 | test "pass by non-copying value as method" { | ||
| 146 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 147 | assert(pt.addPointCoords() == 3); | ||
| 148 | } | ||
| 149 | |||
| 150 | const Point2 = struct { | ||
| 151 | x: i32, | ||
| 152 | y: i32, | ||
| 153 | |||
| 154 | fn addPointCoords(self: Point2) i32 { | ||
| 155 | return self.x + self.y; | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | |||
| 159 | test "pass by non-copying value as method, which is generic" { | ||
| 160 | var pt = Point3{ .x = 1, .y = 2 }; | ||
| 161 | assert(pt.addPointCoords(i32) == 3); | ||
| 162 | } | ||
| 163 | |||
| 164 | const Point3 = struct { | ||
| 165 | x: i32, | ||
| 166 | y: i32, | ||
| 167 | |||
| 168 | fn addPointCoords(self: Point3, comptime T: type) i32 { | ||
| 169 | return self.x + self.y; | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | test "pass by non-copying value as method, at comptime" { | ||
| 174 | comptime { | ||
| 175 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 176 | assert(pt.addPointCoords() == 3); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | fn outer(y: u32) fn (u32) u32 { | ||
| 181 | const Y = @typeOf(y); | ||
| 182 | const st = struct { | ||
| 183 | fn get(z: u32) u32 { | ||
| 184 | return z + @sizeOf(Y); | ||
| 185 | } | ||
| 186 | }; | ||
| 187 | return st.get; | ||
| 188 | } | ||
| 189 | |||
| 190 | test "return inner function which references comptime variable of outer function" { | ||
| 191 | var func = outer(10); | ||
| 192 | assert(func(3) == 7); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "extern struct with stdcallcc fn pointer" { | ||
| 196 | const S = extern struct { | ||
| 197 | ptr: stdcallcc fn () i32, | ||
| 198 | |||
| 199 | stdcallcc fn foo() i32 { | ||
| 200 | return 1234; | ||
| 201 | } | ||
| 202 | }; | ||
| 203 | |||
| 204 | var s: S = undefined; | ||
| 205 | s.ptr = S.foo; | ||
| 206 | assert(s.ptr() == 1234); | ||
| 207 | } | ||
test/cases/fn_in_struct_in_comptime.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | fn get_foo() fn (*u8) usize { | ||
| 4 | comptime { | ||
| 5 | return struct { | ||
| 6 | fn func(ptr: *u8) usize { | ||
| 7 | var u = @ptrToInt(ptr); | ||
| 8 | return u; | ||
| 9 | } | ||
| 10 | }.func; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "define a function in an anonymous struct in comptime" { | ||
| 15 | const foo = get_foo(); | ||
| 16 | assert(foo(@intToPtr(*u8, 12345)) == 12345); | ||
| 17 | } | ||
test/cases/for.zig deleted-106| ... | @@ -1,106 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "continue in for loop" { | ||
| 6 | const array = []i32{ | ||
| 7 | 1, | ||
| 8 | 2, | ||
| 9 | 3, | ||
| 10 | 4, | ||
| 11 | 5, | ||
| 12 | }; | ||
| 13 | var sum: i32 = 0; | ||
| 14 | for (array) |x| { | ||
| 15 | sum += x; | ||
| 16 | if (x < 3) { | ||
| 17 | continue; | ||
| 18 | } | ||
| 19 | break; | ||
| 20 | } | ||
| 21 | if (sum != 6) unreachable; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "for loop with pointer elem var" { | ||
| 25 | const source = "abcdefg"; | ||
| 26 | var target: [source.len]u8 = undefined; | ||
| 27 | mem.copy(u8, target[0..], source); | ||
| 28 | mangleString(target[0..]); | ||
| 29 | assert(mem.eql(u8, target, "bcdefgh")); | ||
| 30 | } | ||
| 31 | fn mangleString(s: []u8) void { | ||
| 32 | for (s) |*c| { | ||
| 33 | c.* += 1; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "basic for loop" { | ||
| 38 | const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | ||
| 39 | |||
| 40 | var buffer: [expected_result.len]u8 = undefined; | ||
| 41 | var buf_index: usize = 0; | ||
| 42 | |||
| 43 | const array = []u8{ 9, 8, 7, 6 }; | ||
| 44 | for (array) |item| { | ||
| 45 | buffer[buf_index] = item; | ||
| 46 | buf_index += 1; | ||
| 47 | } | ||
| 48 | for (array) |item, index| { | ||
| 49 | buffer[buf_index] = @intCast(u8, index); | ||
| 50 | buf_index += 1; | ||
| 51 | } | ||
| 52 | const array_ptr = &array; | ||
| 53 | for (array_ptr) |item| { | ||
| 54 | buffer[buf_index] = item; | ||
| 55 | buf_index += 1; | ||
| 56 | } | ||
| 57 | for (array_ptr) |item, index| { | ||
| 58 | buffer[buf_index] = @intCast(u8, index); | ||
| 59 | buf_index += 1; | ||
| 60 | } | ||
| 61 | const unknown_size: []const u8 = array; | ||
| 62 | for (unknown_size) |item| { | ||
| 63 | buffer[buf_index] = item; | ||
| 64 | buf_index += 1; | ||
| 65 | } | ||
| 66 | for (unknown_size) |item, index| { | ||
| 67 | buffer[buf_index] = @intCast(u8, index); | ||
| 68 | buf_index += 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | assert(mem.eql(u8, buffer[0..buf_index], expected_result)); | ||
| 72 | } | ||
| 73 | |||
| 74 | test "break from outer for loop" { | ||
| 75 | testBreakOuter(); | ||
| 76 | comptime testBreakOuter(); | ||
| 77 | } | ||
| 78 | |||
| 79 | fn testBreakOuter() void { | ||
| 80 | var array = "aoeu"; | ||
| 81 | var count: usize = 0; | ||
| 82 | outer: for (array) |_| { | ||
| 83 | for (array) |_| { | ||
| 84 | count += 1; | ||
| 85 | break :outer; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | assert(count == 1); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "continue outer for loop" { | ||
| 92 | testContinueOuter(); | ||
| 93 | comptime testContinueOuter(); | ||
| 94 | } | ||
| 95 | |||
| 96 | fn testContinueOuter() void { | ||
| 97 | var array = "aoeu"; | ||
| 98 | var counter: usize = 0; | ||
| 99 | outer: for (array) |_| { | ||
| 100 | for (array) |_| { | ||
| 101 | counter += 1; | ||
| 102 | continue :outer; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | assert(counter == array.len); | ||
| 106 | } | ||
test/cases/generics.zig deleted-151| ... | @@ -1,151 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "simple generic fn" { | ||
| 4 | assert(max(i32, 3, -1) == 3); | ||
| 5 | assert(max(f32, 0.123, 0.456) == 0.456); | ||
| 6 | assert(add(2, 3) == 5); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn max(comptime T: type, a: T, b: T) T { | ||
| 10 | return if (a > b) a else b; | ||
| 11 | } | ||
| 12 | |||
| 13 | fn add(comptime a: i32, b: i32) i32 { | ||
| 14 | return (comptime a) + b; | ||
| 15 | } | ||
| 16 | |||
| 17 | const the_max = max(u32, 1234, 5678); | ||
| 18 | test "compile time generic eval" { | ||
| 19 | assert(the_max == 5678); | ||
| 20 | } | ||
| 21 | |||
| 22 | fn gimmeTheBigOne(a: u32, b: u32) u32 { | ||
| 23 | return max(u32, a, b); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn shouldCallSameInstance(a: u32, b: u32) u32 { | ||
| 27 | return max(u32, a, b); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn sameButWithFloats(a: f64, b: f64) f64 { | ||
| 31 | return max(f64, a, b); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "fn with comptime args" { | ||
| 35 | assert(gimmeTheBigOne(1234, 5678) == 5678); | ||
| 36 | assert(shouldCallSameInstance(34, 12) == 34); | ||
| 37 | assert(sameButWithFloats(0.43, 0.49) == 0.49); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "var params" { | ||
| 41 | assert(max_i32(12, 34) == 34); | ||
| 42 | assert(max_f64(1.2, 3.4) == 3.4); | ||
| 43 | } | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | assert(max_i32(12, 34) == 34); | ||
| 47 | assert(max_f64(1.2, 3.4) == 3.4); | ||
| 48 | } | ||
| 49 | |||
| 50 | fn max_var(a: var, b: var) @typeOf(a + b) { | ||
| 51 | return if (a > b) a else b; | ||
| 52 | } | ||
| 53 | |||
| 54 | fn max_i32(a: i32, b: i32) i32 { | ||
| 55 | return max_var(a, b); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn max_f64(a: f64, b: f64) f64 { | ||
| 59 | return max_var(a, b); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn List(comptime T: type) type { | ||
| 63 | return SmallList(T, 8); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { | ||
| 67 | return struct { | ||
| 68 | items: []T, | ||
| 69 | length: usize, | ||
| 70 | prealloc_items: [STATIC_SIZE]T, | ||
| 71 | }; | ||
| 72 | } | ||
| 73 | |||
| 74 | test "function with return type type" { | ||
| 75 | var list: List(i32) = undefined; | ||
| 76 | var list2: List(i32) = undefined; | ||
| 77 | list.length = 10; | ||
| 78 | list2.length = 10; | ||
| 79 | assert(list.prealloc_items.len == 8); | ||
| 80 | assert(list2.prealloc_items.len == 8); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "generic struct" { | ||
| 84 | var a1 = GenNode(i32){ | ||
| 85 | .value = 13, | ||
| 86 | .next = null, | ||
| 87 | }; | ||
| 88 | var b1 = GenNode(bool){ | ||
| 89 | .value = true, | ||
| 90 | .next = null, | ||
| 91 | }; | ||
| 92 | assert(a1.value == 13); | ||
| 93 | assert(a1.value == a1.getVal()); | ||
| 94 | assert(b1.getVal()); | ||
| 95 | } | ||
| 96 | fn GenNode(comptime T: type) type { | ||
| 97 | return struct { | ||
| 98 | value: T, | ||
| 99 | next: ?*GenNode(T), | ||
| 100 | fn getVal(n: *const GenNode(T)) T { | ||
| 101 | return n.value; | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "const decls in struct" { | ||
| 107 | assert(GenericDataThing(3).count_plus_one == 4); | ||
| 108 | } | ||
| 109 | fn GenericDataThing(comptime count: isize) type { | ||
| 110 | return struct { | ||
| 111 | const count_plus_one = count + 1; | ||
| 112 | }; | ||
| 113 | } | ||
| 114 | |||
| 115 | test "use generic param in generic param" { | ||
| 116 | assert(aGenericFn(i32, 3, 4) == 7); | ||
| 117 | } | ||
| 118 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { | ||
| 119 | return a + b; | ||
| 120 | } | ||
| 121 | |||
| 122 | test "generic fn with implicit cast" { | ||
| 123 | assert(getFirstByte(u8, []u8{13}) == 13); | ||
| 124 | assert(getFirstByte(u16, []u16{ | ||
| 125 | 0, | ||
| 126 | 13, | ||
| 127 | }) == 0); | ||
| 128 | } | ||
| 129 | fn getByte(ptr: ?*const u8) u8 { | ||
| 130 | return ptr.?.*; | ||
| 131 | } | ||
| 132 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 133 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 134 | } | ||
| 135 | |||
| 136 | const foos = []fn (var) bool{ | ||
| 137 | foo1, | ||
| 138 | foo2, | ||
| 139 | }; | ||
| 140 | |||
| 141 | fn foo1(arg: var) bool { | ||
| 142 | return arg; | ||
| 143 | } | ||
| 144 | fn foo2(arg: var) bool { | ||
| 145 | return !arg; | ||
| 146 | } | ||
| 147 | |||
| 148 | test "array of generic fns" { | ||
| 149 | assert(foos[0](true)); | ||
| 150 | assert(!foos[1](true)); | ||
| 151 | } | ||
test/cases/if.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "if statements" { | ||
| 4 | shouldBeEqual(1, 1); | ||
| 5 | firstEqlThird(2, 1, 2); | ||
| 6 | } | ||
| 7 | fn shouldBeEqual(a: i32, b: i32) void { | ||
| 8 | if (a != b) { | ||
| 9 | unreachable; | ||
| 10 | } else { | ||
| 11 | return; | ||
| 12 | } | ||
| 13 | } | ||
| 14 | fn firstEqlThird(a: i32, b: i32, c: i32) void { | ||
| 15 | if (a == b) { | ||
| 16 | unreachable; | ||
| 17 | } else if (b == c) { | ||
| 18 | unreachable; | ||
| 19 | } else if (a == c) { | ||
| 20 | return; | ||
| 21 | } else { | ||
| 22 | unreachable; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | test "else if expression" { | ||
| 27 | assert(elseIfExpressionF(1) == 1); | ||
| 28 | } | ||
| 29 | fn elseIfExpressionF(c: u8) u8 { | ||
| 30 | if (c == 0) { | ||
| 31 | return 0; | ||
| 32 | } else if (c == 1) { | ||
| 33 | return 1; | ||
| 34 | } else { | ||
| 35 | return u8(2); | ||
| 36 | } | ||
| 37 | } | ||
test/cases/import.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const a_namespace = @import("import/a_namespace.zig"); | ||
| 3 | |||
| 4 | test "call fn via namespace lookup" { | ||
| 5 | assert(a_namespace.foo() == 1234); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "importing the same thing gives the same import" { | ||
| 9 | assert(@import("std") == @import("std")); | ||
| 10 | } | ||
test/cases/import/a_namespace.zig deleted-3| ... | @@ -1,3 +0,0 @@ | ||
| 1 | pub fn foo() i32 { | ||
| 2 | return 1234; | ||
| 3 | } | ||
test/cases/incomplete_struct_param_tld.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const A = struct { | ||
| 4 | b: B, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const B = struct { | ||
| 8 | c: C, | ||
| 9 | }; | ||
| 10 | |||
| 11 | const C = struct { | ||
| 12 | x: i32, | ||
| 13 | |||
| 14 | fn d(c: *const C) i32 { | ||
| 15 | return c.x; | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(a: A) i32 { | ||
| 20 | return a.b.c.d(); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "incomplete struct param top level declaration" { | ||
| 24 | const a = A{ | ||
| 25 | .b = B{ | ||
| 26 | .c = C{ .x = 13 }, | ||
| 27 | }, | ||
| 28 | }; | ||
| 29 | assert(foo(a) == 13); | ||
| 30 | } | ||
test/cases/inttoptr.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | test "casting random address to function pointer" { | ||
| 6 | randomAddressToFunction(); | ||
| 7 | comptime randomAddressToFunction(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn randomAddressToFunction() void { | ||
| 11 | var addr: usize = 0xdeadbeef; | ||
| 12 | var ptr = @intToPtr(fn () void, addr); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "mutate through ptr initialized with constant intToPtr value" { | ||
| 16 | forceCompilerAnalyzeBranchHardCodedPtrDereference(false); | ||
| 17 | } | ||
| 18 | |||
| 19 | fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { | ||
| 20 | const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); | ||
| 21 | if (x) { | ||
| 22 | hardCodedP.* = hardCodedP.* | 10; | ||
| 23 | } else { | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
test/cases/ir_block_deps.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | fn foo(id: u64) !i32 { | ||
| 4 | return switch (id) { | ||
| 5 | 1 => getErrInt(), | ||
| 6 | 2 => { | ||
| 7 | const size = try getErrInt(); | ||
| 8 | return try getErrInt(); | ||
| 9 | }, | ||
| 10 | else => error.ItBroke, | ||
| 11 | }; | ||
| 12 | } | ||
| 13 | |||
| 14 | fn getErrInt() anyerror!i32 { | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "ir block deps" { | ||
| 19 | assert((foo(1) catch unreachable) == 0); | ||
| 20 | assert((foo(2) catch unreachable) == 0); | ||
| 21 | } | ||
test/cases/math.zig deleted-500| ... | @@ -1,500 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | const minInt = std.math.minInt; | ||
| 5 | |||
| 6 | test "division" { | ||
| 7 | testDivision(); | ||
| 8 | comptime testDivision(); | ||
| 9 | } | ||
| 10 | fn testDivision() void { | ||
| 11 | assert(div(u32, 13, 3) == 4); | ||
| 12 | assert(div(f16, 1.0, 2.0) == 0.5); | ||
| 13 | assert(div(f32, 1.0, 2.0) == 0.5); | ||
| 14 | |||
| 15 | assert(divExact(u32, 55, 11) == 5); | ||
| 16 | assert(divExact(i32, -55, 11) == -5); | ||
| 17 | assert(divExact(f16, 55.0, 11.0) == 5.0); | ||
| 18 | assert(divExact(f16, -55.0, 11.0) == -5.0); | ||
| 19 | assert(divExact(f32, 55.0, 11.0) == 5.0); | ||
| 20 | assert(divExact(f32, -55.0, 11.0) == -5.0); | ||
| 21 | |||
| 22 | assert(divFloor(i32, 5, 3) == 1); | ||
| 23 | assert(divFloor(i32, -5, 3) == -2); | ||
| 24 | assert(divFloor(f16, 5.0, 3.0) == 1.0); | ||
| 25 | assert(divFloor(f16, -5.0, 3.0) == -2.0); | ||
| 26 | assert(divFloor(f32, 5.0, 3.0) == 1.0); | ||
| 27 | assert(divFloor(f32, -5.0, 3.0) == -2.0); | ||
| 28 | assert(divFloor(i32, -0x80000000, -2) == 0x40000000); | ||
| 29 | assert(divFloor(i32, 0, -0x80000000) == 0); | ||
| 30 | assert(divFloor(i32, -0x40000001, 0x40000000) == -2); | ||
| 31 | assert(divFloor(i32, -0x80000000, 1) == -0x80000000); | ||
| 32 | |||
| 33 | assert(divTrunc(i32, 5, 3) == 1); | ||
| 34 | assert(divTrunc(i32, -5, 3) == -1); | ||
| 35 | assert(divTrunc(f16, 5.0, 3.0) == 1.0); | ||
| 36 | assert(divTrunc(f16, -5.0, 3.0) == -1.0); | ||
| 37 | assert(divTrunc(f32, 5.0, 3.0) == 1.0); | ||
| 38 | assert(divTrunc(f32, -5.0, 3.0) == -1.0); | ||
| 39 | assert(divTrunc(f64, 5.0, 3.0) == 1.0); | ||
| 40 | assert(divTrunc(f64, -5.0, 3.0) == -1.0); | ||
| 41 | |||
| 42 | comptime { | ||
| 43 | assert( | ||
| 44 | 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, | ||
| 45 | ); | ||
| 46 | assert( | ||
| 47 | @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, | ||
| 48 | ); | ||
| 49 | assert( | ||
| 50 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, | ||
| 51 | ); | ||
| 52 | assert( | ||
| 53 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | ||
| 54 | ); | ||
| 55 | assert( | ||
| 56 | @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, | ||
| 57 | ); | ||
| 58 | assert( | ||
| 59 | @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, | ||
| 60 | ); | ||
| 61 | assert( | ||
| 62 | 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | fn div(comptime T: type, a: T, b: T) T { | ||
| 67 | return a / b; | ||
| 68 | } | ||
| 69 | fn divExact(comptime T: type, a: T, b: T) T { | ||
| 70 | return @divExact(a, b); | ||
| 71 | } | ||
| 72 | fn divFloor(comptime T: type, a: T, b: T) T { | ||
| 73 | return @divFloor(a, b); | ||
| 74 | } | ||
| 75 | fn divTrunc(comptime T: type, a: T, b: T) T { | ||
| 76 | return @divTrunc(a, b); | ||
| 77 | } | ||
| 78 | |||
| 79 | test "@addWithOverflow" { | ||
| 80 | var result: u8 = undefined; | ||
| 81 | assert(@addWithOverflow(u8, 250, 100, &result)); | ||
| 82 | assert(!@addWithOverflow(u8, 100, 150, &result)); | ||
| 83 | assert(result == 250); | ||
| 84 | } | ||
| 85 | |||
| 86 | // TODO test mulWithOverflow | ||
| 87 | // TODO test subWithOverflow | ||
| 88 | |||
| 89 | test "@shlWithOverflow" { | ||
| 90 | var result: u16 = undefined; | ||
| 91 | assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | ||
| 92 | assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | ||
| 93 | assert(result == 0b1011111111111100); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "@clz" { | ||
| 97 | testClz(); | ||
| 98 | comptime testClz(); | ||
| 99 | } | ||
| 100 | |||
| 101 | fn testClz() void { | ||
| 102 | assert(clz(u8(0b00001010)) == 4); | ||
| 103 | assert(clz(u8(0b10001010)) == 0); | ||
| 104 | assert(clz(u8(0b00000000)) == 8); | ||
| 105 | assert(clz(u128(0xffffffffffffffff)) == 64); | ||
| 106 | assert(clz(u128(0x10000000000000000)) == 63); | ||
| 107 | } | ||
| 108 | |||
| 109 | fn clz(x: var) usize { | ||
| 110 | return @clz(x); | ||
| 111 | } | ||
| 112 | |||
| 113 | test "@ctz" { | ||
| 114 | testCtz(); | ||
| 115 | comptime testCtz(); | ||
| 116 | } | ||
| 117 | |||
| 118 | fn testCtz() void { | ||
| 119 | assert(ctz(u8(0b10100000)) == 5); | ||
| 120 | assert(ctz(u8(0b10001010)) == 1); | ||
| 121 | assert(ctz(u8(0b00000000)) == 8); | ||
| 122 | } | ||
| 123 | |||
| 124 | fn ctz(x: var) usize { | ||
| 125 | return @ctz(x); | ||
| 126 | } | ||
| 127 | |||
| 128 | test "assignment operators" { | ||
| 129 | var i: u32 = 0; | ||
| 130 | i += 5; | ||
| 131 | assert(i == 5); | ||
| 132 | i -= 2; | ||
| 133 | assert(i == 3); | ||
| 134 | i *= 20; | ||
| 135 | assert(i == 60); | ||
| 136 | i /= 3; | ||
| 137 | assert(i == 20); | ||
| 138 | i %= 11; | ||
| 139 | assert(i == 9); | ||
| 140 | i <<= 1; | ||
| 141 | assert(i == 18); | ||
| 142 | i >>= 2; | ||
| 143 | assert(i == 4); | ||
| 144 | i = 6; | ||
| 145 | i &= 5; | ||
| 146 | assert(i == 4); | ||
| 147 | i ^= 6; | ||
| 148 | assert(i == 2); | ||
| 149 | i = 6; | ||
| 150 | i |= 3; | ||
| 151 | assert(i == 7); | ||
| 152 | } | ||
| 153 | |||
| 154 | test "three expr in a row" { | ||
| 155 | testThreeExprInARow(false, true); | ||
| 156 | comptime testThreeExprInARow(false, true); | ||
| 157 | } | ||
| 158 | fn testThreeExprInARow(f: bool, t: bool) void { | ||
| 159 | assertFalse(f or f or f); | ||
| 160 | assertFalse(t and t and f); | ||
| 161 | assertFalse(1 | 2 | 4 != 7); | ||
| 162 | assertFalse(3 ^ 6 ^ 8 != 13); | ||
| 163 | assertFalse(7 & 14 & 28 != 4); | ||
| 164 | assertFalse(9 << 1 << 2 != 9 << 3); | ||
| 165 | assertFalse(90 >> 1 >> 2 != 90 >> 3); | ||
| 166 | assertFalse(100 - 1 + 1000 != 1099); | ||
| 167 | assertFalse(5 * 4 / 2 % 3 != 1); | ||
| 168 | assertFalse(i32(i32(5)) != 5); | ||
| 169 | assertFalse(!!false); | ||
| 170 | assertFalse(i32(7) != --(i32(7))); | ||
| 171 | } | ||
| 172 | fn assertFalse(b: bool) void { | ||
| 173 | assert(!b); | ||
| 174 | } | ||
| 175 | |||
| 176 | test "const number literal" { | ||
| 177 | const one = 1; | ||
| 178 | const eleven = ten + one; | ||
| 179 | |||
| 180 | assert(eleven == 11); | ||
| 181 | } | ||
| 182 | const ten = 10; | ||
| 183 | |||
| 184 | test "unsigned wrapping" { | ||
| 185 | testUnsignedWrappingEval(maxInt(u32)); | ||
| 186 | comptime testUnsignedWrappingEval(maxInt(u32)); | ||
| 187 | } | ||
| 188 | fn testUnsignedWrappingEval(x: u32) void { | ||
| 189 | const zero = x +% 1; | ||
| 190 | assert(zero == 0); | ||
| 191 | const orig = zero -% 1; | ||
| 192 | assert(orig == maxInt(u32)); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "signed wrapping" { | ||
| 196 | testSignedWrappingEval(maxInt(i32)); | ||
| 197 | comptime testSignedWrappingEval(maxInt(i32)); | ||
| 198 | } | ||
| 199 | fn testSignedWrappingEval(x: i32) void { | ||
| 200 | const min_val = x +% 1; | ||
| 201 | assert(min_val == minInt(i32)); | ||
| 202 | const max_val = min_val -% 1; | ||
| 203 | assert(max_val == maxInt(i32)); | ||
| 204 | } | ||
| 205 | |||
| 206 | test "negation wrapping" { | ||
| 207 | testNegationWrappingEval(minInt(i16)); | ||
| 208 | comptime testNegationWrappingEval(minInt(i16)); | ||
| 209 | } | ||
| 210 | fn testNegationWrappingEval(x: i16) void { | ||
| 211 | assert(x == -32768); | ||
| 212 | const neg = -%x; | ||
| 213 | assert(neg == -32768); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "unsigned 64-bit division" { | ||
| 217 | test_u64_div(); | ||
| 218 | comptime test_u64_div(); | ||
| 219 | } | ||
| 220 | fn test_u64_div() void { | ||
| 221 | const result = divWithResult(1152921504606846976, 34359738365); | ||
| 222 | assert(result.quotient == 33554432); | ||
| 223 | assert(result.remainder == 100663296); | ||
| 224 | } | ||
| 225 | fn divWithResult(a: u64, b: u64) DivResult { | ||
| 226 | return DivResult{ | ||
| 227 | .quotient = a / b, | ||
| 228 | .remainder = a % b, | ||
| 229 | }; | ||
| 230 | } | ||
| 231 | const DivResult = struct { | ||
| 232 | quotient: u64, | ||
| 233 | remainder: u64, | ||
| 234 | }; | ||
| 235 | |||
| 236 | test "binary not" { | ||
| 237 | assert(comptime x: { | ||
| 238 | break :x ~u16(0b1010101010101010) == 0b0101010101010101; | ||
| 239 | }); | ||
| 240 | assert(comptime x: { | ||
| 241 | break :x ~u64(2147483647) == 18446744071562067968; | ||
| 242 | }); | ||
| 243 | testBinaryNot(0b1010101010101010); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn testBinaryNot(x: u16) void { | ||
| 247 | assert(~x == 0b0101010101010101); | ||
| 248 | } | ||
| 249 | |||
| 250 | test "small int addition" { | ||
| 251 | var x: @IntType(false, 2) = 0; | ||
| 252 | assert(x == 0); | ||
| 253 | |||
| 254 | x += 1; | ||
| 255 | assert(x == 1); | ||
| 256 | |||
| 257 | x += 1; | ||
| 258 | assert(x == 2); | ||
| 259 | |||
| 260 | x += 1; | ||
| 261 | assert(x == 3); | ||
| 262 | |||
| 263 | var result: @typeOf(x) = 3; | ||
| 264 | assert(@addWithOverflow(@typeOf(x), x, 1, &result)); | ||
| 265 | |||
| 266 | assert(result == 0); | ||
| 267 | } | ||
| 268 | |||
| 269 | test "float equality" { | ||
| 270 | const x: f64 = 0.012; | ||
| 271 | const y: f64 = x + 1.0; | ||
| 272 | |||
| 273 | testFloatEqualityImpl(x, y); | ||
| 274 | comptime testFloatEqualityImpl(x, y); | ||
| 275 | } | ||
| 276 | |||
| 277 | fn testFloatEqualityImpl(x: f64, y: f64) void { | ||
| 278 | const y2 = x + 1.0; | ||
| 279 | assert(y == y2); | ||
| 280 | } | ||
| 281 | |||
| 282 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { | ||
| 283 | assert(5 / 3 == 1); | ||
| 284 | assert(-5 / -3 == 1); | ||
| 285 | assert(-6 / 3 == -2); | ||
| 286 | |||
| 287 | assert(5 % 3 == 2); | ||
| 288 | assert(-6 % 3 == 0); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "hex float literal parsing" { | ||
| 292 | comptime assert(0x1.0 == 1.0); | ||
| 293 | } | ||
| 294 | |||
| 295 | test "quad hex float literal parsing in range" { | ||
| 296 | const a = 0x1.af23456789bbaaab347645365cdep+5; | ||
| 297 | const b = 0x1.dedafcff354b6ae9758763545432p-9; | ||
| 298 | const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; | ||
| 299 | const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; | ||
| 300 | } | ||
| 301 | |||
| 302 | test "quad hex float literal parsing accurate" { | ||
| 303 | const a: f128 = 0x1.1111222233334444555566667777p+0; | ||
| 304 | |||
| 305 | // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. | ||
| 306 | const expected: u128 = 0x3fff1111222233334444555566667777; | ||
| 307 | assert(@bitCast(u128, a) == expected); | ||
| 308 | } | ||
| 309 | |||
| 310 | test "hex float literal within range" { | ||
| 311 | const a = 0x1.0p16383; | ||
| 312 | const b = 0x0.1p16387; | ||
| 313 | const c = 0x1.0p-16382; | ||
| 314 | } | ||
| 315 | |||
| 316 | test "truncating shift left" { | ||
| 317 | testShlTrunc(maxInt(u16)); | ||
| 318 | comptime testShlTrunc(maxInt(u16)); | ||
| 319 | } | ||
| 320 | fn testShlTrunc(x: u16) void { | ||
| 321 | const shifted = x << 1; | ||
| 322 | assert(shifted == 65534); | ||
| 323 | } | ||
| 324 | |||
| 325 | test "truncating shift right" { | ||
| 326 | testShrTrunc(maxInt(u16)); | ||
| 327 | comptime testShrTrunc(maxInt(u16)); | ||
| 328 | } | ||
| 329 | fn testShrTrunc(x: u16) void { | ||
| 330 | const shifted = x >> 1; | ||
| 331 | assert(shifted == 32767); | ||
| 332 | } | ||
| 333 | |||
| 334 | test "exact shift left" { | ||
| 335 | testShlExact(0b00110101); | ||
| 336 | comptime testShlExact(0b00110101); | ||
| 337 | } | ||
| 338 | fn testShlExact(x: u8) void { | ||
| 339 | const shifted = @shlExact(x, 2); | ||
| 340 | assert(shifted == 0b11010100); | ||
| 341 | } | ||
| 342 | |||
| 343 | test "exact shift right" { | ||
| 344 | testShrExact(0b10110100); | ||
| 345 | comptime testShrExact(0b10110100); | ||
| 346 | } | ||
| 347 | fn testShrExact(x: u8) void { | ||
| 348 | const shifted = @shrExact(x, 2); | ||
| 349 | assert(shifted == 0b00101101); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "comptime_int addition" { | ||
| 353 | comptime { | ||
| 354 | assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | ||
| 355 | assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | test "comptime_int multiplication" { | ||
| 360 | comptime { | ||
| 361 | assert( | ||
| 362 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | ||
| 363 | ); | ||
| 364 | assert( | ||
| 365 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | ||
| 366 | ); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | test "comptime_int shifting" { | ||
| 371 | comptime { | ||
| 372 | assert((u128(1) << 127) == 0x80000000000000000000000000000000); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | test "comptime_int multi-limb shift and mask" { | ||
| 377 | comptime { | ||
| 378 | var a = 0xefffffffa0000001eeeeeeefaaaaaaab; | ||
| 379 | |||
| 380 | assert(u32(a & 0xffffffff) == 0xaaaaaaab); | ||
| 381 | a >>= 32; | ||
| 382 | assert(u32(a & 0xffffffff) == 0xeeeeeeef); | ||
| 383 | a >>= 32; | ||
| 384 | assert(u32(a & 0xffffffff) == 0xa0000001); | ||
| 385 | a >>= 32; | ||
| 386 | assert(u32(a & 0xffffffff) == 0xefffffff); | ||
| 387 | a >>= 32; | ||
| 388 | |||
| 389 | assert(a == 0); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | test "comptime_int multi-limb partial shift right" { | ||
| 394 | comptime { | ||
| 395 | var a = 0x1ffffffffeeeeeeee; | ||
| 396 | a >>= 16; | ||
| 397 | assert(a == 0x1ffffffffeeee); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | test "xor" { | ||
| 402 | test_xor(); | ||
| 403 | comptime test_xor(); | ||
| 404 | } | ||
| 405 | |||
| 406 | fn test_xor() void { | ||
| 407 | assert(0xFF ^ 0x00 == 0xFF); | ||
| 408 | assert(0xF0 ^ 0x0F == 0xFF); | ||
| 409 | assert(0xFF ^ 0xF0 == 0x0F); | ||
| 410 | assert(0xFF ^ 0x0F == 0xF0); | ||
| 411 | assert(0xFF ^ 0xFF == 0x00); | ||
| 412 | } | ||
| 413 | |||
| 414 | test "comptime_int xor" { | ||
| 415 | comptime { | ||
| 416 | assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 417 | assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 418 | assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); | ||
| 419 | assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); | ||
| 420 | assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); | ||
| 421 | assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 422 | assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); | ||
| 423 | assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | test "f128" { | ||
| 428 | test_f128(); | ||
| 429 | comptime test_f128(); | ||
| 430 | } | ||
| 431 | |||
| 432 | fn make_f128(x: f128) f128 { | ||
| 433 | return x; | ||
| 434 | } | ||
| 435 | |||
| 436 | fn test_f128() void { | ||
| 437 | assert(@sizeOf(f128) == 16); | ||
| 438 | assert(make_f128(1.0) == 1.0); | ||
| 439 | assert(make_f128(1.0) != 1.1); | ||
| 440 | assert(make_f128(1.0) > 0.9); | ||
| 441 | assert(make_f128(1.0) >= 0.9); | ||
| 442 | assert(make_f128(1.0) >= 1.0); | ||
| 443 | should_not_be_zero(1.0); | ||
| 444 | } | ||
| 445 | |||
| 446 | fn should_not_be_zero(x: f128) void { | ||
| 447 | assert(x != 0.0); | ||
| 448 | } | ||
| 449 | |||
| 450 | test "comptime float rem int" { | ||
| 451 | comptime { | ||
| 452 | var x = f32(1) % 2; | ||
| 453 | assert(x == 1.0); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | test "remainder division" { | ||
| 458 | comptime remdiv(f16); | ||
| 459 | comptime remdiv(f32); | ||
| 460 | comptime remdiv(f64); | ||
| 461 | comptime remdiv(f128); | ||
| 462 | remdiv(f16); | ||
| 463 | remdiv(f64); | ||
| 464 | remdiv(f128); | ||
| 465 | } | ||
| 466 | |||
| 467 | fn remdiv(comptime T: type) void { | ||
| 468 | assert(T(1) == T(1) % T(2)); | ||
| 469 | assert(T(1) == T(7) % T(3)); | ||
| 470 | } | ||
| 471 | |||
| 472 | test "@sqrt" { | ||
| 473 | testSqrt(f64, 12.0); | ||
| 474 | comptime testSqrt(f64, 12.0); | ||
| 475 | testSqrt(f32, 13.0); | ||
| 476 | comptime testSqrt(f32, 13.0); | ||
| 477 | testSqrt(f16, 13.0); | ||
| 478 | comptime testSqrt(f16, 13.0); | ||
| 479 | |||
| 480 | const x = 14.0; | ||
| 481 | const y = x * x; | ||
| 482 | const z = @sqrt(@typeOf(y), y); | ||
| 483 | comptime assert(z == x); | ||
| 484 | } | ||
| 485 | |||
| 486 | fn testSqrt(comptime T: type, x: T) void { | ||
| 487 | assert(@sqrt(T, x * x) == x); | ||
| 488 | } | ||
| 489 | |||
| 490 | test "comptime_int param and return" { | ||
| 491 | const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); | ||
| 492 | assert(a == 137114567242441932203689521744947848950); | ||
| 493 | |||
| 494 | const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); | ||
| 495 | assert(b == 985095453608931032642182098849559179469148836107390954364380); | ||
| 496 | } | ||
| 497 | |||
| 498 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | ||
| 499 | return a + b; | ||
| 500 | } | ||
test/cases/merge_error_sets.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const A = error{ | ||
| 2 | FileNotFound, | ||
| 3 | NotDir, | ||
| 4 | }; | ||
| 5 | const B = error{OutOfMemory}; | ||
| 6 | |||
| 7 | const C = A || B; | ||
| 8 | |||
| 9 | fn foo() C!void { | ||
| 10 | return error.NotDir; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "merge error sets" { | ||
| 14 | if (foo()) { | ||
| 15 | @panic("unexpected"); | ||
| 16 | } else |err| switch (err) { | ||
| 17 | error.OutOfMemory => @panic("unexpected"), | ||
| 18 | error.FileNotFound => @panic("unexpected"), | ||
| 19 | error.NotDir => {}, | ||
| 20 | } | ||
| 21 | } | ||
test/cases/misc.zig deleted-681| ... | @@ -1,681 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | ||
| 4 | const cstr = std.cstr; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | const maxInt = std.math.maxInt; | ||
| 7 | |||
| 8 | // normal comment | ||
| 9 | |||
| 10 | /// this is a documentation comment | ||
| 11 | /// doc comment line 2 | ||
| 12 | fn emptyFunctionWithComments() void {} | ||
| 13 | |||
| 14 | test "empty function with comments" { | ||
| 15 | emptyFunctionWithComments(); | ||
| 16 | } | ||
| 17 | |||
| 18 | comptime { | ||
| 19 | @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); | ||
| 20 | } | ||
| 21 | |||
| 22 | extern fn disabledExternFn() void {} | ||
| 23 | |||
| 24 | test "call disabled extern fn" { | ||
| 25 | disabledExternFn(); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "@IntType builtin" { | ||
| 29 | assert(@IntType(true, 8) == i8); | ||
| 30 | assert(@IntType(true, 16) == i16); | ||
| 31 | assert(@IntType(true, 32) == i32); | ||
| 32 | assert(@IntType(true, 64) == i64); | ||
| 33 | |||
| 34 | assert(@IntType(false, 8) == u8); | ||
| 35 | assert(@IntType(false, 16) == u16); | ||
| 36 | assert(@IntType(false, 32) == u32); | ||
| 37 | assert(@IntType(false, 64) == u64); | ||
| 38 | |||
| 39 | assert(i8.bit_count == 8); | ||
| 40 | assert(i16.bit_count == 16); | ||
| 41 | assert(i32.bit_count == 32); | ||
| 42 | assert(i64.bit_count == 64); | ||
| 43 | |||
| 44 | assert(i8.is_signed); | ||
| 45 | assert(i16.is_signed); | ||
| 46 | assert(i32.is_signed); | ||
| 47 | assert(i64.is_signed); | ||
| 48 | assert(isize.is_signed); | ||
| 49 | |||
| 50 | assert(!u8.is_signed); | ||
| 51 | assert(!u16.is_signed); | ||
| 52 | assert(!u32.is_signed); | ||
| 53 | assert(!u64.is_signed); | ||
| 54 | assert(!usize.is_signed); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "floating point primitive bit counts" { | ||
| 58 | assert(f16.bit_count == 16); | ||
| 59 | assert(f32.bit_count == 32); | ||
| 60 | assert(f64.bit_count == 64); | ||
| 61 | } | ||
| 62 | |||
| 63 | test "short circuit" { | ||
| 64 | testShortCircuit(false, true); | ||
| 65 | comptime testShortCircuit(false, true); | ||
| 66 | } | ||
| 67 | |||
| 68 | fn testShortCircuit(f: bool, t: bool) void { | ||
| 69 | var hit_1 = f; | ||
| 70 | var hit_2 = f; | ||
| 71 | var hit_3 = f; | ||
| 72 | var hit_4 = f; | ||
| 73 | |||
| 74 | if (t or x: { | ||
| 75 | assert(f); | ||
| 76 | break :x f; | ||
| 77 | }) { | ||
| 78 | hit_1 = t; | ||
| 79 | } | ||
| 80 | if (f or x: { | ||
| 81 | hit_2 = t; | ||
| 82 | break :x f; | ||
| 83 | }) { | ||
| 84 | assert(f); | ||
| 85 | } | ||
| 86 | |||
| 87 | if (t and x: { | ||
| 88 | hit_3 = t; | ||
| 89 | break :x f; | ||
| 90 | }) { | ||
| 91 | assert(f); | ||
| 92 | } | ||
| 93 | if (f and x: { | ||
| 94 | assert(f); | ||
| 95 | break :x f; | ||
| 96 | }) { | ||
| 97 | assert(f); | ||
| 98 | } else { | ||
| 99 | hit_4 = t; | ||
| 100 | } | ||
| 101 | assert(hit_1); | ||
| 102 | assert(hit_2); | ||
| 103 | assert(hit_3); | ||
| 104 | assert(hit_4); | ||
| 105 | } | ||
| 106 | |||
| 107 | test "truncate" { | ||
| 108 | assert(testTruncate(0x10fd) == 0xfd); | ||
| 109 | } | ||
| 110 | fn testTruncate(x: u32) u8 { | ||
| 111 | return @truncate(u8, x); | ||
| 112 | } | ||
| 113 | |||
| 114 | fn first4KeysOfHomeRow() []const u8 { | ||
| 115 | return "aoeu"; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "return string from function" { | ||
| 119 | assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 120 | } | ||
| 121 | |||
| 122 | const g1: i32 = 1233 + 1; | ||
| 123 | var g2: i32 = 0; | ||
| 124 | |||
| 125 | test "global variables" { | ||
| 126 | assert(g2 == 0); | ||
| 127 | g2 = g1; | ||
| 128 | assert(g2 == 1234); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "memcpy and memset intrinsics" { | ||
| 132 | var foo: [20]u8 = undefined; | ||
| 133 | var bar: [20]u8 = undefined; | ||
| 134 | |||
| 135 | @memset(foo[0..].ptr, 'A', foo.len); | ||
| 136 | @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); | ||
| 137 | |||
| 138 | if (bar[11] != 'A') unreachable; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "builtin static eval" { | ||
| 142 | const x: i32 = comptime x: { | ||
| 143 | break :x 1 + 2 + 3; | ||
| 144 | }; | ||
| 145 | assert(x == comptime 6); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "slicing" { | ||
| 149 | var array: [20]i32 = undefined; | ||
| 150 | |||
| 151 | array[5] = 1234; | ||
| 152 | |||
| 153 | var slice = array[5..10]; | ||
| 154 | |||
| 155 | if (slice.len != 5) unreachable; | ||
| 156 | |||
| 157 | const ptr = &slice[0]; | ||
| 158 | if (ptr.* != 1234) unreachable; | ||
| 159 | |||
| 160 | var slice_rest = array[10..]; | ||
| 161 | if (slice_rest.len != 10) unreachable; | ||
| 162 | } | ||
| 163 | |||
| 164 | test "constant equal function pointers" { | ||
| 165 | const alias = emptyFn; | ||
| 166 | assert(comptime x: { | ||
| 167 | break :x emptyFn == alias; | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn emptyFn() void {} | ||
| 172 | |||
| 173 | test "hex escape" { | ||
| 174 | assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); | ||
| 175 | } | ||
| 176 | |||
| 177 | test "string concatenation" { | ||
| 178 | assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); | ||
| 179 | } | ||
| 180 | |||
| 181 | test "array mult operator" { | ||
| 182 | assert(mem.eql(u8, "ab" ** 5, "ababababab")); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "string escapes" { | ||
| 186 | assert(mem.eql(u8, "\"", "\x22")); | ||
| 187 | assert(mem.eql(u8, "\'", "\x27")); | ||
| 188 | assert(mem.eql(u8, "\n", "\x0a")); | ||
| 189 | assert(mem.eql(u8, "\r", "\x0d")); | ||
| 190 | assert(mem.eql(u8, "\t", "\x09")); | ||
| 191 | assert(mem.eql(u8, "\\", "\x5c")); | ||
| 192 | assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "multiline string" { | ||
| 196 | const s1 = | ||
| 197 | \\one | ||
| 198 | \\two) | ||
| 199 | \\three | ||
| 200 | ; | ||
| 201 | const s2 = "one\ntwo)\nthree"; | ||
| 202 | assert(mem.eql(u8, s1, s2)); | ||
| 203 | } | ||
| 204 | |||
| 205 | test "multiline C string" { | ||
| 206 | const s1 = | ||
| 207 | c\\one | ||
| 208 | c\\two) | ||
| 209 | c\\three | ||
| 210 | ; | ||
| 211 | const s2 = c"one\ntwo)\nthree"; | ||
| 212 | assert(cstr.cmp(s1, s2) == 0); | ||
| 213 | } | ||
| 214 | |||
| 215 | test "type equality" { | ||
| 216 | assert(*const u8 != *u8); | ||
| 217 | } | ||
| 218 | |||
| 219 | const global_a: i32 = 1234; | ||
| 220 | const global_b: *const i32 = &global_a; | ||
| 221 | const global_c: *const f32 = @ptrCast(*const f32, global_b); | ||
| 222 | test "compile time global reinterpret" { | ||
| 223 | const d = @ptrCast(*const i32, global_c); | ||
| 224 | assert(d.* == 1234); | ||
| 225 | } | ||
| 226 | |||
| 227 | test "explicit cast maybe pointers" { | ||
| 228 | const a: ?*i32 = undefined; | ||
| 229 | const b: ?*f32 = @ptrCast(?*f32, a); | ||
| 230 | } | ||
| 231 | |||
| 232 | test "generic malloc free" { | ||
| 233 | const a = memAlloc(u8, 10) catch unreachable; | ||
| 234 | memFree(u8, a); | ||
| 235 | } | ||
| 236 | var some_mem: [100]u8 = undefined; | ||
| 237 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | ||
| 238 | return @ptrCast([*]T, &some_mem[0])[0..n]; | ||
| 239 | } | ||
| 240 | fn memFree(comptime T: type, memory: []T) void {} | ||
| 241 | |||
| 242 | test "cast undefined" { | ||
| 243 | const array: [100]u8 = undefined; | ||
| 244 | const slice = ([]const u8)(array); | ||
| 245 | testCastUndefined(slice); | ||
| 246 | } | ||
| 247 | fn testCastUndefined(x: []const u8) void {} | ||
| 248 | |||
| 249 | test "cast small unsigned to larger signed" { | ||
| 250 | assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); | ||
| 251 | assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); | ||
| 252 | } | ||
| 253 | fn castSmallUnsignedToLargerSigned1(x: u8) i16 { | ||
| 254 | return x; | ||
| 255 | } | ||
| 256 | fn castSmallUnsignedToLargerSigned2(x: u16) i64 { | ||
| 257 | return x; | ||
| 258 | } | ||
| 259 | |||
| 260 | test "implicit cast after unreachable" { | ||
| 261 | assert(outer() == 1234); | ||
| 262 | } | ||
| 263 | fn inner() i32 { | ||
| 264 | return 1234; | ||
| 265 | } | ||
| 266 | fn outer() i64 { | ||
| 267 | return inner(); | ||
| 268 | } | ||
| 269 | |||
| 270 | test "pointer dereferencing" { | ||
| 271 | var x = i32(3); | ||
| 272 | const y = &x; | ||
| 273 | |||
| 274 | y.* += 1; | ||
| 275 | |||
| 276 | assert(x == 4); | ||
| 277 | assert(y.* == 4); | ||
| 278 | } | ||
| 279 | |||
| 280 | test "call result of if else expression" { | ||
| 281 | assert(mem.eql(u8, f2(true), "a")); | ||
| 282 | assert(mem.eql(u8, f2(false), "b")); | ||
| 283 | } | ||
| 284 | fn f2(x: bool) []const u8 { | ||
| 285 | return (if (x) fA else fB)(); | ||
| 286 | } | ||
| 287 | fn fA() []const u8 { | ||
| 288 | return "a"; | ||
| 289 | } | ||
| 290 | fn fB() []const u8 { | ||
| 291 | return "b"; | ||
| 292 | } | ||
| 293 | |||
| 294 | test "const expression eval handling of variables" { | ||
| 295 | var x = true; | ||
| 296 | while (x) { | ||
| 297 | x = false; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | test "constant enum initialization with differing sizes" { | ||
| 302 | test3_1(test3_foo); | ||
| 303 | test3_2(test3_bar); | ||
| 304 | } | ||
| 305 | const Test3Foo = union(enum) { | ||
| 306 | One: void, | ||
| 307 | Two: f32, | ||
| 308 | Three: Test3Point, | ||
| 309 | }; | ||
| 310 | const Test3Point = struct { | ||
| 311 | x: i32, | ||
| 312 | y: i32, | ||
| 313 | }; | ||
| 314 | const test3_foo = Test3Foo{ | ||
| 315 | .Three = Test3Point{ | ||
| 316 | .x = 3, | ||
| 317 | .y = 4, | ||
| 318 | }, | ||
| 319 | }; | ||
| 320 | const test3_bar = Test3Foo{ .Two = 13 }; | ||
| 321 | fn test3_1(f: Test3Foo) void { | ||
| 322 | switch (f) { | ||
| 323 | Test3Foo.Three => |pt| { | ||
| 324 | assert(pt.x == 3); | ||
| 325 | assert(pt.y == 4); | ||
| 326 | }, | ||
| 327 | else => unreachable, | ||
| 328 | } | ||
| 329 | } | ||
| 330 | fn test3_2(f: Test3Foo) void { | ||
| 331 | switch (f) { | ||
| 332 | Test3Foo.Two => |x| { | ||
| 333 | assert(x == 13); | ||
| 334 | }, | ||
| 335 | else => unreachable, | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | test "character literals" { | ||
| 340 | assert('\'' == single_quote); | ||
| 341 | } | ||
| 342 | const single_quote = '\''; | ||
| 343 | |||
| 344 | test "take address of parameter" { | ||
| 345 | testTakeAddressOfParameter(12.34); | ||
| 346 | } | ||
| 347 | fn testTakeAddressOfParameter(f: f32) void { | ||
| 348 | const f_ptr = &f; | ||
| 349 | assert(f_ptr.* == 12.34); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "pointer comparison" { | ||
| 353 | const a = ([]const u8)("a"); | ||
| 354 | const b = &a; | ||
| 355 | assert(ptrEql(b, b)); | ||
| 356 | } | ||
| 357 | fn ptrEql(a: *const []const u8, b: *const []const u8) bool { | ||
| 358 | return a == b; | ||
| 359 | } | ||
| 360 | |||
| 361 | test "C string concatenation" { | ||
| 362 | const a = c"OK" ++ c" IT " ++ c"WORKED"; | ||
| 363 | const b = c"OK IT WORKED"; | ||
| 364 | |||
| 365 | const len = cstr.len(b); | ||
| 366 | const len_with_null = len + 1; | ||
| 367 | { | ||
| 368 | var i: u32 = 0; | ||
| 369 | while (i < len_with_null) : (i += 1) { | ||
| 370 | assert(a[i] == b[i]); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | assert(a[len] == 0); | ||
| 374 | assert(b[len] == 0); | ||
| 375 | } | ||
| 376 | |||
| 377 | test "cast slice to u8 slice" { | ||
| 378 | assert(@sizeOf(i32) == 4); | ||
| 379 | var big_thing_array = []i32{ | ||
| 380 | 1, | ||
| 381 | 2, | ||
| 382 | 3, | ||
| 383 | 4, | ||
| 384 | }; | ||
| 385 | const big_thing_slice: []i32 = big_thing_array[0..]; | ||
| 386 | const bytes = @sliceToBytes(big_thing_slice); | ||
| 387 | assert(bytes.len == 4 * 4); | ||
| 388 | bytes[4] = 0; | ||
| 389 | bytes[5] = 0; | ||
| 390 | bytes[6] = 0; | ||
| 391 | bytes[7] = 0; | ||
| 392 | assert(big_thing_slice[1] == 0); | ||
| 393 | const big_thing_again = @bytesToSlice(i32, bytes); | ||
| 394 | assert(big_thing_again[2] == 3); | ||
| 395 | big_thing_again[2] = -1; | ||
| 396 | assert(bytes[8] == maxInt(u8)); | ||
| 397 | assert(bytes[9] == maxInt(u8)); | ||
| 398 | assert(bytes[10] == maxInt(u8)); | ||
| 399 | assert(bytes[11] == maxInt(u8)); | ||
| 400 | } | ||
| 401 | |||
| 402 | test "pointer to void return type" { | ||
| 403 | testPointerToVoidReturnType() catch unreachable; | ||
| 404 | } | ||
| 405 | fn testPointerToVoidReturnType() anyerror!void { | ||
| 406 | const a = testPointerToVoidReturnType2(); | ||
| 407 | return a.*; | ||
| 408 | } | ||
| 409 | const test_pointer_to_void_return_type_x = void{}; | ||
| 410 | fn testPointerToVoidReturnType2() *const void { | ||
| 411 | return &test_pointer_to_void_return_type_x; | ||
| 412 | } | ||
| 413 | |||
| 414 | test "non const ptr to aliased type" { | ||
| 415 | const int = i32; | ||
| 416 | assert(?*int == ?*i32); | ||
| 417 | } | ||
| 418 | |||
| 419 | test "array 2D const double ptr" { | ||
| 420 | const rect_2d_vertexes = [][1]f32{ | ||
| 421 | []f32{1.0}, | ||
| 422 | []f32{2.0}, | ||
| 423 | }; | ||
| 424 | testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); | ||
| 425 | } | ||
| 426 | |||
| 427 | fn testArray2DConstDoublePtr(ptr: *const f32) void { | ||
| 428 | const ptr2 = @ptrCast([*]const f32, ptr); | ||
| 429 | assert(ptr2[0] == 1.0); | ||
| 430 | assert(ptr2[1] == 2.0); | ||
| 431 | } | ||
| 432 | |||
| 433 | const Tid = builtin.TypeId; | ||
| 434 | const AStruct = struct { | ||
| 435 | x: i32, | ||
| 436 | }; | ||
| 437 | const AnEnum = enum { | ||
| 438 | One, | ||
| 439 | Two, | ||
| 440 | }; | ||
| 441 | const AUnionEnum = union(enum) { | ||
| 442 | One: i32, | ||
| 443 | Two: void, | ||
| 444 | }; | ||
| 445 | const AUnion = union { | ||
| 446 | One: void, | ||
| 447 | Two: void, | ||
| 448 | }; | ||
| 449 | |||
| 450 | test "@typeId" { | ||
| 451 | comptime { | ||
| 452 | assert(@typeId(type) == Tid.Type); | ||
| 453 | assert(@typeId(void) == Tid.Void); | ||
| 454 | assert(@typeId(bool) == Tid.Bool); | ||
| 455 | assert(@typeId(noreturn) == Tid.NoReturn); | ||
| 456 | assert(@typeId(i8) == Tid.Int); | ||
| 457 | assert(@typeId(u8) == Tid.Int); | ||
| 458 | assert(@typeId(i64) == Tid.Int); | ||
| 459 | assert(@typeId(u64) == Tid.Int); | ||
| 460 | assert(@typeId(f32) == Tid.Float); | ||
| 461 | assert(@typeId(f64) == Tid.Float); | ||
| 462 | assert(@typeId(*f32) == Tid.Pointer); | ||
| 463 | assert(@typeId([2]u8) == Tid.Array); | ||
| 464 | assert(@typeId(AStruct) == Tid.Struct); | ||
| 465 | assert(@typeId(@typeOf(1)) == Tid.ComptimeInt); | ||
| 466 | assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); | ||
| 467 | assert(@typeId(@typeOf(undefined)) == Tid.Undefined); | ||
| 468 | assert(@typeId(@typeOf(null)) == Tid.Null); | ||
| 469 | assert(@typeId(?i32) == Tid.Optional); | ||
| 470 | assert(@typeId(anyerror!i32) == Tid.ErrorUnion); | ||
| 471 | assert(@typeId(anyerror) == Tid.ErrorSet); | ||
| 472 | assert(@typeId(AnEnum) == Tid.Enum); | ||
| 473 | assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); | ||
| 474 | assert(@typeId(AUnionEnum) == Tid.Union); | ||
| 475 | assert(@typeId(AUnion) == Tid.Union); | ||
| 476 | assert(@typeId(fn () void) == Tid.Fn); | ||
| 477 | assert(@typeId(@typeOf(builtin)) == Tid.Namespace); | ||
| 478 | // TODO bound fn | ||
| 479 | // TODO arg tuple | ||
| 480 | // TODO opaque | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | test "@typeName" { | ||
| 485 | const Struct = struct {}; | ||
| 486 | const Union = union { | ||
| 487 | unused: u8, | ||
| 488 | }; | ||
| 489 | const Enum = enum { | ||
| 490 | Unused, | ||
| 491 | }; | ||
| 492 | comptime { | ||
| 493 | assert(mem.eql(u8, @typeName(i64), "i64")); | ||
| 494 | assert(mem.eql(u8, @typeName(*usize), "*usize")); | ||
| 495 | // https://github.com/ziglang/zig/issues/675 | ||
| 496 | assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); | ||
| 497 | assert(mem.eql(u8, @typeName(Struct), "Struct")); | ||
| 498 | assert(mem.eql(u8, @typeName(Union), "Union")); | ||
| 499 | assert(mem.eql(u8, @typeName(Enum), "Enum")); | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | fn TypeFromFn(comptime T: type) type { | ||
| 504 | return struct {}; | ||
| 505 | } | ||
| 506 | |||
| 507 | test "volatile load and store" { | ||
| 508 | var number: i32 = 1234; | ||
| 509 | const ptr = (*volatile i32)(&number); | ||
| 510 | ptr.* += 1; | ||
| 511 | assert(ptr.* == 1235); | ||
| 512 | } | ||
| 513 | |||
| 514 | test "slice string literal has type []const u8" { | ||
| 515 | comptime { | ||
| 516 | assert(@typeOf("aoeu"[0..]) == []const u8); | ||
| 517 | const array = []i32{ | ||
| 518 | 1, | ||
| 519 | 2, | ||
| 520 | 3, | ||
| 521 | 4, | ||
| 522 | }; | ||
| 523 | assert(@typeOf(array[0..]) == []const i32); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | test "global variable initialized to global variable array element" { | ||
| 528 | assert(global_ptr == &gdt[0]); | ||
| 529 | } | ||
| 530 | const GDTEntry = struct { | ||
| 531 | field: i32, | ||
| 532 | }; | ||
| 533 | var gdt = []GDTEntry{ | ||
| 534 | GDTEntry{ .field = 1 }, | ||
| 535 | GDTEntry{ .field = 2 }, | ||
| 536 | }; | ||
| 537 | var global_ptr = &gdt[0]; | ||
| 538 | |||
| 539 | // can't really run this test but we can make sure it has no compile error | ||
| 540 | // and generates code | ||
| 541 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 542 | export fn writeToVRam() void { | ||
| 543 | vram[0] = 'X'; | ||
| 544 | } | ||
| 545 | |||
| 546 | test "pointer child field" { | ||
| 547 | assert((*u32).Child == u32); | ||
| 548 | } | ||
| 549 | |||
| 550 | const OpaqueA = @OpaqueType(); | ||
| 551 | const OpaqueB = @OpaqueType(); | ||
| 552 | test "@OpaqueType" { | ||
| 553 | assert(*OpaqueA != *OpaqueB); | ||
| 554 | assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); | ||
| 555 | assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | ||
| 556 | } | ||
| 557 | |||
| 558 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 559 | var x: i32 = 1234; | ||
| 560 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 561 | } | ||
| 562 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 563 | var a = ptr; | ||
| 564 | return a; | ||
| 565 | } | ||
| 566 | |||
| 567 | test "comptime if inside runtime while which unconditionally breaks" { | ||
| 568 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 569 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 570 | } | ||
| 571 | fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { | ||
| 572 | while (cond) { | ||
| 573 | if (false) {} | ||
| 574 | break; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | test "implicit comptime while" { | ||
| 579 | while (false) { | ||
| 580 | @compileError("bad"); | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | test "struct inside function" { | ||
| 585 | testStructInFn(); | ||
| 586 | comptime testStructInFn(); | ||
| 587 | } | ||
| 588 | |||
| 589 | fn testStructInFn() void { | ||
| 590 | const BlockKind = u32; | ||
| 591 | |||
| 592 | const Block = struct { | ||
| 593 | kind: BlockKind, | ||
| 594 | }; | ||
| 595 | |||
| 596 | var block = Block{ .kind = 1234 }; | ||
| 597 | |||
| 598 | block.kind += 1; | ||
| 599 | |||
| 600 | assert(block.kind == 1235); | ||
| 601 | } | ||
| 602 | |||
| 603 | fn fnThatClosesOverLocalConst() type { | ||
| 604 | const c = 1; | ||
| 605 | return struct { | ||
| 606 | fn g() i32 { | ||
| 607 | return c; | ||
| 608 | } | ||
| 609 | }; | ||
| 610 | } | ||
| 611 | |||
| 612 | test "function closes over local const" { | ||
| 613 | const x = fnThatClosesOverLocalConst().g(); | ||
| 614 | assert(x == 1); | ||
| 615 | } | ||
| 616 | |||
| 617 | test "cold function" { | ||
| 618 | thisIsAColdFn(); | ||
| 619 | comptime thisIsAColdFn(); | ||
| 620 | } | ||
| 621 | |||
| 622 | fn thisIsAColdFn() void { | ||
| 623 | @setCold(true); | ||
| 624 | } | ||
| 625 | |||
| 626 | const PackedStruct = packed struct { | ||
| 627 | a: u8, | ||
| 628 | b: u8, | ||
| 629 | }; | ||
| 630 | const PackedUnion = packed union { | ||
| 631 | a: u8, | ||
| 632 | b: u32, | ||
| 633 | }; | ||
| 634 | const PackedEnum = packed enum { | ||
| 635 | A, | ||
| 636 | B, | ||
| 637 | }; | ||
| 638 | |||
| 639 | test "packed struct, enum, union parameters in extern function" { | ||
| 640 | testPackedStuff(&(PackedStruct{ | ||
| 641 | .a = 1, | ||
| 642 | .b = 2, | ||
| 643 | }), &(PackedUnion{ .a = 1 }), PackedEnum.A); | ||
| 644 | } | ||
| 645 | |||
| 646 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} | ||
| 647 | |||
| 648 | test "slicing zero length array" { | ||
| 649 | const s1 = ""[0..]; | ||
| 650 | const s2 = ([]u32{})[0..]; | ||
| 651 | assert(s1.len == 0); | ||
| 652 | assert(s2.len == 0); | ||
| 653 | assert(mem.eql(u8, s1, "")); | ||
| 654 | assert(mem.eql(u32, s2, []u32{})); | ||
| 655 | } | ||
| 656 | |||
| 657 | const addr1 = @ptrCast(*const u8, emptyFn); | ||
| 658 | test "comptime cast fn to ptr" { | ||
| 659 | const addr2 = @ptrCast(*const u8, emptyFn); | ||
| 660 | comptime assert(addr1 == addr2); | ||
| 661 | } | ||
| 662 | |||
| 663 | test "equality compare fn ptrs" { | ||
| 664 | var a = emptyFn; | ||
| 665 | assert(a == a); | ||
| 666 | } | ||
| 667 | |||
| 668 | test "self reference through fn ptr field" { | ||
| 669 | const S = struct { | ||
| 670 | const A = struct { | ||
| 671 | f: fn (A) u8, | ||
| 672 | }; | ||
| 673 | |||
| 674 | fn foo(a: A) u8 { | ||
| 675 | return 12; | ||
| 676 | } | ||
| 677 | }; | ||
| 678 | var a: S.A = undefined; | ||
| 679 | a.f = S.foo; | ||
| 680 | assert(a.f(a) == 12); | ||
| 681 | } | ||
test/cases/namespace_depends_on_compile_var/a.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const a_bool = true; | ||
test/cases/namespace_depends_on_compile_var/b.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const a_bool = false; | ||
test/cases/namespace_depends_on_compile_var/index.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const assert = @import("std").debug.assert; | ||
| 3 | |||
| 4 | test "namespace depends on compile var" { | ||
| 5 | if (some_namespace.a_bool) { | ||
| 6 | assert(some_namespace.a_bool); | ||
| 7 | } else { | ||
| 8 | assert(!some_namespace.a_bool); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | const some_namespace = switch (builtin.os) { | ||
| 12 | builtin.Os.linux => @import("a.zig"), | ||
| 13 | else => @import("b.zig"), | ||
| 14 | }; | ||
test/cases/new_stack_call.zig deleted-26| ... | @@ -1,26 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | var new_stack_bytes: [1024]u8 = undefined; | ||
| 5 | |||
| 6 | test "calling a function with a new stack" { | ||
| 7 | const arg = 1234; | ||
| 8 | |||
| 9 | const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); | ||
| 10 | const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); | ||
| 11 | _ = targetFunction(arg); | ||
| 12 | |||
| 13 | assert(arg == 1234); | ||
| 14 | assert(a < b); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn targetFunction(x: i32) usize { | ||
| 18 | assert(x == 1234); | ||
| 19 | |||
| 20 | var local_variable: i32 = 42; | ||
| 21 | const ptr = &local_variable; | ||
| 22 | ptr.* += 1; | ||
| 23 | |||
| 24 | assert(local_variable == 43); | ||
| 25 | return @ptrToInt(ptr); | ||
| 26 | } | ||
test/cases/null.zig deleted-162| ... | @@ -1,162 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "optional type" { | ||
| 4 | const x: ?bool = true; | ||
| 5 | |||
| 6 | if (x) |y| { | ||
| 7 | if (y) { | ||
| 8 | // OK | ||
| 9 | } else { | ||
| 10 | unreachable; | ||
| 11 | } | ||
| 12 | } else { | ||
| 13 | unreachable; | ||
| 14 | } | ||
| 15 | |||
| 16 | const next_x: ?i32 = null; | ||
| 17 | |||
| 18 | const z = next_x orelse 1234; | ||
| 19 | |||
| 20 | assert(z == 1234); | ||
| 21 | |||
| 22 | const final_x: ?i32 = 13; | ||
| 23 | |||
| 24 | const num = final_x orelse unreachable; | ||
| 25 | |||
| 26 | assert(num == 13); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "test maybe object and get a pointer to the inner value" { | ||
| 30 | var maybe_bool: ?bool = true; | ||
| 31 | |||
| 32 | if (maybe_bool) |*b| { | ||
| 33 | b.* = false; | ||
| 34 | } | ||
| 35 | |||
| 36 | assert(maybe_bool.? == false); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "rhs maybe unwrap return" { | ||
| 40 | const x: ?bool = true; | ||
| 41 | const y = x orelse return; | ||
| 42 | } | ||
| 43 | |||
| 44 | test "maybe return" { | ||
| 45 | maybeReturnImpl(); | ||
| 46 | comptime maybeReturnImpl(); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn maybeReturnImpl() void { | ||
| 50 | assert(foo(1235).?); | ||
| 51 | if (foo(null) != null) unreachable; | ||
| 52 | assert(!foo(1234).?); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn foo(x: ?i32) ?bool { | ||
| 56 | const value = x orelse return null; | ||
| 57 | return value > 1234; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "if var maybe pointer" { | ||
| 61 | assert(shouldBeAPlus1(Particle{ | ||
| 62 | .a = 14, | ||
| 63 | .b = 1, | ||
| 64 | .c = 1, | ||
| 65 | .d = 1, | ||
| 66 | }) == 15); | ||
| 67 | } | ||
| 68 | fn shouldBeAPlus1(p: Particle) u64 { | ||
| 69 | var maybe_particle: ?Particle = p; | ||
| 70 | if (maybe_particle) |*particle| { | ||
| 71 | particle.a += 1; | ||
| 72 | } | ||
| 73 | if (maybe_particle) |particle| { | ||
| 74 | return particle.a; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | const Particle = struct { | ||
| 79 | a: u64, | ||
| 80 | b: u64, | ||
| 81 | c: u64, | ||
| 82 | d: u64, | ||
| 83 | }; | ||
| 84 | |||
| 85 | test "null literal outside function" { | ||
| 86 | const is_null = here_is_a_null_literal.context == null; | ||
| 87 | assert(is_null); | ||
| 88 | |||
| 89 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 90 | assert(!is_non_null); | ||
| 91 | } | ||
| 92 | const SillyStruct = struct { | ||
| 93 | context: ?i32, | ||
| 94 | }; | ||
| 95 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 96 | |||
| 97 | test "test null runtime" { | ||
| 98 | testTestNullRuntime(null); | ||
| 99 | } | ||
| 100 | fn testTestNullRuntime(x: ?i32) void { | ||
| 101 | assert(x == null); | ||
| 102 | assert(!(x != null)); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "optional void" { | ||
| 106 | optionalVoidImpl(); | ||
| 107 | comptime optionalVoidImpl(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn optionalVoidImpl() void { | ||
| 111 | assert(bar(null) == null); | ||
| 112 | assert(bar({}) != null); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn bar(x: ?void) ?void { | ||
| 116 | if (x) |_| { | ||
| 117 | return {}; | ||
| 118 | } else { | ||
| 119 | return null; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | const StructWithOptional = struct { | ||
| 124 | field: ?i32, | ||
| 125 | }; | ||
| 126 | |||
| 127 | var struct_with_optional: StructWithOptional = undefined; | ||
| 128 | |||
| 129 | test "unwrap optional which is field of global var" { | ||
| 130 | struct_with_optional.field = null; | ||
| 131 | if (struct_with_optional.field) |payload| { | ||
| 132 | unreachable; | ||
| 133 | } | ||
| 134 | struct_with_optional.field = 1234; | ||
| 135 | if (struct_with_optional.field) |payload| { | ||
| 136 | assert(payload == 1234); | ||
| 137 | } else { | ||
| 138 | unreachable; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | test "null with default unwrap" { | ||
| 143 | const x: i32 = null orelse 1; | ||
| 144 | assert(x == 1); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "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 | |||
| 154 | const StructWithOptionalType = struct { | ||
| 155 | t: ?type, | ||
| 156 | }; | ||
| 157 | |||
| 158 | test "optional pointer to 0 bit type null value at runtime" { | ||
| 159 | const EmptyStruct = struct {}; | ||
| 160 | var x: ?*EmptyStruct = null; | ||
| 161 | assert(x == null); | ||
| 162 | } | ||
test/cases/optional.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | pub const EmptyStruct = struct {}; | ||
| 4 | |||
| 5 | test "optional pointer to size zero struct" { | ||
| 6 | var e = EmptyStruct{}; | ||
| 7 | var o: ?*EmptyStruct = &e; | ||
| 8 | assert(o != null); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "equality compare nullable pointers" { | ||
| 12 | testNullPtrsEql(); | ||
| 13 | comptime testNullPtrsEql(); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn testNullPtrsEql() void { | ||
| 17 | var number: i32 = 1234; | ||
| 18 | |||
| 19 | var x: ?*i32 = null; | ||
| 20 | var y: ?*i32 = null; | ||
| 21 | assert(x == y); | ||
| 22 | y = &number; | ||
| 23 | assert(x != y); | ||
| 24 | assert(x != &number); | ||
| 25 | assert(&number != x); | ||
| 26 | x = &number; | ||
| 27 | assert(x == y); | ||
| 28 | assert(x == &number); | ||
| 29 | assert(&number == x); | ||
| 30 | } | ||
test/cases/pointers.zig deleted-44| ... | @@ -1,44 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | test "dereference pointer" { | ||
| 5 | comptime testDerefPtr(); | ||
| 6 | testDerefPtr(); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn testDerefPtr() void { | ||
| 10 | var x: i32 = 1234; | ||
| 11 | var y = &x; | ||
| 12 | y.* += 1; | ||
| 13 | assert(x == 1235); | ||
| 14 | } | ||
| 15 | |||
| 16 | test "pointer arithmetic" { | ||
| 17 | var ptr = c"abcd"; | ||
| 18 | |||
| 19 | assert(ptr[0] == 'a'); | ||
| 20 | ptr += 1; | ||
| 21 | assert(ptr[0] == 'b'); | ||
| 22 | ptr += 1; | ||
| 23 | assert(ptr[0] == 'c'); | ||
| 24 | ptr += 1; | ||
| 25 | assert(ptr[0] == 'd'); | ||
| 26 | ptr += 1; | ||
| 27 | assert(ptr[0] == 0); | ||
| 28 | ptr -= 1; | ||
| 29 | assert(ptr[0] == 'd'); | ||
| 30 | ptr -= 1; | ||
| 31 | assert(ptr[0] == 'c'); | ||
| 32 | ptr -= 1; | ||
| 33 | assert(ptr[0] == 'b'); | ||
| 34 | ptr -= 1; | ||
| 35 | assert(ptr[0] == 'a'); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "double pointer parsing" { | ||
| 39 | comptime assert(PtrOf(PtrOf(i32)) == **i32); | ||
| 40 | } | ||
| 41 | |||
| 42 | fn PtrOf(comptime T: type) type { | ||
| 43 | return *T; | ||
| 44 | } | ||
test/cases/popcount.zig deleted-24| ... | @@ -1,24 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "@popCount" { | ||
| 4 | comptime testPopCount(); | ||
| 5 | testPopCount(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testPopCount() void { | ||
| 9 | { | ||
| 10 | var x: u32 = 0xaa; | ||
| 11 | assert(@popCount(x) == 4); | ||
| 12 | } | ||
| 13 | { | ||
| 14 | var x: u32 = 0xaaaaaaaa; | ||
| 15 | assert(@popCount(x) == 16); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var x: i16 = -1; | ||
| 19 | assert(@popCount(x) == 16); | ||
| 20 | } | ||
| 21 | comptime { | ||
| 22 | assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); | ||
| 23 | } | ||
| 24 | } | ||
test/cases/ptrcast.zig deleted-52| ... | @@ -1,52 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | test "reinterpret bytes as integer with nonzero offset" { | ||
| 6 | testReinterpretBytesAsInteger(); | ||
| 7 | comptime testReinterpretBytesAsInteger(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testReinterpretBytesAsInteger() void { | ||
| 11 | const bytes = "\x12\x34\x56\x78\xab"; | ||
| 12 | const expected = switch (builtin.endian) { | ||
| 13 | builtin.Endian.Little => 0xab785634, | ||
| 14 | builtin.Endian.Big => 0x345678ab, | ||
| 15 | }; | ||
| 16 | assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "reinterpret bytes of an array into an extern struct" { | ||
| 20 | testReinterpretBytesAsExternStruct(); | ||
| 21 | comptime testReinterpretBytesAsExternStruct(); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn testReinterpretBytesAsExternStruct() void { | ||
| 25 | var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; | ||
| 26 | |||
| 27 | const S = extern struct { | ||
| 28 | a: u8, | ||
| 29 | b: u16, | ||
| 30 | c: u8, | ||
| 31 | }; | ||
| 32 | |||
| 33 | var ptr = @ptrCast(*const S, &bytes); | ||
| 34 | var val = ptr.c; | ||
| 35 | assertOrPanic(val == 5); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "reinterpret struct field at comptime" { | ||
| 39 | const numLittle = comptime Bytes.init(0x12345678); | ||
| 40 | assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); | ||
| 41 | } | ||
| 42 | |||
| 43 | const Bytes = struct { | ||
| 44 | bytes: [4]u8, | ||
| 45 | |||
| 46 | pub fn init(v: u32) Bytes { | ||
| 47 | var res: Bytes = undefined; | ||
| 48 | @ptrCast(*align(1) u32, &res.bytes).* = v; | ||
| 49 | |||
| 50 | return res; | ||
| 51 | } | ||
| 52 | }; | ||
test/cases/pub_enum/index.zig deleted-13| ... | @@ -1,13 +0,0 @@ | ||
| 1 | const other = @import("other.zig"); | ||
| 2 | const assert = @import("std").debug.assert; | ||
| 3 | |||
| 4 | test "pub enum" { | ||
| 5 | pubEnumTest(other.APubEnum.Two); | ||
| 6 | } | ||
| 7 | fn pubEnumTest(foo: other.APubEnum) void { | ||
| 8 | assert(foo == other.APubEnum.Two); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "cast with imported symbol" { | ||
| 12 | assert(other.size_t(42) == 42); | ||
| 13 | } | ||
test/cases/pub_enum/other.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | pub const APubEnum = enum { | ||
| 2 | One, | ||
| 3 | Two, | ||
| 4 | Three, | ||
| 5 | }; | ||
| 6 | pub const size_t = u64; | ||
test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | var ok: bool = false; | ||
| 5 | test "reference a variable in an if after an if in the 2nd switch prong" { | ||
| 6 | foo(true, Num.Two, false, "aoeu"); | ||
| 7 | assert(!ok); | ||
| 8 | foo(false, Num.One, false, "aoeu"); | ||
| 9 | assert(!ok); | ||
| 10 | foo(true, Num.One, false, "aoeu"); | ||
| 11 | assert(ok); | ||
| 12 | } | ||
| 13 | |||
| 14 | const Num = enum { | ||
| 15 | One, | ||
| 16 | Two, | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { | ||
| 20 | switch (k) { | ||
| 21 | Num.Two => {}, | ||
| 22 | Num.One => { | ||
| 23 | if (c) { | ||
| 24 | const output_path = b; | ||
| 25 | |||
| 26 | if (c2) {} | ||
| 27 | |||
| 28 | a(output_path); | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn a(x: []const u8) void { | ||
| 35 | assert(mem.eql(u8, x, "aoeu")); | ||
| 36 | ok = true; | ||
| 37 | } | ||
test/cases/reflection.zig deleted-95| ... | @@ -1,95 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const reflection = @This(); | ||
| 4 | |||
| 5 | test "reflection: array, pointer, optional, error union type child" { | ||
| 6 | comptime { | ||
| 7 | assert(([10]u8).Child == u8); | ||
| 8 | assert((*u8).Child == u8); | ||
| 9 | assert((anyerror!u8).Payload == u8); | ||
| 10 | assert((?u8).Child == u8); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "reflection: function return type, var args, and param types" { | ||
| 15 | comptime { | ||
| 16 | assert(@typeOf(dummy).ReturnType == i32); | ||
| 17 | assert(!@typeOf(dummy).is_var_args); | ||
| 18 | assert(@typeOf(dummy_varargs).is_var_args); | ||
| 19 | assert(@typeOf(dummy).arg_count == 3); | ||
| 20 | assert(@ArgType(@typeOf(dummy), 0) == bool); | ||
| 21 | assert(@ArgType(@typeOf(dummy), 1) == i32); | ||
| 22 | assert(@ArgType(@typeOf(dummy), 2) == f32); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | fn dummy(a: bool, b: i32, c: f32) i32 { | ||
| 27 | return 1234; | ||
| 28 | } | ||
| 29 | fn dummy_varargs(args: ...) void {} | ||
| 30 | |||
| 31 | test "reflection: struct member types and names" { | ||
| 32 | comptime { | ||
| 33 | assert(@memberCount(Foo) == 3); | ||
| 34 | |||
| 35 | assert(@memberType(Foo, 0) == i32); | ||
| 36 | assert(@memberType(Foo, 1) == bool); | ||
| 37 | assert(@memberType(Foo, 2) == void); | ||
| 38 | |||
| 39 | assert(mem.eql(u8, @memberName(Foo, 0), "one")); | ||
| 40 | assert(mem.eql(u8, @memberName(Foo, 1), "two")); | ||
| 41 | assert(mem.eql(u8, @memberName(Foo, 2), "three")); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | test "reflection: enum member types and names" { | ||
| 46 | comptime { | ||
| 47 | assert(@memberCount(Bar) == 4); | ||
| 48 | |||
| 49 | assert(@memberType(Bar, 0) == void); | ||
| 50 | assert(@memberType(Bar, 1) == i32); | ||
| 51 | assert(@memberType(Bar, 2) == bool); | ||
| 52 | assert(@memberType(Bar, 3) == f64); | ||
| 53 | |||
| 54 | assert(mem.eql(u8, @memberName(Bar, 0), "One")); | ||
| 55 | assert(mem.eql(u8, @memberName(Bar, 1), "Two")); | ||
| 56 | assert(mem.eql(u8, @memberName(Bar, 2), "Three")); | ||
| 57 | assert(mem.eql(u8, @memberName(Bar, 3), "Four")); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "reflection: @field" { | ||
| 62 | var f = Foo{ | ||
| 63 | .one = 42, | ||
| 64 | .two = true, | ||
| 65 | .three = void{}, | ||
| 66 | }; | ||
| 67 | |||
| 68 | assert(f.one == f.one); | ||
| 69 | assert(@field(f, "o" ++ "ne") == f.one); | ||
| 70 | assert(@field(f, "t" ++ "wo") == f.two); | ||
| 71 | assert(@field(f, "th" ++ "ree") == f.three); | ||
| 72 | assert(@field(Foo, "const" ++ "ant") == Foo.constant); | ||
| 73 | assert(@field(Bar, "O" ++ "ne") == Bar.One); | ||
| 74 | assert(@field(Bar, "T" ++ "wo") == Bar.Two); | ||
| 75 | assert(@field(Bar, "Th" ++ "ree") == Bar.Three); | ||
| 76 | assert(@field(Bar, "F" ++ "our") == Bar.Four); | ||
| 77 | assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); | ||
| 78 | @field(f, "o" ++ "ne") = 4; | ||
| 79 | assert(f.one == 4); | ||
| 80 | } | ||
| 81 | |||
| 82 | const Foo = struct { | ||
| 83 | const constant = 52; | ||
| 84 | |||
| 85 | one: i32, | ||
| 86 | two: bool, | ||
| 87 | three: void, | ||
| 88 | }; | ||
| 89 | |||
| 90 | const Bar = union(enum) { | ||
| 91 | One: void, | ||
| 92 | Two: i32, | ||
| 93 | Three: bool, | ||
| 94 | Four: f64, | ||
| 95 | }; | ||
test/cases/sizeof_and_typeof.zig deleted-69| ... | @@ -1,69 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const assert = @import("std").debug.assert; | ||
| 3 | |||
| 4 | test "@sizeOf and @typeOf" { | ||
| 5 | const y: @typeOf(x) = 120; | ||
| 6 | assert(@sizeOf(@typeOf(y)) == 2); | ||
| 7 | } | ||
| 8 | const x: u16 = 13; | ||
| 9 | const z: @typeOf(x) = 19; | ||
| 10 | |||
| 11 | const A = struct { | ||
| 12 | a: u8, | ||
| 13 | b: u32, | ||
| 14 | c: u8, | ||
| 15 | d: u3, | ||
| 16 | e: u5, | ||
| 17 | f: u16, | ||
| 18 | g: u16, | ||
| 19 | }; | ||
| 20 | |||
| 21 | const P = packed struct { | ||
| 22 | a: u8, | ||
| 23 | b: u32, | ||
| 24 | c: u8, | ||
| 25 | d: u3, | ||
| 26 | e: u5, | ||
| 27 | f: u16, | ||
| 28 | g: u16, | ||
| 29 | }; | ||
| 30 | |||
| 31 | test "@byteOffsetOf" { | ||
| 32 | // Packed structs have fixed memory layout | ||
| 33 | assert(@byteOffsetOf(P, "a") == 0); | ||
| 34 | assert(@byteOffsetOf(P, "b") == 1); | ||
| 35 | assert(@byteOffsetOf(P, "c") == 5); | ||
| 36 | assert(@byteOffsetOf(P, "d") == 6); | ||
| 37 | assert(@byteOffsetOf(P, "e") == 6); | ||
| 38 | assert(@byteOffsetOf(P, "f") == 7); | ||
| 39 | assert(@byteOffsetOf(P, "g") == 9); | ||
| 40 | |||
| 41 | // Normal struct fields can be moved/padded | ||
| 42 | var a: A = undefined; | ||
| 43 | assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); | ||
| 44 | assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); | ||
| 45 | assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); | ||
| 46 | assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); | ||
| 47 | assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); | ||
| 48 | assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); | ||
| 49 | assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "@bitOffsetOf" { | ||
| 53 | // Packed structs have fixed memory layout | ||
| 54 | assert(@bitOffsetOf(P, "a") == 0); | ||
| 55 | assert(@bitOffsetOf(P, "b") == 8); | ||
| 56 | assert(@bitOffsetOf(P, "c") == 40); | ||
| 57 | assert(@bitOffsetOf(P, "d") == 48); | ||
| 58 | assert(@bitOffsetOf(P, "e") == 51); | ||
| 59 | assert(@bitOffsetOf(P, "f") == 56); | ||
| 60 | assert(@bitOffsetOf(P, "g") == 72); | ||
| 61 | |||
| 62 | assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 63 | assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 64 | assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 65 | assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 66 | assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 67 | assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 68 | assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 69 | } | ||
test/cases/slice.zig deleted-40| ... | @@ -1,40 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | ||
| 5 | const y = x[0x100..]; | ||
| 6 | test "compile time slice of pointer to hard coded address" { | ||
| 7 | assert(@ptrToInt(x.ptr) == 0x1000); | ||
| 8 | assert(x.len == 0x500); | ||
| 9 | |||
| 10 | assert(@ptrToInt(y.ptr) == 0x1100); | ||
| 11 | assert(y.len == 0x400); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "slice child property" { | ||
| 15 | var array: [5]i32 = undefined; | ||
| 16 | var slice = array[0..]; | ||
| 17 | assert(@typeOf(slice).Child == i32); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "runtime safety lets us slice from len..len" { | ||
| 21 | var an_array = []u8{ | ||
| 22 | 1, | ||
| 23 | 2, | ||
| 24 | 3, | ||
| 25 | }; | ||
| 26 | assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | ||
| 30 | return a_slice[start..end]; | ||
| 31 | } | ||
| 32 | |||
| 33 | test "implicitly cast array of size 0 to slice" { | ||
| 34 | var msg = []u8{}; | ||
| 35 | assertLenIsZero(msg); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn assertLenIsZero(msg: []const u8) void { | ||
| 39 | assert(msg.len == 0); | ||
| 40 | } | ||
test/cases/struct.zig deleted-470| ... | @@ -1,470 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | const StructWithNoFields = struct { | ||
| 7 | fn add(a: i32, b: i32) i32 { | ||
| 8 | return a + b; | ||
| 9 | } | ||
| 10 | }; | ||
| 11 | const empty_global_instance = StructWithNoFields{}; | ||
| 12 | |||
| 13 | test "call struct static method" { | ||
| 14 | const result = StructWithNoFields.add(3, 4); | ||
| 15 | assert(result == 7); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "return empty struct instance" { | ||
| 19 | _ = returnEmptyStructInstance(); | ||
| 20 | } | ||
| 21 | fn returnEmptyStructInstance() StructWithNoFields { | ||
| 22 | return empty_global_instance; | ||
| 23 | } | ||
| 24 | |||
| 25 | const should_be_11 = StructWithNoFields.add(5, 6); | ||
| 26 | |||
| 27 | test "invake static method in global scope" { | ||
| 28 | assert(should_be_11 == 11); | ||
| 29 | } | ||
| 30 | |||
| 31 | test "void struct fields" { | ||
| 32 | const foo = VoidStructFieldsFoo{ | ||
| 33 | .a = void{}, | ||
| 34 | .b = 1, | ||
| 35 | .c = void{}, | ||
| 36 | }; | ||
| 37 | assert(foo.b == 1); | ||
| 38 | assert(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 39 | } | ||
| 40 | const VoidStructFieldsFoo = struct { | ||
| 41 | a: void, | ||
| 42 | b: i32, | ||
| 43 | c: void, | ||
| 44 | }; | ||
| 45 | |||
| 46 | test "structs" { | ||
| 47 | var foo: StructFoo = undefined; | ||
| 48 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 49 | foo.a += 1; | ||
| 50 | foo.b = foo.a == 1; | ||
| 51 | testFoo(foo); | ||
| 52 | testMutation(&foo); | ||
| 53 | assert(foo.c == 100); | ||
| 54 | } | ||
| 55 | const StructFoo = struct { | ||
| 56 | a: i32, | ||
| 57 | b: bool, | ||
| 58 | c: f32, | ||
| 59 | }; | ||
| 60 | fn testFoo(foo: StructFoo) void { | ||
| 61 | assert(foo.b); | ||
| 62 | } | ||
| 63 | fn testMutation(foo: *StructFoo) void { | ||
| 64 | foo.c = 100; | ||
| 65 | } | ||
| 66 | |||
| 67 | const Node = struct { | ||
| 68 | val: Val, | ||
| 69 | next: *Node, | ||
| 70 | }; | ||
| 71 | |||
| 72 | const Val = struct { | ||
| 73 | x: i32, | ||
| 74 | }; | ||
| 75 | |||
| 76 | test "struct point to self" { | ||
| 77 | var root: Node = undefined; | ||
| 78 | root.val.x = 1; | ||
| 79 | |||
| 80 | var node: Node = undefined; | ||
| 81 | node.next = &root; | ||
| 82 | node.val.x = 2; | ||
| 83 | |||
| 84 | root.next = &node; | ||
| 85 | |||
| 86 | assert(node.next.next.next.val.x == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "struct byval assign" { | ||
| 90 | var foo1: StructFoo = undefined; | ||
| 91 | var foo2: StructFoo = undefined; | ||
| 92 | |||
| 93 | foo1.a = 1234; | ||
| 94 | foo2.a = 0; | ||
| 95 | assert(foo2.a == 0); | ||
| 96 | foo2 = foo1; | ||
| 97 | assert(foo2.a == 1234); | ||
| 98 | } | ||
| 99 | |||
| 100 | fn structInitializer() void { | ||
| 101 | const val = Val{ .x = 42 }; | ||
| 102 | assert(val.x == 42); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "fn call of struct field" { | ||
| 106 | assert(callStructField(Foo{ .ptr = aFunc }) == 13); | ||
| 107 | } | ||
| 108 | |||
| 109 | const Foo = struct { | ||
| 110 | ptr: fn () i32, | ||
| 111 | }; | ||
| 112 | |||
| 113 | fn aFunc() i32 { | ||
| 114 | return 13; | ||
| 115 | } | ||
| 116 | |||
| 117 | fn callStructField(foo: Foo) i32 { | ||
| 118 | return foo.ptr(); | ||
| 119 | } | ||
| 120 | |||
| 121 | test "store member function in variable" { | ||
| 122 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 123 | const memberFn = MemberFnTestFoo.member; | ||
| 124 | const result = memberFn(instance); | ||
| 125 | assert(result == 1234); | ||
| 126 | } | ||
| 127 | const MemberFnTestFoo = struct { | ||
| 128 | x: i32, | ||
| 129 | fn member(foo: MemberFnTestFoo) i32 { | ||
| 130 | return foo.x; | ||
| 131 | } | ||
| 132 | }; | ||
| 133 | |||
| 134 | test "call member function directly" { | ||
| 135 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 136 | const result = MemberFnTestFoo.member(instance); | ||
| 137 | assert(result == 1234); | ||
| 138 | } | ||
| 139 | |||
| 140 | test "member functions" { | ||
| 141 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 142 | assert(r.getSeed() == 1234); | ||
| 143 | } | ||
| 144 | const MemberFnRand = struct { | ||
| 145 | seed: u32, | ||
| 146 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 147 | return r.seed; | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | test "return struct byval from function" { | ||
| 152 | const bar = makeBar(1234, 5678); | ||
| 153 | assert(bar.y == 5678); | ||
| 154 | } | ||
| 155 | const Bar = struct { | ||
| 156 | x: i32, | ||
| 157 | y: i32, | ||
| 158 | }; | ||
| 159 | fn makeBar(x: i32, y: i32) Bar { | ||
| 160 | return Bar{ | ||
| 161 | .x = x, | ||
| 162 | .y = y, | ||
| 163 | }; | ||
| 164 | } | ||
| 165 | |||
| 166 | test "empty struct method call" { | ||
| 167 | const es = EmptyStruct{}; | ||
| 168 | assert(es.method() == 1234); | ||
| 169 | } | ||
| 170 | const EmptyStruct = struct { | ||
| 171 | fn method(es: *const EmptyStruct) i32 { | ||
| 172 | return 1234; | ||
| 173 | } | ||
| 174 | }; | ||
| 175 | |||
| 176 | test "return empty struct from fn" { | ||
| 177 | _ = testReturnEmptyStructFromFn(); | ||
| 178 | } | ||
| 179 | const EmptyStruct2 = struct {}; | ||
| 180 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 181 | return EmptyStruct2{}; | ||
| 182 | } | ||
| 183 | |||
| 184 | test "pass slice of empty struct to fn" { | ||
| 185 | assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); | ||
| 186 | } | ||
| 187 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { | ||
| 188 | return slice.len; | ||
| 189 | } | ||
| 190 | |||
| 191 | const APackedStruct = packed struct { | ||
| 192 | x: u8, | ||
| 193 | y: u8, | ||
| 194 | }; | ||
| 195 | |||
| 196 | test "packed struct" { | ||
| 197 | var foo = APackedStruct{ | ||
| 198 | .x = 1, | ||
| 199 | .y = 2, | ||
| 200 | }; | ||
| 201 | foo.y += 1; | ||
| 202 | const four = foo.x + foo.y; | ||
| 203 | assert(four == 4); | ||
| 204 | } | ||
| 205 | |||
| 206 | const BitField1 = packed struct { | ||
| 207 | a: u3, | ||
| 208 | b: u3, | ||
| 209 | c: u2, | ||
| 210 | }; | ||
| 211 | |||
| 212 | const bit_field_1 = BitField1{ | ||
| 213 | .a = 1, | ||
| 214 | .b = 2, | ||
| 215 | .c = 3, | ||
| 216 | }; | ||
| 217 | |||
| 218 | test "bit field access" { | ||
| 219 | var data = bit_field_1; | ||
| 220 | assert(getA(&data) == 1); | ||
| 221 | assert(getB(&data) == 2); | ||
| 222 | assert(getC(&data) == 3); | ||
| 223 | comptime assert(@sizeOf(BitField1) == 1); | ||
| 224 | |||
| 225 | data.b += 1; | ||
| 226 | assert(data.b == 3); | ||
| 227 | |||
| 228 | data.a += 1; | ||
| 229 | assert(data.a == 2); | ||
| 230 | assert(data.b == 3); | ||
| 231 | } | ||
| 232 | |||
| 233 | fn getA(data: *const BitField1) u3 { | ||
| 234 | return data.a; | ||
| 235 | } | ||
| 236 | |||
| 237 | fn getB(data: *const BitField1) u3 { | ||
| 238 | return data.b; | ||
| 239 | } | ||
| 240 | |||
| 241 | fn getC(data: *const BitField1) u2 { | ||
| 242 | return data.c; | ||
| 243 | } | ||
| 244 | |||
| 245 | const Foo24Bits = packed struct { | ||
| 246 | field: u24, | ||
| 247 | }; | ||
| 248 | const Foo96Bits = packed struct { | ||
| 249 | a: u24, | ||
| 250 | b: u24, | ||
| 251 | c: u24, | ||
| 252 | d: u24, | ||
| 253 | }; | ||
| 254 | |||
| 255 | test "packed struct 24bits" { | ||
| 256 | comptime { | ||
| 257 | assert(@sizeOf(Foo24Bits) == 3); | ||
| 258 | assert(@sizeOf(Foo96Bits) == 12); | ||
| 259 | } | ||
| 260 | |||
| 261 | var value = Foo96Bits{ | ||
| 262 | .a = 0, | ||
| 263 | .b = 0, | ||
| 264 | .c = 0, | ||
| 265 | .d = 0, | ||
| 266 | }; | ||
| 267 | value.a += 1; | ||
| 268 | assert(value.a == 1); | ||
| 269 | assert(value.b == 0); | ||
| 270 | assert(value.c == 0); | ||
| 271 | assert(value.d == 0); | ||
| 272 | |||
| 273 | value.b += 1; | ||
| 274 | assert(value.a == 1); | ||
| 275 | assert(value.b == 1); | ||
| 276 | assert(value.c == 0); | ||
| 277 | assert(value.d == 0); | ||
| 278 | |||
| 279 | value.c += 1; | ||
| 280 | assert(value.a == 1); | ||
| 281 | assert(value.b == 1); | ||
| 282 | assert(value.c == 1); | ||
| 283 | assert(value.d == 0); | ||
| 284 | |||
| 285 | value.d += 1; | ||
| 286 | assert(value.a == 1); | ||
| 287 | assert(value.b == 1); | ||
| 288 | assert(value.c == 1); | ||
| 289 | assert(value.d == 1); | ||
| 290 | } | ||
| 291 | |||
| 292 | const FooArray24Bits = packed struct { | ||
| 293 | a: u16, | ||
| 294 | b: [2]Foo24Bits, | ||
| 295 | c: u16, | ||
| 296 | }; | ||
| 297 | |||
| 298 | test "packed array 24bits" { | ||
| 299 | comptime { | ||
| 300 | assert(@sizeOf([9]Foo24Bits) == 9 * 3); | ||
| 301 | assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); | ||
| 302 | } | ||
| 303 | |||
| 304 | var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); | ||
| 305 | bytes[bytes.len - 1] = 0xaa; | ||
| 306 | const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; | ||
| 307 | assert(ptr.a == 0); | ||
| 308 | assert(ptr.b[0].field == 0); | ||
| 309 | assert(ptr.b[1].field == 0); | ||
| 310 | assert(ptr.c == 0); | ||
| 311 | |||
| 312 | ptr.a = maxInt(u16); | ||
| 313 | assert(ptr.a == maxInt(u16)); | ||
| 314 | assert(ptr.b[0].field == 0); | ||
| 315 | assert(ptr.b[1].field == 0); | ||
| 316 | assert(ptr.c == 0); | ||
| 317 | |||
| 318 | ptr.b[0].field = maxInt(u24); | ||
| 319 | assert(ptr.a == maxInt(u16)); | ||
| 320 | assert(ptr.b[0].field == maxInt(u24)); | ||
| 321 | assert(ptr.b[1].field == 0); | ||
| 322 | assert(ptr.c == 0); | ||
| 323 | |||
| 324 | ptr.b[1].field = maxInt(u24); | ||
| 325 | assert(ptr.a == maxInt(u16)); | ||
| 326 | assert(ptr.b[0].field == maxInt(u24)); | ||
| 327 | assert(ptr.b[1].field == maxInt(u24)); | ||
| 328 | assert(ptr.c == 0); | ||
| 329 | |||
| 330 | ptr.c = maxInt(u16); | ||
| 331 | assert(ptr.a == maxInt(u16)); | ||
| 332 | assert(ptr.b[0].field == maxInt(u24)); | ||
| 333 | assert(ptr.b[1].field == maxInt(u24)); | ||
| 334 | assert(ptr.c == maxInt(u16)); | ||
| 335 | |||
| 336 | assert(bytes[bytes.len - 1] == 0xaa); | ||
| 337 | } | ||
| 338 | |||
| 339 | const FooStructAligned = packed struct { | ||
| 340 | a: u8, | ||
| 341 | b: u8, | ||
| 342 | }; | ||
| 343 | |||
| 344 | const FooArrayOfAligned = packed struct { | ||
| 345 | a: [2]FooStructAligned, | ||
| 346 | }; | ||
| 347 | |||
| 348 | test "aligned array of packed struct" { | ||
| 349 | comptime { | ||
| 350 | assert(@sizeOf(FooStructAligned) == 2); | ||
| 351 | assert(@sizeOf(FooArrayOfAligned) == 2 * 2); | ||
| 352 | } | ||
| 353 | |||
| 354 | var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); | ||
| 355 | const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; | ||
| 356 | |||
| 357 | assert(ptr.a[0].a == 0xbb); | ||
| 358 | assert(ptr.a[0].b == 0xbb); | ||
| 359 | assert(ptr.a[1].a == 0xbb); | ||
| 360 | assert(ptr.a[1].b == 0xbb); | ||
| 361 | } | ||
| 362 | |||
| 363 | test "runtime struct initialization of bitfield" { | ||
| 364 | const s1 = Nibbles{ | ||
| 365 | .x = x1, | ||
| 366 | .y = x1, | ||
| 367 | }; | ||
| 368 | const s2 = Nibbles{ | ||
| 369 | .x = @intCast(u4, x2), | ||
| 370 | .y = @intCast(u4, x2), | ||
| 371 | }; | ||
| 372 | |||
| 373 | assert(s1.x == x1); | ||
| 374 | assert(s1.y == x1); | ||
| 375 | assert(s2.x == @intCast(u4, x2)); | ||
| 376 | assert(s2.y == @intCast(u4, x2)); | ||
| 377 | } | ||
| 378 | |||
| 379 | var x1 = u4(1); | ||
| 380 | var x2 = u8(2); | ||
| 381 | |||
| 382 | const Nibbles = packed struct { | ||
| 383 | x: u4, | ||
| 384 | y: u4, | ||
| 385 | }; | ||
| 386 | |||
| 387 | const Bitfields = packed struct { | ||
| 388 | f1: u16, | ||
| 389 | f2: u16, | ||
| 390 | f3: u8, | ||
| 391 | f4: u8, | ||
| 392 | f5: u4, | ||
| 393 | f6: u4, | ||
| 394 | f7: u8, | ||
| 395 | }; | ||
| 396 | |||
| 397 | test "native bit field understands endianness" { | ||
| 398 | var all: u64 = 0x7765443322221111; | ||
| 399 | var bytes: [8]u8 = undefined; | ||
| 400 | @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); | ||
| 401 | var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; | ||
| 402 | |||
| 403 | assert(bitfields.f1 == 0x1111); | ||
| 404 | assert(bitfields.f2 == 0x2222); | ||
| 405 | assert(bitfields.f3 == 0x33); | ||
| 406 | assert(bitfields.f4 == 0x44); | ||
| 407 | assert(bitfields.f5 == 0x5); | ||
| 408 | assert(bitfields.f6 == 0x6); | ||
| 409 | assert(bitfields.f7 == 0x77); | ||
| 410 | } | ||
| 411 | |||
| 412 | test "align 1 field before self referential align 8 field as slice return type" { | ||
| 413 | const result = alloc(Expr); | ||
| 414 | assert(result.len == 0); | ||
| 415 | } | ||
| 416 | |||
| 417 | const Expr = union(enum) { | ||
| 418 | Literal: u8, | ||
| 419 | Question: *Expr, | ||
| 420 | }; | ||
| 421 | |||
| 422 | fn alloc(comptime T: type) []T { | ||
| 423 | return []T{}; | ||
| 424 | } | ||
| 425 | |||
| 426 | test "call method with mutable reference to struct with no fields" { | ||
| 427 | const S = struct { | ||
| 428 | fn doC(s: *const @This()) bool { | ||
| 429 | return true; | ||
| 430 | } | ||
| 431 | fn do(s: *@This()) bool { | ||
| 432 | return true; | ||
| 433 | } | ||
| 434 | }; | ||
| 435 | |||
| 436 | var s = S{}; | ||
| 437 | assert(S.doC(&s)); | ||
| 438 | assert(s.doC()); | ||
| 439 | assert(S.do(&s)); | ||
| 440 | assert(s.do()); | ||
| 441 | } | ||
| 442 | |||
| 443 | test "implicit cast packed struct field to const ptr" { | ||
| 444 | const LevelUpMove = packed struct { | ||
| 445 | move_id: u9, | ||
| 446 | level: u7, | ||
| 447 | |||
| 448 | fn toInt(value: u7) u7 { | ||
| 449 | return value; | ||
| 450 | } | ||
| 451 | }; | ||
| 452 | |||
| 453 | var lup: LevelUpMove = undefined; | ||
| 454 | lup.level = 12; | ||
| 455 | const res = LevelUpMove.toInt(lup.level); | ||
| 456 | assert(res == 12); | ||
| 457 | } | ||
| 458 | |||
| 459 | test "pointer to packed struct member in a stack variable" { | ||
| 460 | const S = packed struct { | ||
| 461 | a: u2, | ||
| 462 | b: u2, | ||
| 463 | }; | ||
| 464 | |||
| 465 | var s = S{ .a = 2, .b = 0 }; | ||
| 466 | var b_ptr = &s.b; | ||
| 467 | assert(s.b == 0); | ||
| 468 | b_ptr.* = 2; | ||
| 469 | assert(s.b == 2); | ||
| 470 | } | ||
test/cases/struct_contains_null_ptr_itself.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | test "struct contains null pointer which contains original struct" { | ||
| 5 | var x: ?*NodeLineComment = null; | ||
| 6 | assert(x == null); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub const Node = struct { | ||
| 10 | id: Id, | ||
| 11 | comment: ?*NodeLineComment, | ||
| 12 | |||
| 13 | pub const Id = enum { | ||
| 14 | Root, | ||
| 15 | LineComment, | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub const NodeLineComment = struct { | ||
| 20 | base: Node, | ||
| 21 | }; | ||
test/cases/struct_contains_slice_of_itself.zig deleted-85| ... | @@ -1,85 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const Node = struct { | ||
| 4 | payload: i32, | ||
| 5 | children: []Node, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const NodeAligned = struct { | ||
| 9 | payload: i32, | ||
| 10 | children: []align(@alignOf(NodeAligned)) NodeAligned, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "struct contains slice of itself" { | ||
| 14 | var other_nodes = []Node{ | ||
| 15 | Node{ | ||
| 16 | .payload = 31, | ||
| 17 | .children = []Node{}, | ||
| 18 | }, | ||
| 19 | Node{ | ||
| 20 | .payload = 32, | ||
| 21 | .children = []Node{}, | ||
| 22 | }, | ||
| 23 | }; | ||
| 24 | var nodes = []Node{ | ||
| 25 | Node{ | ||
| 26 | .payload = 1, | ||
| 27 | .children = []Node{}, | ||
| 28 | }, | ||
| 29 | Node{ | ||
| 30 | .payload = 2, | ||
| 31 | .children = []Node{}, | ||
| 32 | }, | ||
| 33 | Node{ | ||
| 34 | .payload = 3, | ||
| 35 | .children = other_nodes[0..], | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | const root = Node{ | ||
| 39 | .payload = 1234, | ||
| 40 | .children = nodes[0..], | ||
| 41 | }; | ||
| 42 | assert(root.payload == 1234); | ||
| 43 | assert(root.children[0].payload == 1); | ||
| 44 | assert(root.children[1].payload == 2); | ||
| 45 | assert(root.children[2].payload == 3); | ||
| 46 | assert(root.children[2].children[0].payload == 31); | ||
| 47 | assert(root.children[2].children[1].payload == 32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "struct contains aligned slice of itself" { | ||
| 51 | var other_nodes = []NodeAligned{ | ||
| 52 | NodeAligned{ | ||
| 53 | .payload = 31, | ||
| 54 | .children = []NodeAligned{}, | ||
| 55 | }, | ||
| 56 | NodeAligned{ | ||
| 57 | .payload = 32, | ||
| 58 | .children = []NodeAligned{}, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | var nodes = []NodeAligned{ | ||
| 62 | NodeAligned{ | ||
| 63 | .payload = 1, | ||
| 64 | .children = []NodeAligned{}, | ||
| 65 | }, | ||
| 66 | NodeAligned{ | ||
| 67 | .payload = 2, | ||
| 68 | .children = []NodeAligned{}, | ||
| 69 | }, | ||
| 70 | NodeAligned{ | ||
| 71 | .payload = 3, | ||
| 72 | .children = other_nodes[0..], | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | const root = NodeAligned{ | ||
| 76 | .payload = 1234, | ||
| 77 | .children = nodes[0..], | ||
| 78 | }; | ||
| 79 | assert(root.payload == 1234); | ||
| 80 | assert(root.children[0].payload == 1); | ||
| 81 | assert(root.children[1].payload == 2); | ||
| 82 | assert(root.children[2].payload == 3); | ||
| 83 | assert(root.children[2].children[0].payload == 31); | ||
| 84 | assert(root.children[2].children[1].payload == 32); | ||
| 85 | } | ||
test/cases/switch.zig deleted-271| ... | @@ -1,271 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "switch with numbers" { | ||
| 4 | testSwitchWithNumbers(13); | ||
| 5 | } | ||
| 6 | |||
| 7 | fn testSwitchWithNumbers(x: u32) void { | ||
| 8 | const result = switch (x) { | ||
| 9 | 1, 2, 3, 4...8 => false, | ||
| 10 | 13 => true, | ||
| 11 | else => false, | ||
| 12 | }; | ||
| 13 | assert(result); | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch with all ranges" { | ||
| 17 | assert(testSwitchWithAllRanges(50, 3) == 1); | ||
| 18 | assert(testSwitchWithAllRanges(101, 0) == 2); | ||
| 19 | assert(testSwitchWithAllRanges(300, 5) == 3); | ||
| 20 | assert(testSwitchWithAllRanges(301, 6) == 6); | ||
| 21 | } | ||
| 22 | |||
| 23 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 24 | return switch (x) { | ||
| 25 | 0...100 => 1, | ||
| 26 | 101...200 => 2, | ||
| 27 | 201...300 => 3, | ||
| 28 | else => y, | ||
| 29 | }; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "implicit comptime switch" { | ||
| 33 | const x = 3 + 4; | ||
| 34 | const result = switch (x) { | ||
| 35 | 3 => 10, | ||
| 36 | 4 => 11, | ||
| 37 | 5, 6 => 12, | ||
| 38 | 7, 8 => 13, | ||
| 39 | else => 14, | ||
| 40 | }; | ||
| 41 | |||
| 42 | comptime { | ||
| 43 | assert(result + 1 == 14); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | test "switch on enum" { | ||
| 48 | const fruit = Fruit.Orange; | ||
| 49 | nonConstSwitchOnEnum(fruit); | ||
| 50 | } | ||
| 51 | const Fruit = enum { | ||
| 52 | Apple, | ||
| 53 | Orange, | ||
| 54 | Banana, | ||
| 55 | }; | ||
| 56 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 57 | switch (fruit) { | ||
| 58 | Fruit.Apple => unreachable, | ||
| 59 | Fruit.Orange => {}, | ||
| 60 | Fruit.Banana => unreachable, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | test "switch statement" { | ||
| 65 | nonConstSwitch(SwitchStatmentFoo.C); | ||
| 66 | } | ||
| 67 | fn nonConstSwitch(foo: SwitchStatmentFoo) void { | ||
| 68 | const val = switch (foo) { | ||
| 69 | SwitchStatmentFoo.A => i32(1), | ||
| 70 | SwitchStatmentFoo.B => 2, | ||
| 71 | SwitchStatmentFoo.C => 3, | ||
| 72 | SwitchStatmentFoo.D => 4, | ||
| 73 | }; | ||
| 74 | assert(val == 3); | ||
| 75 | } | ||
| 76 | const SwitchStatmentFoo = enum { | ||
| 77 | A, | ||
| 78 | B, | ||
| 79 | C, | ||
| 80 | D, | ||
| 81 | }; | ||
| 82 | |||
| 83 | test "switch prong with variable" { | ||
| 84 | switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | ||
| 85 | switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | ||
| 86 | switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); | ||
| 87 | } | ||
| 88 | const SwitchProngWithVarEnum = union(enum) { | ||
| 89 | One: i32, | ||
| 90 | Two: f32, | ||
| 91 | Meh: void, | ||
| 92 | }; | ||
| 93 | fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { | ||
| 94 | switch (a) { | ||
| 95 | SwitchProngWithVarEnum.One => |x| { | ||
| 96 | assert(x == 13); | ||
| 97 | }, | ||
| 98 | SwitchProngWithVarEnum.Two => |x| { | ||
| 99 | assert(x == 13.0); | ||
| 100 | }, | ||
| 101 | SwitchProngWithVarEnum.Meh => |x| { | ||
| 102 | const v: void = x; | ||
| 103 | }, | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | test "switch on enum using pointer capture" { | ||
| 108 | testSwitchEnumPtrCapture(); | ||
| 109 | comptime testSwitchEnumPtrCapture(); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn testSwitchEnumPtrCapture() void { | ||
| 113 | var value = SwitchProngWithVarEnum{ .One = 1234 }; | ||
| 114 | switch (value) { | ||
| 115 | SwitchProngWithVarEnum.One => |*x| x.* += 1, | ||
| 116 | else => unreachable, | ||
| 117 | } | ||
| 118 | switch (value) { | ||
| 119 | SwitchProngWithVarEnum.One => |x| assert(x == 1235), | ||
| 120 | else => unreachable, | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | test "switch with multiple expressions" { | ||
| 125 | const x = switch (returnsFive()) { | ||
| 126 | 1, 2, 3 => 1, | ||
| 127 | 4, 5, 6 => 2, | ||
| 128 | else => i32(3), | ||
| 129 | }; | ||
| 130 | assert(x == 2); | ||
| 131 | } | ||
| 132 | fn returnsFive() i32 { | ||
| 133 | return 5; | ||
| 134 | } | ||
| 135 | |||
| 136 | const Number = union(enum) { | ||
| 137 | One: u64, | ||
| 138 | Two: u8, | ||
| 139 | Three: f32, | ||
| 140 | }; | ||
| 141 | |||
| 142 | const number = Number{ .Three = 1.23 }; | ||
| 143 | |||
| 144 | fn returnsFalse() bool { | ||
| 145 | switch (number) { | ||
| 146 | Number.One => |x| return x > 1234, | ||
| 147 | Number.Two => |x| return x == 'a', | ||
| 148 | Number.Three => |x| return x > 12.34, | ||
| 149 | } | ||
| 150 | } | ||
| 151 | test "switch on const enum with var" { | ||
| 152 | assert(!returnsFalse()); | ||
| 153 | } | ||
| 154 | |||
| 155 | test "switch on type" { | ||
| 156 | assert(trueIfBoolFalseOtherwise(bool)); | ||
| 157 | assert(!trueIfBoolFalseOtherwise(i32)); | ||
| 158 | } | ||
| 159 | |||
| 160 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 161 | return switch (T) { | ||
| 162 | bool => true, | ||
| 163 | else => false, | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "switch handles all cases of number" { | ||
| 168 | testSwitchHandleAllCases(); | ||
| 169 | comptime testSwitchHandleAllCases(); | ||
| 170 | } | ||
| 171 | |||
| 172 | fn testSwitchHandleAllCases() void { | ||
| 173 | assert(testSwitchHandleAllCasesExhaustive(0) == 3); | ||
| 174 | assert(testSwitchHandleAllCasesExhaustive(1) == 2); | ||
| 175 | assert(testSwitchHandleAllCasesExhaustive(2) == 1); | ||
| 176 | assert(testSwitchHandleAllCasesExhaustive(3) == 0); | ||
| 177 | |||
| 178 | assert(testSwitchHandleAllCasesRange(100) == 0); | ||
| 179 | assert(testSwitchHandleAllCasesRange(200) == 1); | ||
| 180 | assert(testSwitchHandleAllCasesRange(201) == 2); | ||
| 181 | assert(testSwitchHandleAllCasesRange(202) == 4); | ||
| 182 | assert(testSwitchHandleAllCasesRange(230) == 3); | ||
| 183 | } | ||
| 184 | |||
| 185 | fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { | ||
| 186 | return switch (x) { | ||
| 187 | 0 => u2(3), | ||
| 188 | 1 => 2, | ||
| 189 | 2 => 1, | ||
| 190 | 3 => 0, | ||
| 191 | }; | ||
| 192 | } | ||
| 193 | |||
| 194 | fn testSwitchHandleAllCasesRange(x: u8) u8 { | ||
| 195 | return switch (x) { | ||
| 196 | 0...100 => u8(0), | ||
| 197 | 101...200 => 1, | ||
| 198 | 201, 203 => 2, | ||
| 199 | 202 => 4, | ||
| 200 | 204...255 => 3, | ||
| 201 | }; | ||
| 202 | } | ||
| 203 | |||
| 204 | test "switch all prongs unreachable" { | ||
| 205 | testAllProngsUnreachable(); | ||
| 206 | comptime testAllProngsUnreachable(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testAllProngsUnreachable() void { | ||
| 210 | assert(switchWithUnreachable(1) == 2); | ||
| 211 | assert(switchWithUnreachable(2) == 10); | ||
| 212 | } | ||
| 213 | |||
| 214 | fn switchWithUnreachable(x: i32) i32 { | ||
| 215 | while (true) { | ||
| 216 | switch (x) { | ||
| 217 | 1 => return 2, | ||
| 218 | 2 => break, | ||
| 219 | else => continue, | ||
| 220 | } | ||
| 221 | } | ||
| 222 | return 10; | ||
| 223 | } | ||
| 224 | |||
| 225 | fn return_a_number() anyerror!i32 { | ||
| 226 | return 1; | ||
| 227 | } | ||
| 228 | |||
| 229 | test "capture value of switch with all unreachable prongs" { | ||
| 230 | const x = return_a_number() catch |err| switch (err) { | ||
| 231 | else => unreachable, | ||
| 232 | }; | ||
| 233 | assert(x == 1); | ||
| 234 | } | ||
| 235 | |||
| 236 | test "switching on booleans" { | ||
| 237 | testSwitchOnBools(); | ||
| 238 | comptime testSwitchOnBools(); | ||
| 239 | } | ||
| 240 | |||
| 241 | fn testSwitchOnBools() void { | ||
| 242 | assert(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 243 | assert(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 244 | |||
| 245 | assert(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 246 | assert(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 247 | |||
| 248 | assert(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 249 | assert(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 250 | } | ||
| 251 | |||
| 252 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 253 | return switch (x) { | ||
| 254 | true => false, | ||
| 255 | false => true, | ||
| 256 | }; | ||
| 257 | } | ||
| 258 | |||
| 259 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 260 | return switch (x) { | ||
| 261 | true => false, | ||
| 262 | else => true, | ||
| 263 | }; | ||
| 264 | } | ||
| 265 | |||
| 266 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 267 | return switch (x) { | ||
| 268 | false => true, | ||
| 269 | else => false, | ||
| 270 | }; | ||
| 271 | } | ||
test/cases/switch_prong_err_enum.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | var read_count: u64 = 0; | ||
| 4 | |||
| 5 | fn readOnce() anyerror!u64 { | ||
| 6 | read_count += 1; | ||
| 7 | return read_count; | ||
| 8 | } | ||
| 9 | |||
| 10 | const FormValue = union(enum) { | ||
| 11 | Address: u64, | ||
| 12 | Other: bool, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn doThing(form_id: u64) anyerror!FormValue { | ||
| 16 | return switch (form_id) { | ||
| 17 | 17 => FormValue{ .Address = try readOnce() }, | ||
| 18 | else => error.InvalidDebugInfo, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "switch prong returns error enum" { | ||
| 23 | switch (doThing(17) catch unreachable) { | ||
| 24 | FormValue.Address => |payload| { | ||
| 25 | assert(payload == 1); | ||
| 26 | }, | ||
| 27 | else => unreachable, | ||
| 28 | } | ||
| 29 | assert(read_count == 1); | ||
| 30 | } | ||
test/cases/switch_prong_implicit_cast.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const FormValue = union(enum) { | ||
| 4 | One: void, | ||
| 5 | Two: bool, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn foo(id: u64) !FormValue { | ||
| 9 | return switch (id) { | ||
| 10 | 2 => FormValue{ .Two = true }, | ||
| 11 | 1 => FormValue{ .One = {} }, | ||
| 12 | else => return error.Whatever, | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch prong implicit cast" { | ||
| 17 | const result = switch (foo(2) catch unreachable) { | ||
| 18 | FormValue.One => false, | ||
| 19 | FormValue.Two => |x| x, | ||
| 20 | }; | ||
| 21 | assert(result); | ||
| 22 | } | ||
test/cases/syntax.zig deleted-59| ... | @@ -1,59 +0,0 @@ | ||
| 1 | // Test trailing comma syntax | ||
| 2 | // zig fmt: off | ||
| 3 | |||
| 4 | const struct_trailing_comma = struct { x: i32, y: i32, }; | ||
| 5 | const struct_no_comma = struct { x: i32, y: i32 }; | ||
| 6 | const struct_fn_no_comma = struct { fn m() void {} y: i32 }; | ||
| 7 | |||
| 8 | const enum_no_comma = enum { A, B }; | ||
| 9 | |||
| 10 | fn container_init() void { | ||
| 11 | const S = struct { x: i32, y: i32 }; | ||
| 12 | _ = S { .x = 1, .y = 2 }; | ||
| 13 | _ = S { .x = 1, .y = 2, }; | ||
| 14 | } | ||
| 15 | |||
| 16 | fn type_expr_return1() if (true) A {} | ||
| 17 | fn type_expr_return2() for (true) |_| A {} | ||
| 18 | fn type_expr_return3() while (true) A {} | ||
| 19 | fn type_expr_return4() comptime A {} | ||
| 20 | |||
| 21 | fn switch_cases(x: i32) void { | ||
| 22 | switch (x) { | ||
| 23 | 1,2,3 => {}, | ||
| 24 | 4,5, => {}, | ||
| 25 | 6...8, => {}, | ||
| 26 | else => {}, | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | fn switch_prongs(x: i32) void { | ||
| 31 | switch (x) { | ||
| 32 | 0 => {}, | ||
| 33 | else => {}, | ||
| 34 | } | ||
| 35 | switch (x) { | ||
| 36 | 0 => {}, | ||
| 37 | else => {} | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | const fn_no_comma = fn(i32, i32)void; | ||
| 42 | const fn_trailing_comma = fn(i32, i32,)void; | ||
| 43 | |||
| 44 | fn fn_calls() void { | ||
| 45 | fn add(x: i32, y: i32,) i32 { x + y }; | ||
| 46 | _ = add(1, 2); | ||
| 47 | _ = add(1, 2,); | ||
| 48 | } | ||
| 49 | |||
| 50 | fn asm_lists() void { | ||
| 51 | if (false) { // Build AST but don't analyze | ||
| 52 | asm ("not real assembly" | ||
| 53 | :[a] "x" (x),); | ||
| 54 | asm ("not real assembly" | ||
| 55 | :[a] "x" (->i32),:[a] "x" (1),); | ||
| 56 | asm ("still not real assembly" | ||
| 57 | :::"a","b",); | ||
| 58 | } | ||
| 59 | } | ||
test/cases/this.zig deleted-34| ... | @@ -1,34 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const module = @This(); | ||
| 4 | |||
| 5 | fn Point(comptime T: type) type { | ||
| 6 | return struct { | ||
| 7 | const Self = @This(); | ||
| 8 | x: T, | ||
| 9 | y: T, | ||
| 10 | |||
| 11 | fn addOne(self: *Self) void { | ||
| 12 | self.x += 1; | ||
| 13 | self.y += 1; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn add(x: i32, y: i32) i32 { | ||
| 19 | return x + y; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "this refer to module call private fn" { | ||
| 23 | assert(module.add(1, 2) == 3); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "this refer to container" { | ||
| 27 | var pt = Point(i32){ | ||
| 28 | .x = 12, | ||
| 29 | .y = 34, | ||
| 30 | }; | ||
| 31 | pt.addOne(); | ||
| 32 | assert(pt.x == 13); | ||
| 33 | assert(pt.y == 35); | ||
| 34 | } | ||
test/cases/truncate.zig deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | test "truncate u0 to larger integer allowed and has comptime known result" { | ||
| 5 | var x: u0 = 0; | ||
| 6 | const y = @truncate(u8, x); | ||
| 7 | comptime assert(y == 0); | ||
| 8 | } | ||
test/cases/try.zig deleted-43| ... | @@ -1,43 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "try on error union" { | ||
| 4 | tryOnErrorUnionImpl(); | ||
| 5 | comptime tryOnErrorUnionImpl(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn tryOnErrorUnionImpl() void { | ||
| 9 | const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { | ||
| 10 | error.ItBroke, error.NoMem => 1, | ||
| 11 | error.CrappedOut => i32(2), | ||
| 12 | else => unreachable, | ||
| 13 | }; | ||
| 14 | assert(x == 11); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn returnsTen() anyerror!i32 { | ||
| 18 | return 10; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "try without vars" { | ||
| 22 | const result1 = if (failIfTrue(true)) 1 else |_| i32(2); | ||
| 23 | assert(result1 == 2); | ||
| 24 | |||
| 25 | const result2 = if (failIfTrue(false)) 1 else |_| i32(2); | ||
| 26 | assert(result2 == 1); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn failIfTrue(ok: bool) anyerror!void { | ||
| 30 | if (ok) { | ||
| 31 | return error.ItBroke; | ||
| 32 | } else { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "try then not executed with assignment" { | ||
| 38 | if (failIfTrue(true)) { | ||
| 39 | unreachable; | ||
| 40 | } else |err| { | ||
| 41 | assert(err == error.ItBroke); | ||
| 42 | } | ||
| 43 | } | ||
test/cases/type_info.zig deleted-264| ... | @@ -1,264 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const TypeInfo = @import("builtin").TypeInfo; | ||
| 4 | const TypeId = @import("builtin").TypeId; | ||
| 5 | |||
| 6 | test "type info: tag type, void info" { | ||
| 7 | testBasic(); | ||
| 8 | comptime testBasic(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testBasic() void { | ||
| 12 | assert(@TagType(TypeInfo) == TypeId); | ||
| 13 | const void_info = @typeInfo(void); | ||
| 14 | assert(TypeId(void_info) == TypeId.Void); | ||
| 15 | assert(void_info.Void == {}); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "type info: integer, floating point type info" { | ||
| 19 | testIntFloat(); | ||
| 20 | comptime testIntFloat(); | ||
| 21 | } | ||
| 22 | |||
| 23 | fn testIntFloat() void { | ||
| 24 | const u8_info = @typeInfo(u8); | ||
| 25 | assert(TypeId(u8_info) == TypeId.Int); | ||
| 26 | assert(!u8_info.Int.is_signed); | ||
| 27 | assert(u8_info.Int.bits == 8); | ||
| 28 | |||
| 29 | const f64_info = @typeInfo(f64); | ||
| 30 | assert(TypeId(f64_info) == TypeId.Float); | ||
| 31 | assert(f64_info.Float.bits == 64); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "type info: pointer type info" { | ||
| 35 | testPointer(); | ||
| 36 | comptime testPointer(); | ||
| 37 | } | ||
| 38 | |||
| 39 | fn testPointer() void { | ||
| 40 | const u32_ptr_info = @typeInfo(*u32); | ||
| 41 | assert(TypeId(u32_ptr_info) == TypeId.Pointer); | ||
| 42 | assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); | ||
| 43 | assert(u32_ptr_info.Pointer.is_const == false); | ||
| 44 | assert(u32_ptr_info.Pointer.is_volatile == false); | ||
| 45 | assert(u32_ptr_info.Pointer.alignment == @alignOf(u32)); | ||
| 46 | assert(u32_ptr_info.Pointer.child == u32); | ||
| 47 | } | ||
| 48 | |||
| 49 | test "type info: unknown length pointer type info" { | ||
| 50 | testUnknownLenPtr(); | ||
| 51 | comptime testUnknownLenPtr(); | ||
| 52 | } | ||
| 53 | |||
| 54 | fn 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 | |||
| 64 | test "type info: slice type info" { | ||
| 65 | testSlice(); | ||
| 66 | comptime testSlice(); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn testSlice() void { | ||
| 70 | const u32_slice_info = @typeInfo([]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); | ||
| 77 | } | ||
| 78 | |||
| 79 | test "type info: array type info" { | ||
| 80 | testArray(); | ||
| 81 | comptime testArray(); | ||
| 82 | } | ||
| 83 | |||
| 84 | fn testArray() void { | ||
| 85 | const arr_info = @typeInfo([42]bool); | ||
| 86 | assert(TypeId(arr_info) == TypeId.Array); | ||
| 87 | assert(arr_info.Array.len == 42); | ||
| 88 | assert(arr_info.Array.child == bool); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "type info: optional type info" { | ||
| 92 | testOptional(); | ||
| 93 | comptime testOptional(); | ||
| 94 | } | ||
| 95 | |||
| 96 | fn testOptional() void { | ||
| 97 | const null_info = @typeInfo(?void); | ||
| 98 | assert(TypeId(null_info) == TypeId.Optional); | ||
| 99 | assert(null_info.Optional.child == void); | ||
| 100 | } | ||
| 101 | |||
| 102 | test "type info: promise info" { | ||
| 103 | testPromise(); | ||
| 104 | comptime testPromise(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn testPromise() void { | ||
| 108 | const null_promise_info = @typeInfo(promise); | ||
| 109 | assert(TypeId(null_promise_info) == TypeId.Promise); | ||
| 110 | assert(null_promise_info.Promise.child == null); | ||
| 111 | |||
| 112 | const promise_info = @typeInfo(promise->usize); | ||
| 113 | assert(TypeId(promise_info) == TypeId.Promise); | ||
| 114 | assert(promise_info.Promise.child.? == usize); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "type info: error set, error union info" { | ||
| 118 | testErrorSet(); | ||
| 119 | comptime testErrorSet(); | ||
| 120 | } | ||
| 121 | |||
| 122 | fn testErrorSet() void { | ||
| 123 | const TestErrorSet = error{ | ||
| 124 | First, | ||
| 125 | Second, | ||
| 126 | Third, | ||
| 127 | }; | ||
| 128 | |||
| 129 | const error_set_info = @typeInfo(TestErrorSet); | ||
| 130 | assert(TypeId(error_set_info) == TypeId.ErrorSet); | ||
| 131 | assert(error_set_info.ErrorSet.errors.len == 3); | ||
| 132 | assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); | ||
| 133 | assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); | ||
| 134 | |||
| 135 | const error_union_info = @typeInfo(TestErrorSet!usize); | ||
| 136 | assert(TypeId(error_union_info) == TypeId.ErrorUnion); | ||
| 137 | assert(error_union_info.ErrorUnion.error_set == TestErrorSet); | ||
| 138 | assert(error_union_info.ErrorUnion.payload == usize); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "type info: enum info" { | ||
| 142 | testEnum(); | ||
| 143 | comptime testEnum(); | ||
| 144 | } | ||
| 145 | |||
| 146 | fn testEnum() void { | ||
| 147 | const Os = enum { | ||
| 148 | Windows, | ||
| 149 | Macos, | ||
| 150 | Linux, | ||
| 151 | FreeBSD, | ||
| 152 | }; | ||
| 153 | |||
| 154 | const os_info = @typeInfo(Os); | ||
| 155 | assert(TypeId(os_info) == TypeId.Enum); | ||
| 156 | assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); | ||
| 157 | assert(os_info.Enum.fields.len == 4); | ||
| 158 | assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); | ||
| 159 | assert(os_info.Enum.fields[3].value == 3); | ||
| 160 | assert(os_info.Enum.tag_type == u2); | ||
| 161 | assert(os_info.Enum.defs.len == 0); | ||
| 162 | } | ||
| 163 | |||
| 164 | test "type info: union info" { | ||
| 165 | testUnion(); | ||
| 166 | comptime testUnion(); | ||
| 167 | } | ||
| 168 | |||
| 169 | fn testUnion() void { | ||
| 170 | const typeinfo_info = @typeInfo(TypeInfo); | ||
| 171 | assert(TypeId(typeinfo_info) == TypeId.Union); | ||
| 172 | assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); | ||
| 173 | assert(typeinfo_info.Union.tag_type.? == TypeId); | ||
| 174 | assert(typeinfo_info.Union.fields.len == 24); | ||
| 175 | assert(typeinfo_info.Union.fields[4].enum_field != null); | ||
| 176 | assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4); | ||
| 177 | assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); | ||
| 178 | assert(typeinfo_info.Union.defs.len == 20); | ||
| 179 | |||
| 180 | const TestNoTagUnion = union { | ||
| 181 | Foo: void, | ||
| 182 | Bar: u32, | ||
| 183 | }; | ||
| 184 | |||
| 185 | const notag_union_info = @typeInfo(TestNoTagUnion); | ||
| 186 | assert(TypeId(notag_union_info) == TypeId.Union); | ||
| 187 | assert(notag_union_info.Union.tag_type == null); | ||
| 188 | assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); | ||
| 189 | assert(notag_union_info.Union.fields.len == 2); | ||
| 190 | assert(notag_union_info.Union.fields[0].enum_field == null); | ||
| 191 | assert(notag_union_info.Union.fields[1].field_type == u32); | ||
| 192 | |||
| 193 | const TestExternUnion = extern union { | ||
| 194 | foo: *c_void, | ||
| 195 | }; | ||
| 196 | |||
| 197 | const extern_union_info = @typeInfo(TestExternUnion); | ||
| 198 | assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); | ||
| 199 | assert(extern_union_info.Union.tag_type == null); | ||
| 200 | assert(extern_union_info.Union.fields[0].enum_field == null); | ||
| 201 | assert(extern_union_info.Union.fields[0].field_type == *c_void); | ||
| 202 | } | ||
| 203 | |||
| 204 | test "type info: struct info" { | ||
| 205 | testStruct(); | ||
| 206 | comptime testStruct(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testStruct() void { | ||
| 210 | const struct_info = @typeInfo(TestStruct); | ||
| 211 | assert(TypeId(struct_info) == TypeId.Struct); | ||
| 212 | assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); | ||
| 213 | assert(struct_info.Struct.fields.len == 3); | ||
| 214 | assert(struct_info.Struct.fields[1].offset == null); | ||
| 215 | assert(struct_info.Struct.fields[2].field_type == *TestStruct); | ||
| 216 | assert(struct_info.Struct.defs.len == 2); | ||
| 217 | assert(struct_info.Struct.defs[0].is_pub); | ||
| 218 | assert(!struct_info.Struct.defs[0].data.Fn.is_extern); | ||
| 219 | assert(struct_info.Struct.defs[0].data.Fn.lib_name == null); | ||
| 220 | assert(struct_info.Struct.defs[0].data.Fn.return_type == void); | ||
| 221 | assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); | ||
| 222 | } | ||
| 223 | |||
| 224 | const TestStruct = packed struct { | ||
| 225 | const Self = @This(); | ||
| 226 | |||
| 227 | fieldA: usize, | ||
| 228 | fieldB: void, | ||
| 229 | fieldC: *Self, | ||
| 230 | |||
| 231 | pub fn foo(self: *const Self) void {} | ||
| 232 | }; | ||
| 233 | |||
| 234 | test "type info: function type info" { | ||
| 235 | testFunction(); | ||
| 236 | comptime testFunction(); | ||
| 237 | } | ||
| 238 | |||
| 239 | fn testFunction() void { | ||
| 240 | const fn_info = @typeInfo(@typeOf(foo)); | ||
| 241 | assert(TypeId(fn_info) == TypeId.Fn); | ||
| 242 | assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); | ||
| 243 | assert(fn_info.Fn.is_generic); | ||
| 244 | assert(fn_info.Fn.args.len == 2); | ||
| 245 | assert(fn_info.Fn.is_var_args); | ||
| 246 | assert(fn_info.Fn.return_type == null); | ||
| 247 | assert(fn_info.Fn.async_allocator_type == null); | ||
| 248 | |||
| 249 | const test_instance: TestStruct = undefined; | ||
| 250 | const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); | ||
| 251 | assert(TypeId(bound_fn_info) == TypeId.BoundFn); | ||
| 252 | assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn foo(comptime a: usize, b: bool, args: ...) usize { | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | test "typeInfo with comptime parameter in struct fn def" { | ||
| 260 | const S = struct { | ||
| 261 | pub fn func(comptime x: f32) void {} | ||
| 262 | }; | ||
| 263 | comptime var info = @typeInfo(S); | ||
| 264 | } | ||
test/cases/undefined.zig deleted-68| ... | @@ -1,68 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | fn initStaticArray() [10]i32 { | ||
| 5 | var array: [10]i32 = undefined; | ||
| 6 | array[0] = 1; | ||
| 7 | array[4] = 2; | ||
| 8 | array[7] = 3; | ||
| 9 | array[9] = 4; | ||
| 10 | return array; | ||
| 11 | } | ||
| 12 | const static_array = initStaticArray(); | ||
| 13 | test "init static array to undefined" { | ||
| 14 | assert(static_array[0] == 1); | ||
| 15 | assert(static_array[4] == 2); | ||
| 16 | assert(static_array[7] == 3); | ||
| 17 | assert(static_array[9] == 4); | ||
| 18 | |||
| 19 | comptime { | ||
| 20 | assert(static_array[0] == 1); | ||
| 21 | assert(static_array[4] == 2); | ||
| 22 | assert(static_array[7] == 3); | ||
| 23 | assert(static_array[9] == 4); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | const Foo = struct { | ||
| 28 | x: i32, | ||
| 29 | |||
| 30 | fn setFooXMethod(foo: *Foo) void { | ||
| 31 | foo.x = 3; | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | |||
| 35 | fn setFooX(foo: *Foo) void { | ||
| 36 | foo.x = 2; | ||
| 37 | } | ||
| 38 | |||
| 39 | test "assign undefined to struct" { | ||
| 40 | comptime { | ||
| 41 | var foo: Foo = undefined; | ||
| 42 | setFooX(&foo); | ||
| 43 | assert(foo.x == 2); | ||
| 44 | } | ||
| 45 | { | ||
| 46 | var foo: Foo = undefined; | ||
| 47 | setFooX(&foo); | ||
| 48 | assert(foo.x == 2); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | test "assign undefined to struct with method" { | ||
| 53 | comptime { | ||
| 54 | var foo: Foo = undefined; | ||
| 55 | foo.setFooXMethod(); | ||
| 56 | assert(foo.x == 3); | ||
| 57 | } | ||
| 58 | { | ||
| 59 | var foo: Foo = undefined; | ||
| 60 | foo.setFooXMethod(); | ||
| 61 | assert(foo.x == 3); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | test "type name of undefined" { | ||
| 66 | const x = undefined; | ||
| 67 | assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); | ||
| 68 | } | ||
test/cases/underscore.zig deleted-28| ... | @@ -1,28 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | test "ignore lval with underscore" { | ||
| 5 | _ = false; | ||
| 6 | } | ||
| 7 | |||
| 8 | test "ignore lval with underscore (for loop)" { | ||
| 9 | for ([]void{}) |_, i| { | ||
| 10 | for ([]void{}) |_, j| { | ||
| 11 | break; | ||
| 12 | } | ||
| 13 | break; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | test "ignore lval with underscore (while loop)" { | ||
| 18 | while (optionalReturnError()) |_| { | ||
| 19 | while (optionalReturnError()) |_| { | ||
| 20 | break; | ||
| 21 | } else |_| {} | ||
| 22 | break; | ||
| 23 | } else |_| {} | ||
| 24 | } | ||
| 25 | |||
| 26 | fn optionalReturnError() !?u32 { | ||
| 27 | return error.optionalReturnError; | ||
| 28 | } | ||
test/cases/union.zig deleted-352| ... | @@ -1,352 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const Value = union(enum) { | ||
| 4 | Int: u64, | ||
| 5 | Array: [9]u8, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Agg = struct { | ||
| 9 | val1: Value, | ||
| 10 | val2: Value, | ||
| 11 | }; | ||
| 12 | |||
| 13 | const v1 = Value{ .Int = 1234 }; | ||
| 14 | const v2 = Value{ .Array = []u8{3} ** 9 }; | ||
| 15 | |||
| 16 | const err = (anyerror!Agg)(Agg{ | ||
| 17 | .val1 = v1, | ||
| 18 | .val2 = v2, | ||
| 19 | }); | ||
| 20 | |||
| 21 | const array = []Value{ | ||
| 22 | v1, | ||
| 23 | v2, | ||
| 24 | v1, | ||
| 25 | v2, | ||
| 26 | }; | ||
| 27 | |||
| 28 | test "unions embedded in aggregate types" { | ||
| 29 | switch (array[1]) { | ||
| 30 | Value.Array => |arr| assert(arr[4] == 3), | ||
| 31 | else => unreachable, | ||
| 32 | } | ||
| 33 | switch ((err catch unreachable).val1) { | ||
| 34 | Value.Int => |x| assert(x == 1234), | ||
| 35 | else => unreachable, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | const Foo = union { | ||
| 40 | float: f64, | ||
| 41 | int: i32, | ||
| 42 | }; | ||
| 43 | |||
| 44 | test "basic unions" { | ||
| 45 | var foo = Foo{ .int = 1 }; | ||
| 46 | assert(foo.int == 1); | ||
| 47 | foo = Foo{ .float = 12.34 }; | ||
| 48 | assert(foo.float == 12.34); | ||
| 49 | } | ||
| 50 | |||
| 51 | test "comptime union field access" { | ||
| 52 | comptime { | ||
| 53 | var foo = Foo{ .int = 0 }; | ||
| 54 | assert(foo.int == 0); | ||
| 55 | |||
| 56 | foo = Foo{ .float = 42.42 }; | ||
| 57 | assert(foo.float == 42.42); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "init union with runtime value" { | ||
| 62 | var foo: Foo = undefined; | ||
| 63 | |||
| 64 | setFloat(&foo, 12.34); | ||
| 65 | assert(foo.float == 12.34); | ||
| 66 | |||
| 67 | setInt(&foo, 42); | ||
| 68 | assert(foo.int == 42); | ||
| 69 | } | ||
| 70 | |||
| 71 | fn setFloat(foo: *Foo, x: f64) void { | ||
| 72 | foo.* = Foo{ .float = x }; | ||
| 73 | } | ||
| 74 | |||
| 75 | fn setInt(foo: *Foo, x: i32) void { | ||
| 76 | foo.* = Foo{ .int = x }; | ||
| 77 | } | ||
| 78 | |||
| 79 | const FooExtern = extern union { | ||
| 80 | float: f64, | ||
| 81 | int: i32, | ||
| 82 | }; | ||
| 83 | |||
| 84 | test "basic extern unions" { | ||
| 85 | var foo = FooExtern{ .int = 1 }; | ||
| 86 | assert(foo.int == 1); | ||
| 87 | foo.float = 12.34; | ||
| 88 | assert(foo.float == 12.34); | ||
| 89 | } | ||
| 90 | |||
| 91 | const Letter = enum { | ||
| 92 | A, | ||
| 93 | B, | ||
| 94 | C, | ||
| 95 | }; | ||
| 96 | const Payload = union(Letter) { | ||
| 97 | A: i32, | ||
| 98 | B: f64, | ||
| 99 | C: bool, | ||
| 100 | }; | ||
| 101 | |||
| 102 | test "union with specified enum tag" { | ||
| 103 | doTest(); | ||
| 104 | comptime doTest(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn doTest() void { | ||
| 108 | assert(bar(Payload{ .A = 1234 }) == -10); | ||
| 109 | } | ||
| 110 | |||
| 111 | fn bar(value: Payload) i32 { | ||
| 112 | assert(Letter(value) == Letter.A); | ||
| 113 | return switch (value) { | ||
| 114 | Payload.A => |x| return x - 1244, | ||
| 115 | Payload.B => |x| if (x == 12.34) i32(20) else 21, | ||
| 116 | Payload.C => |x| if (x) i32(30) else 31, | ||
| 117 | }; | ||
| 118 | } | ||
| 119 | |||
| 120 | const MultipleChoice = union(enum(u32)) { | ||
| 121 | A = 20, | ||
| 122 | B = 40, | ||
| 123 | C = 60, | ||
| 124 | D = 1000, | ||
| 125 | }; | ||
| 126 | test "simple union(enum(u32))" { | ||
| 127 | var x = MultipleChoice.C; | ||
| 128 | assert(x == MultipleChoice.C); | ||
| 129 | assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60); | ||
| 130 | } | ||
| 131 | |||
| 132 | const MultipleChoice2 = union(enum(u32)) { | ||
| 133 | Unspecified1: i32, | ||
| 134 | A: f32 = 20, | ||
| 135 | Unspecified2: void, | ||
| 136 | B: bool = 40, | ||
| 137 | Unspecified3: i32, | ||
| 138 | C: i8 = 60, | ||
| 139 | Unspecified4: void, | ||
| 140 | D: void = 1000, | ||
| 141 | Unspecified5: i32, | ||
| 142 | }; | ||
| 143 | |||
| 144 | test "union(enum(u32)) with specified and unspecified tag values" { | ||
| 145 | comptime assert(@TagType(@TagType(MultipleChoice2)) == u32); | ||
| 146 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 147 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 148 | } | ||
| 149 | |||
| 150 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | ||
| 151 | assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); | ||
| 152 | assert(1123 == switch (x) { | ||
| 153 | MultipleChoice2.A => 1, | ||
| 154 | MultipleChoice2.B => 2, | ||
| 155 | MultipleChoice2.C => |v| i32(1000) + v, | ||
| 156 | MultipleChoice2.D => 4, | ||
| 157 | MultipleChoice2.Unspecified1 => 5, | ||
| 158 | MultipleChoice2.Unspecified2 => 6, | ||
| 159 | MultipleChoice2.Unspecified3 => 7, | ||
| 160 | MultipleChoice2.Unspecified4 => 8, | ||
| 161 | MultipleChoice2.Unspecified5 => 9, | ||
| 162 | }); | ||
| 163 | } | ||
| 164 | |||
| 165 | const ExternPtrOrInt = extern union { | ||
| 166 | ptr: *u8, | ||
| 167 | int: u64, | ||
| 168 | }; | ||
| 169 | test "extern union size" { | ||
| 170 | comptime assert(@sizeOf(ExternPtrOrInt) == 8); | ||
| 171 | } | ||
| 172 | |||
| 173 | const PackedPtrOrInt = packed union { | ||
| 174 | ptr: *u8, | ||
| 175 | int: u64, | ||
| 176 | }; | ||
| 177 | test "extern union size" { | ||
| 178 | comptime assert(@sizeOf(PackedPtrOrInt) == 8); | ||
| 179 | } | ||
| 180 | |||
| 181 | const ZeroBits = union { | ||
| 182 | OnlyField: void, | ||
| 183 | }; | ||
| 184 | test "union with only 1 field which is void should be zero bits" { | ||
| 185 | comptime assert(@sizeOf(ZeroBits) == 0); | ||
| 186 | } | ||
| 187 | |||
| 188 | const TheTag = enum { | ||
| 189 | A, | ||
| 190 | B, | ||
| 191 | C, | ||
| 192 | }; | ||
| 193 | const TheUnion = union(TheTag) { | ||
| 194 | A: i32, | ||
| 195 | B: i32, | ||
| 196 | C: i32, | ||
| 197 | }; | ||
| 198 | test "union field access gives the enum values" { | ||
| 199 | assert(TheUnion.A == TheTag.A); | ||
| 200 | assert(TheUnion.B == TheTag.B); | ||
| 201 | assert(TheUnion.C == TheTag.C); | ||
| 202 | } | ||
| 203 | |||
| 204 | test "cast union to tag type of union" { | ||
| 205 | testCastUnionToTagType(TheUnion{ .B = 1234 }); | ||
| 206 | comptime testCastUnionToTagType(TheUnion{ .B = 1234 }); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testCastUnionToTagType(x: TheUnion) void { | ||
| 210 | assert(TheTag(x) == TheTag.B); | ||
| 211 | } | ||
| 212 | |||
| 213 | test "cast tag type of union to union" { | ||
| 214 | var x: Value2 = Letter2.B; | ||
| 215 | assert(Letter2(x) == Letter2.B); | ||
| 216 | } | ||
| 217 | const Letter2 = enum { | ||
| 218 | A, | ||
| 219 | B, | ||
| 220 | C, | ||
| 221 | }; | ||
| 222 | const Value2 = union(Letter2) { | ||
| 223 | A: i32, | ||
| 224 | B, | ||
| 225 | C, | ||
| 226 | }; | ||
| 227 | |||
| 228 | test "implicit cast union to its tag type" { | ||
| 229 | var x: Value2 = Letter2.B; | ||
| 230 | assert(x == Letter2.B); | ||
| 231 | giveMeLetterB(x); | ||
| 232 | } | ||
| 233 | fn giveMeLetterB(x: Letter2) void { | ||
| 234 | assert(x == Value2.B); | ||
| 235 | } | ||
| 236 | |||
| 237 | pub const PackThis = union(enum) { | ||
| 238 | Invalid: bool, | ||
| 239 | StringLiteral: u2, | ||
| 240 | }; | ||
| 241 | |||
| 242 | test "constant packed union" { | ||
| 243 | testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }}); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn testConstPackedUnion(expected_tokens: []const PackThis) void { | ||
| 247 | assert(expected_tokens[0].StringLiteral == 1); | ||
| 248 | } | ||
| 249 | |||
| 250 | test "switch on union with only 1 field" { | ||
| 251 | var r: PartialInst = undefined; | ||
| 252 | r = PartialInst.Compiled; | ||
| 253 | switch (r) { | ||
| 254 | PartialInst.Compiled => { | ||
| 255 | var z: PartialInstWithPayload = undefined; | ||
| 256 | z = PartialInstWithPayload{ .Compiled = 1234 }; | ||
| 257 | switch (z) { | ||
| 258 | PartialInstWithPayload.Compiled => |x| { | ||
| 259 | assert(x == 1234); | ||
| 260 | return; | ||
| 261 | }, | ||
| 262 | } | ||
| 263 | }, | ||
| 264 | } | ||
| 265 | unreachable; | ||
| 266 | } | ||
| 267 | |||
| 268 | const PartialInst = union(enum) { | ||
| 269 | Compiled, | ||
| 270 | }; | ||
| 271 | |||
| 272 | const PartialInstWithPayload = union(enum) { | ||
| 273 | Compiled: i32, | ||
| 274 | }; | ||
| 275 | |||
| 276 | test "access a member of tagged union with conflicting enum tag name" { | ||
| 277 | const Bar = union(enum) { | ||
| 278 | A: A, | ||
| 279 | B: B, | ||
| 280 | |||
| 281 | const A = u8; | ||
| 282 | const B = void; | ||
| 283 | }; | ||
| 284 | |||
| 285 | comptime assert(Bar.A == u8); | ||
| 286 | } | ||
| 287 | |||
| 288 | test "tagged union initialization with runtime void" { | ||
| 289 | assert(testTaggedUnionInit({})); | ||
| 290 | } | ||
| 291 | |||
| 292 | const TaggedUnionWithAVoid = union(enum) { | ||
| 293 | A, | ||
| 294 | B: i32, | ||
| 295 | }; | ||
| 296 | |||
| 297 | fn testTaggedUnionInit(x: var) bool { | ||
| 298 | const y = TaggedUnionWithAVoid{ .A = x }; | ||
| 299 | return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A; | ||
| 300 | } | ||
| 301 | |||
| 302 | pub const UnionEnumNoPayloads = union(enum) { | ||
| 303 | A, | ||
| 304 | B, | ||
| 305 | }; | ||
| 306 | |||
| 307 | test "tagged union with no payloads" { | ||
| 308 | const a = UnionEnumNoPayloads{ .B = {} }; | ||
| 309 | switch (a) { | ||
| 310 | @TagType(UnionEnumNoPayloads).A => @panic("wrong"), | ||
| 311 | @TagType(UnionEnumNoPayloads).B => {}, | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | test "union with only 1 field casted to its enum type" { | ||
| 316 | const Literal = union(enum) { | ||
| 317 | Number: f64, | ||
| 318 | Bool: bool, | ||
| 319 | }; | ||
| 320 | |||
| 321 | const Expr = union(enum) { | ||
| 322 | Literal: Literal, | ||
| 323 | }; | ||
| 324 | |||
| 325 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 326 | const Tag = @TagType(Expr); | ||
| 327 | comptime assert(@TagType(Tag) == comptime_int); | ||
| 328 | var t = Tag(e); | ||
| 329 | assert(t == Expr.Literal); | ||
| 330 | } | ||
| 331 | |||
| 332 | test "union with only 1 field casted to its enum type which has enum value specified" { | ||
| 333 | const Literal = union(enum) { | ||
| 334 | Number: f64, | ||
| 335 | Bool: bool, | ||
| 336 | }; | ||
| 337 | |||
| 338 | const Tag = enum { | ||
| 339 | Literal = 33, | ||
| 340 | }; | ||
| 341 | |||
| 342 | const Expr = union(Tag) { | ||
| 343 | Literal: Literal, | ||
| 344 | }; | ||
| 345 | |||
| 346 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 347 | comptime assert(@TagType(Tag) == comptime_int); | ||
| 348 | var t = Tag(e); | ||
| 349 | assert(t == Expr.Literal); | ||
| 350 | assert(@enumToInt(t) == 33); | ||
| 351 | comptime assert(@enumToInt(t) == 33); | ||
| 352 | } | ||
test/cases/var_args.zig deleted-84| ... | @@ -1,84 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | fn add(args: ...) i32 { | ||
| 4 | var sum = i32(0); | ||
| 5 | { | ||
| 6 | comptime var i: usize = 0; | ||
| 7 | inline while (i < args.len) : (i += 1) { | ||
| 8 | sum += args[i]; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | return sum; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "add arbitrary args" { | ||
| 15 | assert(add(i32(1), i32(2), i32(3), i32(4)) == 10); | ||
| 16 | assert(add(i32(1234)) == 1234); | ||
| 17 | assert(add() == 0); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn readFirstVarArg(args: ...) void { | ||
| 21 | const value = args[0]; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "send void arg to var args" { | ||
| 25 | readFirstVarArg({}); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "pass args directly" { | ||
| 29 | assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); | ||
| 30 | assert(addSomeStuff(i32(1234)) == 1234); | ||
| 31 | assert(addSomeStuff() == 0); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn addSomeStuff(args: ...) i32 { | ||
| 35 | return add(args); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "runtime parameter before var args" { | ||
| 39 | assert(extraFn(10) == 0); | ||
| 40 | assert(extraFn(10, false) == 1); | ||
| 41 | assert(extraFn(10, false, true) == 2); | ||
| 42 | |||
| 43 | // TODO issue #313 | ||
| 44 | //comptime { | ||
| 45 | // assert(extraFn(10) == 0); | ||
| 46 | // assert(extraFn(10, false) == 1); | ||
| 47 | // assert(extraFn(10, false, true) == 2); | ||
| 48 | //} | ||
| 49 | } | ||
| 50 | |||
| 51 | fn extraFn(extra: u32, args: ...) usize { | ||
| 52 | if (args.len >= 1) { | ||
| 53 | assert(args[0] == false); | ||
| 54 | } | ||
| 55 | if (args.len >= 2) { | ||
| 56 | assert(args[1] == true); | ||
| 57 | } | ||
| 58 | return args.len; | ||
| 59 | } | ||
| 60 | |||
| 61 | const foos = []fn (...) bool{ | ||
| 62 | foo1, | ||
| 63 | foo2, | ||
| 64 | }; | ||
| 65 | |||
| 66 | fn foo1(args: ...) bool { | ||
| 67 | return true; | ||
| 68 | } | ||
| 69 | fn foo2(args: ...) bool { | ||
| 70 | return false; | ||
| 71 | } | ||
| 72 | |||
| 73 | test "array of var args functions" { | ||
| 74 | assert(foos[0]()); | ||
| 75 | assert(!foos[1]()); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "pass zero length array to var args param" { | ||
| 79 | doNothingWithFirstArg(""); | ||
| 80 | } | ||
| 81 | |||
| 82 | fn doNothingWithFirstArg(args: ...) void { | ||
| 83 | const a = args[0]; | ||
| 84 | } | ||
test/cases/void.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: void, | ||
| 5 | b: i32, | ||
| 6 | c: void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "compare void with void compile time known" { | ||
| 10 | comptime { | ||
| 11 | const foo = Foo{ | ||
| 12 | .a = {}, | ||
| 13 | .b = 1, | ||
| 14 | .c = {}, | ||
| 15 | }; | ||
| 16 | assert(foo.a == {}); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "iterate over a void slice" { | ||
| 21 | var j: usize = 0; | ||
| 22 | for (times(10)) |_, i| { | ||
| 23 | assert(i == j); | ||
| 24 | j += 1; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | fn times(n: usize) []const void { | ||
| 29 | return ([*]void)(undefined)[0..n]; | ||
| 30 | } | ||
test/cases/while.zig deleted-227| ... | @@ -1,227 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "while loop" { | ||
| 4 | var i: i32 = 0; | ||
| 5 | while (i < 4) { | ||
| 6 | i += 1; | ||
| 7 | } | ||
| 8 | assert(i == 4); | ||
| 9 | assert(whileLoop1() == 1); | ||
| 10 | } | ||
| 11 | fn whileLoop1() i32 { | ||
| 12 | return whileLoop2(); | ||
| 13 | } | ||
| 14 | fn whileLoop2() i32 { | ||
| 15 | while (true) { | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | test "static eval while" { | ||
| 20 | assert(static_eval_while_number == 1); | ||
| 21 | } | ||
| 22 | const static_eval_while_number = staticWhileLoop1(); | ||
| 23 | fn staticWhileLoop1() i32 { | ||
| 24 | return whileLoop2(); | ||
| 25 | } | ||
| 26 | fn staticWhileLoop2() i32 { | ||
| 27 | while (true) { | ||
| 28 | return 1; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | test "continue and break" { | ||
| 33 | runContinueAndBreakTest(); | ||
| 34 | assert(continue_and_break_counter == 8); | ||
| 35 | } | ||
| 36 | var continue_and_break_counter: i32 = 0; | ||
| 37 | fn runContinueAndBreakTest() void { | ||
| 38 | var i: i32 = 0; | ||
| 39 | while (true) { | ||
| 40 | continue_and_break_counter += 2; | ||
| 41 | i += 1; | ||
| 42 | if (i < 4) { | ||
| 43 | continue; | ||
| 44 | } | ||
| 45 | break; | ||
| 46 | } | ||
| 47 | assert(i == 4); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "return with implicit cast from while loop" { | ||
| 51 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | ||
| 52 | } | ||
| 53 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | ||
| 54 | while (true) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | test "while with continue expression" { | ||
| 60 | var sum: i32 = 0; | ||
| 61 | { | ||
| 62 | var i: i32 = 0; | ||
| 63 | while (i < 10) : (i += 1) { | ||
| 64 | if (i == 5) continue; | ||
| 65 | sum += i; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | assert(sum == 40); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "while with else" { | ||
| 72 | var sum: i32 = 0; | ||
| 73 | var i: i32 = 0; | ||
| 74 | var got_else: i32 = 0; | ||
| 75 | while (i < 10) : (i += 1) { | ||
| 76 | sum += 1; | ||
| 77 | } else { | ||
| 78 | got_else += 1; | ||
| 79 | } | ||
| 80 | assert(sum == 10); | ||
| 81 | assert(got_else == 1); | ||
| 82 | } | ||
| 83 | |||
| 84 | test "while with optional as condition" { | ||
| 85 | numbers_left = 10; | ||
| 86 | var sum: i32 = 0; | ||
| 87 | while (getNumberOrNull()) |value| { | ||
| 88 | sum += value; | ||
| 89 | } | ||
| 90 | assert(sum == 45); | ||
| 91 | } | ||
| 92 | |||
| 93 | test "while with optional as condition with else" { | ||
| 94 | numbers_left = 10; | ||
| 95 | var sum: i32 = 0; | ||
| 96 | var got_else: i32 = 0; | ||
| 97 | while (getNumberOrNull()) |value| { | ||
| 98 | sum += value; | ||
| 99 | assert(got_else == 0); | ||
| 100 | } else { | ||
| 101 | got_else += 1; | ||
| 102 | } | ||
| 103 | assert(sum == 45); | ||
| 104 | assert(got_else == 1); | ||
| 105 | } | ||
| 106 | |||
| 107 | test "while with error union condition" { | ||
| 108 | numbers_left = 10; | ||
| 109 | var sum: i32 = 0; | ||
| 110 | var got_else: i32 = 0; | ||
| 111 | while (getNumberOrErr()) |value| { | ||
| 112 | sum += value; | ||
| 113 | } else |err| { | ||
| 114 | assert(err == error.OutOfNumbers); | ||
| 115 | got_else += 1; | ||
| 116 | } | ||
| 117 | assert(sum == 45); | ||
| 118 | assert(got_else == 1); | ||
| 119 | } | ||
| 120 | |||
| 121 | var numbers_left: i32 = undefined; | ||
| 122 | fn getNumberOrErr() anyerror!i32 { | ||
| 123 | return if (numbers_left == 0) error.OutOfNumbers else x: { | ||
| 124 | numbers_left -= 1; | ||
| 125 | break :x numbers_left; | ||
| 126 | }; | ||
| 127 | } | ||
| 128 | fn getNumberOrNull() ?i32 { | ||
| 129 | return if (numbers_left == 0) null else x: { | ||
| 130 | numbers_left -= 1; | ||
| 131 | break :x numbers_left; | ||
| 132 | }; | ||
| 133 | } | ||
| 134 | |||
| 135 | test "while on optional with else result follow else prong" { | ||
| 136 | const result = while (returnNull()) |value| { | ||
| 137 | break value; | ||
| 138 | } else | ||
| 139 | i32(2); | ||
| 140 | assert(result == 2); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "while on optional with else result follow break prong" { | ||
| 144 | const result = while (returnOptional(10)) |value| { | ||
| 145 | break value; | ||
| 146 | } else | ||
| 147 | i32(2); | ||
| 148 | assert(result == 10); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "while on error union with else result follow else prong" { | ||
| 152 | const result = while (returnError()) |value| { | ||
| 153 | break value; | ||
| 154 | } else |err| | ||
| 155 | i32(2); | ||
| 156 | assert(result == 2); | ||
| 157 | } | ||
| 158 | |||
| 159 | test "while on error union with else result follow break prong" { | ||
| 160 | const result = while (returnSuccess(10)) |value| { | ||
| 161 | break value; | ||
| 162 | } else |err| | ||
| 163 | i32(2); | ||
| 164 | assert(result == 10); | ||
| 165 | } | ||
| 166 | |||
| 167 | test "while on bool with else result follow else prong" { | ||
| 168 | const result = while (returnFalse()) { | ||
| 169 | break i32(10); | ||
| 170 | } else | ||
| 171 | i32(2); | ||
| 172 | assert(result == 2); | ||
| 173 | } | ||
| 174 | |||
| 175 | test "while on bool with else result follow break prong" { | ||
| 176 | const result = while (returnTrue()) { | ||
| 177 | break i32(10); | ||
| 178 | } else | ||
| 179 | i32(2); | ||
| 180 | assert(result == 10); | ||
| 181 | } | ||
| 182 | |||
| 183 | test "break from outer while loop" { | ||
| 184 | testBreakOuter(); | ||
| 185 | comptime testBreakOuter(); | ||
| 186 | } | ||
| 187 | |||
| 188 | fn testBreakOuter() void { | ||
| 189 | outer: while (true) { | ||
| 190 | while (true) { | ||
| 191 | break :outer; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | test "continue outer while loop" { | ||
| 197 | testContinueOuter(); | ||
| 198 | comptime testContinueOuter(); | ||
| 199 | } | ||
| 200 | |||
| 201 | fn testContinueOuter() void { | ||
| 202 | var i: usize = 0; | ||
| 203 | outer: while (i < 10) : (i += 1) { | ||
| 204 | while (true) { | ||
| 205 | continue :outer; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | fn returnNull() ?i32 { | ||
| 211 | return null; | ||
| 212 | } | ||
| 213 | fn returnOptional(x: i32) ?i32 { | ||
| 214 | return x; | ||
| 215 | } | ||
| 216 | fn returnError() anyerror!i32 { | ||
| 217 | return error.YouWantedAnError; | ||
| 218 | } | ||
| 219 | fn returnSuccess(x: i32) anyerror!i32 { | ||
| 220 | return x; | ||
| 221 | } | ||
| 222 | fn returnFalse() bool { | ||
| 223 | return false; | ||
| 224 | } | ||
| 225 | fn returnTrue() bool { | ||
| 226 | return true; | ||
| 227 | } | ||
test/cases/widening.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "integer widening" { | ||
| 6 | var a: u8 = 250; | ||
| 7 | var b: u16 = a; | ||
| 8 | var c: u32 = b; | ||
| 9 | var d: u64 = c; | ||
| 10 | var e: u64 = d; | ||
| 11 | var f: u128 = e; | ||
| 12 | assert(f == a); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "implicit unsigned integer to signed integer" { | ||
| 16 | var a: u8 = 250; | ||
| 17 | var b: i16 = a; | ||
| 18 | assert(b == 250); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "float widening" { | ||
| 22 | var a: f16 = 12.34; | ||
| 23 | var b: f32 = a; | ||
| 24 | var c: f64 = b; | ||
| 25 | var d: f128 = c; | ||
| 26 | assert(d == a); | ||
| 27 | } | ||
test/compile_errors.zig+69-5| ... | @@ -1,6 +1,40 @@ | ... | @@ -1,6 +1,40 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.add( | ||
| 5 | "@bitCast same size but bit count mismatch", | ||
| 6 | \\export fn entry(byte: u8) void { | ||
| 7 | \\ var oops = @bitCast(u7, byte); | ||
| 8 | \\} | ||
| 9 | , | ||
| 10 | ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits", | ||
| 11 | ); | ||
| 12 | |||
| 13 | cases.add( | ||
| 14 | "attempted `&&`", | ||
| 15 | \\export fn entry(a: bool, b: bool) i32 { | ||
| 16 | \\ if (a && b) { | ||
| 17 | \\ return 1234; | ||
| 18 | \\ } | ||
| 19 | \\ return 5678; | ||
| 20 | \\} | ||
| 21 | , | ||
| 22 | ".tmp_source.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.", | ||
| 23 | ); | ||
| 24 | |||
| 25 | cases.add( | ||
| 26 | "attempted `||` on boolean values", | ||
| 27 | \\export fn entry(a: bool, b: bool) i32 { | ||
| 28 | \\ if (a || b) { | ||
| 29 | \\ return 1234; | ||
| 30 | \\ } | ||
| 31 | \\ return 5678; | ||
| 32 | \\} | ||
| 33 | , | ||
| 34 | ".tmp_source.zig:2:9: error: expected error set type, found 'bool'", | ||
| 35 | ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR", | ||
| 36 | ); | ||
| 37 | |||
| 4 | cases.add( | 38 | cases.add( |
| 5 | "compile log a pointer to an opaque value", | 39 | "compile log a pointer to an opaque value", |
| 6 | \\export fn entry() void { | 40 | \\export fn entry() void { |
| ... | @@ -267,8 +301,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -267,8 +301,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 267 | \\ const Errors = error{} || u16; | 301 | \\ const Errors = error{} || u16; |
| 268 | \\} | 302 | \\} |
| 269 | , | 303 | , |
| 270 | ".tmp_source.zig:2:20: error: expected error set type, found 'u8'", | 304 | ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'", |
| 271 | ".tmp_source.zig:5:31: error: expected error set type, found 'u16'", | 305 | ".tmp_source.zig:2:23: note: `||` merges error sets; `or` performs boolean OR", |
| 306 | ".tmp_source.zig:5:31: error: expected error set type, found type 'u16'", | ||
| 307 | ".tmp_source.zig:5:28: note: `||` merges error sets; `or` performs boolean OR", | ||
| 272 | ); | 308 | ); |
| 273 | 309 | ||
| 274 | cases.add( | 310 | cases.add( |
| ... | @@ -2618,7 +2654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2618,7 +2654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2618 | \\ | 2654 | \\ |
| 2619 | \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } | 2655 | \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } |
| 2620 | , | 2656 | , |
| 2621 | ".tmp_source.zig:1:13: error: newline not allowed in string literal", | 2657 | ".tmp_source.zig:1:15: error: newline not allowed in string literal", |
| 2622 | ); | 2658 | ); |
| 2623 | 2659 | ||
| 2624 | cases.add( | 2660 | cases.add( |
| ... | @@ -3193,7 +3229,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3193,7 +3229,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3193 | \\ return 2; | 3229 | \\ return 2; |
| 3194 | \\} | 3230 | \\} |
| 3195 | , | 3231 | , |
| 3196 | ".tmp_source.zig:2:15: error: unable to infer expression type", | 3232 | ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known", |
| 3197 | ); | 3233 | ); |
| 3198 | 3234 | ||
| 3199 | cases.add( | 3235 | cases.add( |
| ... | @@ -3539,7 +3575,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3539,7 +3575,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3539 | \\ | 3575 | \\ |
| 3540 | \\export fn entry() usize { return @sizeOf(@typeOf(a)); } | 3576 | \\export fn entry() usize { return @sizeOf(@typeOf(a)); } |
| 3541 | , | 3577 | , |
| 3542 | ".tmp_source.zig:2:11: error: expected type, found 'i32'", | 3578 | ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'", |
| 3543 | ); | 3579 | ); |
| 3544 | 3580 | ||
| 3545 | cases.add( | 3581 | cases.add( |
| ... | @@ -5331,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5331,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5331 | , | 5367 | , |
| 5332 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", | 5368 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", |
| 5333 | ); | 5369 | ); |
| 5370 | |||
| 5371 | cases.add( | ||
| 5372 | "runtime assignment to comptime struct type", | ||
| 5373 | \\const Foo = struct { | ||
| 5374 | \\ Bar: u8, | ||
| 5375 | \\ Baz: type, | ||
| 5376 | \\}; | ||
| 5377 | \\export fn f() void { | ||
| 5378 | \\ var x: u8 = 0; | ||
| 5379 | \\ const foo = Foo { .Bar = x, .Baz = u8 }; | ||
| 5380 | \\} | ||
| 5381 | , | ||
| 5382 | ".tmp_source.zig:7:30: error: unable to evaluate constant expression", | ||
| 5383 | ); | ||
| 5384 | |||
| 5385 | cases.add( | ||
| 5386 | "runtime assignment to comptime union type", | ||
| 5387 | \\const Foo = union { | ||
| 5388 | \\ Bar: u8, | ||
| 5389 | \\ Baz: type, | ||
| 5390 | \\}; | ||
| 5391 | \\export fn f() void { | ||
| 5392 | \\ var x: u8 = 0; | ||
| 5393 | \\ const foo = Foo { .Bar = x }; | ||
| 5394 | \\} | ||
| 5395 | , | ||
| 5396 | ".tmp_source.zig:7:30: error: unable to evaluate constant expression", | ||
| 5397 | ); | ||
| 5334 | } | 5398 | } |
test/stage1/behavior.zig created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | comptime { | ||
| 2 | _ = @import("behavior/align.zig"); | ||
| 3 | _ = @import("behavior/alignof.zig"); | ||
| 4 | _ = @import("behavior/array.zig"); | ||
| 5 | _ = @import("behavior/asm.zig"); | ||
| 6 | _ = @import("behavior/atomics.zig"); | ||
| 7 | _ = @import("behavior/bit_shifting.zig"); | ||
| 8 | _ = @import("behavior/bitcast.zig"); | ||
| 9 | _ = @import("behavior/bitreverse.zig"); | ||
| 10 | _ = @import("behavior/bool.zig"); | ||
| 11 | _ = @import("behavior/bswap.zig"); | ||
| 12 | _ = @import("behavior/bugs/1076.zig"); | ||
| 13 | _ = @import("behavior/bugs/1111.zig"); | ||
| 14 | _ = @import("behavior/bugs/1277.zig"); | ||
| 15 | _ = @import("behavior/bugs/1322.zig"); | ||
| 16 | _ = @import("behavior/bugs/1381.zig"); | ||
| 17 | _ = @import("behavior/bugs/1421.zig"); | ||
| 18 | _ = @import("behavior/bugs/1442.zig"); | ||
| 19 | _ = @import("behavior/bugs/1486.zig"); | ||
| 20 | _ = @import("behavior/bugs/394.zig"); | ||
| 21 | _ = @import("behavior/bugs/655.zig"); | ||
| 22 | _ = @import("behavior/bugs/656.zig"); | ||
| 23 | _ = @import("behavior/bugs/726.zig"); | ||
| 24 | _ = @import("behavior/bugs/828.zig"); | ||
| 25 | _ = @import("behavior/bugs/920.zig"); | ||
| 26 | _ = @import("behavior/byval_arg_var.zig"); | ||
| 27 | _ = @import("behavior/cancel.zig"); | ||
| 28 | _ = @import("behavior/cast.zig"); | ||
| 29 | _ = @import("behavior/const_slice_child.zig"); | ||
| 30 | _ = @import("behavior/coroutine_await_struct.zig"); | ||
| 31 | _ = @import("behavior/coroutines.zig"); | ||
| 32 | _ = @import("behavior/defer.zig"); | ||
| 33 | _ = @import("behavior/enum.zig"); | ||
| 34 | _ = @import("behavior/enum_with_members.zig"); | ||
| 35 | _ = @import("behavior/error.zig"); | ||
| 36 | _ = @import("behavior/eval.zig"); | ||
| 37 | _ = @import("behavior/field_parent_ptr.zig"); | ||
| 38 | _ = @import("behavior/fn.zig"); | ||
| 39 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); | ||
| 40 | _ = @import("behavior/for.zig"); | ||
| 41 | _ = @import("behavior/generics.zig"); | ||
| 42 | _ = @import("behavior/if.zig"); | ||
| 43 | _ = @import("behavior/import.zig"); | ||
| 44 | _ = @import("behavior/incomplete_struct_param_tld.zig"); | ||
| 45 | _ = @import("behavior/inttoptr.zig"); | ||
| 46 | _ = @import("behavior/ir_block_deps.zig"); | ||
| 47 | _ = @import("behavior/math.zig"); | ||
| 48 | _ = @import("behavior/merge_error_sets.zig"); | ||
| 49 | _ = @import("behavior/misc.zig"); | ||
| 50 | _ = @import("behavior/namespace_depends_on_compile_var/index.zig"); | ||
| 51 | _ = @import("behavior/new_stack_call.zig"); | ||
| 52 | _ = @import("behavior/null.zig"); | ||
| 53 | _ = @import("behavior/optional.zig"); | ||
| 54 | _ = @import("behavior/pointers.zig"); | ||
| 55 | _ = @import("behavior/popcount.zig"); | ||
| 56 | _ = @import("behavior/ptrcast.zig"); | ||
| 57 | _ = @import("behavior/pub_enum/index.zig"); | ||
| 58 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | ||
| 59 | _ = @import("behavior/reflection.zig"); | ||
| 60 | _ = @import("behavior/sizeof_and_typeof.zig"); | ||
| 61 | _ = @import("behavior/slice.zig"); | ||
| 62 | _ = @import("behavior/struct.zig"); | ||
| 63 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | ||
| 64 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | ||
| 65 | _ = @import("behavior/switch.zig"); | ||
| 66 | _ = @import("behavior/switch_prong_err_enum.zig"); | ||
| 67 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | ||
| 68 | _ = @import("behavior/syntax.zig"); | ||
| 69 | _ = @import("behavior/this.zig"); | ||
| 70 | _ = @import("behavior/truncate.zig"); | ||
| 71 | _ = @import("behavior/try.zig"); | ||
| 72 | _ = @import("behavior/type_info.zig"); | ||
| 73 | _ = @import("behavior/undefined.zig"); | ||
| 74 | _ = @import("behavior/underscore.zig"); | ||
| 75 | _ = @import("behavior/union.zig"); | ||
| 76 | _ = @import("behavior/var_args.zig"); | ||
| 77 | _ = @import("behavior/vector.zig"); | ||
| 78 | _ = @import("behavior/void.zig"); | ||
| 79 | _ = @import("behavior/while.zig"); | ||
| 80 | _ = @import("behavior/widening.zig"); | ||
| 81 | } | ||
test/stage1/behavior/align.zig created+230| ... | @@ -0,0 +1,230 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | var foo: u8 align(4) = 100; | ||
| 5 | |||
| 6 | test "global variable alignment" { | ||
| 7 | assertOrPanic(@typeOf(&foo).alignment == 4); | ||
| 8 | assertOrPanic(@typeOf(&foo) == *align(4) u8); | ||
| 9 | const slice = (*[1]u8)(&foo)[0..]; | ||
| 10 | assertOrPanic(@typeOf(slice) == []align(4) u8); | ||
| 11 | } | ||
| 12 | |||
| 13 | fn derp() align(@sizeOf(usize) * 2) i32 { | ||
| 14 | return 1234; | ||
| 15 | } | ||
| 16 | fn noop1() align(1) void {} | ||
| 17 | fn noop4() align(4) void {} | ||
| 18 | |||
| 19 | test "function alignment" { | ||
| 20 | assertOrPanic(derp() == 1234); | ||
| 21 | assertOrPanic(@typeOf(noop1) == fn () align(1) void); | ||
| 22 | assertOrPanic(@typeOf(noop4) == fn () align(4) void); | ||
| 23 | noop1(); | ||
| 24 | noop4(); | ||
| 25 | } | ||
| 26 | |||
| 27 | var baz: packed struct { | ||
| 28 | a: u32, | ||
| 29 | b: u32, | ||
| 30 | } = undefined; | ||
| 31 | |||
| 32 | test "packed struct alignment" { | ||
| 33 | assertOrPanic(@typeOf(&baz.b) == *align(1) u32); | ||
| 34 | } | ||
| 35 | |||
| 36 | const blah: packed struct { | ||
| 37 | a: u3, | ||
| 38 | b: u3, | ||
| 39 | c: u2, | ||
| 40 | } = undefined; | ||
| 41 | |||
| 42 | test "bit field alignment" { | ||
| 43 | assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3); | ||
| 44 | } | ||
| 45 | |||
| 46 | test "default alignment allows unspecified in type syntax" { | ||
| 47 | assertOrPanic(*u32 == *align(@alignOf(u32)) u32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "implicitly decreasing pointer alignment" { | ||
| 51 | const a: u32 align(4) = 3; | ||
| 52 | const b: u32 align(8) = 4; | ||
| 53 | assertOrPanic(addUnaligned(&a, &b) == 7); | ||
| 54 | } | ||
| 55 | |||
| 56 | fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { | ||
| 57 | return a.* + b.*; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "implicitly decreasing slice alignment" { | ||
| 61 | const a: u32 align(4) = 3; | ||
| 62 | const b: u32 align(8) = 4; | ||
| 63 | assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); | ||
| 64 | } | ||
| 65 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { | ||
| 66 | return a[0] + b[0]; | ||
| 67 | } | ||
| 68 | |||
| 69 | test "specifying alignment allows pointer cast" { | ||
| 70 | testBytesAlign(0x33); | ||
| 71 | } | ||
| 72 | fn testBytesAlign(b: u8) void { | ||
| 73 | var bytes align(4) = []u8{ | ||
| 74 | b, | ||
| 75 | b, | ||
| 76 | b, | ||
| 77 | b, | ||
| 78 | }; | ||
| 79 | const ptr = @ptrCast(*u32, &bytes[0]); | ||
| 80 | assertOrPanic(ptr.* == 0x33333333); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "specifying alignment allows slice cast" { | ||
| 84 | testBytesAlignSlice(0x33); | ||
| 85 | } | ||
| 86 | fn testBytesAlignSlice(b: u8) void { | ||
| 87 | var bytes align(4) = []u8{ | ||
| 88 | b, | ||
| 89 | b, | ||
| 90 | b, | ||
| 91 | b, | ||
| 92 | }; | ||
| 93 | const slice: []u32 = @bytesToSlice(u32, bytes[0..]); | ||
| 94 | assertOrPanic(slice[0] == 0x33333333); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "@alignCast pointers" { | ||
| 98 | var x: u32 align(4) = 1; | ||
| 99 | expectsOnly1(&x); | ||
| 100 | assertOrPanic(x == 2); | ||
| 101 | } | ||
| 102 | fn expectsOnly1(x: *align(1) u32) void { | ||
| 103 | expects4(@alignCast(4, x)); | ||
| 104 | } | ||
| 105 | fn expects4(x: *align(4) u32) void { | ||
| 106 | x.* += 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | test "@alignCast slices" { | ||
| 110 | var array align(4) = []u32{ | ||
| 111 | 1, | ||
| 112 | 1, | ||
| 113 | }; | ||
| 114 | const slice = array[0..]; | ||
| 115 | sliceExpectsOnly1(slice); | ||
| 116 | assertOrPanic(slice[0] == 2); | ||
| 117 | } | ||
| 118 | fn sliceExpectsOnly1(slice: []align(1) u32) void { | ||
| 119 | sliceExpects4(@alignCast(4, slice)); | ||
| 120 | } | ||
| 121 | fn sliceExpects4(slice: []align(4) u32) void { | ||
| 122 | slice[0] += 1; | ||
| 123 | } | ||
| 124 | |||
| 125 | test "implicitly decreasing fn alignment" { | ||
| 126 | testImplicitlyDecreaseFnAlign(alignedSmall, 1234); | ||
| 127 | testImplicitlyDecreaseFnAlign(alignedBig, 5678); | ||
| 128 | } | ||
| 129 | |||
| 130 | fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { | ||
| 131 | assertOrPanic(ptr() == answer); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn alignedSmall() align(8) i32 { | ||
| 135 | return 1234; | ||
| 136 | } | ||
| 137 | fn alignedBig() align(16) i32 { | ||
| 138 | return 5678; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "@alignCast functions" { | ||
| 142 | assertOrPanic(fnExpectsOnly1(simple4) == 0x19); | ||
| 143 | } | ||
| 144 | fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { | ||
| 145 | return fnExpects4(@alignCast(4, ptr)); | ||
| 146 | } | ||
| 147 | fn fnExpects4(ptr: fn () align(4) i32) i32 { | ||
| 148 | return ptr(); | ||
| 149 | } | ||
| 150 | fn simple4() align(4) i32 { | ||
| 151 | return 0x19; | ||
| 152 | } | ||
| 153 | |||
| 154 | test "generic function with align param" { | ||
| 155 | assertOrPanic(whyWouldYouEverDoThis(1) == 0x1); | ||
| 156 | assertOrPanic(whyWouldYouEverDoThis(4) == 0x1); | ||
| 157 | assertOrPanic(whyWouldYouEverDoThis(8) == 0x1); | ||
| 158 | } | ||
| 159 | |||
| 160 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { | ||
| 161 | return 0x1; | ||
| 162 | } | ||
| 163 | |||
| 164 | test "@ptrCast preserves alignment of bigger source" { | ||
| 165 | var x: u32 align(16) = 1234; | ||
| 166 | const ptr = @ptrCast(*u8, &x); | ||
| 167 | assertOrPanic(@typeOf(ptr) == *align(16) u8); | ||
| 168 | } | ||
| 169 | |||
| 170 | test "runtime known array index has best alignment possible" { | ||
| 171 | // take full advantage of over-alignment | ||
| 172 | var array align(4) = []u8{ 1, 2, 3, 4 }; | ||
| 173 | assertOrPanic(@typeOf(&array[0]) == *align(4) u8); | ||
| 174 | assertOrPanic(@typeOf(&array[1]) == *u8); | ||
| 175 | assertOrPanic(@typeOf(&array[2]) == *align(2) u8); | ||
| 176 | assertOrPanic(@typeOf(&array[3]) == *u8); | ||
| 177 | |||
| 178 | // because align is too small but we still figure out to use 2 | ||
| 179 | var bigger align(2) = []u64{ 1, 2, 3, 4 }; | ||
| 180 | assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64); | ||
| 181 | assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64); | ||
| 182 | assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64); | ||
| 183 | assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64); | ||
| 184 | |||
| 185 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | ||
| 186 | var smaller align(2) = []u32{ 1, 2, 3, 4 }; | ||
| 187 | comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32); | ||
| 188 | comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32); | ||
| 189 | testIndex(smaller[0..].ptr, 0, *align(2) u32); | ||
| 190 | testIndex(smaller[0..].ptr, 1, *align(2) u32); | ||
| 191 | testIndex(smaller[0..].ptr, 2, *align(2) u32); | ||
| 192 | testIndex(smaller[0..].ptr, 3, *align(2) u32); | ||
| 193 | |||
| 194 | // has to use ABI alignment because index known at runtime only | ||
| 195 | testIndex2(array[0..].ptr, 0, *u8); | ||
| 196 | testIndex2(array[0..].ptr, 1, *u8); | ||
| 197 | testIndex2(array[0..].ptr, 2, *u8); | ||
| 198 | testIndex2(array[0..].ptr, 3, *u8); | ||
| 199 | } | ||
| 200 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { | ||
| 201 | comptime assertOrPanic(@typeOf(&smaller[index]) == T); | ||
| 202 | } | ||
| 203 | fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { | ||
| 204 | comptime assertOrPanic(@typeOf(&ptr[index]) == T); | ||
| 205 | } | ||
| 206 | |||
| 207 | test "alignstack" { | ||
| 208 | assertOrPanic(fnWithAlignedStack() == 1234); | ||
| 209 | } | ||
| 210 | |||
| 211 | fn fnWithAlignedStack() i32 { | ||
| 212 | @setAlignStack(256); | ||
| 213 | return 1234; | ||
| 214 | } | ||
| 215 | |||
| 216 | test "alignment of structs" { | ||
| 217 | assertOrPanic(@alignOf(struct { | ||
| 218 | a: i32, | ||
| 219 | b: *i32, | ||
| 220 | }) == @alignOf(usize)); | ||
| 221 | } | ||
| 222 | |||
| 223 | test "alignment of extern() void" { | ||
| 224 | var runtime_nothing = nothing; | ||
| 225 | const casted1 = @ptrCast(*const u8, runtime_nothing); | ||
| 226 | const casted2 = @ptrCast(extern fn () void, casted1); | ||
| 227 | casted2(); | ||
| 228 | } | ||
| 229 | |||
| 230 | extern fn nothing() void {} | ||
test/stage1/behavior/alignof.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | const Foo = struct { | ||
| 7 | x: u32, | ||
| 8 | y: u32, | ||
| 9 | z: u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "@alignOf(T) before referencing T" { | ||
| 13 | comptime assertOrPanic(@alignOf(Foo) != maxInt(usize)); | ||
| 14 | if (builtin.arch == builtin.Arch.x86_64) { | ||
| 15 | comptime assertOrPanic(@alignOf(Foo) == 4); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
test/stage1/behavior/array.zig created+270| ... | @@ -0,0 +1,270 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | test "arrays" { | ||
| 5 | var array: [5]u32 = undefined; | ||
| 6 | |||
| 7 | var i: u32 = 0; | ||
| 8 | while (i < 5) { | ||
| 9 | array[i] = i + 1; | ||
| 10 | i = array[i]; | ||
| 11 | } | ||
| 12 | |||
| 13 | i = 0; | ||
| 14 | var accumulator = u32(0); | ||
| 15 | while (i < 5) { | ||
| 16 | accumulator += array[i]; | ||
| 17 | |||
| 18 | i += 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | assertOrPanic(accumulator == 15); | ||
| 22 | assertOrPanic(getArrayLen(array) == 5); | ||
| 23 | } | ||
| 24 | fn getArrayLen(a: []const u32) usize { | ||
| 25 | return a.len; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "void arrays" { | ||
| 29 | var array: [4]void = undefined; | ||
| 30 | array[0] = void{}; | ||
| 31 | array[1] = array[2]; | ||
| 32 | assertOrPanic(@sizeOf(@typeOf(array)) == 0); | ||
| 33 | assertOrPanic(array.len == 4); | ||
| 34 | } | ||
| 35 | |||
| 36 | test "array literal" { | ||
| 37 | const hex_mult = []u16{ | ||
| 38 | 4096, | ||
| 39 | 256, | ||
| 40 | 16, | ||
| 41 | 1, | ||
| 42 | }; | ||
| 43 | |||
| 44 | assertOrPanic(hex_mult.len == 4); | ||
| 45 | assertOrPanic(hex_mult[1] == 256); | ||
| 46 | } | ||
| 47 | |||
| 48 | test "array dot len const expr" { | ||
| 49 | assertOrPanic(comptime x: { | ||
| 50 | break :x some_array.len == 4; | ||
| 51 | }); | ||
| 52 | } | ||
| 53 | |||
| 54 | const ArrayDotLenConstExpr = struct { | ||
| 55 | y: [some_array.len]u8, | ||
| 56 | }; | ||
| 57 | const some_array = []u8{ | ||
| 58 | 0, | ||
| 59 | 1, | ||
| 60 | 2, | ||
| 61 | 3, | ||
| 62 | }; | ||
| 63 | |||
| 64 | test "nested arrays" { | ||
| 65 | const array_of_strings = [][]const u8{ | ||
| 66 | "hello", | ||
| 67 | "this", | ||
| 68 | "is", | ||
| 69 | "my", | ||
| 70 | "thing", | ||
| 71 | }; | ||
| 72 | for (array_of_strings) |s, i| { | ||
| 73 | if (i == 0) assertOrPanic(mem.eql(u8, s, "hello")); | ||
| 74 | if (i == 1) assertOrPanic(mem.eql(u8, s, "this")); | ||
| 75 | if (i == 2) assertOrPanic(mem.eql(u8, s, "is")); | ||
| 76 | if (i == 3) assertOrPanic(mem.eql(u8, s, "my")); | ||
| 77 | if (i == 4) assertOrPanic(mem.eql(u8, s, "thing")); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | var s_array: [8]Sub = undefined; | ||
| 82 | const Sub = struct { | ||
| 83 | b: u8, | ||
| 84 | }; | ||
| 85 | const Str = struct { | ||
| 86 | a: []Sub, | ||
| 87 | }; | ||
| 88 | test "set global var array via slice embedded in struct" { | ||
| 89 | var s = Str{ .a = s_array[0..] }; | ||
| 90 | |||
| 91 | s.a[0].b = 1; | ||
| 92 | s.a[1].b = 2; | ||
| 93 | s.a[2].b = 3; | ||
| 94 | |||
| 95 | assertOrPanic(s_array[0].b == 1); | ||
| 96 | assertOrPanic(s_array[1].b == 2); | ||
| 97 | assertOrPanic(s_array[2].b == 3); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "array literal with specified size" { | ||
| 101 | var array = [2]u8{ | ||
| 102 | 1, | ||
| 103 | 2, | ||
| 104 | }; | ||
| 105 | assertOrPanic(array[0] == 1); | ||
| 106 | assertOrPanic(array[1] == 2); | ||
| 107 | } | ||
| 108 | |||
| 109 | test "array child property" { | ||
| 110 | var x: [5]i32 = undefined; | ||
| 111 | assertOrPanic(@typeOf(x).Child == i32); | ||
| 112 | } | ||
| 113 | |||
| 114 | test "array len property" { | ||
| 115 | var x: [5]i32 = undefined; | ||
| 116 | assertOrPanic(@typeOf(x).len == 5); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "array len field" { | ||
| 120 | var arr = [4]u8{ 0, 0, 0, 0 }; | ||
| 121 | var ptr = &arr; | ||
| 122 | assertOrPanic(arr.len == 4); | ||
| 123 | comptime assertOrPanic(arr.len == 4); | ||
| 124 | assertOrPanic(ptr.len == 4); | ||
| 125 | comptime assertOrPanic(ptr.len == 4); | ||
| 126 | } | ||
| 127 | |||
| 128 | test "single-item pointer to array indexing and slicing" { | ||
| 129 | testSingleItemPtrArrayIndexSlice(); | ||
| 130 | comptime testSingleItemPtrArrayIndexSlice(); | ||
| 131 | } | ||
| 132 | |||
| 133 | fn testSingleItemPtrArrayIndexSlice() void { | ||
| 134 | var array = "aaaa"; | ||
| 135 | doSomeMangling(&array); | ||
| 136 | assertOrPanic(mem.eql(u8, "azya", array)); | ||
| 137 | } | ||
| 138 | |||
| 139 | fn doSomeMangling(array: *[4]u8) void { | ||
| 140 | array[1] = 'z'; | ||
| 141 | array[2..3][0] = 'y'; | ||
| 142 | } | ||
| 143 | |||
| 144 | test "implicit cast single-item pointer" { | ||
| 145 | testImplicitCastSingleItemPtr(); | ||
| 146 | comptime testImplicitCastSingleItemPtr(); | ||
| 147 | } | ||
| 148 | |||
| 149 | fn testImplicitCastSingleItemPtr() void { | ||
| 150 | var byte: u8 = 100; | ||
| 151 | const slice = (*[1]u8)(&byte)[0..]; | ||
| 152 | slice[0] += 1; | ||
| 153 | assertOrPanic(byte == 101); | ||
| 154 | } | ||
| 155 | |||
| 156 | fn testArrayByValAtComptime(b: [2]u8) u8 { | ||
| 157 | return b[0]; | ||
| 158 | } | ||
| 159 | |||
| 160 | test "comptime evalutating function that takes array by value" { | ||
| 161 | const arr = []u8{ 0, 1 }; | ||
| 162 | _ = comptime testArrayByValAtComptime(arr); | ||
| 163 | _ = comptime testArrayByValAtComptime(arr); | ||
| 164 | } | ||
| 165 | |||
| 166 | test "implicit comptime in array type size" { | ||
| 167 | var arr: [plusOne(10)]bool = undefined; | ||
| 168 | assertOrPanic(arr.len == 11); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn plusOne(x: u32) u32 { | ||
| 172 | return x + 1; | ||
| 173 | } | ||
| 174 | |||
| 175 | test "array literal as argument to function" { | ||
| 176 | const S = struct { | ||
| 177 | fn entry(two: i32) void { | ||
| 178 | foo([]i32{ | ||
| 179 | 1, | ||
| 180 | 2, | ||
| 181 | 3, | ||
| 182 | }); | ||
| 183 | foo([]i32{ | ||
| 184 | 1, | ||
| 185 | two, | ||
| 186 | 3, | ||
| 187 | }); | ||
| 188 | foo2(true, []i32{ | ||
| 189 | 1, | ||
| 190 | 2, | ||
| 191 | 3, | ||
| 192 | }); | ||
| 193 | foo2(true, []i32{ | ||
| 194 | 1, | ||
| 195 | two, | ||
| 196 | 3, | ||
| 197 | }); | ||
| 198 | } | ||
| 199 | fn foo(x: []const i32) void { | ||
| 200 | assertOrPanic(x[0] == 1); | ||
| 201 | assertOrPanic(x[1] == 2); | ||
| 202 | assertOrPanic(x[2] == 3); | ||
| 203 | } | ||
| 204 | fn foo2(trash: bool, x: []const i32) void { | ||
| 205 | assertOrPanic(trash); | ||
| 206 | assertOrPanic(x[0] == 1); | ||
| 207 | assertOrPanic(x[1] == 2); | ||
| 208 | assertOrPanic(x[2] == 3); | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | S.entry(2); | ||
| 212 | comptime S.entry(2); | ||
| 213 | } | ||
| 214 | |||
| 215 | test "double nested array to const slice cast in array literal" { | ||
| 216 | const S = struct { | ||
| 217 | fn entry(two: i32) void { | ||
| 218 | const cases = [][]const []const i32{ | ||
| 219 | [][]const i32{[]i32{1}}, | ||
| 220 | [][]const i32{[]i32{ 2, 3 }}, | ||
| 221 | [][]const i32{ | ||
| 222 | []i32{4}, | ||
| 223 | []i32{ 5, 6, 7 }, | ||
| 224 | }, | ||
| 225 | }; | ||
| 226 | check(cases); | ||
| 227 | |||
| 228 | const cases2 = [][]const i32{ | ||
| 229 | []i32{1}, | ||
| 230 | []i32{ two, 3 }, | ||
| 231 | }; | ||
| 232 | assertOrPanic(cases2.len == 2); | ||
| 233 | assertOrPanic(cases2[0].len == 1); | ||
| 234 | assertOrPanic(cases2[0][0] == 1); | ||
| 235 | assertOrPanic(cases2[1].len == 2); | ||
| 236 | assertOrPanic(cases2[1][0] == 2); | ||
| 237 | assertOrPanic(cases2[1][1] == 3); | ||
| 238 | |||
| 239 | const cases3 = [][]const []const i32{ | ||
| 240 | [][]const i32{[]i32{1}}, | ||
| 241 | [][]const i32{[]i32{ two, 3 }}, | ||
| 242 | [][]const i32{ | ||
| 243 | []i32{4}, | ||
| 244 | []i32{ 5, 6, 7 }, | ||
| 245 | }, | ||
| 246 | }; | ||
| 247 | check(cases3); | ||
| 248 | } | ||
| 249 | |||
| 250 | fn check(cases: []const []const []const i32) void { | ||
| 251 | assertOrPanic(cases.len == 3); | ||
| 252 | assertOrPanic(cases[0].len == 1); | ||
| 253 | assertOrPanic(cases[0][0].len == 1); | ||
| 254 | assertOrPanic(cases[0][0][0] == 1); | ||
| 255 | assertOrPanic(cases[1].len == 1); | ||
| 256 | assertOrPanic(cases[1][0].len == 2); | ||
| 257 | assertOrPanic(cases[1][0][0] == 2); | ||
| 258 | assertOrPanic(cases[1][0][1] == 3); | ||
| 259 | assertOrPanic(cases[2].len == 2); | ||
| 260 | assertOrPanic(cases[2][0].len == 1); | ||
| 261 | assertOrPanic(cases[2][0][0] == 4); | ||
| 262 | assertOrPanic(cases[2][1].len == 3); | ||
| 263 | assertOrPanic(cases[2][1][0] == 5); | ||
| 264 | assertOrPanic(cases[2][1][1] == 6); | ||
| 265 | assertOrPanic(cases[2][1][2] == 7); | ||
| 266 | } | ||
| 267 | }; | ||
| 268 | S.entry(2); | ||
| 269 | comptime S.entry(2); | ||
| 270 | } | ||
test/stage1/behavior/asm.zig created+92| ... | @@ -0,0 +1,92 @@ | ||
| 1 | const config = @import("builtin"); | ||
| 2 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 3 | |||
| 4 | comptime { | ||
| 5 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { | ||
| 6 | asm volatile ( | ||
| 7 | \\.globl aoeu; | ||
| 8 | \\.type aoeu, @function; | ||
| 9 | \\.set aoeu, derp; | ||
| 10 | ); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "module level assembly" { | ||
| 15 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { | ||
| 16 | assertOrPanic(aoeu() == 1234); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "output constraint modifiers" { | ||
| 21 | // This is only testing compilation. | ||
| 22 | var a: u32 = 3; | ||
| 23 | asm volatile ("" | ||
| 24 | : [_] "=m,r" (a) | ||
| 25 | : | ||
| 26 | : "" | ||
| 27 | ); | ||
| 28 | asm volatile ("" | ||
| 29 | : [_] "=r,m" (a) | ||
| 30 | : | ||
| 31 | : "" | ||
| 32 | ); | ||
| 33 | } | ||
| 34 | |||
| 35 | test "alternative constraints" { | ||
| 36 | // Make sure we allow commas as a separator for alternative constraints. | ||
| 37 | var a: u32 = 3; | ||
| 38 | asm volatile ("" | ||
| 39 | : [_] "=r,m" (a) | ||
| 40 | : [_] "r,m" (a) | ||
| 41 | : "" | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | |||
| 45 | test "sized integer/float in asm input" { | ||
| 46 | asm volatile ("" | ||
| 47 | : | ||
| 48 | : [_] "m" (usize(3)) | ||
| 49 | : "" | ||
| 50 | ); | ||
| 51 | asm volatile ("" | ||
| 52 | : | ||
| 53 | : [_] "m" (i15(-3)) | ||
| 54 | : "" | ||
| 55 | ); | ||
| 56 | asm volatile ("" | ||
| 57 | : | ||
| 58 | : [_] "m" (u3(3)) | ||
| 59 | : "" | ||
| 60 | ); | ||
| 61 | asm volatile ("" | ||
| 62 | : | ||
| 63 | : [_] "m" (i3(3)) | ||
| 64 | : "" | ||
| 65 | ); | ||
| 66 | asm volatile ("" | ||
| 67 | : | ||
| 68 | : [_] "m" (u121(3)) | ||
| 69 | : "" | ||
| 70 | ); | ||
| 71 | asm volatile ("" | ||
| 72 | : | ||
| 73 | : [_] "m" (i121(3)) | ||
| 74 | : "" | ||
| 75 | ); | ||
| 76 | asm volatile ("" | ||
| 77 | : | ||
| 78 | : [_] "m" (f32(3.17)) | ||
| 79 | : "" | ||
| 80 | ); | ||
| 81 | asm volatile ("" | ||
| 82 | : | ||
| 83 | : [_] "m" (f64(3.17)) | ||
| 84 | : "" | ||
| 85 | ); | ||
| 86 | } | ||
| 87 | |||
| 88 | extern fn aoeu() i32; | ||
| 89 | |||
| 90 | export fn derp() i32 { | ||
| 91 | return 1234; | ||
| 92 | } | ||
test/stage1/behavior/atomics.zig created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const AtomicRmwOp = builtin.AtomicRmwOp; | ||
| 5 | const AtomicOrder = builtin.AtomicOrder; | ||
| 6 | |||
| 7 | test "cmpxchg" { | ||
| 8 | var x: i32 = 1234; | ||
| 9 | if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 10 | assertOrPanic(x1 == 1234); | ||
| 11 | } else { | ||
| 12 | @panic("cmpxchg should have failed"); | ||
| 13 | } | ||
| 14 | |||
| 15 | while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 16 | assertOrPanic(x1 == 1234); | ||
| 17 | } | ||
| 18 | assertOrPanic(x == 5678); | ||
| 19 | |||
| 20 | assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); | ||
| 21 | assertOrPanic(x == 42); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "fence" { | ||
| 25 | var x: i32 = 1234; | ||
| 26 | @fence(AtomicOrder.SeqCst); | ||
| 27 | x = 5678; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "atomicrmw and atomicload" { | ||
| 31 | var data: u8 = 200; | ||
| 32 | testAtomicRmw(&data); | ||
| 33 | assertOrPanic(data == 42); | ||
| 34 | testAtomicLoad(&data); | ||
| 35 | } | ||
| 36 | |||
| 37 | fn testAtomicRmw(ptr: *u8) void { | ||
| 38 | const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); | ||
| 39 | assertOrPanic(prev_value == 200); | ||
| 40 | comptime { | ||
| 41 | var x: i32 = 1234; | ||
| 42 | const y: i32 = 12345; | ||
| 43 | assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); | ||
| 44 | assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | fn testAtomicLoad(ptr: *u8) void { | ||
| 49 | const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); | ||
| 50 | assertOrPanic(x == 42); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "cmpxchg with ptr" { | ||
| 54 | var data1: i32 = 1234; | ||
| 55 | var data2: i32 = 5678; | ||
| 56 | var data3: i32 = 9101; | ||
| 57 | var x: *i32 = &data1; | ||
| 58 | if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 59 | assertOrPanic(x1 == &data1); | ||
| 60 | } else { | ||
| 61 | @panic("cmpxchg should have failed"); | ||
| 62 | } | ||
| 63 | |||
| 64 | while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { | ||
| 65 | assertOrPanic(x1 == &data1); | ||
| 66 | } | ||
| 67 | assertOrPanic(x == &data3); | ||
| 68 | |||
| 69 | assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); | ||
| 70 | assertOrPanic(x == &data2); | ||
| 71 | } | ||
test/stage1/behavior/bit_shifting.zig created+88| ... | @@ -0,0 +1,88 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { | ||
| 5 | assertOrPanic(Key == @IntType(false, Key.bit_count)); | ||
| 6 | assertOrPanic(Key.bit_count >= mask_bit_count); | ||
| 7 | const ShardKey = @IntType(false, mask_bit_count); | ||
| 8 | const shift_amount = Key.bit_count - ShardKey.bit_count; | ||
| 9 | return struct { | ||
| 10 | const Self = @This(); | ||
| 11 | shards: [1 << ShardKey.bit_count]?*Node, | ||
| 12 | |||
| 13 | pub fn create() Self { | ||
| 14 | return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) }; | ||
| 15 | } | ||
| 16 | |||
| 17 | fn getShardKey(key: Key) ShardKey { | ||
| 18 | // https://github.com/ziglang/zig/issues/1544 | ||
| 19 | // this special case is needed because you can't u32 >> 32. | ||
| 20 | if (ShardKey == u0) return 0; | ||
| 21 | |||
| 22 | // this can be u1 >> u0 | ||
| 23 | const shard_key = key >> shift_amount; | ||
| 24 | |||
| 25 | // TODO: https://github.com/ziglang/zig/issues/1544 | ||
| 26 | // This cast could be implicit if we teach the compiler that | ||
| 27 | // u32 >> 30 -> u2 | ||
| 28 | return @intCast(ShardKey, shard_key); | ||
| 29 | } | ||
| 30 | |||
| 31 | pub fn put(self: *Self, node: *Node) void { | ||
| 32 | const shard_key = Self.getShardKey(node.key); | ||
| 33 | node.next = self.shards[shard_key]; | ||
| 34 | self.shards[shard_key] = node; | ||
| 35 | } | ||
| 36 | |||
| 37 | pub fn get(self: *Self, key: Key) ?*Node { | ||
| 38 | const shard_key = Self.getShardKey(key); | ||
| 39 | var maybe_node = self.shards[shard_key]; | ||
| 40 | while (maybe_node) |node| : (maybe_node = node.next) { | ||
| 41 | if (node.key == key) return node; | ||
| 42 | } | ||
| 43 | return null; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub const Node = struct { | ||
| 47 | key: Key, | ||
| 48 | value: V, | ||
| 49 | next: ?*Node, | ||
| 50 | |||
| 51 | pub fn init(self: *Node, key: Key, value: V) void { | ||
| 52 | self.key = key; | ||
| 53 | self.value = value; | ||
| 54 | self.next = null; | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "sharded table" { | ||
| 61 | // realistic 16-way sharding | ||
| 62 | testShardedTable(u32, 4, 8); | ||
| 63 | |||
| 64 | testShardedTable(u5, 0, 32); // ShardKey == u0 | ||
| 65 | testShardedTable(u5, 2, 32); | ||
| 66 | testShardedTable(u5, 5, 32); | ||
| 67 | |||
| 68 | testShardedTable(u1, 0, 2); | ||
| 69 | testShardedTable(u1, 1, 2); // this does u1 >> u0 | ||
| 70 | |||
| 71 | testShardedTable(u0, 0, 1); | ||
| 72 | } | ||
| 73 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void { | ||
| 74 | const Table = ShardedTable(Key, mask_bit_count, void); | ||
| 75 | |||
| 76 | var table = Table.create(); | ||
| 77 | var node_buffer: [node_count]Table.Node = undefined; | ||
| 78 | for (node_buffer) |*node, i| { | ||
| 79 | const key = @intCast(Key, i); | ||
| 80 | assertOrPanic(table.get(key) == null); | ||
| 81 | node.init(key, {}); | ||
| 82 | table.put(node); | ||
| 83 | } | ||
| 84 | |||
| 85 | for (node_buffer) |*node, i| { | ||
| 86 | assertOrPanic(table.get(@intCast(Key, i)) == node); | ||
| 87 | } | ||
| 88 | } | ||
test/stage1/behavior/bitcast.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | |||
| 5 | test "@bitCast i32 -> u32" { | ||
| 6 | testBitCast_i32_u32(); | ||
| 7 | comptime testBitCast_i32_u32(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitCast_i32_u32() void { | ||
| 11 | assertOrPanic(conv(-1) == maxInt(u32)); | ||
| 12 | assertOrPanic(conv2(maxInt(u32)) == -1); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn conv(x: i32) u32 { | ||
| 16 | return @bitCast(u32, x); | ||
| 17 | } | ||
| 18 | fn conv2(x: u32) i32 { | ||
| 19 | return @bitCast(i32, x); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "@bitCast extern enum to its integer type" { | ||
| 23 | const SOCK = extern enum { | ||
| 24 | A, | ||
| 25 | B, | ||
| 26 | |||
| 27 | fn testBitCastExternEnum() void { | ||
| 28 | var SOCK_DGRAM = @This().B; | ||
| 29 | var sock_dgram = @bitCast(c_int, SOCK_DGRAM); | ||
| 30 | assertOrPanic(sock_dgram == 1); | ||
| 31 | } | ||
| 32 | }; | ||
| 33 | |||
| 34 | SOCK.testBitCastExternEnum(); | ||
| 35 | comptime SOCK.testBitCastExternEnum(); | ||
| 36 | } | ||
test/stage1/behavior/bitreverse.zig created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const minInt = std.math.minInt; | ||
| 4 | |||
| 5 | test "@bitreverse" { | ||
| 6 | comptime testBitReverse(); | ||
| 7 | testBitReverse(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitReverse() void { | ||
| 11 | // using comptime_ints, unsigned | ||
| 12 | assertOrPanic(@bitreverse(u0, 0) == 0); | ||
| 13 | assertOrPanic(@bitreverse(u5, 0x12) == 0x9); | ||
| 14 | assertOrPanic(@bitreverse(u8, 0x12) == 0x48); | ||
| 15 | assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48); | ||
| 16 | assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48); | ||
| 17 | assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); | ||
| 18 | assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); | ||
| 19 | assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); | ||
| 20 | assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); | ||
| 21 | assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); | ||
| 22 | assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 23 | |||
| 24 | // using runtime uints, unsigned | ||
| 25 | var num0: u0 = 0; | ||
| 26 | assertOrPanic(@bitreverse(u0, num0) == 0); | ||
| 27 | var num5: u5 = 0x12; | ||
| 28 | assertOrPanic(@bitreverse(u5, num5) == 0x9); | ||
| 29 | var num8: u8 = 0x12; | ||
| 30 | assertOrPanic(@bitreverse(u8, num8) == 0x48); | ||
| 31 | var num16: u16 = 0x1234; | ||
| 32 | assertOrPanic(@bitreverse(u16, num16) == 0x2c48); | ||
| 33 | var num24: u24 = 0x123456; | ||
| 34 | assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48); | ||
| 35 | var num32: u32 = 0x12345678; | ||
| 36 | assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48); | ||
| 37 | var num40: u40 = 0x123456789a; | ||
| 38 | assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48); | ||
| 39 | var num48: u48 = 0x123456789abc; | ||
| 40 | assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48); | ||
| 41 | var num56: u56 = 0x123456789abcde; | ||
| 42 | assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); | ||
| 43 | var num64: u64 = 0x123456789abcdef1; | ||
| 44 | assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); | ||
| 45 | var num128: u128 = 0x123456789abcdef11121314151617181; | ||
| 46 | assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 47 | |||
| 48 | // using comptime_ints, signed, positive | ||
| 49 | assertOrPanic(@bitreverse(i0, 0) == 0); | ||
| 50 | assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); | ||
| 51 | assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); | ||
| 52 | assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); | ||
| 53 | assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); | ||
| 54 | assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); | ||
| 55 | assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); | ||
| 56 | assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); | ||
| 57 | assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); | ||
| 58 | assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); | ||
| 59 | |||
| 60 | // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. | ||
| 61 | var neg5: i5 = minInt(i5) + 1; | ||
| 62 | assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); | ||
| 63 | var neg8: i8 = -18; | ||
| 64 | assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); | ||
| 65 | var neg16: i16 = -32694; | ||
| 66 | assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); | ||
| 67 | var neg24: i24 = -6773785; | ||
| 68 | assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); | ||
| 69 | var neg32: i32 = -16773785; | ||
| 70 | assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); | ||
| 71 | var neg40: i40 = minInt(i40) + 12345; | ||
| 72 | assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); | ||
| 73 | var neg48: i48 = minInt(i48) + 12345; | ||
| 74 | assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); | ||
| 75 | var neg56: i56 = minInt(i56) + 12345; | ||
| 76 | assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); | ||
| 77 | var neg64: i64 = minInt(i64) + 12345; | ||
| 78 | assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); | ||
| 79 | var neg128: i128 = minInt(i128) + 12345; | ||
| 80 | assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); | ||
| 81 | } | ||
test/stage1/behavior/bool.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "bool literals" { | ||
| 4 | assertOrPanic(true); | ||
| 5 | assertOrPanic(!false); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "cast bool to int" { | ||
| 9 | const t = true; | ||
| 10 | const f = false; | ||
| 11 | assertOrPanic(@boolToInt(t) == u32(1)); | ||
| 12 | assertOrPanic(@boolToInt(f) == u32(0)); | ||
| 13 | nonConstCastBoolToInt(t, f); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn nonConstCastBoolToInt(t: bool, f: bool) void { | ||
| 17 | assertOrPanic(@boolToInt(t) == u32(1)); | ||
| 18 | assertOrPanic(@boolToInt(f) == u32(0)); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "bool cmp" { | ||
| 22 | assertOrPanic(testBoolCmp(true, false) == false); | ||
| 23 | } | ||
| 24 | fn testBoolCmp(a: bool, b: bool) bool { | ||
| 25 | return a == b; | ||
| 26 | } | ||
| 27 | |||
| 28 | const global_f = false; | ||
| 29 | const global_t = true; | ||
| 30 | const not_global_f = !global_f; | ||
| 31 | const not_global_t = !global_t; | ||
| 32 | test "compile time bool not" { | ||
| 33 | assertOrPanic(not_global_f); | ||
| 34 | assertOrPanic(!not_global_t); | ||
| 35 | } | ||
test/stage1/behavior/bswap.zig created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "@bswap" { | ||
| 5 | comptime testByteSwap(); | ||
| 6 | testByteSwap(); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn testByteSwap() void { | ||
| 10 | assertOrPanic(@bswap(u0, 0) == 0); | ||
| 11 | assertOrPanic(@bswap(u8, 0x12) == 0x12); | ||
| 12 | assertOrPanic(@bswap(u16, 0x1234) == 0x3412); | ||
| 13 | assertOrPanic(@bswap(u24, 0x123456) == 0x563412); | ||
| 14 | assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412); | ||
| 15 | assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412); | ||
| 16 | assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); | ||
| 17 | assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); | ||
| 18 | assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); | ||
| 19 | assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); | ||
| 20 | |||
| 21 | assertOrPanic(@bswap(i0, 0) == 0); | ||
| 22 | assertOrPanic(@bswap(i8, -50) == -50); | ||
| 23 | assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); | ||
| 24 | assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); | ||
| 25 | assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); | ||
| 26 | assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); | ||
| 27 | assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); | ||
| 28 | assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); | ||
| 29 | assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); | ||
| 30 | assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == | ||
| 31 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); | ||
| 32 | } | ||
test/stage1/behavior/bugs/1076.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | test "comptime code should not modify constant data" { | ||
| 6 | testCastPtrOfArrayToSliceAndPtr(); | ||
| 7 | comptime testCastPtrOfArrayToSliceAndPtr(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testCastPtrOfArrayToSliceAndPtr() void { | ||
| 11 | var array = "aoeu"; | ||
| 12 | const x: [*]u8 = &array; | ||
| 13 | x[0] += 1; | ||
| 14 | assertOrPanic(mem.eql(u8, array[0..], "boeu")); | ||
| 15 | } | ||
| 16 | |||
test/stage1/behavior/bugs/1111.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const Foo = extern enum { | ||
| 2 | Bar = -1, | ||
| 3 | }; | ||
| 4 | |||
| 5 | test "issue 1111 fixed" { | ||
| 6 | const v = Foo.Bar; | ||
| 7 | |||
| 8 | switch (v) { | ||
| 9 | Foo.Bar => return, | ||
| 10 | else => return, | ||
| 11 | } | ||
| 12 | } | ||
test/stage1/behavior/bugs/1277.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const S = struct { | ||
| 4 | f: ?fn () i32, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const s = S{ .f = f }; | ||
| 8 | |||
| 9 | fn f() i32 { | ||
| 10 | return 1234; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "don't emit an LLVM global for a const function when it's in an optional in a struct" { | ||
| 14 | std.debug.assertOrPanic(s.f.?() == 1234); | ||
| 15 | } | ||
test/stage1/behavior/bugs/1322.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | c: C, | ||
| 5 | None, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = struct { | ||
| 9 | b: B, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const C = struct {}; | ||
| 13 | |||
| 14 | test "tagged union with all void fields but a meaningful tag" { | ||
| 15 | var a: A = A{ .b = B{ .c = C{} } }; | ||
| 16 | std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c); | ||
| 17 | a = A{ .b = B.None }; | ||
| 18 | std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None); | ||
| 19 | } | ||
test/stage1/behavior/bugs/1381.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | D: u8, | ||
| 5 | E: u16, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = union(enum) { | ||
| 9 | B: B, | ||
| 10 | C: u8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "union that needs padding bytes inside an array" { | ||
| 14 | var as = []A{ | ||
| 15 | A{ .B = B{ .D = 1 } }, | ||
| 16 | A{ .B = B{ .D = 1 } }, | ||
| 17 | }; | ||
| 18 | |||
| 19 | const a = as[0].B; | ||
| 20 | std.debug.assertOrPanic(a.D == 1); | ||
| 21 | } | ||
test/stage1/behavior/bugs/1421.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | const S = struct { | ||
| 6 | fn method() builtin.TypeInfo { | ||
| 7 | return @typeInfo(S); | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | test "functions with return type required to be comptime are generic" { | ||
| 12 | const ti = S.method(); | ||
| 13 | assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct); | ||
| 14 | } | ||
test/stage1/behavior/bugs/1442.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Union = union(enum) { | ||
| 4 | Text: []const u8, | ||
| 5 | Color: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | test "const error union field alignment" { | ||
| 9 | var union_or_err: anyerror!Union = Union{ .Color = 1234 }; | ||
| 10 | std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); | ||
| 11 | } | ||
test/stage1/behavior/bugs/1486.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const ptr = &global; | ||
| 4 | var global: u64 = 123; | ||
| 5 | |||
| 6 | test "constant pointer to global variable causes runtime load" { | ||
| 7 | global = 1234; | ||
| 8 | assertOrPanic(&global == ptr); | ||
| 9 | assertOrPanic(ptr.* == 1234); | ||
| 10 | } | ||
| 11 | |||
test/stage1/behavior/bugs/394.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const E = union(enum) { | ||
| 2 | A: [9]u8, | ||
| 3 | B: u64, | ||
| 4 | }; | ||
| 5 | const S = struct { | ||
| 6 | x: u8, | ||
| 7 | y: E, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 11 | |||
| 12 | test "bug 394 fixed" { | ||
| 13 | const x = S{ | ||
| 14 | .x = 3, | ||
| 15 | .y = E{ .B = 1 }, | ||
| 16 | }; | ||
| 17 | assertOrPanic(x.x == 3); | ||
| 18 | } | ||
test/stage1/behavior/bugs/655.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const other_file = @import("655_other_file.zig"); | ||
| 3 | |||
| 4 | test "function with *const parameter with type dereferenced by namespace" { | ||
| 5 | const x: other_file.Integer = 1234; | ||
| 6 | comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer); | ||
| 7 | foo(&x); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn foo(x: *const other_file.Integer) void { | ||
| 11 | std.debug.assertOrPanic(x.* == 1234); | ||
| 12 | } | ||
test/stage1/behavior/bugs/655_other_file.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const Integer = u32; | ||
test/stage1/behavior/bugs/656.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const PrefixOp = union(enum) { | ||
| 4 | Return, | ||
| 5 | AddrOf: Value, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Value = struct { | ||
| 9 | align_expr: ?u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { | ||
| 13 | foo(false, true); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(a: bool, b: bool) void { | ||
| 17 | var prefix_op = PrefixOp{ | ||
| 18 | .AddrOf = Value{ .align_expr = 1234 }, | ||
| 19 | }; | ||
| 20 | if (a) {} else { | ||
| 21 | switch (prefix_op) { | ||
| 22 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 23 | if (b) {} | ||
| 24 | if (addr_of_info.align_expr) |align_expr| { | ||
| 25 | assertOrPanic(align_expr == 1234); | ||
| 26 | } | ||
| 27 | }, | ||
| 28 | PrefixOp.Return => {}, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
test/stage1/behavior/bugs/726.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "@ptrCast from const to nullable" { | ||
| 4 | const c: u8 = 4; | ||
| 5 | var x: ?*const u8 = @ptrCast(?*const u8, &c); | ||
| 6 | assertOrPanic(x.?.* == 4); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "@ptrCast from var in empty struct to nullable" { | ||
| 10 | const container = struct { | ||
| 11 | var c: u8 = 4; | ||
| 12 | }; | ||
| 13 | var x: ?*const u8 = @ptrCast(?*const u8, &container.c); | ||
| 14 | assertOrPanic(x.?.* == 4); | ||
| 15 | } | ||
| 16 | |||
test/stage1/behavior/bugs/828.zig created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | const CountBy = struct { | ||
| 2 | a: usize, | ||
| 3 | |||
| 4 | const One = CountBy{ .a = 1 }; | ||
| 5 | |||
| 6 | pub fn counter(self: *const CountBy) Counter { | ||
| 7 | return Counter{ .i = 0 }; | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Counter = struct { | ||
| 12 | i: usize, | ||
| 13 | |||
| 14 | pub fn count(self: *Counter) bool { | ||
| 15 | self.i += 1; | ||
| 16 | return self.i <= 10; | ||
| 17 | } | ||
| 18 | }; | ||
| 19 | |||
| 20 | fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { | ||
| 21 | comptime { | ||
| 22 | var cnt = cb.counter(); | ||
| 23 | if (cnt.i != 0) @compileError("Counter instance reused!"); | ||
| 24 | while (cnt.count()) {} | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "comptime struct return should not return the same instance" { | ||
| 29 | //the first parameter must be passed by reference to trigger the bug | ||
| 30 | //a second parameter is required to trigger the bug | ||
| 31 | const ValA = constCount(&CountBy.One, 12); | ||
| 32 | const ValB = constCount(&CountBy.One, 15); | ||
| 33 | } | ||
test/stage1/behavior/bugs/920.zig created+65| ... | @@ -0,0 +1,65 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const Random = std.rand.Random; | ||
| 4 | |||
| 5 | const ZigTable = struct { | ||
| 6 | r: f64, | ||
| 7 | x: [257]f64, | ||
| 8 | f: [257]f64, | ||
| 9 | |||
| 10 | pdf: fn (f64) f64, | ||
| 11 | is_symmetric: bool, | ||
| 12 | zero_case: fn (*Random, f64) f64, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { | ||
| 16 | var tables: ZigTable = undefined; | ||
| 17 | |||
| 18 | tables.is_symmetric = is_symmetric; | ||
| 19 | tables.r = r; | ||
| 20 | tables.pdf = f; | ||
| 21 | tables.zero_case = zero_case; | ||
| 22 | |||
| 23 | tables.x[0] = v / f(r); | ||
| 24 | tables.x[1] = r; | ||
| 25 | |||
| 26 | for (tables.x[2..256]) |*entry, i| { | ||
| 27 | const last = tables.x[2 + i - 1]; | ||
| 28 | entry.* = f_inv(v / last + f(last)); | ||
| 29 | } | ||
| 30 | tables.x[256] = 0; | ||
| 31 | |||
| 32 | for (tables.f[0..]) |*entry, i| { | ||
| 33 | entry.* = f(tables.x[i]); | ||
| 34 | } | ||
| 35 | |||
| 36 | return tables; | ||
| 37 | } | ||
| 38 | |||
| 39 | const norm_r = 3.6541528853610088; | ||
| 40 | const norm_v = 0.00492867323399; | ||
| 41 | |||
| 42 | fn norm_f(x: f64) f64 { | ||
| 43 | return math.exp(-x * x / 2.0); | ||
| 44 | } | ||
| 45 | fn norm_f_inv(y: f64) f64 { | ||
| 46 | return math.sqrt(-2.0 * math.ln(y)); | ||
| 47 | } | ||
| 48 | fn norm_zero_case(random: *Random, u: f64) f64 { | ||
| 49 | return 0.0; | ||
| 50 | } | ||
| 51 | |||
| 52 | const NormalDist = blk: { | ||
| 53 | @setEvalBranchQuota(30000); | ||
| 54 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 55 | }; | ||
| 56 | |||
| 57 | test "bug 920 fixed" { | ||
| 58 | const NormalDist1 = blk: { | ||
| 59 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 60 | }; | ||
| 61 | |||
| 62 | for (NormalDist1.f) |_, i| { | ||
| 63 | std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]); | ||
| 64 | } | ||
| 65 | } | ||
test/stage1/behavior/byval_arg_var.zig created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var result: []const u8 = "wrong"; | ||
| 4 | |||
| 5 | test "pass string literal byvalue to a generic var param" { | ||
| 6 | start(); | ||
| 7 | blowUpStack(10); | ||
| 8 | |||
| 9 | std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal")); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn start() void { | ||
| 13 | foo("string literal"); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(x: var) void { | ||
| 17 | bar(x); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn bar(x: var) void { | ||
| 21 | result = x; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn blowUpStack(x: u32) void { | ||
| 25 | if (x == 0) return; | ||
| 26 | blowUpStack(x - 1); | ||
| 27 | } | ||
test/stage1/behavior/cancel.zig created+92| ... | @@ -0,0 +1,92 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var defer_f1: bool = false; | ||
| 4 | var defer_f2: bool = false; | ||
| 5 | var defer_f3: bool = false; | ||
| 6 | |||
| 7 | test "cancel forwards" { | ||
| 8 | var da = std.heap.DirectAllocator.init(); | ||
| 9 | defer da.deinit(); | ||
| 10 | |||
| 11 | const p = async<&da.allocator> f1() catch unreachable; | ||
| 12 | cancel p; | ||
| 13 | std.debug.assertOrPanic(defer_f1); | ||
| 14 | std.debug.assertOrPanic(defer_f2); | ||
| 15 | std.debug.assertOrPanic(defer_f3); | ||
| 16 | } | ||
| 17 | |||
| 18 | async fn f1() void { | ||
| 19 | defer { | ||
| 20 | defer_f1 = true; | ||
| 21 | } | ||
| 22 | await (async f2() catch unreachable); | ||
| 23 | } | ||
| 24 | |||
| 25 | async fn f2() void { | ||
| 26 | defer { | ||
| 27 | defer_f2 = true; | ||
| 28 | } | ||
| 29 | await (async f3() catch unreachable); | ||
| 30 | } | ||
| 31 | |||
| 32 | async fn f3() void { | ||
| 33 | defer { | ||
| 34 | defer_f3 = true; | ||
| 35 | } | ||
| 36 | suspend; | ||
| 37 | } | ||
| 38 | |||
| 39 | var defer_b1: bool = false; | ||
| 40 | var defer_b2: bool = false; | ||
| 41 | var defer_b3: bool = false; | ||
| 42 | var defer_b4: bool = false; | ||
| 43 | |||
| 44 | test "cancel backwards" { | ||
| 45 | var da = std.heap.DirectAllocator.init(); | ||
| 46 | defer da.deinit(); | ||
| 47 | |||
| 48 | const p = async<&da.allocator> b1() catch unreachable; | ||
| 49 | cancel p; | ||
| 50 | std.debug.assertOrPanic(defer_b1); | ||
| 51 | std.debug.assertOrPanic(defer_b2); | ||
| 52 | std.debug.assertOrPanic(defer_b3); | ||
| 53 | std.debug.assertOrPanic(defer_b4); | ||
| 54 | } | ||
| 55 | |||
| 56 | async fn b1() void { | ||
| 57 | defer { | ||
| 58 | defer_b1 = true; | ||
| 59 | } | ||
| 60 | await (async b2() catch unreachable); | ||
| 61 | } | ||
| 62 | |||
| 63 | var b4_handle: promise = undefined; | ||
| 64 | |||
| 65 | async fn b2() void { | ||
| 66 | const b3_handle = async b3() catch unreachable; | ||
| 67 | resume b4_handle; | ||
| 68 | cancel b4_handle; | ||
| 69 | defer { | ||
| 70 | defer_b2 = true; | ||
| 71 | } | ||
| 72 | const value = await b3_handle; | ||
| 73 | @panic("unreachable"); | ||
| 74 | } | ||
| 75 | |||
| 76 | async fn b3() i32 { | ||
| 77 | defer { | ||
| 78 | defer_b3 = true; | ||
| 79 | } | ||
| 80 | await (async b4() catch unreachable); | ||
| 81 | return 1234; | ||
| 82 | } | ||
| 83 | |||
| 84 | async fn b4() void { | ||
| 85 | defer { | ||
| 86 | defer_b4 = true; | ||
| 87 | } | ||
| 88 | suspend { | ||
| 89 | b4_handle = @handle(); | ||
| 90 | } | ||
| 91 | suspend; | ||
| 92 | } | ||
test/stage1/behavior/cast.zig created+473| ... | @@ -0,0 +1,473 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const mem = std.mem; | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | test "int to ptr cast" { | ||
| 7 | const x = usize(13); | ||
| 8 | const y = @intToPtr(*u8, x); | ||
| 9 | const z = @ptrToInt(y); | ||
| 10 | assertOrPanic(z == 13); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "integer literal to pointer cast" { | ||
| 14 | const vga_mem = @intToPtr(*u16, 0xB8000); | ||
| 15 | assertOrPanic(@ptrToInt(vga_mem) == 0xB8000); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "pointer reinterpret const float to int" { | ||
| 19 | const float: f64 = 5.99999999999994648725e-01; | ||
| 20 | const float_ptr = &float; | ||
| 21 | const int_ptr = @ptrCast(*const i32, float_ptr); | ||
| 22 | const int_val = int_ptr.*; | ||
| 23 | assertOrPanic(int_val == 858993411); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "implicitly cast indirect pointer to maybe-indirect pointer" { | ||
| 27 | const S = struct { | ||
| 28 | const Self = @This(); | ||
| 29 | x: u8, | ||
| 30 | fn constConst(p: *const *const Self) u8 { | ||
| 31 | return p.*.x; | ||
| 32 | } | ||
| 33 | fn maybeConstConst(p: ?*const *const Self) u8 { | ||
| 34 | return p.?.*.x; | ||
| 35 | } | ||
| 36 | fn constConstConst(p: *const *const *const Self) u8 { | ||
| 37 | return p.*.*.x; | ||
| 38 | } | ||
| 39 | fn maybeConstConstConst(p: ?*const *const *const Self) u8 { | ||
| 40 | return p.?.*.*.x; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | const s = S{ .x = 42 }; | ||
| 44 | const p = &s; | ||
| 45 | const q = &p; | ||
| 46 | const r = &q; | ||
| 47 | assertOrPanic(42 == S.constConst(q)); | ||
| 48 | assertOrPanic(42 == S.maybeConstConst(q)); | ||
| 49 | assertOrPanic(42 == S.constConstConst(r)); | ||
| 50 | assertOrPanic(42 == S.maybeConstConstConst(r)); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "explicit cast from integer to error type" { | ||
| 54 | testCastIntToErr(error.ItBroke); | ||
| 55 | comptime testCastIntToErr(error.ItBroke); | ||
| 56 | } | ||
| 57 | fn testCastIntToErr(err: anyerror) void { | ||
| 58 | const x = @errorToInt(err); | ||
| 59 | const y = @intToError(x); | ||
| 60 | assertOrPanic(error.ItBroke == y); | ||
| 61 | } | ||
| 62 | |||
| 63 | test "peer resolve arrays of different size to const slice" { | ||
| 64 | assertOrPanic(mem.eql(u8, boolToStr(true), "true")); | ||
| 65 | assertOrPanic(mem.eql(u8, boolToStr(false), "false")); | ||
| 66 | comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true")); | ||
| 67 | comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false")); | ||
| 68 | } | ||
| 69 | fn boolToStr(b: bool) []const u8 { | ||
| 70 | return if (b) "true" else "false"; | ||
| 71 | } | ||
| 72 | |||
| 73 | test "peer resolve array and const slice" { | ||
| 74 | testPeerResolveArrayConstSlice(true); | ||
| 75 | comptime testPeerResolveArrayConstSlice(true); | ||
| 76 | } | ||
| 77 | fn testPeerResolveArrayConstSlice(b: bool) void { | ||
| 78 | const value1 = if (b) "aoeu" else ([]const u8)("zz"); | ||
| 79 | const value2 = if (b) ([]const u8)("zz") else "aoeu"; | ||
| 80 | assertOrPanic(mem.eql(u8, value1, "aoeu")); | ||
| 81 | assertOrPanic(mem.eql(u8, value2, "zz")); | ||
| 82 | } | ||
| 83 | |||
| 84 | test "implicitly cast from T to anyerror!?T" { | ||
| 85 | castToOptionalTypeError(1); | ||
| 86 | comptime castToOptionalTypeError(1); | ||
| 87 | } | ||
| 88 | |||
| 89 | const A = struct { | ||
| 90 | a: i32, | ||
| 91 | }; | ||
| 92 | fn castToOptionalTypeError(z: i32) void { | ||
| 93 | const x = i32(1); | ||
| 94 | const y: anyerror!?i32 = x; | ||
| 95 | assertOrPanic((try y).? == 1); | ||
| 96 | |||
| 97 | const f = z; | ||
| 98 | const g: anyerror!?i32 = f; | ||
| 99 | |||
| 100 | const a = A{ .a = z }; | ||
| 101 | const b: anyerror!?A = a; | ||
| 102 | assertOrPanic((b catch unreachable).?.a == 1); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "implicitly cast from int to anyerror!?T" { | ||
| 106 | implicitIntLitToOptional(); | ||
| 107 | comptime implicitIntLitToOptional(); | ||
| 108 | } | ||
| 109 | fn implicitIntLitToOptional() void { | ||
| 110 | const f: ?i32 = 1; | ||
| 111 | const g: anyerror!?i32 = 1; | ||
| 112 | } | ||
| 113 | |||
| 114 | test "return null from fn() anyerror!?&T" { | ||
| 115 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 116 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 117 | assertOrPanic((try a) == null and (try b) == null); | ||
| 118 | } | ||
| 119 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 120 | const a: ?*A = null; | ||
| 121 | return a; | ||
| 122 | } | ||
| 123 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 124 | return null; | ||
| 125 | } | ||
| 126 | |||
| 127 | test "peer type resolution: ?T and T" { | ||
| 128 | assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 129 | assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 130 | comptime { | ||
| 131 | assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 132 | assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { | ||
| 136 | if (c) { | ||
| 137 | return if (b) null else usize(0); | ||
| 138 | } | ||
| 139 | |||
| 140 | return usize(3); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 144 | assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 145 | assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 146 | comptime { | ||
| 147 | assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 148 | assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 152 | if (a) { | ||
| 153 | return []const u8{}; | ||
| 154 | } | ||
| 155 | |||
| 156 | return slice[0..1]; | ||
| 157 | } | ||
| 158 | |||
| 159 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 160 | assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 161 | comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 162 | } | ||
| 163 | |||
| 164 | fn castToOptionalSlice() ?[]const u8 { | ||
| 165 | return "hi"; | ||
| 166 | } | ||
| 167 | |||
| 168 | test "implicitly cast from [0]T to anyerror![]T" { | ||
| 169 | testCastZeroArrayToErrSliceMut(); | ||
| 170 | comptime testCastZeroArrayToErrSliceMut(); | ||
| 171 | } | ||
| 172 | |||
| 173 | fn testCastZeroArrayToErrSliceMut() void { | ||
| 174 | assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0); | ||
| 175 | } | ||
| 176 | |||
| 177 | fn gimmeErrOrSlice() anyerror![]u8 { | ||
| 178 | return []u8{}; | ||
| 179 | } | ||
| 180 | |||
| 181 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { | ||
| 182 | { | ||
| 183 | var data = "hi"; | ||
| 184 | const slice = data[0..]; | ||
| 185 | assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 186 | assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 187 | } | ||
| 188 | comptime { | ||
| 189 | var data = "hi"; | ||
| 190 | const slice = data[0..]; | ||
| 191 | assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 192 | assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { | ||
| 196 | if (a) { | ||
| 197 | return []u8{}; | ||
| 198 | } | ||
| 199 | |||
| 200 | return slice[0..1]; | ||
| 201 | } | ||
| 202 | |||
| 203 | test "resolve undefined with integer" { | ||
| 204 | testResolveUndefWithInt(true, 1234); | ||
| 205 | comptime testResolveUndefWithInt(true, 1234); | ||
| 206 | } | ||
| 207 | fn testResolveUndefWithInt(b: bool, x: i32) void { | ||
| 208 | const value = if (b) x else undefined; | ||
| 209 | if (b) { | ||
| 210 | assertOrPanic(value == x); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | test "implicit cast from &const [N]T to []const T" { | ||
| 215 | testCastConstArrayRefToConstSlice(); | ||
| 216 | comptime testCastConstArrayRefToConstSlice(); | ||
| 217 | } | ||
| 218 | |||
| 219 | fn testCastConstArrayRefToConstSlice() void { | ||
| 220 | const blah = "aoeu"; | ||
| 221 | const const_array_ref = &blah; | ||
| 222 | assertOrPanic(@typeOf(const_array_ref) == *const [4]u8); | ||
| 223 | const slice: []const u8 = const_array_ref; | ||
| 224 | assertOrPanic(mem.eql(u8, slice, "aoeu")); | ||
| 225 | } | ||
| 226 | |||
| 227 | test "peer type resolution: error and [N]T" { | ||
| 228 | // TODO: implicit error!T to error!U where T can implicitly cast to U | ||
| 229 | //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 230 | //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 231 | assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 232 | comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 233 | } | ||
| 234 | |||
| 235 | //fn testPeerErrorAndArray(x: u8) error![]const u8 { | ||
| 236 | // return switch (x) { | ||
| 237 | // 0x00 => "OK", | ||
| 238 | // else => error.BadValue, | ||
| 239 | // }; | ||
| 240 | //} | ||
| 241 | fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { | ||
| 242 | return switch (x) { | ||
| 243 | 0x00 => "OK", | ||
| 244 | 0x01 => "OKK", | ||
| 245 | else => error.BadValue, | ||
| 246 | }; | ||
| 247 | } | ||
| 248 | |||
| 249 | test "@floatToInt" { | ||
| 250 | testFloatToInts(); | ||
| 251 | comptime testFloatToInts(); | ||
| 252 | } | ||
| 253 | |||
| 254 | fn testFloatToInts() void { | ||
| 255 | const x = i32(1e4); | ||
| 256 | assertOrPanic(x == 10000); | ||
| 257 | const y = @floatToInt(i32, f32(1e4)); | ||
| 258 | assertOrPanic(y == 10000); | ||
| 259 | expectFloatToInt(f16, 255.1, u8, 255); | ||
| 260 | expectFloatToInt(f16, 127.2, i8, 127); | ||
| 261 | expectFloatToInt(f16, -128.2, i8, -128); | ||
| 262 | expectFloatToInt(f32, 255.1, u8, 255); | ||
| 263 | expectFloatToInt(f32, 127.2, i8, 127); | ||
| 264 | expectFloatToInt(f32, -128.2, i8, -128); | ||
| 265 | expectFloatToInt(comptime_int, 1234, i16, 1234); | ||
| 266 | } | ||
| 267 | |||
| 268 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { | ||
| 269 | assertOrPanic(@floatToInt(I, f) == i); | ||
| 270 | } | ||
| 271 | |||
| 272 | test "cast u128 to f128 and back" { | ||
| 273 | comptime testCast128(); | ||
| 274 | testCast128(); | ||
| 275 | } | ||
| 276 | |||
| 277 | fn testCast128() void { | ||
| 278 | assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 279 | } | ||
| 280 | |||
| 281 | fn cast128Int(x: f128) u128 { | ||
| 282 | return @bitCast(u128, x); | ||
| 283 | } | ||
| 284 | |||
| 285 | fn cast128Float(x: u128) f128 { | ||
| 286 | return @bitCast(f128, x); | ||
| 287 | } | ||
| 288 | |||
| 289 | test "const slice widen cast" { | ||
| 290 | const bytes align(4) = []u8{ | ||
| 291 | 0x12, | ||
| 292 | 0x12, | ||
| 293 | 0x12, | ||
| 294 | 0x12, | ||
| 295 | }; | ||
| 296 | |||
| 297 | const u32_value = @bytesToSlice(u32, bytes[0..])[0]; | ||
| 298 | assertOrPanic(u32_value == 0x12121212); | ||
| 299 | |||
| 300 | assertOrPanic(@bitCast(u32, bytes) == 0x12121212); | ||
| 301 | } | ||
| 302 | |||
| 303 | test "single-item pointer of array to slice and to unknown length pointer" { | ||
| 304 | testCastPtrOfArrayToSliceAndPtr(); | ||
| 305 | comptime testCastPtrOfArrayToSliceAndPtr(); | ||
| 306 | } | ||
| 307 | |||
| 308 | fn testCastPtrOfArrayToSliceAndPtr() void { | ||
| 309 | var array = "aoeu"; | ||
| 310 | const x: [*]u8 = &array; | ||
| 311 | x[0] += 1; | ||
| 312 | assertOrPanic(mem.eql(u8, array[0..], "boeu")); | ||
| 313 | const y: []u8 = &array; | ||
| 314 | y[0] += 1; | ||
| 315 | assertOrPanic(mem.eql(u8, array[0..], "coeu")); | ||
| 316 | } | ||
| 317 | |||
| 318 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | ||
| 319 | const window_name = [1][*]const u8{c"window name"}; | ||
| 320 | const x: [*]const ?[*]const u8 = &window_name; | ||
| 321 | assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); | ||
| 322 | } | ||
| 323 | |||
| 324 | test "@intCast comptime_int" { | ||
| 325 | const result = @intCast(i32, 1234); | ||
| 326 | assertOrPanic(@typeOf(result) == i32); | ||
| 327 | assertOrPanic(result == 1234); | ||
| 328 | } | ||
| 329 | |||
| 330 | test "@floatCast comptime_int and comptime_float" { | ||
| 331 | { | ||
| 332 | const result = @floatCast(f16, 1234); | ||
| 333 | assertOrPanic(@typeOf(result) == f16); | ||
| 334 | assertOrPanic(result == 1234.0); | ||
| 335 | } | ||
| 336 | { | ||
| 337 | const result = @floatCast(f16, 1234.0); | ||
| 338 | assertOrPanic(@typeOf(result) == f16); | ||
| 339 | assertOrPanic(result == 1234.0); | ||
| 340 | } | ||
| 341 | { | ||
| 342 | const result = @floatCast(f32, 1234); | ||
| 343 | assertOrPanic(@typeOf(result) == f32); | ||
| 344 | assertOrPanic(result == 1234.0); | ||
| 345 | } | ||
| 346 | { | ||
| 347 | const result = @floatCast(f32, 1234.0); | ||
| 348 | assertOrPanic(@typeOf(result) == f32); | ||
| 349 | assertOrPanic(result == 1234.0); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | test "comptime_int @intToFloat" { | ||
| 354 | { | ||
| 355 | const result = @intToFloat(f16, 1234); | ||
| 356 | assertOrPanic(@typeOf(result) == f16); | ||
| 357 | assertOrPanic(result == 1234.0); | ||
| 358 | } | ||
| 359 | { | ||
| 360 | const result = @intToFloat(f32, 1234); | ||
| 361 | assertOrPanic(@typeOf(result) == f32); | ||
| 362 | assertOrPanic(result == 1234.0); | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | test "@bytesToSlice keeps pointer alignment" { | ||
| 367 | var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; | ||
| 368 | const numbers = @bytesToSlice(u32, bytes[0..]); | ||
| 369 | comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); | ||
| 370 | } | ||
| 371 | |||
| 372 | test "@intCast i32 to u7" { | ||
| 373 | var x: u128 = maxInt(u128); | ||
| 374 | var y: i32 = 120; | ||
| 375 | var z = x >> @intCast(u7, y); | ||
| 376 | assertOrPanic(z == 0xff); | ||
| 377 | } | ||
| 378 | |||
| 379 | test "implicit cast undefined to optional" { | ||
| 380 | assertOrPanic(MakeType(void).getNull() == null); | ||
| 381 | assertOrPanic(MakeType(void).getNonNull() != null); | ||
| 382 | } | ||
| 383 | |||
| 384 | fn MakeType(comptime T: type) type { | ||
| 385 | return struct { | ||
| 386 | fn getNull() ?T { | ||
| 387 | return null; | ||
| 388 | } | ||
| 389 | |||
| 390 | fn getNonNull() ?T { | ||
| 391 | return T(undefined); | ||
| 392 | } | ||
| 393 | }; | ||
| 394 | } | ||
| 395 | |||
| 396 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 397 | var x: ?[*]u16 = null; | ||
| 398 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 399 | |||
| 400 | x = &y; | ||
| 401 | assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 402 | x.?[0] = 8; | ||
| 403 | y[3] = 6; | ||
| 404 | assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 405 | } | ||
| 406 | |||
| 407 | test "implicit cast from *T to ?*c_void" { | ||
| 408 | var a: u8 = 1; | ||
| 409 | incrementVoidPtrValue(&a); | ||
| 410 | std.debug.assertOrPanic(a == 2); | ||
| 411 | } | ||
| 412 | |||
| 413 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 414 | @ptrCast(*u8, value.?).* += 1; | ||
| 415 | } | ||
| 416 | |||
| 417 | test "implicit cast from [*]T to ?*c_void" { | ||
| 418 | var a = []u8{ 3, 2, 1 }; | ||
| 419 | incrementVoidPtrArray(a[0..].ptr, 3); | ||
| 420 | assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); | ||
| 421 | } | ||
| 422 | |||
| 423 | fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { | ||
| 424 | var n: usize = 0; | ||
| 425 | while (n < len) : (n += 1) { | ||
| 426 | @ptrCast([*]u8, array.?)[n] += 1; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | test "*usize to *void" { | ||
| 431 | var i = usize(0); | ||
| 432 | var v = @ptrCast(*void, &i); | ||
| 433 | v.* = {}; | ||
| 434 | } | ||
| 435 | |||
| 436 | test "compile time int to ptr of function" { | ||
| 437 | foobar(FUNCTION_CONSTANT); | ||
| 438 | } | ||
| 439 | |||
| 440 | pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); | ||
| 441 | pub const PFN_void = extern fn (*c_void) void; | ||
| 442 | |||
| 443 | fn foobar(func: PFN_void) void { | ||
| 444 | std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize)); | ||
| 445 | } | ||
| 446 | |||
| 447 | test "implicit ptr to *c_void" { | ||
| 448 | var a: u32 = 1; | ||
| 449 | var ptr: *c_void = &a; | ||
| 450 | var b: *u32 = @ptrCast(*u32, ptr); | ||
| 451 | assertOrPanic(b.* == 1); | ||
| 452 | var ptr2: ?*c_void = &a; | ||
| 453 | var c: *u32 = @ptrCast(*u32, ptr2.?); | ||
| 454 | assertOrPanic(c.* == 1); | ||
| 455 | } | ||
| 456 | |||
| 457 | test "@intCast to comptime_int" { | ||
| 458 | assertOrPanic(@intCast(comptime_int, 0) == 0); | ||
| 459 | } | ||
| 460 | |||
| 461 | test "implicit cast comptime numbers to any type when the value fits" { | ||
| 462 | const a: u64 = 255; | ||
| 463 | var b: u8 = a; | ||
| 464 | assertOrPanic(b == 255); | ||
| 465 | } | ||
| 466 | |||
| 467 | test "@intToEnum passed a comptime_int to an enum with one item" { | ||
| 468 | const E = enum { | ||
| 469 | A, | ||
| 470 | }; | ||
| 471 | const x = @intToEnum(E, 0); | ||
| 472 | assertOrPanic(x == E.A); | ||
| 473 | } | ||
test/stage1/behavior/const_slice_child.zig created+45| ... | @@ -0,0 +1,45 @@ | ||
| 1 | const debug = @import("std").debug; | ||
| 2 | const assertOrPanic = debug.assertOrPanic; | ||
| 3 | |||
| 4 | var argv: [*]const [*]const u8 = undefined; | ||
| 5 | |||
| 6 | test "const slice child" { | ||
| 7 | const strs = ([][*]const u8){ | ||
| 8 | c"one", | ||
| 9 | c"two", | ||
| 10 | c"three", | ||
| 11 | }; | ||
| 12 | // TODO this should implicitly cast | ||
| 13 | argv = @ptrCast([*]const [*]const u8, &strs); | ||
| 14 | bar(strs.len); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn foo(args: [][]const u8) void { | ||
| 18 | assertOrPanic(args.len == 3); | ||
| 19 | assertOrPanic(streql(args[0], "one")); | ||
| 20 | assertOrPanic(streql(args[1], "two")); | ||
| 21 | assertOrPanic(streql(args[2], "three")); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn bar(argc: usize) void { | ||
| 25 | const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable; | ||
| 26 | for (args) |_, i| { | ||
| 27 | const ptr = argv[i]; | ||
| 28 | args[i] = ptr[0..strlen(ptr)]; | ||
| 29 | } | ||
| 30 | foo(args); | ||
| 31 | } | ||
| 32 | |||
| 33 | fn strlen(ptr: [*]const u8) usize { | ||
| 34 | var count: usize = 0; | ||
| 35 | while (ptr[count] != 0) : (count += 1) {} | ||
| 36 | return count; | ||
| 37 | } | ||
| 38 | |||
| 39 | fn streql(a: []const u8, b: []const u8) bool { | ||
| 40 | if (a.len != b.len) return false; | ||
| 41 | for (a) |item, index| { | ||
| 42 | if (b[index] != item) return false; | ||
| 43 | } | ||
| 44 | return true; | ||
| 45 | } | ||
test/stage1/behavior/coroutine_await_struct.zig created+47| ... | @@ -0,0 +1,47 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | const Foo = struct { | ||
| 6 | x: i32, | ||
| 7 | }; | ||
| 8 | |||
| 9 | var await_a_promise: promise = undefined; | ||
| 10 | var await_final_result = Foo{ .x = 0 }; | ||
| 11 | |||
| 12 | test "coroutine await struct" { | ||
| 13 | var da = std.heap.DirectAllocator.init(); | ||
| 14 | defer da.deinit(); | ||
| 15 | |||
| 16 | await_seq('a'); | ||
| 17 | const p = async<&da.allocator> await_amain() catch unreachable; | ||
| 18 | await_seq('f'); | ||
| 19 | resume await_a_promise; | ||
| 20 | await_seq('i'); | ||
| 21 | assertOrPanic(await_final_result.x == 1234); | ||
| 22 | assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); | ||
| 23 | } | ||
| 24 | async fn await_amain() void { | ||
| 25 | await_seq('b'); | ||
| 26 | const p = async await_another() catch unreachable; | ||
| 27 | await_seq('e'); | ||
| 28 | await_final_result = await p; | ||
| 29 | await_seq('h'); | ||
| 30 | } | ||
| 31 | async fn await_another() Foo { | ||
| 32 | await_seq('c'); | ||
| 33 | suspend { | ||
| 34 | await_seq('d'); | ||
| 35 | await_a_promise = @handle(); | ||
| 36 | } | ||
| 37 | await_seq('g'); | ||
| 38 | return Foo{ .x = 1234 }; | ||
| 39 | } | ||
| 40 | |||
| 41 | var await_points = []u8{0} ** "abcdefghi".len; | ||
| 42 | var await_seq_index: usize = 0; | ||
| 43 | |||
| 44 | fn await_seq(c: u8) void { | ||
| 45 | await_points[await_seq_index] = c; | ||
| 46 | await_seq_index += 1; | ||
| 47 | } | ||
test/stage1/behavior/coroutines.zig created+258| ... | @@ -0,0 +1,258 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | var x: i32 = 1; | ||
| 6 | |||
| 7 | test "create a coroutine and cancel it" { | ||
| 8 | var da = std.heap.DirectAllocator.init(); | ||
| 9 | defer da.deinit(); | ||
| 10 | |||
| 11 | const p = try async<&da.allocator> simpleAsyncFn(); | ||
| 12 | comptime assertOrPanic(@typeOf(p) == promise->void); | ||
| 13 | cancel p; | ||
| 14 | assertOrPanic(x == 2); | ||
| 15 | } | ||
| 16 | async fn simpleAsyncFn() void { | ||
| 17 | x += 1; | ||
| 18 | suspend; | ||
| 19 | x += 1; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "coroutine suspend, resume, cancel" { | ||
| 23 | var da = std.heap.DirectAllocator.init(); | ||
| 24 | defer da.deinit(); | ||
| 25 | |||
| 26 | seq('a'); | ||
| 27 | const p = try async<&da.allocator> testAsyncSeq(); | ||
| 28 | seq('c'); | ||
| 29 | resume p; | ||
| 30 | seq('f'); | ||
| 31 | cancel p; | ||
| 32 | seq('g'); | ||
| 33 | |||
| 34 | assertOrPanic(std.mem.eql(u8, points, "abcdefg")); | ||
| 35 | } | ||
| 36 | async fn testAsyncSeq() void { | ||
| 37 | defer seq('e'); | ||
| 38 | |||
| 39 | seq('b'); | ||
| 40 | suspend; | ||
| 41 | seq('d'); | ||
| 42 | } | ||
| 43 | var points = []u8{0} ** "abcdefg".len; | ||
| 44 | var index: usize = 0; | ||
| 45 | |||
| 46 | fn seq(c: u8) void { | ||
| 47 | points[index] = c; | ||
| 48 | index += 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | test "coroutine suspend with block" { | ||
| 52 | var da = std.heap.DirectAllocator.init(); | ||
| 53 | defer da.deinit(); | ||
| 54 | |||
| 55 | const p = try async<&da.allocator> testSuspendBlock(); | ||
| 56 | std.debug.assertOrPanic(!result); | ||
| 57 | resume a_promise; | ||
| 58 | std.debug.assertOrPanic(result); | ||
| 59 | cancel p; | ||
| 60 | } | ||
| 61 | |||
| 62 | var a_promise: promise = undefined; | ||
| 63 | var result = false; | ||
| 64 | async fn testSuspendBlock() void { | ||
| 65 | suspend { | ||
| 66 | comptime assertOrPanic(@typeOf(@handle()) == promise->void); | ||
| 67 | a_promise = @handle(); | ||
| 68 | } | ||
| 69 | |||
| 70 | //Test to make sure that @handle() works as advertised (issue #1296) | ||
| 71 | //var our_handle: promise = @handle(); | ||
| 72 | assertOrPanic(a_promise == @handle()); | ||
| 73 | |||
| 74 | result = true; | ||
| 75 | } | ||
| 76 | |||
| 77 | var await_a_promise: promise = undefined; | ||
| 78 | var await_final_result: i32 = 0; | ||
| 79 | |||
| 80 | test "coroutine await" { | ||
| 81 | var da = std.heap.DirectAllocator.init(); | ||
| 82 | defer da.deinit(); | ||
| 83 | |||
| 84 | await_seq('a'); | ||
| 85 | const p = async<&da.allocator> await_amain() catch unreachable; | ||
| 86 | await_seq('f'); | ||
| 87 | resume await_a_promise; | ||
| 88 | await_seq('i'); | ||
| 89 | assertOrPanic(await_final_result == 1234); | ||
| 90 | assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); | ||
| 91 | } | ||
| 92 | async fn await_amain() void { | ||
| 93 | await_seq('b'); | ||
| 94 | const p = async await_another() catch unreachable; | ||
| 95 | await_seq('e'); | ||
| 96 | await_final_result = await p; | ||
| 97 | await_seq('h'); | ||
| 98 | } | ||
| 99 | async fn await_another() i32 { | ||
| 100 | await_seq('c'); | ||
| 101 | suspend { | ||
| 102 | await_seq('d'); | ||
| 103 | await_a_promise = @handle(); | ||
| 104 | } | ||
| 105 | await_seq('g'); | ||
| 106 | return 1234; | ||
| 107 | } | ||
| 108 | |||
| 109 | var await_points = []u8{0} ** "abcdefghi".len; | ||
| 110 | var await_seq_index: usize = 0; | ||
| 111 | |||
| 112 | fn await_seq(c: u8) void { | ||
| 113 | await_points[await_seq_index] = c; | ||
| 114 | await_seq_index += 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | var early_final_result: i32 = 0; | ||
| 118 | |||
| 119 | test "coroutine await early return" { | ||
| 120 | var da = std.heap.DirectAllocator.init(); | ||
| 121 | defer da.deinit(); | ||
| 122 | |||
| 123 | early_seq('a'); | ||
| 124 | const p = async<&da.allocator> early_amain() catch @panic("out of memory"); | ||
| 125 | early_seq('f'); | ||
| 126 | assertOrPanic(early_final_result == 1234); | ||
| 127 | assertOrPanic(std.mem.eql(u8, early_points, "abcdef")); | ||
| 128 | } | ||
| 129 | async fn early_amain() void { | ||
| 130 | early_seq('b'); | ||
| 131 | const p = async early_another() catch @panic("out of memory"); | ||
| 132 | early_seq('d'); | ||
| 133 | early_final_result = await p; | ||
| 134 | early_seq('e'); | ||
| 135 | } | ||
| 136 | async fn early_another() i32 { | ||
| 137 | early_seq('c'); | ||
| 138 | return 1234; | ||
| 139 | } | ||
| 140 | |||
| 141 | var early_points = []u8{0} ** "abcdef".len; | ||
| 142 | var early_seq_index: usize = 0; | ||
| 143 | |||
| 144 | fn early_seq(c: u8) void { | ||
| 145 | early_points[early_seq_index] = c; | ||
| 146 | early_seq_index += 1; | ||
| 147 | } | ||
| 148 | |||
| 149 | test "coro allocation failure" { | ||
| 150 | var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); | ||
| 151 | if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { | ||
| 152 | @panic("expected allocation failure"); | ||
| 153 | } else |err| switch (err) { | ||
| 154 | error.OutOfMemory => {}, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | async fn asyncFuncThatNeverGetsRun() void { | ||
| 158 | @panic("coro frame allocation should fail"); | ||
| 159 | } | ||
| 160 | |||
| 161 | test "async function with dot syntax" { | ||
| 162 | const S = struct { | ||
| 163 | var y: i32 = 1; | ||
| 164 | async fn foo() void { | ||
| 165 | y += 1; | ||
| 166 | suspend; | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | var da = std.heap.DirectAllocator.init(); | ||
| 170 | defer da.deinit(); | ||
| 171 | const p = try async<&da.allocator> S.foo(); | ||
| 172 | cancel p; | ||
| 173 | assertOrPanic(S.y == 2); | ||
| 174 | } | ||
| 175 | |||
| 176 | test "async fn pointer in a struct field" { | ||
| 177 | var data: i32 = 1; | ||
| 178 | const Foo = struct { | ||
| 179 | bar: async<*std.mem.Allocator> fn (*i32) void, | ||
| 180 | }; | ||
| 181 | var foo = Foo{ .bar = simpleAsyncFn2 }; | ||
| 182 | var da = std.heap.DirectAllocator.init(); | ||
| 183 | defer da.deinit(); | ||
| 184 | const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; | ||
| 185 | assertOrPanic(data == 2); | ||
| 186 | cancel p; | ||
| 187 | assertOrPanic(data == 4); | ||
| 188 | } | ||
| 189 | async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { | ||
| 190 | defer y.* += 2; | ||
| 191 | y.* += 1; | ||
| 192 | suspend; | ||
| 193 | } | ||
| 194 | |||
| 195 | test "async fn with inferred error set" { | ||
| 196 | var da = std.heap.DirectAllocator.init(); | ||
| 197 | defer da.deinit(); | ||
| 198 | const p = (async<&da.allocator> failing()) catch unreachable; | ||
| 199 | resume p; | ||
| 200 | cancel p; | ||
| 201 | } | ||
| 202 | |||
| 203 | async fn failing() !void { | ||
| 204 | suspend; | ||
| 205 | return error.Fail; | ||
| 206 | } | ||
| 207 | |||
| 208 | test "error return trace across suspend points - early return" { | ||
| 209 | const p = nonFailing(); | ||
| 210 | resume p; | ||
| 211 | var da = std.heap.DirectAllocator.init(); | ||
| 212 | defer da.deinit(); | ||
| 213 | const p2 = try async<&da.allocator> printTrace(p); | ||
| 214 | cancel p2; | ||
| 215 | } | ||
| 216 | |||
| 217 | test "error return trace across suspend points - async return" { | ||
| 218 | const p = nonFailing(); | ||
| 219 | const p2 = try async<std.debug.global_allocator> printTrace(p); | ||
| 220 | resume p; | ||
| 221 | cancel p2; | ||
| 222 | } | ||
| 223 | |||
| 224 | fn nonFailing() (promise->anyerror!void) { | ||
| 225 | return async<std.debug.global_allocator> suspendThenFail() catch unreachable; | ||
| 226 | } | ||
| 227 | async fn suspendThenFail() anyerror!void { | ||
| 228 | suspend; | ||
| 229 | return error.Fail; | ||
| 230 | } | ||
| 231 | async fn printTrace(p: promise->(anyerror!void)) void { | ||
| 232 | (await p) catch |e| { | ||
| 233 | std.debug.assertOrPanic(e == error.Fail); | ||
| 234 | if (@errorReturnTrace()) |trace| { | ||
| 235 | assertOrPanic(trace.index == 1); | ||
| 236 | } else switch (builtin.mode) { | ||
| 237 | builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), | ||
| 238 | builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | } | ||
| 242 | |||
| 243 | test "break from suspend" { | ||
| 244 | var buf: [500]u8 = undefined; | ||
| 245 | var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; | ||
| 246 | var my_result: i32 = 1; | ||
| 247 | const p = try async<a> testBreakFromSuspend(&my_result); | ||
| 248 | cancel p; | ||
| 249 | std.debug.assertOrPanic(my_result == 2); | ||
| 250 | } | ||
| 251 | async fn testBreakFromSuspend(my_result: *i32) void { | ||
| 252 | suspend { | ||
| 253 | resume @handle(); | ||
| 254 | } | ||
| 255 | my_result.* += 1; | ||
| 256 | suspend; | ||
| 257 | my_result.* += 1; | ||
| 258 | } | ||
test/stage1/behavior/defer.zig created+78| ... | @@ -0,0 +1,78 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | var result: [3]u8 = undefined; | ||
| 4 | var index: usize = undefined; | ||
| 5 | |||
| 6 | fn runSomeErrorDefers(x: bool) !bool { | ||
| 7 | index = 0; | ||
| 8 | defer { | ||
| 9 | result[index] = 'a'; | ||
| 10 | index += 1; | ||
| 11 | } | ||
| 12 | errdefer { | ||
| 13 | result[index] = 'b'; | ||
| 14 | index += 1; | ||
| 15 | } | ||
| 16 | defer { | ||
| 17 | result[index] = 'c'; | ||
| 18 | index += 1; | ||
| 19 | } | ||
| 20 | return if (x) x else error.FalseNotAllowed; | ||
| 21 | } | ||
| 22 | |||
| 23 | test "mixing normal and error defers" { | ||
| 24 | assertOrPanic(runSomeErrorDefers(true) catch unreachable); | ||
| 25 | assertOrPanic(result[0] == 'c'); | ||
| 26 | assertOrPanic(result[1] == 'a'); | ||
| 27 | |||
| 28 | const ok = runSomeErrorDefers(false) catch |err| x: { | ||
| 29 | assertOrPanic(err == error.FalseNotAllowed); | ||
| 30 | break :x true; | ||
| 31 | }; | ||
| 32 | assertOrPanic(ok); | ||
| 33 | assertOrPanic(result[0] == 'c'); | ||
| 34 | assertOrPanic(result[1] == 'b'); | ||
| 35 | assertOrPanic(result[2] == 'a'); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "break and continue inside loop inside defer expression" { | ||
| 39 | testBreakContInDefer(10); | ||
| 40 | comptime testBreakContInDefer(10); | ||
| 41 | } | ||
| 42 | |||
| 43 | fn testBreakContInDefer(x: usize) void { | ||
| 44 | defer { | ||
| 45 | var i: usize = 0; | ||
| 46 | while (i < x) : (i += 1) { | ||
| 47 | if (i < 5) continue; | ||
| 48 | if (i == 5) break; | ||
| 49 | } | ||
| 50 | assertOrPanic(i == 5); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | test "defer and labeled break" { | ||
| 55 | var i = usize(0); | ||
| 56 | |||
| 57 | blk: { | ||
| 58 | defer i += 1; | ||
| 59 | break :blk; | ||
| 60 | } | ||
| 61 | |||
| 62 | assertOrPanic(i == 1); | ||
| 63 | } | ||
| 64 | |||
| 65 | test "errdefer does not apply to fn inside fn" { | ||
| 66 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn testNestedFnErrDefer() anyerror!void { | ||
| 70 | var a: i32 = 0; | ||
| 71 | errdefer a += 1; | ||
| 72 | const S = struct { | ||
| 73 | fn baz() anyerror { | ||
| 74 | return error.Bad; | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | return S.baz(); | ||
| 78 | } | ||
test/stage1/behavior/enum.zig created+894| ... | @@ -0,0 +1,894 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | test "enum type" { | ||
| 5 | const foo1 = Foo{ .One = 13 }; | ||
| 6 | const foo2 = Foo{ | ||
| 7 | .Two = Point{ | ||
| 8 | .x = 1234, | ||
| 9 | .y = 5678, | ||
| 10 | }, | ||
| 11 | }; | ||
| 12 | const bar = Bar.B; | ||
| 13 | |||
| 14 | assertOrPanic(bar == Bar.B); | ||
| 15 | assertOrPanic(@memberCount(Foo) == 3); | ||
| 16 | assertOrPanic(@memberCount(Bar) == 4); | ||
| 17 | assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid)); | ||
| 18 | assertOrPanic(@sizeOf(Bar) == 1); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "enum as return value" { | ||
| 22 | switch (returnAnInt(13)) { | ||
| 23 | Foo.One => |value| assertOrPanic(value == 13), | ||
| 24 | else => unreachable, | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | const Point = struct { | ||
| 29 | x: u64, | ||
| 30 | y: u64, | ||
| 31 | }; | ||
| 32 | const Foo = union(enum) { | ||
| 33 | One: i32, | ||
| 34 | Two: Point, | ||
| 35 | Three: void, | ||
| 36 | }; | ||
| 37 | const FooNoVoid = union(enum) { | ||
| 38 | One: i32, | ||
| 39 | Two: Point, | ||
| 40 | }; | ||
| 41 | const Bar = enum { | ||
| 42 | A, | ||
| 43 | B, | ||
| 44 | C, | ||
| 45 | D, | ||
| 46 | }; | ||
| 47 | |||
| 48 | fn returnAnInt(x: i32) Foo { | ||
| 49 | return Foo{ .One = x }; | ||
| 50 | } | ||
| 51 | |||
| 52 | test "constant enum with payload" { | ||
| 53 | var empty = AnEnumWithPayload{ .Empty = {} }; | ||
| 54 | var full = AnEnumWithPayload{ .Full = 13 }; | ||
| 55 | shouldBeEmpty(empty); | ||
| 56 | shouldBeNotEmpty(full); | ||
| 57 | } | ||
| 58 | |||
| 59 | fn shouldBeEmpty(x: AnEnumWithPayload) void { | ||
| 60 | switch (x) { | ||
| 61 | AnEnumWithPayload.Empty => {}, | ||
| 62 | else => unreachable, | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | fn shouldBeNotEmpty(x: AnEnumWithPayload) void { | ||
| 67 | switch (x) { | ||
| 68 | AnEnumWithPayload.Empty => unreachable, | ||
| 69 | else => {}, | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | const AnEnumWithPayload = union(enum) { | ||
| 74 | Empty: void, | ||
| 75 | Full: i32, | ||
| 76 | }; | ||
| 77 | |||
| 78 | const Number = enum { | ||
| 79 | Zero, | ||
| 80 | One, | ||
| 81 | Two, | ||
| 82 | Three, | ||
| 83 | Four, | ||
| 84 | }; | ||
| 85 | |||
| 86 | test "enum to int" { | ||
| 87 | shouldEqual(Number.Zero, 0); | ||
| 88 | shouldEqual(Number.One, 1); | ||
| 89 | shouldEqual(Number.Two, 2); | ||
| 90 | shouldEqual(Number.Three, 3); | ||
| 91 | shouldEqual(Number.Four, 4); | ||
| 92 | } | ||
| 93 | |||
| 94 | fn shouldEqual(n: Number, expected: u3) void { | ||
| 95 | assertOrPanic(@enumToInt(n) == expected); | ||
| 96 | } | ||
| 97 | |||
| 98 | test "int to enum" { | ||
| 99 | testIntToEnumEval(3); | ||
| 100 | } | ||
| 101 | fn testIntToEnumEval(x: i32) void { | ||
| 102 | assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); | ||
| 103 | } | ||
| 104 | const IntToEnumNumber = enum { | ||
| 105 | Zero, | ||
| 106 | One, | ||
| 107 | Two, | ||
| 108 | Three, | ||
| 109 | Four, | ||
| 110 | }; | ||
| 111 | |||
| 112 | test "@tagName" { | ||
| 113 | assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 114 | comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 115 | } | ||
| 116 | |||
| 117 | fn testEnumTagNameBare(n: BareNumber) []const u8 { | ||
| 118 | return @tagName(n); | ||
| 119 | } | ||
| 120 | |||
| 121 | const BareNumber = enum { | ||
| 122 | One, | ||
| 123 | Two, | ||
| 124 | Three, | ||
| 125 | }; | ||
| 126 | |||
| 127 | test "enum alignment" { | ||
| 128 | comptime { | ||
| 129 | assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); | ||
| 130 | assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64)); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | const AlignTestEnum = union(enum) { | ||
| 135 | A: [9]u8, | ||
| 136 | B: u64, | ||
| 137 | }; | ||
| 138 | |||
| 139 | const ValueCount1 = enum { | ||
| 140 | I0, | ||
| 141 | }; | ||
| 142 | const ValueCount2 = enum { | ||
| 143 | I0, | ||
| 144 | I1, | ||
| 145 | }; | ||
| 146 | const ValueCount256 = enum { | ||
| 147 | I0, | ||
| 148 | I1, | ||
| 149 | I2, | ||
| 150 | I3, | ||
| 151 | I4, | ||
| 152 | I5, | ||
| 153 | I6, | ||
| 154 | I7, | ||
| 155 | I8, | ||
| 156 | I9, | ||
| 157 | I10, | ||
| 158 | I11, | ||
| 159 | I12, | ||
| 160 | I13, | ||
| 161 | I14, | ||
| 162 | I15, | ||
| 163 | I16, | ||
| 164 | I17, | ||
| 165 | I18, | ||
| 166 | I19, | ||
| 167 | I20, | ||
| 168 | I21, | ||
| 169 | I22, | ||
| 170 | I23, | ||
| 171 | I24, | ||
| 172 | I25, | ||
| 173 | I26, | ||
| 174 | I27, | ||
| 175 | I28, | ||
| 176 | I29, | ||
| 177 | I30, | ||
| 178 | I31, | ||
| 179 | I32, | ||
| 180 | I33, | ||
| 181 | I34, | ||
| 182 | I35, | ||
| 183 | I36, | ||
| 184 | I37, | ||
| 185 | I38, | ||
| 186 | I39, | ||
| 187 | I40, | ||
| 188 | I41, | ||
| 189 | I42, | ||
| 190 | I43, | ||
| 191 | I44, | ||
| 192 | I45, | ||
| 193 | I46, | ||
| 194 | I47, | ||
| 195 | I48, | ||
| 196 | I49, | ||
| 197 | I50, | ||
| 198 | I51, | ||
| 199 | I52, | ||
| 200 | I53, | ||
| 201 | I54, | ||
| 202 | I55, | ||
| 203 | I56, | ||
| 204 | I57, | ||
| 205 | I58, | ||
| 206 | I59, | ||
| 207 | I60, | ||
| 208 | I61, | ||
| 209 | I62, | ||
| 210 | I63, | ||
| 211 | I64, | ||
| 212 | I65, | ||
| 213 | I66, | ||
| 214 | I67, | ||
| 215 | I68, | ||
| 216 | I69, | ||
| 217 | I70, | ||
| 218 | I71, | ||
| 219 | I72, | ||
| 220 | I73, | ||
| 221 | I74, | ||
| 222 | I75, | ||
| 223 | I76, | ||
| 224 | I77, | ||
| 225 | I78, | ||
| 226 | I79, | ||
| 227 | I80, | ||
| 228 | I81, | ||
| 229 | I82, | ||
| 230 | I83, | ||
| 231 | I84, | ||
| 232 | I85, | ||
| 233 | I86, | ||
| 234 | I87, | ||
| 235 | I88, | ||
| 236 | I89, | ||
| 237 | I90, | ||
| 238 | I91, | ||
| 239 | I92, | ||
| 240 | I93, | ||
| 241 | I94, | ||
| 242 | I95, | ||
| 243 | I96, | ||
| 244 | I97, | ||
| 245 | I98, | ||
| 246 | I99, | ||
| 247 | I100, | ||
| 248 | I101, | ||
| 249 | I102, | ||
| 250 | I103, | ||
| 251 | I104, | ||
| 252 | I105, | ||
| 253 | I106, | ||
| 254 | I107, | ||
| 255 | I108, | ||
| 256 | I109, | ||
| 257 | I110, | ||
| 258 | I111, | ||
| 259 | I112, | ||
| 260 | I113, | ||
| 261 | I114, | ||
| 262 | I115, | ||
| 263 | I116, | ||
| 264 | I117, | ||
| 265 | I118, | ||
| 266 | I119, | ||
| 267 | I120, | ||
| 268 | I121, | ||
| 269 | I122, | ||
| 270 | I123, | ||
| 271 | I124, | ||
| 272 | I125, | ||
| 273 | I126, | ||
| 274 | I127, | ||
| 275 | I128, | ||
| 276 | I129, | ||
| 277 | I130, | ||
| 278 | I131, | ||
| 279 | I132, | ||
| 280 | I133, | ||
| 281 | I134, | ||
| 282 | I135, | ||
| 283 | I136, | ||
| 284 | I137, | ||
| 285 | I138, | ||
| 286 | I139, | ||
| 287 | I140, | ||
| 288 | I141, | ||
| 289 | I142, | ||
| 290 | I143, | ||
| 291 | I144, | ||
| 292 | I145, | ||
| 293 | I146, | ||
| 294 | I147, | ||
| 295 | I148, | ||
| 296 | I149, | ||
| 297 | I150, | ||
| 298 | I151, | ||
| 299 | I152, | ||
| 300 | I153, | ||
| 301 | I154, | ||
| 302 | I155, | ||
| 303 | I156, | ||
| 304 | I157, | ||
| 305 | I158, | ||
| 306 | I159, | ||
| 307 | I160, | ||
| 308 | I161, | ||
| 309 | I162, | ||
| 310 | I163, | ||
| 311 | I164, | ||
| 312 | I165, | ||
| 313 | I166, | ||
| 314 | I167, | ||
| 315 | I168, | ||
| 316 | I169, | ||
| 317 | I170, | ||
| 318 | I171, | ||
| 319 | I172, | ||
| 320 | I173, | ||
| 321 | I174, | ||
| 322 | I175, | ||
| 323 | I176, | ||
| 324 | I177, | ||
| 325 | I178, | ||
| 326 | I179, | ||
| 327 | I180, | ||
| 328 | I181, | ||
| 329 | I182, | ||
| 330 | I183, | ||
| 331 | I184, | ||
| 332 | I185, | ||
| 333 | I186, | ||
| 334 | I187, | ||
| 335 | I188, | ||
| 336 | I189, | ||
| 337 | I190, | ||
| 338 | I191, | ||
| 339 | I192, | ||
| 340 | I193, | ||
| 341 | I194, | ||
| 342 | I195, | ||
| 343 | I196, | ||
| 344 | I197, | ||
| 345 | I198, | ||
| 346 | I199, | ||
| 347 | I200, | ||
| 348 | I201, | ||
| 349 | I202, | ||
| 350 | I203, | ||
| 351 | I204, | ||
| 352 | I205, | ||
| 353 | I206, | ||
| 354 | I207, | ||
| 355 | I208, | ||
| 356 | I209, | ||
| 357 | I210, | ||
| 358 | I211, | ||
| 359 | I212, | ||
| 360 | I213, | ||
| 361 | I214, | ||
| 362 | I215, | ||
| 363 | I216, | ||
| 364 | I217, | ||
| 365 | I218, | ||
| 366 | I219, | ||
| 367 | I220, | ||
| 368 | I221, | ||
| 369 | I222, | ||
| 370 | I223, | ||
| 371 | I224, | ||
| 372 | I225, | ||
| 373 | I226, | ||
| 374 | I227, | ||
| 375 | I228, | ||
| 376 | I229, | ||
| 377 | I230, | ||
| 378 | I231, | ||
| 379 | I232, | ||
| 380 | I233, | ||
| 381 | I234, | ||
| 382 | I235, | ||
| 383 | I236, | ||
| 384 | I237, | ||
| 385 | I238, | ||
| 386 | I239, | ||
| 387 | I240, | ||
| 388 | I241, | ||
| 389 | I242, | ||
| 390 | I243, | ||
| 391 | I244, | ||
| 392 | I245, | ||
| 393 | I246, | ||
| 394 | I247, | ||
| 395 | I248, | ||
| 396 | I249, | ||
| 397 | I250, | ||
| 398 | I251, | ||
| 399 | I252, | ||
| 400 | I253, | ||
| 401 | I254, | ||
| 402 | I255, | ||
| 403 | }; | ||
| 404 | const ValueCount257 = enum { | ||
| 405 | I0, | ||
| 406 | I1, | ||
| 407 | I2, | ||
| 408 | I3, | ||
| 409 | I4, | ||
| 410 | I5, | ||
| 411 | I6, | ||
| 412 | I7, | ||
| 413 | I8, | ||
| 414 | I9, | ||
| 415 | I10, | ||
| 416 | I11, | ||
| 417 | I12, | ||
| 418 | I13, | ||
| 419 | I14, | ||
| 420 | I15, | ||
| 421 | I16, | ||
| 422 | I17, | ||
| 423 | I18, | ||
| 424 | I19, | ||
| 425 | I20, | ||
| 426 | I21, | ||
| 427 | I22, | ||
| 428 | I23, | ||
| 429 | I24, | ||
| 430 | I25, | ||
| 431 | I26, | ||
| 432 | I27, | ||
| 433 | I28, | ||
| 434 | I29, | ||
| 435 | I30, | ||
| 436 | I31, | ||
| 437 | I32, | ||
| 438 | I33, | ||
| 439 | I34, | ||
| 440 | I35, | ||
| 441 | I36, | ||
| 442 | I37, | ||
| 443 | I38, | ||
| 444 | I39, | ||
| 445 | I40, | ||
| 446 | I41, | ||
| 447 | I42, | ||
| 448 | I43, | ||
| 449 | I44, | ||
| 450 | I45, | ||
| 451 | I46, | ||
| 452 | I47, | ||
| 453 | I48, | ||
| 454 | I49, | ||
| 455 | I50, | ||
| 456 | I51, | ||
| 457 | I52, | ||
| 458 | I53, | ||
| 459 | I54, | ||
| 460 | I55, | ||
| 461 | I56, | ||
| 462 | I57, | ||
| 463 | I58, | ||
| 464 | I59, | ||
| 465 | I60, | ||
| 466 | I61, | ||
| 467 | I62, | ||
| 468 | I63, | ||
| 469 | I64, | ||
| 470 | I65, | ||
| 471 | I66, | ||
| 472 | I67, | ||
| 473 | I68, | ||
| 474 | I69, | ||
| 475 | I70, | ||
| 476 | I71, | ||
| 477 | I72, | ||
| 478 | I73, | ||
| 479 | I74, | ||
| 480 | I75, | ||
| 481 | I76, | ||
| 482 | I77, | ||
| 483 | I78, | ||
| 484 | I79, | ||
| 485 | I80, | ||
| 486 | I81, | ||
| 487 | I82, | ||
| 488 | I83, | ||
| 489 | I84, | ||
| 490 | I85, | ||
| 491 | I86, | ||
| 492 | I87, | ||
| 493 | I88, | ||
| 494 | I89, | ||
| 495 | I90, | ||
| 496 | I91, | ||
| 497 | I92, | ||
| 498 | I93, | ||
| 499 | I94, | ||
| 500 | I95, | ||
| 501 | I96, | ||
| 502 | I97, | ||
| 503 | I98, | ||
| 504 | I99, | ||
| 505 | I100, | ||
| 506 | I101, | ||
| 507 | I102, | ||
| 508 | I103, | ||
| 509 | I104, | ||
| 510 | I105, | ||
| 511 | I106, | ||
| 512 | I107, | ||
| 513 | I108, | ||
| 514 | I109, | ||
| 515 | I110, | ||
| 516 | I111, | ||
| 517 | I112, | ||
| 518 | I113, | ||
| 519 | I114, | ||
| 520 | I115, | ||
| 521 | I116, | ||
| 522 | I117, | ||
| 523 | I118, | ||
| 524 | I119, | ||
| 525 | I120, | ||
| 526 | I121, | ||
| 527 | I122, | ||
| 528 | I123, | ||
| 529 | I124, | ||
| 530 | I125, | ||
| 531 | I126, | ||
| 532 | I127, | ||
| 533 | I128, | ||
| 534 | I129, | ||
| 535 | I130, | ||
| 536 | I131, | ||
| 537 | I132, | ||
| 538 | I133, | ||
| 539 | I134, | ||
| 540 | I135, | ||
| 541 | I136, | ||
| 542 | I137, | ||
| 543 | I138, | ||
| 544 | I139, | ||
| 545 | I140, | ||
| 546 | I141, | ||
| 547 | I142, | ||
| 548 | I143, | ||
| 549 | I144, | ||
| 550 | I145, | ||
| 551 | I146, | ||
| 552 | I147, | ||
| 553 | I148, | ||
| 554 | I149, | ||
| 555 | I150, | ||
| 556 | I151, | ||
| 557 | I152, | ||
| 558 | I153, | ||
| 559 | I154, | ||
| 560 | I155, | ||
| 561 | I156, | ||
| 562 | I157, | ||
| 563 | I158, | ||
| 564 | I159, | ||
| 565 | I160, | ||
| 566 | I161, | ||
| 567 | I162, | ||
| 568 | I163, | ||
| 569 | I164, | ||
| 570 | I165, | ||
| 571 | I166, | ||
| 572 | I167, | ||
| 573 | I168, | ||
| 574 | I169, | ||
| 575 | I170, | ||
| 576 | I171, | ||
| 577 | I172, | ||
| 578 | I173, | ||
| 579 | I174, | ||
| 580 | I175, | ||
| 581 | I176, | ||
| 582 | I177, | ||
| 583 | I178, | ||
| 584 | I179, | ||
| 585 | I180, | ||
| 586 | I181, | ||
| 587 | I182, | ||
| 588 | I183, | ||
| 589 | I184, | ||
| 590 | I185, | ||
| 591 | I186, | ||
| 592 | I187, | ||
| 593 | I188, | ||
| 594 | I189, | ||
| 595 | I190, | ||
| 596 | I191, | ||
| 597 | I192, | ||
| 598 | I193, | ||
| 599 | I194, | ||
| 600 | I195, | ||
| 601 | I196, | ||
| 602 | I197, | ||
| 603 | I198, | ||
| 604 | I199, | ||
| 605 | I200, | ||
| 606 | I201, | ||
| 607 | I202, | ||
| 608 | I203, | ||
| 609 | I204, | ||
| 610 | I205, | ||
| 611 | I206, | ||
| 612 | I207, | ||
| 613 | I208, | ||
| 614 | I209, | ||
| 615 | I210, | ||
| 616 | I211, | ||
| 617 | I212, | ||
| 618 | I213, | ||
| 619 | I214, | ||
| 620 | I215, | ||
| 621 | I216, | ||
| 622 | I217, | ||
| 623 | I218, | ||
| 624 | I219, | ||
| 625 | I220, | ||
| 626 | I221, | ||
| 627 | I222, | ||
| 628 | I223, | ||
| 629 | I224, | ||
| 630 | I225, | ||
| 631 | I226, | ||
| 632 | I227, | ||
| 633 | I228, | ||
| 634 | I229, | ||
| 635 | I230, | ||
| 636 | I231, | ||
| 637 | I232, | ||
| 638 | I233, | ||
| 639 | I234, | ||
| 640 | I235, | ||
| 641 | I236, | ||
| 642 | I237, | ||
| 643 | I238, | ||
| 644 | I239, | ||
| 645 | I240, | ||
| 646 | I241, | ||
| 647 | I242, | ||
| 648 | I243, | ||
| 649 | I244, | ||
| 650 | I245, | ||
| 651 | I246, | ||
| 652 | I247, | ||
| 653 | I248, | ||
| 654 | I249, | ||
| 655 | I250, | ||
| 656 | I251, | ||
| 657 | I252, | ||
| 658 | I253, | ||
| 659 | I254, | ||
| 660 | I255, | ||
| 661 | I256, | ||
| 662 | }; | ||
| 663 | |||
| 664 | test "enum sizes" { | ||
| 665 | comptime { | ||
| 666 | assertOrPanic(@sizeOf(ValueCount1) == 0); | ||
| 667 | assertOrPanic(@sizeOf(ValueCount2) == 1); | ||
| 668 | assertOrPanic(@sizeOf(ValueCount256) == 1); | ||
| 669 | assertOrPanic(@sizeOf(ValueCount257) == 2); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | const Small2 = enum(u2) { | ||
| 674 | One, | ||
| 675 | Two, | ||
| 676 | }; | ||
| 677 | const Small = enum(u2) { | ||
| 678 | One, | ||
| 679 | Two, | ||
| 680 | Three, | ||
| 681 | Four, | ||
| 682 | }; | ||
| 683 | |||
| 684 | test "set enum tag type" { | ||
| 685 | { | ||
| 686 | var x = Small.One; | ||
| 687 | x = Small.Two; | ||
| 688 | comptime assertOrPanic(@TagType(Small) == u2); | ||
| 689 | } | ||
| 690 | { | ||
| 691 | var x = Small2.One; | ||
| 692 | x = Small2.Two; | ||
| 693 | comptime assertOrPanic(@TagType(Small2) == u2); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | const A = enum(u3) { | ||
| 698 | One, | ||
| 699 | Two, | ||
| 700 | Three, | ||
| 701 | Four, | ||
| 702 | One2, | ||
| 703 | Two2, | ||
| 704 | Three2, | ||
| 705 | Four2, | ||
| 706 | }; | ||
| 707 | |||
| 708 | const B = enum(u3) { | ||
| 709 | One3, | ||
| 710 | Two3, | ||
| 711 | Three3, | ||
| 712 | Four3, | ||
| 713 | One23, | ||
| 714 | Two23, | ||
| 715 | Three23, | ||
| 716 | Four23, | ||
| 717 | }; | ||
| 718 | |||
| 719 | const C = enum(u2) { | ||
| 720 | One4, | ||
| 721 | Two4, | ||
| 722 | Three4, | ||
| 723 | Four4, | ||
| 724 | }; | ||
| 725 | |||
| 726 | const BitFieldOfEnums = packed struct { | ||
| 727 | a: A, | ||
| 728 | b: B, | ||
| 729 | c: C, | ||
| 730 | }; | ||
| 731 | |||
| 732 | const bit_field_1 = BitFieldOfEnums{ | ||
| 733 | .a = A.Two, | ||
| 734 | .b = B.Three3, | ||
| 735 | .c = C.Four4, | ||
| 736 | }; | ||
| 737 | |||
| 738 | test "bit field access with enum fields" { | ||
| 739 | var data = bit_field_1; | ||
| 740 | assertOrPanic(getA(&data) == A.Two); | ||
| 741 | assertOrPanic(getB(&data) == B.Three3); | ||
| 742 | assertOrPanic(getC(&data) == C.Four4); | ||
| 743 | comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1); | ||
| 744 | |||
| 745 | data.b = B.Four3; | ||
| 746 | assertOrPanic(data.b == B.Four3); | ||
| 747 | |||
| 748 | data.a = A.Three; | ||
| 749 | assertOrPanic(data.a == A.Three); | ||
| 750 | assertOrPanic(data.b == B.Four3); | ||
| 751 | } | ||
| 752 | |||
| 753 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 754 | return data.a; | ||
| 755 | } | ||
| 756 | |||
| 757 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 758 | return data.b; | ||
| 759 | } | ||
| 760 | |||
| 761 | fn getC(data: *const BitFieldOfEnums) C { | ||
| 762 | return data.c; | ||
| 763 | } | ||
| 764 | |||
| 765 | test "casting enum to its tag type" { | ||
| 766 | testCastEnumToTagType(Small2.Two); | ||
| 767 | comptime testCastEnumToTagType(Small2.Two); | ||
| 768 | } | ||
| 769 | |||
| 770 | fn testCastEnumToTagType(value: Small2) void { | ||
| 771 | assertOrPanic(@enumToInt(value) == 1); | ||
| 772 | } | ||
| 773 | |||
| 774 | const MultipleChoice = enum(u32) { | ||
| 775 | A = 20, | ||
| 776 | B = 40, | ||
| 777 | C = 60, | ||
| 778 | D = 1000, | ||
| 779 | }; | ||
| 780 | |||
| 781 | test "enum with specified tag values" { | ||
| 782 | testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 783 | comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 784 | } | ||
| 785 | |||
| 786 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { | ||
| 787 | assertOrPanic(@enumToInt(x) == 60); | ||
| 788 | assertOrPanic(1234 == switch (x) { | ||
| 789 | MultipleChoice.A => 1, | ||
| 790 | MultipleChoice.B => 2, | ||
| 791 | MultipleChoice.C => u32(1234), | ||
| 792 | MultipleChoice.D => 4, | ||
| 793 | }); | ||
| 794 | } | ||
| 795 | |||
| 796 | const MultipleChoice2 = enum(u32) { | ||
| 797 | Unspecified1, | ||
| 798 | A = 20, | ||
| 799 | Unspecified2, | ||
| 800 | B = 40, | ||
| 801 | Unspecified3, | ||
| 802 | C = 60, | ||
| 803 | Unspecified4, | ||
| 804 | D = 1000, | ||
| 805 | Unspecified5, | ||
| 806 | }; | ||
| 807 | |||
| 808 | test "enum with specified and unspecified tag values" { | ||
| 809 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 810 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 811 | } | ||
| 812 | |||
| 813 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | ||
| 814 | assertOrPanic(@enumToInt(x) == 1000); | ||
| 815 | assertOrPanic(1234 == switch (x) { | ||
| 816 | MultipleChoice2.A => 1, | ||
| 817 | MultipleChoice2.B => 2, | ||
| 818 | MultipleChoice2.C => 3, | ||
| 819 | MultipleChoice2.D => u32(1234), | ||
| 820 | MultipleChoice2.Unspecified1 => 5, | ||
| 821 | MultipleChoice2.Unspecified2 => 6, | ||
| 822 | MultipleChoice2.Unspecified3 => 7, | ||
| 823 | MultipleChoice2.Unspecified4 => 8, | ||
| 824 | MultipleChoice2.Unspecified5 => 9, | ||
| 825 | }); | ||
| 826 | } | ||
| 827 | |||
| 828 | test "cast integer literal to enum" { | ||
| 829 | assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | ||
| 830 | assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | ||
| 831 | } | ||
| 832 | |||
| 833 | const EnumWithOneMember = enum { | ||
| 834 | Eof, | ||
| 835 | }; | ||
| 836 | |||
| 837 | fn doALoopThing(id: EnumWithOneMember) void { | ||
| 838 | while (true) { | ||
| 839 | if (id == EnumWithOneMember.Eof) { | ||
| 840 | break; | ||
| 841 | } | ||
| 842 | @compileError("above if condition should be comptime"); | ||
| 843 | } | ||
| 844 | } | ||
| 845 | |||
| 846 | test "comparison operator on enum with one member is comptime known" { | ||
| 847 | doALoopThing(EnumWithOneMember.Eof); | ||
| 848 | } | ||
| 849 | |||
| 850 | const State = enum { | ||
| 851 | Start, | ||
| 852 | }; | ||
| 853 | test "switch on enum with one member is comptime known" { | ||
| 854 | var state = State.Start; | ||
| 855 | switch (state) { | ||
| 856 | State.Start => return, | ||
| 857 | } | ||
| 858 | @compileError("analysis should not reach here"); | ||
| 859 | } | ||
| 860 | |||
| 861 | const EnumWithTagValues = enum(u4) { | ||
| 862 | A = 1 << 0, | ||
| 863 | B = 1 << 1, | ||
| 864 | C = 1 << 2, | ||
| 865 | D = 1 << 3, | ||
| 866 | }; | ||
| 867 | test "enum with tag values don't require parens" { | ||
| 868 | assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100); | ||
| 869 | } | ||
| 870 | |||
| 871 | test "enum with 1 field but explicit tag type should still have the tag type" { | ||
| 872 | const Enum = enum(u8) { | ||
| 873 | B = 2, | ||
| 874 | }; | ||
| 875 | comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8)); | ||
| 876 | } | ||
| 877 | |||
| 878 | test "empty extern enum with members" { | ||
| 879 | const E = extern enum { | ||
| 880 | A, | ||
| 881 | B, | ||
| 882 | C, | ||
| 883 | }; | ||
| 884 | assertOrPanic(@sizeOf(E) == @sizeOf(c_int)); | ||
| 885 | } | ||
| 886 | |||
| 887 | test "tag name with assigned enum values" { | ||
| 888 | const LocalFoo = enum { | ||
| 889 | A = 1, | ||
| 890 | B = 0, | ||
| 891 | }; | ||
| 892 | var b = LocalFoo.B; | ||
| 893 | assertOrPanic(mem.eql(u8, @tagName(b), "B")); | ||
| 894 | } | ||
test/stage1/behavior/enum_with_members.zig created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const fmt = @import("std").fmt; | ||
| 4 | |||
| 5 | const ET = union(enum) { | ||
| 6 | SINT: i32, | ||
| 7 | UINT: u32, | ||
| 8 | |||
| 9 | pub fn print(a: *const ET, buf: []u8) anyerror!usize { | ||
| 10 | return switch (a.*) { | ||
| 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | ||
| 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | |||
| 17 | test "enum with members" { | ||
| 18 | const a = ET{ .SINT = -42 }; | ||
| 19 | const b = ET{ .UINT = 42 }; | ||
| 20 | var buf: [20]u8 = undefined; | ||
| 21 | |||
| 22 | assertOrPanic((a.print(buf[0..]) catch unreachable) == 3); | ||
| 23 | assertOrPanic(mem.eql(u8, buf[0..3], "-42")); | ||
| 24 | |||
| 25 | assertOrPanic((b.print(buf[0..]) catch unreachable) == 2); | ||
| 26 | assertOrPanic(mem.eql(u8, buf[0..2], "42")); | ||
| 27 | } | ||
test/stage1/behavior/error.zig created+332| ... | @@ -0,0 +1,332 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const assertError = std.debug.assertError; | ||
| 4 | const mem = std.mem; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | |||
| 7 | pub fn foo() anyerror!i32 { | ||
| 8 | const x = try bar(); | ||
| 9 | return x + 1; | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn bar() anyerror!i32 { | ||
| 13 | return 13; | ||
| 14 | } | ||
| 15 | |||
| 16 | pub fn baz() anyerror!i32 { | ||
| 17 | const y = foo() catch 1234; | ||
| 18 | return y + 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "error wrapping" { | ||
| 22 | assertOrPanic((baz() catch unreachable) == 15); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn gimmeItBroke() []const u8 { | ||
| 26 | return @errorName(error.ItBroke); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "@errorName" { | ||
| 30 | assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError")); | ||
| 31 | assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "error values" { | ||
| 35 | const a = @errorToInt(error.err1); | ||
| 36 | const b = @errorToInt(error.err2); | ||
| 37 | assertOrPanic(a != b); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "redefinition of error values allowed" { | ||
| 41 | shouldBeNotEqual(error.AnError, error.SecondError); | ||
| 42 | } | ||
| 43 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { | ||
| 44 | if (a == b) unreachable; | ||
| 45 | } | ||
| 46 | |||
| 47 | test "error binary operator" { | ||
| 48 | const a = errBinaryOperatorG(true) catch 3; | ||
| 49 | const b = errBinaryOperatorG(false) catch 3; | ||
| 50 | assertOrPanic(a == 3); | ||
| 51 | assertOrPanic(b == 10); | ||
| 52 | } | ||
| 53 | fn errBinaryOperatorG(x: bool) anyerror!isize { | ||
| 54 | return if (x) error.ItBroke else isize(10); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "unwrap simple value from error" { | ||
| 58 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; | ||
| 59 | assertOrPanic(i == 13); | ||
| 60 | } | ||
| 61 | fn unwrapSimpleValueFromErrorDo() anyerror!isize { | ||
| 62 | return 13; | ||
| 63 | } | ||
| 64 | |||
| 65 | test "error return in assignment" { | ||
| 66 | doErrReturnInAssignment() catch unreachable; | ||
| 67 | } | ||
| 68 | |||
| 69 | fn doErrReturnInAssignment() anyerror!void { | ||
| 70 | var x: i32 = undefined; | ||
| 71 | x = try makeANonErr(); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn makeANonErr() anyerror!i32 { | ||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | test "error union type " { | ||
| 79 | testErrorUnionType(); | ||
| 80 | comptime testErrorUnionType(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn testErrorUnionType() void { | ||
| 84 | const x: anyerror!i32 = 1234; | ||
| 85 | if (x) |value| assertOrPanic(value == 1234) else |_| unreachable; | ||
| 86 | assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); | ||
| 87 | assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); | ||
| 88 | assertOrPanic(@typeOf(x).ErrorSet == anyerror); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "error set type" { | ||
| 92 | testErrorSetType(); | ||
| 93 | comptime testErrorSetType(); | ||
| 94 | } | ||
| 95 | |||
| 96 | const MyErrSet = error{ | ||
| 97 | OutOfMemory, | ||
| 98 | FileNotFound, | ||
| 99 | }; | ||
| 100 | |||
| 101 | fn testErrorSetType() void { | ||
| 102 | assertOrPanic(@memberCount(MyErrSet) == 2); | ||
| 103 | |||
| 104 | const a: MyErrSet!i32 = 5678; | ||
| 105 | const b: MyErrSet!i32 = MyErrSet.OutOfMemory; | ||
| 106 | |||
| 107 | if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) { | ||
| 108 | error.OutOfMemory => unreachable, | ||
| 109 | error.FileNotFound => unreachable, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | test "explicit error set cast" { | ||
| 114 | testExplicitErrorSetCast(Set1.A); | ||
| 115 | comptime testExplicitErrorSetCast(Set1.A); | ||
| 116 | } | ||
| 117 | |||
| 118 | const Set1 = error{ | ||
| 119 | A, | ||
| 120 | B, | ||
| 121 | }; | ||
| 122 | const Set2 = error{ | ||
| 123 | A, | ||
| 124 | C, | ||
| 125 | }; | ||
| 126 | |||
| 127 | fn testExplicitErrorSetCast(set1: Set1) void { | ||
| 128 | var x = @errSetCast(Set2, set1); | ||
| 129 | var y = @errSetCast(Set1, x); | ||
| 130 | assertOrPanic(y == error.A); | ||
| 131 | } | ||
| 132 | |||
| 133 | test "comptime test error for empty error set" { | ||
| 134 | testComptimeTestErrorEmptySet(1234); | ||
| 135 | comptime testComptimeTestErrorEmptySet(1234); | ||
| 136 | } | ||
| 137 | |||
| 138 | const EmptyErrorSet = error{}; | ||
| 139 | |||
| 140 | fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { | ||
| 141 | if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad"); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "syntax: optional operator in front of error union operator" { | ||
| 145 | comptime { | ||
| 146 | assertOrPanic(?(anyerror!i32) == ?(anyerror!i32)); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | test "comptime err to int of error set with only 1 possible value" { | ||
| 151 | testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 152 | comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 153 | } | ||
| 154 | fn testErrToIntWithOnePossibleValue( | ||
| 155 | x: error{A}, | ||
| 156 | comptime value: u32, | ||
| 157 | ) void { | ||
| 158 | if (@errorToInt(x) != value) { | ||
| 159 | @compileError("bad"); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | test "error union peer type resolution" { | ||
| 164 | testErrorUnionPeerTypeResolution(1); | ||
| 165 | } | ||
| 166 | |||
| 167 | fn testErrorUnionPeerTypeResolution(x: i32) void { | ||
| 168 | const y = switch (x) { | ||
| 169 | 1 => bar_1(), | ||
| 170 | 2 => baz_1(), | ||
| 171 | else => quux_1(), | ||
| 172 | }; | ||
| 173 | if (y) |_| { | ||
| 174 | @panic("expected error"); | ||
| 175 | } else |e| { | ||
| 176 | assertOrPanic(e == error.A); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | fn bar_1() anyerror { | ||
| 181 | return error.A; | ||
| 182 | } | ||
| 183 | |||
| 184 | fn baz_1() !i32 { | ||
| 185 | return error.B; | ||
| 186 | } | ||
| 187 | |||
| 188 | fn quux_1() !i32 { | ||
| 189 | return error.C; | ||
| 190 | } | ||
| 191 | |||
| 192 | test "error: fn returning empty error set can be passed as fn returning any error" { | ||
| 193 | entry(); | ||
| 194 | comptime entry(); | ||
| 195 | } | ||
| 196 | |||
| 197 | fn entry() void { | ||
| 198 | foo2(bar2); | ||
| 199 | } | ||
| 200 | |||
| 201 | fn foo2(f: fn () anyerror!void) void { | ||
| 202 | const x = f(); | ||
| 203 | } | ||
| 204 | |||
| 205 | fn bar2() (error{}!void) {} | ||
| 206 | |||
| 207 | test "error: Zero sized error set returned with value payload crash" { | ||
| 208 | _ = foo3(0); | ||
| 209 | _ = comptime foo3(0); | ||
| 210 | } | ||
| 211 | |||
| 212 | const Error = error{}; | ||
| 213 | fn foo3(b: usize) Error!usize { | ||
| 214 | return b; | ||
| 215 | } | ||
| 216 | |||
| 217 | test "error: Infer error set from literals" { | ||
| 218 | _ = nullLiteral("n") catch |err| handleErrors(err); | ||
| 219 | _ = floatLiteral("n") catch |err| handleErrors(err); | ||
| 220 | _ = intLiteral("n") catch |err| handleErrors(err); | ||
| 221 | _ = comptime nullLiteral("n") catch |err| handleErrors(err); | ||
| 222 | _ = comptime floatLiteral("n") catch |err| handleErrors(err); | ||
| 223 | _ = comptime intLiteral("n") catch |err| handleErrors(err); | ||
| 224 | } | ||
| 225 | |||
| 226 | fn handleErrors(err: var) noreturn { | ||
| 227 | switch (err) { | ||
| 228 | error.T => {}, | ||
| 229 | } | ||
| 230 | |||
| 231 | unreachable; | ||
| 232 | } | ||
| 233 | |||
| 234 | fn nullLiteral(str: []const u8) !?i64 { | ||
| 235 | if (str[0] == 'n') return null; | ||
| 236 | |||
| 237 | return error.T; | ||
| 238 | } | ||
| 239 | |||
| 240 | fn floatLiteral(str: []const u8) !?f64 { | ||
| 241 | if (str[0] == 'n') return 1.0; | ||
| 242 | |||
| 243 | return error.T; | ||
| 244 | } | ||
| 245 | |||
| 246 | fn intLiteral(str: []const u8) !?i64 { | ||
| 247 | if (str[0] == 'n') return 1; | ||
| 248 | |||
| 249 | return error.T; | ||
| 250 | } | ||
| 251 | |||
| 252 | test "nested error union function call in optional unwrap" { | ||
| 253 | const S = struct { | ||
| 254 | const Foo = struct { | ||
| 255 | a: i32, | ||
| 256 | }; | ||
| 257 | |||
| 258 | fn errorable() !i32 { | ||
| 259 | var x: Foo = (try getFoo()) orelse return error.Other; | ||
| 260 | return x.a; | ||
| 261 | } | ||
| 262 | |||
| 263 | fn errorable2() !i32 { | ||
| 264 | var x: Foo = (try getFoo2()) orelse return error.Other; | ||
| 265 | return x.a; | ||
| 266 | } | ||
| 267 | |||
| 268 | fn errorable3() !i32 { | ||
| 269 | var x: Foo = (try getFoo3()) orelse return error.Other; | ||
| 270 | return x.a; | ||
| 271 | } | ||
| 272 | |||
| 273 | fn getFoo() anyerror!?Foo { | ||
| 274 | return Foo{ .a = 1234 }; | ||
| 275 | } | ||
| 276 | |||
| 277 | fn getFoo2() anyerror!?Foo { | ||
| 278 | return error.Failure; | ||
| 279 | } | ||
| 280 | |||
| 281 | fn getFoo3() anyerror!?Foo { | ||
| 282 | return null; | ||
| 283 | } | ||
| 284 | }; | ||
| 285 | assertOrPanic((try S.errorable()) == 1234); | ||
| 286 | assertError(S.errorable2(), error.Failure); | ||
| 287 | assertError(S.errorable3(), error.Other); | ||
| 288 | comptime { | ||
| 289 | assertOrPanic((try S.errorable()) == 1234); | ||
| 290 | assertError(S.errorable2(), error.Failure); | ||
| 291 | assertError(S.errorable3(), error.Other); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | test "widen cast integer payload of error union function call" { | ||
| 296 | const S = struct { | ||
| 297 | fn errorable() !u64 { | ||
| 298 | var x = u64(try number()); | ||
| 299 | return x; | ||
| 300 | } | ||
| 301 | |||
| 302 | fn number() anyerror!u32 { | ||
| 303 | return 1234; | ||
| 304 | } | ||
| 305 | }; | ||
| 306 | assertOrPanic((try S.errorable()) == 1234); | ||
| 307 | } | ||
| 308 | |||
| 309 | test "return function call to error set from error union function" { | ||
| 310 | const S = struct { | ||
| 311 | fn errorable() anyerror!i32 { | ||
| 312 | return fail(); | ||
| 313 | } | ||
| 314 | |||
| 315 | fn fail() anyerror { | ||
| 316 | return error.Failure; | ||
| 317 | } | ||
| 318 | }; | ||
| 319 | assertError(S.errorable(), error.Failure); | ||
| 320 | comptime assertError(S.errorable(), error.Failure); | ||
| 321 | } | ||
| 322 | |||
| 323 | test "optional error set is the same size as error set" { | ||
| 324 | comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror)); | ||
| 325 | const S = struct { | ||
| 326 | fn returnsOptErrSet() ?anyerror { | ||
| 327 | return null; | ||
| 328 | } | ||
| 329 | }; | ||
| 330 | assertOrPanic(S.returnsOptErrSet() == null); | ||
| 331 | comptime assertOrPanic(S.returnsOptErrSet() == null); | ||
| 332 | } | ||
test/stage1/behavior/eval.zig created+784| ... | @@ -0,0 +1,784 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | |||
| 5 | test "compile time recursion" { | ||
| 6 | assertOrPanic(some_data.len == 21); | ||
| 7 | } | ||
| 8 | var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; | ||
| 9 | fn fibonacci(x: i32) i32 { | ||
| 10 | if (x <= 1) return 1; | ||
| 11 | return fibonacci(x - 1) + fibonacci(x - 2); | ||
| 12 | } | ||
| 13 | |||
| 14 | fn unwrapAndAddOne(blah: ?i32) i32 { | ||
| 15 | return blah.? + 1; | ||
| 16 | } | ||
| 17 | const should_be_1235 = unwrapAndAddOne(1234); | ||
| 18 | test "static add one" { | ||
| 19 | assertOrPanic(should_be_1235 == 1235); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "inlined loop" { | ||
| 23 | comptime var i = 0; | ||
| 24 | comptime var sum = 0; | ||
| 25 | inline while (i <= 5) : (i += 1) | ||
| 26 | sum += i; | ||
| 27 | assertOrPanic(sum == 15); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn gimme1or2(comptime a: bool) i32 { | ||
| 31 | const x: i32 = 1; | ||
| 32 | const y: i32 = 2; | ||
| 33 | comptime var z: i32 = if (a) x else y; | ||
| 34 | return z; | ||
| 35 | } | ||
| 36 | test "inline variable gets result of const if" { | ||
| 37 | assertOrPanic(gimme1or2(true) == 1); | ||
| 38 | assertOrPanic(gimme1or2(false) == 2); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "static function evaluation" { | ||
| 42 | assertOrPanic(statically_added_number == 3); | ||
| 43 | } | ||
| 44 | const statically_added_number = staticAdd(1, 2); | ||
| 45 | fn staticAdd(a: i32, b: i32) i32 { | ||
| 46 | return a + b; | ||
| 47 | } | ||
| 48 | |||
| 49 | test "const expr eval on single expr blocks" { | ||
| 50 | assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 51 | comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 52 | } | ||
| 53 | |||
| 54 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { | ||
| 55 | const literal = 3; | ||
| 56 | |||
| 57 | const result = if (b) b: { | ||
| 58 | break :b literal; | ||
| 59 | } else b: { | ||
| 60 | break :b x; | ||
| 61 | }; | ||
| 62 | |||
| 63 | return result; | ||
| 64 | } | ||
| 65 | |||
| 66 | test "statically initialized list" { | ||
| 67 | assertOrPanic(static_point_list[0].x == 1); | ||
| 68 | assertOrPanic(static_point_list[0].y == 2); | ||
| 69 | assertOrPanic(static_point_list[1].x == 3); | ||
| 70 | assertOrPanic(static_point_list[1].y == 4); | ||
| 71 | } | ||
| 72 | const Point = struct { | ||
| 73 | x: i32, | ||
| 74 | y: i32, | ||
| 75 | }; | ||
| 76 | const static_point_list = []Point{ | ||
| 77 | makePoint(1, 2), | ||
| 78 | makePoint(3, 4), | ||
| 79 | }; | ||
| 80 | fn makePoint(x: i32, y: i32) Point { | ||
| 81 | return Point{ | ||
| 82 | .x = x, | ||
| 83 | .y = y, | ||
| 84 | }; | ||
| 85 | } | ||
| 86 | |||
| 87 | test "static eval list init" { | ||
| 88 | assertOrPanic(static_vec3.data[2] == 1.0); | ||
| 89 | assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | ||
| 90 | } | ||
| 91 | const static_vec3 = vec3(0.0, 0.0, 1.0); | ||
| 92 | pub const Vec3 = struct { | ||
| 93 | data: [3]f32, | ||
| 94 | }; | ||
| 95 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | ||
| 96 | return Vec3{ .data = []f32{ | ||
| 97 | x, | ||
| 98 | y, | ||
| 99 | z, | ||
| 100 | } }; | ||
| 101 | } | ||
| 102 | |||
| 103 | test "constant expressions" { | ||
| 104 | var array: [array_size]u8 = undefined; | ||
| 105 | assertOrPanic(@sizeOf(@typeOf(array)) == 20); | ||
| 106 | } | ||
| 107 | const array_size: u8 = 20; | ||
| 108 | |||
| 109 | test "constant struct with negation" { | ||
| 110 | assertOrPanic(vertices[0].x == -0.6); | ||
| 111 | } | ||
| 112 | const Vertex = struct { | ||
| 113 | x: f32, | ||
| 114 | y: f32, | ||
| 115 | r: f32, | ||
| 116 | g: f32, | ||
| 117 | b: f32, | ||
| 118 | }; | ||
| 119 | const vertices = []Vertex{ | ||
| 120 | Vertex{ | ||
| 121 | .x = -0.6, | ||
| 122 | .y = -0.4, | ||
| 123 | .r = 1.0, | ||
| 124 | .g = 0.0, | ||
| 125 | .b = 0.0, | ||
| 126 | }, | ||
| 127 | Vertex{ | ||
| 128 | .x = 0.6, | ||
| 129 | .y = -0.4, | ||
| 130 | .r = 0.0, | ||
| 131 | .g = 1.0, | ||
| 132 | .b = 0.0, | ||
| 133 | }, | ||
| 134 | Vertex{ | ||
| 135 | .x = 0.0, | ||
| 136 | .y = 0.6, | ||
| 137 | .r = 0.0, | ||
| 138 | .g = 0.0, | ||
| 139 | .b = 1.0, | ||
| 140 | }, | ||
| 141 | }; | ||
| 142 | |||
| 143 | test "statically initialized struct" { | ||
| 144 | st_init_str_foo.x += 1; | ||
| 145 | assertOrPanic(st_init_str_foo.x == 14); | ||
| 146 | } | ||
| 147 | const StInitStrFoo = struct { | ||
| 148 | x: i32, | ||
| 149 | y: bool, | ||
| 150 | }; | ||
| 151 | var st_init_str_foo = StInitStrFoo{ | ||
| 152 | .x = 13, | ||
| 153 | .y = true, | ||
| 154 | }; | ||
| 155 | |||
| 156 | test "statically initalized array literal" { | ||
| 157 | const y: [4]u8 = st_init_arr_lit_x; | ||
| 158 | assertOrPanic(y[3] == 4); | ||
| 159 | } | ||
| 160 | const st_init_arr_lit_x = []u8{ | ||
| 161 | 1, | ||
| 162 | 2, | ||
| 163 | 3, | ||
| 164 | 4, | ||
| 165 | }; | ||
| 166 | |||
| 167 | test "const slice" { | ||
| 168 | comptime { | ||
| 169 | const a = "1234567890"; | ||
| 170 | assertOrPanic(a.len == 10); | ||
| 171 | const b = a[1..2]; | ||
| 172 | assertOrPanic(b.len == 1); | ||
| 173 | assertOrPanic(b[0] == '2'); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | test "try to trick eval with runtime if" { | ||
| 178 | assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10); | ||
| 179 | } | ||
| 180 | |||
| 181 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | ||
| 182 | comptime var i: usize = 0; | ||
| 183 | inline while (i < 10) : (i += 1) { | ||
| 184 | const result = if (b) false else true; | ||
| 185 | } | ||
| 186 | comptime { | ||
| 187 | return i; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | fn max(comptime T: type, a: T, b: T) T { | ||
| 192 | if (T == bool) { | ||
| 193 | return a or b; | ||
| 194 | } else if (a > b) { | ||
| 195 | return a; | ||
| 196 | } else { | ||
| 197 | return b; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | fn letsTryToCompareBools(a: bool, b: bool) bool { | ||
| 201 | return max(bool, a, b); | ||
| 202 | } | ||
| 203 | test "inlined block and runtime block phi" { | ||
| 204 | assertOrPanic(letsTryToCompareBools(true, true)); | ||
| 205 | assertOrPanic(letsTryToCompareBools(true, false)); | ||
| 206 | assertOrPanic(letsTryToCompareBools(false, true)); | ||
| 207 | assertOrPanic(!letsTryToCompareBools(false, false)); | ||
| 208 | |||
| 209 | comptime { | ||
| 210 | assertOrPanic(letsTryToCompareBools(true, true)); | ||
| 211 | assertOrPanic(letsTryToCompareBools(true, false)); | ||
| 212 | assertOrPanic(letsTryToCompareBools(false, true)); | ||
| 213 | assertOrPanic(!letsTryToCompareBools(false, false)); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | const CmdFn = struct { | ||
| 218 | name: []const u8, | ||
| 219 | func: fn (i32) i32, | ||
| 220 | }; | ||
| 221 | |||
| 222 | const cmd_fns = []CmdFn{ | ||
| 223 | CmdFn{ | ||
| 224 | .name = "one", | ||
| 225 | .func = one, | ||
| 226 | }, | ||
| 227 | CmdFn{ | ||
| 228 | .name = "two", | ||
| 229 | .func = two, | ||
| 230 | }, | ||
| 231 | CmdFn{ | ||
| 232 | .name = "three", | ||
| 233 | .func = three, | ||
| 234 | }, | ||
| 235 | }; | ||
| 236 | fn one(value: i32) i32 { | ||
| 237 | return value + 1; | ||
| 238 | } | ||
| 239 | fn two(value: i32) i32 { | ||
| 240 | return value + 2; | ||
| 241 | } | ||
| 242 | fn three(value: i32) i32 { | ||
| 243 | return value + 3; | ||
| 244 | } | ||
| 245 | |||
| 246 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | ||
| 247 | var result: i32 = start_value; | ||
| 248 | comptime var i = 0; | ||
| 249 | inline while (i < cmd_fns.len) : (i += 1) { | ||
| 250 | if (cmd_fns[i].name[0] == prefix_char) { | ||
| 251 | result = cmd_fns[i].func(result); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | return result; | ||
| 255 | } | ||
| 256 | |||
| 257 | test "comptime iterate over fn ptr list" { | ||
| 258 | assertOrPanic(performFn('t', 1) == 6); | ||
| 259 | assertOrPanic(performFn('o', 0) == 1); | ||
| 260 | assertOrPanic(performFn('w', 99) == 99); | ||
| 261 | } | ||
| 262 | |||
| 263 | test "eval @setRuntimeSafety at compile-time" { | ||
| 264 | const result = comptime fnWithSetRuntimeSafety(); | ||
| 265 | assertOrPanic(result == 1234); | ||
| 266 | } | ||
| 267 | |||
| 268 | fn fnWithSetRuntimeSafety() i32 { | ||
| 269 | @setRuntimeSafety(true); | ||
| 270 | return 1234; | ||
| 271 | } | ||
| 272 | |||
| 273 | test "eval @setFloatMode at compile-time" { | ||
| 274 | const result = comptime fnWithFloatMode(); | ||
| 275 | assertOrPanic(result == 1234.0); | ||
| 276 | } | ||
| 277 | |||
| 278 | fn fnWithFloatMode() f32 { | ||
| 279 | @setFloatMode(builtin.FloatMode.Strict); | ||
| 280 | return 1234.0; | ||
| 281 | } | ||
| 282 | |||
| 283 | const SimpleStruct = struct { | ||
| 284 | field: i32, | ||
| 285 | |||
| 286 | fn method(self: *const SimpleStruct) i32 { | ||
| 287 | return self.field + 3; | ||
| 288 | } | ||
| 289 | }; | ||
| 290 | |||
| 291 | var simple_struct = SimpleStruct{ .field = 1234 }; | ||
| 292 | |||
| 293 | const bound_fn = simple_struct.method; | ||
| 294 | |||
| 295 | test "call method on bound fn referring to var instance" { | ||
| 296 | assertOrPanic(bound_fn() == 1237); | ||
| 297 | } | ||
| 298 | |||
| 299 | test "ptr to local array argument at comptime" { | ||
| 300 | comptime { | ||
| 301 | var bytes: [10]u8 = undefined; | ||
| 302 | modifySomeBytes(bytes[0..]); | ||
| 303 | assertOrPanic(bytes[0] == 'a'); | ||
| 304 | assertOrPanic(bytes[9] == 'b'); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | fn modifySomeBytes(bytes: []u8) void { | ||
| 309 | bytes[0] = 'a'; | ||
| 310 | bytes[9] = 'b'; | ||
| 311 | } | ||
| 312 | |||
| 313 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | ||
| 314 | testCompTimeUIntComparisons(1234); | ||
| 315 | } | ||
| 316 | fn testCompTimeUIntComparisons(x: u32) void { | ||
| 317 | if (!(0 <= x)) { | ||
| 318 | @compileError("this condition should be comptime known"); | ||
| 319 | } | ||
| 320 | if (0 > x) { | ||
| 321 | @compileError("this condition should be comptime known"); | ||
| 322 | } | ||
| 323 | if (!(x >= 0)) { | ||
| 324 | @compileError("this condition should be comptime known"); | ||
| 325 | } | ||
| 326 | if (x < 0) { | ||
| 327 | @compileError("this condition should be comptime known"); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | test "const ptr to variable data changes at runtime" { | ||
| 332 | assertOrPanic(foo_ref.name[0] == 'a'); | ||
| 333 | foo_ref.name = "b"; | ||
| 334 | assertOrPanic(foo_ref.name[0] == 'b'); | ||
| 335 | } | ||
| 336 | |||
| 337 | const Foo = struct { | ||
| 338 | name: []const u8, | ||
| 339 | }; | ||
| 340 | |||
| 341 | var foo_contents = Foo{ .name = "a" }; | ||
| 342 | const foo_ref = &foo_contents; | ||
| 343 | |||
| 344 | test "create global array with for loop" { | ||
| 345 | assertOrPanic(global_array[5] == 5 * 5); | ||
| 346 | assertOrPanic(global_array[9] == 9 * 9); | ||
| 347 | } | ||
| 348 | |||
| 349 | const global_array = x: { | ||
| 350 | var result: [10]usize = undefined; | ||
| 351 | for (result) |*item, index| { | ||
| 352 | item.* = index * index; | ||
| 353 | } | ||
| 354 | break :x result; | ||
| 355 | }; | ||
| 356 | |||
| 357 | test "compile-time downcast when the bits fit" { | ||
| 358 | comptime { | ||
| 359 | const spartan_count: u16 = 255; | ||
| 360 | const byte = @intCast(u8, spartan_count); | ||
| 361 | assertOrPanic(byte == 255); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | const hi1 = "hi"; | ||
| 366 | const hi2 = hi1; | ||
| 367 | test "const global shares pointer with other same one" { | ||
| 368 | assertEqualPtrs(&hi1[0], &hi2[0]); | ||
| 369 | comptime assertOrPanic(&hi1[0] == &hi2[0]); | ||
| 370 | } | ||
| 371 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { | ||
| 372 | assertOrPanic(ptr1 == ptr2); | ||
| 373 | } | ||
| 374 | |||
| 375 | test "@setEvalBranchQuota" { | ||
| 376 | comptime { | ||
| 377 | // 1001 for the loop and then 1 more for the assertOrPanic fn call | ||
| 378 | @setEvalBranchQuota(1002); | ||
| 379 | var i = 0; | ||
| 380 | var sum = 0; | ||
| 381 | while (i < 1001) : (i += 1) { | ||
| 382 | sum += i; | ||
| 383 | } | ||
| 384 | assertOrPanic(sum == 500500); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | // TODO test "float literal at compile time not lossy" { | ||
| 389 | // TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0); | ||
| 390 | // TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0); | ||
| 391 | // TODO } | ||
| 392 | |||
| 393 | test "f32 at compile time is lossy" { | ||
| 394 | assertOrPanic(f32(1 << 24) + 1 == 1 << 24); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "f64 at compile time is lossy" { | ||
| 398 | assertOrPanic(f64(1 << 53) + 1 == 1 << 53); | ||
| 399 | } | ||
| 400 | |||
| 401 | test "f128 at compile time is lossy" { | ||
| 402 | assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | ||
| 403 | } | ||
| 404 | |||
| 405 | comptime { | ||
| 406 | assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192); | ||
| 407 | } | ||
| 408 | |||
| 409 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | ||
| 410 | return struct { | ||
| 411 | pub const Node = struct {}; | ||
| 412 | }; | ||
| 413 | } | ||
| 414 | |||
| 415 | test "string literal used as comptime slice is memoized" { | ||
| 416 | const a = "link"; | ||
| 417 | const b = "link"; | ||
| 418 | comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | ||
| 419 | comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | ||
| 420 | } | ||
| 421 | |||
| 422 | test "comptime slice of undefined pointer of length 0" { | ||
| 423 | const slice1 = ([*]i32)(undefined)[0..0]; | ||
| 424 | assertOrPanic(slice1.len == 0); | ||
| 425 | const slice2 = ([*]i32)(undefined)[100..100]; | ||
| 426 | assertOrPanic(slice2.len == 0); | ||
| 427 | } | ||
| 428 | |||
| 429 | fn copyWithPartialInline(s: []u32, b: []u8) void { | ||
| 430 | comptime var i: usize = 0; | ||
| 431 | inline while (i < 4) : (i += 1) { | ||
| 432 | s[i] = 0; | ||
| 433 | s[i] |= u32(b[i * 4 + 0]) << 24; | ||
| 434 | s[i] |= u32(b[i * 4 + 1]) << 16; | ||
| 435 | s[i] |= u32(b[i * 4 + 2]) << 8; | ||
| 436 | s[i] |= u32(b[i * 4 + 3]) << 0; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | test "binary math operator in partially inlined function" { | ||
| 441 | var s: [4]u32 = undefined; | ||
| 442 | var b: [16]u8 = undefined; | ||
| 443 | |||
| 444 | for (b) |*r, i| | ||
| 445 | r.* = @intCast(u8, i + 1); | ||
| 446 | |||
| 447 | copyWithPartialInline(s[0..], b[0..]); | ||
| 448 | assertOrPanic(s[0] == 0x1020304); | ||
| 449 | assertOrPanic(s[1] == 0x5060708); | ||
| 450 | assertOrPanic(s[2] == 0x90a0b0c); | ||
| 451 | assertOrPanic(s[3] == 0xd0e0f10); | ||
| 452 | } | ||
| 453 | |||
| 454 | test "comptime function with the same args is memoized" { | ||
| 455 | comptime { | ||
| 456 | assertOrPanic(MakeType(i32) == MakeType(i32)); | ||
| 457 | assertOrPanic(MakeType(i32) != MakeType(f64)); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | fn MakeType(comptime T: type) type { | ||
| 462 | return struct { | ||
| 463 | field: T, | ||
| 464 | }; | ||
| 465 | } | ||
| 466 | |||
| 467 | test "comptime function with mutable pointer is not memoized" { | ||
| 468 | comptime { | ||
| 469 | var x: i32 = 1; | ||
| 470 | const ptr = &x; | ||
| 471 | increment(ptr); | ||
| 472 | increment(ptr); | ||
| 473 | assertOrPanic(x == 3); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | fn increment(value: *i32) void { | ||
| 478 | value.* += 1; | ||
| 479 | } | ||
| 480 | |||
| 481 | fn generateTable(comptime T: type) [1010]T { | ||
| 482 | var res: [1010]T = undefined; | ||
| 483 | var i: usize = 0; | ||
| 484 | while (i < 1010) : (i += 1) { | ||
| 485 | res[i] = @intCast(T, i); | ||
| 486 | } | ||
| 487 | return res; | ||
| 488 | } | ||
| 489 | |||
| 490 | fn doesAlotT(comptime T: type, value: usize) T { | ||
| 491 | @setEvalBranchQuota(5000); | ||
| 492 | const table = comptime blk: { | ||
| 493 | break :blk generateTable(T); | ||
| 494 | }; | ||
| 495 | return table[value]; | ||
| 496 | } | ||
| 497 | |||
| 498 | test "@setEvalBranchQuota at same scope as generic function call" { | ||
| 499 | assertOrPanic(doesAlotT(u32, 2) == 2); | ||
| 500 | } | ||
| 501 | |||
| 502 | test "comptime slice of slice preserves comptime var" { | ||
| 503 | comptime { | ||
| 504 | var buff: [10]u8 = undefined; | ||
| 505 | buff[0..][0..][0] = 1; | ||
| 506 | assertOrPanic(buff[0..][0..][0] == 1); | ||
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 510 | test "comptime slice of pointer preserves comptime var" { | ||
| 511 | comptime { | ||
| 512 | var buff: [10]u8 = undefined; | ||
| 513 | var a = buff[0..].ptr; | ||
| 514 | a[0..1][0] = 1; | ||
| 515 | assertOrPanic(buff[0..][0..][0] == 1); | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | const SingleFieldStruct = struct { | ||
| 520 | x: i32, | ||
| 521 | |||
| 522 | fn read_x(self: *const SingleFieldStruct) i32 { | ||
| 523 | return self.x; | ||
| 524 | } | ||
| 525 | }; | ||
| 526 | test "const ptr to comptime mutable data is not memoized" { | ||
| 527 | comptime { | ||
| 528 | var foo = SingleFieldStruct{ .x = 1 }; | ||
| 529 | assertOrPanic(foo.read_x() == 1); | ||
| 530 | foo.x = 2; | ||
| 531 | assertOrPanic(foo.read_x() == 2); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | test "array concat of slices gives slice" { | ||
| 536 | comptime { | ||
| 537 | var a: []const u8 = "aoeu"; | ||
| 538 | var b: []const u8 = "asdf"; | ||
| 539 | const c = a ++ b; | ||
| 540 | assertOrPanic(std.mem.eql(u8, c, "aoeuasdf")); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | test "comptime shlWithOverflow" { | ||
| 545 | const ct_shifted: u64 = comptime amt: { | ||
| 546 | var amt = u64(0); | ||
| 547 | _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); | ||
| 548 | break :amt amt; | ||
| 549 | }; | ||
| 550 | |||
| 551 | const rt_shifted: u64 = amt: { | ||
| 552 | var amt = u64(0); | ||
| 553 | _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); | ||
| 554 | break :amt amt; | ||
| 555 | }; | ||
| 556 | |||
| 557 | assertOrPanic(ct_shifted == rt_shifted); | ||
| 558 | } | ||
| 559 | |||
| 560 | test "runtime 128 bit integer division" { | ||
| 561 | var a: u128 = 152313999999999991610955792383; | ||
| 562 | var b: u128 = 10000000000000000000; | ||
| 563 | var c = a / b; | ||
| 564 | assertOrPanic(c == 15231399999); | ||
| 565 | } | ||
| 566 | |||
| 567 | pub const Info = struct { | ||
| 568 | version: u8, | ||
| 569 | }; | ||
| 570 | |||
| 571 | pub const diamond_info = Info{ .version = 0 }; | ||
| 572 | |||
| 573 | test "comptime modification of const struct field" { | ||
| 574 | comptime { | ||
| 575 | var res = diamond_info; | ||
| 576 | res.version = 1; | ||
| 577 | assertOrPanic(diamond_info.version == 0); | ||
| 578 | assertOrPanic(res.version == 1); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | test "pointer to type" { | ||
| 583 | comptime { | ||
| 584 | var T: type = i32; | ||
| 585 | assertOrPanic(T == i32); | ||
| 586 | var ptr = &T; | ||
| 587 | assertOrPanic(@typeOf(ptr) == *type); | ||
| 588 | ptr.* = f32; | ||
| 589 | assertOrPanic(T == f32); | ||
| 590 | assertOrPanic(*T == *f32); | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 594 | test "slice of type" { | ||
| 595 | comptime { | ||
| 596 | var types_array = []type{ i32, f64, type }; | ||
| 597 | for (types_array) |T, i| { | ||
| 598 | switch (i) { | ||
| 599 | 0 => assertOrPanic(T == i32), | ||
| 600 | 1 => assertOrPanic(T == f64), | ||
| 601 | 2 => assertOrPanic(T == type), | ||
| 602 | else => unreachable, | ||
| 603 | } | ||
| 604 | } | ||
| 605 | for (types_array[0..]) |T, i| { | ||
| 606 | switch (i) { | ||
| 607 | 0 => assertOrPanic(T == i32), | ||
| 608 | 1 => assertOrPanic(T == f64), | ||
| 609 | 2 => assertOrPanic(T == type), | ||
| 610 | else => unreachable, | ||
| 611 | } | ||
| 612 | } | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | const Wrapper = struct { | ||
| 617 | T: type, | ||
| 618 | }; | ||
| 619 | |||
| 620 | fn wrap(comptime T: type) Wrapper { | ||
| 621 | return Wrapper{ .T = T }; | ||
| 622 | } | ||
| 623 | |||
| 624 | test "function which returns struct with type field causes implicit comptime" { | ||
| 625 | const ty = wrap(i32).T; | ||
| 626 | assertOrPanic(ty == i32); | ||
| 627 | } | ||
| 628 | |||
| 629 | test "call method with comptime pass-by-non-copying-value self parameter" { | ||
| 630 | const S = struct { | ||
| 631 | a: u8, | ||
| 632 | |||
| 633 | fn b(comptime s: @This()) u8 { | ||
| 634 | return s.a; | ||
| 635 | } | ||
| 636 | }; | ||
| 637 | |||
| 638 | const s = S{ .a = 2 }; | ||
| 639 | var b = s.b(); | ||
| 640 | assertOrPanic(b == 2); | ||
| 641 | } | ||
| 642 | |||
| 643 | test "@tagName of @typeId" { | ||
| 644 | const str = @tagName(@typeId(u8)); | ||
| 645 | assertOrPanic(std.mem.eql(u8, str, "Int")); | ||
| 646 | } | ||
| 647 | |||
| 648 | test "setting backward branch quota just before a generic fn call" { | ||
| 649 | @setEvalBranchQuota(1001); | ||
| 650 | loopNTimes(1001); | ||
| 651 | } | ||
| 652 | |||
| 653 | fn loopNTimes(comptime n: usize) void { | ||
| 654 | comptime var i = 0; | ||
| 655 | inline while (i < n) : (i += 1) {} | ||
| 656 | } | ||
| 657 | |||
| 658 | test "variable inside inline loop that has different types on different iterations" { | ||
| 659 | testVarInsideInlineLoop(true, u32(42)); | ||
| 660 | } | ||
| 661 | |||
| 662 | fn testVarInsideInlineLoop(args: ...) void { | ||
| 663 | comptime var i = 0; | ||
| 664 | inline while (i < args.len) : (i += 1) { | ||
| 665 | const x = args[i]; | ||
| 666 | if (i == 0) assertOrPanic(x); | ||
| 667 | if (i == 1) assertOrPanic(x == 42); | ||
| 668 | } | ||
| 669 | } | ||
| 670 | |||
| 671 | test "inline for with same type but different values" { | ||
| 672 | var res: usize = 0; | ||
| 673 | inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| { | ||
| 674 | var a: T = undefined; | ||
| 675 | res += a.len; | ||
| 676 | } | ||
| 677 | assertOrPanic(res == 5); | ||
| 678 | } | ||
| 679 | |||
| 680 | test "refer to the type of a generic function" { | ||
| 681 | const Func = fn (type) void; | ||
| 682 | const f: Func = doNothingWithType; | ||
| 683 | f(i32); | ||
| 684 | } | ||
| 685 | |||
| 686 | fn doNothingWithType(comptime T: type) void {} | ||
| 687 | |||
| 688 | test "zero extend from u0 to u1" { | ||
| 689 | var zero_u0: u0 = 0; | ||
| 690 | var zero_u1: u1 = zero_u0; | ||
| 691 | assertOrPanic(zero_u1 == 0); | ||
| 692 | } | ||
| 693 | |||
| 694 | test "bit shift a u1" { | ||
| 695 | var x: u1 = 1; | ||
| 696 | var y = x << 0; | ||
| 697 | assertOrPanic(y == 1); | ||
| 698 | } | ||
| 699 | |||
| 700 | test "@intCast to a u0" { | ||
| 701 | var x: u8 = 0; | ||
| 702 | var y: u0 = @intCast(u0, x); | ||
| 703 | assertOrPanic(y == 0); | ||
| 704 | } | ||
| 705 | |||
| 706 | test "@bytesToslice on a packed struct" { | ||
| 707 | const F = packed struct { | ||
| 708 | a: u8, | ||
| 709 | }; | ||
| 710 | |||
| 711 | var b = [1]u8{9}; | ||
| 712 | var f = @bytesToSlice(F, b); | ||
| 713 | assertOrPanic(f[0].a == 9); | ||
| 714 | } | ||
| 715 | |||
| 716 | test "comptime pointer cast array and then slice" { | ||
| 717 | const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | ||
| 718 | |||
| 719 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | ||
| 720 | const sliceA: []const u8 = ptrA[0..2]; | ||
| 721 | |||
| 722 | const ptrB: [*]const u8 = &array; | ||
| 723 | const sliceB: []const u8 = ptrB[0..2]; | ||
| 724 | |||
| 725 | assertOrPanic(sliceA[1] == 2); | ||
| 726 | assertOrPanic(sliceB[1] == 2); | ||
| 727 | } | ||
| 728 | |||
| 729 | test "slice bounds in comptime concatenation" { | ||
| 730 | const bs = comptime blk: { | ||
| 731 | const b = c"........1........"; | ||
| 732 | break :blk b[8..9]; | ||
| 733 | }; | ||
| 734 | const str = "" ++ bs; | ||
| 735 | assertOrPanic(str.len == 1); | ||
| 736 | assertOrPanic(std.mem.eql(u8, str, "1")); | ||
| 737 | |||
| 738 | const str2 = bs ++ ""; | ||
| 739 | assertOrPanic(str2.len == 1); | ||
| 740 | assertOrPanic(std.mem.eql(u8, str2, "1")); | ||
| 741 | } | ||
| 742 | |||
| 743 | test "comptime bitwise operators" { | ||
| 744 | comptime { | ||
| 745 | assertOrPanic(3 & 1 == 1); | ||
| 746 | assertOrPanic(3 & -1 == 3); | ||
| 747 | assertOrPanic(-3 & -1 == -3); | ||
| 748 | assertOrPanic(3 | -1 == -1); | ||
| 749 | assertOrPanic(-3 | -1 == -1); | ||
| 750 | assertOrPanic(3 ^ -1 == -4); | ||
| 751 | assertOrPanic(-3 ^ -1 == 2); | ||
| 752 | assertOrPanic(~i8(-1) == 0); | ||
| 753 | assertOrPanic(~i128(-1) == 0); | ||
| 754 | assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | ||
| 755 | assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | ||
| 756 | assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff); | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 760 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | ||
| 761 | comptime { | ||
| 762 | assertOrPanic(*align(1:0:2) u16 == *align(1) u16); | ||
| 763 | // TODO add parsing support for this syntax | ||
| 764 | //assertOrPanic(*align(:0:2) u16 == *u16); | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | test "array concatenation forces comptime" { | ||
| 769 | var a = oneItem(3) ++ oneItem(4); | ||
| 770 | assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 })); | ||
| 771 | } | ||
| 772 | |||
| 773 | test "array multiplication forces comptime" { | ||
| 774 | var a = oneItem(3) ** scalar(2); | ||
| 775 | assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 })); | ||
| 776 | } | ||
| 777 | |||
| 778 | fn oneItem(x: i32) [1]i32 { | ||
| 779 | return []i32{x}; | ||
| 780 | } | ||
| 781 | |||
| 782 | fn scalar(x: u32) u32 { | ||
| 783 | return x; | ||
| 784 | } | ||
test/stage1/behavior/field_parent_ptr.zig created+41| ... | @@ -0,0 +1,41 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "@fieldParentPtr non-first field" { | ||
| 4 | testParentFieldPtr(&foo.c); | ||
| 5 | comptime testParentFieldPtr(&foo.c); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "@fieldParentPtr first field" { | ||
| 9 | testParentFieldPtrFirst(&foo.a); | ||
| 10 | comptime testParentFieldPtrFirst(&foo.a); | ||
| 11 | } | ||
| 12 | |||
| 13 | const Foo = struct { | ||
| 14 | a: bool, | ||
| 15 | b: f32, | ||
| 16 | c: i32, | ||
| 17 | d: i32, | ||
| 18 | }; | ||
| 19 | |||
| 20 | const foo = Foo{ | ||
| 21 | .a = true, | ||
| 22 | .b = 0.123, | ||
| 23 | .c = 1234, | ||
| 24 | .d = -10, | ||
| 25 | }; | ||
| 26 | |||
| 27 | fn testParentFieldPtr(c: *const i32) void { | ||
| 28 | assertOrPanic(c == &foo.c); | ||
| 29 | |||
| 30 | const base = @fieldParentPtr(Foo, "c", c); | ||
| 31 | assertOrPanic(base == &foo); | ||
| 32 | assertOrPanic(&base.c == c); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn testParentFieldPtrFirst(a: *const bool) void { | ||
| 36 | assertOrPanic(a == &foo.a); | ||
| 37 | |||
| 38 | const base = @fieldParentPtr(Foo, "a", a); | ||
| 39 | assertOrPanic(base == &foo); | ||
| 40 | assertOrPanic(&base.a == a); | ||
| 41 | } | ||
test/stage1/behavior/fn.zig created+208| ... | @@ -0,0 +1,208 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "params" { | ||
| 4 | assertOrPanic(testParamsAdd(22, 11) == 33); | ||
| 5 | } | ||
| 6 | fn testParamsAdd(a: i32, b: i32) i32 { | ||
| 7 | return a + b; | ||
| 8 | } | ||
| 9 | |||
| 10 | test "local variables" { | ||
| 11 | testLocVars(2); | ||
| 12 | } | ||
| 13 | fn testLocVars(b: i32) void { | ||
| 14 | const a: i32 = 1; | ||
| 15 | if (a + b != 3) unreachable; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "void parameters" { | ||
| 19 | voidFun(1, void{}, 2, {}); | ||
| 20 | } | ||
| 21 | fn voidFun(a: i32, b: void, c: i32, d: void) void { | ||
| 22 | const v = b; | ||
| 23 | const vv: void = if (a == 1) v else {}; | ||
| 24 | assertOrPanic(a + c == 3); | ||
| 25 | return vv; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "mutable local variables" { | ||
| 29 | var zero: i32 = 0; | ||
| 30 | assertOrPanic(zero == 0); | ||
| 31 | |||
| 32 | var i = i32(0); | ||
| 33 | while (i != 3) { | ||
| 34 | i += 1; | ||
| 35 | } | ||
| 36 | assertOrPanic(i == 3); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "separate block scopes" { | ||
| 40 | { | ||
| 41 | const no_conflict: i32 = 5; | ||
| 42 | assertOrPanic(no_conflict == 5); | ||
| 43 | } | ||
| 44 | |||
| 45 | const c = x: { | ||
| 46 | const no_conflict = i32(10); | ||
| 47 | break :x no_conflict; | ||
| 48 | }; | ||
| 49 | assertOrPanic(c == 10); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "call function with empty string" { | ||
| 53 | acceptsString(""); | ||
| 54 | } | ||
| 55 | |||
| 56 | fn acceptsString(foo: []u8) void {} | ||
| 57 | |||
| 58 | fn @"weird function name"() i32 { | ||
| 59 | return 1234; | ||
| 60 | } | ||
| 61 | test "weird function name" { | ||
| 62 | assertOrPanic(@"weird function name"() == 1234); | ||
| 63 | } | ||
| 64 | |||
| 65 | test "implicit cast function unreachable return" { | ||
| 66 | wantsFnWithVoid(fnWithUnreachable); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn wantsFnWithVoid(f: fn () void) void {} | ||
| 70 | |||
| 71 | fn fnWithUnreachable() noreturn { | ||
| 72 | unreachable; | ||
| 73 | } | ||
| 74 | |||
| 75 | test "function pointers" { | ||
| 76 | const fns = []@typeOf(fn1){ | ||
| 77 | fn1, | ||
| 78 | fn2, | ||
| 79 | fn3, | ||
| 80 | fn4, | ||
| 81 | }; | ||
| 82 | for (fns) |f, i| { | ||
| 83 | assertOrPanic(f() == @intCast(u32, i) + 5); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | fn fn1() u32 { | ||
| 87 | return 5; | ||
| 88 | } | ||
| 89 | fn fn2() u32 { | ||
| 90 | return 6; | ||
| 91 | } | ||
| 92 | fn fn3() u32 { | ||
| 93 | return 7; | ||
| 94 | } | ||
| 95 | fn fn4() u32 { | ||
| 96 | return 8; | ||
| 97 | } | ||
| 98 | |||
| 99 | test "inline function call" { | ||
| 100 | assertOrPanic(@inlineCall(add, 3, 9) == 12); | ||
| 101 | } | ||
| 102 | |||
| 103 | fn add(a: i32, b: i32) i32 { | ||
| 104 | return a + b; | ||
| 105 | } | ||
| 106 | |||
| 107 | test "number literal as an argument" { | ||
| 108 | numberLiteralArg(3); | ||
| 109 | comptime numberLiteralArg(3); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn numberLiteralArg(a: var) void { | ||
| 113 | assertOrPanic(a == 3); | ||
| 114 | } | ||
| 115 | |||
| 116 | test "assign inline fn to const variable" { | ||
| 117 | const a = inlineFn; | ||
| 118 | a(); | ||
| 119 | } | ||
| 120 | |||
| 121 | inline fn inlineFn() void {} | ||
| 122 | |||
| 123 | test "pass by non-copying value" { | ||
| 124 | assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | ||
| 125 | } | ||
| 126 | |||
| 127 | const Point = struct { | ||
| 128 | x: i32, | ||
| 129 | y: i32, | ||
| 130 | }; | ||
| 131 | |||
| 132 | fn addPointCoords(pt: Point) i32 { | ||
| 133 | return pt.x + pt.y; | ||
| 134 | } | ||
| 135 | |||
| 136 | test "pass by non-copying value through var arg" { | ||
| 137 | assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); | ||
| 138 | } | ||
| 139 | |||
| 140 | fn addPointCoordsVar(pt: var) i32 { | ||
| 141 | comptime assertOrPanic(@typeOf(pt) == Point); | ||
| 142 | return pt.x + pt.y; | ||
| 143 | } | ||
| 144 | |||
| 145 | test "pass by non-copying value as method" { | ||
| 146 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 147 | assertOrPanic(pt.addPointCoords() == 3); | ||
| 148 | } | ||
| 149 | |||
| 150 | const Point2 = struct { | ||
| 151 | x: i32, | ||
| 152 | y: i32, | ||
| 153 | |||
| 154 | fn addPointCoords(self: Point2) i32 { | ||
| 155 | return self.x + self.y; | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | |||
| 159 | test "pass by non-copying value as method, which is generic" { | ||
| 160 | var pt = Point3{ .x = 1, .y = 2 }; | ||
| 161 | assertOrPanic(pt.addPointCoords(i32) == 3); | ||
| 162 | } | ||
| 163 | |||
| 164 | const Point3 = struct { | ||
| 165 | x: i32, | ||
| 166 | y: i32, | ||
| 167 | |||
| 168 | fn addPointCoords(self: Point3, comptime T: type) i32 { | ||
| 169 | return self.x + self.y; | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | test "pass by non-copying value as method, at comptime" { | ||
| 174 | comptime { | ||
| 175 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 176 | assertOrPanic(pt.addPointCoords() == 3); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | fn outer(y: u32) fn (u32) u32 { | ||
| 181 | const Y = @typeOf(y); | ||
| 182 | const st = struct { | ||
| 183 | fn get(z: u32) u32 { | ||
| 184 | return z + @sizeOf(Y); | ||
| 185 | } | ||
| 186 | }; | ||
| 187 | return st.get; | ||
| 188 | } | ||
| 189 | |||
| 190 | test "return inner function which references comptime variable of outer function" { | ||
| 191 | var func = outer(10); | ||
| 192 | assertOrPanic(func(3) == 7); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "extern struct with stdcallcc fn pointer" { | ||
| 196 | const S = extern struct { | ||
| 197 | ptr: stdcallcc fn () i32, | ||
| 198 | |||
| 199 | stdcallcc fn foo() i32 { | ||
| 200 | return 1234; | ||
| 201 | } | ||
| 202 | }; | ||
| 203 | |||
| 204 | var s: S = undefined; | ||
| 205 | s.ptr = S.foo; | ||
| 206 | assertOrPanic(s.ptr() == 1234); | ||
| 207 | } | ||
| 208 | |||
test/stage1/behavior/fn_in_struct_in_comptime.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | fn get_foo() fn (*u8) usize { | ||
| 4 | comptime { | ||
| 5 | return struct { | ||
| 6 | fn func(ptr: *u8) usize { | ||
| 7 | var u = @ptrToInt(ptr); | ||
| 8 | return u; | ||
| 9 | } | ||
| 10 | }.func; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "define a function in an anonymous struct in comptime" { | ||
| 15 | const foo = get_foo(); | ||
| 16 | assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345); | ||
| 17 | } | ||
test/stage1/behavior/for.zig created+106| ... | @@ -0,0 +1,106 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "continue in for loop" { | ||
| 6 | const array = []i32{ | ||
| 7 | 1, | ||
| 8 | 2, | ||
| 9 | 3, | ||
| 10 | 4, | ||
| 11 | 5, | ||
| 12 | }; | ||
| 13 | var sum: i32 = 0; | ||
| 14 | for (array) |x| { | ||
| 15 | sum += x; | ||
| 16 | if (x < 3) { | ||
| 17 | continue; | ||
| 18 | } | ||
| 19 | break; | ||
| 20 | } | ||
| 21 | if (sum != 6) unreachable; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "for loop with pointer elem var" { | ||
| 25 | const source = "abcdefg"; | ||
| 26 | var target: [source.len]u8 = undefined; | ||
| 27 | mem.copy(u8, target[0..], source); | ||
| 28 | mangleString(target[0..]); | ||
| 29 | assertOrPanic(mem.eql(u8, target, "bcdefgh")); | ||
| 30 | } | ||
| 31 | fn mangleString(s: []u8) void { | ||
| 32 | for (s) |*c| { | ||
| 33 | c.* += 1; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "basic for loop" { | ||
| 38 | const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | ||
| 39 | |||
| 40 | var buffer: [expected_result.len]u8 = undefined; | ||
| 41 | var buf_index: usize = 0; | ||
| 42 | |||
| 43 | const array = []u8{ 9, 8, 7, 6 }; | ||
| 44 | for (array) |item| { | ||
| 45 | buffer[buf_index] = item; | ||
| 46 | buf_index += 1; | ||
| 47 | } | ||
| 48 | for (array) |item, index| { | ||
| 49 | buffer[buf_index] = @intCast(u8, index); | ||
| 50 | buf_index += 1; | ||
| 51 | } | ||
| 52 | const array_ptr = &array; | ||
| 53 | for (array_ptr) |item| { | ||
| 54 | buffer[buf_index] = item; | ||
| 55 | buf_index += 1; | ||
| 56 | } | ||
| 57 | for (array_ptr) |item, index| { | ||
| 58 | buffer[buf_index] = @intCast(u8, index); | ||
| 59 | buf_index += 1; | ||
| 60 | } | ||
| 61 | const unknown_size: []const u8 = array; | ||
| 62 | for (unknown_size) |item| { | ||
| 63 | buffer[buf_index] = item; | ||
| 64 | buf_index += 1; | ||
| 65 | } | ||
| 66 | for (unknown_size) |item, index| { | ||
| 67 | buffer[buf_index] = @intCast(u8, index); | ||
| 68 | buf_index += 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result)); | ||
| 72 | } | ||
| 73 | |||
| 74 | test "break from outer for loop" { | ||
| 75 | testBreakOuter(); | ||
| 76 | comptime testBreakOuter(); | ||
| 77 | } | ||
| 78 | |||
| 79 | fn testBreakOuter() void { | ||
| 80 | var array = "aoeu"; | ||
| 81 | var count: usize = 0; | ||
| 82 | outer: for (array) |_| { | ||
| 83 | for (array) |_| { | ||
| 84 | count += 1; | ||
| 85 | break :outer; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | assertOrPanic(count == 1); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "continue outer for loop" { | ||
| 92 | testContinueOuter(); | ||
| 93 | comptime testContinueOuter(); | ||
| 94 | } | ||
| 95 | |||
| 96 | fn testContinueOuter() void { | ||
| 97 | var array = "aoeu"; | ||
| 98 | var counter: usize = 0; | ||
| 99 | outer: for (array) |_| { | ||
| 100 | for (array) |_| { | ||
| 101 | counter += 1; | ||
| 102 | continue :outer; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | assertOrPanic(counter == array.len); | ||
| 106 | } | ||
test/stage1/behavior/generics.zig created+151| ... | @@ -0,0 +1,151 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "simple generic fn" { | ||
| 4 | assertOrPanic(max(i32, 3, -1) == 3); | ||
| 5 | assertOrPanic(max(f32, 0.123, 0.456) == 0.456); | ||
| 6 | assertOrPanic(add(2, 3) == 5); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn max(comptime T: type, a: T, b: T) T { | ||
| 10 | return if (a > b) a else b; | ||
| 11 | } | ||
| 12 | |||
| 13 | fn add(comptime a: i32, b: i32) i32 { | ||
| 14 | return (comptime a) + b; | ||
| 15 | } | ||
| 16 | |||
| 17 | const the_max = max(u32, 1234, 5678); | ||
| 18 | test "compile time generic eval" { | ||
| 19 | assertOrPanic(the_max == 5678); | ||
| 20 | } | ||
| 21 | |||
| 22 | fn gimmeTheBigOne(a: u32, b: u32) u32 { | ||
| 23 | return max(u32, a, b); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn shouldCallSameInstance(a: u32, b: u32) u32 { | ||
| 27 | return max(u32, a, b); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn sameButWithFloats(a: f64, b: f64) f64 { | ||
| 31 | return max(f64, a, b); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "fn with comptime args" { | ||
| 35 | assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678); | ||
| 36 | assertOrPanic(shouldCallSameInstance(34, 12) == 34); | ||
| 37 | assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "var params" { | ||
| 41 | assertOrPanic(max_i32(12, 34) == 34); | ||
| 42 | assertOrPanic(max_f64(1.2, 3.4) == 3.4); | ||
| 43 | } | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | assertOrPanic(max_i32(12, 34) == 34); | ||
| 47 | assertOrPanic(max_f64(1.2, 3.4) == 3.4); | ||
| 48 | } | ||
| 49 | |||
| 50 | fn max_var(a: var, b: var) @typeOf(a + b) { | ||
| 51 | return if (a > b) a else b; | ||
| 52 | } | ||
| 53 | |||
| 54 | fn max_i32(a: i32, b: i32) i32 { | ||
| 55 | return max_var(a, b); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn max_f64(a: f64, b: f64) f64 { | ||
| 59 | return max_var(a, b); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn List(comptime T: type) type { | ||
| 63 | return SmallList(T, 8); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { | ||
| 67 | return struct { | ||
| 68 | items: []T, | ||
| 69 | length: usize, | ||
| 70 | prealloc_items: [STATIC_SIZE]T, | ||
| 71 | }; | ||
| 72 | } | ||
| 73 | |||
| 74 | test "function with return type type" { | ||
| 75 | var list: List(i32) = undefined; | ||
| 76 | var list2: List(i32) = undefined; | ||
| 77 | list.length = 10; | ||
| 78 | list2.length = 10; | ||
| 79 | assertOrPanic(list.prealloc_items.len == 8); | ||
| 80 | assertOrPanic(list2.prealloc_items.len == 8); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "generic struct" { | ||
| 84 | var a1 = GenNode(i32){ | ||
| 85 | .value = 13, | ||
| 86 | .next = null, | ||
| 87 | }; | ||
| 88 | var b1 = GenNode(bool){ | ||
| 89 | .value = true, | ||
| 90 | .next = null, | ||
| 91 | }; | ||
| 92 | assertOrPanic(a1.value == 13); | ||
| 93 | assertOrPanic(a1.value == a1.getVal()); | ||
| 94 | assertOrPanic(b1.getVal()); | ||
| 95 | } | ||
| 96 | fn GenNode(comptime T: type) type { | ||
| 97 | return struct { | ||
| 98 | value: T, | ||
| 99 | next: ?*GenNode(T), | ||
| 100 | fn getVal(n: *const GenNode(T)) T { | ||
| 101 | return n.value; | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "const decls in struct" { | ||
| 107 | assertOrPanic(GenericDataThing(3).count_plus_one == 4); | ||
| 108 | } | ||
| 109 | fn GenericDataThing(comptime count: isize) type { | ||
| 110 | return struct { | ||
| 111 | const count_plus_one = count + 1; | ||
| 112 | }; | ||
| 113 | } | ||
| 114 | |||
| 115 | test "use generic param in generic param" { | ||
| 116 | assertOrPanic(aGenericFn(i32, 3, 4) == 7); | ||
| 117 | } | ||
| 118 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { | ||
| 119 | return a + b; | ||
| 120 | } | ||
| 121 | |||
| 122 | test "generic fn with implicit cast" { | ||
| 123 | assertOrPanic(getFirstByte(u8, []u8{13}) == 13); | ||
| 124 | assertOrPanic(getFirstByte(u16, []u16{ | ||
| 125 | 0, | ||
| 126 | 13, | ||
| 127 | }) == 0); | ||
| 128 | } | ||
| 129 | fn getByte(ptr: ?*const u8) u8 { | ||
| 130 | return ptr.?.*; | ||
| 131 | } | ||
| 132 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 133 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 134 | } | ||
| 135 | |||
| 136 | const foos = []fn (var) bool{ | ||
| 137 | foo1, | ||
| 138 | foo2, | ||
| 139 | }; | ||
| 140 | |||
| 141 | fn foo1(arg: var) bool { | ||
| 142 | return arg; | ||
| 143 | } | ||
| 144 | fn foo2(arg: var) bool { | ||
| 145 | return !arg; | ||
| 146 | } | ||
| 147 | |||
| 148 | test "array of generic fns" { | ||
| 149 | assertOrPanic(foos[0](true)); | ||
| 150 | assertOrPanic(!foos[1](true)); | ||
| 151 | } | ||
test/stage1/behavior/if.zig created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "if statements" { | ||
| 4 | shouldBeEqual(1, 1); | ||
| 5 | firstEqlThird(2, 1, 2); | ||
| 6 | } | ||
| 7 | fn shouldBeEqual(a: i32, b: i32) void { | ||
| 8 | if (a != b) { | ||
| 9 | unreachable; | ||
| 10 | } else { | ||
| 11 | return; | ||
| 12 | } | ||
| 13 | } | ||
| 14 | fn firstEqlThird(a: i32, b: i32, c: i32) void { | ||
| 15 | if (a == b) { | ||
| 16 | unreachable; | ||
| 17 | } else if (b == c) { | ||
| 18 | unreachable; | ||
| 19 | } else if (a == c) { | ||
| 20 | return; | ||
| 21 | } else { | ||
| 22 | unreachable; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | test "else if expression" { | ||
| 27 | assertOrPanic(elseIfExpressionF(1) == 1); | ||
| 28 | } | ||
| 29 | fn elseIfExpressionF(c: u8) u8 { | ||
| 30 | if (c == 0) { | ||
| 31 | return 0; | ||
| 32 | } else if (c == 1) { | ||
| 33 | return 1; | ||
| 34 | } else { | ||
| 35 | return u8(2); | ||
| 36 | } | ||
| 37 | } | ||
test/stage1/behavior/import.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const a_namespace = @import("import/a_namespace.zig"); | ||
| 3 | |||
| 4 | test "call fn via namespace lookup" { | ||
| 5 | assertOrPanic(a_namespace.foo() == 1234); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "importing the same thing gives the same import" { | ||
| 9 | assertOrPanic(@import("std") == @import("std")); | ||
| 10 | } | ||
test/stage1/behavior/import/a_namespace.zig created+3| ... | @@ -0,0 +1,3 @@ | ||
| 1 | pub fn foo() i32 { | ||
| 2 | return 1234; | ||
| 3 | } | ||
test/stage1/behavior/incomplete_struct_param_tld.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const A = struct { | ||
| 4 | b: B, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const B = struct { | ||
| 8 | c: C, | ||
| 9 | }; | ||
| 10 | |||
| 11 | const C = struct { | ||
| 12 | x: i32, | ||
| 13 | |||
| 14 | fn d(c: *const C) i32 { | ||
| 15 | return c.x; | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(a: A) i32 { | ||
| 20 | return a.b.c.d(); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "incomplete struct param top level declaration" { | ||
| 24 | const a = A{ | ||
| 25 | .b = B{ | ||
| 26 | .c = C{ .x = 13 }, | ||
| 27 | }, | ||
| 28 | }; | ||
| 29 | assertOrPanic(foo(a) == 13); | ||
| 30 | } | ||
test/stage1/behavior/inttoptr.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | test "casting random address to function pointer" { | ||
| 6 | randomAddressToFunction(); | ||
| 7 | comptime randomAddressToFunction(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn randomAddressToFunction() void { | ||
| 11 | var addr: usize = 0xdeadbeef; | ||
| 12 | var ptr = @intToPtr(fn () void, addr); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "mutate through ptr initialized with constant intToPtr value" { | ||
| 16 | forceCompilerAnalyzeBranchHardCodedPtrDereference(false); | ||
| 17 | } | ||
| 18 | |||
| 19 | fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { | ||
| 20 | const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); | ||
| 21 | if (x) { | ||
| 22 | hardCodedP.* = hardCodedP.* | 10; | ||
| 23 | } else { | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | } | ||
test/stage1/behavior/ir_block_deps.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | fn foo(id: u64) !i32 { | ||
| 4 | return switch (id) { | ||
| 5 | 1 => getErrInt(), | ||
| 6 | 2 => { | ||
| 7 | const size = try getErrInt(); | ||
| 8 | return try getErrInt(); | ||
| 9 | }, | ||
| 10 | else => error.ItBroke, | ||
| 11 | }; | ||
| 12 | } | ||
| 13 | |||
| 14 | fn getErrInt() anyerror!i32 { | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "ir block deps" { | ||
| 19 | assertOrPanic((foo(1) catch unreachable) == 0); | ||
| 20 | assertOrPanic((foo(2) catch unreachable) == 0); | ||
| 21 | } | ||
test/stage1/behavior/math.zig created+500| ... | @@ -0,0 +1,500 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | const minInt = std.math.minInt; | ||
| 5 | |||
| 6 | test "division" { | ||
| 7 | testDivision(); | ||
| 8 | comptime testDivision(); | ||
| 9 | } | ||
| 10 | fn testDivision() void { | ||
| 11 | assertOrPanic(div(u32, 13, 3) == 4); | ||
| 12 | assertOrPanic(div(f16, 1.0, 2.0) == 0.5); | ||
| 13 | assertOrPanic(div(f32, 1.0, 2.0) == 0.5); | ||
| 14 | |||
| 15 | assertOrPanic(divExact(u32, 55, 11) == 5); | ||
| 16 | assertOrPanic(divExact(i32, -55, 11) == -5); | ||
| 17 | assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0); | ||
| 18 | assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0); | ||
| 19 | assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0); | ||
| 20 | assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0); | ||
| 21 | |||
| 22 | assertOrPanic(divFloor(i32, 5, 3) == 1); | ||
| 23 | assertOrPanic(divFloor(i32, -5, 3) == -2); | ||
| 24 | assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0); | ||
| 25 | assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0); | ||
| 26 | assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0); | ||
| 27 | assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0); | ||
| 28 | assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000); | ||
| 29 | assertOrPanic(divFloor(i32, 0, -0x80000000) == 0); | ||
| 30 | assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2); | ||
| 31 | assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000); | ||
| 32 | |||
| 33 | assertOrPanic(divTrunc(i32, 5, 3) == 1); | ||
| 34 | assertOrPanic(divTrunc(i32, -5, 3) == -1); | ||
| 35 | assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0); | ||
| 36 | assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0); | ||
| 37 | assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0); | ||
| 38 | assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0); | ||
| 39 | assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0); | ||
| 40 | assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0); | ||
| 41 | |||
| 42 | comptime { | ||
| 43 | assertOrPanic( | ||
| 44 | 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, | ||
| 45 | ); | ||
| 46 | assertOrPanic( | ||
| 47 | @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, | ||
| 48 | ); | ||
| 49 | assertOrPanic( | ||
| 50 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, | ||
| 51 | ); | ||
| 52 | assertOrPanic( | ||
| 53 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | ||
| 54 | ); | ||
| 55 | assertOrPanic( | ||
| 56 | @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, | ||
| 57 | ); | ||
| 58 | assertOrPanic( | ||
| 59 | @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, | ||
| 60 | ); | ||
| 61 | assertOrPanic( | ||
| 62 | 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | fn div(comptime T: type, a: T, b: T) T { | ||
| 67 | return a / b; | ||
| 68 | } | ||
| 69 | fn divExact(comptime T: type, a: T, b: T) T { | ||
| 70 | return @divExact(a, b); | ||
| 71 | } | ||
| 72 | fn divFloor(comptime T: type, a: T, b: T) T { | ||
| 73 | return @divFloor(a, b); | ||
| 74 | } | ||
| 75 | fn divTrunc(comptime T: type, a: T, b: T) T { | ||
| 76 | return @divTrunc(a, b); | ||
| 77 | } | ||
| 78 | |||
| 79 | test "@addWithOverflow" { | ||
| 80 | var result: u8 = undefined; | ||
| 81 | assertOrPanic(@addWithOverflow(u8, 250, 100, &result)); | ||
| 82 | assertOrPanic(!@addWithOverflow(u8, 100, 150, &result)); | ||
| 83 | assertOrPanic(result == 250); | ||
| 84 | } | ||
| 85 | |||
| 86 | // TODO test mulWithOverflow | ||
| 87 | // TODO test subWithOverflow | ||
| 88 | |||
| 89 | test "@shlWithOverflow" { | ||
| 90 | var result: u16 = undefined; | ||
| 91 | assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | ||
| 92 | assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | ||
| 93 | assertOrPanic(result == 0b1011111111111100); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "@clz" { | ||
| 97 | testClz(); | ||
| 98 | comptime testClz(); | ||
| 99 | } | ||
| 100 | |||
| 101 | fn testClz() void { | ||
| 102 | assertOrPanic(clz(u8(0b00001010)) == 4); | ||
| 103 | assertOrPanic(clz(u8(0b10001010)) == 0); | ||
| 104 | assertOrPanic(clz(u8(0b00000000)) == 8); | ||
| 105 | assertOrPanic(clz(u128(0xffffffffffffffff)) == 64); | ||
| 106 | assertOrPanic(clz(u128(0x10000000000000000)) == 63); | ||
| 107 | } | ||
| 108 | |||
| 109 | fn clz(x: var) usize { | ||
| 110 | return @clz(x); | ||
| 111 | } | ||
| 112 | |||
| 113 | test "@ctz" { | ||
| 114 | testCtz(); | ||
| 115 | comptime testCtz(); | ||
| 116 | } | ||
| 117 | |||
| 118 | fn testCtz() void { | ||
| 119 | assertOrPanic(ctz(u8(0b10100000)) == 5); | ||
| 120 | assertOrPanic(ctz(u8(0b10001010)) == 1); | ||
| 121 | assertOrPanic(ctz(u8(0b00000000)) == 8); | ||
| 122 | } | ||
| 123 | |||
| 124 | fn ctz(x: var) usize { | ||
| 125 | return @ctz(x); | ||
| 126 | } | ||
| 127 | |||
| 128 | test "assignment operators" { | ||
| 129 | var i: u32 = 0; | ||
| 130 | i += 5; | ||
| 131 | assertOrPanic(i == 5); | ||
| 132 | i -= 2; | ||
| 133 | assertOrPanic(i == 3); | ||
| 134 | i *= 20; | ||
| 135 | assertOrPanic(i == 60); | ||
| 136 | i /= 3; | ||
| 137 | assertOrPanic(i == 20); | ||
| 138 | i %= 11; | ||
| 139 | assertOrPanic(i == 9); | ||
| 140 | i <<= 1; | ||
| 141 | assertOrPanic(i == 18); | ||
| 142 | i >>= 2; | ||
| 143 | assertOrPanic(i == 4); | ||
| 144 | i = 6; | ||
| 145 | i &= 5; | ||
| 146 | assertOrPanic(i == 4); | ||
| 147 | i ^= 6; | ||
| 148 | assertOrPanic(i == 2); | ||
| 149 | i = 6; | ||
| 150 | i |= 3; | ||
| 151 | assertOrPanic(i == 7); | ||
| 152 | } | ||
| 153 | |||
| 154 | test "three expr in a row" { | ||
| 155 | testThreeExprInARow(false, true); | ||
| 156 | comptime testThreeExprInARow(false, true); | ||
| 157 | } | ||
| 158 | fn testThreeExprInARow(f: bool, t: bool) void { | ||
| 159 | assertFalse(f or f or f); | ||
| 160 | assertFalse(t and t and f); | ||
| 161 | assertFalse(1 | 2 | 4 != 7); | ||
| 162 | assertFalse(3 ^ 6 ^ 8 != 13); | ||
| 163 | assertFalse(7 & 14 & 28 != 4); | ||
| 164 | assertFalse(9 << 1 << 2 != 9 << 3); | ||
| 165 | assertFalse(90 >> 1 >> 2 != 90 >> 3); | ||
| 166 | assertFalse(100 - 1 + 1000 != 1099); | ||
| 167 | assertFalse(5 * 4 / 2 % 3 != 1); | ||
| 168 | assertFalse(i32(i32(5)) != 5); | ||
| 169 | assertFalse(!!false); | ||
| 170 | assertFalse(i32(7) != --(i32(7))); | ||
| 171 | } | ||
| 172 | fn assertFalse(b: bool) void { | ||
| 173 | assertOrPanic(!b); | ||
| 174 | } | ||
| 175 | |||
| 176 | test "const number literal" { | ||
| 177 | const one = 1; | ||
| 178 | const eleven = ten + one; | ||
| 179 | |||
| 180 | assertOrPanic(eleven == 11); | ||
| 181 | } | ||
| 182 | const ten = 10; | ||
| 183 | |||
| 184 | test "unsigned wrapping" { | ||
| 185 | testUnsignedWrappingEval(maxInt(u32)); | ||
| 186 | comptime testUnsignedWrappingEval(maxInt(u32)); | ||
| 187 | } | ||
| 188 | fn testUnsignedWrappingEval(x: u32) void { | ||
| 189 | const zero = x +% 1; | ||
| 190 | assertOrPanic(zero == 0); | ||
| 191 | const orig = zero -% 1; | ||
| 192 | assertOrPanic(orig == maxInt(u32)); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "signed wrapping" { | ||
| 196 | testSignedWrappingEval(maxInt(i32)); | ||
| 197 | comptime testSignedWrappingEval(maxInt(i32)); | ||
| 198 | } | ||
| 199 | fn testSignedWrappingEval(x: i32) void { | ||
| 200 | const min_val = x +% 1; | ||
| 201 | assertOrPanic(min_val == minInt(i32)); | ||
| 202 | const max_val = min_val -% 1; | ||
| 203 | assertOrPanic(max_val == maxInt(i32)); | ||
| 204 | } | ||
| 205 | |||
| 206 | test "negation wrapping" { | ||
| 207 | testNegationWrappingEval(minInt(i16)); | ||
| 208 | comptime testNegationWrappingEval(minInt(i16)); | ||
| 209 | } | ||
| 210 | fn testNegationWrappingEval(x: i16) void { | ||
| 211 | assertOrPanic(x == -32768); | ||
| 212 | const neg = -%x; | ||
| 213 | assertOrPanic(neg == -32768); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "unsigned 64-bit division" { | ||
| 217 | test_u64_div(); | ||
| 218 | comptime test_u64_div(); | ||
| 219 | } | ||
| 220 | fn test_u64_div() void { | ||
| 221 | const result = divWithResult(1152921504606846976, 34359738365); | ||
| 222 | assertOrPanic(result.quotient == 33554432); | ||
| 223 | assertOrPanic(result.remainder == 100663296); | ||
| 224 | } | ||
| 225 | fn divWithResult(a: u64, b: u64) DivResult { | ||
| 226 | return DivResult{ | ||
| 227 | .quotient = a / b, | ||
| 228 | .remainder = a % b, | ||
| 229 | }; | ||
| 230 | } | ||
| 231 | const DivResult = struct { | ||
| 232 | quotient: u64, | ||
| 233 | remainder: u64, | ||
| 234 | }; | ||
| 235 | |||
| 236 | test "binary not" { | ||
| 237 | assertOrPanic(comptime x: { | ||
| 238 | break :x ~u16(0b1010101010101010) == 0b0101010101010101; | ||
| 239 | }); | ||
| 240 | assertOrPanic(comptime x: { | ||
| 241 | break :x ~u64(2147483647) == 18446744071562067968; | ||
| 242 | }); | ||
| 243 | testBinaryNot(0b1010101010101010); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn testBinaryNot(x: u16) void { | ||
| 247 | assertOrPanic(~x == 0b0101010101010101); | ||
| 248 | } | ||
| 249 | |||
| 250 | test "small int addition" { | ||
| 251 | var x: @IntType(false, 2) = 0; | ||
| 252 | assertOrPanic(x == 0); | ||
| 253 | |||
| 254 | x += 1; | ||
| 255 | assertOrPanic(x == 1); | ||
| 256 | |||
| 257 | x += 1; | ||
| 258 | assertOrPanic(x == 2); | ||
| 259 | |||
| 260 | x += 1; | ||
| 261 | assertOrPanic(x == 3); | ||
| 262 | |||
| 263 | var result: @typeOf(x) = 3; | ||
| 264 | assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result)); | ||
| 265 | |||
| 266 | assertOrPanic(result == 0); | ||
| 267 | } | ||
| 268 | |||
| 269 | test "float equality" { | ||
| 270 | const x: f64 = 0.012; | ||
| 271 | const y: f64 = x + 1.0; | ||
| 272 | |||
| 273 | testFloatEqualityImpl(x, y); | ||
| 274 | comptime testFloatEqualityImpl(x, y); | ||
| 275 | } | ||
| 276 | |||
| 277 | fn testFloatEqualityImpl(x: f64, y: f64) void { | ||
| 278 | const y2 = x + 1.0; | ||
| 279 | assertOrPanic(y == y2); | ||
| 280 | } | ||
| 281 | |||
| 282 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { | ||
| 283 | assertOrPanic(5 / 3 == 1); | ||
| 284 | assertOrPanic(-5 / -3 == 1); | ||
| 285 | assertOrPanic(-6 / 3 == -2); | ||
| 286 | |||
| 287 | assertOrPanic(5 % 3 == 2); | ||
| 288 | assertOrPanic(-6 % 3 == 0); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "hex float literal parsing" { | ||
| 292 | comptime assertOrPanic(0x1.0 == 1.0); | ||
| 293 | } | ||
| 294 | |||
| 295 | test "quad hex float literal parsing in range" { | ||
| 296 | const a = 0x1.af23456789bbaaab347645365cdep+5; | ||
| 297 | const b = 0x1.dedafcff354b6ae9758763545432p-9; | ||
| 298 | const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; | ||
| 299 | const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; | ||
| 300 | } | ||
| 301 | |||
| 302 | test "quad hex float literal parsing accurate" { | ||
| 303 | const a: f128 = 0x1.1111222233334444555566667777p+0; | ||
| 304 | |||
| 305 | // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. | ||
| 306 | const expected: u128 = 0x3fff1111222233334444555566667777; | ||
| 307 | assertOrPanic(@bitCast(u128, a) == expected); | ||
| 308 | } | ||
| 309 | |||
| 310 | test "hex float literal within range" { | ||
| 311 | const a = 0x1.0p16383; | ||
| 312 | const b = 0x0.1p16387; | ||
| 313 | const c = 0x1.0p-16382; | ||
| 314 | } | ||
| 315 | |||
| 316 | test "truncating shift left" { | ||
| 317 | testShlTrunc(maxInt(u16)); | ||
| 318 | comptime testShlTrunc(maxInt(u16)); | ||
| 319 | } | ||
| 320 | fn testShlTrunc(x: u16) void { | ||
| 321 | const shifted = x << 1; | ||
| 322 | assertOrPanic(shifted == 65534); | ||
| 323 | } | ||
| 324 | |||
| 325 | test "truncating shift right" { | ||
| 326 | testShrTrunc(maxInt(u16)); | ||
| 327 | comptime testShrTrunc(maxInt(u16)); | ||
| 328 | } | ||
| 329 | fn testShrTrunc(x: u16) void { | ||
| 330 | const shifted = x >> 1; | ||
| 331 | assertOrPanic(shifted == 32767); | ||
| 332 | } | ||
| 333 | |||
| 334 | test "exact shift left" { | ||
| 335 | testShlExact(0b00110101); | ||
| 336 | comptime testShlExact(0b00110101); | ||
| 337 | } | ||
| 338 | fn testShlExact(x: u8) void { | ||
| 339 | const shifted = @shlExact(x, 2); | ||
| 340 | assertOrPanic(shifted == 0b11010100); | ||
| 341 | } | ||
| 342 | |||
| 343 | test "exact shift right" { | ||
| 344 | testShrExact(0b10110100); | ||
| 345 | comptime testShrExact(0b10110100); | ||
| 346 | } | ||
| 347 | fn testShrExact(x: u8) void { | ||
| 348 | const shifted = @shrExact(x, 2); | ||
| 349 | assertOrPanic(shifted == 0b00101101); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "comptime_int addition" { | ||
| 353 | comptime { | ||
| 354 | assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | ||
| 355 | assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | test "comptime_int multiplication" { | ||
| 360 | comptime { | ||
| 361 | assertOrPanic( | ||
| 362 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | ||
| 363 | ); | ||
| 364 | assertOrPanic( | ||
| 365 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | ||
| 366 | ); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | test "comptime_int shifting" { | ||
| 371 | comptime { | ||
| 372 | assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | test "comptime_int multi-limb shift and mask" { | ||
| 377 | comptime { | ||
| 378 | var a = 0xefffffffa0000001eeeeeeefaaaaaaab; | ||
| 379 | |||
| 380 | assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab); | ||
| 381 | a >>= 32; | ||
| 382 | assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef); | ||
| 383 | a >>= 32; | ||
| 384 | assertOrPanic(u32(a & 0xffffffff) == 0xa0000001); | ||
| 385 | a >>= 32; | ||
| 386 | assertOrPanic(u32(a & 0xffffffff) == 0xefffffff); | ||
| 387 | a >>= 32; | ||
| 388 | |||
| 389 | assertOrPanic(a == 0); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | test "comptime_int multi-limb partial shift right" { | ||
| 394 | comptime { | ||
| 395 | var a = 0x1ffffffffeeeeeeee; | ||
| 396 | a >>= 16; | ||
| 397 | assertOrPanic(a == 0x1ffffffffeeee); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | test "xor" { | ||
| 402 | test_xor(); | ||
| 403 | comptime test_xor(); | ||
| 404 | } | ||
| 405 | |||
| 406 | fn test_xor() void { | ||
| 407 | assertOrPanic(0xFF ^ 0x00 == 0xFF); | ||
| 408 | assertOrPanic(0xF0 ^ 0x0F == 0xFF); | ||
| 409 | assertOrPanic(0xFF ^ 0xF0 == 0x0F); | ||
| 410 | assertOrPanic(0xFF ^ 0x0F == 0xF0); | ||
| 411 | assertOrPanic(0xFF ^ 0xFF == 0x00); | ||
| 412 | } | ||
| 413 | |||
| 414 | test "comptime_int xor" { | ||
| 415 | comptime { | ||
| 416 | assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 417 | assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 418 | assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); | ||
| 419 | assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); | ||
| 420 | assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); | ||
| 421 | assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 422 | assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); | ||
| 423 | assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | test "f128" { | ||
| 428 | test_f128(); | ||
| 429 | comptime test_f128(); | ||
| 430 | } | ||
| 431 | |||
| 432 | fn make_f128(x: f128) f128 { | ||
| 433 | return x; | ||
| 434 | } | ||
| 435 | |||
| 436 | fn test_f128() void { | ||
| 437 | assertOrPanic(@sizeOf(f128) == 16); | ||
| 438 | assertOrPanic(make_f128(1.0) == 1.0); | ||
| 439 | assertOrPanic(make_f128(1.0) != 1.1); | ||
| 440 | assertOrPanic(make_f128(1.0) > 0.9); | ||
| 441 | assertOrPanic(make_f128(1.0) >= 0.9); | ||
| 442 | assertOrPanic(make_f128(1.0) >= 1.0); | ||
| 443 | should_not_be_zero(1.0); | ||
| 444 | } | ||
| 445 | |||
| 446 | fn should_not_be_zero(x: f128) void { | ||
| 447 | assertOrPanic(x != 0.0); | ||
| 448 | } | ||
| 449 | |||
| 450 | test "comptime float rem int" { | ||
| 451 | comptime { | ||
| 452 | var x = f32(1) % 2; | ||
| 453 | assertOrPanic(x == 1.0); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | test "remainder division" { | ||
| 458 | comptime remdiv(f16); | ||
| 459 | comptime remdiv(f32); | ||
| 460 | comptime remdiv(f64); | ||
| 461 | comptime remdiv(f128); | ||
| 462 | remdiv(f16); | ||
| 463 | remdiv(f64); | ||
| 464 | remdiv(f128); | ||
| 465 | } | ||
| 466 | |||
| 467 | fn remdiv(comptime T: type) void { | ||
| 468 | assertOrPanic(T(1) == T(1) % T(2)); | ||
| 469 | assertOrPanic(T(1) == T(7) % T(3)); | ||
| 470 | } | ||
| 471 | |||
| 472 | test "@sqrt" { | ||
| 473 | testSqrt(f64, 12.0); | ||
| 474 | comptime testSqrt(f64, 12.0); | ||
| 475 | testSqrt(f32, 13.0); | ||
| 476 | comptime testSqrt(f32, 13.0); | ||
| 477 | testSqrt(f16, 13.0); | ||
| 478 | comptime testSqrt(f16, 13.0); | ||
| 479 | |||
| 480 | const x = 14.0; | ||
| 481 | const y = x * x; | ||
| 482 | const z = @sqrt(@typeOf(y), y); | ||
| 483 | comptime assertOrPanic(z == x); | ||
| 484 | } | ||
| 485 | |||
| 486 | fn testSqrt(comptime T: type, x: T) void { | ||
| 487 | assertOrPanic(@sqrt(T, x * x) == x); | ||
| 488 | } | ||
| 489 | |||
| 490 | test "comptime_int param and return" { | ||
| 491 | const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); | ||
| 492 | assertOrPanic(a == 137114567242441932203689521744947848950); | ||
| 493 | |||
| 494 | const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); | ||
| 495 | assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380); | ||
| 496 | } | ||
| 497 | |||
| 498 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | ||
| 499 | return a + b; | ||
| 500 | } | ||
test/stage1/behavior/merge_error_sets.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const A = error{ | ||
| 2 | FileNotFound, | ||
| 3 | NotDir, | ||
| 4 | }; | ||
| 5 | const B = error{OutOfMemory}; | ||
| 6 | |||
| 7 | const C = A || B; | ||
| 8 | |||
| 9 | fn foo() C!void { | ||
| 10 | return error.NotDir; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "merge error sets" { | ||
| 14 | if (foo()) { | ||
| 15 | @panic("unexpected"); | ||
| 16 | } else |err| switch (err) { | ||
| 17 | error.OutOfMemory => @panic("unexpected"), | ||
| 18 | error.FileNotFound => @panic("unexpected"), | ||
| 19 | error.NotDir => {}, | ||
| 20 | } | ||
| 21 | } | ||
test/stage1/behavior/misc.zig created+687| ... | @@ -0,0 +1,687 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const mem = std.mem; | ||
| 4 | const cstr = std.cstr; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | const maxInt = std.math.maxInt; | ||
| 7 | |||
| 8 | // normal comment | ||
| 9 | |||
| 10 | /// this is a documentation comment | ||
| 11 | /// doc comment line 2 | ||
| 12 | fn emptyFunctionWithComments() void {} | ||
| 13 | |||
| 14 | test "empty function with comments" { | ||
| 15 | emptyFunctionWithComments(); | ||
| 16 | } | ||
| 17 | |||
| 18 | comptime { | ||
| 19 | @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); | ||
| 20 | } | ||
| 21 | |||
| 22 | extern fn disabledExternFn() void {} | ||
| 23 | |||
| 24 | test "call disabled extern fn" { | ||
| 25 | disabledExternFn(); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "@IntType builtin" { | ||
| 29 | assertOrPanic(@IntType(true, 8) == i8); | ||
| 30 | assertOrPanic(@IntType(true, 16) == i16); | ||
| 31 | assertOrPanic(@IntType(true, 32) == i32); | ||
| 32 | assertOrPanic(@IntType(true, 64) == i64); | ||
| 33 | |||
| 34 | assertOrPanic(@IntType(false, 8) == u8); | ||
| 35 | assertOrPanic(@IntType(false, 16) == u16); | ||
| 36 | assertOrPanic(@IntType(false, 32) == u32); | ||
| 37 | assertOrPanic(@IntType(false, 64) == u64); | ||
| 38 | |||
| 39 | assertOrPanic(i8.bit_count == 8); | ||
| 40 | assertOrPanic(i16.bit_count == 16); | ||
| 41 | assertOrPanic(i32.bit_count == 32); | ||
| 42 | assertOrPanic(i64.bit_count == 64); | ||
| 43 | |||
| 44 | assertOrPanic(i8.is_signed); | ||
| 45 | assertOrPanic(i16.is_signed); | ||
| 46 | assertOrPanic(i32.is_signed); | ||
| 47 | assertOrPanic(i64.is_signed); | ||
| 48 | assertOrPanic(isize.is_signed); | ||
| 49 | |||
| 50 | assertOrPanic(!u8.is_signed); | ||
| 51 | assertOrPanic(!u16.is_signed); | ||
| 52 | assertOrPanic(!u32.is_signed); | ||
| 53 | assertOrPanic(!u64.is_signed); | ||
| 54 | assertOrPanic(!usize.is_signed); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "floating point primitive bit counts" { | ||
| 58 | assertOrPanic(f16.bit_count == 16); | ||
| 59 | assertOrPanic(f32.bit_count == 32); | ||
| 60 | assertOrPanic(f64.bit_count == 64); | ||
| 61 | } | ||
| 62 | |||
| 63 | test "short circuit" { | ||
| 64 | testShortCircuit(false, true); | ||
| 65 | comptime testShortCircuit(false, true); | ||
| 66 | } | ||
| 67 | |||
| 68 | fn testShortCircuit(f: bool, t: bool) void { | ||
| 69 | var hit_1 = f; | ||
| 70 | var hit_2 = f; | ||
| 71 | var hit_3 = f; | ||
| 72 | var hit_4 = f; | ||
| 73 | |||
| 74 | if (t or x: { | ||
| 75 | assertOrPanic(f); | ||
| 76 | break :x f; | ||
| 77 | }) { | ||
| 78 | hit_1 = t; | ||
| 79 | } | ||
| 80 | if (f or x: { | ||
| 81 | hit_2 = t; | ||
| 82 | break :x f; | ||
| 83 | }) { | ||
| 84 | assertOrPanic(f); | ||
| 85 | } | ||
| 86 | |||
| 87 | if (t and x: { | ||
| 88 | hit_3 = t; | ||
| 89 | break :x f; | ||
| 90 | }) { | ||
| 91 | assertOrPanic(f); | ||
| 92 | } | ||
| 93 | if (f and x: { | ||
| 94 | assertOrPanic(f); | ||
| 95 | break :x f; | ||
| 96 | }) { | ||
| 97 | assertOrPanic(f); | ||
| 98 | } else { | ||
| 99 | hit_4 = t; | ||
| 100 | } | ||
| 101 | assertOrPanic(hit_1); | ||
| 102 | assertOrPanic(hit_2); | ||
| 103 | assertOrPanic(hit_3); | ||
| 104 | assertOrPanic(hit_4); | ||
| 105 | } | ||
| 106 | |||
| 107 | test "truncate" { | ||
| 108 | assertOrPanic(testTruncate(0x10fd) == 0xfd); | ||
| 109 | } | ||
| 110 | fn testTruncate(x: u32) u8 { | ||
| 111 | return @truncate(u8, x); | ||
| 112 | } | ||
| 113 | |||
| 114 | fn first4KeysOfHomeRow() []const u8 { | ||
| 115 | return "aoeu"; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "return string from function" { | ||
| 119 | assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 120 | } | ||
| 121 | |||
| 122 | const g1: i32 = 1233 + 1; | ||
| 123 | var g2: i32 = 0; | ||
| 124 | |||
| 125 | test "global variables" { | ||
| 126 | assertOrPanic(g2 == 0); | ||
| 127 | g2 = g1; | ||
| 128 | assertOrPanic(g2 == 1234); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "memcpy and memset intrinsics" { | ||
| 132 | var foo: [20]u8 = undefined; | ||
| 133 | var bar: [20]u8 = undefined; | ||
| 134 | |||
| 135 | @memset(foo[0..].ptr, 'A', foo.len); | ||
| 136 | @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); | ||
| 137 | |||
| 138 | if (bar[11] != 'A') unreachable; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "builtin static eval" { | ||
| 142 | const x: i32 = comptime x: { | ||
| 143 | break :x 1 + 2 + 3; | ||
| 144 | }; | ||
| 145 | assertOrPanic(x == comptime 6); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "slicing" { | ||
| 149 | var array: [20]i32 = undefined; | ||
| 150 | |||
| 151 | array[5] = 1234; | ||
| 152 | |||
| 153 | var slice = array[5..10]; | ||
| 154 | |||
| 155 | if (slice.len != 5) unreachable; | ||
| 156 | |||
| 157 | const ptr = &slice[0]; | ||
| 158 | if (ptr.* != 1234) unreachable; | ||
| 159 | |||
| 160 | var slice_rest = array[10..]; | ||
| 161 | if (slice_rest.len != 10) unreachable; | ||
| 162 | } | ||
| 163 | |||
| 164 | test "constant equal function pointers" { | ||
| 165 | const alias = emptyFn; | ||
| 166 | assertOrPanic(comptime x: { | ||
| 167 | break :x emptyFn == alias; | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn emptyFn() void {} | ||
| 172 | |||
| 173 | test "hex escape" { | ||
| 174 | assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); | ||
| 175 | } | ||
| 176 | |||
| 177 | test "string concatenation" { | ||
| 178 | assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); | ||
| 179 | } | ||
| 180 | |||
| 181 | test "array mult operator" { | ||
| 182 | assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab")); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "string escapes" { | ||
| 186 | assertOrPanic(mem.eql(u8, "\"", "\x22")); | ||
| 187 | assertOrPanic(mem.eql(u8, "\'", "\x27")); | ||
| 188 | assertOrPanic(mem.eql(u8, "\n", "\x0a")); | ||
| 189 | assertOrPanic(mem.eql(u8, "\r", "\x0d")); | ||
| 190 | assertOrPanic(mem.eql(u8, "\t", "\x09")); | ||
| 191 | assertOrPanic(mem.eql(u8, "\\", "\x5c")); | ||
| 192 | assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "multiline string" { | ||
| 196 | const s1 = | ||
| 197 | \\one | ||
| 198 | \\two) | ||
| 199 | \\three | ||
| 200 | ; | ||
| 201 | const s2 = "one\ntwo)\nthree"; | ||
| 202 | assertOrPanic(mem.eql(u8, s1, s2)); | ||
| 203 | } | ||
| 204 | |||
| 205 | test "multiline C string" { | ||
| 206 | const s1 = | ||
| 207 | c\\one | ||
| 208 | c\\two) | ||
| 209 | c\\three | ||
| 210 | ; | ||
| 211 | const s2 = c"one\ntwo)\nthree"; | ||
| 212 | assertOrPanic(cstr.cmp(s1, s2) == 0); | ||
| 213 | } | ||
| 214 | |||
| 215 | test "type equality" { | ||
| 216 | assertOrPanic(*const u8 != *u8); | ||
| 217 | } | ||
| 218 | |||
| 219 | const global_a: i32 = 1234; | ||
| 220 | const global_b: *const i32 = &global_a; | ||
| 221 | const global_c: *const f32 = @ptrCast(*const f32, global_b); | ||
| 222 | test "compile time global reinterpret" { | ||
| 223 | const d = @ptrCast(*const i32, global_c); | ||
| 224 | assertOrPanic(d.* == 1234); | ||
| 225 | } | ||
| 226 | |||
| 227 | test "explicit cast maybe pointers" { | ||
| 228 | const a: ?*i32 = undefined; | ||
| 229 | const b: ?*f32 = @ptrCast(?*f32, a); | ||
| 230 | } | ||
| 231 | |||
| 232 | test "generic malloc free" { | ||
| 233 | const a = memAlloc(u8, 10) catch unreachable; | ||
| 234 | memFree(u8, a); | ||
| 235 | } | ||
| 236 | var some_mem: [100]u8 = undefined; | ||
| 237 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | ||
| 238 | return @ptrCast([*]T, &some_mem[0])[0..n]; | ||
| 239 | } | ||
| 240 | fn memFree(comptime T: type, memory: []T) void {} | ||
| 241 | |||
| 242 | test "cast undefined" { | ||
| 243 | const array: [100]u8 = undefined; | ||
| 244 | const slice = ([]const u8)(array); | ||
| 245 | testCastUndefined(slice); | ||
| 246 | } | ||
| 247 | fn testCastUndefined(x: []const u8) void {} | ||
| 248 | |||
| 249 | test "cast small unsigned to larger signed" { | ||
| 250 | assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200)); | ||
| 251 | assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); | ||
| 252 | } | ||
| 253 | fn castSmallUnsignedToLargerSigned1(x: u8) i16 { | ||
| 254 | return x; | ||
| 255 | } | ||
| 256 | fn castSmallUnsignedToLargerSigned2(x: u16) i64 { | ||
| 257 | return x; | ||
| 258 | } | ||
| 259 | |||
| 260 | test "implicit cast after unreachable" { | ||
| 261 | assertOrPanic(outer() == 1234); | ||
| 262 | } | ||
| 263 | fn inner() i32 { | ||
| 264 | return 1234; | ||
| 265 | } | ||
| 266 | fn outer() i64 { | ||
| 267 | return inner(); | ||
| 268 | } | ||
| 269 | |||
| 270 | test "pointer dereferencing" { | ||
| 271 | var x = i32(3); | ||
| 272 | const y = &x; | ||
| 273 | |||
| 274 | y.* += 1; | ||
| 275 | |||
| 276 | assertOrPanic(x == 4); | ||
| 277 | assertOrPanic(y.* == 4); | ||
| 278 | } | ||
| 279 | |||
| 280 | test "call result of if else expression" { | ||
| 281 | assertOrPanic(mem.eql(u8, f2(true), "a")); | ||
| 282 | assertOrPanic(mem.eql(u8, f2(false), "b")); | ||
| 283 | } | ||
| 284 | fn f2(x: bool) []const u8 { | ||
| 285 | return (if (x) fA else fB)(); | ||
| 286 | } | ||
| 287 | fn fA() []const u8 { | ||
| 288 | return "a"; | ||
| 289 | } | ||
| 290 | fn fB() []const u8 { | ||
| 291 | return "b"; | ||
| 292 | } | ||
| 293 | |||
| 294 | test "const expression eval handling of variables" { | ||
| 295 | var x = true; | ||
| 296 | while (x) { | ||
| 297 | x = false; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | test "constant enum initialization with differing sizes" { | ||
| 302 | test3_1(test3_foo); | ||
| 303 | test3_2(test3_bar); | ||
| 304 | } | ||
| 305 | const Test3Foo = union(enum) { | ||
| 306 | One: void, | ||
| 307 | Two: f32, | ||
| 308 | Three: Test3Point, | ||
| 309 | }; | ||
| 310 | const Test3Point = struct { | ||
| 311 | x: i32, | ||
| 312 | y: i32, | ||
| 313 | }; | ||
| 314 | const test3_foo = Test3Foo{ | ||
| 315 | .Three = Test3Point{ | ||
| 316 | .x = 3, | ||
| 317 | .y = 4, | ||
| 318 | }, | ||
| 319 | }; | ||
| 320 | const test3_bar = Test3Foo{ .Two = 13 }; | ||
| 321 | fn test3_1(f: Test3Foo) void { | ||
| 322 | switch (f) { | ||
| 323 | Test3Foo.Three => |pt| { | ||
| 324 | assertOrPanic(pt.x == 3); | ||
| 325 | assertOrPanic(pt.y == 4); | ||
| 326 | }, | ||
| 327 | else => unreachable, | ||
| 328 | } | ||
| 329 | } | ||
| 330 | fn test3_2(f: Test3Foo) void { | ||
| 331 | switch (f) { | ||
| 332 | Test3Foo.Two => |x| { | ||
| 333 | assertOrPanic(x == 13); | ||
| 334 | }, | ||
| 335 | else => unreachable, | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | test "character literals" { | ||
| 340 | assertOrPanic('\'' == single_quote); | ||
| 341 | } | ||
| 342 | const single_quote = '\''; | ||
| 343 | |||
| 344 | test "take address of parameter" { | ||
| 345 | testTakeAddressOfParameter(12.34); | ||
| 346 | } | ||
| 347 | fn testTakeAddressOfParameter(f: f32) void { | ||
| 348 | const f_ptr = &f; | ||
| 349 | assertOrPanic(f_ptr.* == 12.34); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "pointer comparison" { | ||
| 353 | const a = ([]const u8)("a"); | ||
| 354 | const b = &a; | ||
| 355 | assertOrPanic(ptrEql(b, b)); | ||
| 356 | } | ||
| 357 | fn ptrEql(a: *const []const u8, b: *const []const u8) bool { | ||
| 358 | return a == b; | ||
| 359 | } | ||
| 360 | |||
| 361 | test "C string concatenation" { | ||
| 362 | const a = c"OK" ++ c" IT " ++ c"WORKED"; | ||
| 363 | const b = c"OK IT WORKED"; | ||
| 364 | |||
| 365 | const len = cstr.len(b); | ||
| 366 | const len_with_null = len + 1; | ||
| 367 | { | ||
| 368 | var i: u32 = 0; | ||
| 369 | while (i < len_with_null) : (i += 1) { | ||
| 370 | assertOrPanic(a[i] == b[i]); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | assertOrPanic(a[len] == 0); | ||
| 374 | assertOrPanic(b[len] == 0); | ||
| 375 | } | ||
| 376 | |||
| 377 | test "cast slice to u8 slice" { | ||
| 378 | assertOrPanic(@sizeOf(i32) == 4); | ||
| 379 | var big_thing_array = []i32{ 1, 2, 3, 4 }; | ||
| 380 | const big_thing_slice: []i32 = big_thing_array[0..]; | ||
| 381 | const bytes = @sliceToBytes(big_thing_slice); | ||
| 382 | assertOrPanic(bytes.len == 4 * 4); | ||
| 383 | bytes[4] = 0; | ||
| 384 | bytes[5] = 0; | ||
| 385 | bytes[6] = 0; | ||
| 386 | bytes[7] = 0; | ||
| 387 | assertOrPanic(big_thing_slice[1] == 0); | ||
| 388 | const big_thing_again = @bytesToSlice(i32, bytes); | ||
| 389 | assertOrPanic(big_thing_again[2] == 3); | ||
| 390 | big_thing_again[2] = -1; | ||
| 391 | assertOrPanic(bytes[8] == maxInt(u8)); | ||
| 392 | assertOrPanic(bytes[9] == maxInt(u8)); | ||
| 393 | assertOrPanic(bytes[10] == maxInt(u8)); | ||
| 394 | assertOrPanic(bytes[11] == maxInt(u8)); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "pointer to void return type" { | ||
| 398 | testPointerToVoidReturnType() catch unreachable; | ||
| 399 | } | ||
| 400 | fn testPointerToVoidReturnType() anyerror!void { | ||
| 401 | const a = testPointerToVoidReturnType2(); | ||
| 402 | return a.*; | ||
| 403 | } | ||
| 404 | const test_pointer_to_void_return_type_x = void{}; | ||
| 405 | fn testPointerToVoidReturnType2() *const void { | ||
| 406 | return &test_pointer_to_void_return_type_x; | ||
| 407 | } | ||
| 408 | |||
| 409 | test "non const ptr to aliased type" { | ||
| 410 | const int = i32; | ||
| 411 | assertOrPanic(?*int == ?*i32); | ||
| 412 | } | ||
| 413 | |||
| 414 | test "array 2D const double ptr" { | ||
| 415 | const rect_2d_vertexes = [][1]f32{ | ||
| 416 | []f32{1.0}, | ||
| 417 | []f32{2.0}, | ||
| 418 | }; | ||
| 419 | testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); | ||
| 420 | } | ||
| 421 | |||
| 422 | fn testArray2DConstDoublePtr(ptr: *const f32) void { | ||
| 423 | const ptr2 = @ptrCast([*]const f32, ptr); | ||
| 424 | assertOrPanic(ptr2[0] == 1.0); | ||
| 425 | assertOrPanic(ptr2[1] == 2.0); | ||
| 426 | } | ||
| 427 | |||
| 428 | const Tid = builtin.TypeId; | ||
| 429 | const AStruct = struct { | ||
| 430 | x: i32, | ||
| 431 | }; | ||
| 432 | const AnEnum = enum { | ||
| 433 | One, | ||
| 434 | Two, | ||
| 435 | }; | ||
| 436 | const AUnionEnum = union(enum) { | ||
| 437 | One: i32, | ||
| 438 | Two: void, | ||
| 439 | }; | ||
| 440 | const AUnion = union { | ||
| 441 | One: void, | ||
| 442 | Two: void, | ||
| 443 | }; | ||
| 444 | |||
| 445 | test "@typeId" { | ||
| 446 | comptime { | ||
| 447 | assertOrPanic(@typeId(type) == Tid.Type); | ||
| 448 | assertOrPanic(@typeId(void) == Tid.Void); | ||
| 449 | assertOrPanic(@typeId(bool) == Tid.Bool); | ||
| 450 | assertOrPanic(@typeId(noreturn) == Tid.NoReturn); | ||
| 451 | assertOrPanic(@typeId(i8) == Tid.Int); | ||
| 452 | assertOrPanic(@typeId(u8) == Tid.Int); | ||
| 453 | assertOrPanic(@typeId(i64) == Tid.Int); | ||
| 454 | assertOrPanic(@typeId(u64) == Tid.Int); | ||
| 455 | assertOrPanic(@typeId(f32) == Tid.Float); | ||
| 456 | assertOrPanic(@typeId(f64) == Tid.Float); | ||
| 457 | assertOrPanic(@typeId(*f32) == Tid.Pointer); | ||
| 458 | assertOrPanic(@typeId([2]u8) == Tid.Array); | ||
| 459 | assertOrPanic(@typeId(AStruct) == Tid.Struct); | ||
| 460 | assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt); | ||
| 461 | assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); | ||
| 462 | assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined); | ||
| 463 | assertOrPanic(@typeId(@typeOf(null)) == Tid.Null); | ||
| 464 | assertOrPanic(@typeId(?i32) == Tid.Optional); | ||
| 465 | assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion); | ||
| 466 | assertOrPanic(@typeId(anyerror) == Tid.ErrorSet); | ||
| 467 | assertOrPanic(@typeId(AnEnum) == Tid.Enum); | ||
| 468 | assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); | ||
| 469 | assertOrPanic(@typeId(AUnionEnum) == Tid.Union); | ||
| 470 | assertOrPanic(@typeId(AUnion) == Tid.Union); | ||
| 471 | assertOrPanic(@typeId(fn () void) == Tid.Fn); | ||
| 472 | assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace); | ||
| 473 | // TODO bound fn | ||
| 474 | // TODO arg tuple | ||
| 475 | // TODO opaque | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | test "@typeName" { | ||
| 480 | const Struct = struct {}; | ||
| 481 | const Union = union { | ||
| 482 | unused: u8, | ||
| 483 | }; | ||
| 484 | const Enum = enum { | ||
| 485 | Unused, | ||
| 486 | }; | ||
| 487 | comptime { | ||
| 488 | assertOrPanic(mem.eql(u8, @typeName(i64), "i64")); | ||
| 489 | assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize")); | ||
| 490 | // https://github.com/ziglang/zig/issues/675 | ||
| 491 | assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); | ||
| 492 | assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct")); | ||
| 493 | assertOrPanic(mem.eql(u8, @typeName(Union), "Union")); | ||
| 494 | assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum")); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | fn TypeFromFn(comptime T: type) type { | ||
| 499 | return struct {}; | ||
| 500 | } | ||
| 501 | |||
| 502 | test "double implicit cast in same expression" { | ||
| 503 | var x = i32(u16(nine())); | ||
| 504 | assertOrPanic(x == 9); | ||
| 505 | } | ||
| 506 | fn nine() u8 { | ||
| 507 | return 9; | ||
| 508 | } | ||
| 509 | |||
| 510 | test "global variable initialized to global variable array element" { | ||
| 511 | assertOrPanic(global_ptr == &gdt[0]); | ||
| 512 | } | ||
| 513 | const GDTEntry = struct { | ||
| 514 | field: i32, | ||
| 515 | }; | ||
| 516 | var gdt = []GDTEntry{ | ||
| 517 | GDTEntry{ .field = 1 }, | ||
| 518 | GDTEntry{ .field = 2 }, | ||
| 519 | }; | ||
| 520 | var global_ptr = &gdt[0]; | ||
| 521 | |||
| 522 | // can't really run this test but we can make sure it has no compile error | ||
| 523 | // and generates code | ||
| 524 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 525 | export fn writeToVRam() void { | ||
| 526 | vram[0] = 'X'; | ||
| 527 | } | ||
| 528 | |||
| 529 | const OpaqueA = @OpaqueType(); | ||
| 530 | const OpaqueB = @OpaqueType(); | ||
| 531 | test "@OpaqueType" { | ||
| 532 | assertOrPanic(*OpaqueA != *OpaqueB); | ||
| 533 | assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); | ||
| 534 | assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | ||
| 535 | } | ||
| 536 | |||
| 537 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 538 | var x: i32 = 1234; | ||
| 539 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 540 | } | ||
| 541 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 542 | var a = ptr; | ||
| 543 | return a; | ||
| 544 | } | ||
| 545 | |||
| 546 | test "comptime if inside runtime while which unconditionally breaks" { | ||
| 547 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 548 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 549 | } | ||
| 550 | fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { | ||
| 551 | while (cond) { | ||
| 552 | if (false) {} | ||
| 553 | break; | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | test "implicit comptime while" { | ||
| 558 | while (false) { | ||
| 559 | @compileError("bad"); | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | fn fnThatClosesOverLocalConst() type { | ||
| 564 | const c = 1; | ||
| 565 | return struct { | ||
| 566 | fn g() i32 { | ||
| 567 | return c; | ||
| 568 | } | ||
| 569 | }; | ||
| 570 | } | ||
| 571 | |||
| 572 | test "function closes over local const" { | ||
| 573 | const x = fnThatClosesOverLocalConst().g(); | ||
| 574 | assertOrPanic(x == 1); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "cold function" { | ||
| 578 | thisIsAColdFn(); | ||
| 579 | comptime thisIsAColdFn(); | ||
| 580 | } | ||
| 581 | |||
| 582 | fn thisIsAColdFn() void { | ||
| 583 | @setCold(true); | ||
| 584 | } | ||
| 585 | |||
| 586 | const PackedStruct = packed struct { | ||
| 587 | a: u8, | ||
| 588 | b: u8, | ||
| 589 | }; | ||
| 590 | const PackedUnion = packed union { | ||
| 591 | a: u8, | ||
| 592 | b: u32, | ||
| 593 | }; | ||
| 594 | const PackedEnum = packed enum { | ||
| 595 | A, | ||
| 596 | B, | ||
| 597 | }; | ||
| 598 | |||
| 599 | test "packed struct, enum, union parameters in extern function" { | ||
| 600 | testPackedStuff(&(PackedStruct{ | ||
| 601 | .a = 1, | ||
| 602 | .b = 2, | ||
| 603 | }), &(PackedUnion{ .a = 1 }), PackedEnum.A); | ||
| 604 | } | ||
| 605 | |||
| 606 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} | ||
| 607 | |||
| 608 | test "slicing zero length array" { | ||
| 609 | const s1 = ""[0..]; | ||
| 610 | const s2 = ([]u32{})[0..]; | ||
| 611 | assertOrPanic(s1.len == 0); | ||
| 612 | assertOrPanic(s2.len == 0); | ||
| 613 | assertOrPanic(mem.eql(u8, s1, "")); | ||
| 614 | assertOrPanic(mem.eql(u32, s2, []u32{})); | ||
| 615 | } | ||
| 616 | |||
| 617 | const addr1 = @ptrCast(*const u8, emptyFn); | ||
| 618 | test "comptime cast fn to ptr" { | ||
| 619 | const addr2 = @ptrCast(*const u8, emptyFn); | ||
| 620 | comptime assertOrPanic(addr1 == addr2); | ||
| 621 | } | ||
| 622 | |||
| 623 | test "equality compare fn ptrs" { | ||
| 624 | var a = emptyFn; | ||
| 625 | assertOrPanic(a == a); | ||
| 626 | } | ||
| 627 | |||
| 628 | test "self reference through fn ptr field" { | ||
| 629 | const S = struct { | ||
| 630 | const A = struct { | ||
| 631 | f: fn (A) u8, | ||
| 632 | }; | ||
| 633 | |||
| 634 | fn foo(a: A) u8 { | ||
| 635 | return 12; | ||
| 636 | } | ||
| 637 | }; | ||
| 638 | var a: S.A = undefined; | ||
| 639 | a.f = S.foo; | ||
| 640 | assertOrPanic(a.f(a) == 12); | ||
| 641 | } | ||
| 642 | |||
| 643 | test "volatile load and store" { | ||
| 644 | var number: i32 = 1234; | ||
| 645 | const ptr = (*volatile i32)(&number); | ||
| 646 | ptr.* += 1; | ||
| 647 | assertOrPanic(ptr.* == 1235); | ||
| 648 | } | ||
| 649 | |||
| 650 | test "slice string literal has type []const u8" { | ||
| 651 | comptime { | ||
| 652 | assertOrPanic(@typeOf("aoeu"[0..]) == []const u8); | ||
| 653 | const array = []i32{ 1, 2, 3, 4 }; | ||
| 654 | assertOrPanic(@typeOf(array[0..]) == []const i32); | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 658 | test "pointer child field" { | ||
| 659 | assertOrPanic((*u32).Child == u32); | ||
| 660 | } | ||
| 661 | |||
| 662 | test "struct inside function" { | ||
| 663 | testStructInFn(); | ||
| 664 | comptime testStructInFn(); | ||
| 665 | } | ||
| 666 | |||
| 667 | fn testStructInFn() void { | ||
| 668 | const BlockKind = u32; | ||
| 669 | |||
| 670 | const Block = struct { | ||
| 671 | kind: BlockKind, | ||
| 672 | }; | ||
| 673 | |||
| 674 | var block = Block{ .kind = 1234 }; | ||
| 675 | |||
| 676 | block.kind += 1; | ||
| 677 | |||
| 678 | assertOrPanic(block.kind == 1235); | ||
| 679 | } | ||
| 680 | |||
| 681 | test "fn call returning scalar optional in equality expression" { | ||
| 682 | assertOrPanic(getNull() == null); | ||
| 683 | } | ||
| 684 | |||
| 685 | fn getNull() ?*i32 { | ||
| 686 | return null; | ||
| 687 | } | ||
test/stage1/behavior/namespace_depends_on_compile_var/a.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const a_bool = true; | ||
test/stage1/behavior/namespace_depends_on_compile_var/b.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const a_bool = false; | ||
test/stage1/behavior/namespace_depends_on_compile_var/index.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "namespace depends on compile var" { | ||
| 5 | if (some_namespace.a_bool) { | ||
| 6 | assertOrPanic(some_namespace.a_bool); | ||
| 7 | } else { | ||
| 8 | assertOrPanic(!some_namespace.a_bool); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | const some_namespace = switch (builtin.os) { | ||
| 12 | builtin.Os.linux => @import("a.zig"), | ||
| 13 | else => @import("b.zig"), | ||
| 14 | }; | ||
test/stage1/behavior/new_stack_call.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | var new_stack_bytes: [1024]u8 = undefined; | ||
| 5 | |||
| 6 | test "calling a function with a new stack" { | ||
| 7 | const arg = 1234; | ||
| 8 | |||
| 9 | const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); | ||
| 10 | const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); | ||
| 11 | _ = targetFunction(arg); | ||
| 12 | |||
| 13 | assertOrPanic(arg == 1234); | ||
| 14 | assertOrPanic(a < b); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn targetFunction(x: i32) usize { | ||
| 18 | assertOrPanic(x == 1234); | ||
| 19 | |||
| 20 | var local_variable: i32 = 42; | ||
| 21 | const ptr = &local_variable; | ||
| 22 | ptr.* += 1; | ||
| 23 | |||
| 24 | assertOrPanic(local_variable == 43); | ||
| 25 | return @ptrToInt(ptr); | ||
| 26 | } | ||
test/stage1/behavior/null.zig created+162| ... | @@ -0,0 +1,162 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "optional type" { | ||
| 4 | const x: ?bool = true; | ||
| 5 | |||
| 6 | if (x) |y| { | ||
| 7 | if (y) { | ||
| 8 | // OK | ||
| 9 | } else { | ||
| 10 | unreachable; | ||
| 11 | } | ||
| 12 | } else { | ||
| 13 | unreachable; | ||
| 14 | } | ||
| 15 | |||
| 16 | const next_x: ?i32 = null; | ||
| 17 | |||
| 18 | const z = next_x orelse 1234; | ||
| 19 | |||
| 20 | assertOrPanic(z == 1234); | ||
| 21 | |||
| 22 | const final_x: ?i32 = 13; | ||
| 23 | |||
| 24 | const num = final_x orelse unreachable; | ||
| 25 | |||
| 26 | assertOrPanic(num == 13); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "test maybe object and get a pointer to the inner value" { | ||
| 30 | var maybe_bool: ?bool = true; | ||
| 31 | |||
| 32 | if (maybe_bool) |*b| { | ||
| 33 | b.* = false; | ||
| 34 | } | ||
| 35 | |||
| 36 | assertOrPanic(maybe_bool.? == false); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "rhs maybe unwrap return" { | ||
| 40 | const x: ?bool = true; | ||
| 41 | const y = x orelse return; | ||
| 42 | } | ||
| 43 | |||
| 44 | test "maybe return" { | ||
| 45 | maybeReturnImpl(); | ||
| 46 | comptime maybeReturnImpl(); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn maybeReturnImpl() void { | ||
| 50 | assertOrPanic(foo(1235).?); | ||
| 51 | if (foo(null) != null) unreachable; | ||
| 52 | assertOrPanic(!foo(1234).?); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn foo(x: ?i32) ?bool { | ||
| 56 | const value = x orelse return null; | ||
| 57 | return value > 1234; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "if var maybe pointer" { | ||
| 61 | assertOrPanic(shouldBeAPlus1(Particle{ | ||
| 62 | .a = 14, | ||
| 63 | .b = 1, | ||
| 64 | .c = 1, | ||
| 65 | .d = 1, | ||
| 66 | }) == 15); | ||
| 67 | } | ||
| 68 | fn shouldBeAPlus1(p: Particle) u64 { | ||
| 69 | var maybe_particle: ?Particle = p; | ||
| 70 | if (maybe_particle) |*particle| { | ||
| 71 | particle.a += 1; | ||
| 72 | } | ||
| 73 | if (maybe_particle) |particle| { | ||
| 74 | return particle.a; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | const Particle = struct { | ||
| 79 | a: u64, | ||
| 80 | b: u64, | ||
| 81 | c: u64, | ||
| 82 | d: u64, | ||
| 83 | }; | ||
| 84 | |||
| 85 | test "null literal outside function" { | ||
| 86 | const is_null = here_is_a_null_literal.context == null; | ||
| 87 | assertOrPanic(is_null); | ||
| 88 | |||
| 89 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 90 | assertOrPanic(!is_non_null); | ||
| 91 | } | ||
| 92 | const SillyStruct = struct { | ||
| 93 | context: ?i32, | ||
| 94 | }; | ||
| 95 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 96 | |||
| 97 | test "test null runtime" { | ||
| 98 | testTestNullRuntime(null); | ||
| 99 | } | ||
| 100 | fn testTestNullRuntime(x: ?i32) void { | ||
| 101 | assertOrPanic(x == null); | ||
| 102 | assertOrPanic(!(x != null)); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "optional void" { | ||
| 106 | optionalVoidImpl(); | ||
| 107 | comptime optionalVoidImpl(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn optionalVoidImpl() void { | ||
| 111 | assertOrPanic(bar(null) == null); | ||
| 112 | assertOrPanic(bar({}) != null); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn bar(x: ?void) ?void { | ||
| 116 | if (x) |_| { | ||
| 117 | return {}; | ||
| 118 | } else { | ||
| 119 | return null; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | const StructWithOptional = struct { | ||
| 124 | field: ?i32, | ||
| 125 | }; | ||
| 126 | |||
| 127 | var struct_with_optional: StructWithOptional = undefined; | ||
| 128 | |||
| 129 | test "unwrap optional which is field of global var" { | ||
| 130 | struct_with_optional.field = null; | ||
| 131 | if (struct_with_optional.field) |payload| { | ||
| 132 | unreachable; | ||
| 133 | } | ||
| 134 | struct_with_optional.field = 1234; | ||
| 135 | if (struct_with_optional.field) |payload| { | ||
| 136 | assertOrPanic(payload == 1234); | ||
| 137 | } else { | ||
| 138 | unreachable; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | test "null with default unwrap" { | ||
| 143 | const x: i32 = null orelse 1; | ||
| 144 | assertOrPanic(x == 1); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "optional types" { | ||
| 148 | comptime { | ||
| 149 | const opt_type_struct = StructWithOptionalType{ .t = u8 }; | ||
| 150 | assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | const StructWithOptionalType = struct { | ||
| 155 | t: ?type, | ||
| 156 | }; | ||
| 157 | |||
| 158 | test "optional pointer to 0 bit type null value at runtime" { | ||
| 159 | const EmptyStruct = struct {}; | ||
| 160 | var x: ?*EmptyStruct = null; | ||
| 161 | assertOrPanic(x == null); | ||
| 162 | } | ||
test/stage1/behavior/optional.zig created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | pub const EmptyStruct = struct {}; | ||
| 4 | |||
| 5 | test "optional pointer to size zero struct" { | ||
| 6 | var e = EmptyStruct{}; | ||
| 7 | var o: ?*EmptyStruct = &e; | ||
| 8 | assertOrPanic(o != null); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "equality compare nullable pointers" { | ||
| 12 | testNullPtrsEql(); | ||
| 13 | comptime testNullPtrsEql(); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn testNullPtrsEql() void { | ||
| 17 | var number: i32 = 1234; | ||
| 18 | |||
| 19 | var x: ?*i32 = null; | ||
| 20 | var y: ?*i32 = null; | ||
| 21 | assertOrPanic(x == y); | ||
| 22 | y = &number; | ||
| 23 | assertOrPanic(x != y); | ||
| 24 | assertOrPanic(x != &number); | ||
| 25 | assertOrPanic(&number != x); | ||
| 26 | x = &number; | ||
| 27 | assertOrPanic(x == y); | ||
| 28 | assertOrPanic(x == &number); | ||
| 29 | assertOrPanic(&number == x); | ||
| 30 | } | ||
| 31 | |||
| 32 | test "address of unwrap optional" { | ||
| 33 | const S = struct { | ||
| 34 | const Foo = struct { | ||
| 35 | a: i32, | ||
| 36 | }; | ||
| 37 | |||
| 38 | var global: ?Foo = null; | ||
| 39 | |||
| 40 | pub fn getFoo() anyerror!*Foo { | ||
| 41 | return &global.?; | ||
| 42 | } | ||
| 43 | }; | ||
| 44 | S.global = S.Foo{ .a = 1234 }; | ||
| 45 | const foo = S.getFoo() catch unreachable; | ||
| 46 | assertOrPanic(foo.a == 1234); | ||
| 47 | } | ||
| 48 | |||
| 49 | test "passing an optional integer as a parameter" { | ||
| 50 | const S = struct { | ||
| 51 | fn entry() bool { | ||
| 52 | var x: i32 = 1234; | ||
| 53 | return foo(x); | ||
| 54 | } | ||
| 55 | |||
| 56 | fn foo(x: ?i32) bool { | ||
| 57 | return x.? == 1234; | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | assertOrPanic(S.entry()); | ||
| 61 | comptime assertOrPanic(S.entry()); | ||
| 62 | } | ||
| 63 | |||
| 64 | test "unwrap function call with optional pointer return value" { | ||
| 65 | const S = struct { | ||
| 66 | fn entry() void { | ||
| 67 | assertOrPanic(foo().?.* == 1234); | ||
| 68 | assertOrPanic(bar() == null); | ||
| 69 | } | ||
| 70 | const global: i32 = 1234; | ||
| 71 | fn foo() ?*const i32 { | ||
| 72 | return &global; | ||
| 73 | } | ||
| 74 | fn bar() ?*i32 { | ||
| 75 | return null; | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | S.entry(); | ||
| 79 | // TODO https://github.com/ziglang/zig/issues/1901 | ||
| 80 | //comptime S.entry(); | ||
| 81 | } | ||
test/stage1/behavior/pointers.zig created+44| ... | @@ -0,0 +1,44 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "dereference pointer" { | ||
| 5 | comptime testDerefPtr(); | ||
| 6 | testDerefPtr(); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn testDerefPtr() void { | ||
| 10 | var x: i32 = 1234; | ||
| 11 | var y = &x; | ||
| 12 | y.* += 1; | ||
| 13 | assertOrPanic(x == 1235); | ||
| 14 | } | ||
| 15 | |||
| 16 | test "pointer arithmetic" { | ||
| 17 | var ptr = c"abcd"; | ||
| 18 | |||
| 19 | assertOrPanic(ptr[0] == 'a'); | ||
| 20 | ptr += 1; | ||
| 21 | assertOrPanic(ptr[0] == 'b'); | ||
| 22 | ptr += 1; | ||
| 23 | assertOrPanic(ptr[0] == 'c'); | ||
| 24 | ptr += 1; | ||
| 25 | assertOrPanic(ptr[0] == 'd'); | ||
| 26 | ptr += 1; | ||
| 27 | assertOrPanic(ptr[0] == 0); | ||
| 28 | ptr -= 1; | ||
| 29 | assertOrPanic(ptr[0] == 'd'); | ||
| 30 | ptr -= 1; | ||
| 31 | assertOrPanic(ptr[0] == 'c'); | ||
| 32 | ptr -= 1; | ||
| 33 | assertOrPanic(ptr[0] == 'b'); | ||
| 34 | ptr -= 1; | ||
| 35 | assertOrPanic(ptr[0] == 'a'); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "double pointer parsing" { | ||
| 39 | comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32); | ||
| 40 | } | ||
| 41 | |||
| 42 | fn PtrOf(comptime T: type) type { | ||
| 43 | return *T; | ||
| 44 | } | ||
test/stage1/behavior/popcount.zig created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "@popCount" { | ||
| 4 | comptime testPopCount(); | ||
| 5 | testPopCount(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testPopCount() void { | ||
| 9 | { | ||
| 10 | var x: u32 = 0xaa; | ||
| 11 | assertOrPanic(@popCount(x) == 4); | ||
| 12 | } | ||
| 13 | { | ||
| 14 | var x: u32 = 0xaaaaaaaa; | ||
| 15 | assertOrPanic(@popCount(x) == 16); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var x: i16 = -1; | ||
| 19 | assertOrPanic(@popCount(x) == 16); | ||
| 20 | } | ||
| 21 | comptime { | ||
| 22 | assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
test/stage1/behavior/ptrcast.zig created+52| ... | @@ -0,0 +1,52 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 4 | |||
| 5 | test "reinterpret bytes as integer with nonzero offset" { | ||
| 6 | testReinterpretBytesAsInteger(); | ||
| 7 | comptime testReinterpretBytesAsInteger(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testReinterpretBytesAsInteger() void { | ||
| 11 | const bytes = "\x12\x34\x56\x78\xab"; | ||
| 12 | const expected = switch (builtin.endian) { | ||
| 13 | builtin.Endian.Little => 0xab785634, | ||
| 14 | builtin.Endian.Big => 0x345678ab, | ||
| 15 | }; | ||
| 16 | assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "reinterpret bytes of an array into an extern struct" { | ||
| 20 | testReinterpretBytesAsExternStruct(); | ||
| 21 | comptime testReinterpretBytesAsExternStruct(); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn testReinterpretBytesAsExternStruct() void { | ||
| 25 | var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; | ||
| 26 | |||
| 27 | const S = extern struct { | ||
| 28 | a: u8, | ||
| 29 | b: u16, | ||
| 30 | c: u8, | ||
| 31 | }; | ||
| 32 | |||
| 33 | var ptr = @ptrCast(*const S, &bytes); | ||
| 34 | var val = ptr.c; | ||
| 35 | assertOrPanic(val == 5); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "reinterpret struct field at comptime" { | ||
| 39 | const numLittle = comptime Bytes.init(0x12345678); | ||
| 40 | assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); | ||
| 41 | } | ||
| 42 | |||
| 43 | const Bytes = struct { | ||
| 44 | bytes: [4]u8, | ||
| 45 | |||
| 46 | pub fn init(v: u32) Bytes { | ||
| 47 | var res: Bytes = undefined; | ||
| 48 | @ptrCast(*align(1) u32, &res.bytes).* = v; | ||
| 49 | |||
| 50 | return res; | ||
| 51 | } | ||
| 52 | }; | ||
test/stage1/behavior/pub_enum/index.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | const other = @import("other.zig"); | ||
| 2 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "pub enum" { | ||
| 5 | pubEnumTest(other.APubEnum.Two); | ||
| 6 | } | ||
| 7 | fn pubEnumTest(foo: other.APubEnum) void { | ||
| 8 | assertOrPanic(foo == other.APubEnum.Two); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "cast with imported symbol" { | ||
| 12 | assertOrPanic(other.size_t(42) == 42); | ||
| 13 | } | ||
test/stage1/behavior/pub_enum/other.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | pub const APubEnum = enum { | ||
| 2 | One, | ||
| 3 | Two, | ||
| 4 | Three, | ||
| 5 | }; | ||
| 6 | pub const size_t = u64; | ||
test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | var ok: bool = false; | ||
| 5 | test "reference a variable in an if after an if in the 2nd switch prong" { | ||
| 6 | foo(true, Num.Two, false, "aoeu"); | ||
| 7 | assertOrPanic(!ok); | ||
| 8 | foo(false, Num.One, false, "aoeu"); | ||
| 9 | assertOrPanic(!ok); | ||
| 10 | foo(true, Num.One, false, "aoeu"); | ||
| 11 | assertOrPanic(ok); | ||
| 12 | } | ||
| 13 | |||
| 14 | const Num = enum { | ||
| 15 | One, | ||
| 16 | Two, | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { | ||
| 20 | switch (k) { | ||
| 21 | Num.Two => {}, | ||
| 22 | Num.One => { | ||
| 23 | if (c) { | ||
| 24 | const output_path = b; | ||
| 25 | |||
| 26 | if (c2) {} | ||
| 27 | |||
| 28 | a(output_path); | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn a(x: []const u8) void { | ||
| 35 | assertOrPanic(mem.eql(u8, x, "aoeu")); | ||
| 36 | ok = true; | ||
| 37 | } | ||
test/stage1/behavior/reflection.zig created+96| ... | @@ -0,0 +1,96 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const reflection = @This(); | ||
| 4 | |||
| 5 | test "reflection: array, pointer, optional, error union type child" { | ||
| 6 | comptime { | ||
| 7 | assertOrPanic(([10]u8).Child == u8); | ||
| 8 | assertOrPanic((*u8).Child == u8); | ||
| 9 | assertOrPanic((anyerror!u8).Payload == u8); | ||
| 10 | assertOrPanic((?u8).Child == u8); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "reflection: function return type, var args, and param types" { | ||
| 15 | comptime { | ||
| 16 | assertOrPanic(@typeOf(dummy).ReturnType == i32); | ||
| 17 | assertOrPanic(!@typeOf(dummy).is_var_args); | ||
| 18 | assertOrPanic(@typeOf(dummy_varargs).is_var_args); | ||
| 19 | assertOrPanic(@typeOf(dummy).arg_count == 3); | ||
| 20 | assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool); | ||
| 21 | assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32); | ||
| 22 | assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | fn dummy(a: bool, b: i32, c: f32) i32 { | ||
| 27 | return 1234; | ||
| 28 | } | ||
| 29 | fn dummy_varargs(args: ...) void {} | ||
| 30 | |||
| 31 | test "reflection: struct member types and names" { | ||
| 32 | comptime { | ||
| 33 | assertOrPanic(@memberCount(Foo) == 3); | ||
| 34 | |||
| 35 | assertOrPanic(@memberType(Foo, 0) == i32); | ||
| 36 | assertOrPanic(@memberType(Foo, 1) == bool); | ||
| 37 | assertOrPanic(@memberType(Foo, 2) == void); | ||
| 38 | |||
| 39 | assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one")); | ||
| 40 | assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two")); | ||
| 41 | assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three")); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | test "reflection: enum member types and names" { | ||
| 46 | comptime { | ||
| 47 | assertOrPanic(@memberCount(Bar) == 4); | ||
| 48 | |||
| 49 | assertOrPanic(@memberType(Bar, 0) == void); | ||
| 50 | assertOrPanic(@memberType(Bar, 1) == i32); | ||
| 51 | assertOrPanic(@memberType(Bar, 2) == bool); | ||
| 52 | assertOrPanic(@memberType(Bar, 3) == f64); | ||
| 53 | |||
| 54 | assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One")); | ||
| 55 | assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two")); | ||
| 56 | assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three")); | ||
| 57 | assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four")); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "reflection: @field" { | ||
| 62 | var f = Foo{ | ||
| 63 | .one = 42, | ||
| 64 | .two = true, | ||
| 65 | .three = void{}, | ||
| 66 | }; | ||
| 67 | |||
| 68 | assertOrPanic(f.one == f.one); | ||
| 69 | assertOrPanic(@field(f, "o" ++ "ne") == f.one); | ||
| 70 | assertOrPanic(@field(f, "t" ++ "wo") == f.two); | ||
| 71 | assertOrPanic(@field(f, "th" ++ "ree") == f.three); | ||
| 72 | assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant); | ||
| 73 | assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One); | ||
| 74 | assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two); | ||
| 75 | assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three); | ||
| 76 | assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four); | ||
| 77 | assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); | ||
| 78 | @field(f, "o" ++ "ne") = 4; | ||
| 79 | assertOrPanic(f.one == 4); | ||
| 80 | } | ||
| 81 | |||
| 82 | const Foo = struct { | ||
| 83 | const constant = 52; | ||
| 84 | |||
| 85 | one: i32, | ||
| 86 | two: bool, | ||
| 87 | three: void, | ||
| 88 | }; | ||
| 89 | |||
| 90 | const Bar = union(enum) { | ||
| 91 | One: void, | ||
| 92 | Two: i32, | ||
| 93 | Three: bool, | ||
| 94 | Four: f64, | ||
| 95 | }; | ||
| 96 | |||
test/stage1/behavior/sizeof_and_typeof.zig created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "@sizeOf and @typeOf" { | ||
| 5 | const y: @typeOf(x) = 120; | ||
| 6 | assertOrPanic(@sizeOf(@typeOf(y)) == 2); | ||
| 7 | } | ||
| 8 | const x: u16 = 13; | ||
| 9 | const z: @typeOf(x) = 19; | ||
| 10 | |||
| 11 | const A = struct { | ||
| 12 | a: u8, | ||
| 13 | b: u32, | ||
| 14 | c: u8, | ||
| 15 | d: u3, | ||
| 16 | e: u5, | ||
| 17 | f: u16, | ||
| 18 | g: u16, | ||
| 19 | }; | ||
| 20 | |||
| 21 | const P = packed struct { | ||
| 22 | a: u8, | ||
| 23 | b: u32, | ||
| 24 | c: u8, | ||
| 25 | d: u3, | ||
| 26 | e: u5, | ||
| 27 | f: u16, | ||
| 28 | g: u16, | ||
| 29 | }; | ||
| 30 | |||
| 31 | test "@byteOffsetOf" { | ||
| 32 | // Packed structs have fixed memory layout | ||
| 33 | assertOrPanic(@byteOffsetOf(P, "a") == 0); | ||
| 34 | assertOrPanic(@byteOffsetOf(P, "b") == 1); | ||
| 35 | assertOrPanic(@byteOffsetOf(P, "c") == 5); | ||
| 36 | assertOrPanic(@byteOffsetOf(P, "d") == 6); | ||
| 37 | assertOrPanic(@byteOffsetOf(P, "e") == 6); | ||
| 38 | assertOrPanic(@byteOffsetOf(P, "f") == 7); | ||
| 39 | assertOrPanic(@byteOffsetOf(P, "g") == 9); | ||
| 40 | |||
| 41 | // Normal struct fields can be moved/padded | ||
| 42 | var a: A = undefined; | ||
| 43 | assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); | ||
| 44 | assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); | ||
| 45 | assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); | ||
| 46 | assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); | ||
| 47 | assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); | ||
| 48 | assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); | ||
| 49 | assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "@bitOffsetOf" { | ||
| 53 | // Packed structs have fixed memory layout | ||
| 54 | assertOrPanic(@bitOffsetOf(P, "a") == 0); | ||
| 55 | assertOrPanic(@bitOffsetOf(P, "b") == 8); | ||
| 56 | assertOrPanic(@bitOffsetOf(P, "c") == 40); | ||
| 57 | assertOrPanic(@bitOffsetOf(P, "d") == 48); | ||
| 58 | assertOrPanic(@bitOffsetOf(P, "e") == 51); | ||
| 59 | assertOrPanic(@bitOffsetOf(P, "f") == 56); | ||
| 60 | assertOrPanic(@bitOffsetOf(P, "g") == 72); | ||
| 61 | |||
| 62 | assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 63 | assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 64 | assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 65 | assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 66 | assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 67 | assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 68 | assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 69 | } | ||
test/stage1/behavior/slice.zig created+40| ... | @@ -0,0 +1,40 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | ||
| 5 | const y = x[0x100..]; | ||
| 6 | test "compile time slice of pointer to hard coded address" { | ||
| 7 | assertOrPanic(@ptrToInt(x.ptr) == 0x1000); | ||
| 8 | assertOrPanic(x.len == 0x500); | ||
| 9 | |||
| 10 | assertOrPanic(@ptrToInt(y.ptr) == 0x1100); | ||
| 11 | assertOrPanic(y.len == 0x400); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "slice child property" { | ||
| 15 | var array: [5]i32 = undefined; | ||
| 16 | var slice = array[0..]; | ||
| 17 | assertOrPanic(@typeOf(slice).Child == i32); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "runtime safety lets us slice from len..len" { | ||
| 21 | var an_array = []u8{ | ||
| 22 | 1, | ||
| 23 | 2, | ||
| 24 | 3, | ||
| 25 | }; | ||
| 26 | assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | ||
| 30 | return a_slice[start..end]; | ||
| 31 | } | ||
| 32 | |||
| 33 | test "implicitly cast array of size 0 to slice" { | ||
| 34 | var msg = []u8{}; | ||
| 35 | assertLenIsZero(msg); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn assertLenIsZero(msg: []const u8) void { | ||
| 39 | assertOrPanic(msg.len == 0); | ||
| 40 | } | ||
test/stage1/behavior/struct.zig created+470| ... | @@ -0,0 +1,470 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | const StructWithNoFields = struct { | ||
| 7 | fn add(a: i32, b: i32) i32 { | ||
| 8 | return a + b; | ||
| 9 | } | ||
| 10 | }; | ||
| 11 | const empty_global_instance = StructWithNoFields{}; | ||
| 12 | |||
| 13 | test "call struct static method" { | ||
| 14 | const result = StructWithNoFields.add(3, 4); | ||
| 15 | assertOrPanic(result == 7); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "return empty struct instance" { | ||
| 19 | _ = returnEmptyStructInstance(); | ||
| 20 | } | ||
| 21 | fn returnEmptyStructInstance() StructWithNoFields { | ||
| 22 | return empty_global_instance; | ||
| 23 | } | ||
| 24 | |||
| 25 | const should_be_11 = StructWithNoFields.add(5, 6); | ||
| 26 | |||
| 27 | test "invoke static method in global scope" { | ||
| 28 | assertOrPanic(should_be_11 == 11); | ||
| 29 | } | ||
| 30 | |||
| 31 | test "void struct fields" { | ||
| 32 | const foo = VoidStructFieldsFoo{ | ||
| 33 | .a = void{}, | ||
| 34 | .b = 1, | ||
| 35 | .c = void{}, | ||
| 36 | }; | ||
| 37 | assertOrPanic(foo.b == 1); | ||
| 38 | assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 39 | } | ||
| 40 | const VoidStructFieldsFoo = struct { | ||
| 41 | a: void, | ||
| 42 | b: i32, | ||
| 43 | c: void, | ||
| 44 | }; | ||
| 45 | |||
| 46 | test "structs" { | ||
| 47 | var foo: StructFoo = undefined; | ||
| 48 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 49 | foo.a += 1; | ||
| 50 | foo.b = foo.a == 1; | ||
| 51 | testFoo(foo); | ||
| 52 | testMutation(&foo); | ||
| 53 | assertOrPanic(foo.c == 100); | ||
| 54 | } | ||
| 55 | const StructFoo = struct { | ||
| 56 | a: i32, | ||
| 57 | b: bool, | ||
| 58 | c: f32, | ||
| 59 | }; | ||
| 60 | fn testFoo(foo: StructFoo) void { | ||
| 61 | assertOrPanic(foo.b); | ||
| 62 | } | ||
| 63 | fn testMutation(foo: *StructFoo) void { | ||
| 64 | foo.c = 100; | ||
| 65 | } | ||
| 66 | |||
| 67 | const Node = struct { | ||
| 68 | val: Val, | ||
| 69 | next: *Node, | ||
| 70 | }; | ||
| 71 | |||
| 72 | const Val = struct { | ||
| 73 | x: i32, | ||
| 74 | }; | ||
| 75 | |||
| 76 | test "struct point to self" { | ||
| 77 | var root: Node = undefined; | ||
| 78 | root.val.x = 1; | ||
| 79 | |||
| 80 | var node: Node = undefined; | ||
| 81 | node.next = &root; | ||
| 82 | node.val.x = 2; | ||
| 83 | |||
| 84 | root.next = &node; | ||
| 85 | |||
| 86 | assertOrPanic(node.next.next.next.val.x == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "struct byval assign" { | ||
| 90 | var foo1: StructFoo = undefined; | ||
| 91 | var foo2: StructFoo = undefined; | ||
| 92 | |||
| 93 | foo1.a = 1234; | ||
| 94 | foo2.a = 0; | ||
| 95 | assertOrPanic(foo2.a == 0); | ||
| 96 | foo2 = foo1; | ||
| 97 | assertOrPanic(foo2.a == 1234); | ||
| 98 | } | ||
| 99 | |||
| 100 | fn structInitializer() void { | ||
| 101 | const val = Val{ .x = 42 }; | ||
| 102 | assertOrPanic(val.x == 42); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "fn call of struct field" { | ||
| 106 | assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13); | ||
| 107 | } | ||
| 108 | |||
| 109 | const Foo = struct { | ||
| 110 | ptr: fn () i32, | ||
| 111 | }; | ||
| 112 | |||
| 113 | fn aFunc() i32 { | ||
| 114 | return 13; | ||
| 115 | } | ||
| 116 | |||
| 117 | fn callStructField(foo: Foo) i32 { | ||
| 118 | return foo.ptr(); | ||
| 119 | } | ||
| 120 | |||
| 121 | test "store member function in variable" { | ||
| 122 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 123 | const memberFn = MemberFnTestFoo.member; | ||
| 124 | const result = memberFn(instance); | ||
| 125 | assertOrPanic(result == 1234); | ||
| 126 | } | ||
| 127 | const MemberFnTestFoo = struct { | ||
| 128 | x: i32, | ||
| 129 | fn member(foo: MemberFnTestFoo) i32 { | ||
| 130 | return foo.x; | ||
| 131 | } | ||
| 132 | }; | ||
| 133 | |||
| 134 | test "call member function directly" { | ||
| 135 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 136 | const result = MemberFnTestFoo.member(instance); | ||
| 137 | assertOrPanic(result == 1234); | ||
| 138 | } | ||
| 139 | |||
| 140 | test "member functions" { | ||
| 141 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 142 | assertOrPanic(r.getSeed() == 1234); | ||
| 143 | } | ||
| 144 | const MemberFnRand = struct { | ||
| 145 | seed: u32, | ||
| 146 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 147 | return r.seed; | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | test "return struct byval from function" { | ||
| 152 | const bar = makeBar(1234, 5678); | ||
| 153 | assertOrPanic(bar.y == 5678); | ||
| 154 | } | ||
| 155 | const Bar = struct { | ||
| 156 | x: i32, | ||
| 157 | y: i32, | ||
| 158 | }; | ||
| 159 | fn makeBar(x: i32, y: i32) Bar { | ||
| 160 | return Bar{ | ||
| 161 | .x = x, | ||
| 162 | .y = y, | ||
| 163 | }; | ||
| 164 | } | ||
| 165 | |||
| 166 | test "empty struct method call" { | ||
| 167 | const es = EmptyStruct{}; | ||
| 168 | assertOrPanic(es.method() == 1234); | ||
| 169 | } | ||
| 170 | const EmptyStruct = struct { | ||
| 171 | fn method(es: *const EmptyStruct) i32 { | ||
| 172 | return 1234; | ||
| 173 | } | ||
| 174 | }; | ||
| 175 | |||
| 176 | test "return empty struct from fn" { | ||
| 177 | _ = testReturnEmptyStructFromFn(); | ||
| 178 | } | ||
| 179 | const EmptyStruct2 = struct {}; | ||
| 180 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 181 | return EmptyStruct2{}; | ||
| 182 | } | ||
| 183 | |||
| 184 | test "pass slice of empty struct to fn" { | ||
| 185 | assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); | ||
| 186 | } | ||
| 187 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { | ||
| 188 | return slice.len; | ||
| 189 | } | ||
| 190 | |||
| 191 | const APackedStruct = packed struct { | ||
| 192 | x: u8, | ||
| 193 | y: u8, | ||
| 194 | }; | ||
| 195 | |||
| 196 | test "packed struct" { | ||
| 197 | var foo = APackedStruct{ | ||
| 198 | .x = 1, | ||
| 199 | .y = 2, | ||
| 200 | }; | ||
| 201 | foo.y += 1; | ||
| 202 | const four = foo.x + foo.y; | ||
| 203 | assertOrPanic(four == 4); | ||
| 204 | } | ||
| 205 | |||
| 206 | const BitField1 = packed struct { | ||
| 207 | a: u3, | ||
| 208 | b: u3, | ||
| 209 | c: u2, | ||
| 210 | }; | ||
| 211 | |||
| 212 | const bit_field_1 = BitField1{ | ||
| 213 | .a = 1, | ||
| 214 | .b = 2, | ||
| 215 | .c = 3, | ||
| 216 | }; | ||
| 217 | |||
| 218 | test "bit field access" { | ||
| 219 | var data = bit_field_1; | ||
| 220 | assertOrPanic(getA(&data) == 1); | ||
| 221 | assertOrPanic(getB(&data) == 2); | ||
| 222 | assertOrPanic(getC(&data) == 3); | ||
| 223 | comptime assertOrPanic(@sizeOf(BitField1) == 1); | ||
| 224 | |||
| 225 | data.b += 1; | ||
| 226 | assertOrPanic(data.b == 3); | ||
| 227 | |||
| 228 | data.a += 1; | ||
| 229 | assertOrPanic(data.a == 2); | ||
| 230 | assertOrPanic(data.b == 3); | ||
| 231 | } | ||
| 232 | |||
| 233 | fn getA(data: *const BitField1) u3 { | ||
| 234 | return data.a; | ||
| 235 | } | ||
| 236 | |||
| 237 | fn getB(data: *const BitField1) u3 { | ||
| 238 | return data.b; | ||
| 239 | } | ||
| 240 | |||
| 241 | fn getC(data: *const BitField1) u2 { | ||
| 242 | return data.c; | ||
| 243 | } | ||
| 244 | |||
| 245 | const Foo24Bits = packed struct { | ||
| 246 | field: u24, | ||
| 247 | }; | ||
| 248 | const Foo96Bits = packed struct { | ||
| 249 | a: u24, | ||
| 250 | b: u24, | ||
| 251 | c: u24, | ||
| 252 | d: u24, | ||
| 253 | }; | ||
| 254 | |||
| 255 | test "packed struct 24bits" { | ||
| 256 | comptime { | ||
| 257 | assertOrPanic(@sizeOf(Foo24Bits) == 3); | ||
| 258 | assertOrPanic(@sizeOf(Foo96Bits) == 12); | ||
| 259 | } | ||
| 260 | |||
| 261 | var value = Foo96Bits{ | ||
| 262 | .a = 0, | ||
| 263 | .b = 0, | ||
| 264 | .c = 0, | ||
| 265 | .d = 0, | ||
| 266 | }; | ||
| 267 | value.a += 1; | ||
| 268 | assertOrPanic(value.a == 1); | ||
| 269 | assertOrPanic(value.b == 0); | ||
| 270 | assertOrPanic(value.c == 0); | ||
| 271 | assertOrPanic(value.d == 0); | ||
| 272 | |||
| 273 | value.b += 1; | ||
| 274 | assertOrPanic(value.a == 1); | ||
| 275 | assertOrPanic(value.b == 1); | ||
| 276 | assertOrPanic(value.c == 0); | ||
| 277 | assertOrPanic(value.d == 0); | ||
| 278 | |||
| 279 | value.c += 1; | ||
| 280 | assertOrPanic(value.a == 1); | ||
| 281 | assertOrPanic(value.b == 1); | ||
| 282 | assertOrPanic(value.c == 1); | ||
| 283 | assertOrPanic(value.d == 0); | ||
| 284 | |||
| 285 | value.d += 1; | ||
| 286 | assertOrPanic(value.a == 1); | ||
| 287 | assertOrPanic(value.b == 1); | ||
| 288 | assertOrPanic(value.c == 1); | ||
| 289 | assertOrPanic(value.d == 1); | ||
| 290 | } | ||
| 291 | |||
| 292 | const FooArray24Bits = packed struct { | ||
| 293 | a: u16, | ||
| 294 | b: [2]Foo24Bits, | ||
| 295 | c: u16, | ||
| 296 | }; | ||
| 297 | |||
| 298 | test "packed array 24bits" { | ||
| 299 | comptime { | ||
| 300 | assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3); | ||
| 301 | assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); | ||
| 302 | } | ||
| 303 | |||
| 304 | var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); | ||
| 305 | bytes[bytes.len - 1] = 0xaa; | ||
| 306 | const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; | ||
| 307 | assertOrPanic(ptr.a == 0); | ||
| 308 | assertOrPanic(ptr.b[0].field == 0); | ||
| 309 | assertOrPanic(ptr.b[1].field == 0); | ||
| 310 | assertOrPanic(ptr.c == 0); | ||
| 311 | |||
| 312 | ptr.a = maxInt(u16); | ||
| 313 | assertOrPanic(ptr.a == maxInt(u16)); | ||
| 314 | assertOrPanic(ptr.b[0].field == 0); | ||
| 315 | assertOrPanic(ptr.b[1].field == 0); | ||
| 316 | assertOrPanic(ptr.c == 0); | ||
| 317 | |||
| 318 | ptr.b[0].field = maxInt(u24); | ||
| 319 | assertOrPanic(ptr.a == maxInt(u16)); | ||
| 320 | assertOrPanic(ptr.b[0].field == maxInt(u24)); | ||
| 321 | assertOrPanic(ptr.b[1].field == 0); | ||
| 322 | assertOrPanic(ptr.c == 0); | ||
| 323 | |||
| 324 | ptr.b[1].field = maxInt(u24); | ||
| 325 | assertOrPanic(ptr.a == maxInt(u16)); | ||
| 326 | assertOrPanic(ptr.b[0].field == maxInt(u24)); | ||
| 327 | assertOrPanic(ptr.b[1].field == maxInt(u24)); | ||
| 328 | assertOrPanic(ptr.c == 0); | ||
| 329 | |||
| 330 | ptr.c = maxInt(u16); | ||
| 331 | assertOrPanic(ptr.a == maxInt(u16)); | ||
| 332 | assertOrPanic(ptr.b[0].field == maxInt(u24)); | ||
| 333 | assertOrPanic(ptr.b[1].field == maxInt(u24)); | ||
| 334 | assertOrPanic(ptr.c == maxInt(u16)); | ||
| 335 | |||
| 336 | assertOrPanic(bytes[bytes.len - 1] == 0xaa); | ||
| 337 | } | ||
| 338 | |||
| 339 | const FooStructAligned = packed struct { | ||
| 340 | a: u8, | ||
| 341 | b: u8, | ||
| 342 | }; | ||
| 343 | |||
| 344 | const FooArrayOfAligned = packed struct { | ||
| 345 | a: [2]FooStructAligned, | ||
| 346 | }; | ||
| 347 | |||
| 348 | test "aligned array of packed struct" { | ||
| 349 | comptime { | ||
| 350 | assertOrPanic(@sizeOf(FooStructAligned) == 2); | ||
| 351 | assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2); | ||
| 352 | } | ||
| 353 | |||
| 354 | var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); | ||
| 355 | const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; | ||
| 356 | |||
| 357 | assertOrPanic(ptr.a[0].a == 0xbb); | ||
| 358 | assertOrPanic(ptr.a[0].b == 0xbb); | ||
| 359 | assertOrPanic(ptr.a[1].a == 0xbb); | ||
| 360 | assertOrPanic(ptr.a[1].b == 0xbb); | ||
| 361 | } | ||
| 362 | |||
| 363 | test "runtime struct initialization of bitfield" { | ||
| 364 | const s1 = Nibbles{ | ||
| 365 | .x = x1, | ||
| 366 | .y = x1, | ||
| 367 | }; | ||
| 368 | const s2 = Nibbles{ | ||
| 369 | .x = @intCast(u4, x2), | ||
| 370 | .y = @intCast(u4, x2), | ||
| 371 | }; | ||
| 372 | |||
| 373 | assertOrPanic(s1.x == x1); | ||
| 374 | assertOrPanic(s1.y == x1); | ||
| 375 | assertOrPanic(s2.x == @intCast(u4, x2)); | ||
| 376 | assertOrPanic(s2.y == @intCast(u4, x2)); | ||
| 377 | } | ||
| 378 | |||
| 379 | var x1 = u4(1); | ||
| 380 | var x2 = u8(2); | ||
| 381 | |||
| 382 | const Nibbles = packed struct { | ||
| 383 | x: u4, | ||
| 384 | y: u4, | ||
| 385 | }; | ||
| 386 | |||
| 387 | const Bitfields = packed struct { | ||
| 388 | f1: u16, | ||
| 389 | f2: u16, | ||
| 390 | f3: u8, | ||
| 391 | f4: u8, | ||
| 392 | f5: u4, | ||
| 393 | f6: u4, | ||
| 394 | f7: u8, | ||
| 395 | }; | ||
| 396 | |||
| 397 | test "native bit field understands endianness" { | ||
| 398 | var all: u64 = 0x7765443322221111; | ||
| 399 | var bytes: [8]u8 = undefined; | ||
| 400 | @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); | ||
| 401 | var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; | ||
| 402 | |||
| 403 | assertOrPanic(bitfields.f1 == 0x1111); | ||
| 404 | assertOrPanic(bitfields.f2 == 0x2222); | ||
| 405 | assertOrPanic(bitfields.f3 == 0x33); | ||
| 406 | assertOrPanic(bitfields.f4 == 0x44); | ||
| 407 | assertOrPanic(bitfields.f5 == 0x5); | ||
| 408 | assertOrPanic(bitfields.f6 == 0x6); | ||
| 409 | assertOrPanic(bitfields.f7 == 0x77); | ||
| 410 | } | ||
| 411 | |||
| 412 | test "align 1 field before self referential align 8 field as slice return type" { | ||
| 413 | const result = alloc(Expr); | ||
| 414 | assertOrPanic(result.len == 0); | ||
| 415 | } | ||
| 416 | |||
| 417 | const Expr = union(enum) { | ||
| 418 | Literal: u8, | ||
| 419 | Question: *Expr, | ||
| 420 | }; | ||
| 421 | |||
| 422 | fn alloc(comptime T: type) []T { | ||
| 423 | return []T{}; | ||
| 424 | } | ||
| 425 | |||
| 426 | test "call method with mutable reference to struct with no fields" { | ||
| 427 | const S = struct { | ||
| 428 | fn doC(s: *const @This()) bool { | ||
| 429 | return true; | ||
| 430 | } | ||
| 431 | fn do(s: *@This()) bool { | ||
| 432 | return true; | ||
| 433 | } | ||
| 434 | }; | ||
| 435 | |||
| 436 | var s = S{}; | ||
| 437 | assertOrPanic(S.doC(&s)); | ||
| 438 | assertOrPanic(s.doC()); | ||
| 439 | assertOrPanic(S.do(&s)); | ||
| 440 | assertOrPanic(s.do()); | ||
| 441 | } | ||
| 442 | |||
| 443 | test "implicit cast packed struct field to const ptr" { | ||
| 444 | const LevelUpMove = packed struct { | ||
| 445 | move_id: u9, | ||
| 446 | level: u7, | ||
| 447 | |||
| 448 | fn toInt(value: u7) u7 { | ||
| 449 | return value; | ||
| 450 | } | ||
| 451 | }; | ||
| 452 | |||
| 453 | var lup: LevelUpMove = undefined; | ||
| 454 | lup.level = 12; | ||
| 455 | const res = LevelUpMove.toInt(lup.level); | ||
| 456 | assertOrPanic(res == 12); | ||
| 457 | } | ||
| 458 | |||
| 459 | test "pointer to packed struct member in a stack variable" { | ||
| 460 | const S = packed struct { | ||
| 461 | a: u2, | ||
| 462 | b: u2, | ||
| 463 | }; | ||
| 464 | |||
| 465 | var s = S{ .a = 2, .b = 0 }; | ||
| 466 | var b_ptr = &s.b; | ||
| 467 | assertOrPanic(s.b == 0); | ||
| 468 | b_ptr.* = 2; | ||
| 469 | assertOrPanic(s.b == 2); | ||
| 470 | } | ||
test/stage1/behavior/struct_contains_null_ptr_itself.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "struct contains null pointer which contains original struct" { | ||
| 5 | var x: ?*NodeLineComment = null; | ||
| 6 | assertOrPanic(x == null); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub const Node = struct { | ||
| 10 | id: Id, | ||
| 11 | comment: ?*NodeLineComment, | ||
| 12 | |||
| 13 | pub const Id = enum { | ||
| 14 | Root, | ||
| 15 | LineComment, | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub const NodeLineComment = struct { | ||
| 20 | base: Node, | ||
| 21 | }; | ||
test/stage1/behavior/struct_contains_slice_of_itself.zig created+85| ... | @@ -0,0 +1,85 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const Node = struct { | ||
| 4 | payload: i32, | ||
| 5 | children: []Node, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const NodeAligned = struct { | ||
| 9 | payload: i32, | ||
| 10 | children: []align(@alignOf(NodeAligned)) NodeAligned, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "struct contains slice of itself" { | ||
| 14 | var other_nodes = []Node{ | ||
| 15 | Node{ | ||
| 16 | .payload = 31, | ||
| 17 | .children = []Node{}, | ||
| 18 | }, | ||
| 19 | Node{ | ||
| 20 | .payload = 32, | ||
| 21 | .children = []Node{}, | ||
| 22 | }, | ||
| 23 | }; | ||
| 24 | var nodes = []Node{ | ||
| 25 | Node{ | ||
| 26 | .payload = 1, | ||
| 27 | .children = []Node{}, | ||
| 28 | }, | ||
| 29 | Node{ | ||
| 30 | .payload = 2, | ||
| 31 | .children = []Node{}, | ||
| 32 | }, | ||
| 33 | Node{ | ||
| 34 | .payload = 3, | ||
| 35 | .children = other_nodes[0..], | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | const root = Node{ | ||
| 39 | .payload = 1234, | ||
| 40 | .children = nodes[0..], | ||
| 41 | }; | ||
| 42 | assertOrPanic(root.payload == 1234); | ||
| 43 | assertOrPanic(root.children[0].payload == 1); | ||
| 44 | assertOrPanic(root.children[1].payload == 2); | ||
| 45 | assertOrPanic(root.children[2].payload == 3); | ||
| 46 | assertOrPanic(root.children[2].children[0].payload == 31); | ||
| 47 | assertOrPanic(root.children[2].children[1].payload == 32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "struct contains aligned slice of itself" { | ||
| 51 | var other_nodes = []NodeAligned{ | ||
| 52 | NodeAligned{ | ||
| 53 | .payload = 31, | ||
| 54 | .children = []NodeAligned{}, | ||
| 55 | }, | ||
| 56 | NodeAligned{ | ||
| 57 | .payload = 32, | ||
| 58 | .children = []NodeAligned{}, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | var nodes = []NodeAligned{ | ||
| 62 | NodeAligned{ | ||
| 63 | .payload = 1, | ||
| 64 | .children = []NodeAligned{}, | ||
| 65 | }, | ||
| 66 | NodeAligned{ | ||
| 67 | .payload = 2, | ||
| 68 | .children = []NodeAligned{}, | ||
| 69 | }, | ||
| 70 | NodeAligned{ | ||
| 71 | .payload = 3, | ||
| 72 | .children = other_nodes[0..], | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | const root = NodeAligned{ | ||
| 76 | .payload = 1234, | ||
| 77 | .children = nodes[0..], | ||
| 78 | }; | ||
| 79 | assertOrPanic(root.payload == 1234); | ||
| 80 | assertOrPanic(root.children[0].payload == 1); | ||
| 81 | assertOrPanic(root.children[1].payload == 2); | ||
| 82 | assertOrPanic(root.children[2].payload == 3); | ||
| 83 | assertOrPanic(root.children[2].children[0].payload == 31); | ||
| 84 | assertOrPanic(root.children[2].children[1].payload == 32); | ||
| 85 | } | ||
test/stage1/behavior/switch.zig created+271| ... | @@ -0,0 +1,271 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "switch with numbers" { | ||
| 4 | testSwitchWithNumbers(13); | ||
| 5 | } | ||
| 6 | |||
| 7 | fn testSwitchWithNumbers(x: u32) void { | ||
| 8 | const result = switch (x) { | ||
| 9 | 1, 2, 3, 4...8 => false, | ||
| 10 | 13 => true, | ||
| 11 | else => false, | ||
| 12 | }; | ||
| 13 | assertOrPanic(result); | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch with all ranges" { | ||
| 17 | assertOrPanic(testSwitchWithAllRanges(50, 3) == 1); | ||
| 18 | assertOrPanic(testSwitchWithAllRanges(101, 0) == 2); | ||
| 19 | assertOrPanic(testSwitchWithAllRanges(300, 5) == 3); | ||
| 20 | assertOrPanic(testSwitchWithAllRanges(301, 6) == 6); | ||
| 21 | } | ||
| 22 | |||
| 23 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 24 | return switch (x) { | ||
| 25 | 0...100 => 1, | ||
| 26 | 101...200 => 2, | ||
| 27 | 201...300 => 3, | ||
| 28 | else => y, | ||
| 29 | }; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "implicit comptime switch" { | ||
| 33 | const x = 3 + 4; | ||
| 34 | const result = switch (x) { | ||
| 35 | 3 => 10, | ||
| 36 | 4 => 11, | ||
| 37 | 5, 6 => 12, | ||
| 38 | 7, 8 => 13, | ||
| 39 | else => 14, | ||
| 40 | }; | ||
| 41 | |||
| 42 | comptime { | ||
| 43 | assertOrPanic(result + 1 == 14); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | test "switch on enum" { | ||
| 48 | const fruit = Fruit.Orange; | ||
| 49 | nonConstSwitchOnEnum(fruit); | ||
| 50 | } | ||
| 51 | const Fruit = enum { | ||
| 52 | Apple, | ||
| 53 | Orange, | ||
| 54 | Banana, | ||
| 55 | }; | ||
| 56 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 57 | switch (fruit) { | ||
| 58 | Fruit.Apple => unreachable, | ||
| 59 | Fruit.Orange => {}, | ||
| 60 | Fruit.Banana => unreachable, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | test "switch statement" { | ||
| 65 | nonConstSwitch(SwitchStatmentFoo.C); | ||
| 66 | } | ||
| 67 | fn nonConstSwitch(foo: SwitchStatmentFoo) void { | ||
| 68 | const val = switch (foo) { | ||
| 69 | SwitchStatmentFoo.A => i32(1), | ||
| 70 | SwitchStatmentFoo.B => 2, | ||
| 71 | SwitchStatmentFoo.C => 3, | ||
| 72 | SwitchStatmentFoo.D => 4, | ||
| 73 | }; | ||
| 74 | assertOrPanic(val == 3); | ||
| 75 | } | ||
| 76 | const SwitchStatmentFoo = enum { | ||
| 77 | A, | ||
| 78 | B, | ||
| 79 | C, | ||
| 80 | D, | ||
| 81 | }; | ||
| 82 | |||
| 83 | test "switch prong with variable" { | ||
| 84 | switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | ||
| 85 | switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | ||
| 86 | switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); | ||
| 87 | } | ||
| 88 | const SwitchProngWithVarEnum = union(enum) { | ||
| 89 | One: i32, | ||
| 90 | Two: f32, | ||
| 91 | Meh: void, | ||
| 92 | }; | ||
| 93 | fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { | ||
| 94 | switch (a) { | ||
| 95 | SwitchProngWithVarEnum.One => |x| { | ||
| 96 | assertOrPanic(x == 13); | ||
| 97 | }, | ||
| 98 | SwitchProngWithVarEnum.Two => |x| { | ||
| 99 | assertOrPanic(x == 13.0); | ||
| 100 | }, | ||
| 101 | SwitchProngWithVarEnum.Meh => |x| { | ||
| 102 | const v: void = x; | ||
| 103 | }, | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | test "switch on enum using pointer capture" { | ||
| 108 | testSwitchEnumPtrCapture(); | ||
| 109 | comptime testSwitchEnumPtrCapture(); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn testSwitchEnumPtrCapture() void { | ||
| 113 | var value = SwitchProngWithVarEnum{ .One = 1234 }; | ||
| 114 | switch (value) { | ||
| 115 | SwitchProngWithVarEnum.One => |*x| x.* += 1, | ||
| 116 | else => unreachable, | ||
| 117 | } | ||
| 118 | switch (value) { | ||
| 119 | SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235), | ||
| 120 | else => unreachable, | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | test "switch with multiple expressions" { | ||
| 125 | const x = switch (returnsFive()) { | ||
| 126 | 1, 2, 3 => 1, | ||
| 127 | 4, 5, 6 => 2, | ||
| 128 | else => i32(3), | ||
| 129 | }; | ||
| 130 | assertOrPanic(x == 2); | ||
| 131 | } | ||
| 132 | fn returnsFive() i32 { | ||
| 133 | return 5; | ||
| 134 | } | ||
| 135 | |||
| 136 | const Number = union(enum) { | ||
| 137 | One: u64, | ||
| 138 | Two: u8, | ||
| 139 | Three: f32, | ||
| 140 | }; | ||
| 141 | |||
| 142 | const number = Number{ .Three = 1.23 }; | ||
| 143 | |||
| 144 | fn returnsFalse() bool { | ||
| 145 | switch (number) { | ||
| 146 | Number.One => |x| return x > 1234, | ||
| 147 | Number.Two => |x| return x == 'a', | ||
| 148 | Number.Three => |x| return x > 12.34, | ||
| 149 | } | ||
| 150 | } | ||
| 151 | test "switch on const enum with var" { | ||
| 152 | assertOrPanic(!returnsFalse()); | ||
| 153 | } | ||
| 154 | |||
| 155 | test "switch on type" { | ||
| 156 | assertOrPanic(trueIfBoolFalseOtherwise(bool)); | ||
| 157 | assertOrPanic(!trueIfBoolFalseOtherwise(i32)); | ||
| 158 | } | ||
| 159 | |||
| 160 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 161 | return switch (T) { | ||
| 162 | bool => true, | ||
| 163 | else => false, | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "switch handles all cases of number" { | ||
| 168 | testSwitchHandleAllCases(); | ||
| 169 | comptime testSwitchHandleAllCases(); | ||
| 170 | } | ||
| 171 | |||
| 172 | fn testSwitchHandleAllCases() void { | ||
| 173 | assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3); | ||
| 174 | assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2); | ||
| 175 | assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1); | ||
| 176 | assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0); | ||
| 177 | |||
| 178 | assertOrPanic(testSwitchHandleAllCasesRange(100) == 0); | ||
| 179 | assertOrPanic(testSwitchHandleAllCasesRange(200) == 1); | ||
| 180 | assertOrPanic(testSwitchHandleAllCasesRange(201) == 2); | ||
| 181 | assertOrPanic(testSwitchHandleAllCasesRange(202) == 4); | ||
| 182 | assertOrPanic(testSwitchHandleAllCasesRange(230) == 3); | ||
| 183 | } | ||
| 184 | |||
| 185 | fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { | ||
| 186 | return switch (x) { | ||
| 187 | 0 => u2(3), | ||
| 188 | 1 => 2, | ||
| 189 | 2 => 1, | ||
| 190 | 3 => 0, | ||
| 191 | }; | ||
| 192 | } | ||
| 193 | |||
| 194 | fn testSwitchHandleAllCasesRange(x: u8) u8 { | ||
| 195 | return switch (x) { | ||
| 196 | 0...100 => u8(0), | ||
| 197 | 101...200 => 1, | ||
| 198 | 201, 203 => 2, | ||
| 199 | 202 => 4, | ||
| 200 | 204...255 => 3, | ||
| 201 | }; | ||
| 202 | } | ||
| 203 | |||
| 204 | test "switch all prongs unreachable" { | ||
| 205 | testAllProngsUnreachable(); | ||
| 206 | comptime testAllProngsUnreachable(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testAllProngsUnreachable() void { | ||
| 210 | assertOrPanic(switchWithUnreachable(1) == 2); | ||
| 211 | assertOrPanic(switchWithUnreachable(2) == 10); | ||
| 212 | } | ||
| 213 | |||
| 214 | fn switchWithUnreachable(x: i32) i32 { | ||
| 215 | while (true) { | ||
| 216 | switch (x) { | ||
| 217 | 1 => return 2, | ||
| 218 | 2 => break, | ||
| 219 | else => continue, | ||
| 220 | } | ||
| 221 | } | ||
| 222 | return 10; | ||
| 223 | } | ||
| 224 | |||
| 225 | fn return_a_number() anyerror!i32 { | ||
| 226 | return 1; | ||
| 227 | } | ||
| 228 | |||
| 229 | test "capture value of switch with all unreachable prongs" { | ||
| 230 | const x = return_a_number() catch |err| switch (err) { | ||
| 231 | else => unreachable, | ||
| 232 | }; | ||
| 233 | assertOrPanic(x == 1); | ||
| 234 | } | ||
| 235 | |||
| 236 | test "switching on booleans" { | ||
| 237 | testSwitchOnBools(); | ||
| 238 | comptime testSwitchOnBools(); | ||
| 239 | } | ||
| 240 | |||
| 241 | fn testSwitchOnBools() void { | ||
| 242 | assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 243 | assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 244 | |||
| 245 | assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 246 | assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 247 | |||
| 248 | assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 249 | assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 250 | } | ||
| 251 | |||
| 252 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 253 | return switch (x) { | ||
| 254 | true => false, | ||
| 255 | false => true, | ||
| 256 | }; | ||
| 257 | } | ||
| 258 | |||
| 259 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 260 | return switch (x) { | ||
| 261 | true => false, | ||
| 262 | else => true, | ||
| 263 | }; | ||
| 264 | } | ||
| 265 | |||
| 266 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 267 | return switch (x) { | ||
| 268 | false => true, | ||
| 269 | else => false, | ||
| 270 | }; | ||
| 271 | } | ||
test/stage1/behavior/switch_prong_err_enum.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | var read_count: u64 = 0; | ||
| 4 | |||
| 5 | fn readOnce() anyerror!u64 { | ||
| 6 | read_count += 1; | ||
| 7 | return read_count; | ||
| 8 | } | ||
| 9 | |||
| 10 | const FormValue = union(enum) { | ||
| 11 | Address: u64, | ||
| 12 | Other: bool, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn doThing(form_id: u64) anyerror!FormValue { | ||
| 16 | return switch (form_id) { | ||
| 17 | 17 => FormValue{ .Address = try readOnce() }, | ||
| 18 | else => error.InvalidDebugInfo, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "switch prong returns error enum" { | ||
| 23 | switch (doThing(17) catch unreachable) { | ||
| 24 | FormValue.Address => |payload| { | ||
| 25 | assertOrPanic(payload == 1); | ||
| 26 | }, | ||
| 27 | else => unreachable, | ||
| 28 | } | ||
| 29 | assertOrPanic(read_count == 1); | ||
| 30 | } | ||
test/stage1/behavior/switch_prong_implicit_cast.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const FormValue = union(enum) { | ||
| 4 | One: void, | ||
| 5 | Two: bool, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn foo(id: u64) !FormValue { | ||
| 9 | return switch (id) { | ||
| 10 | 2 => FormValue{ .Two = true }, | ||
| 11 | 1 => FormValue{ .One = {} }, | ||
| 12 | else => return error.Whatever, | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch prong implicit cast" { | ||
| 17 | const result = switch (foo(2) catch unreachable) { | ||
| 18 | FormValue.One => false, | ||
| 19 | FormValue.Two => |x| x, | ||
| 20 | }; | ||
| 21 | assertOrPanic(result); | ||
| 22 | } | ||
test/stage1/behavior/syntax.zig created+60| ... | @@ -0,0 +1,60 @@ | ||
| 1 | // Test trailing comma syntax | ||
| 2 | // zig fmt: off | ||
| 3 | |||
| 4 | const struct_trailing_comma = struct { x: i32, y: i32, }; | ||
| 5 | const struct_no_comma = struct { x: i32, y: i32 }; | ||
| 6 | const struct_fn_no_comma = struct { fn m() void {} y: i32 }; | ||
| 7 | |||
| 8 | const enum_no_comma = enum { A, B }; | ||
| 9 | |||
| 10 | fn container_init() void { | ||
| 11 | const S = struct { x: i32, y: i32 }; | ||
| 12 | _ = S { .x = 1, .y = 2 }; | ||
| 13 | _ = S { .x = 1, .y = 2, }; | ||
| 14 | } | ||
| 15 | |||
| 16 | fn type_expr_return1() if (true) A {} | ||
| 17 | fn type_expr_return2() for (true) |_| A {} | ||
| 18 | fn type_expr_return3() while (true) A {} | ||
| 19 | fn type_expr_return4() comptime A {} | ||
| 20 | |||
| 21 | fn switch_cases(x: i32) void { | ||
| 22 | switch (x) { | ||
| 23 | 1,2,3 => {}, | ||
| 24 | 4,5, => {}, | ||
| 25 | 6...8, => {}, | ||
| 26 | else => {}, | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | fn switch_prongs(x: i32) void { | ||
| 31 | switch (x) { | ||
| 32 | 0 => {}, | ||
| 33 | else => {}, | ||
| 34 | } | ||
| 35 | switch (x) { | ||
| 36 | 0 => {}, | ||
| 37 | else => {} | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | const fn_no_comma = fn(i32, i32)void; | ||
| 42 | const fn_trailing_comma = fn(i32, i32,)void; | ||
| 43 | |||
| 44 | fn fn_calls() void { | ||
| 45 | fn add(x: i32, y: i32,) i32 { x + y }; | ||
| 46 | _ = add(1, 2); | ||
| 47 | _ = add(1, 2,); | ||
| 48 | } | ||
| 49 | |||
| 50 | fn asm_lists() void { | ||
| 51 | if (false) { // Build AST but don't analyze | ||
| 52 | asm ("not real assembly" | ||
| 53 | :[a] "x" (x),); | ||
| 54 | asm ("not real assembly" | ||
| 55 | :[a] "x" (->i32),:[a] "x" (1),); | ||
| 56 | asm ("still not real assembly" | ||
| 57 | :::"a","b",); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
test/stage1/behavior/this.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const module = @This(); | ||
| 4 | |||
| 5 | fn Point(comptime T: type) type { | ||
| 6 | return struct { | ||
| 7 | const Self = @This(); | ||
| 8 | x: T, | ||
| 9 | y: T, | ||
| 10 | |||
| 11 | fn addOne(self: *Self) void { | ||
| 12 | self.x += 1; | ||
| 13 | self.y += 1; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn add(x: i32, y: i32) i32 { | ||
| 19 | return x + y; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "this refer to module call private fn" { | ||
| 23 | assertOrPanic(module.add(1, 2) == 3); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "this refer to container" { | ||
| 27 | var pt = Point(i32){ | ||
| 28 | .x = 12, | ||
| 29 | .y = 34, | ||
| 30 | }; | ||
| 31 | pt.addOne(); | ||
| 32 | assertOrPanic(pt.x == 13); | ||
| 33 | assertOrPanic(pt.y == 35); | ||
| 34 | } | ||
| 35 | |||
test/stage1/behavior/truncate.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "truncate u0 to larger integer allowed and has comptime known result" { | ||
| 5 | var x: u0 = 0; | ||
| 6 | const y = @truncate(u8, x); | ||
| 7 | comptime assertOrPanic(y == 0); | ||
| 8 | } | ||
test/stage1/behavior/try.zig created+43| ... | @@ -0,0 +1,43 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "try on error union" { | ||
| 4 | tryOnErrorUnionImpl(); | ||
| 5 | comptime tryOnErrorUnionImpl(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn tryOnErrorUnionImpl() void { | ||
| 9 | const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { | ||
| 10 | error.ItBroke, error.NoMem => 1, | ||
| 11 | error.CrappedOut => i32(2), | ||
| 12 | else => unreachable, | ||
| 13 | }; | ||
| 14 | assertOrPanic(x == 11); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn returnsTen() anyerror!i32 { | ||
| 18 | return 10; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "try without vars" { | ||
| 22 | const result1 = if (failIfTrue(true)) 1 else |_| i32(2); | ||
| 23 | assertOrPanic(result1 == 2); | ||
| 24 | |||
| 25 | const result2 = if (failIfTrue(false)) 1 else |_| i32(2); | ||
| 26 | assertOrPanic(result2 == 1); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn failIfTrue(ok: bool) anyerror!void { | ||
| 30 | if (ok) { | ||
| 31 | return error.ItBroke; | ||
| 32 | } else { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "try then not executed with assignment" { | ||
| 38 | if (failIfTrue(true)) { | ||
| 39 | unreachable; | ||
| 40 | } else |err| { | ||
| 41 | assertOrPanic(err == error.ItBroke); | ||
| 42 | } | ||
| 43 | } | ||
test/stage1/behavior/type_info.zig created+276| ... | @@ -0,0 +1,276 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const TypeInfo = @import("builtin").TypeInfo; | ||
| 4 | const TypeId = @import("builtin").TypeId; | ||
| 5 | |||
| 6 | test "type info: tag type, void info" { | ||
| 7 | testBasic(); | ||
| 8 | comptime testBasic(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testBasic() void { | ||
| 12 | assertOrPanic(@TagType(TypeInfo) == TypeId); | ||
| 13 | const void_info = @typeInfo(void); | ||
| 14 | assertOrPanic(TypeId(void_info) == TypeId.Void); | ||
| 15 | assertOrPanic(void_info.Void == {}); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "type info: integer, floating point type info" { | ||
| 19 | testIntFloat(); | ||
| 20 | comptime testIntFloat(); | ||
| 21 | } | ||
| 22 | |||
| 23 | fn testIntFloat() void { | ||
| 24 | const u8_info = @typeInfo(u8); | ||
| 25 | assertOrPanic(TypeId(u8_info) == TypeId.Int); | ||
| 26 | assertOrPanic(!u8_info.Int.is_signed); | ||
| 27 | assertOrPanic(u8_info.Int.bits == 8); | ||
| 28 | |||
| 29 | const f64_info = @typeInfo(f64); | ||
| 30 | assertOrPanic(TypeId(f64_info) == TypeId.Float); | ||
| 31 | assertOrPanic(f64_info.Float.bits == 64); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "type info: pointer type info" { | ||
| 35 | testPointer(); | ||
| 36 | comptime testPointer(); | ||
| 37 | } | ||
| 38 | |||
| 39 | fn testPointer() void { | ||
| 40 | const u32_ptr_info = @typeInfo(*u32); | ||
| 41 | assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); | ||
| 42 | assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); | ||
| 43 | assertOrPanic(u32_ptr_info.Pointer.is_const == false); | ||
| 44 | assertOrPanic(u32_ptr_info.Pointer.is_volatile == false); | ||
| 45 | assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32)); | ||
| 46 | assertOrPanic(u32_ptr_info.Pointer.child == u32); | ||
| 47 | } | ||
| 48 | |||
| 49 | test "type info: unknown length pointer type info" { | ||
| 50 | testUnknownLenPtr(); | ||
| 51 | comptime testUnknownLenPtr(); | ||
| 52 | } | ||
| 53 | |||
| 54 | fn testUnknownLenPtr() void { | ||
| 55 | const u32_ptr_info = @typeInfo([*]const volatile f64); | ||
| 56 | assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); | ||
| 57 | assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); | ||
| 58 | assertOrPanic(u32_ptr_info.Pointer.is_const == true); | ||
| 59 | assertOrPanic(u32_ptr_info.Pointer.is_volatile == true); | ||
| 60 | assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64)); | ||
| 61 | assertOrPanic(u32_ptr_info.Pointer.child == f64); | ||
| 62 | } | ||
| 63 | |||
| 64 | test "type info: slice type info" { | ||
| 65 | testSlice(); | ||
| 66 | comptime testSlice(); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn testSlice() void { | ||
| 70 | const u32_slice_info = @typeInfo([]u32); | ||
| 71 | assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer); | ||
| 72 | assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); | ||
| 73 | assertOrPanic(u32_slice_info.Pointer.is_const == false); | ||
| 74 | assertOrPanic(u32_slice_info.Pointer.is_volatile == false); | ||
| 75 | assertOrPanic(u32_slice_info.Pointer.alignment == 4); | ||
| 76 | assertOrPanic(u32_slice_info.Pointer.child == u32); | ||
| 77 | } | ||
| 78 | |||
| 79 | test "type info: array type info" { | ||
| 80 | testArray(); | ||
| 81 | comptime testArray(); | ||
| 82 | } | ||
| 83 | |||
| 84 | fn testArray() void { | ||
| 85 | const arr_info = @typeInfo([42]bool); | ||
| 86 | assertOrPanic(TypeId(arr_info) == TypeId.Array); | ||
| 87 | assertOrPanic(arr_info.Array.len == 42); | ||
| 88 | assertOrPanic(arr_info.Array.child == bool); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "type info: optional type info" { | ||
| 92 | testOptional(); | ||
| 93 | comptime testOptional(); | ||
| 94 | } | ||
| 95 | |||
| 96 | fn testOptional() void { | ||
| 97 | const null_info = @typeInfo(?void); | ||
| 98 | assertOrPanic(TypeId(null_info) == TypeId.Optional); | ||
| 99 | assertOrPanic(null_info.Optional.child == void); | ||
| 100 | } | ||
| 101 | |||
| 102 | test "type info: promise info" { | ||
| 103 | testPromise(); | ||
| 104 | comptime testPromise(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn testPromise() void { | ||
| 108 | const null_promise_info = @typeInfo(promise); | ||
| 109 | assertOrPanic(TypeId(null_promise_info) == TypeId.Promise); | ||
| 110 | assertOrPanic(null_promise_info.Promise.child == null); | ||
| 111 | |||
| 112 | const promise_info = @typeInfo(promise->usize); | ||
| 113 | assertOrPanic(TypeId(promise_info) == TypeId.Promise); | ||
| 114 | assertOrPanic(promise_info.Promise.child.? == usize); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "type info: error set, error union info" { | ||
| 118 | testErrorSet(); | ||
| 119 | comptime testErrorSet(); | ||
| 120 | } | ||
| 121 | |||
| 122 | fn testErrorSet() void { | ||
| 123 | const TestErrorSet = error{ | ||
| 124 | First, | ||
| 125 | Second, | ||
| 126 | Third, | ||
| 127 | }; | ||
| 128 | |||
| 129 | const error_set_info = @typeInfo(TestErrorSet); | ||
| 130 | assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet); | ||
| 131 | assertOrPanic(error_set_info.ErrorSet.errors.len == 3); | ||
| 132 | assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); | ||
| 133 | assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); | ||
| 134 | |||
| 135 | const error_union_info = @typeInfo(TestErrorSet!usize); | ||
| 136 | assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion); | ||
| 137 | assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet); | ||
| 138 | assertOrPanic(error_union_info.ErrorUnion.payload == usize); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "type info: enum info" { | ||
| 142 | testEnum(); | ||
| 143 | comptime testEnum(); | ||
| 144 | } | ||
| 145 | |||
| 146 | fn testEnum() void { | ||
| 147 | const Os = enum { | ||
| 148 | Windows, | ||
| 149 | Macos, | ||
| 150 | Linux, | ||
| 151 | FreeBSD, | ||
| 152 | }; | ||
| 153 | |||
| 154 | const os_info = @typeInfo(Os); | ||
| 155 | assertOrPanic(TypeId(os_info) == TypeId.Enum); | ||
| 156 | assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); | ||
| 157 | assertOrPanic(os_info.Enum.fields.len == 4); | ||
| 158 | assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); | ||
| 159 | assertOrPanic(os_info.Enum.fields[3].value == 3); | ||
| 160 | assertOrPanic(os_info.Enum.tag_type == u2); | ||
| 161 | assertOrPanic(os_info.Enum.defs.len == 0); | ||
| 162 | } | ||
| 163 | |||
| 164 | test "type info: union info" { | ||
| 165 | testUnion(); | ||
| 166 | comptime testUnion(); | ||
| 167 | } | ||
| 168 | |||
| 169 | fn testUnion() void { | ||
| 170 | const typeinfo_info = @typeInfo(TypeInfo); | ||
| 171 | assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); | ||
| 172 | assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); | ||
| 173 | assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); | ||
| 174 | assertOrPanic(typeinfo_info.Union.fields.len == 25); | ||
| 175 | assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); | ||
| 176 | assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); | ||
| 177 | assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); | ||
| 178 | assertOrPanic(typeinfo_info.Union.defs.len == 21); | ||
| 179 | |||
| 180 | const TestNoTagUnion = union { | ||
| 181 | Foo: void, | ||
| 182 | Bar: u32, | ||
| 183 | }; | ||
| 184 | |||
| 185 | const notag_union_info = @typeInfo(TestNoTagUnion); | ||
| 186 | assertOrPanic(TypeId(notag_union_info) == TypeId.Union); | ||
| 187 | assertOrPanic(notag_union_info.Union.tag_type == null); | ||
| 188 | assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); | ||
| 189 | assertOrPanic(notag_union_info.Union.fields.len == 2); | ||
| 190 | assertOrPanic(notag_union_info.Union.fields[0].enum_field == null); | ||
| 191 | assertOrPanic(notag_union_info.Union.fields[1].field_type == u32); | ||
| 192 | |||
| 193 | const TestExternUnion = extern union { | ||
| 194 | foo: *c_void, | ||
| 195 | }; | ||
| 196 | |||
| 197 | const extern_union_info = @typeInfo(TestExternUnion); | ||
| 198 | assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); | ||
| 199 | assertOrPanic(extern_union_info.Union.tag_type == null); | ||
| 200 | assertOrPanic(extern_union_info.Union.fields[0].enum_field == null); | ||
| 201 | assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void); | ||
| 202 | } | ||
| 203 | |||
| 204 | test "type info: struct info" { | ||
| 205 | testStruct(); | ||
| 206 | comptime testStruct(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testStruct() void { | ||
| 210 | const struct_info = @typeInfo(TestStruct); | ||
| 211 | assertOrPanic(TypeId(struct_info) == TypeId.Struct); | ||
| 212 | assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); | ||
| 213 | assertOrPanic(struct_info.Struct.fields.len == 3); | ||
| 214 | assertOrPanic(struct_info.Struct.fields[1].offset == null); | ||
| 215 | assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct); | ||
| 216 | assertOrPanic(struct_info.Struct.defs.len == 2); | ||
| 217 | assertOrPanic(struct_info.Struct.defs[0].is_pub); | ||
| 218 | assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern); | ||
| 219 | assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null); | ||
| 220 | assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void); | ||
| 221 | assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); | ||
| 222 | } | ||
| 223 | |||
| 224 | const TestStruct = packed struct { | ||
| 225 | const Self = @This(); | ||
| 226 | |||
| 227 | fieldA: usize, | ||
| 228 | fieldB: void, | ||
| 229 | fieldC: *Self, | ||
| 230 | |||
| 231 | pub fn foo(self: *const Self) void {} | ||
| 232 | }; | ||
| 233 | |||
| 234 | test "type info: function type info" { | ||
| 235 | testFunction(); | ||
| 236 | comptime testFunction(); | ||
| 237 | } | ||
| 238 | |||
| 239 | fn testFunction() void { | ||
| 240 | const fn_info = @typeInfo(@typeOf(foo)); | ||
| 241 | assertOrPanic(TypeId(fn_info) == TypeId.Fn); | ||
| 242 | assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); | ||
| 243 | assertOrPanic(fn_info.Fn.is_generic); | ||
| 244 | assertOrPanic(fn_info.Fn.args.len == 2); | ||
| 245 | assertOrPanic(fn_info.Fn.is_var_args); | ||
| 246 | assertOrPanic(fn_info.Fn.return_type == null); | ||
| 247 | assertOrPanic(fn_info.Fn.async_allocator_type == null); | ||
| 248 | |||
| 249 | const test_instance: TestStruct = undefined; | ||
| 250 | const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); | ||
| 251 | assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn); | ||
| 252 | assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn foo(comptime a: usize, b: bool, args: ...) usize { | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | test "typeInfo with comptime parameter in struct fn def" { | ||
| 260 | const S = struct { | ||
| 261 | pub fn func(comptime x: f32) void {} | ||
| 262 | }; | ||
| 263 | comptime var info = @typeInfo(S); | ||
| 264 | } | ||
| 265 | |||
| 266 | test "type info: vectors" { | ||
| 267 | testVector(); | ||
| 268 | comptime testVector(); | ||
| 269 | } | ||
| 270 | |||
| 271 | fn testVector() void { | ||
| 272 | const vec_info = @typeInfo(@Vector(4, i32)); | ||
| 273 | assertOrPanic(TypeId(vec_info) == TypeId.Vector); | ||
| 274 | assertOrPanic(vec_info.Vector.len == 4); | ||
| 275 | assertOrPanic(vec_info.Vector.child == i32); | ||
| 276 | } | ||
test/stage1/behavior/undefined.zig created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | fn initStaticArray() [10]i32 { | ||
| 5 | var array: [10]i32 = undefined; | ||
| 6 | array[0] = 1; | ||
| 7 | array[4] = 2; | ||
| 8 | array[7] = 3; | ||
| 9 | array[9] = 4; | ||
| 10 | return array; | ||
| 11 | } | ||
| 12 | const static_array = initStaticArray(); | ||
| 13 | test "init static array to undefined" { | ||
| 14 | assertOrPanic(static_array[0] == 1); | ||
| 15 | assertOrPanic(static_array[4] == 2); | ||
| 16 | assertOrPanic(static_array[7] == 3); | ||
| 17 | assertOrPanic(static_array[9] == 4); | ||
| 18 | |||
| 19 | comptime { | ||
| 20 | assertOrPanic(static_array[0] == 1); | ||
| 21 | assertOrPanic(static_array[4] == 2); | ||
| 22 | assertOrPanic(static_array[7] == 3); | ||
| 23 | assertOrPanic(static_array[9] == 4); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | const Foo = struct { | ||
| 28 | x: i32, | ||
| 29 | |||
| 30 | fn setFooXMethod(foo: *Foo) void { | ||
| 31 | foo.x = 3; | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | |||
| 35 | fn setFooX(foo: *Foo) void { | ||
| 36 | foo.x = 2; | ||
| 37 | } | ||
| 38 | |||
| 39 | test "assign undefined to struct" { | ||
| 40 | comptime { | ||
| 41 | var foo: Foo = undefined; | ||
| 42 | setFooX(&foo); | ||
| 43 | assertOrPanic(foo.x == 2); | ||
| 44 | } | ||
| 45 | { | ||
| 46 | var foo: Foo = undefined; | ||
| 47 | setFooX(&foo); | ||
| 48 | assertOrPanic(foo.x == 2); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | test "assign undefined to struct with method" { | ||
| 53 | comptime { | ||
| 54 | var foo: Foo = undefined; | ||
| 55 | foo.setFooXMethod(); | ||
| 56 | assertOrPanic(foo.x == 3); | ||
| 57 | } | ||
| 58 | { | ||
| 59 | var foo: Foo = undefined; | ||
| 60 | foo.setFooXMethod(); | ||
| 61 | assertOrPanic(foo.x == 3); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | test "type name of undefined" { | ||
| 66 | const x = undefined; | ||
| 67 | assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); | ||
| 68 | } | ||
| 69 | |||
test/stage1/behavior/underscore.zig created+28| ... | @@ -0,0 +1,28 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "ignore lval with underscore" { | ||
| 5 | _ = false; | ||
| 6 | } | ||
| 7 | |||
| 8 | test "ignore lval with underscore (for loop)" { | ||
| 9 | for ([]void{}) |_, i| { | ||
| 10 | for ([]void{}) |_, j| { | ||
| 11 | break; | ||
| 12 | } | ||
| 13 | break; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | test "ignore lval with underscore (while loop)" { | ||
| 18 | while (optionalReturnError()) |_| { | ||
| 19 | while (optionalReturnError()) |_| { | ||
| 20 | break; | ||
| 21 | } else |_| {} | ||
| 22 | break; | ||
| 23 | } else |_| {} | ||
| 24 | } | ||
| 25 | |||
| 26 | fn optionalReturnError() !?u32 { | ||
| 27 | return error.optionalReturnError; | ||
| 28 | } | ||
test/stage1/behavior/union.zig created+352| ... | @@ -0,0 +1,352 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const Value = union(enum) { | ||
| 4 | Int: u64, | ||
| 5 | Array: [9]u8, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Agg = struct { | ||
| 9 | val1: Value, | ||
| 10 | val2: Value, | ||
| 11 | }; | ||
| 12 | |||
| 13 | const v1 = Value{ .Int = 1234 }; | ||
| 14 | const v2 = Value{ .Array = []u8{3} ** 9 }; | ||
| 15 | |||
| 16 | const err = (anyerror!Agg)(Agg{ | ||
| 17 | .val1 = v1, | ||
| 18 | .val2 = v2, | ||
| 19 | }); | ||
| 20 | |||
| 21 | const array = []Value{ | ||
| 22 | v1, | ||
| 23 | v2, | ||
| 24 | v1, | ||
| 25 | v2, | ||
| 26 | }; | ||
| 27 | |||
| 28 | test "unions embedded in aggregate types" { | ||
| 29 | switch (array[1]) { | ||
| 30 | Value.Array => |arr| assertOrPanic(arr[4] == 3), | ||
| 31 | else => unreachable, | ||
| 32 | } | ||
| 33 | switch ((err catch unreachable).val1) { | ||
| 34 | Value.Int => |x| assertOrPanic(x == 1234), | ||
| 35 | else => unreachable, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | const Foo = union { | ||
| 40 | float: f64, | ||
| 41 | int: i32, | ||
| 42 | }; | ||
| 43 | |||
| 44 | test "basic unions" { | ||
| 45 | var foo = Foo{ .int = 1 }; | ||
| 46 | assertOrPanic(foo.int == 1); | ||
| 47 | foo = Foo{ .float = 12.34 }; | ||
| 48 | assertOrPanic(foo.float == 12.34); | ||
| 49 | } | ||
| 50 | |||
| 51 | test "comptime union field access" { | ||
| 52 | comptime { | ||
| 53 | var foo = Foo{ .int = 0 }; | ||
| 54 | assertOrPanic(foo.int == 0); | ||
| 55 | |||
| 56 | foo = Foo{ .float = 42.42 }; | ||
| 57 | assertOrPanic(foo.float == 42.42); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "init union with runtime value" { | ||
| 62 | var foo: Foo = undefined; | ||
| 63 | |||
| 64 | setFloat(&foo, 12.34); | ||
| 65 | assertOrPanic(foo.float == 12.34); | ||
| 66 | |||
| 67 | setInt(&foo, 42); | ||
| 68 | assertOrPanic(foo.int == 42); | ||
| 69 | } | ||
| 70 | |||
| 71 | fn setFloat(foo: *Foo, x: f64) void { | ||
| 72 | foo.* = Foo{ .float = x }; | ||
| 73 | } | ||
| 74 | |||
| 75 | fn setInt(foo: *Foo, x: i32) void { | ||
| 76 | foo.* = Foo{ .int = x }; | ||
| 77 | } | ||
| 78 | |||
| 79 | const FooExtern = extern union { | ||
| 80 | float: f64, | ||
| 81 | int: i32, | ||
| 82 | }; | ||
| 83 | |||
| 84 | test "basic extern unions" { | ||
| 85 | var foo = FooExtern{ .int = 1 }; | ||
| 86 | assertOrPanic(foo.int == 1); | ||
| 87 | foo.float = 12.34; | ||
| 88 | assertOrPanic(foo.float == 12.34); | ||
| 89 | } | ||
| 90 | |||
| 91 | const Letter = enum { | ||
| 92 | A, | ||
| 93 | B, | ||
| 94 | C, | ||
| 95 | }; | ||
| 96 | const Payload = union(Letter) { | ||
| 97 | A: i32, | ||
| 98 | B: f64, | ||
| 99 | C: bool, | ||
| 100 | }; | ||
| 101 | |||
| 102 | test "union with specified enum tag" { | ||
| 103 | doTest(); | ||
| 104 | comptime doTest(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn doTest() void { | ||
| 108 | assertOrPanic(bar(Payload{ .A = 1234 }) == -10); | ||
| 109 | } | ||
| 110 | |||
| 111 | fn bar(value: Payload) i32 { | ||
| 112 | assertOrPanic(Letter(value) == Letter.A); | ||
| 113 | return switch (value) { | ||
| 114 | Payload.A => |x| return x - 1244, | ||
| 115 | Payload.B => |x| if (x == 12.34) i32(20) else 21, | ||
| 116 | Payload.C => |x| if (x) i32(30) else 31, | ||
| 117 | }; | ||
| 118 | } | ||
| 119 | |||
| 120 | const MultipleChoice = union(enum(u32)) { | ||
| 121 | A = 20, | ||
| 122 | B = 40, | ||
| 123 | C = 60, | ||
| 124 | D = 1000, | ||
| 125 | }; | ||
| 126 | test "simple union(enum(u32))" { | ||
| 127 | var x = MultipleChoice.C; | ||
| 128 | assertOrPanic(x == MultipleChoice.C); | ||
| 129 | assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60); | ||
| 130 | } | ||
| 131 | |||
| 132 | const MultipleChoice2 = union(enum(u32)) { | ||
| 133 | Unspecified1: i32, | ||
| 134 | A: f32 = 20, | ||
| 135 | Unspecified2: void, | ||
| 136 | B: bool = 40, | ||
| 137 | Unspecified3: i32, | ||
| 138 | C: i8 = 60, | ||
| 139 | Unspecified4: void, | ||
| 140 | D: void = 1000, | ||
| 141 | Unspecified5: i32, | ||
| 142 | }; | ||
| 143 | |||
| 144 | test "union(enum(u32)) with specified and unspecified tag values" { | ||
| 145 | comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32); | ||
| 146 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 147 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 148 | } | ||
| 149 | |||
| 150 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | ||
| 151 | assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); | ||
| 152 | assertOrPanic(1123 == switch (x) { | ||
| 153 | MultipleChoice2.A => 1, | ||
| 154 | MultipleChoice2.B => 2, | ||
| 155 | MultipleChoice2.C => |v| i32(1000) + v, | ||
| 156 | MultipleChoice2.D => 4, | ||
| 157 | MultipleChoice2.Unspecified1 => 5, | ||
| 158 | MultipleChoice2.Unspecified2 => 6, | ||
| 159 | MultipleChoice2.Unspecified3 => 7, | ||
| 160 | MultipleChoice2.Unspecified4 => 8, | ||
| 161 | MultipleChoice2.Unspecified5 => 9, | ||
| 162 | }); | ||
| 163 | } | ||
| 164 | |||
| 165 | const ExternPtrOrInt = extern union { | ||
| 166 | ptr: *u8, | ||
| 167 | int: u64, | ||
| 168 | }; | ||
| 169 | test "extern union size" { | ||
| 170 | comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8); | ||
| 171 | } | ||
| 172 | |||
| 173 | const PackedPtrOrInt = packed union { | ||
| 174 | ptr: *u8, | ||
| 175 | int: u64, | ||
| 176 | }; | ||
| 177 | test "extern union size" { | ||
| 178 | comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8); | ||
| 179 | } | ||
| 180 | |||
| 181 | const ZeroBits = union { | ||
| 182 | OnlyField: void, | ||
| 183 | }; | ||
| 184 | test "union with only 1 field which is void should be zero bits" { | ||
| 185 | comptime assertOrPanic(@sizeOf(ZeroBits) == 0); | ||
| 186 | } | ||
| 187 | |||
| 188 | const TheTag = enum { | ||
| 189 | A, | ||
| 190 | B, | ||
| 191 | C, | ||
| 192 | }; | ||
| 193 | const TheUnion = union(TheTag) { | ||
| 194 | A: i32, | ||
| 195 | B: i32, | ||
| 196 | C: i32, | ||
| 197 | }; | ||
| 198 | test "union field access gives the enum values" { | ||
| 199 | assertOrPanic(TheUnion.A == TheTag.A); | ||
| 200 | assertOrPanic(TheUnion.B == TheTag.B); | ||
| 201 | assertOrPanic(TheUnion.C == TheTag.C); | ||
| 202 | } | ||
| 203 | |||
| 204 | test "cast union to tag type of union" { | ||
| 205 | testCastUnionToTagType(TheUnion{ .B = 1234 }); | ||
| 206 | comptime testCastUnionToTagType(TheUnion{ .B = 1234 }); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn testCastUnionToTagType(x: TheUnion) void { | ||
| 210 | assertOrPanic(TheTag(x) == TheTag.B); | ||
| 211 | } | ||
| 212 | |||
| 213 | test "cast tag type of union to union" { | ||
| 214 | var x: Value2 = Letter2.B; | ||
| 215 | assertOrPanic(Letter2(x) == Letter2.B); | ||
| 216 | } | ||
| 217 | const Letter2 = enum { | ||
| 218 | A, | ||
| 219 | B, | ||
| 220 | C, | ||
| 221 | }; | ||
| 222 | const Value2 = union(Letter2) { | ||
| 223 | A: i32, | ||
| 224 | B, | ||
| 225 | C, | ||
| 226 | }; | ||
| 227 | |||
| 228 | test "implicit cast union to its tag type" { | ||
| 229 | var x: Value2 = Letter2.B; | ||
| 230 | assertOrPanic(x == Letter2.B); | ||
| 231 | giveMeLetterB(x); | ||
| 232 | } | ||
| 233 | fn giveMeLetterB(x: Letter2) void { | ||
| 234 | assertOrPanic(x == Value2.B); | ||
| 235 | } | ||
| 236 | |||
| 237 | pub const PackThis = union(enum) { | ||
| 238 | Invalid: bool, | ||
| 239 | StringLiteral: u2, | ||
| 240 | }; | ||
| 241 | |||
| 242 | test "constant packed union" { | ||
| 243 | testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }}); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn testConstPackedUnion(expected_tokens: []const PackThis) void { | ||
| 247 | assertOrPanic(expected_tokens[0].StringLiteral == 1); | ||
| 248 | } | ||
| 249 | |||
| 250 | test "switch on union with only 1 field" { | ||
| 251 | var r: PartialInst = undefined; | ||
| 252 | r = PartialInst.Compiled; | ||
| 253 | switch (r) { | ||
| 254 | PartialInst.Compiled => { | ||
| 255 | var z: PartialInstWithPayload = undefined; | ||
| 256 | z = PartialInstWithPayload{ .Compiled = 1234 }; | ||
| 257 | switch (z) { | ||
| 258 | PartialInstWithPayload.Compiled => |x| { | ||
| 259 | assertOrPanic(x == 1234); | ||
| 260 | return; | ||
| 261 | }, | ||
| 262 | } | ||
| 263 | }, | ||
| 264 | } | ||
| 265 | unreachable; | ||
| 266 | } | ||
| 267 | |||
| 268 | const PartialInst = union(enum) { | ||
| 269 | Compiled, | ||
| 270 | }; | ||
| 271 | |||
| 272 | const PartialInstWithPayload = union(enum) { | ||
| 273 | Compiled: i32, | ||
| 274 | }; | ||
| 275 | |||
| 276 | test "access a member of tagged union with conflicting enum tag name" { | ||
| 277 | const Bar = union(enum) { | ||
| 278 | A: A, | ||
| 279 | B: B, | ||
| 280 | |||
| 281 | const A = u8; | ||
| 282 | const B = void; | ||
| 283 | }; | ||
| 284 | |||
| 285 | comptime assertOrPanic(Bar.A == u8); | ||
| 286 | } | ||
| 287 | |||
| 288 | test "tagged union initialization with runtime void" { | ||
| 289 | assertOrPanic(testTaggedUnionInit({})); | ||
| 290 | } | ||
| 291 | |||
| 292 | const TaggedUnionWithAVoid = union(enum) { | ||
| 293 | A, | ||
| 294 | B: i32, | ||
| 295 | }; | ||
| 296 | |||
| 297 | fn testTaggedUnionInit(x: var) bool { | ||
| 298 | const y = TaggedUnionWithAVoid{ .A = x }; | ||
| 299 | return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A; | ||
| 300 | } | ||
| 301 | |||
| 302 | pub const UnionEnumNoPayloads = union(enum) { | ||
| 303 | A, | ||
| 304 | B, | ||
| 305 | }; | ||
| 306 | |||
| 307 | test "tagged union with no payloads" { | ||
| 308 | const a = UnionEnumNoPayloads{ .B = {} }; | ||
| 309 | switch (a) { | ||
| 310 | @TagType(UnionEnumNoPayloads).A => @panic("wrong"), | ||
| 311 | @TagType(UnionEnumNoPayloads).B => {}, | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | test "union with only 1 field casted to its enum type" { | ||
| 316 | const Literal = union(enum) { | ||
| 317 | Number: f64, | ||
| 318 | Bool: bool, | ||
| 319 | }; | ||
| 320 | |||
| 321 | const Expr = union(enum) { | ||
| 322 | Literal: Literal, | ||
| 323 | }; | ||
| 324 | |||
| 325 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 326 | const Tag = @TagType(Expr); | ||
| 327 | comptime assertOrPanic(@TagType(Tag) == comptime_int); | ||
| 328 | var t = Tag(e); | ||
| 329 | assertOrPanic(t == Expr.Literal); | ||
| 330 | } | ||
| 331 | |||
| 332 | test "union with only 1 field casted to its enum type which has enum value specified" { | ||
| 333 | const Literal = union(enum) { | ||
| 334 | Number: f64, | ||
| 335 | Bool: bool, | ||
| 336 | }; | ||
| 337 | |||
| 338 | const Tag = enum { | ||
| 339 | Literal = 33, | ||
| 340 | }; | ||
| 341 | |||
| 342 | const Expr = union(Tag) { | ||
| 343 | Literal: Literal, | ||
| 344 | }; | ||
| 345 | |||
| 346 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 347 | comptime assertOrPanic(@TagType(Tag) == comptime_int); | ||
| 348 | var t = Tag(e); | ||
| 349 | assertOrPanic(t == Expr.Literal); | ||
| 350 | assertOrPanic(@enumToInt(t) == 33); | ||
| 351 | comptime assertOrPanic(@enumToInt(t) == 33); | ||
| 352 | } | ||
test/stage1/behavior/var_args.zig created+84| ... | @@ -0,0 +1,84 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | fn add(args: ...) i32 { | ||
| 4 | var sum = i32(0); | ||
| 5 | { | ||
| 6 | comptime var i: usize = 0; | ||
| 7 | inline while (i < args.len) : (i += 1) { | ||
| 8 | sum += args[i]; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | return sum; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "add arbitrary args" { | ||
| 15 | assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10); | ||
| 16 | assertOrPanic(add(i32(1234)) == 1234); | ||
| 17 | assertOrPanic(add() == 0); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn readFirstVarArg(args: ...) void { | ||
| 21 | const value = args[0]; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "send void arg to var args" { | ||
| 25 | readFirstVarArg({}); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "pass args directly" { | ||
| 29 | assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); | ||
| 30 | assertOrPanic(addSomeStuff(i32(1234)) == 1234); | ||
| 31 | assertOrPanic(addSomeStuff() == 0); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn addSomeStuff(args: ...) i32 { | ||
| 35 | return add(args); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "runtime parameter before var args" { | ||
| 39 | assertOrPanic(extraFn(10) == 0); | ||
| 40 | assertOrPanic(extraFn(10, false) == 1); | ||
| 41 | assertOrPanic(extraFn(10, false, true) == 2); | ||
| 42 | |||
| 43 | // TODO issue #313 | ||
| 44 | //comptime { | ||
| 45 | // assertOrPanic(extraFn(10) == 0); | ||
| 46 | // assertOrPanic(extraFn(10, false) == 1); | ||
| 47 | // assertOrPanic(extraFn(10, false, true) == 2); | ||
| 48 | //} | ||
| 49 | } | ||
| 50 | |||
| 51 | fn extraFn(extra: u32, args: ...) usize { | ||
| 52 | if (args.len >= 1) { | ||
| 53 | assertOrPanic(args[0] == false); | ||
| 54 | } | ||
| 55 | if (args.len >= 2) { | ||
| 56 | assertOrPanic(args[1] == true); | ||
| 57 | } | ||
| 58 | return args.len; | ||
| 59 | } | ||
| 60 | |||
| 61 | const foos = []fn (...) bool{ | ||
| 62 | foo1, | ||
| 63 | foo2, | ||
| 64 | }; | ||
| 65 | |||
| 66 | fn foo1(args: ...) bool { | ||
| 67 | return true; | ||
| 68 | } | ||
| 69 | fn foo2(args: ...) bool { | ||
| 70 | return false; | ||
| 71 | } | ||
| 72 | |||
| 73 | test "array of var args functions" { | ||
| 74 | assertOrPanic(foos[0]()); | ||
| 75 | assertOrPanic(!foos[1]()); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "pass zero length array to var args param" { | ||
| 79 | doNothingWithFirstArg(""); | ||
| 80 | } | ||
| 81 | |||
| 82 | fn doNothingWithFirstArg(args: ...) void { | ||
| 83 | const a = args[0]; | ||
| 84 | } | ||
test/stage1/behavior/vector.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | test "implicit array to vector and vector to array" { | ||
| 5 | const S = struct { | ||
| 6 | fn doTheTest() void { | ||
| 7 | var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40}; | ||
| 8 | const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4}; | ||
| 9 | v +%= x; | ||
| 10 | const result: [4]i32 = v; | ||
| 11 | assertOrPanic(result[0] == 11); | ||
| 12 | assertOrPanic(result[1] == 22); | ||
| 13 | assertOrPanic(result[2] == 33); | ||
| 14 | assertOrPanic(result[3] == 44); | ||
| 15 | } | ||
| 16 | }; | ||
| 17 | S.doTheTest(); | ||
| 18 | comptime S.doTheTest(); | ||
| 19 | } | ||
| 20 | |||
test/stage1/behavior/void.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: void, | ||
| 5 | b: i32, | ||
| 6 | c: void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "compare void with void compile time known" { | ||
| 10 | comptime { | ||
| 11 | const foo = Foo{ | ||
| 12 | .a = {}, | ||
| 13 | .b = 1, | ||
| 14 | .c = {}, | ||
| 15 | }; | ||
| 16 | assertOrPanic(foo.a == {}); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "iterate over a void slice" { | ||
| 21 | var j: usize = 0; | ||
| 22 | for (times(10)) |_, i| { | ||
| 23 | assertOrPanic(i == j); | ||
| 24 | j += 1; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | fn times(n: usize) []const void { | ||
| 29 | return ([*]void)(undefined)[0..n]; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "void optional" { | ||
| 33 | var x: ?void = {}; | ||
| 34 | assertOrPanic(x != null); | ||
| 35 | } | ||
test/stage1/behavior/while.zig created+228| ... | @@ -0,0 +1,228 @@ | ||
| 1 | const assertOrPanic = @import("std").debug.assertOrPanic; | ||
| 2 | |||
| 3 | test "while loop" { | ||
| 4 | var i: i32 = 0; | ||
| 5 | while (i < 4) { | ||
| 6 | i += 1; | ||
| 7 | } | ||
| 8 | assertOrPanic(i == 4); | ||
| 9 | assertOrPanic(whileLoop1() == 1); | ||
| 10 | } | ||
| 11 | fn whileLoop1() i32 { | ||
| 12 | return whileLoop2(); | ||
| 13 | } | ||
| 14 | fn whileLoop2() i32 { | ||
| 15 | while (true) { | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "static eval while" { | ||
| 21 | assertOrPanic(static_eval_while_number == 1); | ||
| 22 | } | ||
| 23 | const static_eval_while_number = staticWhileLoop1(); | ||
| 24 | fn staticWhileLoop1() i32 { | ||
| 25 | return whileLoop2(); | ||
| 26 | } | ||
| 27 | fn staticWhileLoop2() i32 { | ||
| 28 | while (true) { | ||
| 29 | return 1; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | test "continue and break" { | ||
| 34 | runContinueAndBreakTest(); | ||
| 35 | assertOrPanic(continue_and_break_counter == 8); | ||
| 36 | } | ||
| 37 | var continue_and_break_counter: i32 = 0; | ||
| 38 | fn runContinueAndBreakTest() void { | ||
| 39 | var i: i32 = 0; | ||
| 40 | while (true) { | ||
| 41 | continue_and_break_counter += 2; | ||
| 42 | i += 1; | ||
| 43 | if (i < 4) { | ||
| 44 | continue; | ||
| 45 | } | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | assertOrPanic(i == 4); | ||
| 49 | } | ||
| 50 | |||
| 51 | test "return with implicit cast from while loop" { | ||
| 52 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | ||
| 53 | } | ||
| 54 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | ||
| 55 | while (true) { | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | test "while with continue expression" { | ||
| 61 | var sum: i32 = 0; | ||
| 62 | { | ||
| 63 | var i: i32 = 0; | ||
| 64 | while (i < 10) : (i += 1) { | ||
| 65 | if (i == 5) continue; | ||
| 66 | sum += i; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | assertOrPanic(sum == 40); | ||
| 70 | } | ||
| 71 | |||
| 72 | test "while with else" { | ||
| 73 | var sum: i32 = 0; | ||
| 74 | var i: i32 = 0; | ||
| 75 | var got_else: i32 = 0; | ||
| 76 | while (i < 10) : (i += 1) { | ||
| 77 | sum += 1; | ||
| 78 | } else { | ||
| 79 | got_else += 1; | ||
| 80 | } | ||
| 81 | assertOrPanic(sum == 10); | ||
| 82 | assertOrPanic(got_else == 1); | ||
| 83 | } | ||
| 84 | |||
| 85 | test "while with optional as condition" { | ||
| 86 | numbers_left = 10; | ||
| 87 | var sum: i32 = 0; | ||
| 88 | while (getNumberOrNull()) |value| { | ||
| 89 | sum += value; | ||
| 90 | } | ||
| 91 | assertOrPanic(sum == 45); | ||
| 92 | } | ||
| 93 | |||
| 94 | test "while with optional as condition with else" { | ||
| 95 | numbers_left = 10; | ||
| 96 | var sum: i32 = 0; | ||
| 97 | var got_else: i32 = 0; | ||
| 98 | while (getNumberOrNull()) |value| { | ||
| 99 | sum += value; | ||
| 100 | assertOrPanic(got_else == 0); | ||
| 101 | } else { | ||
| 102 | got_else += 1; | ||
| 103 | } | ||
| 104 | assertOrPanic(sum == 45); | ||
| 105 | assertOrPanic(got_else == 1); | ||
| 106 | } | ||
| 107 | |||
| 108 | test "while with error union condition" { | ||
| 109 | numbers_left = 10; | ||
| 110 | var sum: i32 = 0; | ||
| 111 | var got_else: i32 = 0; | ||
| 112 | while (getNumberOrErr()) |value| { | ||
| 113 | sum += value; | ||
| 114 | } else |err| { | ||
| 115 | assertOrPanic(err == error.OutOfNumbers); | ||
| 116 | got_else += 1; | ||
| 117 | } | ||
| 118 | assertOrPanic(sum == 45); | ||
| 119 | assertOrPanic(got_else == 1); | ||
| 120 | } | ||
| 121 | |||
| 122 | var numbers_left: i32 = undefined; | ||
| 123 | fn getNumberOrErr() anyerror!i32 { | ||
| 124 | return if (numbers_left == 0) error.OutOfNumbers else x: { | ||
| 125 | numbers_left -= 1; | ||
| 126 | break :x numbers_left; | ||
| 127 | }; | ||
| 128 | } | ||
| 129 | fn getNumberOrNull() ?i32 { | ||
| 130 | return if (numbers_left == 0) null else x: { | ||
| 131 | numbers_left -= 1; | ||
| 132 | break :x numbers_left; | ||
| 133 | }; | ||
| 134 | } | ||
| 135 | |||
| 136 | test "while on optional with else result follow else prong" { | ||
| 137 | const result = while (returnNull()) |value| { | ||
| 138 | break value; | ||
| 139 | } else | ||
| 140 | i32(2); | ||
| 141 | assertOrPanic(result == 2); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "while on optional with else result follow break prong" { | ||
| 145 | const result = while (returnOptional(10)) |value| { | ||
| 146 | break value; | ||
| 147 | } else | ||
| 148 | i32(2); | ||
| 149 | assertOrPanic(result == 10); | ||
| 150 | } | ||
| 151 | |||
| 152 | test "while on error union with else result follow else prong" { | ||
| 153 | const result = while (returnError()) |value| { | ||
| 154 | break value; | ||
| 155 | } else |err| | ||
| 156 | i32(2); | ||
| 157 | assertOrPanic(result == 2); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "while on error union with else result follow break prong" { | ||
| 161 | const result = while (returnSuccess(10)) |value| { | ||
| 162 | break value; | ||
| 163 | } else |err| | ||
| 164 | i32(2); | ||
| 165 | assertOrPanic(result == 10); | ||
| 166 | } | ||
| 167 | |||
| 168 | test "while on bool with else result follow else prong" { | ||
| 169 | const result = while (returnFalse()) { | ||
| 170 | break i32(10); | ||
| 171 | } else | ||
| 172 | i32(2); | ||
| 173 | assertOrPanic(result == 2); | ||
| 174 | } | ||
| 175 | |||
| 176 | test "while on bool with else result follow break prong" { | ||
| 177 | const result = while (returnTrue()) { | ||
| 178 | break i32(10); | ||
| 179 | } else | ||
| 180 | i32(2); | ||
| 181 | assertOrPanic(result == 10); | ||
| 182 | } | ||
| 183 | |||
| 184 | test "break from outer while loop" { | ||
| 185 | testBreakOuter(); | ||
| 186 | comptime testBreakOuter(); | ||
| 187 | } | ||
| 188 | |||
| 189 | fn testBreakOuter() void { | ||
| 190 | outer: while (true) { | ||
| 191 | while (true) { | ||
| 192 | break :outer; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | test "continue outer while loop" { | ||
| 198 | testContinueOuter(); | ||
| 199 | comptime testContinueOuter(); | ||
| 200 | } | ||
| 201 | |||
| 202 | fn testContinueOuter() void { | ||
| 203 | var i: usize = 0; | ||
| 204 | outer: while (i < 10) : (i += 1) { | ||
| 205 | while (true) { | ||
| 206 | continue :outer; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | fn returnNull() ?i32 { | ||
| 212 | return null; | ||
| 213 | } | ||
| 214 | fn returnOptional(x: i32) ?i32 { | ||
| 215 | return x; | ||
| 216 | } | ||
| 217 | fn returnError() anyerror!i32 { | ||
| 218 | return error.YouWantedAnError; | ||
| 219 | } | ||
| 220 | fn returnSuccess(x: i32) anyerror!i32 { | ||
| 221 | return x; | ||
| 222 | } | ||
| 223 | fn returnFalse() bool { | ||
| 224 | return false; | ||
| 225 | } | ||
| 226 | fn returnTrue() bool { | ||
| 227 | return true; | ||
| 228 | } | ||
test/stage1/behavior/widening.zig created+28| ... | @@ -0,0 +1,28 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "integer widening" { | ||
| 6 | var a: u8 = 250; | ||
| 7 | var b: u16 = a; | ||
| 8 | var c: u32 = b; | ||
| 9 | var d: u64 = c; | ||
| 10 | var e: u64 = d; | ||
| 11 | var f: u128 = e; | ||
| 12 | assertOrPanic(f == a); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "implicit unsigned integer to signed integer" { | ||
| 16 | var a: u8 = 250; | ||
| 17 | var b: i16 = a; | ||
| 18 | assertOrPanic(b == 250); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "float widening" { | ||
| 22 | var a: f16 = 12.34; | ||
| 23 | var b: f32 = a; | ||
| 24 | var c: f64 = b; | ||
| 25 | var d: f128 = c; | ||
| 26 | assertOrPanic(d == a); | ||
| 27 | } | ||
| 28 | |||
test/tests.zig+70-48| ... | @@ -48,13 +48,14 @@ const test_targets = []TestTarget{ | ... | @@ -48,13 +48,14 @@ const test_targets = []TestTarget{ |
| 48 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB | 48 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
| 49 | 49 | ||
| 50 | pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | 50 | pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 51 | const cases = b.allocator.create(CompareOutputContext{ | 51 | const cases = b.allocator.create(CompareOutputContext) catch unreachable; |
| 52 | cases.* = CompareOutputContext{ | ||
| 52 | .b = b, | 53 | .b = b, |
| 53 | .step = b.step("test-compare-output", "Run the compare output tests"), | 54 | .step = b.step("test-compare-output", "Run the compare output tests"), |
| 54 | .test_index = 0, | 55 | .test_index = 0, |
| 55 | .test_filter = test_filter, | 56 | .test_filter = test_filter, |
| 56 | .modes = modes, | 57 | .modes = modes, |
| 57 | }) catch unreachable; | 58 | }; |
| 58 | 59 | ||
| 59 | compare_output.addCases(cases); | 60 | compare_output.addCases(cases); |
| 60 | 61 | ||
| ... | @@ -62,13 +63,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: | ... | @@ -62,13 +63,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | 65 | pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 65 | const cases = b.allocator.create(CompareOutputContext{ | 66 | const cases = b.allocator.create(CompareOutputContext) catch unreachable; |
| 67 | cases.* = CompareOutputContext{ | ||
| 66 | .b = b, | 68 | .b = b, |
| 67 | .step = b.step("test-runtime-safety", "Run the runtime safety tests"), | 69 | .step = b.step("test-runtime-safety", "Run the runtime safety tests"), |
| 68 | .test_index = 0, | 70 | .test_index = 0, |
| 69 | .test_filter = test_filter, | 71 | .test_filter = test_filter, |
| 70 | .modes = modes, | 72 | .modes = modes, |
| 71 | }) catch unreachable; | 73 | }; |
| 72 | 74 | ||
| 73 | runtime_safety.addCases(cases); | 75 | runtime_safety.addCases(cases); |
| 74 | 76 | ||
| ... | @@ -76,13 +78,14 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: | ... | @@ -76,13 +78,14 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | 80 | pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 79 | const cases = b.allocator.create(CompileErrorContext{ | 81 | const cases = b.allocator.create(CompileErrorContext) catch unreachable; |
| 82 | cases.* = CompileErrorContext{ | ||
| 80 | .b = b, | 83 | .b = b, |
| 81 | .step = b.step("test-compile-errors", "Run the compile error tests"), | 84 | .step = b.step("test-compile-errors", "Run the compile error tests"), |
| 82 | .test_index = 0, | 85 | .test_index = 0, |
| 83 | .test_filter = test_filter, | 86 | .test_filter = test_filter, |
| 84 | .modes = modes, | 87 | .modes = modes, |
| 85 | }) catch unreachable; | 88 | }; |
| 86 | 89 | ||
| 87 | compile_errors.addCases(cases); | 90 | compile_errors.addCases(cases); |
| 88 | 91 | ||
| ... | @@ -90,13 +93,14 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: | ... | @@ -90,13 +93,14 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 90 | } | 93 | } |
| 91 | 94 | ||
| 92 | pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | 95 | pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 93 | const cases = b.allocator.create(BuildExamplesContext{ | 96 | const cases = b.allocator.create(BuildExamplesContext) catch unreachable; |
| 97 | cases.* = BuildExamplesContext{ | ||
| 94 | .b = b, | 98 | .b = b, |
| 95 | .step = b.step("test-build-examples", "Build the examples"), | 99 | .step = b.step("test-build-examples", "Build the examples"), |
| 96 | .test_index = 0, | 100 | .test_index = 0, |
| 97 | .test_filter = test_filter, | 101 | .test_filter = test_filter, |
| 98 | .modes = modes, | 102 | .modes = modes, |
| 99 | }) catch unreachable; | 103 | }; |
| 100 | 104 | ||
| 101 | build_examples.addCases(cases); | 105 | build_examples.addCases(cases); |
| 102 | 106 | ||
| ... | @@ -119,13 +123,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M | ... | @@ -119,13 +123,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M |
| 119 | } | 123 | } |
| 120 | 124 | ||
| 121 | pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | 125 | pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 122 | const cases = b.allocator.create(CompareOutputContext{ | 126 | const cases = b.allocator.create(CompareOutputContext) catch unreachable; |
| 127 | cases.* = CompareOutputContext{ | ||
| 123 | .b = b, | 128 | .b = b, |
| 124 | .step = b.step("test-asm-link", "Run the assemble and link tests"), | 129 | .step = b.step("test-asm-link", "Run the assemble and link tests"), |
| 125 | .test_index = 0, | 130 | .test_index = 0, |
| 126 | .test_filter = test_filter, | 131 | .test_filter = test_filter, |
| 127 | .modes = modes, | 132 | .modes = modes, |
| 128 | }) catch unreachable; | 133 | }; |
| 129 | 134 | ||
| 130 | assemble_and_link.addCases(cases); | 135 | assemble_and_link.addCases(cases); |
| 131 | 136 | ||
| ... | @@ -133,12 +138,13 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, mode | ... | @@ -133,12 +138,13 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, mode |
| 133 | } | 138 | } |
| 134 | 139 | ||
| 135 | pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { | 140 | pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { |
| 136 | const cases = b.allocator.create(TranslateCContext{ | 141 | const cases = b.allocator.create(TranslateCContext) catch unreachable; |
| 142 | cases.* = TranslateCContext{ | ||
| 137 | .b = b, | 143 | .b = b, |
| 138 | .step = b.step("test-translate-c", "Run the C transation tests"), | 144 | .step = b.step("test-translate-c", "Run the C transation tests"), |
| 139 | .test_index = 0, | 145 | .test_index = 0, |
| 140 | .test_filter = test_filter, | 146 | .test_filter = test_filter, |
| 141 | }) catch unreachable; | 147 | }; |
| 142 | 148 | ||
| 143 | translate_c.addCases(cases); | 149 | translate_c.addCases(cases); |
| 144 | 150 | ||
| ... | @@ -146,12 +152,13 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St | ... | @@ -146,12 +152,13 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St |
| 146 | } | 152 | } |
| 147 | 153 | ||
| 148 | pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { | 154 | pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { |
| 149 | const cases = b.allocator.create(GenHContext{ | 155 | const cases = b.allocator.create(GenHContext) catch unreachable; |
| 156 | cases.* = GenHContext{ | ||
| 150 | .b = b, | 157 | .b = b, |
| 151 | .step = b.step("test-gen-h", "Run the C header file generation tests"), | 158 | .step = b.step("test-gen-h", "Run the C header file generation tests"), |
| 152 | .test_index = 0, | 159 | .test_index = 0, |
| 153 | .test_filter = test_filter, | 160 | .test_filter = test_filter, |
| 154 | }) catch unreachable; | 161 | }; |
| 155 | 162 | ||
| 156 | gen_h.addCases(cases); | 163 | gen_h.addCases(cases); |
| 157 | 164 | ||
| ... | @@ -163,25 +170,32 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons | ... | @@ -163,25 +170,32 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons |
| 163 | for (test_targets) |test_target| { | 170 | for (test_targets) |test_target| { |
| 164 | const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch); | 171 | const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch); |
| 165 | for (modes) |mode| { | 172 | for (modes) |mode| { |
| 166 | for ([]bool{ | 173 | for ([]bool{ false, true }) |link_libc| { |
| 167 | false, | 174 | for ([]bool{ false, true }) |single_threaded| { |
| 168 | true, | 175 | if (link_libc and !is_native) { |
| 169 | }) |link_libc| { | 176 | // don't assume we have a cross-compiling libc set up |
| 170 | if (link_libc and !is_native) { | 177 | continue; |
| 171 | // don't assume we have a cross-compiling libc set up | 178 | } |
| 172 | continue; | 179 | const these_tests = b.addTest(root_src); |
| 173 | } | 180 | these_tests.setNamePrefix(b.fmt( |
| 174 | const these_tests = b.addTest(root_src); | 181 | "{}-{}-{}-{}-{}-{} ", |
| 175 | these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare")); | 182 | name, |
| 176 | these_tests.setFilter(test_filter); | 183 | @tagName(test_target.os), |
| 177 | these_tests.setBuildMode(mode); | 184 | @tagName(test_target.arch), |
| 178 | if (!is_native) { | 185 | @tagName(mode), |
| 179 | these_tests.setTarget(test_target.arch, test_target.os, test_target.environ); | 186 | if (link_libc) "c" else "bare", |
| 180 | } | 187 | if (single_threaded) "single" else "multi", |
| 181 | if (link_libc) { | 188 | )); |
| 182 | these_tests.linkSystemLibrary("c"); | 189 | these_tests.setFilter(test_filter); |
| 190 | these_tests.setBuildMode(mode); | ||
| 191 | if (!is_native) { | ||
| 192 | these_tests.setTarget(test_target.arch, test_target.os, test_target.environ); | ||
| 193 | } | ||
| 194 | if (link_libc) { | ||
| 195 | these_tests.linkSystemLibrary("c"); | ||
| 196 | } | ||
| 197 | step.dependOn(&these_tests.step); | ||
| 183 | } | 198 | } |
| 184 | step.dependOn(&these_tests.step); | ||
| 185 | } | 199 | } |
| 186 | } | 200 | } |
| 187 | } | 201 | } |
| ... | @@ -237,7 +251,8 @@ pub const CompareOutputContext = struct { | ... | @@ -237,7 +251,8 @@ pub const CompareOutputContext = struct { |
| 237 | 251 | ||
| 238 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep { | 252 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep { |
| 239 | const allocator = context.b.allocator; | 253 | const allocator = context.b.allocator; |
| 240 | const ptr = allocator.create(RunCompareOutputStep{ | 254 | const ptr = allocator.create(RunCompareOutputStep) catch unreachable; |
| 255 | ptr.* = RunCompareOutputStep{ | ||
| 241 | .context = context, | 256 | .context = context, |
| 242 | .exe_path = exe_path, | 257 | .exe_path = exe_path, |
| 243 | .name = name, | 258 | .name = name, |
| ... | @@ -245,7 +260,7 @@ pub const CompareOutputContext = struct { | ... | @@ -245,7 +260,7 @@ pub const CompareOutputContext = struct { |
| 245 | .test_index = context.test_index, | 260 | .test_index = context.test_index, |
| 246 | .step = build.Step.init("RunCompareOutput", allocator, make), | 261 | .step = build.Step.init("RunCompareOutput", allocator, make), |
| 247 | .cli_args = cli_args, | 262 | .cli_args = cli_args, |
| 248 | }) catch unreachable; | 263 | }; |
| 249 | context.test_index += 1; | 264 | context.test_index += 1; |
| 250 | return ptr; | 265 | return ptr; |
| 251 | } | 266 | } |
| ... | @@ -324,13 +339,14 @@ pub const CompareOutputContext = struct { | ... | @@ -324,13 +339,14 @@ pub const CompareOutputContext = struct { |
| 324 | 339 | ||
| 325 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep { | 340 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep { |
| 326 | const allocator = context.b.allocator; | 341 | const allocator = context.b.allocator; |
| 327 | const ptr = allocator.create(RuntimeSafetyRunStep{ | 342 | const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable; |
| 343 | ptr.* = RuntimeSafetyRunStep{ | ||
| 328 | .context = context, | 344 | .context = context, |
| 329 | .exe_path = exe_path, | 345 | .exe_path = exe_path, |
| 330 | .name = name, | 346 | .name = name, |
| 331 | .test_index = context.test_index, | 347 | .test_index = context.test_index, |
| 332 | .step = build.Step.init("RuntimeSafetyRun", allocator, make), | 348 | .step = build.Step.init("RuntimeSafetyRun", allocator, make), |
| 333 | }) catch unreachable; | 349 | }; |
| 334 | 350 | ||
| 335 | context.test_index += 1; | 351 | context.test_index += 1; |
| 336 | return ptr; | 352 | return ptr; |
| ... | @@ -535,14 +551,15 @@ pub const CompileErrorContext = struct { | ... | @@ -535,14 +551,15 @@ pub const CompileErrorContext = struct { |
| 535 | 551 | ||
| 536 | pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep { | 552 | pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep { |
| 537 | const allocator = context.b.allocator; | 553 | const allocator = context.b.allocator; |
| 538 | const ptr = allocator.create(CompileCmpOutputStep{ | 554 | const ptr = allocator.create(CompileCmpOutputStep) catch unreachable; |
| 555 | ptr.* = CompileCmpOutputStep{ | ||
| 539 | .step = build.Step.init("CompileCmpOutput", allocator, make), | 556 | .step = build.Step.init("CompileCmpOutput", allocator, make), |
| 540 | .context = context, | 557 | .context = context, |
| 541 | .name = name, | 558 | .name = name, |
| 542 | .test_index = context.test_index, | 559 | .test_index = context.test_index, |
| 543 | .case = case, | 560 | .case = case, |
| 544 | .build_mode = build_mode, | 561 | .build_mode = build_mode, |
| 545 | }) catch unreachable; | 562 | }; |
| 546 | 563 | ||
| 547 | context.test_index += 1; | 564 | context.test_index += 1; |
| 548 | return ptr; | 565 | return ptr; |
| ... | @@ -654,13 +671,14 @@ pub const CompileErrorContext = struct { | ... | @@ -654,13 +671,14 @@ pub const CompileErrorContext = struct { |
| 654 | } | 671 | } |
| 655 | 672 | ||
| 656 | pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { | 673 | pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { |
| 657 | const tc = self.b.allocator.create(TestCase{ | 674 | const tc = self.b.allocator.create(TestCase) catch unreachable; |
| 675 | tc.* = TestCase{ | ||
| 658 | .name = name, | 676 | .name = name, |
| 659 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), | 677 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 660 | .expected_errors = ArrayList([]const u8).init(self.b.allocator), | 678 | .expected_errors = ArrayList([]const u8).init(self.b.allocator), |
| 661 | .link_libc = false, | 679 | .link_libc = false, |
| 662 | .is_exe = false, | 680 | .is_exe = false, |
| 663 | }) catch unreachable; | 681 | }; |
| 664 | 682 | ||
| 665 | tc.addSourceFile(".tmp_source.zig", source); | 683 | tc.addSourceFile(".tmp_source.zig", source); |
| 666 | comptime var arg_i = 0; | 684 | comptime var arg_i = 0; |
| ... | @@ -814,13 +832,14 @@ pub const TranslateCContext = struct { | ... | @@ -814,13 +832,14 @@ pub const TranslateCContext = struct { |
| 814 | 832 | ||
| 815 | pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep { | 833 | pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep { |
| 816 | const allocator = context.b.allocator; | 834 | const allocator = context.b.allocator; |
| 817 | const ptr = allocator.create(TranslateCCmpOutputStep{ | 835 | const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable; |
| 836 | ptr.* = TranslateCCmpOutputStep{ | ||
| 818 | .step = build.Step.init("ParseCCmpOutput", allocator, make), | 837 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 819 | .context = context, | 838 | .context = context, |
| 820 | .name = name, | 839 | .name = name, |
| 821 | .test_index = context.test_index, | 840 | .test_index = context.test_index, |
| 822 | .case = case, | 841 | .case = case, |
| 823 | }) catch unreachable; | 842 | }; |
| 824 | 843 | ||
| 825 | context.test_index += 1; | 844 | context.test_index += 1; |
| 826 | return ptr; | 845 | return ptr; |
| ... | @@ -921,12 +940,13 @@ pub const TranslateCContext = struct { | ... | @@ -921,12 +940,13 @@ pub const TranslateCContext = struct { |
| 921 | } | 940 | } |
| 922 | 941 | ||
| 923 | pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { | 942 | pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { |
| 924 | const tc = self.b.allocator.create(TestCase{ | 943 | const tc = self.b.allocator.create(TestCase) catch unreachable; |
| 944 | tc.* = TestCase{ | ||
| 925 | .name = name, | 945 | .name = name, |
| 926 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), | 946 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 927 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), | 947 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), |
| 928 | .allow_warnings = allow_warnings, | 948 | .allow_warnings = allow_warnings, |
| 929 | }) catch unreachable; | 949 | }; |
| 930 | 950 | ||
| 931 | tc.addSourceFile(filename, source); | 951 | tc.addSourceFile(filename, source); |
| 932 | comptime var arg_i = 0; | 952 | comptime var arg_i = 0; |
| ... | @@ -1008,14 +1028,15 @@ pub const GenHContext = struct { | ... | @@ -1008,14 +1028,15 @@ pub const GenHContext = struct { |
| 1008 | 1028 | ||
| 1009 | pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep { | 1029 | pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep { |
| 1010 | const allocator = context.b.allocator; | 1030 | const allocator = context.b.allocator; |
| 1011 | const ptr = allocator.create(GenHCmpOutputStep{ | 1031 | const ptr = allocator.create(GenHCmpOutputStep) catch unreachable; |
| 1032 | ptr.* = GenHCmpOutputStep{ | ||
| 1012 | .step = build.Step.init("ParseCCmpOutput", allocator, make), | 1033 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 1013 | .context = context, | 1034 | .context = context, |
| 1014 | .h_path = h_path, | 1035 | .h_path = h_path, |
| 1015 | .name = name, | 1036 | .name = name, |
| 1016 | .test_index = context.test_index, | 1037 | .test_index = context.test_index, |
| 1017 | .case = case, | 1038 | .case = case, |
| 1018 | }) catch unreachable; | 1039 | }; |
| 1019 | 1040 | ||
| 1020 | context.test_index += 1; | 1041 | context.test_index += 1; |
| 1021 | return ptr; | 1042 | return ptr; |
| ... | @@ -1055,11 +1076,12 @@ pub const GenHContext = struct { | ... | @@ -1055,11 +1076,12 @@ pub const GenHContext = struct { |
| 1055 | } | 1076 | } |
| 1056 | 1077 | ||
| 1057 | pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { | 1078 | pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { |
| 1058 | const tc = self.b.allocator.create(TestCase{ | 1079 | const tc = self.b.allocator.create(TestCase) catch unreachable; |
| 1080 | tc.* = TestCase{ | ||
| 1059 | .name = name, | 1081 | .name = name, |
| 1060 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), | 1082 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 1061 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), | 1083 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), |
| 1062 | }) catch unreachable; | 1084 | }; |
| 1063 | 1085 | ||
| 1064 | tc.addSourceFile(filename, source); | 1086 | tc.addSourceFile(filename, source); |
| 1065 | comptime var arg_i = 0; | 1087 | comptime var arg_i = 0; |