| author | |
| committer | |
| log | f32f7a937fa7150aaba450b1282bba9f01918807 |
| tree | ecb462e15546a50b2e948b8f2907872dd39a2dc6 |
| parent | 1411df4e2705e677003e6e5b5cbe1ca30bf637d7 |
| parent | 8c6fa982cd0a02775264b616c37da9907cc603bb |
| signature | Commit is signed but in an unrecognized format. |
234 files changed, 13794 insertions(+), 10517 deletions(-)
.builds/freebsd.yml+8-8| ... | ... | @@ -12,28 +12,28 @@ tasks: |
| 12 | 12 | ninja install |
| 13 | 13 | - test: | |
| 14 | 14 | cd zig/build |
| 15 | bin/zig test ../test/behavior.zig | |
| 15 | bin/zig test ../test/stage1/behavior.zig | |
| 16 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 37 | bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c |
| 38 | 38 | # TODO enable all tests |
| 39 | 39 | #bin/zig build --build-file ../build.zig test |
CMakeLists.txt+16-15| ... | ... | @@ -454,10 +454,10 @@ set(ZIG_STD_FILES |
| 454 | 454 | "crypto/hmac.zig" |
| 455 | 455 | "crypto/index.zig" |
| 456 | 456 | "crypto/md5.zig" |
| 457 | "crypto/poly1305.zig" | |
| 457 | 458 | "crypto/sha1.zig" |
| 458 | 459 | "crypto/sha2.zig" |
| 459 | 460 | "crypto/sha3.zig" |
| 460 | "crypto/poly1305.zig" | |
| 461 | 461 | "crypto/x25519.zig" |
| 462 | 462 | "cstr.zig" |
| 463 | 463 | "debug/failing_allocator.zig" |
| ... | ... | @@ -566,9 +566,9 @@ set(ZIG_STD_FILES |
| 566 | 566 | "math/tan.zig" |
| 567 | 567 | "math/tanh.zig" |
| 568 | 568 | "math/trunc.zig" |
| 569 | "mem.zig" | |
| 569 | 570 | "meta/index.zig" |
| 570 | 571 | "meta/trait.zig" |
| 571 | "mem.zig" | |
| 572 | 572 | "mutex.zig" |
| 573 | 573 | "net.zig" |
| 574 | 574 | "os/child_process.zig" |
| ... | ... | @@ -576,16 +576,16 @@ set(ZIG_STD_FILES |
| 576 | 576 | "os/darwin/errno.zig" |
| 577 | 577 | "os/epoch.zig" |
| 578 | 578 | "os/file.zig" |
| 579 | "os/freebsd/errno.zig" | |
| 580 | "os/freebsd/index.zig" | |
| 579 | 581 | "os/get_app_data_dir.zig" |
| 580 | 582 | "os/get_user_id.zig" |
| 581 | 583 | "os/index.zig" |
| 584 | "os/linux/arm64.zig" | |
| 582 | 585 | "os/linux/errno.zig" |
| 583 | 586 | "os/linux/index.zig" |
| 584 | 587 | "os/linux/vdso.zig" |
| 585 | 588 | "os/linux/x86_64.zig" |
| 586 | "os/linux/arm64.zig" | |
| 587 | "os/freebsd/errno.zig" | |
| 588 | "os/freebsd/index.zig" | |
| 589 | 589 | "os/path.zig" |
| 590 | 590 | "os/time.zig" |
| 591 | 591 | "os/uefi.zig" |
| ... | ... | @@ -612,6 +612,16 @@ set(ZIG_STD_FILES |
| 612 | 612 | "special/compiler_rt/comparetf2.zig" |
| 613 | 613 | "special/compiler_rt/divti3.zig" |
| 614 | 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 | 625 | "special/compiler_rt/fixuint.zig" |
| 616 | 626 | "special/compiler_rt/fixunsdfdi.zig" |
| 617 | 627 | "special/compiler_rt/fixunsdfsi.zig" |
| ... | ... | @@ -622,16 +632,6 @@ set(ZIG_STD_FILES |
| 622 | 632 | "special/compiler_rt/fixunstfdi.zig" |
| 623 | 633 | "special/compiler_rt/fixunstfsi.zig" |
| 624 | 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 | 635 | "special/compiler_rt/floattidf.zig" |
| 636 | 636 | "special/compiler_rt/floattisf.zig" |
| 637 | 637 | "special/compiler_rt/floattitf.zig" |
| ... | ... | @@ -656,6 +656,7 @@ set(ZIG_STD_FILES |
| 656 | 656 | "special/panic.zig" |
| 657 | 657 | "special/test_runner.zig" |
| 658 | 658 | "spinlock.zig" |
| 659 | "statically_initialized_mutex.zig" | |
| 659 | 660 | "unicode.zig" |
| 660 | 661 | "zig/ast.zig" |
| 661 | 662 | "zig/index.zig" |
build.zig+10-11| ... | ... | @@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void { |
| 104 | 104 | } |
| 105 | 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 | 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 | 189 | const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" }); |
| 190 | 190 | |
| 191 | 191 | var result = LibraryDep{ |
| 192 | .prefix = mem.split(prefix_output, " \r\n").next().?, | |
| 192 | .prefix = mem.tokenize(prefix_output, " \r\n").next().?, | |
| 193 | 193 | .libs = ArrayList([]const u8).init(b.allocator), |
| 194 | 194 | .system_libs = ArrayList([]const u8).init(b.allocator), |
| 195 | 195 | .includes = ArrayList([]const u8).init(b.allocator), |
| 196 | 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 | 200 | while (it.next()) |lib_arg| { |
| 201 | 201 | if (mem.startsWith(u8, lib_arg, "-l")) { |
| 202 | 202 | try result.system_libs.append(lib_arg[2..]); |
| ... | ... | @@ -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 | 214 | while (it.next()) |include_arg| { |
| 215 | 215 | if (mem.startsWith(u8, include_arg, "-I")) { |
| 216 | 216 | try result.includes.append(include_arg[2..]); |
| ... | ... | @@ -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 | 224 | while (it.next()) |libdir| { |
| 225 | 225 | if (mem.startsWith(u8, libdir, "-L")) { |
| 226 | 226 | try result.libdirs.append(libdir[2..]); |
| ... | ... | @@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | 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 | 237 | while (it.next()) |stdlib_file| { |
| 238 | 238 | const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable; |
| 239 | 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 | 242 | } |
| 243 | 243 | |
| 244 | 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 | 246 | while (it.next()) |c_header_file| { |
| 247 | 247 | const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable; |
| 248 | 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 | 277 | addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp"); |
| 278 | 278 | if (ctx.lld_include_dir.len != 0) { |
| 279 | 279 | exe.addIncludeDir(ctx.lld_include_dir); |
| 280 | var it = mem.split(ctx.lld_libraries, ";"); | |
| 280 | var it = mem.tokenize(ctx.lld_libraries, ";"); | |
| 281 | 281 | while (it.next()) |lib| { |
| 282 | 282 | exe.addObjectFile(lib); |
| 283 | 283 | } |
| ... | ... | @@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 299 | 299 | } else if (exe.target.isFreeBSD()) { |
| 300 | 300 | try addCxxKnownPath(b, ctx, exe, "libc++.a", null); |
| 301 | 301 | exe.linkSystemLibrary("pthread"); |
| 302 | } | |
| 303 | else if (exe.target.isDarwin()) { | |
| 302 | } else if (exe.target.isDarwin()) { | |
| 304 | 303 | if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { |
| 305 | 304 | // Compiler is GCC. |
| 306 | 305 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); |
| ... | ... | @@ -335,7 +334,7 @@ fn addCxxKnownPath( |
| 335 | 334 | ctx.cxx_compiler, |
| 336 | 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 | 338 | if (mem.eql(u8, path_unpadded, objname)) { |
| 340 | 339 | if (errtxt) |msg| { |
| 341 | 340 | warn("{}", msg); |
doc/langref.html.in+60-6| ... | ... | @@ -1531,6 +1531,29 @@ test "array initialization with function calls" { |
| 1531 | 1531 | {#code_end#} |
| 1532 | 1532 | {#see_also|for|Slices#} |
| 1533 | 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 | 1557 | {#header_open|Pointers#} |
| 1535 | 1558 | <p> |
| 1536 | 1559 | Zig has two kinds of pointers: |
| ... | ... | @@ -4327,7 +4350,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 { |
| 4327 | 4350 | <p> |
| 4328 | 4351 | For example, if we were to introduce another function to the above snippet: |
| 4329 | 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 | 4354 | fn max(comptime T: type, a: T, b: T) T { |
| 4332 | 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 | 5928 | This function is a low level intrinsic with no safety mechanisms. Most code |
| 5906 | 5929 | should not use this function, instead using something like this: |
| 5907 | 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 | 5932 | <p> |
| 5910 | 5933 | The optimizer is intelligent enough to turn the above snippet into a memcpy. |
| 5911 | 5934 | </p> |
| 5912 | 5935 | <p>There is also a standard library function for this:</p> |
| 5913 | 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 | 5938 | {#header_close#} |
| 5916 | 5939 | |
| 5917 | 5940 | {#header_open|@memset#} |
| ... | ... | @@ -5923,7 +5946,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre> |
| 5923 | 5946 | This function is a low level intrinsic with no safety mechanisms. Most |
| 5924 | 5947 | code should not use this function, instead using something like this: |
| 5925 | 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 | 5950 | <p> |
| 5928 | 5951 | The optimizer is intelligent enough to turn the above snippet into a memset. |
| 5929 | 5952 | </p> |
| ... | ... | @@ -6592,9 +6615,10 @@ pub const TypeInfo = union(TypeId) { |
| 6592 | 6615 | {#header_close#} |
| 6593 | 6616 | |
| 6594 | 6617 | {#header_open|@typeName#} |
| 6595 | <pre>{#syntax#}@typeName(T: type) []u8{#endsyntax#}</pre> | |
| 6618 | <pre>{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}</pre> | |
| 6596 | 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 | 6622 | </p> |
| 6599 | 6623 | |
| 6600 | 6624 | {#header_close#} |
| ... | ... | @@ -6606,6 +6630,17 @@ pub const TypeInfo = union(TypeId) { |
| 6606 | 6630 | expression passed as an argument. The expression is evaluated. |
| 6607 | 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 | 6644 | {#header_close#} |
| 6610 | 6645 | {#header_close#} |
| 6611 | 6646 | |
| ... | ... | @@ -6679,6 +6714,25 @@ pub fn build(b: *Builder) void { |
| 6679 | 6714 | {#header_close#} |
| 6680 | 6715 | {#see_also|Compile Variables|Zig Build System|Undefined Behavior#} |
| 6681 | 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 | 6736 | {#header_open|Undefined Behavior#} |
| 6683 | 6737 | <p> |
| 6684 | 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 | 83 | const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; |
| 84 | 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 | 88 | .next = undefined, |
| 88 | 89 | .data = context_ref, |
| 89 | }); | |
| 90 | }; | |
| 90 | 91 | errdefer self.loop.allocator.destroy(node); |
| 91 | 92 | |
| 92 | 93 | return LlvmHandle{ .node = node }; |
| ... | ... | @@ -596,7 +597,8 @@ pub const Compilation = struct { |
| 596 | 597 | } |
| 597 | 598 | |
| 598 | 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 | 602 | .base = Type{ |
| 601 | 603 | .name = "type", |
| 602 | 604 | .base = Value{ |
| ... | ... | @@ -608,12 +610,13 @@ pub const Compilation = struct { |
| 608 | 610 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 609 | 611 | }, |
| 610 | 612 | .value = undefined, |
| 611 | }); | |
| 613 | }; | |
| 612 | 614 | comp.meta_type.value = &comp.meta_type.base; |
| 613 | 615 | comp.meta_type.base.base.typ = &comp.meta_type.base; |
| 614 | 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 | 620 | .base = Type{ |
| 618 | 621 | .name = "void", |
| 619 | 622 | .base = Value{ |
| ... | ... | @@ -624,10 +627,11 @@ pub const Compilation = struct { |
| 624 | 627 | .id = builtin.TypeId.Void, |
| 625 | 628 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 626 | 629 | }, |
| 627 | }); | |
| 630 | }; | |
| 628 | 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 | 635 | .base = Type{ |
| 632 | 636 | .name = "noreturn", |
| 633 | 637 | .base = Value{ |
| ... | ... | @@ -638,10 +642,11 @@ pub const Compilation = struct { |
| 638 | 642 | .id = builtin.TypeId.NoReturn, |
| 639 | 643 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 640 | 644 | }, |
| 641 | }); | |
| 645 | }; | |
| 642 | 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 | 650 | .base = Type{ |
| 646 | 651 | .name = "comptime_int", |
| 647 | 652 | .base = Value{ |
| ... | ... | @@ -652,10 +657,11 @@ pub const Compilation = struct { |
| 652 | 657 | .id = builtin.TypeId.ComptimeInt, |
| 653 | 658 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 654 | 659 | }, |
| 655 | }); | |
| 660 | }; | |
| 656 | 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 | 665 | .base = Type{ |
| 660 | 666 | .name = "bool", |
| 661 | 667 | .base = Value{ |
| ... | ... | @@ -666,45 +672,50 @@ pub const Compilation = struct { |
| 666 | 672 | .id = builtin.TypeId.Bool, |
| 667 | 673 | .abi_alignment = Type.AbiAlignment.init(comp.loop), |
| 668 | 674 | }, |
| 669 | }); | |
| 675 | }; | |
| 670 | 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 | 680 | .base = Value{ |
| 674 | 681 | .id = Value.Id.Void, |
| 675 | 682 | .typ = &Type.Void.get(comp).base, |
| 676 | 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 | 689 | .base = Value{ |
| 682 | 690 | .id = Value.Id.Bool, |
| 683 | 691 | .typ = &Type.Bool.get(comp).base, |
| 684 | 692 | .ref_count = std.atomic.Int(usize).init(1), |
| 685 | 693 | }, |
| 686 | 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 | 699 | .base = Value{ |
| 691 | 700 | .id = Value.Id.Bool, |
| 692 | 701 | .typ = &Type.Bool.get(comp).base, |
| 693 | 702 | .ref_count = std.atomic.Int(usize).init(1), |
| 694 | 703 | }, |
| 695 | 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 | 709 | .base = Value{ |
| 700 | 710 | .id = Value.Id.NoReturn, |
| 701 | 711 | .typ = &Type.NoReturn.get(comp).base, |
| 702 | 712 | .ref_count = std.atomic.Int(usize).init(1), |
| 703 | 713 | }, |
| 704 | }); | |
| 714 | }; | |
| 705 | 715 | |
| 706 | 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 | 719 | .base = Type{ |
| 709 | 720 | .name = cint.zig_name, |
| 710 | 721 | .base = Value{ |
| ... | ... | @@ -720,11 +731,12 @@ pub const Compilation = struct { |
| 720 | 731 | .bit_count = comp.target.cIntTypeSizeInBits(cint.id), |
| 721 | 732 | }, |
| 722 | 733 | .garbage_node = undefined, |
| 723 | }); | |
| 734 | }; | |
| 724 | 735 | comp.c_int_types[i] = c_int_type; |
| 725 | 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 | 740 | .base = Type{ |
| 729 | 741 | .name = "u8", |
| 730 | 742 | .base = Value{ |
| ... | ... | @@ -740,7 +752,7 @@ pub const Compilation = struct { |
| 740 | 752 | .bit_count = 8, |
| 741 | 753 | }, |
| 742 | 754 | .garbage_node = undefined, |
| 743 | }); | |
| 755 | }; | |
| 744 | 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 | 841 | }; |
| 830 | 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 | 845 | tree.* = try std.zig.parse(self.gpa(), source_code); |
| 834 | 846 | errdefer { |
| 835 | 847 | tree.deinit(); |
| ... | ... | @@ -925,7 +937,8 @@ pub const Compilation = struct { |
| 925 | 937 | } |
| 926 | 938 | } else { |
| 927 | 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 | 942 | .base = Decl{ |
| 930 | 943 | .id = Decl.Id.Fn, |
| 931 | 944 | .name = name, |
| ... | ... | @@ -936,7 +949,7 @@ pub const Compilation = struct { |
| 936 | 949 | }, |
| 937 | 950 | .value = Decl.Fn.Val{ .Unresolved = {} }, |
| 938 | 951 | .fn_proto = fn_proto, |
| 939 | }); | |
| 952 | }; | |
| 940 | 953 | tree_scope.base.ref(); |
| 941 | 954 | errdefer self.gpa().destroy(fn_decl); |
| 942 | 955 | |
| ... | ... | @@ -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 | 1158 | .name = name, |
| 1145 | 1159 | .path = null, |
| 1146 | 1160 | .provided_explicitly = provided_explicitly, |
| 1147 | 1161 | .symbols = ArrayList([]u8).init(self.gpa()), |
| 1148 | }); | |
| 1162 | }; | |
| 1149 | 1163 | try self.link_libs_list.append(link_lib); |
| 1150 | 1164 | if (is_libc) { |
| 1151 | 1165 | self.libc_link_lib = link_lib; |
src-self-hosted/errmsg.zig+12-8| ... | ... | @@ -118,7 +118,8 @@ pub const Msg = struct { |
| 118 | 118 | const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); |
| 119 | 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 | 123 | .text = text, |
| 123 | 124 | .realpath = realpath, |
| 124 | 125 | .data = Data{ |
| ... | ... | @@ -128,7 +129,7 @@ pub const Msg = struct { |
| 128 | 129 | .span = span, |
| 129 | 130 | }, |
| 130 | 131 | }, |
| 131 | }); | |
| 132 | }; | |
| 132 | 133 | tree_scope.base.ref(); |
| 133 | 134 | return msg; |
| 134 | 135 | } |
| ... | ... | @@ -139,13 +140,14 @@ pub const Msg = struct { |
| 139 | 140 | const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath); |
| 140 | 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 | 145 | .text = text, |
| 144 | 146 | .realpath = realpath_copy, |
| 145 | 147 | .data = Data{ |
| 146 | 148 | .Cli = Cli{ .allocator = comp.gpa() }, |
| 147 | 149 | }, |
| 148 | }); | |
| 150 | }; | |
| 149 | 151 | return msg; |
| 150 | 152 | } |
| 151 | 153 | |
| ... | ... | @@ -164,7 +166,8 @@ pub const Msg = struct { |
| 164 | 166 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; |
| 165 | 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 | 171 | .text = undefined, |
| 169 | 172 | .realpath = realpath_copy, |
| 170 | 173 | .data = Data{ |
| ... | ... | @@ -177,7 +180,7 @@ pub const Msg = struct { |
| 177 | 180 | }, |
| 178 | 181 | }, |
| 179 | 182 | }, |
| 180 | }); | |
| 183 | }; | |
| 181 | 184 | tree_scope.base.ref(); |
| 182 | 185 | msg.text = text_buf.toOwnedSlice(); |
| 183 | 186 | return msg; |
| ... | ... | @@ -203,7 +206,8 @@ pub const Msg = struct { |
| 203 | 206 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; |
| 204 | 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 | 211 | .text = undefined, |
| 208 | 212 | .realpath = realpath_copy, |
| 209 | 213 | .data = Data{ |
| ... | ... | @@ -216,7 +220,7 @@ pub const Msg = struct { |
| 216 | 220 | }, |
| 217 | 221 | }, |
| 218 | 222 | }, |
| 219 | }); | |
| 223 | }; | |
| 220 | 224 | msg.text = text_buf.toOwnedSlice(); |
| 221 | 225 | errdefer allocator.destroy(msg); |
| 222 | 226 |
src-self-hosted/ir.zig+9-6| ... | ... | @@ -1021,12 +1021,13 @@ pub const Builder = struct { |
| 1021 | 1021 | pub const Error = Analyze.Error; |
| 1022 | 1022 | |
| 1023 | 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 | 1026 | .basic_block_list = undefined, |
| 1026 | 1027 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| 1027 | 1028 | .return_type = null, |
| 1028 | 1029 | .tree_scope = tree_scope, |
| 1029 | }); | |
| 1030 | }; | |
| 1030 | 1031 | code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); |
| 1031 | 1032 | errdefer code.destroy(comp.gpa()); |
| 1032 | 1033 | |
| ... | ... | @@ -1052,7 +1053,8 @@ pub const Builder = struct { |
| 1052 | 1053 | |
| 1053 | 1054 | /// No need to clean up resources thanks to the arena allocator. |
| 1054 | 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 | 1058 | .ref_count = 0, |
| 1057 | 1059 | .name_hint = name_hint, |
| 1058 | 1060 | .debug_id = self.next_debug_id, |
| ... | ... | @@ -1063,7 +1065,7 @@ pub const Builder = struct { |
| 1063 | 1065 | .ref_instruction = null, |
| 1064 | 1066 | .llvm_block = undefined, |
| 1065 | 1067 | .llvm_exit_block = undefined, |
| 1066 | }); | |
| 1068 | }; | |
| 1067 | 1069 | self.next_debug_id += 1; |
| 1068 | 1070 | return basic_block; |
| 1069 | 1071 | } |
| ... | ... | @@ -1774,7 +1776,8 @@ pub const Builder = struct { |
| 1774 | 1776 | params: I.Params, |
| 1775 | 1777 | is_generated: bool, |
| 1776 | 1778 | ) !*Inst { |
| 1777 | const inst = try self.arena().create(I{ | |
| 1779 | const inst = try self.arena().create(I); | |
| 1780 | inst.* = I{ | |
| 1778 | 1781 | .base = Inst{ |
| 1779 | 1782 | .id = Inst.typeToId(I), |
| 1780 | 1783 | .is_generated = is_generated, |
| ... | ... | @@ -1793,7 +1796,7 @@ pub const Builder = struct { |
| 1793 | 1796 | .owner_bb = self.current_basic_block, |
| 1794 | 1797 | }, |
| 1795 | 1798 | .params = params, |
| 1796 | }); | |
| 1799 | }; | |
| 1797 | 1800 | |
| 1798 | 1801 | // Look at the params and ref() other instructions |
| 1799 | 1802 | comptime var i = 0; |
src-self-hosted/libc_installation.zig+4-4| ... | ... | @@ -57,10 +57,10 @@ pub const LibCInstallation = struct { |
| 57 | 57 | const contents = try std.io.readFileAlloc(allocator, libc_file); |
| 58 | 58 | defer allocator.free(contents); |
| 59 | 59 | |
| 60 | var it = std.mem.split(contents, "\n"); | |
| 60 | var it = std.mem.tokenize(contents, "\n"); | |
| 61 | 61 | while (it.next()) |line| { |
| 62 | 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 | 64 | const name = line_it.next() orelse { |
| 65 | 65 | try stderr.print("missing equal sign after field name\n"); |
| 66 | 66 | return error.ParseError; |
| ... | ... | @@ -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 | 217 | var search_paths = std.ArrayList([]const u8).init(loop.allocator); |
| 218 | 218 | defer search_paths.deinit(); |
| 219 | 219 | while (it.next()) |line| { |
| ... | ... | @@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo |
| 410 | 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 | 414 | const line = it.next() orelse return error.LibCRuntimeNotFound; |
| 415 | 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 | 351 | const root_name = if (provided_name) |n| n else blk: { |
| 352 | 352 | if (root_source_file) |file| { |
| 353 | 353 | const basename = os.path.basename(file); |
| 354 | var it = mem.split(basename, "."); | |
| 354 | var it = mem.separate(basename, "."); | |
| 355 | 355 | break :blk it.next() orelse basename; |
| 356 | 356 | } else { |
| 357 | 357 | try stderr.write("--name [name] not provided and unable to infer\n"); |
| ... | ... | @@ -944,12 +944,13 @@ const CliPkg = struct { |
| 944 | 944 | parent: ?*CliPkg, |
| 945 | 945 | |
| 946 | 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 | 949 | .name = name, |
| 949 | 950 | .path = path, |
| 950 | 951 | .children = ArrayList(*CliPkg).init(allocator), |
| 951 | 952 | .parent = parent, |
| 952 | }); | |
| 953 | }; | |
| 953 | 954 | return pkg; |
| 954 | 955 | } |
| 955 | 956 |
src-self-hosted/package.zig+4-2| ... | ... | @@ -15,11 +15,13 @@ pub const Package = struct { |
| 15 | 15 | /// makes internal copies of root_src_dir and root_src_path |
| 16 | 16 | /// allocator should be an arena allocator because Package never frees anything |
| 17 | 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 | 20 | .root_src_dir = try Buffer.init(allocator, root_src_dir), |
| 20 | 21 | .root_src_path = try Buffer.init(allocator, root_src_path), |
| 21 | 22 | .table = Table.init(allocator), |
| 22 | }); | |
| 23 | }; | |
| 24 | return ptr; | |
| 23 | 25 | } |
| 24 | 26 | |
| 25 | 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 | 120 | /// Creates a Root scope with 1 reference |
| 121 | 121 | /// Takes ownership of realpath |
| 122 | 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 | 124 | self.* = Root{ |
| 125 | 125 | .base = Scope{ |
| 126 | 126 | .id = Id.Root, |
| ... | ... | @@ -150,7 +150,7 @@ pub const Scope = struct { |
| 150 | 150 | /// Creates a scope with 1 reference |
| 151 | 151 | /// Takes ownership of tree, will deinit and destroy when done. |
| 152 | 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 | 154 | self.* = AstTree{ |
| 155 | 155 | .base = undefined, |
| 156 | 156 | .tree = tree, |
| ... | ... | @@ -182,7 +182,7 @@ pub const Scope = struct { |
| 182 | 182 | |
| 183 | 183 | /// Creates a Decls scope with 1 reference |
| 184 | 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 | 186 | self.* = Decls{ |
| 187 | 187 | .base = undefined, |
| 188 | 188 | .table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())), |
| ... | ... | @@ -235,7 +235,7 @@ pub const Scope = struct { |
| 235 | 235 | |
| 236 | 236 | /// Creates a Block scope with 1 reference |
| 237 | 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 | 239 | self.* = Block{ |
| 240 | 240 | .base = undefined, |
| 241 | 241 | .incoming_values = undefined, |
| ... | ... | @@ -262,7 +262,7 @@ pub const Scope = struct { |
| 262 | 262 | /// Creates a FnDef scope with 1 reference |
| 263 | 263 | /// Must set the fn_val later |
| 264 | 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 | 266 | self.* = FnDef{ |
| 267 | 267 | .base = undefined, |
| 268 | 268 | .fn_val = null, |
| ... | ... | @@ -281,7 +281,7 @@ pub const Scope = struct { |
| 281 | 281 | |
| 282 | 282 | /// Creates a CompTime scope with 1 reference |
| 283 | 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 | 285 | self.* = CompTime{ .base = undefined }; |
| 286 | 286 | self.base.init(Id.CompTime, parent); |
| 287 | 287 | return self; |
| ... | ... | @@ -309,7 +309,7 @@ pub const Scope = struct { |
| 309 | 309 | kind: Kind, |
| 310 | 310 | defer_expr_scope: *DeferExpr, |
| 311 | 311 | ) !*Defer { |
| 312 | const self = try comp.gpa().createOne(Defer); | |
| 312 | const self = try comp.gpa().create(Defer); | |
| 313 | 313 | self.* = Defer{ |
| 314 | 314 | .base = undefined, |
| 315 | 315 | .defer_expr_scope = defer_expr_scope, |
| ... | ... | @@ -333,7 +333,7 @@ pub const Scope = struct { |
| 333 | 333 | |
| 334 | 334 | /// Creates a DeferExpr scope with 1 reference |
| 335 | 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 | 337 | self.* = DeferExpr{ |
| 338 | 338 | .base = undefined, |
| 339 | 339 | .expr_node = expr_node, |
| ... | ... | @@ -398,7 +398,7 @@ pub const Scope = struct { |
| 398 | 398 | } |
| 399 | 399 | |
| 400 | 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 | 402 | self.* = Var{ |
| 403 | 403 | .base = undefined, |
| 404 | 404 | .name = name, |
src-self-hosted/type.zig+26-7| ... | ... | @@ -44,6 +44,7 @@ pub const Type = struct { |
| 44 | 44 | Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp), |
| 45 | 45 | Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp), |
| 46 | 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 | 78 | Id.ArgTuple => unreachable, |
| 78 | 79 | Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context), |
| 79 | 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 | 105 | Id.Enum, |
| 104 | 106 | Id.Fn, |
| 105 | 107 | Id.Promise, |
| 108 | Id.Vector, | |
| 106 | 109 | => return false, |
| 107 | 110 | |
| 108 | 111 | Id.Struct => @panic("TODO"), |
| ... | ... | @@ -135,6 +138,7 @@ pub const Type = struct { |
| 135 | 138 | Id.Float, |
| 136 | 139 | Id.Fn, |
| 137 | 140 | Id.Promise, |
| 141 | Id.Vector, | |
| 138 | 142 | => return true, |
| 139 | 143 | |
| 140 | 144 | Id.Pointer => { |
| ... | ... | @@ -409,7 +413,7 @@ pub const Type = struct { |
| 409 | 413 | key.ref(); |
| 410 | 414 | errdefer key.deref(comp); |
| 411 | 415 | |
| 412 | const self = try comp.gpa().createOne(Fn); | |
| 416 | const self = try comp.gpa().create(Fn); | |
| 413 | 417 | self.* = Fn{ |
| 414 | 418 | .base = undefined, |
| 415 | 419 | .key = key, |
| ... | ... | @@ -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 | 620 | .base = undefined, |
| 616 | 621 | .key = key, |
| 617 | 622 | .garbage_node = undefined, |
| 618 | }); | |
| 623 | }; | |
| 619 | 624 | errdefer comp.gpa().destroy(self); |
| 620 | 625 | |
| 621 | 626 | const u_or_i = "ui"[@boolToInt(key.is_signed)]; |
| ... | ... | @@ -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 | 787 | .base = undefined, |
| 782 | 788 | .key = normal_key, |
| 783 | 789 | .garbage_node = undefined, |
| 784 | }); | |
| 790 | }; | |
| 785 | 791 | errdefer comp.gpa().destroy(self); |
| 786 | 792 | |
| 787 | 793 | const size_str = switch (self.key.size) { |
| ... | ... | @@ -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 | 886 | .base = undefined, |
| 880 | 887 | .key = key, |
| 881 | 888 | .garbage_node = undefined, |
| 882 | }); | |
| 889 | }; | |
| 883 | 890 | errdefer comp.gpa().destroy(self); |
| 884 | 891 | |
| 885 | 892 | const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name); |
| ... | ... | @@ -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 | 924 | pub const ComptimeFloat = struct { |
| 906 | 925 | base: Type, |
| 907 | 926 |
src-self-hosted/value.zig+21-14| ... | ... | @@ -135,14 +135,15 @@ pub const Value = struct { |
| 135 | 135 | symbol_name: Buffer, |
| 136 | 136 | |
| 137 | 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 | 140 | .base = Value{ |
| 140 | 141 | .id = Value.Id.FnProto, |
| 141 | 142 | .typ = &fn_type.base, |
| 142 | 143 | .ref_count = std.atomic.Int(usize).init(1), |
| 143 | 144 | }, |
| 144 | 145 | .symbol_name = symbol_name, |
| 145 | }); | |
| 146 | }; | |
| 146 | 147 | fn_type.base.base.ref(); |
| 147 | 148 | return self; |
| 148 | 149 | } |
| ... | ... | @@ -190,14 +191,16 @@ pub const Value = struct { |
| 190 | 191 | /// Creates a Fn value with 1 ref |
| 191 | 192 | /// Takes ownership of symbol_name |
| 192 | 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 | 196 | .data = null, |
| 195 | 197 | .next = undefined, |
| 196 | 198 | .prev = undefined, |
| 197 | }); | |
| 199 | }; | |
| 198 | 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 | 204 | .base = Value{ |
| 202 | 205 | .id = Value.Id.Fn, |
| 203 | 206 | .typ = &fn_type.base, |
| ... | ... | @@ -209,7 +212,7 @@ pub const Value = struct { |
| 209 | 212 | .symbol_name = symbol_name, |
| 210 | 213 | .containing_object = Buffer.initNull(comp.gpa()), |
| 211 | 214 | .link_set_node = link_set_node, |
| 212 | }); | |
| 215 | }; | |
| 213 | 216 | fn_type.base.base.ref(); |
| 214 | 217 | fndef_scope.fn_val = self; |
| 215 | 218 | fndef_scope.base.ref(); |
| ... | ... | @@ -353,7 +356,8 @@ pub const Value = struct { |
| 353 | 356 | var ptr_type_consumed = false; |
| 354 | 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 | 361 | .base = Value{ |
| 358 | 362 | .id = Value.Id.Ptr, |
| 359 | 363 | .typ = &ptr_type.base, |
| ... | ... | @@ -366,7 +370,7 @@ pub const Value = struct { |
| 366 | 370 | }, |
| 367 | 371 | }, |
| 368 | 372 | .mut = Mut.CompTimeConst, |
| 369 | }); | |
| 373 | }; | |
| 370 | 374 | ptr_type_consumed = true; |
| 371 | 375 | errdefer comp.gpa().destroy(self); |
| 372 | 376 | |
| ... | ... | @@ -430,14 +434,15 @@ pub const Value = struct { |
| 430 | 434 | }) catch unreachable); |
| 431 | 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 | 439 | .base = Value{ |
| 435 | 440 | .id = Value.Id.Array, |
| 436 | 441 | .typ = &array_type.base, |
| 437 | 442 | .ref_count = std.atomic.Int(usize).init(1), |
| 438 | 443 | }, |
| 439 | 444 | .special = Special{ .OwnedBuffer = buffer }, |
| 440 | }); | |
| 445 | }; | |
| 441 | 446 | errdefer comp.gpa().destroy(self); |
| 442 | 447 | |
| 443 | 448 | return self; |
| ... | ... | @@ -509,14 +514,15 @@ pub const Value = struct { |
| 509 | 514 | big_int: std.math.big.Int, |
| 510 | 515 | |
| 511 | 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 | 519 | .base = Value{ |
| 514 | 520 | .id = Value.Id.Int, |
| 515 | 521 | .typ = typ, |
| 516 | 522 | .ref_count = std.atomic.Int(usize).init(1), |
| 517 | 523 | }, |
| 518 | 524 | .big_int = undefined, |
| 519 | }); | |
| 525 | }; | |
| 520 | 526 | typ.base.ref(); |
| 521 | 527 | errdefer comp.gpa().destroy(self); |
| 522 | 528 | |
| ... | ... | @@ -557,14 +563,15 @@ pub const Value = struct { |
| 557 | 563 | old.base.typ.base.ref(); |
| 558 | 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 | 568 | .base = Value{ |
| 562 | 569 | .id = Value.Id.Int, |
| 563 | 570 | .typ = old.base.typ, |
| 564 | 571 | .ref_count = std.atomic.Int(usize).init(1), |
| 565 | 572 | }, |
| 566 | 573 | .big_int = undefined, |
| 567 | }); | |
| 574 | }; | |
| 568 | 575 | errdefer comp.gpa().destroy(new); |
| 569 | 576 | |
| 570 | 577 | new.big_int = try old.big_int.clone(); |
src/all_types.hpp+152-50| ... | ... | @@ -56,9 +56,6 @@ struct IrExecutable { |
| 56 | 56 | size_t next_debug_id; |
| 57 | 57 | size_t *backward_branch_count; |
| 58 | 58 | size_t backward_branch_quota; |
| 59 | bool invalid; | |
| 60 | bool is_inline; | |
| 61 | bool is_generic_instantiation; | |
| 62 | 59 | ZigFn *fn_entry; |
| 63 | 60 | Buf *c_import_buf; |
| 64 | 61 | AstNode *source_node; |
| ... | ... | @@ -78,6 +75,10 @@ struct IrExecutable { |
| 78 | 75 | IrBasicBlock *coro_suspend_block; |
| 79 | 76 | IrBasicBlock *coro_final_cleanup_block; |
| 80 | 77 | ZigVar *coro_allocator_var; |
| 78 | ||
| 79 | bool invalid; | |
| 80 | bool is_inline; | |
| 81 | bool is_generic_instantiation; | |
| 81 | 82 | }; |
| 82 | 83 | |
| 83 | 84 | enum OutType { |
| ... | ... | @@ -90,6 +91,9 @@ enum OutType { |
| 90 | 91 | enum ConstParentId { |
| 91 | 92 | ConstParentIdNone, |
| 92 | 93 | ConstParentIdStruct, |
| 94 | ConstParentIdErrUnionCode, | |
| 95 | ConstParentIdErrUnionPayload, | |
| 96 | ConstParentIdOptionalPayload, | |
| 93 | 97 | ConstParentIdArray, |
| 94 | 98 | ConstParentIdUnion, |
| 95 | 99 | ConstParentIdScalar, |
| ... | ... | @@ -107,6 +111,15 @@ struct ConstParent { |
| 107 | 111 | ConstExprValue *struct_val; |
| 108 | 112 | size_t field_index; |
| 109 | 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 | 123 | struct { |
| 111 | 124 | ConstExprValue *union_val; |
| 112 | 125 | } p_union; |
| ... | ... | @@ -118,13 +131,11 @@ struct ConstParent { |
| 118 | 131 | |
| 119 | 132 | struct ConstStructValue { |
| 120 | 133 | ConstExprValue *fields; |
| 121 | ConstParent parent; | |
| 122 | 134 | }; |
| 123 | 135 | |
| 124 | 136 | struct ConstUnionValue { |
| 125 | 137 | BigInt tag; |
| 126 | 138 | ConstExprValue *payload; |
| 127 | ConstParent parent; | |
| 128 | 139 | }; |
| 129 | 140 | |
| 130 | 141 | enum ConstArraySpecial { |
| ... | ... | @@ -138,7 +149,6 @@ struct ConstArrayValue { |
| 138 | 149 | union { |
| 139 | 150 | struct { |
| 140 | 151 | ConstExprValue *elements; |
| 141 | ConstParent parent; | |
| 142 | 152 | } s_none; |
| 143 | 153 | Buf *s_buf; |
| 144 | 154 | } data; |
| ... | ... | @@ -153,19 +163,29 @@ enum ConstPtrSpecial { |
| 153 | 163 | ConstPtrSpecialBaseArray, |
| 154 | 164 | // The pointer points to a field in an underlying struct. |
| 155 | 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 | 172 | // This means that we did a compile-time pointer reinterpret and we cannot |
| 157 | 173 | // understand the value of pointee at compile time. However, we will still |
| 158 | 174 | // emit a binary with a compile time known address. |
| 159 | 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 | 176 | ConstPtrSpecialHardCodedAddr, |
| 164 | 177 | // This means that the pointer represents memory of assigning to _. |
| 165 | 178 | // That is, storing discards the data, and loading is invalid. |
| 166 | 179 | ConstPtrSpecialDiscard, |
| 167 | 180 | // This is actually a function. |
| 168 | 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 | 191 | enum ConstPtrMut { |
| ... | ... | @@ -199,6 +219,15 @@ struct ConstPtrValue { |
| 199 | 219 | ConstExprValue *struct_val; |
| 200 | 220 | size_t field_index; |
| 201 | 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 | 231 | struct { |
| 203 | 232 | uint64_t addr; |
| 204 | 233 | } hard_coded_addr; |
| ... | ... | @@ -209,7 +238,7 @@ struct ConstPtrValue { |
| 209 | 238 | }; |
| 210 | 239 | |
| 211 | 240 | struct ConstErrValue { |
| 212 | ErrorTableEntry *err; | |
| 241 | ConstExprValue *error_set; | |
| 213 | 242 | ConstExprValue *payload; |
| 214 | 243 | }; |
| 215 | 244 | |
| ... | ... | @@ -265,6 +294,7 @@ struct ConstGlobalRefs { |
| 265 | 294 | struct ConstExprValue { |
| 266 | 295 | ZigType *type; |
| 267 | 296 | ConstValSpecial special; |
| 297 | ConstParent parent; | |
| 268 | 298 | ConstGlobalRefs *global_refs; |
| 269 | 299 | |
| 270 | 300 | union { |
| ... | ... | @@ -433,7 +463,7 @@ enum NodeType { |
| 433 | 463 | NodeTypeArrayType, |
| 434 | 464 | NodeTypeErrorType, |
| 435 | 465 | NodeTypeIfErrorExpr, |
| 436 | NodeTypeTestExpr, | |
| 466 | NodeTypeIfOptional, | |
| 437 | 467 | NodeTypeErrorSetDecl, |
| 438 | 468 | NodeTypeCancel, |
| 439 | 469 | NodeTypeResume, |
| ... | ... | @@ -677,7 +707,7 @@ struct AstNodeUse { |
| 677 | 707 | AstNode *expr; |
| 678 | 708 | |
| 679 | 709 | TldResolution resolution; |
| 680 | IrInstruction *value; | |
| 710 | ConstExprValue *value; | |
| 681 | 711 | }; |
| 682 | 712 | |
| 683 | 713 | struct AstNodeIfBoolExpr { |
| ... | ... | @@ -1180,6 +1210,12 @@ struct ZigTypePromise { |
| 1180 | 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 | 1219 | enum ZigTypeId { |
| 1184 | 1220 | ZigTypeIdInvalid, |
| 1185 | 1221 | ZigTypeIdMetaType, |
| ... | ... | @@ -1206,6 +1242,7 @@ enum ZigTypeId { |
| 1206 | 1242 | ZigTypeIdArgTuple, |
| 1207 | 1243 | ZigTypeIdOpaque, |
| 1208 | 1244 | ZigTypeIdPromise, |
| 1245 | ZigTypeIdVector, | |
| 1209 | 1246 | }; |
| 1210 | 1247 | |
| 1211 | 1248 | struct ZigType { |
| ... | ... | @@ -1232,6 +1269,7 @@ struct ZigType { |
| 1232 | 1269 | ZigTypeFn fn; |
| 1233 | 1270 | ZigTypeBoundFn bound_fn; |
| 1234 | 1271 | ZigTypePromise promise; |
| 1272 | ZigTypeVector vector; | |
| 1235 | 1273 | } data; |
| 1236 | 1274 | |
| 1237 | 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 | 1423 | BuiltinFnIdEnumToInt, |
| 1386 | 1424 | BuiltinFnIdIntToEnum, |
| 1387 | 1425 | BuiltinFnIdIntType, |
| 1426 | BuiltinFnIdVectorType, | |
| 1388 | 1427 | BuiltinFnIdSetCold, |
| 1389 | 1428 | BuiltinFnIdSetRuntimeSafety, |
| 1390 | 1429 | BuiltinFnIdSetFloatMode, |
| ... | ... | @@ -1475,6 +1514,10 @@ struct TypeId { |
| 1475 | 1514 | ZigType *err_set_type; |
| 1476 | 1515 | ZigType *payload_type; |
| 1477 | 1516 | } error_union; |
| 1517 | struct { | |
| 1518 | ZigType *elem_type; | |
| 1519 | uint32_t len; | |
| 1520 | } vector; | |
| 1478 | 1521 | } data; |
| 1479 | 1522 | }; |
| 1480 | 1523 | |
| ... | ... | @@ -1610,7 +1653,7 @@ struct CodeGen { |
| 1610 | 1653 | HashMap<FnTypeId *, ZigType *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1611 | 1654 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; |
| 1612 | 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 | 1657 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; |
| 1615 | 1658 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1616 | 1659 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| ... | ... | @@ -1760,6 +1803,7 @@ struct CodeGen { |
| 1760 | 1803 | bool is_static; |
| 1761 | 1804 | bool strip_debug_symbols; |
| 1762 | 1805 | bool is_test_build; |
| 1806 | bool is_single_threaded; | |
| 1763 | 1807 | bool is_native_target; |
| 1764 | 1808 | bool linker_rdynamic; |
| 1765 | 1809 | bool no_rosegment_workaround; |
| ... | ... | @@ -1802,10 +1846,9 @@ enum VarLinkage { |
| 1802 | 1846 | |
| 1803 | 1847 | struct ZigVar { |
| 1804 | 1848 | Buf name; |
| 1805 | ConstExprValue *value; | |
| 1849 | ConstExprValue *const_value; | |
| 1850 | ZigType *var_type; | |
| 1806 | 1851 | LLVMValueRef value_ref; |
| 1807 | bool src_is_const; | |
| 1808 | bool gen_is_const; | |
| 1809 | 1852 | IrInstruction *is_comptime; |
| 1810 | 1853 | // which node is the declaration of the variable |
| 1811 | 1854 | AstNode *decl_node; |
| ... | ... | @@ -1815,17 +1858,21 @@ struct ZigVar { |
| 1815 | 1858 | Scope *parent_scope; |
| 1816 | 1859 | Scope *child_scope; |
| 1817 | 1860 | LLVMValueRef param_value_ref; |
| 1818 | bool shadowable; | |
| 1819 | 1861 | size_t mem_slot_index; |
| 1820 | 1862 | IrExecutable *owner_exec; |
| 1821 | 1863 | size_t ref_count; |
| 1822 | VarLinkage linkage; | |
| 1823 | uint32_t align_bytes; | |
| 1824 | 1864 | |
| 1825 | 1865 | // In an inline loop, multiple variables may be created, |
| 1826 | 1866 | // In this case, a reference to a variable should follow |
| 1827 | 1867 | // this pointer to the redefined variable. |
| 1828 | 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 | 1878 | struct ErrorTableEntry { |
| ... | ... | @@ -1891,10 +1938,11 @@ struct ScopeBlock { |
| 1891 | 1938 | ZigList<IrInstruction *> *incoming_values; |
| 1892 | 1939 | ZigList<IrBasicBlock *> *incoming_blocks; |
| 1893 | 1940 | |
| 1894 | bool safety_off; | |
| 1895 | 1941 | AstNode *safety_set_node; |
| 1896 | bool fast_math_on; | |
| 1897 | 1942 | AstNode *fast_math_set_node; |
| 1943 | ||
| 1944 | bool safety_off; | |
| 1945 | bool fast_math_on; | |
| 1898 | 1946 | }; |
| 1899 | 1947 | |
| 1900 | 1948 | // This scope is created from every defer expression. |
| ... | ... | @@ -2030,8 +2078,19 @@ struct IrBasicBlock { |
| 2030 | 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 | 2090 | enum IrInstructionId { |
| 2034 | 2091 | IrInstructionIdInvalid, |
| 2092 | IrInstructionIdDeclVarSrc, | |
| 2093 | IrInstructionIdDeclVarGen, | |
| 2035 | 2094 | IrInstructionIdBr, |
| 2036 | 2095 | IrInstructionIdCondBr, |
| 2037 | 2096 | IrInstructionIdSwitchBr, |
| ... | ... | @@ -2040,7 +2099,6 @@ enum IrInstructionId { |
| 2040 | 2099 | IrInstructionIdPhi, |
| 2041 | 2100 | IrInstructionIdUnOp, |
| 2042 | 2101 | IrInstructionIdBinOp, |
| 2043 | IrInstructionIdDeclVar, | |
| 2044 | 2102 | IrInstructionIdLoadPtr, |
| 2045 | 2103 | IrInstructionIdStorePtr, |
| 2046 | 2104 | IrInstructionIdFieldPtr, |
| ... | ... | @@ -2069,7 +2127,7 @@ enum IrInstructionId { |
| 2069 | 2127 | IrInstructionIdAsm, |
| 2070 | 2128 | IrInstructionIdSizeOf, |
| 2071 | 2129 | IrInstructionIdTestNonNull, |
| 2072 | IrInstructionIdUnwrapOptional, | |
| 2130 | IrInstructionIdOptionalUnwrapPtr, | |
| 2073 | 2131 | IrInstructionIdOptionalWrap, |
| 2074 | 2132 | IrInstructionIdUnionTag, |
| 2075 | 2133 | IrInstructionIdClz, |
| ... | ... | @@ -2085,7 +2143,8 @@ enum IrInstructionId { |
| 2085 | 2143 | IrInstructionIdCompileLog, |
| 2086 | 2144 | IrInstructionIdErrName, |
| 2087 | 2145 | IrInstructionIdEmbedFile, |
| 2088 | IrInstructionIdCmpxchg, | |
| 2146 | IrInstructionIdCmpxchgSrc, | |
| 2147 | IrInstructionIdCmpxchgGen, | |
| 2089 | 2148 | IrInstructionIdFence, |
| 2090 | 2149 | IrInstructionIdTruncate, |
| 2091 | 2150 | IrInstructionIdIntCast, |
| ... | ... | @@ -2094,6 +2153,7 @@ enum IrInstructionId { |
| 2094 | 2153 | IrInstructionIdFloatToInt, |
| 2095 | 2154 | IrInstructionIdBoolToInt, |
| 2096 | 2155 | IrInstructionIdIntType, |
| 2156 | IrInstructionIdVectorType, | |
| 2097 | 2157 | IrInstructionIdBoolNot, |
| 2098 | 2158 | IrInstructionIdMemset, |
| 2099 | 2159 | IrInstructionIdMemcpy, |
| ... | ... | @@ -2114,7 +2174,8 @@ enum IrInstructionId { |
| 2114 | 2174 | IrInstructionIdErrWrapPayload, |
| 2115 | 2175 | IrInstructionIdFnProto, |
| 2116 | 2176 | IrInstructionIdTestComptime, |
| 2117 | IrInstructionIdPtrCast, | |
| 2177 | IrInstructionIdPtrCastSrc, | |
| 2178 | IrInstructionIdPtrCastGen, | |
| 2118 | 2179 | IrInstructionIdBitCast, |
| 2119 | 2180 | IrInstructionIdWidenOrShorten, |
| 2120 | 2181 | IrInstructionIdIntToPtr, |
| ... | ... | @@ -2173,6 +2234,8 @@ enum IrInstructionId { |
| 2173 | 2234 | IrInstructionIdToBytes, |
| 2174 | 2235 | IrInstructionIdFromBytes, |
| 2175 | 2236 | IrInstructionIdCheckRuntimeScope, |
| 2237 | IrInstructionIdVectorToArray, | |
| 2238 | IrInstructionIdArrayToVector, | |
| 2176 | 2239 | }; |
| 2177 | 2240 | |
| 2178 | 2241 | struct IrInstruction { |
| ... | ... | @@ -2194,6 +2257,22 @@ struct IrInstruction { |
| 2194 | 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 | 2276 | struct IrInstructionCondBr { |
| 2198 | 2277 | IrInstruction base; |
| 2199 | 2278 | |
| ... | ... | @@ -2302,20 +2381,11 @@ struct IrInstructionBinOp { |
| 2302 | 2381 | IrInstruction base; |
| 2303 | 2382 | |
| 2304 | 2383 | IrInstruction *op1; |
| 2305 | IrBinOp op_id; | |
| 2306 | 2384 | IrInstruction *op2; |
| 2385 | IrBinOp op_id; | |
| 2307 | 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 | 2389 | struct IrInstructionLoadPtr { |
| 2320 | 2390 | IrInstruction base; |
| 2321 | 2391 | |
| ... | ... | @@ -2335,7 +2405,6 @@ struct IrInstructionFieldPtr { |
| 2335 | 2405 | IrInstruction *container_ptr; |
| 2336 | 2406 | Buf *field_name_buffer; |
| 2337 | 2407 | IrInstruction *field_name_expr; |
| 2338 | bool is_const; | |
| 2339 | 2408 | }; |
| 2340 | 2409 | |
| 2341 | 2410 | struct IrInstructionStructFieldPtr { |
| ... | ... | @@ -2378,13 +2447,13 @@ struct IrInstructionCall { |
| 2378 | 2447 | ZigFn *fn_entry; |
| 2379 | 2448 | size_t arg_count; |
| 2380 | 2449 | IrInstruction **args; |
| 2381 | bool is_comptime; | |
| 2382 | 2450 | LLVMValueRef tmp_ptr; |
| 2383 | FnInline fn_inline; | |
| 2384 | bool is_async; | |
| 2385 | 2451 | |
| 2386 | 2452 | IrInstruction *async_allocator; |
| 2387 | 2453 | IrInstruction *new_stack; |
| 2454 | FnInline fn_inline; | |
| 2455 | bool is_async; | |
| 2456 | bool is_comptime; | |
| 2388 | 2457 | }; |
| 2389 | 2458 | |
| 2390 | 2459 | struct IrInstructionConst { |
| ... | ... | @@ -2527,9 +2596,9 @@ struct IrInstructionSliceType { |
| 2527 | 2596 | IrInstruction base; |
| 2528 | 2597 | |
| 2529 | 2598 | IrInstruction *align_value; |
| 2599 | IrInstruction *child_type; | |
| 2530 | 2600 | bool is_const; |
| 2531 | 2601 | bool is_volatile; |
| 2532 | IrInstruction *child_type; | |
| 2533 | 2602 | }; |
| 2534 | 2603 | |
| 2535 | 2604 | struct IrInstructionAsm { |
| ... | ... | @@ -2557,10 +2626,12 @@ struct IrInstructionTestNonNull { |
| 2557 | 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 | 2632 | IrInstruction base; |
| 2562 | 2633 | |
| 2563 | IrInstruction *value; | |
| 2634 | IrInstruction *base_ptr; | |
| 2564 | 2635 | bool safety_check_on; |
| 2565 | 2636 | }; |
| 2566 | 2637 | |
| ... | ... | @@ -2651,7 +2722,7 @@ struct IrInstructionEmbedFile { |
| 2651 | 2722 | IrInstruction *name; |
| 2652 | 2723 | }; |
| 2653 | 2724 | |
| 2654 | struct IrInstructionCmpxchg { | |
| 2725 | struct IrInstructionCmpxchgSrc { | |
| 2655 | 2726 | IrInstruction base; |
| 2656 | 2727 | |
| 2657 | 2728 | IrInstruction *type_value; |
| ... | ... | @@ -2661,14 +2732,19 @@ struct IrInstructionCmpxchg { |
| 2661 | 2732 | IrInstruction *success_order_value; |
| 2662 | 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 | 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 | 2744 | LLVMValueRef tmp_ptr; |
| 2745 | AtomicOrder success_order; | |
| 2746 | AtomicOrder failure_order; | |
| 2747 | bool is_weak; | |
| 2672 | 2748 | }; |
| 2673 | 2749 | |
| 2674 | 2750 | struct IrInstructionFence { |
| ... | ... | @@ -2748,6 +2824,13 @@ struct IrInstructionIntType { |
| 2748 | 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 | 2834 | struct IrInstructionBoolNot { |
| 2752 | 2835 | IrInstruction base; |
| 2753 | 2836 | |
| ... | ... | @@ -2851,7 +2934,7 @@ struct IrInstructionTestErr { |
| 2851 | 2934 | struct IrInstructionUnwrapErrCode { |
| 2852 | 2935 | IrInstruction base; |
| 2853 | 2936 | |
| 2854 | IrInstruction *value; | |
| 2937 | IrInstruction *err_union; | |
| 2855 | 2938 | }; |
| 2856 | 2939 | |
| 2857 | 2940 | struct IrInstructionUnwrapErrPayload { |
| ... | ... | @@ -2899,13 +2982,19 @@ struct IrInstructionTestComptime { |
| 2899 | 2982 | IrInstruction *value; |
| 2900 | 2983 | }; |
| 2901 | 2984 | |
| 2902 | struct IrInstructionPtrCast { | |
| 2985 | struct IrInstructionPtrCastSrc { | |
| 2903 | 2986 | IrInstruction base; |
| 2904 | 2987 | |
| 2905 | 2988 | IrInstruction *dest_type; |
| 2906 | 2989 | IrInstruction *ptr; |
| 2907 | 2990 | }; |
| 2908 | 2991 | |
| 2992 | struct IrInstructionPtrCastGen { | |
| 2993 | IrInstruction base; | |
| 2994 | ||
| 2995 | IrInstruction *ptr; | |
| 2996 | }; | |
| 2997 | ||
| 2909 | 2998 | struct IrInstructionBitCast { |
| 2910 | 2999 | IrInstruction base; |
| 2911 | 3000 | |
| ... | ... | @@ -3276,6 +3365,19 @@ struct IrInstructionBitReverse { |
| 3276 | 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 | 3381 | static const size_t slice_ptr_index = 0; |
| 3280 | 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 | 250 | case ZigTypeIdBoundFn: |
| 251 | 251 | case ZigTypeIdArgTuple: |
| 252 | 252 | case ZigTypeIdPromise: |
| 253 | case ZigTypeIdVector: | |
| 253 | 254 | return nullptr; |
| 254 | 255 | } |
| 255 | 256 | zig_unreachable(); |
| ... | ... | @@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 311 | 312 | case ZigTypeIdBoundFn: |
| 312 | 313 | case ZigTypeIdArgTuple: |
| 313 | 314 | case ZigTypeIdPromise: |
| 315 | case ZigTypeIdVector: | |
| 314 | 316 | return true; |
| 315 | 317 | } |
| 316 | 318 | zig_unreachable(); |
| ... | ... | @@ -570,7 +572,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| 570 | 572 | if (child_type->zero_bits) { |
| 571 | 573 | entry->type_ref = LLVMInt1Type(); |
| 572 | 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 | 576 | assert(child_type->di_type); |
| 575 | 577 | // this is an optimization but also is necessary for calling C |
| 576 | 578 | // functions where all pointers are maybe pointers |
| ... | ... | @@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { |
| 1055 | 1057 | } |
| 1056 | 1058 | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| 1057 | 1059 | X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); |
| 1058 | if (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)); | |
| 1060 | return abi_class == X64CABIClass_MEMORY; | |
| 1063 | 1061 | } else if (target_is_arm(&g->zig_target)) { |
| 1064 | 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 | 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 | 1282 | size_t backward_branch_count = 0; |
| 1283 | 1283 | return ir_eval_const_value(g, scope, node, type_entry, |
| 1284 | 1284 | &backward_branch_count, default_backward_branch_quota, |
| ... | ... | @@ -1286,12 +1286,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod |
| 1286 | 1286 | } |
| 1287 | 1287 | |
| 1288 | 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); | |
| 1290 | if (result->value.type->id == ZigTypeIdInvalid) | |
| 1289 | ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); | |
| 1290 | if (type_is_invalid(result->type)) | |
| 1291 | 1291 | return g->builtin_types.entry_invalid; |
| 1292 | 1292 | |
| 1293 | assert(result->value.special != ConstValSpecialRuntime); | |
| 1294 | return result->value.data.x_type; | |
| 1293 | assert(result->special != ConstValSpecialRuntime); | |
| 1294 | return result->data.x_type; | |
| 1295 | 1295 | } |
| 1296 | 1296 | |
| 1297 | 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 | 1342 | } |
| 1343 | 1343 | |
| 1344 | 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); | |
| 1346 | if (type_is_invalid(align_result->value.type)) | |
| 1345 | ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); | |
| 1346 | if (type_is_invalid(align_result->type)) | |
| 1347 | 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 | 1350 | if (align_bytes == 0) { |
| 1351 | 1351 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 1352 | 1352 | return false; |
| ... | ... | @@ -1364,12 +1364,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1364 | 1364 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, |
| 1365 | 1365 | PtrLenUnknown, 0, 0, 0); |
| 1366 | 1366 | ZigType *str_type = get_slice_type(g, ptr_type); |
| 1367 | IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); | |
| 1368 | if (type_is_invalid(instr->value.type)) | |
| 1367 | ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); | |
| 1368 | if (type_is_invalid(result_val->type)) | |
| 1369 | 1369 | return false; |
| 1370 | 1370 | |
| 1371 | ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; | |
| 1372 | ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; | |
| 1371 | ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index]; | |
| 1372 | ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index]; | |
| 1373 | 1373 | |
| 1374 | 1374 | assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 1375 | 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 | 1422 | case ZigTypeIdPointer: |
| 1423 | 1423 | case ZigTypeIdArray: |
| 1424 | 1424 | case ZigTypeIdFn: |
| 1425 | case ZigTypeIdVector: | |
| 1425 | 1426 | return true; |
| 1426 | 1427 | case ZigTypeIdStruct: |
| 1427 | 1428 | return type_entry->data.structure.layout == ContainerLayoutPacked; |
| ... | ... | @@ -1470,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { |
| 1470 | 1471 | default: |
| 1471 | 1472 | return false; |
| 1472 | 1473 | } |
| 1474 | case ZigTypeIdVector: | |
| 1475 | return type_allowed_in_extern(g, type_entry->data.vector.elem_type); | |
| 1473 | 1476 | case ZigTypeIdFloat: |
| 1474 | 1477 | return true; |
| 1475 | 1478 | case ZigTypeIdArray: |
| ... | ... | @@ -1623,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1623 | 1626 | case ZigTypeIdUnion: |
| 1624 | 1627 | case ZigTypeIdFn: |
| 1625 | 1628 | case ZigTypeIdPromise: |
| 1629 | case ZigTypeIdVector: | |
| 1626 | 1630 | switch (type_requires_comptime(g, type_entry)) { |
| 1627 | 1631 | case ReqCompTimeNo: |
| 1628 | 1632 | break; |
| ... | ... | @@ -1718,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1718 | 1722 | case ZigTypeIdUnion: |
| 1719 | 1723 | case ZigTypeIdFn: |
| 1720 | 1724 | case ZigTypeIdPromise: |
| 1725 | case ZigTypeIdVector: | |
| 1721 | 1726 | switch (type_requires_comptime(g, fn_type_id.return_type)) { |
| 1722 | 1727 | case ReqCompTimeInvalid: |
| 1723 | 1728 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -2504,20 +2509,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2504 | 2509 | // In this first pass we resolve explicit tag values. |
| 2505 | 2510 | // In a second pass we will fill in the unspecified ones. |
| 2506 | 2511 | if (tag_value != nullptr) { |
| 2507 | IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2508 | if (result_inst->value.type->id == ZigTypeIdInvalid) { | |
| 2512 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2513 | if (type_is_invalid(result->type)) { | |
| 2509 | 2514 | enum_type->data.enumeration.is_invalid = true; |
| 2510 | 2515 | continue; |
| 2511 | 2516 | } |
| 2512 | assert(result_inst->value.special != ConstValSpecialRuntime); | |
| 2513 | assert(result_inst->value.type->id == ZigTypeIdInt || | |
| 2514 | result_inst->value.type->id == ZigTypeIdComptimeInt); | |
| 2515 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | |
| 2517 | assert(result->special != ConstValSpecialRuntime); | |
| 2518 | assert(result->type->id == ZigTypeIdInt || | |
| 2519 | result->type->id == ZigTypeIdComptimeInt); | |
| 2520 | auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); | |
| 2516 | 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 | 2523 | } else { |
| 2519 | 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 | 2527 | ErrorMsg *msg = add_node_error(g, tag_value, |
| 2523 | 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 | 2949 | // In a second pass we will fill in the unspecified ones. |
| 2945 | 2950 | if (tag_value != nullptr) { |
| 2946 | 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); | |
| 2948 | if (result_inst->value.type->id == ZigTypeIdInvalid) { | |
| 2952 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2953 | if (type_is_invalid(result->type)) { | |
| 2949 | 2954 | union_type->data.unionation.is_invalid = true; |
| 2950 | 2955 | continue; |
| 2951 | 2956 | } |
| 2952 | assert(result_inst->value.special != ConstValSpecialRuntime); | |
| 2953 | assert(result_inst->value.type->id == ZigTypeIdInt); | |
| 2954 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | |
| 2957 | assert(result->special != ConstValSpecialRuntime); | |
| 2958 | assert(result->type->id == ZigTypeIdInt); | |
| 2959 | auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); | |
| 2955 | 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 | 2962 | } else { |
| 2958 | 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 | 2966 | ErrorMsg *msg = add_node_error(g, tag_value, |
| 2962 | 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 | 3424 | resolve_top_level_decl(g, tld, false, tld->source_node); |
| 3420 | 3425 | assert(tld->id == TldIdVar); |
| 3421 | 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 | 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 | 3519 | case NodeTypeArrayType: |
| 3514 | 3520 | case NodeTypeErrorType: |
| 3515 | 3521 | case NodeTypeIfErrorExpr: |
| 3516 | case NodeTypeTestExpr: | |
| 3522 | case NodeTypeIfOptional: | |
| 3517 | 3523 | case NodeTypeErrorSetDecl: |
| 3518 | 3524 | case NodeTypeCancel: |
| 3519 | 3525 | case NodeTypeResume: |
| ... | ... | @@ -3574,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry |
| 3574 | 3580 | case ZigTypeIdFn: |
| 3575 | 3581 | case ZigTypeIdBoundFn: |
| 3576 | 3582 | case ZigTypeIdPromise: |
| 3583 | case ZigTypeIdVector: | |
| 3577 | 3584 | return type_entry; |
| 3578 | 3585 | } |
| 3579 | 3586 | zig_unreachable(); |
| ... | ... | @@ -3582,13 +3589,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry |
| 3582 | 3589 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 3583 | 3590 | // TODO merge with definition of add_local_var in ir.cpp |
| 3584 | 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 | 3594 | Error err; |
| 3588 | assert(value); | |
| 3595 | assert(const_value != nullptr); | |
| 3596 | assert(var_type != nullptr); | |
| 3589 | 3597 | |
| 3590 | 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 | 3601 | variable_entry->parent_scope = parent_scope; |
| 3593 | 3602 | variable_entry->shadowable = false; |
| 3594 | 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 | 3606 | assert(name); |
| 3598 | 3607 | buf_init_from_buf(&variable_entry->name, name); |
| 3599 | 3608 | |
| 3600 | if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) { | |
| 3601 | variable_entry->value->type = g->builtin_types.entry_invalid; | |
| 3609 | if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { | |
| 3610 | variable_entry->var_type = g->builtin_types.entry_invalid; | |
| 3602 | 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 | 3614 | ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); |
| 3606 | 3615 | if (existing_var && !existing_var->shadowable) { |
| 3607 | 3616 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3608 | 3617 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 3609 | 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 | 3620 | } else { |
| 3612 | 3621 | ZigType *type; |
| 3613 | 3622 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { |
| 3614 | 3623 | add_node_error(g, source_node, |
| 3615 | 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 | 3626 | } else { |
| 3618 | 3627 | Scope *search_scope = nullptr; |
| 3619 | 3628 | if (src_tld == nullptr) { |
| ... | ... | @@ -3627,7 +3636,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3627 | 3636 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3628 | 3637 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 3629 | 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 | 3686 | linkage = VarLinkageInternal; |
| 3678 | 3687 | } |
| 3679 | 3688 | |
| 3680 | IrInstruction *init_value = nullptr; | |
| 3689 | ConstExprValue *init_value = nullptr; | |
| 3681 | 3690 | |
| 3682 | 3691 | // TODO more validation for types that can't be used for export/extern variables |
| 3683 | 3692 | ZigType *implicit_type = nullptr; |
| ... | ... | @@ -3686,7 +3695,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3686 | 3695 | } else if (var_decl->expr) { |
| 3687 | 3696 | init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); |
| 3688 | 3697 | assert(init_value); |
| 3689 | implicit_type = init_value->value.type; | |
| 3698 | implicit_type = init_value->type; | |
| 3690 | 3699 | |
| 3691 | 3700 | if (implicit_type->id == ZigTypeIdUnreachable) { |
| 3692 | 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 | 3713 | add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); |
| 3705 | 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 | 3717 | } else if (linkage != VarLinkageExternal) { |
| 3709 | 3718 | add_node_error(g, source_node, buf_sprintf("variables must be initialized")); |
| 3710 | 3719 | implicit_type = g->builtin_types.entry_invalid; |
| ... | ... | @@ -3713,19 +3722,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3713 | 3722 | ZigType *type = explicit_type ? explicit_type : implicit_type; |
| 3714 | 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 | 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 | 3729 | tld_var->var->linkage = linkage; |
| 3721 | 3730 | |
| 3722 | 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 | 3735 | if (var_decl->align_expr != nullptr) { |
| 3727 | 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 | 3947 | case ZigTypeIdArgTuple: |
| 3939 | 3948 | case ZigTypeIdOpaque: |
| 3940 | 3949 | case ZigTypeIdPromise: |
| 3950 | case ZigTypeIdVector: | |
| 3941 | 3951 | return false; |
| 3942 | 3952 | } |
| 3943 | 3953 | zig_unreachable(); |
| ... | ... | @@ -3997,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { |
| 3997 | 4007 | case ZigTypeIdArgTuple: |
| 3998 | 4008 | case ZigTypeIdOpaque: |
| 3999 | 4009 | case ZigTypeIdPromise: |
| 4010 | case ZigTypeIdVector: | |
| 4000 | 4011 | zig_unreachable(); |
| 4001 | 4012 | } |
| 4002 | 4013 | } |
| ... | ... | @@ -4090,7 +4101,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { |
| 4090 | 4101 | } |
| 4091 | 4102 | |
| 4092 | 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 | 4105 | var->src_arg_index = i; |
| 4095 | 4106 | fn_table_entry->child_scope = var->child_scope; |
| 4096 | 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 | 4239 | preview_use_decl(g, src_use_node); |
| 4229 | 4240 | } |
| 4230 | 4241 | |
| 4231 | IrInstruction *use_target_value = src_use_node->data.use.value; | |
| 4232 | if (use_target_value->value.type->id == ZigTypeIdInvalid) { | |
| 4242 | ConstExprValue *use_target_value = src_use_node->data.use.value; | |
| 4243 | if (type_is_invalid(use_target_value->type)) { | |
| 4233 | 4244 | dst_use_node->owner->any_imports_failed = true; |
| 4234 | 4245 | return; |
| 4235 | 4246 | } |
| 4236 | 4247 | |
| 4237 | 4248 | dst_use_node->data.use.resolution = TldResolutionOk; |
| 4238 | 4249 | |
| 4239 | ConstExprValue *const_val = &use_target_value->value; | |
| 4240 | assert(const_val->special != ConstValSpecialRuntime); | |
| 4250 | assert(use_target_value->special != ConstValSpecialRuntime); | |
| 4241 | 4251 | |
| 4242 | ImportTableEntry *target_import = const_val->data.x_import; | |
| 4252 | ImportTableEntry *target_import = use_target_value->data.x_import; | |
| 4243 | 4253 | assert(target_import); |
| 4244 | 4254 | |
| 4245 | 4255 | if (target_import->any_imports_failed) { |
| ... | ... | @@ -4302,10 +4312,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { |
| 4302 | 4312 | } |
| 4303 | 4313 | |
| 4304 | 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 | 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 | 4319 | node->owner->any_imports_failed = true; |
| 4310 | 4320 | |
| 4311 | 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 | 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 | 4496 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { |
| 4451 | 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 | 4524 | case ZigTypeIdFn: |
| 4479 | 4525 | case ZigTypeIdEnum: |
| 4480 | 4526 | case ZigTypeIdPromise: |
| 4527 | case ZigTypeIdVector: | |
| 4481 | 4528 | return false; |
| 4482 | 4529 | case ZigTypeIdArray: |
| 4483 | 4530 | case ZigTypeIdStruct: |
| ... | ... | @@ -4486,7 +4533,8 @@ bool handle_is_ptr(ZigType *type_entry) { |
| 4486 | 4533 | return type_has_bits(type_entry->data.error_union.payload_type); |
| 4487 | 4534 | case ZigTypeIdOptional: |
| 4488 | 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 | 4538 | case ZigTypeIdUnion: |
| 4491 | 4539 | assert(type_entry->data.unionation.zero_bits_known); |
| 4492 | 4540 | if (type_entry->data.unionation.gen_field_count == 0) |
| ... | ... | @@ -4732,6 +4780,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { |
| 4732 | 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 | 4788 | static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { |
| 4736 | 4789 | uint32_t hash_val = 0; |
| 4737 | 4790 | switch (const_val->data.x_ptr.mut) { |
| ... | ... | @@ -4763,6 +4816,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { |
| 4763 | 4816 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); |
| 4764 | 4817 | hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); |
| 4765 | 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 | 4831 | case ConstPtrSpecialHardCodedAddr: |
| 4767 | 4832 | hash_val += (uint32_t)4048518294; |
| 4768 | 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 | 4839 | hash_val += (uint32_t)2590901619; |
| 4775 | 4840 | hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); |
| 4776 | 4841 | return hash_val; |
| 4842 | case ConstPtrSpecialNull: | |
| 4843 | hash_val += (uint32_t)1486246455; | |
| 4844 | return hash_val; | |
| 4777 | 4845 | } |
| 4778 | 4846 | zig_unreachable(); |
| 4779 | 4847 | } |
| ... | ... | @@ -4872,7 +4940,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 4872 | 4940 | return 2709806591; |
| 4873 | 4941 | case ZigTypeIdOptional: |
| 4874 | 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 | 4946 | } else { |
| 4877 | 4947 | if (const_val->data.x_optional) { |
| 4878 | 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 | 4954 | // TODO better hashing algorithm |
| 4885 | 4955 | return 3415065496; |
| 4886 | 4956 | case ZigTypeIdErrorSet: |
| 4887 | assert(const_val->data.x_err_set != nullptr); | |
| 4888 | return const_val->data.x_err_set->value ^ 2630160122; | |
| 4957 | return hash_const_val_error_set(const_val); | |
| 4889 | 4958 | case ZigTypeIdNamespace: |
| 4890 | 4959 | return hash_ptr(const_val->data.x_import); |
| 4960 | case ZigTypeIdVector: | |
| 4961 | // TODO better hashing algorithm | |
| 4962 | return 3647867726; | |
| 4891 | 4963 | case ZigTypeIdBoundFn: |
| 4892 | 4964 | case ZigTypeIdInvalid: |
| 4893 | 4965 | case ZigTypeIdUnreachable: |
| ... | ... | @@ -4940,6 +5012,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { |
| 4940 | 5012 | case ZigTypeIdBool: |
| 4941 | 5013 | case ZigTypeIdUnreachable: |
| 4942 | 5014 | case ZigTypeIdInt: |
| 5015 | case ZigTypeIdVector: | |
| 4943 | 5016 | case ZigTypeIdFloat: |
| 4944 | 5017 | case ZigTypeIdComptimeFloat: |
| 4945 | 5018 | case ZigTypeIdComptimeInt: |
| ... | ... | @@ -4987,7 +5060,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { |
| 4987 | 5060 | return can_mutate_comptime_var_state(value->data.x_optional); |
| 4988 | 5061 | |
| 4989 | 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 | 5064 | return false; |
| 4992 | 5065 | assert(value->data.x_err_union.payload != nullptr); |
| 4993 | 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 | 5096 | case ZigTypeIdErrorSet: |
| 5024 | 5097 | case ZigTypeIdEnum: |
| 5025 | 5098 | case ZigTypeIdPointer: |
| 5099 | case ZigTypeIdVector: | |
| 5026 | 5100 | return true; |
| 5027 | 5101 | |
| 5028 | 5102 | case ZigTypeIdArray: |
| ... | ... | @@ -5048,9 +5122,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { |
| 5048 | 5122 | while (scope) { |
| 5049 | 5123 | if (scope->id == ScopeIdVarDecl) { |
| 5050 | 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 | 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 | 5128 | return false; |
| 5055 | 5129 | } else if (scope->id == ScopeIdFnDef) { |
| 5056 | 5130 | return true; |
| ... | ... | @@ -5068,7 +5142,7 @@ uint32_t fn_eval_hash(Scope* scope) { |
| 5068 | 5142 | while (scope) { |
| 5069 | 5143 | if (scope->id == ScopeIdVarDecl) { |
| 5070 | 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 | 5146 | } else if (scope->id == ScopeIdFnDef) { |
| 5073 | 5147 | ScopeFnDef *fn_scope = (ScopeFnDef *)scope; |
| 5074 | 5148 | result += hash_ptr(fn_scope->fn_entry); |
| ... | ... | @@ -5092,10 +5166,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { |
| 5092 | 5166 | if (a->id == ScopeIdVarDecl) { |
| 5093 | 5167 | ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; |
| 5094 | 5168 | ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; |
| 5095 | if (a_var_scope->var->value->type != b_var_scope->var->value->type) | |
| 5096 | return false; | |
| 5097 | if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value)) | |
| 5169 | if (a_var_scope->var->var_type != b_var_scope->var->var_type) | |
| 5098 | 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 | 5179 | } else if (a->id == ScopeIdFnDef) { |
| 5100 | 5180 | ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; |
| 5101 | 5181 | ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; |
| ... | ... | @@ -5113,6 +5193,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { |
| 5113 | 5193 | return false; |
| 5114 | 5194 | } |
| 5115 | 5195 | |
| 5196 | // Whether the type has bits at runtime. | |
| 5116 | 5197 | bool type_has_bits(ZigType *type_entry) { |
| 5117 | 5198 | assert(type_entry); |
| 5118 | 5199 | assert(!type_is_invalid(type_entry)); |
| ... | ... | @@ -5120,6 +5201,66 @@ bool type_has_bits(ZigType *type_entry) { |
| 5120 | 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 | 5264 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 5124 | 5265 | Error err; |
| 5125 | 5266 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) |
| ... | ... | @@ -5159,6 +5300,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 5159 | 5300 | case ZigTypeIdErrorSet: |
| 5160 | 5301 | case ZigTypeIdBool: |
| 5161 | 5302 | case ZigTypeIdInt: |
| 5303 | case ZigTypeIdVector: | |
| 5162 | 5304 | case ZigTypeIdFloat: |
| 5163 | 5305 | case ZigTypeIdVoid: |
| 5164 | 5306 | case ZigTypeIdUnreachable: |
| ... | ... | @@ -5574,6 +5716,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { |
| 5574 | 5716 | if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) |
| 5575 | 5717 | return false; |
| 5576 | 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 | 5746 | case ConstPtrSpecialHardCodedAddr: |
| 5578 | 5747 | if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) |
| 5579 | 5748 | return false; |
| ... | ... | @@ -5582,10 +5751,34 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { |
| 5582 | 5751 | return true; |
| 5583 | 5752 | case ConstPtrSpecialFunction: |
| 5584 | 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 | 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 | 5782 | bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { |
| 5590 | 5783 | assert(a->type->id == b->type->id); |
| 5591 | 5784 | assert(a->special == ConstValSpecialStatic); |
| ... | ... | @@ -5640,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { |
| 5640 | 5833 | case ZigTypeIdPointer: |
| 5641 | 5834 | case ZigTypeIdFn: |
| 5642 | 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 | 5839 | case ZigTypeIdArray: { |
| 5644 | 5840 | assert(a->type->data.array.len == b->type->data.array.len); |
| 5645 | assert(a->data.x_array.special != ConstArraySpecialUndef); | |
| 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; | |
| 5841 | return const_values_equal_array(g, a, b, a->type->data.array.len); | |
| 5665 | 5842 | } |
| 5666 | 5843 | case ZigTypeIdStruct: |
| 5667 | 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 | 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 | 5931 | assert(type_entry->id == ZigTypeIdPointer); |
| 5755 | 5932 | |
| 5756 | 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 | 5940 | zig_unreachable(); |
| 5764 | 5941 | case ConstPtrSpecialRef: |
| 5765 | 5942 | case ConstPtrSpecialBaseStruct: |
| 5943 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 5944 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 5945 | case ConstPtrSpecialBaseOptionalPayload: | |
| 5766 | 5946 | buf_appendf(buf, "*"); |
| 5767 | 5947 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors |
| 5768 | 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 | 5970 | buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); |
| 5791 | 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 | 6019 | zig_unreachable(); |
| 5795 | 6020 | } |
| ... | ... | @@ -5874,39 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5874 | 6099 | } |
| 5875 | 6100 | case ZigTypeIdPointer: |
| 5876 | 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 | 6104 | case ZigTypeIdArray: |
| 5878 | switch (const_val->data.x_array.special) { | |
| 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(); | |
| 6105 | return render_const_val_array(g, buf, const_val, type_entry->data.array.len); | |
| 5910 | 6106 | case ZigTypeIdNull: |
| 5911 | 6107 | { |
| 5912 | 6108 | buf_appendf(buf, "null"); |
| ... | ... | @@ -5921,6 +6117,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5921 | 6117 | { |
| 5922 | 6118 | if (get_codegen_ptr_type(const_val->type) != nullptr) |
| 5923 | 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 | 6122 | if (const_val->data.x_optional) { |
| 5925 | 6123 | render_const_value(g, buf, const_val->data.x_optional); |
| 5926 | 6124 | } else { |
| ... | ... | @@ -5958,11 +6156,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5958 | 6156 | case ZigTypeIdErrorUnion: |
| 5959 | 6157 | { |
| 5960 | 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 | 6161 | render_const_value(g, buf, const_val->data.x_err_union.payload); |
| 5963 | 6162 | } else { |
| 5964 | 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 | 6166 | buf_appendf(buf, ")"); |
| 5968 | 6167 | return; |
| ... | ... | @@ -5977,10 +6176,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5977 | 6176 | return; |
| 5978 | 6177 | } |
| 5979 | 6178 | case ZigTypeIdErrorSet: |
| 5980 | { | |
| 5981 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); | |
| 5982 | return; | |
| 5983 | } | |
| 6179 | return render_const_val_err_set(g, buf, const_val, type_entry); | |
| 5984 | 6180 | case ZigTypeIdArgTuple: |
| 5985 | 6181 | { |
| 5986 | 6182 | buf_appendf(buf, "(args value)"); |
| ... | ... | @@ -6065,6 +6261,8 @@ uint32_t type_id_hash(TypeId x) { |
| 6065 | 6261 | case ZigTypeIdInt: |
| 6066 | 6262 | return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + |
| 6067 | 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 | 6267 | zig_unreachable(); |
| 6070 | 6268 | } |
| ... | ... | @@ -6113,6 +6311,9 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 6113 | 6311 | case ZigTypeIdInt: |
| 6114 | 6312 | return a.data.integer.is_signed == b.data.integer.is_signed && |
| 6115 | 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 | 6318 | zig_unreachable(); |
| 6118 | 6319 | } |
| ... | ... | @@ -6171,24 +6372,34 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6171 | 6372 | |
| 6172 | 6373 | // Canonicalize the array value as ConstArraySpecialNone |
| 6173 | 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 | 6390 | switch (const_val->data.x_array.special) { |
| 6176 | 6391 | case ConstArraySpecialNone: |
| 6177 | 6392 | return; |
| 6178 | 6393 | case ConstArraySpecialUndef: { |
| 6179 | 6394 | const_val->data.x_array.special = ConstArraySpecialNone; |
| 6180 | size_t elem_count = const_val->type->data.array.len; | |
| 6181 | 6395 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); |
| 6182 | 6396 | for (size_t i = 0; i < elem_count; i += 1) { |
| 6183 | 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 | 6399 | init_const_undefined(g, element_val); |
| 6186 | ConstParent *parent = get_const_val_parent(g, element_val); | |
| 6187 | if (parent != nullptr) { | |
| 6188 | parent->id = ConstParentIdArray; | |
| 6189 | parent->data.p_array.array_val = const_val; | |
| 6190 | parent->data.p_array.elem_index = i; | |
| 6191 | } | |
| 6400 | element_val->parent.id = ConstParentIdArray; | |
| 6401 | element_val->parent.data.p_array.array_val = const_val; | |
| 6402 | element_val->parent.data.p_array.elem_index = i; | |
| 6192 | 6403 | } |
| 6193 | 6404 | return; |
| 6194 | 6405 | } |
| ... | ... | @@ -6199,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6199 | 6410 | g->string_literals_table.maybe_remove(buf); |
| 6200 | 6411 | |
| 6201 | 6412 | const_val->data.x_array.special = ConstArraySpecialNone; |
| 6202 | size_t elem_count = const_val->type->data.array.len; | |
| 6203 | 6413 | assert(elem_count == buf_len(buf)); |
| 6204 | 6414 | const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); |
| 6205 | 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 | 6417 | this_char->special = ConstValSpecialStatic; |
| 6208 | 6418 | this_char->type = g->builtin_types.entry_u8; |
| 6209 | 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 | 6424 | return; |
| 6212 | 6425 | } |
| ... | ... | @@ -6214,18 +6427,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6214 | 6427 | zig_unreachable(); |
| 6215 | 6428 | } |
| 6216 | 6429 | |
| 6430 | // Deprecated. Reference the parent field directly. | |
| 6217 | 6431 | ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 6218 | assert(value->type); | |
| 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; | |
| 6432 | return &value->parent; | |
| 6229 | 6433 | } |
| 6230 | 6434 | |
| 6231 | 6435 | static const ZigTypeId all_type_ids[] = { |
| ... | ... | @@ -6253,6 +6457,7 @@ static const ZigTypeId all_type_ids[] = { |
| 6253 | 6457 | ZigTypeIdArgTuple, |
| 6254 | 6458 | ZigTypeIdOpaque, |
| 6255 | 6459 | ZigTypeIdPromise, |
| 6460 | ZigTypeIdVector, | |
| 6256 | 6461 | }; |
| 6257 | 6462 | |
| 6258 | 6463 | ZigTypeId type_id_at_index(size_t index) { |
| ... | ... | @@ -6318,6 +6523,8 @@ size_t type_id_index(ZigType *entry) { |
| 6318 | 6523 | return 22; |
| 6319 | 6524 | case ZigTypeIdPromise: |
| 6320 | 6525 | return 23; |
| 6526 | case ZigTypeIdVector: | |
| 6527 | return 24; | |
| 6321 | 6528 | } |
| 6322 | 6529 | zig_unreachable(); |
| 6323 | 6530 | } |
| ... | ... | @@ -6374,6 +6581,8 @@ const char *type_id_name(ZigTypeId id) { |
| 6374 | 6581 | return "Opaque"; |
| 6375 | 6582 | case ZigTypeIdPromise: |
| 6376 | 6583 | return "Promise"; |
| 6584 | case ZigTypeIdVector: | |
| 6585 | return "Vector"; | |
| 6377 | 6586 | } |
| 6378 | 6587 | zig_unreachable(); |
| 6379 | 6588 | } |
| ... | ... | @@ -6453,7 +6662,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 6453 | 6662 | resolve_top_level_decl(codegen, tld, false, nullptr); |
| 6454 | 6663 | assert(tld->id == TldIdVar); |
| 6455 | 6664 | TldVar *tld_var = (TldVar *)tld; |
| 6456 | ConstExprValue *var_value = tld_var->var->value; | |
| 6665 | ConstExprValue *var_value = tld_var->var->const_value; | |
| 6457 | 6666 | assert(var_value != nullptr); |
| 6458 | 6667 | return var_value; |
| 6459 | 6668 | } |
| ... | ... | @@ -6529,6 +6738,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { |
| 6529 | 6738 | case ZigTypeIdBool: |
| 6530 | 6739 | return X64CABIClass_INTEGER; |
| 6531 | 6740 | case ZigTypeIdFloat: |
| 6741 | case ZigTypeIdVector: | |
| 6532 | 6742 | return X64CABIClass_SSE; |
| 6533 | 6743 | case ZigTypeIdStruct: { |
| 6534 | 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 | 20 | uint64_t type_size(CodeGen *g, ZigType *type_entry); |
| 21 | 21 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); |
| 22 | 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 | 24 | ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
| 24 | 25 | ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); |
| 25 | 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 | 74 | bool is_ref(ZigType *type_entry); |
| 74 | 75 | bool is_array_ref(ZigType *type_entry); |
| 75 | 76 | bool is_container_ref(ZigType *type_entry); |
| 77 | bool is_valid_vector_elem_type(ZigType *elem_type); | |
| 76 | 78 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 77 | 79 | void scan_import(CodeGen *g, ImportTableEntry *import); |
| 78 | 80 | void preview_use_decl(CodeGen *g, AstNode *node); |
| ... | ... | @@ -81,7 +83,7 @@ ZigFn *scope_fn_entry(Scope *scope); |
| 81 | 83 | ImportTableEntry *get_scope_import(Scope *scope); |
| 82 | 84 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); |
| 83 | 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 | 87 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); |
| 86 | 88 | ZigFn *create_fn(CodeGen *g, AstNode *proto_node); |
| 87 | 89 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); |
| ... | ... | @@ -222,6 +224,13 @@ enum ReqCompTime { |
| 222 | 224 | }; |
| 223 | 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 | 234 | Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, |
| 226 | 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 | 233 | return "ErrorType"; |
| 234 | 234 | case NodeTypeIfErrorExpr: |
| 235 | 235 | return "IfErrorExpr"; |
| 236 | case NodeTypeTestExpr: | |
| 237 | return "TestExpr"; | |
| 236 | case NodeTypeIfOptional: | |
| 237 | return "IfOptional"; | |
| 238 | 238 | case NodeTypeErrorSetDecl: |
| 239 | 239 | return "ErrorSetDecl"; |
| 240 | 240 | case NodeTypeCancel: |
| ... | ... | @@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { |
| 387 | 387 | if (node->data.if_err_expr.else_node) |
| 388 | 388 | return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); |
| 389 | 389 | return node->data.if_err_expr.then_node->type == NodeTypeBlock; |
| 390 | case NodeTypeTestExpr: | |
| 390 | case NodeTypeIfOptional: | |
| 391 | 391 | if (node->data.test_expr.else_node) |
| 392 | 392 | return statement_terminates_without_semicolon(node->data.test_expr.else_node); |
| 393 | 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 | 974 | } |
| 975 | 975 | break; |
| 976 | 976 | } |
| 977 | case NodeTypeTestExpr: | |
| 977 | case NodeTypeIfOptional: | |
| 978 | 978 | { |
| 979 | 979 | fprintf(ar->f, "if ("); |
| 980 | 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 | 222 | assert(chf->path != nullptr); |
| 223 | 223 | |
| 224 | 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 | 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 | 228 | if ((err = hash_file(chf->bin_digest, this_file, contents))) { |
| 234 | 229 | os_file_close(this_file); |
| 235 | 230 | return err; |
| ... | ... | @@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { |
| 351 | 346 | |
| 352 | 347 | // if the mtime matches we can trust the digest |
| 353 | 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 | 351 | fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); |
| 356 | 352 | os_file_close(ch->manifest_file); |
| 357 | 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 | 355 | if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) { |
| 366 | 356 | os_file_close(this_file); |
| 367 | 357 | } else { |
src/codegen.cpp+396-104| ... | ... | @@ -118,6 +118,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 118 | 118 | g->string_literals_table.init(16); |
| 119 | 119 | g->type_info_cache.init(32); |
| 120 | 120 | g->is_test_build = false; |
| 121 | g->is_single_threaded = false; | |
| 121 | 122 | buf_resize(&g->global_asm, 0); |
| 122 | 123 | |
| 123 | 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 | 314 | static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); |
| 314 | 315 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name); |
| 315 | 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 | 320 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { |
| 318 | 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 | 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 | 482 | static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 465 | 483 | if (fn_table_entry->llvm_value) |
| 466 | 484 | return fn_table_entry->llvm_value; |
| ... | ... | @@ -598,9 +616,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 598 | 616 | } else if (type_is_codegen_pointer(return_type)) { |
| 599 | 617 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 600 | 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 | 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 | 622 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias"); |
| 605 | 623 | } |
| 606 | 624 | init_gen_i = 1; |
| ... | ... | @@ -1903,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { |
| 1903 | 1921 | } |
| 1904 | 1922 | |
| 1905 | 1923 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| 1906 | assert(alignment > 0); | |
| 1907 | 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 | 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 | 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 | 1984 | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| 1968 | 1985 | ) { |
| 1969 | 1986 | switch (fn_walk->id) { |
| ... | ... | @@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2200 | 2217 | assert(variable); |
| 2201 | 2218 | assert(variable->value_ref); |
| 2202 | 2219 | |
| 2203 | if (!handle_is_ptr(variable->value->type)) { | |
| 2220 | if (!handle_is_ptr(variable->var_type)) { | |
| 2204 | 2221 | clear_debug_source_node(g); |
| 2205 | gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref, | |
| 2206 | variable->align_bytes, false); | |
| 2222 | gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), | |
| 2223 | variable->value_ref, variable->align_bytes, false); | |
| 2207 | 2224 | } |
| 2208 | 2225 | |
| 2209 | 2226 | if (variable->decl_node) { |
| ... | ... | @@ -2643,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2643 | 2660 | } else { |
| 2644 | 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 | 2684 | } else { |
| 2647 | 2685 | zig_unreachable(); |
| 2648 | 2686 | } |
| ... | ... | @@ -2961,7 +2999,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 2961 | 2999 | } |
| 2962 | 3000 | |
| 2963 | 3001 | static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, |
| 2964 | IrInstructionPtrCast *instruction) | |
| 3002 | IrInstructionPtrCastGen *instruction) | |
| 2965 | 3003 | { |
| 2966 | 3004 | ZigType *wanted_type = instruction->base.value.type; |
| 2967 | 3005 | if (!type_has_bits(wanted_type)) { |
| ... | ... | @@ -3149,11 +3187,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI |
| 3149 | 3187 | } |
| 3150 | 3188 | |
| 3151 | 3189 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 3152 | IrInstructionDeclVar *decl_var_instruction) | |
| 3190 | IrInstructionDeclVarGen *decl_var_instruction) | |
| 3153 | 3191 | { |
| 3154 | 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 | 3195 | return nullptr; |
| 3158 | 3196 | |
| 3159 | 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 | 3199 | |
| 3162 | 3200 | IrInstruction *init_value = decl_var_instruction->init_value; |
| 3163 | 3201 | |
| 3164 | bool have_init_expr = false; | |
| 3165 | ||
| 3166 | ConstExprValue *const_val = &init_value->value; | |
| 3167 | if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) | |
| 3168 | have_init_expr = true; | |
| 3202 | bool have_init_expr = !value_is_all_undef(&init_value->value); | |
| 3169 | 3203 | |
| 3170 | 3204 | if (have_init_expr) { |
| 3171 | assert(var->value->type == init_value->value.type); | |
| 3172 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, | |
| 3205 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, | |
| 3173 | 3206 | PtrLenSingle, var->align_bytes, 0, 0); |
| 3174 | 3207 | LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); |
| 3175 | 3208 | gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); |
| 3176 | } else { | |
| 3177 | bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); | |
| 3178 | if (want_safe) { | |
| 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 | } | |
| 3209 | } else if (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; | |
| 3211 | gen_undef_init(g, align_bytes, var->var_type, var->value_ref); | |
| 3192 | 3212 | } |
| 3193 | 3213 | |
| 3194 | 3214 | gen_var_debug_decl(g, var); |
| ... | ... | @@ -3225,21 +3245,81 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3225 | 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) { | |
| 3229 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); | |
| 3230 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | |
| 3248 | static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { | |
| 3249 | switch (const_val->data.x_array.special) { | |
| 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); | |
| 3233 | ZigType *ptr_type = instruction->ptr->value.type; | |
| 3264 | static bool value_is_all_undef(ConstExprValue *const_val) { | |
| 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 | 3317 | return nullptr; |
| 3238 | 3318 | } |
| 3239 | 3319 | |
| 3240 | 3320 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3241 | 3321 | ZigVar *var = instruction->var; |
| 3242 | if (type_has_bits(var->value->type)) { | |
| 3322 | if (type_has_bits(var->var_type)) { | |
| 3243 | 3323 | assert(var->value_ref); |
| 3244 | 3324 | return var->value_ref; |
| 3245 | 3325 | } else { |
| ... | ... | @@ -3553,7 +3633,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab |
| 3553 | 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 | 3638 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); |
| 3558 | 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 | 3796 | if (child_type->zero_bits) { |
| 3716 | 3797 | return maybe_handle; |
| 3717 | 3798 | } else { |
| 3718 | bool maybe_is_ptr = type_is_codegen_pointer(child_type); | |
| 3719 | if (maybe_is_ptr) { | |
| 3799 | bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; | |
| 3800 | if (is_scalar) { | |
| 3720 | 3801 | return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); |
| 3721 | 3802 | } else { |
| 3722 | 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 | 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, | |
| 3735 | IrInstructionUnwrapOptional *instruction) | |
| 3815 | static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, | |
| 3816 | IrInstructionOptionalUnwrapPtr *instruction) | |
| 3736 | 3817 | { |
| 3737 | ZigType *ptr_type = instruction->value->value.type; | |
| 3818 | ZigType *ptr_type = instruction->base_ptr->value.type; | |
| 3738 | 3819 | assert(ptr_type->id == ZigTypeIdPointer); |
| 3739 | 3820 | ZigType *maybe_type = ptr_type->data.pointer.child_type; |
| 3740 | 3821 | assert(maybe_type->id == ZigTypeIdOptional); |
| 3741 | 3822 | ZigType *child_type = maybe_type->data.maybe.child_type; |
| 3742 | LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); | |
| 3743 | LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); | |
| 3823 | LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); | |
| 3744 | 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 | 3826 | LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); |
| 3746 | 3827 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); |
| 3747 | 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 | 3836 | if (child_type->zero_bits) { |
| 3756 | 3837 | return nullptr; |
| 3757 | 3838 | } else { |
| 3758 | bool maybe_is_ptr = type_is_codegen_pointer(child_type); | |
| 3759 | if (maybe_is_ptr) { | |
| 3839 | bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; | |
| 3840 | if (is_scalar) { | |
| 3760 | 3841 | return maybe_ptr; |
| 3761 | 3842 | } else { |
| 3762 | 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 | 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 | 4259 | LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); |
| 4179 | 4260 | LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); |
| 4180 | 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 | 4270 | assert(maybe_type->id == ZigTypeIdOptional); |
| 4190 | 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 | 4274 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 4194 | 4275 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); |
| 4195 | 4276 | return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); |
| 4196 | 4277 | } |
| 4197 | 4278 | |
| 4198 | 4279 | assert(instruction->tmp_ptr != nullptr); |
| 4199 | assert(type_has_bits(instruction->type)); | |
| 4280 | assert(type_has_bits(child_type)); | |
| 4200 | 4281 | |
| 4201 | 4282 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 4202 | 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 | 4286 | LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); |
| 4206 | 4287 | LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); |
| ... | ... | @@ -4351,6 +4432,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst |
| 4351 | 4432 | assert(array_type->data.structure.is_slice); |
| 4352 | 4433 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 4353 | 4434 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 4435 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); | |
| 4354 | 4436 | |
| 4355 | 4437 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index; |
| 4356 | 4438 | assert(ptr_index != SIZE_MAX); |
| ... | ... | @@ -4540,12 +4622,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI |
| 4540 | 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) { | |
| 4544 | ZigType *ptr_type = instruction->value->value.type; | |
| 4625 | static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, | |
| 4626 | IrInstructionUnwrapErrCode *instruction) | |
| 4627 | { | |
| 4628 | ZigType *ptr_type = instruction->err_union->value.type; | |
| 4545 | 4629 | assert(ptr_type->id == ZigTypeIdPointer); |
| 4546 | 4630 | ZigType *err_union_type = ptr_type->data.pointer.child_type; |
| 4547 | 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 | 4633 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 4550 | 4634 | |
| 4551 | 4635 | if (type_has_bits(payload_type)) { |
| ... | ... | @@ -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 | 4650 | ZigType *ptr_type = instruction->value->value.type; |
| 4561 | 4651 | assert(ptr_type->id == ZigTypeIdPointer); |
| 4562 | 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 | 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 | 4662 | LLVMValueRef err_val; |
| 4573 | 4663 | if (type_has_bits(payload_type)) { |
| 4574 | 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 | 4697 | } |
| 4608 | 4698 | |
| 4609 | 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 | 4701 | return payload_val; |
| 4612 | 4702 | } |
| 4613 | 4703 | |
| ... | ... | @@ -5109,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, |
| 5109 | 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 | 5228 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 5113 | 5229 | AstNode *source_node = instruction->source_node; |
| 5114 | 5230 | Scope *scope = instruction->scope; |
| ... | ... | @@ -5148,6 +5264,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5148 | 5264 | case IrInstructionIdCUndef: |
| 5149 | 5265 | case IrInstructionIdEmbedFile: |
| 5150 | 5266 | case IrInstructionIdIntType: |
| 5267 | case IrInstructionIdVectorType: | |
| 5151 | 5268 | case IrInstructionIdMemberCount: |
| 5152 | 5269 | case IrInstructionIdMemberType: |
| 5153 | 5270 | case IrInstructionIdMemberName: |
| ... | ... | @@ -5184,12 +5301,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5184 | 5301 | case IrInstructionIdToBytes: |
| 5185 | 5302 | case IrInstructionIdEnumToInt: |
| 5186 | 5303 | case IrInstructionIdCheckRuntimeScope: |
| 5304 | case IrInstructionIdDeclVarSrc: | |
| 5305 | case IrInstructionIdPtrCastSrc: | |
| 5306 | case IrInstructionIdCmpxchgSrc: | |
| 5187 | 5307 | zig_unreachable(); |
| 5188 | 5308 | |
| 5309 | case IrInstructionIdDeclVarGen: | |
| 5310 | return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); | |
| 5189 | 5311 | case IrInstructionIdReturn: |
| 5190 | 5312 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| 5191 | case IrInstructionIdDeclVar: | |
| 5192 | return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction); | |
| 5193 | 5313 | case IrInstructionIdBinOp: |
| 5194 | 5314 | return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction); |
| 5195 | 5315 | case IrInstructionIdCast: |
| ... | ... | @@ -5220,8 +5340,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5220 | 5340 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 5221 | 5341 | case IrInstructionIdTestNonNull: |
| 5222 | 5342 | return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); |
| 5223 | case IrInstructionIdUnwrapOptional: | |
| 5224 | return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction); | |
| 5343 | case IrInstructionIdOptionalUnwrapPtr: | |
| 5344 | return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction); | |
| 5225 | 5345 | case IrInstructionIdClz: |
| 5226 | 5346 | return ir_render_clz(g, executable, (IrInstructionClz *)instruction); |
| 5227 | 5347 | case IrInstructionIdCtz: |
| ... | ... | @@ -5236,8 +5356,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5236 | 5356 | return ir_render_ref(g, executable, (IrInstructionRef *)instruction); |
| 5237 | 5357 | case IrInstructionIdErrName: |
| 5238 | 5358 | return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); |
| 5239 | case IrInstructionIdCmpxchg: | |
| 5240 | return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction); | |
| 5359 | case IrInstructionIdCmpxchgGen: | |
| 5360 | return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction); | |
| 5241 | 5361 | case IrInstructionIdFence: |
| 5242 | 5362 | return ir_render_fence(g, executable, (IrInstructionFence *)instruction); |
| 5243 | 5363 | case IrInstructionIdTruncate: |
| ... | ... | @@ -5278,8 +5398,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5278 | 5398 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 5279 | 5399 | case IrInstructionIdUnionInit: |
| 5280 | 5400 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); |
| 5281 | case IrInstructionIdPtrCast: | |
| 5282 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); | |
| 5401 | case IrInstructionIdPtrCastGen: | |
| 5402 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); | |
| 5283 | 5403 | case IrInstructionIdBitCast: |
| 5284 | 5404 | return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); |
| 5285 | 5405 | case IrInstructionIdWidenOrShorten: |
| ... | ... | @@ -5350,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5350 | 5470 | return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); |
| 5351 | 5471 | case IrInstructionIdBitReverse: |
| 5352 | 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 | 5478 | zig_unreachable(); |
| 5355 | 5479 | } |
| ... | ... | @@ -5377,6 +5501,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { |
| 5377 | 5501 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 5378 | 5502 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); |
| 5379 | 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 | 5508 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 5382 | 5509 | switch (parent->id) { |
| ... | ... | @@ -5387,6 +5514,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 5387 | 5514 | case ConstParentIdStruct: |
| 5388 | 5515 | return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, |
| 5389 | 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 | 5523 | case ConstParentIdArray: |
| 5391 | 5524 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 5392 | 5525 | parent->data.p_array.elem_index); |
| ... | ... | @@ -5402,7 +5535,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 5402 | 5535 | |
| 5403 | 5536 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { |
| 5404 | 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 | 5539 | LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); |
| 5407 | 5540 | |
| 5408 | 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 | 5560 | } |
| 5428 | 5561 | |
| 5429 | 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 | 5564 | LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); |
| 5432 | 5565 | |
| 5433 | 5566 | ZigType *u32 = g->builtin_types.entry_u32; |
| ... | ... | @@ -5438,8 +5571,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 5438 | 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 | 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 | 5612 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); |
| 5444 | 5613 | |
| 5445 | 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 | 5678 | } |
| 5510 | 5679 | case ZigTypeIdArray: |
| 5511 | 5680 | zig_panic("TODO bit pack an array"); |
| 5681 | case ZigTypeIdVector: | |
| 5682 | zig_panic("TODO bit pack a vector"); | |
| 5512 | 5683 | case ZigTypeIdUnion: |
| 5513 | 5684 | zig_panic("TODO bit pack a union"); |
| 5514 | 5685 | case ZigTypeIdStruct: |
| ... | ... | @@ -5609,6 +5780,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con |
| 5609 | 5780 | render_const_val_global(g, const_val, ""); |
| 5610 | 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 | 5840 | case ConstPtrSpecialHardCodedAddr: |
| 5613 | 5841 | { |
| 5614 | 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 | 5849 | } |
| 5622 | 5850 | case ConstPtrSpecialFunction: |
| 5623 | 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 | 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 | 5863 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { |
| 5629 | 5864 | Error err; |
| 5630 | 5865 | |
| ... | ... | @@ -5644,9 +5879,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5644 | 5879 | case ZigTypeIdInt: |
| 5645 | 5880 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); |
| 5646 | 5881 | case ZigTypeIdErrorSet: |
| 5647 | assert(const_val->data.x_err_set != nullptr); | |
| 5648 | return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, | |
| 5649 | const_val->data.x_err_set->value, false); | |
| 5882 | return gen_const_val_err_set(g, const_val, name); | |
| 5650 | 5883 | case ZigTypeIdFloat: |
| 5651 | 5884 | switch (type_entry->data.floating.bit_count) { |
| 5652 | 5885 | case 16: |
| ... | ... | @@ -5680,6 +5913,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5680 | 5913 | return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); |
| 5681 | 5914 | } else if (type_is_codegen_pointer(child_type)) { |
| 5682 | 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 | 5918 | } else { |
| 5684 | 5919 | LLVMValueRef child_val; |
| 5685 | 5920 | LLVMValueRef maybe_val; |
| ... | ... | @@ -5816,7 +6051,33 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5816 | 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 | 6081 | case ZigTypeIdUnion: |
| 5821 | 6082 | { |
| 5822 | 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 | 6175 | ZigType *err_set_type = type_entry->data.error_union.err_set_type; |
| 5915 | 6176 | if (!type_has_bits(payload_type)) { |
| 5916 | 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 | 6180 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 5919 | 6181 | } else if (!type_has_bits(err_set_type)) { |
| 5920 | 6182 | assert(type_has_bits(payload_type)); |
| ... | ... | @@ -5923,8 +6185,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5923 | 6185 | LLVMValueRef err_tag_value; |
| 5924 | 6186 | LLVMValueRef err_payload_value; |
| 5925 | 6187 | bool make_unnamed_struct; |
| 5926 | if (const_val->data.x_err_union.err) { | |
| 5927 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); | |
| 6188 | ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; | |
| 6189 | if (err_set != nullptr) { | |
| 6190 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false); | |
| 5928 | 6191 | err_payload_value = LLVMConstNull(payload_type->type_ref); |
| 5929 | 6192 | make_unnamed_struct = false; |
| 5930 | 6193 | } else { |
| ... | ... | @@ -6130,10 +6393,13 @@ static void do_code_gen(CodeGen *g) { |
| 6130 | 6393 | TldVar *tld_var = g->global_vars.at(i); |
| 6131 | 6394 | ZigVar *var = tld_var->var; |
| 6132 | 6395 | |
| 6133 | if (var->value->type->id == ZigTypeIdComptimeFloat) { | |
| 6396 | if (var->var_type->id == ZigTypeIdComptimeFloat) { | |
| 6134 | 6397 | // Generate debug info for it but that's it. |
| 6135 | ConstExprValue *const_val = var->value; | |
| 6398 | ConstExprValue *const_val = var->const_value; | |
| 6136 | 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 | 6403 | ZigType *var_type = g->builtin_types.entry_f128; |
| 6138 | 6404 | ConstExprValue coerced_value; |
| 6139 | 6405 | coerced_value.special = ConstValSpecialStatic; |
| ... | ... | @@ -6144,10 +6410,13 @@ static void do_code_gen(CodeGen *g) { |
| 6144 | 6410 | continue; |
| 6145 | 6411 | } |
| 6146 | 6412 | |
| 6147 | if (var->value->type->id == ZigTypeIdComptimeInt) { | |
| 6413 | if (var->var_type->id == ZigTypeIdComptimeInt) { | |
| 6148 | 6414 | // Generate debug info for it but that's it. |
| 6149 | ConstExprValue *const_val = var->value; | |
| 6415 | ConstExprValue *const_val = var->const_value; | |
| 6150 | 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 | 6420 | size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); |
| 6152 | 6421 | if (bits_needed < 8) { |
| 6153 | 6422 | bits_needed = 8; |
| ... | ... | @@ -6158,7 +6427,7 @@ static void do_code_gen(CodeGen *g) { |
| 6158 | 6427 | continue; |
| 6159 | 6428 | } |
| 6160 | 6429 | |
| 6161 | if (!type_has_bits(var->value->type)) | |
| 6430 | if (!type_has_bits(var->var_type)) | |
| 6162 | 6431 | continue; |
| 6163 | 6432 | |
| 6164 | 6433 | assert(var->decl_node); |
| ... | ... | @@ -6167,9 +6436,9 @@ static void do_code_gen(CodeGen *g) { |
| 6167 | 6436 | if (var->linkage == VarLinkageExternal) { |
| 6168 | 6437 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); |
| 6169 | 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 | 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 | 6442 | // TODO debug info for the extern variable |
| 6174 | 6443 | |
| 6175 | 6444 | LLVMSetLinkage(global_value, LLVMExternalLinkage); |
| ... | ... | @@ -6180,9 +6449,9 @@ static void do_code_gen(CodeGen *g) { |
| 6180 | 6449 | } else { |
| 6181 | 6450 | bool exported = (var->linkage == VarLinkageExport); |
| 6182 | 6451 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); |
| 6183 | render_const_val(g, var->value, mangled_name); | |
| 6184 | render_const_val_global(g, var->value, mangled_name); | |
| 6185 | global_value = var->value->global_refs->llvm_global; | |
| 6452 | render_const_val(g, var->const_value, mangled_name); | |
| 6453 | render_const_val_global(g, var->const_value, mangled_name); | |
| 6454 | global_value = var->const_value->global_refs->llvm_global; | |
| 6186 | 6455 | |
| 6187 | 6456 | if (exported) { |
| 6188 | 6457 | LLVMSetLinkage(global_value, LLVMExternalLinkage); |
| ... | ... | @@ -6194,8 +6463,10 @@ static void do_code_gen(CodeGen *g) { |
| 6194 | 6463 | LLVMSetAlignment(global_value, var->align_bytes); |
| 6195 | 6464 | |
| 6196 | 6465 | // TODO debug info for function pointers |
| 6197 | if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) { | |
| 6198 | gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type); | |
| 6466 | // Here we use const_value->type because that's the type of the llvm global, | |
| 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 | 6472 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| ... | ... | @@ -6249,6 +6520,7 @@ static void do_code_gen(CodeGen *g) { |
| 6249 | 6520 | IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); |
| 6250 | 6521 | LLVMValueRef *slot; |
| 6251 | 6522 | ZigType *slot_type = instruction->value.type; |
| 6523 | uint32_t alignment_bytes = 0; | |
| 6252 | 6524 | if (instruction->id == IrInstructionIdCast) { |
| 6253 | 6525 | IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; |
| 6254 | 6526 | slot = &cast_instruction->tmp_ptr; |
| ... | ... | @@ -6281,13 +6553,17 @@ static void do_code_gen(CodeGen *g) { |
| 6281 | 6553 | } else if (instruction->id == IrInstructionIdErrWrapCode) { |
| 6282 | 6554 | IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; |
| 6283 | 6555 | slot = &err_wrap_code_instruction->tmp_ptr; |
| 6284 | } else if (instruction->id == IrInstructionIdCmpxchg) { | |
| 6285 | IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction; | |
| 6556 | } else if (instruction->id == IrInstructionIdCmpxchgGen) { | |
| 6557 | IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; | |
| 6286 | 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 | 6563 | } else { |
| 6288 | 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 | 6569 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| ... | ... | @@ -6304,12 +6580,12 @@ static void do_code_gen(CodeGen *g) { |
| 6304 | 6580 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 6305 | 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 | 6584 | continue; |
| 6309 | 6585 | } |
| 6310 | 6586 | if (ir_get_var_is_comptime(var)) |
| 6311 | 6587 | continue; |
| 6312 | switch (type_requires_comptime(g, var->value->type)) { | |
| 6588 | switch (type_requires_comptime(g, var->var_type)) { | |
| 6313 | 6589 | case ReqCompTimeInvalid: |
| 6314 | 6590 | zig_unreachable(); |
| 6315 | 6591 | case ReqCompTimeYes: |
| ... | ... | @@ -6319,11 +6595,11 @@ static void do_code_gen(CodeGen *g) { |
| 6319 | 6595 | } |
| 6320 | 6596 | |
| 6321 | 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 | 6600 | var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| 6325 | 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 | 6604 | } else if (is_c_abi) { |
| 6329 | 6605 | fn_walk_var.data.vars.var = var; |
| ... | ... | @@ -6333,16 +6609,16 @@ static void do_code_gen(CodeGen *g) { |
| 6333 | 6609 | ZigType *gen_type; |
| 6334 | 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 | 6613 | if (gen_info->is_byval) { |
| 6338 | gen_type = var->value->type; | |
| 6614 | gen_type = var->var_type; | |
| 6339 | 6615 | } else { |
| 6340 | 6616 | gen_type = gen_info->type; |
| 6341 | 6617 | } |
| 6342 | 6618 | var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index); |
| 6343 | 6619 | } else { |
| 6344 | gen_type = var->value->type; | |
| 6345 | var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); | |
| 6620 | gen_type = var->var_type; | |
| 6621 | var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); | |
| 6346 | 6622 | } |
| 6347 | 6623 | if (var->decl_node) { |
| 6348 | 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 | 7018 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); |
| 6743 | 7019 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 6744 | 7020 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 7021 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); | |
| 6745 | 7022 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); |
| 6746 | 7023 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); |
| 6747 | 7024 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); |
| ... | ... | @@ -6967,6 +7244,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 6967 | 7244 | " ArgTuple: void,\n" |
| 6968 | 7245 | " Opaque: void,\n" |
| 6969 | 7246 | " Promise: Promise,\n" |
| 7247 | " Vector: Vector,\n" | |
| 6970 | 7248 | "\n\n" |
| 6971 | 7249 | " pub const Int = struct {\n" |
| 6972 | 7250 | " is_signed: bool,\n" |
| ... | ... | @@ -7085,6 +7363,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7085 | 7363 | " child: ?type,\n" |
| 7086 | 7364 | " };\n" |
| 7087 | 7365 | "\n" |
| 7366 | " pub const Vector = struct {\n" | |
| 7367 | " len: u32,\n" | |
| 7368 | " child: type,\n" | |
| 7369 | " };\n" | |
| 7370 | "\n" | |
| 7088 | 7371 | " pub const Definition = struct {\n" |
| 7089 | 7372 | " name: []const u8,\n" |
| 7090 | 7373 | " is_pub: bool,\n" |
| ... | ... | @@ -7153,6 +7436,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7153 | 7436 | buf_appendf(contents, "pub const endian = %s;\n", endian_str); |
| 7154 | 7437 | } |
| 7155 | 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 | 7440 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); |
| 7157 | 7441 | buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch); |
| 7158 | 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 | 7471 | cache_buf(&cache_hash, compiler_id); |
| 7188 | 7472 | cache_int(&cache_hash, g->build_mode); |
| 7189 | 7473 | cache_bool(&cache_hash, g->is_test_build); |
| 7474 | cache_bool(&cache_hash, g->is_single_threaded); | |
| 7190 | 7475 | cache_int(&cache_hash, g->zig_target.arch.arch); |
| 7191 | 7476 | cache_int(&cache_hash, g->zig_target.arch.sub_arch); |
| 7192 | 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 | 7743 | ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; |
| 7459 | 7744 | this_val->special = ConstValSpecialStatic; |
| 7460 | 7745 | this_val->type = struct_type; |
| 7461 | this_val->data.x_struct.parent.id = ConstParentIdArray; | |
| 7462 | this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array; | |
| 7463 | this_val->data.x_struct.parent.data.p_array.elem_index = i; | |
| 7746 | this_val->parent.id = ConstParentIdArray; | |
| 7747 | this_val->parent.data.p_array.array_val = test_fn_array; | |
| 7748 | this_val->parent.data.p_array.elem_index = i; | |
| 7464 | 7749 | this_val->data.x_struct.fields = create_const_vals(2); |
| 7465 | 7750 | |
| 7466 | 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 | 7941 | case ZigTypeIdArray: |
| 7657 | 7942 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); |
| 7658 | 7943 | return; |
| 7944 | case ZigTypeIdVector: | |
| 7945 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type); | |
| 7946 | return; | |
| 7659 | 7947 | case ZigTypeIdOptional: |
| 7660 | 7948 | prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); |
| 7661 | 7949 | return; |
| ... | ... | @@ -7787,6 +8075,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu |
| 7787 | 8075 | buf_appendf(out_buf, "%s", buf_ptr(child_buf)); |
| 7788 | 8076 | return; |
| 7789 | 8077 | } |
| 8078 | case ZigTypeIdVector: | |
| 8079 | zig_panic("TODO implement get_c_type for vector types"); | |
| 7790 | 8080 | case ZigTypeIdErrorUnion: |
| 7791 | 8081 | case ZigTypeIdErrorSet: |
| 7792 | 8082 | case ZigTypeIdFn: |
| ... | ... | @@ -7952,6 +8242,7 @@ static void gen_h_file(CodeGen *g) { |
| 7952 | 8242 | case ZigTypeIdOptional: |
| 7953 | 8243 | case ZigTypeIdFn: |
| 7954 | 8244 | case ZigTypeIdPromise: |
| 8245 | case ZigTypeIdVector: | |
| 7955 | 8246 | zig_unreachable(); |
| 7956 | 8247 | case ZigTypeIdEnum: |
| 7957 | 8248 | if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { |
| ... | ... | @@ -8099,6 +8390,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 8099 | 8390 | cache_bool(ch, g->is_static); |
| 8100 | 8391 | cache_bool(ch, g->strip_debug_symbols); |
| 8101 | 8392 | cache_bool(ch, g->is_test_build); |
| 8393 | cache_bool(ch, g->is_single_threaded); | |
| 8102 | 8394 | cache_bool(ch, g->is_native_target); |
| 8103 | 8395 | cache_bool(ch, g->linker_rdynamic); |
| 8104 | 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 | 167 | ZigType *dest_type, IrInstruction *dest_type_src); |
| 168 | 168 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); |
| 169 | 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 | 173 | static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { |
| 172 | 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 | 180 | case ConstPtrSpecialRef: |
| 179 | 181 | result = const_val->data.x_ptr.data.ref.pointee; |
| 180 | 182 | break; |
| 181 | case ConstPtrSpecialBaseArray: | |
| 182 | expand_undef_array(g, 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[ | |
| 184 | const_val->data.x_ptr.data.base_array.elem_index]; | |
| 183 | case ConstPtrSpecialBaseArray: { | |
| 184 | ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val; | |
| 185 | expand_undef_array(g, array_val); | |
| 186 | result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; | |
| 185 | 187 | break; |
| 188 | } | |
| 186 | 189 | case ConstPtrSpecialBaseStruct: |
| 187 | 190 | result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ |
| 188 | 191 | const_val->data.x_ptr.data.base_struct.field_index]; |
| 189 | 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 | 205 | case ConstPtrSpecialHardCodedAddr: |
| 191 | 206 | zig_unreachable(); |
| 192 | 207 | case ConstPtrSpecialDiscard: |
| ... | ... | @@ -198,6 +213,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c |
| 198 | 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 | 221 | static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { |
| 202 | 222 | if (a == b) |
| 203 | 223 | return true; |
| ... | ... | @@ -208,15 +228,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { |
| 208 | 228 | if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) |
| 209 | 229 | return true; |
| 210 | 230 | |
| 211 | return false; | |
| 212 | } | |
| 231 | if (is_opt_err_set(a) && is_opt_err_set(b)) | |
| 232 | return true; | |
| 213 | 233 | |
| 214 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { | |
| 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; | |
| 234 | return false; | |
| 220 | 235 | } |
| 221 | 236 | |
| 222 | 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 | 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 | 331 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) { |
| 309 | 332 | return IrInstructionIdCondBr; |
| 310 | 333 | } |
| ... | ... | @@ -337,10 +360,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { |
| 337 | 360 | return IrInstructionIdBinOp; |
| 338 | 361 | } |
| 339 | 362 | |
| 340 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { | |
| 341 | return IrInstructionIdDeclVar; | |
| 342 | } | |
| 343 | ||
| 344 | 363 | static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { |
| 345 | 364 | return IrInstructionIdExport; |
| 346 | 365 | } |
| ... | ... | @@ -449,8 +468,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { |
| 449 | 468 | return IrInstructionIdTestNonNull; |
| 450 | 469 | } |
| 451 | 470 | |
| 452 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) { | |
| 453 | return IrInstructionIdUnwrapOptional; | |
| 471 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) { | |
| 472 | return IrInstructionIdOptionalUnwrapPtr; | |
| 454 | 473 | } |
| 455 | 474 | |
| 456 | 475 | static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { |
| ... | ... | @@ -517,8 +536,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) { |
| 517 | 536 | return IrInstructionIdEmbedFile; |
| 518 | 537 | } |
| 519 | 538 | |
| 520 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) { | |
| 521 | return IrInstructionIdCmpxchg; | |
| 539 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) { | |
| 540 | return IrInstructionIdCmpxchgSrc; | |
| 541 | } | |
| 542 | ||
| 543 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) { | |
| 544 | return IrInstructionIdCmpxchgGen; | |
| 522 | 545 | } |
| 523 | 546 | |
| 524 | 547 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { |
| ... | ... | @@ -565,6 +588,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) { |
| 565 | 588 | return IrInstructionIdIntType; |
| 566 | 589 | } |
| 567 | 590 | |
| 591 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { | |
| 592 | return IrInstructionIdVectorType; | |
| 593 | } | |
| 594 | ||
| 568 | 595 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 569 | 596 | return IrInstructionIdBoolNot; |
| 570 | 597 | } |
| ... | ... | @@ -649,8 +676,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) |
| 649 | 676 | return IrInstructionIdTestComptime; |
| 650 | 677 | } |
| 651 | 678 | |
| 652 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) { | |
| 653 | return IrInstructionIdPtrCast; | |
| 679 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) { | |
| 680 | return IrInstructionIdPtrCastSrc; | |
| 681 | } | |
| 682 | ||
| 683 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { | |
| 684 | return IrInstructionIdPtrCastGen; | |
| 654 | 685 | } |
| 655 | 686 | |
| 656 | 687 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { |
| ... | ... | @@ -869,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop |
| 869 | 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 | 911 | template<typename T> |
| 873 | 912 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 874 | 913 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -915,7 +954,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so |
| 915 | 954 | ir_ref_instruction(condition, irb->current_basic_block); |
| 916 | 955 | ir_ref_bb(then_block); |
| 917 | 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 | 959 | return &cond_br_instruction->base; |
| 921 | 960 | } |
| ... | ... | @@ -931,16 +970,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou |
| 931 | 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 | 973 | static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 945 | 974 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 946 | 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 | 1217 | call_instruction->async_allocator = async_allocator; |
| 1189 | 1218 | call_instruction->new_stack = new_stack; |
| 1190 | 1219 | |
| 1191 | if (fn_ref) | |
| 1192 | ir_ref_instruction(fn_ref, irb->current_basic_block); | |
| 1220 | if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); | |
| 1193 | 1221 | for (size_t i = 0; i < arg_count; i += 1) |
| 1194 | 1222 | ir_ref_instruction(args[i], irb->current_basic_block); |
| 1195 | if (async_allocator) | |
| 1196 | ir_ref_instruction(async_allocator, irb->current_basic_block); | |
| 1197 | if (new_stack != nullptr) | |
| 1198 | ir_ref_instruction(new_stack, irb->current_basic_block); | |
| 1223 | if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block); | |
| 1224 | if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); | |
| 1199 | 1225 | |
| 1200 | 1226 | return &call_instruction->base; |
| 1201 | 1227 | } |
| ... | ... | @@ -1280,7 +1306,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, |
| 1280 | 1306 | container_init_list_instruction->item_count = item_count; |
| 1281 | 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 | 1310 | for (size_t i = 0; i < item_count; i += 1) { |
| 1285 | 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 | 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 | 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 | 1388 | decl_var_instruction->base.value.special = ConstValSpecialStatic; |
| 1363 | 1389 | decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; |
| 1364 | 1390 | decl_var_instruction->var = var; |
| ... | ... | @@ -1366,13 +1392,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s |
| 1366 | 1392 | decl_var_instruction->align_value = align_value; |
| 1367 | 1393 | decl_var_instruction->init_value = init_value; |
| 1368 | 1394 | |
| 1369 | if (var_type) ir_ref_instruction(var_type, irb->current_basic_block); | |
| 1370 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); | |
| 1395 | if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); | |
| 1396 | if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); | |
| 1371 | 1397 | ir_ref_instruction(init_value, irb->current_basic_block); |
| 1372 | 1398 | |
| 1373 | 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 | 1417 | static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1377 | 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 | 1583 | return &instruction->base; |
| 1543 | 1584 | } |
| 1544 | 1585 | |
| 1545 | static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, | |
| 1546 | bool safety_check_on) | |
| 1586 | static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1587 | IrInstruction *base_ptr, bool safety_check_on) | |
| 1547 | 1588 | { |
| 1548 | IrInstructionUnwrapOptional *instruction = ir_build_instruction<IrInstructionUnwrapOptional>(irb, scope, source_node); | |
| 1549 | instruction->value = value; | |
| 1589 | IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction<IrInstructionOptionalUnwrapPtr>(irb, scope, source_node); | |
| 1590 | instruction->base_ptr = base_ptr; | |
| 1550 | 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 | 1595 | return &instruction->base; |
| 1555 | 1596 | } |
| ... | ... | @@ -1765,13 +1806,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode |
| 1765 | 1806 | return &instruction->base; |
| 1766 | 1807 | } |
| 1767 | 1808 | |
| 1768 | static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, | |
| 1769 | IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, | |
| 1809 | static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1810 | IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, | |
| 1770 | 1811 | IrInstruction *success_order_value, IrInstruction *failure_order_value, |
| 1771 | bool is_weak, | |
| 1772 | ZigType *type, AtomicOrder success_order, AtomicOrder failure_order) | |
| 1812 | bool is_weak) | |
| 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 | 1815 | instruction->type_value = type_value; |
| 1776 | 1816 | instruction->ptr = ptr; |
| 1777 | 1817 | instruction->cmp_value = cmp_value; |
| ... | ... | @@ -1779,16 +1819,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so |
| 1779 | 1819 | instruction->success_order_value = success_order_value; |
| 1780 | 1820 | instruction->failure_order_value = failure_order_value; |
| 1781 | 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 | 1824 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 1788 | 1825 | ir_ref_instruction(cmp_value, irb->current_basic_block); |
| 1789 | 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); | |
| 1791 | if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block); | |
| 1827 | ir_ref_instruction(success_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 | 1850 | return &instruction->base; |
| 1794 | 1851 | } |
| ... | ... | @@ -1909,6 +1966,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 1909 | 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 | 1982 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 1913 | 1983 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 1914 | 1984 | instruction->value = value; |
| ... | ... | @@ -2060,12 +2130,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s |
| 2060 | 2130 | } |
| 2061 | 2131 | |
| 2062 | 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 | 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 | 2140 | return &instruction->base; |
| 2071 | 2141 | } |
| ... | ... | @@ -2115,20 +2185,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo |
| 2115 | 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 | 2189 | IrInstruction *dest_type, IrInstruction *ptr) |
| 2120 | 2190 | { |
| 2121 | IrInstructionPtrCast *instruction = ir_build_instruction<IrInstructionPtrCast>( | |
| 2191 | IrInstructionPtrCastSrc *instruction = ir_build_instruction<IrInstructionPtrCastSrc>( | |
| 2122 | 2192 | irb, scope, source_node); |
| 2123 | 2193 | instruction->dest_type = dest_type; |
| 2124 | 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 | 2197 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 2128 | 2198 | |
| 2129 | 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 | 2215 | static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2133 | 2216 | IrInstruction *dest_type, IrInstruction *value) |
| 2134 | 2217 | { |
| ... | ... | @@ -2747,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, |
| 2747 | 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 | 2861 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2751 | 2862 | results[ReturnKindUnconditional] = 0; |
| 2752 | 2863 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2807,10 +2918,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 2807 | 2918 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; |
| 2808 | 2919 | IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); |
| 2809 | 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 | 2924 | is_noreturn = true; |
| 2812 | 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 | 3179 | variable_entry->mem_slot_index = SIZE_MAX; |
| 3066 | 3180 | variable_entry->is_comptime = is_comptime; |
| 3067 | 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 | 3184 | if (is_comptime != nullptr) { |
| 3071 | 3185 | is_comptime->ref_count += 1; |
| ... | ... | @@ -3080,20 +3194,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 3080 | 3194 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3081 | 3195 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 3082 | 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 | 3198 | } else { |
| 3085 | 3199 | ZigType *type; |
| 3086 | 3200 | if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { |
| 3087 | 3201 | add_node_error(codegen, node, |
| 3088 | 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 | 3204 | } else { |
| 3091 | 3205 | Tld *tld = find_decl(codegen, parent_scope, name); |
| 3092 | 3206 | if (tld != nullptr) { |
| 3093 | 3207 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3094 | 3208 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 3095 | 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 | 3270 | scope_block->incoming_blocks = &incoming_blocks; |
| 3157 | 3271 | scope_block->incoming_values = &incoming_values; |
| 3158 | 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 | 3277 | bool is_continuation_unreachable = false; |
| ... | ... | @@ -3174,9 +3289,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3174 | 3289 | // defer starts a new scope |
| 3175 | 3290 | child_scope = statement_node->data.defer.child_scope; |
| 3176 | 3291 | assert(child_scope); |
| 3177 | } else if (statement_value->id == IrInstructionIdDeclVar) { | |
| 3292 | } else if (statement_value->id == IrInstructionIdDeclVarSrc) { | |
| 3178 | 3293 | // variable declarations start a new scope |
| 3179 | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; | |
| 3294 | IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value; | |
| 3180 | 3295 | child_scope = decl_var_instruction->var->child_scope; |
| 3181 | 3296 | } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) { |
| 3182 | 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 | 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 | 3450 | assert(node->type == NodeTypeBinOpExpr); |
| 3336 | 3451 | |
| 3337 | 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 | 3480 | ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); |
| 3366 | 3481 | |
| 3367 | 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 | 3484 | IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); |
| 3370 | 3485 | IrBasicBlock *after_ok_block = irb->current_basic_block; |
| 3371 | 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 | 3598 | case BinOpTypeMergeErrorSets: |
| 3484 | 3599 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); |
| 3485 | 3600 | case BinOpTypeUnwrapOptional: |
| 3486 | return ir_gen_maybe_ok_or(irb, scope, node); | |
| 3601 | return ir_gen_orelse(irb, scope, node); | |
| 3487 | 3602 | case BinOpTypeErrorUnion: |
| 3488 | 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 | 3657 | buf_ptr(variable_name))); |
| 3543 | 3658 | return irb->codegen->invalid_instruction; |
| 3544 | 3659 | } |
| 3660 | assert(err == ErrorPrimitiveTypeNotFound); | |
| 3545 | 3661 | } else { |
| 3546 | 3662 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); |
| 3547 | 3663 | if (lval == LValPtr) { |
| ... | ... | @@ -3904,9 +4020,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 3904 | 4020 | if (arg5_value == irb->codegen->invalid_instruction) |
| 3905 | 4021 | return arg5_value; |
| 3906 | 4022 | |
| 3907 | IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value, | |
| 3908 | arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), | |
| 3909 | nullptr, AtomicOrderUnordered, AtomicOrderUnordered); | |
| 4023 | IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, | |
| 4024 | arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); | |
| 3910 | 4025 | return ir_lval_wrap(irb, scope, cmpxchg, lval); |
| 3911 | 4026 | } |
| 3912 | 4027 | case BuiltinFnIdFence: |
| ... | ... | @@ -4169,6 +4284,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4169 | 4284 | IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); |
| 4170 | 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 | 4302 | case BuiltinFnIdMemcpy: |
| 4173 | 4303 | { |
| 4174 | 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 | 4476 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4347 | 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 | 4480 | return ir_lval_wrap(irb, scope, ptr_cast, lval); |
| 4351 | 4481 | } |
| 4352 | 4482 | case BuiltinFnIdBitCast: |
| ... | ... | @@ -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 | 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 | 4924 | |
| 4794 | 4925 | IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); |
| 4795 | 4926 | if (condition == irb->codegen->invalid_instruction) |
| 4796 | return condition; | |
| 4927 | return irb->codegen->invalid_instruction; | |
| 4797 | 4928 | |
| 4798 | 4929 | IrInstruction *is_comptime; |
| 4799 | 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 | 4947 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); |
| 4817 | 4948 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); |
| 4818 | 4949 | if (then_expr_result == irb->codegen->invalid_instruction) |
| 4819 | return then_expr_result; | |
| 4950 | return irb->codegen->invalid_instruction; | |
| 4820 | 4951 | IrBasicBlock *after_then_block = irb->current_basic_block; |
| 4821 | 4952 | if (!instr_is_unreachable(then_expr_result)) |
| 4822 | 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 | 4957 | if (else_node) { |
| 4827 | 4958 | else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); |
| 4828 | 4959 | if (else_expr_result == irb->codegen->invalid_instruction) |
| 4829 | return else_expr_result; | |
| 4960 | return irb->codegen->invalid_instruction; | |
| 4830 | 4961 | } else { |
| 4831 | 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 | 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 | 5062 | LVal lval) |
| 4932 | 5063 | { |
| 4933 | 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 | 5184 | ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); |
| 5054 | 5185 | ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, |
| 5055 | 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 | 5188 | // is inside var->child_scope |
| 5058 | 5189 | |
| 5059 | 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 | 5192 | add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); |
| 5062 | 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 | 5215 | if (init_value == irb->codegen->invalid_instruction) |
| 5085 | 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 | 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 | 5271 | err_val_ptr, false); |
| 5141 | 5272 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 5142 | 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 | 5277 | ZigList<IrInstruction *> incoming_values = {0}; |
| ... | ... | @@ -5180,7 +5311,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 5180 | 5311 | true, false, false, is_comptime); |
| 5181 | 5312 | Scope *err_scope = err_var->child_scope; |
| 5182 | 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 | 5316 | IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); |
| 5186 | 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 | 5351 | } |
| 5221 | 5352 | |
| 5222 | 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 | 5355 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 5225 | 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 | 5359 | ZigList<IrInstruction *> incoming_values = {0}; |
| 5229 | 5360 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| ... | ... | @@ -5380,7 +5511,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5380 | 5511 | Scope *child_scope = elem_var->child_scope; |
| 5381 | 5512 | |
| 5382 | 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 | 5515 | IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); |
| 5385 | 5516 | |
| 5386 | 5517 | AstNode *index_var_source_node; |
| ... | ... | @@ -5398,7 +5529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5398 | 5529 | IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); |
| 5399 | 5530 | IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); |
| 5400 | 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 | 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 | 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) { | |
| 5626 | assert(node->type == NodeTypeTestExpr); | |
| 5756 | static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 5757 | assert(node->type == NodeTypeIfOptional); | |
| 5627 | 5758 | |
| 5628 | 5759 | Buf *var_symbol = node->data.test_expr.var_symbol; |
| 5629 | 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 | 5792 | ZigVar *var = ir_create_var(irb, node, subexpr_scope, |
| 5662 | 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 | 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 | 5798 | var_scope = var->child_scope; |
| 5668 | 5799 | } else { |
| 5669 | 5800 | var_scope = subexpr_scope; |
| ... | ... | @@ -5738,7 +5869,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 5738 | 5869 | |
| 5739 | 5870 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); |
| 5740 | 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 | 5873 | var_scope = var->child_scope; |
| 5743 | 5874 | } else { |
| 5744 | 5875 | var_scope = subexpr_scope; |
| ... | ... | @@ -5763,7 +5894,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 5763 | 5894 | err_symbol, is_const, is_const, is_shadowable, is_comptime); |
| 5764 | 5895 | |
| 5765 | 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 | 5898 | err_var_scope = var->child_scope; |
| 5768 | 5899 | } else { |
| 5769 | 5900 | err_var_scope = subexpr_scope; |
| ... | ... | @@ -5818,7 +5949,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 5818 | 5949 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); |
| 5819 | 5950 | } |
| 5820 | 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 | 5953 | } else { |
| 5823 | 5954 | child_scope = scope; |
| 5824 | 5955 | } |
| ... | ... | @@ -6228,7 +6359,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) |
| 6228 | 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 | 6363 | assert(node->type == NodeTypeUnwrapErrorExpr); |
| 6233 | 6364 | |
| 6234 | 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 | 6373 | add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); |
| 6243 | 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 | 6407 | is_const, is_const, is_shadowable, is_comptime); |
| 6277 | 6408 | err_scope = var->child_scope; |
| 6278 | 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 | 6411 | } else { |
| 6281 | 6412 | err_scope = parent_scope; |
| 6282 | 6413 | } |
| ... | ... | @@ -6312,7 +6443,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o |
| 6312 | 6443 | ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; |
| 6313 | 6444 | if (need_comma) |
| 6314 | 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 | 6448 | return true; |
| 6317 | 6449 | } |
| 6318 | 6450 | |
| ... | ... | @@ -6562,7 +6694,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode |
| 6562 | 6694 | IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 |
| 6563 | 6695 | |
| 6564 | 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 | 6698 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); |
| 6567 | 6699 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6568 | 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 | 6772 | get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); |
| 6641 | 6773 | |
| 6642 | 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 | 6776 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); |
| 6645 | 6777 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6646 | 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 | 6888 | IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); |
| 6757 | 6889 | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); |
| 6758 | 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 | 6892 | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); |
| 6761 | 6893 | ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); |
| 6762 | 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 | 7182 | if (maybe_ptr == irb->codegen->invalid_instruction) |
| 7051 | 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 | 7186 | if (lval == LValPtr) |
| 7055 | 7187 | return unwrapped_ptr; |
| 7056 | 7188 | |
| ... | ... | @@ -7074,8 +7206,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7074 | 7206 | return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); |
| 7075 | 7207 | case NodeTypeIfErrorExpr: |
| 7076 | 7208 | return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); |
| 7077 | case NodeTypeTestExpr: | |
| 7078 | return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); | |
| 7209 | case NodeTypeIfOptional: | |
| 7210 | return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); | |
| 7079 | 7211 | case NodeTypeSwitchExpr: |
| 7080 | 7212 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); |
| 7081 | 7213 | case NodeTypeCompTime: |
| ... | ... | @@ -7093,7 +7225,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7093 | 7225 | case NodeTypeSliceExpr: |
| 7094 | 7226 | return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); |
| 7095 | 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 | 7229 | case NodeTypeContainerDecl: |
| 7098 | 7230 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 7099 | 7231 | case NodeTypeFnProto: |
| ... | ... | @@ -7152,6 +7284,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7152 | 7284 | ir_ref_bb(irb->current_basic_block); |
| 7153 | 7285 | |
| 7154 | 7286 | ZigFn *fn_entry = exec_fn_entry(irb->exec); |
| 7287 | ||
| 7155 | 7288 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 7156 | 7289 | IrInstruction *coro_id; |
| 7157 | 7290 | IrInstruction *u8_ptr_type; |
| ... | ... | @@ -7172,27 +7305,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7172 | 7305 | ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); |
| 7173 | 7306 | IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); |
| 7174 | 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 | 7309 | coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); |
| 7177 | 7310 | |
| 7178 | 7311 | ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 7179 | 7312 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); |
| 7180 | 7313 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, |
| 7181 | 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 | 7316 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); |
| 7184 | 7317 | |
| 7185 | 7318 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, |
| 7186 | 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 | 7321 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); |
| 7189 | 7322 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 7190 | 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 | 7325 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, |
| 7193 | 7326 | ImplicitAllocatorIdArg); |
| 7194 | 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 | 7329 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); |
| 7197 | 7330 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); |
| 7198 | 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 | 7341 | ir_build_return(irb, coro_scope, node, undef); |
| 7209 | 7342 | |
| 7210 | 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 | 7345 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); |
| 7213 | 7346 | |
| 7214 | 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 | 7419 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, |
| 7287 | 7420 | false, false, PtrLenUnknown, 0, 0, 0)); |
| 7288 | 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); | |
| 7290 | IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, | |
| 7422 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); | |
| 7423 | IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, | |
| 7291 | 7424 | irb->exec->coro_result_field_ptr); |
| 7292 | 7425 | IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, |
| 7293 | 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 | 7436 | // Before we destroy the coroutine frame, we need to load the target promise into |
| 7304 | 7437 | // a register or local variable which does not get spilled into the frame, |
| 7305 | 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 | 7440 | irb->exec->await_handle_var_ptr, false); |
| 7308 | 7441 | IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); |
| 7309 | 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 | 7471 | IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, |
| 7339 | 7472 | get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, |
| 7340 | 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 | 7475 | IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); |
| 7343 | 7476 | IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); |
| 7344 | 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 | 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 | 7572 | IrBasicBlock *bb = exec->basic_block_list.at(0); |
| 7440 | 7573 | for (size_t i = 0; i < bb->instruction_list.length; i += 1) { |
| 7441 | 7574 | IrInstruction *instruction = bb->instruction_list.at(i); |
| ... | ... | @@ -7445,16 +7578,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) |
| 7445 | 7578 | if (value->value.special == ConstValSpecialRuntime) { |
| 7446 | 7579 | exec_add_error_node(codegen, exec, value->source_node, |
| 7447 | 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 | 7584 | } else if (ir_has_side_effects(instruction)) { |
| 7452 | 7585 | exec_add_error_node(codegen, exec, instruction->source_node, |
| 7453 | 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 | 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 | 8307 | |
| 8175 | 8308 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); |
| 8176 | 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 | 8312 | if (other_type->id == ZigTypeIdFloat) { |
| 8179 | 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 | 8902 | size_t errors_count = 0; |
| 8769 | 8903 | ZigType *err_set_type = nullptr; |
| 8770 | 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 | 8908 | if (type_is_global_error_set(prev_inst->value.type)) { |
| 8772 | 8909 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; |
| 8773 | 8910 | } else { |
| 8774 | 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 | 8912 | update_errors_helper(ira->codegen, &errors, &errors_count); |
| 8779 | 8913 | |
| 8780 | 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 | 9067 | if (prev_type->id == ZigTypeIdArray) { |
| 8934 | 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 | 9073 | if (type_is_global_error_set(cur_type)) { |
| 8937 | 9074 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; |
| 8938 | 9075 | continue; |
| ... | ... | @@ -8940,9 +9077,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 8940 | 9077 | if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { |
| 8941 | 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 | 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 | 9566 | } |
| 9433 | 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 | 9579 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 9436 | 9580 | ZigType *wanted_type, CastOp cast_op, bool need_alloca) |
| 9437 | 9581 | { |
| 9438 | 9582 | if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && |
| 9439 | 9583 | cast_op != CastOpResizeSlice) |
| 9440 | 9584 | { |
| 9441 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 9442 | source_instr->source_node, wanted_type); | |
| 9585 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 9443 | 9586 | if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type, |
| 9444 | 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 | 9619 | if (pointee == nullptr) |
| 9477 | 9620 | return ira->codegen->invalid_instruction; |
| 9478 | 9621 | if (pointee->special != ConstValSpecialRuntime) { |
| 9479 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 9480 | source_instr->source_node, wanted_type); | |
| 9481 | result->value.type = wanted_type; | |
| 9622 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 9482 | 9623 | result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; |
| 9483 | 9624 | result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; |
| 9484 | 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 | 9658 | assert(is_slice(wanted_type)); |
| 9518 | 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, | |
| 9521 | source_instr->source_node, wanted_type); | |
| 9661 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 9522 | 9662 | init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); |
| 9523 | 9663 | result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = |
| 9524 | 9664 | value->value.data.x_ptr.mut; |
| ... | ... | @@ -9653,15 +9793,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction) |
| 9653 | 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 | 9796 | static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { |
| 9666 | 9797 | IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type); |
| 9667 | 9798 | result->value.data.x_type = ty; |
| ... | ... | @@ -9719,13 +9850,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un |
| 9719 | 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 | 9854 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, |
| 9724 | 9855 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 9725 | 9856 | IrExecutable *parent_exec) |
| 9726 | 9857 | { |
| 9727 | 9858 | if (expected_type != nullptr && type_is_invalid(expected_type)) |
| 9728 | return codegen->invalid_instruction; | |
| 9859 | return &codegen->invalid_instruction->value; | |
| 9729 | 9860 | |
| 9730 | 9861 | IrExecutable *ir_executable = allocate<IrExecutable>(1); |
| 9731 | 9862 | ir_executable->source_node = source_node; |
| ... | ... | @@ -9738,13 +9869,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 9738 | 9869 | ir_gen(codegen, node, scope, ir_executable); |
| 9739 | 9870 | |
| 9740 | 9871 | if (ir_executable->invalid) |
| 9741 | return codegen->invalid_instruction; | |
| 9872 | return &codegen->invalid_instruction->value; | |
| 9742 | 9873 | |
| 9743 | 9874 | if (codegen->verbose_ir) { |
| 9744 | 9875 | fprintf(stderr, "\nSource: "); |
| 9745 | 9876 | ast_render(codegen, stderr, node, 4); |
| 9746 | 9877 | fprintf(stderr, "\n{ // (IR)\n"); |
| 9747 | ir_print(codegen, stderr, ir_executable, 4); | |
| 9878 | ir_print(codegen, stderr, ir_executable, 2); | |
| 9748 | 9879 | fprintf(stderr, "}\n"); |
| 9749 | 9880 | } |
| 9750 | 9881 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); |
| ... | ... | @@ -9760,11 +9891,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 9760 | 9891 | analyzed_executable->begin_scope = scope; |
| 9761 | 9892 | ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); |
| 9762 | 9893 | if (type_is_invalid(result_type)) |
| 9763 | return codegen->invalid_instruction; | |
| 9894 | return &codegen->invalid_instruction->value; | |
| 9764 | 9895 | |
| 9765 | 9896 | if (codegen->verbose_ir) { |
| 9766 | 9897 | fprintf(stderr, "{ // (analyzed)\n"); |
| 9767 | ir_print(codegen, stderr, analyzed_executable, 4); | |
| 9898 | ir_print(codegen, stderr, analyzed_executable, 2); | |
| 9768 | 9899 | fprintf(stderr, "}\n"); |
| 9769 | 9900 | } |
| 9770 | 9901 | |
| ... | ... | @@ -9789,6 +9920,34 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 9789 | 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 | 9951 | static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 9793 | 9952 | if (fn_value == ira->codegen->invalid_instruction) |
| 9794 | 9953 | return nullptr; |
| ... | ... | @@ -9810,7 +9969,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 9810 | 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 | 9975 | assert(wanted_type->id == ZigTypeIdOptional); |
| 9815 | 9976 | |
| 9816 | 9977 | if (instr_is_comptime(value)) { |
| ... | ... | @@ -9826,7 +9987,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc |
| 9826 | 9987 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9827 | 9988 | source_instr->scope, source_instr->source_node); |
| 9828 | 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 | 9991 | copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); |
| 9831 | 9992 | } else { |
| 9832 | 9993 | const_instruction->base.value.data.x_optional = val; |
| ... | ... | @@ -9857,11 +10018,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 9857 | 10018 | if (!val) |
| 9858 | 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 | 10026 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9861 | 10027 | source_instr->scope, source_instr->source_node); |
| 9862 | 10028 | const_instruction->base.value.type = wanted_type; |
| 9863 | 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 | 10031 | const_instruction->base.value.data.x_err_union.payload = val; |
| 9866 | 10032 | return &const_instruction->base; |
| 9867 | 10033 | } |
| ... | ... | @@ -9926,11 +10092,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so |
| 9926 | 10092 | if (!val) |
| 9927 | 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 | 10100 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 9930 | 10101 | source_instr->scope, source_instr->source_node); |
| 9931 | 10102 | const_instruction->base.value.type = wanted_type; |
| 9932 | 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 | 10105 | const_instruction->base.value.data.x_err_union.payload = nullptr; |
| 9935 | 10106 | return &const_instruction->base; |
| 9936 | 10107 | } |
| ... | ... | @@ -9952,8 +10123,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so |
| 9952 | 10123 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node); |
| 9953 | 10124 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 9954 | 10125 | if (get_codegen_ptr_type(wanted_type) != nullptr) { |
| 9955 | const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; | |
| 9956 | const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; | |
| 10126 | const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull; | |
| 10127 | } else if (is_opt_err_set(wanted_type)) { | |
| 10128 | const_instruction->base.value.data.x_err_set = nullptr; | |
| 9957 | 10129 | } else { |
| 9958 | 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 | 10158 | source_instruction->source_node, value, is_const, is_volatile); |
| 9987 | 10159 | new_instruction->value.type = ptr_type; |
| 9988 | 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 | 10162 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 9991 | 10163 | assert(fn_entry); |
| 9992 | 10164 | fn_entry->alloca_list.append(new_instruction); |
| ... | ... | @@ -10012,20 +10184,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s |
| 10012 | 10184 | ZigType *array_type = array->value.type; |
| 10013 | 10185 | assert(array_type->id == ZigTypeIdArray); |
| 10014 | 10186 | |
| 10015 | if (instr_is_comptime(array)) { | |
| 10016 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10017 | source_instr->source_node, wanted_type); | |
| 10187 | if (instr_is_comptime(array) || array_type->data.array.len == 0) { | |
| 10188 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10018 | 10189 | init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true); |
| 10019 | 10190 | result->value.type = wanted_type; |
| 10020 | 10191 | return result; |
| 10021 | 10192 | } |
| 10022 | 10193 | |
| 10023 | IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10024 | source_instr->source_node, ira->codegen->builtin_types.entry_usize); | |
| 10194 | IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); | |
| 10025 | 10195 | init_const_usize(ira->codegen, &start->value, 0); |
| 10026 | 10196 | |
| 10027 | IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10028 | source_instr->source_node, ira->codegen->builtin_types.entry_usize); | |
| 10197 | IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); | |
| 10029 | 10198 | init_const_usize(ira->codegen, &end->value, array_type->data.array.len); |
| 10030 | 10199 | |
| 10031 | 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 | 10233 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 10065 | 10234 | if (!val) |
| 10066 | 10235 | return ira->codegen->invalid_instruction; |
| 10067 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10068 | source_instr->source_node, wanted_type); | |
| 10236 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10069 | 10237 | init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); |
| 10070 | 10238 | return result; |
| 10071 | 10239 | } |
| ... | ... | @@ -10075,8 +10243,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour |
| 10075 | 10243 | actual_type->data.enumeration.src_field_count == 1) |
| 10076 | 10244 | { |
| 10077 | 10245 | assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); |
| 10078 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10079 | source_instr->source_node, wanted_type); | |
| 10246 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10080 | 10247 | init_const_bigint(&result->value, wanted_type, |
| 10081 | 10248 | &actual_type->data.enumeration.fields[0].value); |
| 10082 | 10249 | return result; |
| ... | ... | @@ -10099,8 +10266,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou |
| 10099 | 10266 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 10100 | 10267 | if (!val) |
| 10101 | 10268 | return ira->codegen->invalid_instruction; |
| 10102 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10103 | source_instr->source_node, wanted_type); | |
| 10269 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10104 | 10270 | result->value.special = ConstValSpecialStatic; |
| 10105 | 10271 | result->value.type = wanted_type; |
| 10106 | 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 | 10277 | if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && |
| 10112 | 10278 | wanted_type->data.enumeration.src_field_count == 1) |
| 10113 | 10279 | { |
| 10114 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10115 | source_instr->source_node, wanted_type); | |
| 10280 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10116 | 10281 | result->value.special = ConstValSpecialStatic; |
| 10117 | 10282 | result->value.type = wanted_type; |
| 10118 | 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 | 10294 | static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, |
| 10130 | 10295 | IrInstruction *target, ZigType *wanted_type) |
| 10131 | 10296 | { |
| 10132 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10133 | source_instr->source_node, wanted_type); | |
| 10297 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10134 | 10298 | init_const_undefined(ira->codegen, &result->value); |
| 10135 | 10299 | return result; |
| 10136 | 10300 | } |
| ... | ... | @@ -10162,8 +10326,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 10162 | 10326 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); |
| 10163 | 10327 | return ira->codegen->invalid_instruction; |
| 10164 | 10328 | } |
| 10165 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10166 | source_instr->source_node, wanted_type); | |
| 10329 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10167 | 10330 | result->value.special = ConstValSpecialStatic; |
| 10168 | 10331 | result->value.type = wanted_type; |
| 10169 | 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 | 10381 | return ira->codegen->invalid_instruction; |
| 10219 | 10382 | } |
| 10220 | 10383 | } |
| 10221 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10222 | source_instr->source_node, wanted_type); | |
| 10384 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10223 | 10385 | result->value.type = wanted_type; |
| 10224 | 10386 | if (wanted_type->id == ZigTypeIdInt) { |
| 10225 | 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 | 10435 | return ira->codegen->invalid_instruction; |
| 10274 | 10436 | } |
| 10275 | 10437 | |
| 10276 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10277 | source_instr->source_node, wanted_type); | |
| 10438 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10278 | 10439 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); |
| 10279 | 10440 | return result; |
| 10280 | 10441 | } |
| ... | ... | @@ -10292,8 +10453,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction |
| 10292 | 10453 | if (!val) |
| 10293 | 10454 | return ira->codegen->invalid_instruction; |
| 10294 | 10455 | |
| 10295 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10296 | source_instr->source_node, wanted_type); | |
| 10456 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10297 | 10457 | if (wanted_type->id == ZigTypeIdComptimeFloat) { |
| 10298 | 10458 | float_init_float(&result->value, val); |
| 10299 | 10459 | } else if (wanted_type->id == ZigTypeIdComptimeInt) { |
| ... | ... | @@ -10316,8 +10476,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 10316 | 10476 | if (!val) |
| 10317 | 10477 | return ira->codegen->invalid_instruction; |
| 10318 | 10478 | |
| 10319 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10320 | source_instr->source_node, wanted_type); | |
| 10479 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10321 | 10480 | |
| 10322 | 10481 | if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) { |
| 10323 | 10482 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -10381,12 +10540,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 10381 | 10540 | if (!val) |
| 10382 | 10541 | return ira->codegen->invalid_instruction; |
| 10383 | 10542 | |
| 10384 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10385 | source_instr->source_node, wanted_type); | |
| 10543 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10386 | 10544 | |
| 10387 | 10545 | ErrorTableEntry *err; |
| 10388 | 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 | 10548 | } else if (err_type->id == ZigTypeIdErrorSet) { |
| 10391 | 10549 | err = val->data.x_err_set; |
| 10392 | 10550 | } else { |
| ... | ... | @@ -10421,15 +10579,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 10421 | 10579 | return ira->codegen->invalid_instruction; |
| 10422 | 10580 | } |
| 10423 | 10581 | if (err_set_type->data.error_set.err_count == 0) { |
| 10424 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10425 | source_instr->source_node, wanted_type); | |
| 10426 | result->value.type = wanted_type; | |
| 10582 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10427 | 10583 | bigint_init_unsigned(&result->value.data.x_bigint, 0); |
| 10428 | 10584 | return result; |
| 10429 | 10585 | } else if (err_set_type->data.error_set.err_count == 1) { |
| 10430 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 10431 | source_instr->source_node, wanted_type); | |
| 10432 | result->value.type = wanted_type; | |
| 10586 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | |
| 10433 | 10587 | ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; |
| 10434 | 10588 | bigint_init_unsigned(&result->value.data.x_bigint, err->value); |
| 10435 | 10589 | return result; |
| ... | ... | @@ -10476,8 +10630,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou |
| 10476 | 10630 | array_val->type = array_type; |
| 10477 | 10631 | array_val->data.x_array.special = ConstArraySpecialNone; |
| 10478 | 10632 | array_val->data.x_array.data.s_none.elements = pointee; |
| 10479 | array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar; | |
| 10480 | array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee; | |
| 10633 | array_val->parent.id = ConstParentIdScalar; | |
| 10634 | array_val->parent.data.p_scalar.scalar_val = pointee; | |
| 10481 | 10635 | |
| 10482 | 10636 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 10483 | 10637 | source_instr->scope, source_instr->source_node); |
| ... | ... | @@ -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 | 10781 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 10602 | 10782 | ZigType *wanted_type, IrInstruction *value) |
| 10603 | 10783 | { |
| ... | ... | @@ -10625,12 +10805,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10625 | 10805 | if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, |
| 10626 | 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 | 10809 | } else if (actual_type->id == ZigTypeIdComptimeInt || |
| 10630 | 10810 | actual_type->id == ZigTypeIdComptimeFloat) |
| 10631 | 10811 | { |
| 10632 | 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 | 10814 | } else { |
| 10635 | 10815 | return ira->codegen->invalid_instruction; |
| 10636 | 10816 | } |
| ... | ... | @@ -10654,7 +10834,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10654 | 10834 | wanted_child_type); |
| 10655 | 10835 | if (type_is_invalid(cast1->value.type)) |
| 10656 | 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 | 10887 | (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || |
| 10708 | 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 | 10895 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { |
| 10711 | 10896 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { |
| 10712 | 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 | 10945 | |
| 10761 | 10946 | |
| 10762 | 10947 | // cast from [N]T to []const T |
| 10948 | // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this | |
| 10763 | 10949 | if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { |
| 10764 | 10950 | ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; |
| 10765 | 10951 | assert(ptr_type->id == ZigTypeIdPointer); |
| ... | ... | @@ -10772,6 +10958,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10772 | 10958 | } |
| 10773 | 10959 | |
| 10774 | 10960 | // cast from [N]T to ?[]const T |
| 10961 | // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this | |
| 10775 | 10962 | if (wanted_type->id == ZigTypeIdOptional && |
| 10776 | 10963 | is_slice(wanted_type->data.maybe.child_type) && |
| 10777 | 10964 | actual_type->id == ZigTypeIdArray) |
| ... | ... | @@ -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 | 11057 | if (wanted_type->id == ZigTypeIdErrorUnion && |
| 10871 | 11058 | actual_type->id == ZigTypeIdErrorSet) |
| 10872 | 11059 | { |
| ... | ... | @@ -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 | 11187 | // cast from undefined to anything |
| 10984 | 11188 | if (actual_type->id == ZigTypeIdUndefined) { |
| ... | ... | @@ -11018,8 +11222,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 11018 | 11222 | ZigType *child_type = type_entry->data.pointer.child_type; |
| 11019 | 11223 | // dereferencing a *u0 is comptime known to be 0 |
| 11020 | 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, | |
| 11022 | source_instruction->source_node, child_type); | |
| 11225 | IrInstruction *result = ir_const(ira, source_instruction, child_type); | |
| 11023 | 11226 | init_const_unsigned_negative(&result->value, child_type, 0, false); |
| 11024 | 11227 | return result; |
| 11025 | 11228 | } |
| ... | ... | @@ -11033,8 +11236,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 11033 | 11236 | { |
| 11034 | 11237 | ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); |
| 11035 | 11238 | if (pointee->special != ConstValSpecialRuntime) { |
| 11036 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, | |
| 11037 | source_instruction->source_node, child_type); | |
| 11239 | IrInstruction *result = ir_const(ira, source_instruction, child_type); | |
| 11038 | 11240 | |
| 11039 | 11241 | if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, |
| 11040 | 11242 | &ptr->value))) |
| ... | ... | @@ -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 | 11256 | IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, |
| 11051 | 11257 | source_instruction->source_node, ptr); |
| 11052 | 11258 | load_ptr_instruction->value.type = child_type; |
| ... | ... | @@ -11293,8 +11499,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio |
| 11293 | 11499 | |
| 11294 | 11500 | static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) { |
| 11295 | 11501 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); |
| 11296 | // TODO determine if we need to use copy_const_val here | |
| 11297 | result->value = instruction->base.value; | |
| 11502 | copy_const_val(&result->value, &instruction->base.value, true); | |
| 11298 | 11503 | return result; |
| 11299 | 11504 | } |
| 11300 | 11505 | |
| ... | ... | @@ -11369,6 +11574,8 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 11369 | 11574 | if (get_codegen_ptr_type(val->type) != nullptr) { |
| 11370 | 11575 | return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && |
| 11371 | 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 | 11579 | } else { |
| 11373 | 11580 | return val->data.x_optional == nullptr; |
| 11374 | 11581 | } |
| ... | ... | @@ -11523,6 +11730,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11523 | 11730 | case ZigTypeIdComptimeInt: |
| 11524 | 11731 | case ZigTypeIdInt: |
| 11525 | 11732 | case ZigTypeIdFloat: |
| 11733 | case ZigTypeIdVector: | |
| 11526 | 11734 | operator_allowed = true; |
| 11527 | 11735 | break; |
| 11528 | 11736 | |
| ... | ... | @@ -11568,19 +11776,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11568 | 11776 | if (casted_op2 == ira->codegen->invalid_instruction) |
| 11569 | 11777 | return ira->codegen->invalid_instruction; |
| 11570 | 11778 | |
| 11571 | bool requires_comptime; | |
| 11572 | switch (type_requires_comptime(ira->codegen, resolved_type)) { | |
| 11573 | case ReqCompTimeYes: | |
| 11574 | requires_comptime = true; | |
| 11779 | bool one_possible_value; | |
| 11780 | switch (type_has_one_possible_value(ira->codegen, resolved_type)) { | |
| 11781 | case OnePossibleValueInvalid: | |
| 11782 | return ira->codegen->invalid_instruction; | |
| 11783 | case OnePossibleValueYes: | |
| 11784 | one_possible_value = true; | |
| 11575 | 11785 | break; |
| 11576 | case ReqCompTimeNo: | |
| 11577 | requires_comptime = false; | |
| 11786 | case OnePossibleValueNo: | |
| 11787 | one_possible_value = false; | |
| 11578 | 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 | 11791 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { |
| 11585 | 11792 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); |
| 11586 | 11793 | if (op1_val == nullptr) |
| ... | ... | @@ -11654,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11654 | 11861 | return result; |
| 11655 | 11862 | } |
| 11656 | 11863 | |
| 11657 | static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, | |
| 11658 | IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) | |
| 11864 | static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry, | |
| 11865 | ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) | |
| 11659 | 11866 | { |
| 11660 | 11867 | bool is_int; |
| 11661 | 11868 | bool is_float; |
| ... | ... | @@ -11677,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11677 | 11884 | if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || |
| 11678 | 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 | 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 | 11893 | switch (op_id) { |
| ... | ... | @@ -11726,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11726 | 11933 | BigInt orig_bigint; |
| 11727 | 11934 | bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); |
| 11728 | 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 | 11938 | break; |
| 11732 | 11939 | } |
| ... | ... | @@ -11794,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11794 | 12001 | BigInt remainder; |
| 11795 | 12002 | bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 11796 | 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 | 12006 | } else { |
| 11800 | 12007 | float_div_trunc(out_val, op1_val, op2_val); |
| 11801 | 12008 | ConstExprValue remainder; |
| 11802 | 12009 | float_rem(&remainder, op1_val, op2_val); |
| 11803 | 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 | 12014 | break; |
| ... | ... | @@ -11825,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, |
| 11825 | 12032 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, |
| 11826 | 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 | 12039 | out_val->type = type_entry; |
| 11833 | 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 | 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 | 12148 | if (op2_val == nullptr) |
| 11904 | 12149 | return ira->codegen->invalid_instruction; |
| 11905 | 12150 | |
| 11906 | IrInstruction *result_instruction = ir_const(ira, &bin_op_instruction->base, op1->value.type); | |
| 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; | |
| 12151 | return ir_analyze_math_op(ira, &bin_op_instruction->base, op1->value.type, op1_val, op_id, op2_val); | |
| 11924 | 12152 | } else if (op1->value.type->id == ZigTypeIdComptimeInt) { |
| 11925 | 12153 | ir_add_error(ira, &bin_op_instruction->base, |
| 11926 | 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 | 12167 | return result; |
| 11940 | 12168 | } |
| 11941 | 12169 | |
| 11942 | static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { | |
| 11943 | IrInstruction *op1 = instruction->op1->child; | |
| 11944 | if (type_is_invalid(op1->value.type)) | |
| 11945 | return ira->codegen->invalid_instruction; | |
| 11946 | ||
| 11947 | IrInstruction *op2 = instruction->op2->child; | |
| 11948 | if (type_is_invalid(op2->value.type)) | |
| 11949 | return ira->codegen->invalid_instruction; | |
| 11950 | ||
| 11951 | IrBinOp op_id = instruction->op_id; | |
| 11952 | ||
| 11953 | // look for pointer math | |
| 11954 | if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && | |
| 11955 | (op_id == IrBinOpAdd || op_id == IrBinOpSub)) | |
| 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 | } | |
| 12170 | static bool ok_float_op(IrBinOp op) { | |
| 12171 | switch (op) { | |
| 12172 | case IrBinOpInvalid: | |
| 12173 | zig_unreachable(); | |
| 12174 | case IrBinOpAdd: | |
| 12175 | case IrBinOpSub: | |
| 12176 | case IrBinOpMult: | |
| 12177 | case IrBinOpDivUnspecified: | |
| 12178 | case IrBinOpDivTrunc: | |
| 12179 | case IrBinOpDivFloor: | |
| 12180 | case IrBinOpDivExact: | |
| 12181 | case IrBinOpRemRem: | |
| 12182 | case IrBinOpRemMod: | |
| 12183 | return true; | |
| 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 | 12238 | ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2); |
| 11969 | 12239 | if (type_is_invalid(resolved_type)) |
| 11970 | 12240 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -12076,21 +12346,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 12076 | 12346 | op_id = IrBinOpRemRem; |
| 12077 | 12347 | } |
| 12078 | 12348 | |
| 12349 | bool ok = false; | |
| 12079 | 12350 | if (is_int) { |
| 12080 | // int | |
| 12081 | } else if (is_float && | |
| 12082 | (op_id == IrBinOpAdd || | |
| 12083 | op_id == IrBinOpSub || | |
| 12084 | op_id == IrBinOpMult || | |
| 12085 | op_id == IrBinOpDivUnspecified || | |
| 12086 | op_id == IrBinOpDivTrunc || | |
| 12087 | op_id == IrBinOpDivFloor || | |
| 12088 | op_id == IrBinOpDivExact || | |
| 12089 | op_id == IrBinOpRemRem || | |
| 12090 | op_id == IrBinOpRemMod)) | |
| 12091 | { | |
| 12092 | // float | |
| 12093 | } else { | |
| 12351 | ok = true; | |
| 12352 | } else if (is_float && ok_float_op(op_id)) { | |
| 12353 | ok = true; | |
| 12354 | } else if (resolved_type->id == ZigTypeIdVector) { | |
| 12355 | ZigType *elem_type = resolved_type->data.vector.elem_type; | |
| 12356 | if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) { | |
| 12357 | ok = true; | |
| 12358 | } else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) { | |
| 12359 | ok = true; | |
| 12360 | } | |
| 12361 | } | |
| 12362 | if (!ok) { | |
| 12094 | 12363 | AstNode *source_node = instruction->base.source_node; |
| 12095 | 12364 | ir_add_error_node(ira, source_node, |
| 12096 | 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 | 12394 | if (op2_val == nullptr) |
| 12126 | 12395 | return ira->codegen->invalid_instruction; |
| 12127 | 12396 | |
| 12128 | IrInstruction *result_instruction = ir_const(ira, &instruction->base, resolved_type); | |
| 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; | |
| 12397 | return ir_analyze_math_op(ira, &instruction->base, resolved_type, op1_val, op_id, op2_val); | |
| 12152 | 12398 | } |
| 12153 | 12399 | |
| 12154 | 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 | 12448 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 12203 | 12449 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 12204 | 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 | 12452 | } else { |
| 12207 | 12453 | ir_add_error(ira, op1, |
| 12208 | 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 | 12458 | ConstExprValue *op2_array_val; |
| 12213 | 12459 | size_t op2_array_index; |
| 12214 | 12460 | size_t op2_array_end; |
| 12461 | bool op2_type_valid; | |
| 12215 | 12462 | if (op2_type->id == ZigTypeIdArray) { |
| 12216 | if (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 | } | |
| 12463 | op2_type_valid = op2_type->data.array.child_type == child_type; | |
| 12222 | 12464 | op2_array_val = op2_val; |
| 12223 | 12465 | op2_array_index = 0; |
| 12224 | 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 | 12469 | op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && |
| 12228 | 12470 | op2_val->data.x_ptr.data.base_array.is_cstr) |
| 12229 | 12471 | { |
| 12230 | if (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 | } | |
| 12472 | op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8; | |
| 12236 | 12473 | op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; |
| 12237 | 12474 | op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; |
| 12238 | 12475 | op2_array_end = op2_array_val->type->data.array.len - 1; |
| 12239 | 12476 | } else if (is_slice(op2_type)) { |
| 12240 | 12477 | ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; |
| 12241 | if (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 | } | |
| 12478 | op2_type_valid = ptr_type->data.pointer.child_type == child_type; | |
| 12247 | 12479 | ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; |
| 12248 | 12480 | assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 12249 | 12481 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 12250 | 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 | 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 | 12485 | } else { |
| 12255 | 12486 | ir_add_error(ira, op2, |
| 12256 | 12487 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); |
| 12257 | 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 | 12497 | // The type of result is populated in the following if blocks |
| 12261 | 12498 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); |
| ... | ... | @@ -12388,26 +12625,14 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * |
| 12388 | 12625 | } |
| 12389 | 12626 | |
| 12390 | 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 | 12629 | if (type_is_invalid(op1_type)) |
| 12393 | 12630 | return ira->codegen->invalid_instruction; |
| 12394 | 12631 | |
| 12395 | if (op1_type->id != ZigTypeIdErrorSet) { | |
| 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); | |
| 12632 | ZigType *op2_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op2->child); | |
| 12402 | 12633 | if (type_is_invalid(op2_type)) |
| 12403 | 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 | 12636 | if (type_is_global_error_set(op1_type) || |
| 12412 | 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 | 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 | 12712 | Error err; |
| 12486 | 12713 | ZigVar *var = decl_var_instruction->var; |
| 12487 | 12714 | |
| 12488 | 12715 | IrInstruction *init_value = decl_var_instruction->init_value->child; |
| 12489 | 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 | 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 | 12725 | ZigType *proposed_type = ir_resolve_type(ira, var_type); |
| 12499 | 12726 | explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); |
| 12500 | 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 | 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 | 12750 | case ReqCompTimeInvalid: |
| 12524 | 12751 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12525 | 12752 | break; |
| 12526 | case ReqCompTimeYes: { | |
| 12753 | case ReqCompTimeYes: | |
| 12527 | 12754 | var_class_requires_const = true; |
| 12528 | 12755 | if (!var->gen_is_const && !is_comptime_var) { |
| 12529 | 12756 | ir_add_error_node(ira, source_node, |
| ... | ... | @@ -12532,7 +12759,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12532 | 12759 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12533 | 12760 | } |
| 12534 | 12761 | break; |
| 12535 | } | |
| 12536 | 12762 | case ReqCompTimeNo: |
| 12537 | 12763 | if (casted_init_value->value.special == ConstValSpecialStatic && |
| 12538 | 12764 | casted_init_value->value.type->id == ZigTypeIdFn && |
| ... | ... | @@ -12551,7 +12777,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct |
| 12551 | 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 | 12781 | // This is at least the second time we've seen this variable declaration during analysis. |
| 12556 | 12782 | // This means that this is actually a different variable due to, e.g. an inline while loop. |
| 12557 | 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 | 12799 | // This must be done after possibly creating a new variable above |
| 12574 | 12800 | var->ref_count = 0; |
| 12575 | 12801 | |
| 12576 | var->value->type = result_type; | |
| 12577 | assert(var->value->type); | |
| 12802 | var->var_type = result_type; | |
| 12803 | assert(var->var_type); | |
| 12578 | 12804 | |
| 12579 | 12805 | if (type_is_invalid(result_type)) { |
| 12580 | 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 | 12808 | |
| 12583 | 12809 | if (decl_var_instruction->align_value == nullptr) { |
| 12584 | 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 | 12812 | return ir_const_void(ira, &decl_var_instruction->base); |
| 12587 | 12813 | } |
| 12588 | 12814 | var->align_bytes = get_abi_alignment(ira->codegen, result_type); |
| 12589 | 12815 | } else { |
| 12590 | 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 | 12831 | } else if (is_comptime_var) { |
| 12606 | 12832 | ir_add_error(ira, &decl_var_instruction->base, |
| 12607 | 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 | 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 | 12839 | if (fn_entry) |
| 12614 | 12840 | fn_entry->variable_list.append(var); |
| 12615 | 12841 | |
| 12616 | IrInstruction *result = ir_build_var_decl(&ira->new_irb, | |
| 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; | |
| 12842 | return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); | |
| 12621 | 12843 | } |
| 12622 | 12844 | |
| 12623 | 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 | 12961 | case ZigTypeIdPointer: |
| 12740 | 12962 | case ZigTypeIdArray: |
| 12741 | 12963 | case ZigTypeIdBool: |
| 12964 | case ZigTypeIdVector: | |
| 12742 | 12965 | break; |
| 12743 | 12966 | case ZigTypeIdMetaType: |
| 12744 | 12967 | case ZigTypeIdVoid: |
| ... | ... | @@ -12773,6 +12996,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 12773 | 12996 | case ZigTypeIdOptional: |
| 12774 | 12997 | case ZigTypeIdErrorUnion: |
| 12775 | 12998 | case ZigTypeIdErrorSet: |
| 12999 | case ZigTypeIdVector: | |
| 12776 | 13000 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); |
| 12777 | 13001 | case ZigTypeIdNamespace: |
| 12778 | 13002 | case ZigTypeIdBoundFn: |
| ... | ... | @@ -12947,7 +13171,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node |
| 12947 | 13171 | |
| 12948 | 13172 | Buf *param_name = param_decl_node->data.param_decl.name; |
| 12949 | 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 | 13175 | *exec_scope = var->child_scope; |
| 12952 | 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 | 13229 | if (!param_name) return false; |
| 13006 | 13230 | if (!is_var_args) { |
| 13007 | 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 | 13233 | *child_scope = var->child_scope; |
| 13010 | 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 | 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, | |
| 13063 | ZigVar *var) | |
| 13064 | { | |
| 13286 | static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { | |
| 13065 | 13287 | while (var->next_var != nullptr) { |
| 13066 | 13288 | var = var->next_var; |
| 13067 | 13289 | } |
| ... | ... | @@ -13070,14 +13292,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13070 | 13292 | assert(ira->codegen->errors.length != 0); |
| 13071 | 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 | 13296 | return ira->codegen->invalid_instruction; |
| 13075 | 13297 | |
| 13076 | 13298 | bool comptime_var_mem = ir_get_var_is_comptime(var); |
| 13077 | 13299 | |
| 13078 | 13300 | ConstExprValue *mem_slot = nullptr; |
| 13079 | if (var->value->special == ConstValSpecialStatic) { | |
| 13080 | mem_slot = var->value; | |
| 13301 | if (var->const_value->special == ConstValSpecialStatic) { | |
| 13302 | mem_slot = var->const_value; | |
| 13081 | 13303 | } else { |
| 13082 | 13304 | if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { |
| 13083 | 13305 | // find the relevant exec_context |
| ... | ... | @@ -13106,7 +13328,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13106 | 13328 | assert(!comptime_var_mem); |
| 13107 | 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 | 13332 | ptr_mut, is_const, is_volatile, var->align_bytes); |
| 13111 | 13333 | } |
| 13112 | 13334 | } |
| ... | ... | @@ -13117,7 +13339,7 @@ no_mem_slot: |
| 13117 | 13339 | |
| 13118 | 13340 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, |
| 13119 | 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 | 13343 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); |
| 13122 | 13344 | |
| 13123 | 13345 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| ... | ... | @@ -13126,6 +13348,96 @@ no_mem_slot: |
| 13126 | 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 | 13441 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 13130 | 13442 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, |
| 13131 | 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 | 13582 | } |
| 13271 | 13583 | |
| 13272 | 13584 | bool cacheable = fn_eval_cacheable(exec_scope, return_type); |
| 13273 | IrInstruction *result = nullptr; | |
| 13585 | ConstExprValue *result = nullptr; | |
| 13274 | 13586 | if (cacheable) { |
| 13275 | 13587 | auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); |
| 13276 | 13588 | if (entry) |
| ... | ... | @@ -13286,18 +13598,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call |
| 13286 | 13598 | |
| 13287 | 13599 | if (inferred_err_set_type != nullptr) { |
| 13288 | 13600 | inferred_err_set_type->data.error_set.infer_fn = nullptr; |
| 13289 | if (result->value.type->id == ZigTypeIdErrorUnion) { | |
| 13290 | if (result->value.data.x_err_union.err != nullptr) { | |
| 13601 | if (result->type->id == ZigTypeIdErrorUnion) { | |
| 13602 | ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; | |
| 13603 | if (err != nullptr) { | |
| 13291 | 13604 | inferred_err_set_type->data.error_set.err_count = 1; |
| 13292 | 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 | 13609 | inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; |
| 13297 | 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) { | |
| 13299 | inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count; | |
| 13300 | inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors; | |
| 13611 | } else if (result->type->id == ZigTypeIdErrorSet) { | |
| 13612 | inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; | |
| 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 | 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 | 13622 | return ira->codegen->invalid_instruction; |
| 13310 | 13623 | } |
| 13311 | 13624 | |
| 13312 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type); | |
| 13313 | // TODO should we use copy_const_val? | |
| 13314 | new_instruction->value = result->value; | |
| 13625 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); | |
| 13626 | copy_const_val(&new_instruction->value, result, true); | |
| 13315 | 13627 | new_instruction->value.type = return_type; |
| 13316 | 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 | 13782 | ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, |
| 13471 | 13783 | first_var_arg, inst_fn_type_id.param_count); |
| 13472 | 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 | 13786 | impl_fn->child_scope = var->child_scope; |
| 13475 | 13787 | } |
| 13476 | 13788 | |
| 13477 | 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 | 13791 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), |
| 13480 | 13792 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, |
| 13481 | 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 | 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 | 13800 | impl_fn->align_bytes = align_bytes; |
| 13486 | 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 | 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; | |
| 13563 | if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) { | |
| 13877 | FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; | |
| 13878 | if (fn_type_can_fail(impl_fn_type_id)) { | |
| 13564 | 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 | 13883 | if (call_instruction->is_async) { |
| 13569 | 13884 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, |
| 13570 | 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 | 13892 | call_instruction->base.scope, call_instruction->base.source_node, |
| 13578 | 13893 | impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, |
| 13579 | 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 | 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 | 14089 | switch (ptr_val->data.x_ptr.special) { |
| 13775 | 14090 | case ConstPtrSpecialInvalid: |
| 13776 | 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 | 14099 | case ConstPtrSpecialRef: { |
| 13778 | 14100 | opt_ir_add_error_node(ira, codegen, source_node, |
| 13779 | 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 | 14128 | return ErrorNone; |
| 13807 | 14129 | } |
| 13808 | 14130 | case ConstPtrSpecialBaseStruct: |
| 14131 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 14132 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 14133 | case ConstPtrSpecialBaseOptionalPayload: | |
| 13809 | 14134 | case ConstPtrSpecialDiscard: |
| 13810 | 14135 | case ConstPtrSpecialHardCodedAddr: |
| 13811 | 14136 | case ConstPtrSpecialFunction: |
| ... | ... | @@ -13830,6 +14155,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ |
| 13830 | 14155 | case ZigTypeIdVoid: |
| 13831 | 14156 | case ZigTypeIdBool: |
| 13832 | 14157 | case ZigTypeIdInt: |
| 14158 | case ZigTypeIdVector: | |
| 13833 | 14159 | case ZigTypeIdFloat: |
| 13834 | 14160 | case ZigTypeIdPointer: |
| 13835 | 14161 | case ZigTypeIdArray: |
| ... | ... | @@ -14001,9 +14327,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi |
| 14001 | 14327 | if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) |
| 14002 | 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 | 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 | 14338 | return ir_unreach_error(ira); |
| 14008 | 14339 | |
| 14009 | 14340 | IrBasicBlock *old_dest_block = cond_is_true ? |
| ... | ... | @@ -14022,11 +14353,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi |
| 14022 | 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 | 14356 | assert(cond_br_instruction->then_block != cond_br_instruction->else_block); |
| 14031 | 14357 | IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); |
| 14032 | 14358 | if (new_then_block == nullptr) |
| ... | ... | @@ -14065,8 +14391,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh |
| 14065 | 14391 | |
| 14066 | 14392 | if (value->value.special != ConstValSpecialRuntime) { |
| 14067 | 14393 | IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr); |
| 14068 | // TODO use copy_const_val? | |
| 14069 | result->value = value->value; | |
| 14394 | copy_const_val(&result->value, &value->value, true); | |
| 14070 | 14395 | return result; |
| 14071 | 14396 | } else { |
| 14072 | 14397 | return value; |
| ... | ... | @@ -14115,14 +14440,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh |
| 14115 | 14440 | if (type_is_invalid(resolved_type)) |
| 14116 | 14441 | return ira->codegen->invalid_instruction; |
| 14117 | 14442 | |
| 14118 | if (resolved_type->id == ZigTypeIdComptimeFloat || | |
| 14119 | resolved_type->id == ZigTypeIdComptimeInt || | |
| 14120 | resolved_type->id == ZigTypeIdNull || | |
| 14121 | resolved_type->id == ZigTypeIdUndefined) | |
| 14122 | { | |
| 14443 | switch (type_has_one_possible_value(ira->codegen, resolved_type)) { | |
| 14444 | case OnePossibleValueInvalid: | |
| 14445 | return ira->codegen->invalid_instruction; | |
| 14446 | case OnePossibleValueYes: | |
| 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 | 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 | 14458 | return ira->codegen->invalid_instruction; |
| 14459 | case ReqCompTimeNo: | |
| 14460 | break; | |
| 14126 | 14461 | } |
| 14127 | 14462 | |
| 14128 | 14463 | bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); |
| ... | ... | @@ -14412,10 +14747,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 14412 | 14747 | } |
| 14413 | 14748 | case ConstPtrSpecialBaseStruct: |
| 14414 | 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 | 14756 | case ConstPtrSpecialHardCodedAddr: |
| 14416 | 14757 | zig_unreachable(); |
| 14417 | 14758 | case ConstPtrSpecialFunction: |
| 14418 | 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 | 14763 | if (new_index >= mem_size) { |
| 14421 | 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 | 14808 | } |
| 14466 | 14809 | case ConstPtrSpecialBaseStruct: |
| 14467 | 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 | 14817 | case ConstPtrSpecialHardCodedAddr: |
| 14469 | 14818 | zig_unreachable(); |
| 14470 | 14819 | case ConstPtrSpecialFunction: |
| 14471 | 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 | 14824 | return result; |
| 14474 | 14825 | } else if (array_type->id == ZigTypeIdArray) { |
| ... | ... | @@ -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) { | |
| 15159 | IrInstruction *ptr = load_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; | |
| 15509 | static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) { | |
| 15510 | IrInstruction *ptr = instruction->ptr->child; | |
| 15167 | 15511 | if (type_is_invalid(ptr->value.type)) |
| 15168 | 15512 | return ira->codegen->invalid_instruction; |
| 15169 | 15513 | |
| 15170 | IrInstruction *value = store_ptr_instruction->value->child; | |
| 15514 | IrInstruction *value = instruction->value->child; | |
| 15171 | 15515 | if (type_is_invalid(value->value.type)) |
| 15172 | 15516 | return ira->codegen->invalid_instruction; |
| 15173 | 15517 | |
| 15174 | if (ptr->value.type->id != ZigTypeIdPointer) { | |
| 15175 | ir_add_error(ira, ptr, | |
| 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 | } | |
| 15518 | return ir_analyze_store_ptr(ira, &instruction->base, ptr, value); | |
| 15519 | } | |
| 15188 | 15520 | |
| 15189 | ZigType *child_type = ptr->value.type->data.pointer.child_type; | |
| 15190 | IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type); | |
| 15191 | if (casted_value == ira->codegen->invalid_instruction) | |
| 15521 | static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) { | |
| 15522 | IrInstruction *ptr = instruction->ptr->child; | |
| 15523 | if (type_is_invalid(ptr->value.type)) | |
| 15192 | 15524 | return ira->codegen->invalid_instruction; |
| 15193 | ||
| 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; | |
| 15525 | return ir_get_deref(ira, &instruction->base, ptr); | |
| 15226 | 15526 | } |
| 15227 | 15527 | |
| 15228 | 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 | 15530 | ZigType *type_entry = expr_value->value.type; |
| 15231 | 15531 | if (type_is_invalid(type_entry)) |
| 15232 | 15532 | return ira->codegen->invalid_instruction; |
| 15233 | switch (type_entry->id) { | |
| 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(); | |
| 15533 | return ir_const_type(ira, &typeof_instruction->base, type_entry); | |
| 15264 | 15534 | } |
| 15265 | 15535 | |
| 15266 | 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 | 15769 | case ZigTypeIdNamespace: |
| 15500 | 15770 | case ZigTypeIdBoundFn: |
| 15501 | 15771 | case ZigTypeIdPromise: |
| 15772 | case ZigTypeIdVector: | |
| 15502 | 15773 | { |
| 15503 | 15774 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) |
| 15504 | 15775 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -15619,6 +15890,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 15619 | 15890 | case ZigTypeIdNamespace: |
| 15620 | 15891 | case ZigTypeIdBoundFn: |
| 15621 | 15892 | case ZigTypeIdPromise: |
| 15893 | case ZigTypeIdVector: | |
| 15622 | 15894 | { |
| 15623 | 15895 | if ((err = ensure_complete_type(ira->codegen, child_type))) |
| 15624 | 15896 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -15685,6 +15957,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 15685 | 15957 | case ZigTypeIdUnion: |
| 15686 | 15958 | case ZigTypeIdFn: |
| 15687 | 15959 | case ZigTypeIdPromise: |
| 15960 | case ZigTypeIdVector: | |
| 15688 | 15961 | { |
| 15689 | 15962 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| 15690 | 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 | 15966 | zig_unreachable(); |
| 15694 | 15967 | } |
| 15695 | 15968 | |
| 15696 | static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { | |
| 15697 | IrInstruction *value = instruction->value->child; | |
| 15698 | if (type_is_invalid(value->value.type)) | |
| 15699 | return ira->codegen->invalid_instruction; | |
| 15700 | ||
| 15969 | static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { | |
| 15701 | 15970 | ZigType *type_entry = value->value.type; |
| 15702 | 15971 | |
| 15703 | 15972 | if (type_entry->id == ZigTypeIdOptional) { |
| ... | ... | @@ -15706,60 +15975,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns |
| 15706 | 15975 | if (!maybe_val) |
| 15707 | 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 | 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 | 15983 | result->value.type = ira->codegen->builtin_types.entry_bool; |
| 15715 | 15984 | return result; |
| 15716 | 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 | 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, | |
| 15724 | IrInstructionUnwrapOptional *unwrap_maybe_instruction) | |
| 15725 | { | |
| 15726 | IrInstruction *value = unwrap_maybe_instruction->value->child; | |
| 15992 | static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { | |
| 15993 | IrInstruction *value = instruction->value->child; | |
| 15727 | 15994 | if (type_is_invalid(value->value.type)) |
| 15728 | 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 | 16004 | assert(ptr_type->id == ZigTypeIdPointer); |
| 15732 | 16005 | |
| 15733 | 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 | 16008 | return ira->codegen->invalid_instruction; |
| 15736 | } else if (type_entry->id != ZigTypeIdOptional) { | |
| 15737 | ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node, | |
| 16009 | ||
| 16010 | if (type_entry->id != ZigTypeIdOptional) { | |
| 16011 | ir_add_error_node(ira, base_ptr->source_node, | |
| 15738 | 16012 | buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); |
| 15739 | 16013 | return ira->codegen->invalid_instruction; |
| 15740 | 16014 | } |
| 16015 | ||
| 15741 | 16016 | ZigType *child_type = type_entry->data.maybe.child_type; |
| 15742 | 16017 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 15743 | 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)) { | |
| 15746 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); | |
| 16020 | if (instr_is_comptime(base_ptr)) { | |
| 16021 | ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); | |
| 15747 | 16022 | if (!val) |
| 15748 | 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 | 16025 | if (maybe_val == nullptr) |
| 15751 | 16026 | return ira->codegen->invalid_instruction; |
| 15752 | 16027 | |
| 15753 | 16028 | if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { |
| 15754 | 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 | 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 | 16034 | ConstExprValue *out_val = &result->value; |
| 15760 | 16035 | out_val->data.x_ptr.special = ConstPtrSpecialRef; |
| 15761 | 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 | 16038 | out_val->data.x_ptr.data.ref.pointee = maybe_val; |
| 15764 | 16039 | } else { |
| 15765 | 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 | 16043 | } |
| 15769 | 16044 | } |
| 15770 | 16045 | |
| 15771 | IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb, | |
| 15772 | unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node, | |
| 15773 | value, unwrap_maybe_instruction->safety_check_on); | |
| 16046 | IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, | |
| 16047 | source_instr->source_node, base_ptr, safety_check_on); | |
| 15774 | 16048 | result->value.type = result_type; |
| 15775 | 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 | 16062 | static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) { |
| 15779 | 16063 | IrInstruction *value = ctz_instruction->value->child; |
| 15780 | 16064 | if (type_is_invalid(value->value.type)) { |
| ... | ... | @@ -16075,9 +16359,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16075 | 16359 | return result; |
| 16076 | 16360 | } |
| 16077 | 16361 | |
| 16078 | IrInstruction *result = ir_build_load_ptr(&ira->new_irb, | |
| 16079 | switch_target_instruction->base.scope, switch_target_instruction->base.source_node, | |
| 16080 | target_value_ptr); | |
| 16362 | IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); | |
| 16081 | 16363 | result->value.type = target_type; |
| 16082 | 16364 | return result; |
| 16083 | 16365 | } |
| ... | ... | @@ -16107,8 +16389,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16107 | 16389 | return result; |
| 16108 | 16390 | } |
| 16109 | 16391 | |
| 16110 | IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | |
| 16111 | switch_target_instruction->base.source_node, target_value_ptr); | |
| 16392 | IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); | |
| 16112 | 16393 | union_value->value.type = target_type; |
| 16113 | 16394 | |
| 16114 | 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 | 16413 | return result; |
| 16133 | 16414 | } |
| 16134 | 16415 | |
| 16135 | IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | |
| 16136 | switch_target_instruction->base.source_node, target_value_ptr); | |
| 16416 | IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); | |
| 16137 | 16417 | enum_value->value.type = target_type; |
| 16138 | 16418 | return enum_value; |
| 16139 | 16419 | } |
| ... | ... | @@ -16147,6 +16427,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 16147 | 16427 | case ZigTypeIdBoundFn: |
| 16148 | 16428 | case ZigTypeIdArgTuple: |
| 16149 | 16429 | case ZigTypeIdOpaque: |
| 16430 | case ZigTypeIdVector: | |
| 16150 | 16431 | ir_add_error(ira, &switch_target_instruction->base, |
| 16151 | 16432 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); |
| 16152 | 16433 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -16290,7 +16571,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI |
| 16290 | 16571 | Error err; |
| 16291 | 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 | 16575 | return ira->codegen->invalid_instruction; |
| 16295 | 16576 | |
| 16296 | 16577 | if (instr_field_count != 1) { |
| ... | ... | @@ -16322,7 +16603,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI |
| 16322 | 16603 | if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) |
| 16323 | 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 | 16608 | if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || |
| 16327 | 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 | 16616 | ConstExprValue *out_val = &result->value; |
| 16335 | 16617 | out_val->data.x_union.payload = field_val; |
| 16336 | 16618 | out_val->data.x_union.tag = type_field->enum_field->value; |
| 16337 | ||
| 16338 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); | |
| 16339 | if (parent != nullptr) { | |
| 16340 | parent->id = ConstParentIdUnion; | |
| 16341 | parent->data.p_union.union_val = out_val; | |
| 16342 | } | |
| 16619 | out_val->parent.id = ConstParentIdUnion; | |
| 16620 | out_val->parent.data.p_union.union_val = out_val; | |
| 16343 | 16621 | |
| 16344 | 16622 | return result; |
| 16345 | 16623 | } |
| ... | ... | @@ -16366,7 +16644,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16366 | 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 | 16648 | return ira->codegen->invalid_instruction; |
| 16371 | 16649 | |
| 16372 | 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 | 16655 | |
| 16378 | 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 | 16661 | ConstExprValue const_val = {}; |
| 16383 | 16662 | const_val.special = ConstValSpecialStatic; |
| ... | ... | @@ -16445,9 +16724,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 16445 | 16724 | if (const_val.special == ConstValSpecialStatic) { |
| 16446 | 16725 | IrInstruction *result = ir_const(ira, instruction, nullptr); |
| 16447 | 16726 | ConstExprValue *out_val = &result->value; |
| 16448 | // TODO copy_const_val? | |
| 16449 | *out_val = const_val; | |
| 16450 | result->value.type = container_type; | |
| 16727 | copy_const_val(out_val, &const_val, true); | |
| 16728 | out_val->type = container_type; | |
| 16451 | 16729 | |
| 16452 | 16730 | for (size_t i = 0; i < instr_field_count; i += 1) { |
| 16453 | 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 | 16757 | static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 16480 | 16758 | IrInstructionContainerInitList *instruction) |
| 16481 | 16759 | { |
| 16482 | IrInstruction *container_type_value = instruction->container_type->child; | |
| 16483 | if (type_is_invalid(container_type_value->value.type)) | |
| 16760 | ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); | |
| 16761 | if (type_is_invalid(container_type)) | |
| 16484 | 16762 | return ira->codegen->invalid_instruction; |
| 16485 | 16763 | |
| 16486 | 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) { | |
| 16493 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, | |
| 16494 | 0, nullptr); | |
| 16495 | } 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 | |
| 16497 | ZigType *child_type; | |
| 16498 | if (container_type->id == ZigTypeIdArray) { | |
| 16499 | child_type = container_type->data.array.child_type; | |
| 16500 | if (container_type->data.array.len != elem_count) { | |
| 16501 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 16766 | if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { | |
| 16767 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, | |
| 16768 | 0, nullptr); | |
| 16769 | } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { | |
| 16770 | // array is same as slice init but we make a compile error if the length is wrong | |
| 16771 | ZigType *child_type; | |
| 16772 | if (container_type->id == ZigTypeIdArray) { | |
| 16773 | child_type = container_type->data.array.child_type; | |
| 16774 | if (container_type->data.array.len != elem_count) { | |
| 16775 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 16502 | 16776 | |
| 16503 | ir_add_error(ira, &instruction->base, | |
| 16504 | buf_sprintf("expected %s literal, found %s literal", | |
| 16505 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); | |
| 16506 | 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; | |
| 16777 | ir_add_error(ira, &instruction->base, | |
| 16778 | buf_sprintf("expected %s literal, found %s literal", | |
| 16779 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); | |
| 16780 | return ira->codegen->invalid_instruction; | |
| 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 = {}; | |
| 16517 | const_val.special = ConstValSpecialStatic; | |
| 16518 | const_val.type = fixed_size_array_type; | |
| 16519 | const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); | |
| 16790 | ConstExprValue const_val = {}; | |
| 16791 | const_val.special = ConstValSpecialStatic; | |
| 16792 | const_val.type = fixed_size_array_type; | |
| 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) { | |
| 16528 | IrInstruction *arg_value = instruction->items[i]->child; | |
| 16529 | if (type_is_invalid(arg_value->value.type)) | |
| 16530 | return ira->codegen->invalid_instruction; | |
| 16801 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 16802 | IrInstruction *arg_value = instruction->items[i]->child; | |
| 16803 | if (type_is_invalid(arg_value->value.type)) | |
| 16804 | return ira->codegen->invalid_instruction; | |
| 16531 | 16805 | |
| 16532 | IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); | |
| 16533 | if (casted_arg == ira->codegen->invalid_instruction) | |
| 16534 | return ira->codegen->invalid_instruction; | |
| 16806 | IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); | |
| 16807 | if (casted_arg == 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) { | |
| 16539 | if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { | |
| 16540 | ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); | |
| 16541 | if (!elem_val) | |
| 16542 | return ira->codegen->invalid_instruction; | |
| 16812 | if (const_val.special == ConstValSpecialStatic) { | |
| 16813 | if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { | |
| 16814 | ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); | |
| 16815 | if (!elem_val) | |
| 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); | |
| 16545 | } else { | |
| 16546 | first_non_const_instruction = casted_arg; | |
| 16547 | const_val.special = ConstValSpecialRuntime; | |
| 16548 | } | |
| 16818 | copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); | |
| 16819 | } else { | |
| 16820 | first_non_const_instruction = casted_arg; | |
| 16821 | const_val.special = ConstValSpecialRuntime; | |
| 16549 | 16822 | } |
| 16550 | 16823 | } |
| 16824 | } | |
| 16551 | 16825 | |
| 16552 | if (const_val.special == ConstValSpecialStatic) { | |
| 16553 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); | |
| 16554 | ConstExprValue *out_val = &result->value; | |
| 16555 | // TODO copy_const_val? | |
| 16556 | *out_val = const_val; | |
| 16557 | result->value.type = fixed_size_array_type; | |
| 16558 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 16559 | ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; | |
| 16560 | ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); | |
| 16561 | if (parent != nullptr) { | |
| 16562 | parent->id = ConstParentIdArray; | |
| 16563 | parent->data.p_array.array_val = out_val; | |
| 16564 | parent->data.p_array.elem_index = i; | |
| 16565 | } | |
| 16826 | if (const_val.special == ConstValSpecialStatic) { | |
| 16827 | IrInstruction *result = ir_const(ira, &instruction->base, nullptr); | |
| 16828 | ConstExprValue *out_val = &result->value; | |
| 16829 | copy_const_val(out_val, &const_val, true); | |
| 16830 | result->value.type = fixed_size_array_type; | |
| 16831 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 16832 | ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; | |
| 16833 | ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); | |
| 16834 | if (parent != nullptr) { | |
| 16835 | parent->id = ConstParentIdArray; | |
| 16836 | parent->data.p_array.array_val = out_val; | |
| 16837 | parent->data.p_array.elem_index = i; | |
| 16566 | 16838 | } |
| 16567 | return result; | |
| 16568 | 16839 | } |
| 16840 | return result; | |
| 16841 | } | |
| 16569 | 16842 | |
| 16570 | if (is_comptime) { | |
| 16571 | ir_add_error_node(ira, first_non_const_instruction->source_node, | |
| 16572 | buf_sprintf("unable to evaluate constant expression")); | |
| 16573 | return ira->codegen->invalid_instruction; | |
| 16574 | } | |
| 16843 | if (is_comptime) { | |
| 16844 | ir_add_error_node(ira, first_non_const_instruction->source_node, | |
| 16845 | buf_sprintf("unable to evaluate constant expression")); | |
| 16846 | return ira->codegen->invalid_instruction; | |
| 16847 | } | |
| 16575 | 16848 | |
| 16576 | IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, | |
| 16577 | instruction->base.scope, instruction->base.source_node, | |
| 16578 | container_type_value, elem_count, new_items); | |
| 16579 | new_instruction->value.type = fixed_size_array_type; | |
| 16580 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); | |
| 16581 | return new_instruction; | |
| 16582 | } else if (container_type->id == ZigTypeIdVoid) { | |
| 16583 | 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 { | |
| 16849 | IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, | |
| 16850 | instruction->base.scope, instruction->base.source_node, | |
| 16851 | nullptr, elem_count, new_items); | |
| 16852 | new_instruction->value.type = fixed_size_array_type; | |
| 16853 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); | |
| 16854 | return new_instruction; | |
| 16855 | } else if (container_type->id == ZigTypeIdVoid) { | |
| 16856 | if (elem_count != 0) { | |
| 16590 | 16857 | ir_add_error_node(ira, instruction->base.source_node, |
| 16591 | buf_sprintf("type '%s' does not support array initialization", | |
| 16592 | buf_ptr(&container_type->name))); | |
| 16858 | buf_sprintf("void expression expects no arguments")); | |
| 16593 | 16859 | return ira->codegen->invalid_instruction; |
| 16594 | 16860 | } |
| 16861 | return ir_const_void(ira, &instruction->base); | |
| 16595 | 16862 | } else { |
| 16596 | ir_add_error(ira, container_type_value, | |
| 16597 | buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name))); | |
| 16863 | ir_add_error_node(ira, instruction->base.source_node, | |
| 16864 | buf_sprintf("type '%s' does not support array initialization", | |
| 16865 | buf_ptr(&container_type->name))); | |
| 16598 | 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 | 16873 | IrInstruction *container_type_value = instruction->container_type->child; |
| 16604 | 16874 | ZigType *container_type = ir_resolve_type(ira, container_type_value); |
| 16605 | 16875 | if (type_is_invalid(container_type)) |
| ... | ... | @@ -16659,7 +16929,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct |
| 16659 | 16929 | if (type_is_invalid(value->value.type)) |
| 16660 | 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 | 16933 | if (type_is_invalid(casted_value->value.type)) |
| 16664 | 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 | 17190 | |
| 16921 | 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 | 17194 | return ira->codegen->builtin_types.entry_invalid; |
| 16925 | assert(var->value->type->id == ZigTypeIdMetaType); | |
| 16926 | return var->value->data.x_type; | |
| 17195 | ||
| 17196 | assert(var->const_value->type->id == ZigTypeIdMetaType); | |
| 17197 | return var->const_value->data.x_type; | |
| 16927 | 17198 | } |
| 16928 | 17199 | |
| 16929 | 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 | 17249 | definition_array->special = ConstValSpecialStatic; |
| 16979 | 17250 | definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); |
| 16980 | 17251 | definition_array->data.x_array.special = ConstArraySpecialNone; |
| 16981 | definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 16982 | 17252 | definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); |
| 16983 | 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 | 17279 | inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; |
| 17010 | 17280 | inner_fields[2].special = ConstValSpecialStatic; |
| 17011 | 17281 | inner_fields[2].type = type_info_definition_data_type; |
| 17012 | inner_fields[2].data.x_union.parent.id = ConstParentIdStruct; | |
| 17013 | inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; | |
| 17014 | inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; | |
| 17282 | inner_fields[2].parent.id = ConstParentIdStruct; | |
| 17283 | inner_fields[2].parent.data.p_struct.struct_val = definition_val; | |
| 17284 | inner_fields[2].parent.data.p_struct.field_index = 1; | |
| 17015 | 17285 | |
| 17016 | 17286 | switch (curr_entry->value->id) { |
| 17017 | 17287 | case TldIdVar: |
| 17018 | 17288 | { |
| 17019 | 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 | 17291 | return ErrorSemanticAnalyzeFail; |
| 17022 | 17292 | |
| 17023 | if (var->value->type->id == ZigTypeIdMetaType) | |
| 17024 | { | |
| 17293 | if (var->const_value->type->id == ZigTypeIdMetaType) { | |
| 17025 | 17294 | // We have a variable of type 'type', so it's actually a type definition. |
| 17026 | 17295 | // 0: Data.Type: type |
| 17027 | 17296 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); |
| 17028 | inner_fields[2].data.x_union.payload = var->value; | |
| 17029 | } | |
| 17030 | else | |
| 17031 | { | |
| 17297 | inner_fields[2].data.x_union.payload = var->const_value; | |
| 17298 | } else { | |
| 17032 | 17299 | // We have a variable of another type, so we store the type of the variable. |
| 17033 | 17300 | // 1: Data.Var: type |
| 17034 | 17301 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); |
| 17035 | 17302 | |
| 17036 | 17303 | ConstExprValue *payload = create_const_vals(1); |
| 17037 | 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 | 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 | 17322 | ConstExprValue *fn_def_val = create_const_vals(1); |
| 17056 | 17323 | fn_def_val->special = ConstValSpecialStatic; |
| 17057 | 17324 | fn_def_val->type = type_info_fn_def_type; |
| 17058 | fn_def_val->data.x_struct.parent.id = ConstParentIdUnion; | |
| 17059 | fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2]; | |
| 17325 | fn_def_val->parent.id = ConstParentIdUnion; | |
| 17326 | fn_def_val->parent.data.p_union.union_val = &inner_fields[2]; | |
| 17060 | 17327 | |
| 17061 | 17328 | ConstExprValue *fn_def_fields = create_const_vals(9); |
| 17062 | 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 | 17387 | fn_arg_name_array->type = get_array_type(ira->codegen, |
| 17121 | 17388 | get_slice_type(ira->codegen, u8_ptr), fn_arg_count); |
| 17122 | 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 | 17390 | fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); |
| 17125 | 17391 | |
| 17126 | 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++) | |
| 17129 | { | |
| 17394 | for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { | |
| 17130 | 17395 | ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); |
| 17131 | 17396 | ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; |
| 17132 | 17397 | ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); |
| 17133 | 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; | |
| 17135 | fn_arg_name_val->data.x_struct.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; | |
| 17399 | fn_arg_name_val->parent.id = ConstParentIdArray; | |
| 17400 | fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array; | |
| 17401 | fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index; | |
| 17137 | 17402 | } |
| 17138 | 17403 | |
| 17139 | 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 | 17619 | |
| 17355 | 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 | 17643 | case ZigTypeIdOptional: |
| 17358 | 17644 | { |
| 17359 | 17645 | result = create_const_vals(1); |
| ... | ... | @@ -17426,7 +17712,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17426 | 17712 | enum_field_array->special = ConstValSpecialStatic; |
| 17427 | 17713 | enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); |
| 17428 | 17714 | enum_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17429 | enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 17430 | 17715 | enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); |
| 17431 | 17716 | |
| 17432 | 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 | 17721 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; |
| 17437 | 17722 | ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; |
| 17438 | 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; | |
| 17440 | enum_field_val->data.x_struct.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; | |
| 17724 | enum_field_val->parent.id = ConstParentIdArray; | |
| 17725 | enum_field_val->parent.data.p_array.array_val = enum_field_array; | |
| 17726 | enum_field_val->parent.data.p_array.elem_index = enum_field_index; | |
| 17442 | 17727 | } |
| 17443 | 17728 | // defs: []TypeInfo.Definition |
| 17444 | 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 | 17750 | error_array->special = ConstValSpecialStatic; |
| 17466 | 17751 | error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); |
| 17467 | 17752 | error_array->data.x_array.special = ConstArraySpecialNone; |
| 17468 | error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 17469 | 17753 | error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); |
| 17470 | 17754 | |
| 17471 | 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 | 17773 | bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); |
| 17490 | 17774 | |
| 17491 | 17775 | error_val->data.x_struct.fields = inner_fields; |
| 17492 | error_val->data.x_struct.parent.id = ConstParentIdArray; | |
| 17493 | error_val->data.x_struct.parent.data.p_array.array_val = error_array; | |
| 17494 | error_val->data.x_struct.parent.data.p_array.elem_index = error_index; | |
| 17776 | error_val->parent.id = ConstParentIdArray; | |
| 17777 | error_val->parent.data.p_array.array_val = error_array; | |
| 17778 | error_val->parent.data.p_array.elem_index = error_index; | |
| 17495 | 17779 | } |
| 17496 | 17780 | |
| 17497 | 17781 | break; |
| ... | ... | @@ -17560,7 +17844,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE |
| 17560 | 17844 | union_field_array->special = ConstValSpecialStatic; |
| 17561 | 17845 | union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); |
| 17562 | 17846 | union_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17563 | union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 17564 | 17847 | union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); |
| 17565 | 17848 | |
| 17566 | 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 | 17876 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); |
| 17594 | 17877 | |
| 17595 | 17878 | union_field_val->data.x_struct.fields = inner_fields; |
| 17596 | union_field_val->data.x_struct.parent.id = ConstParentIdArray; | |
| 17597 | union_field_val->data.x_struct.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; | |
| 17879 | union_field_val->parent.id = ConstParentIdArray; | |
| 17880 | union_field_val->parent.data.p_array.array_val = union_field_array; | |
| 17881 | union_field_val->parent.data.p_array.elem_index = union_field_index; | |
| 17599 | 17882 | } |
| 17600 | 17883 | // defs: []TypeInfo.Definition |
| 17601 | 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 | 17918 | struct_field_array->special = ConstValSpecialStatic; |
| 17636 | 17919 | struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); |
| 17637 | 17920 | struct_field_array->data.x_array.special = ConstArraySpecialNone; |
| 17638 | struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 17639 | 17921 | struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); |
| 17640 | 17922 | |
| 17641 | 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 | 17951 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); |
| 17670 | 17952 | |
| 17671 | 17953 | struct_field_val->data.x_struct.fields = inner_fields; |
| 17672 | struct_field_val->data.x_struct.parent.id = ConstParentIdArray; | |
| 17673 | struct_field_val->data.x_struct.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; | |
| 17954 | struct_field_val->parent.id = ConstParentIdArray; | |
| 17955 | struct_field_val->parent.data.p_array.array_val = struct_field_array; | |
| 17956 | struct_field_val->parent.data.p_array.elem_index = struct_field_index; | |
| 17675 | 17957 | } |
| 17676 | 17958 | // defs: []TypeInfo.Definition |
| 17677 | 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 | 18023 | fn_arg_array->special = ConstValSpecialStatic; |
| 17742 | 18024 | fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); |
| 17743 | 18025 | fn_arg_array->data.x_array.special = ConstArraySpecialNone; |
| 17744 | fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; | |
| 17745 | 18026 | fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); |
| 17746 | 18027 | |
| 17747 | 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 | 18059 | } |
| 17779 | 18060 | |
| 17780 | 18061 | fn_arg_val->data.x_struct.fields = inner_fields; |
| 17781 | fn_arg_val->data.x_struct.parent.id = ConstParentIdArray; | |
| 17782 | fn_arg_val->data.x_struct.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; | |
| 18062 | fn_arg_val->parent.id = ConstParentIdArray; | |
| 18063 | fn_arg_val->parent.data.p_array.array_val = fn_arg_array; | |
| 18064 | fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; | |
| 17784 | 18065 | } |
| 17785 | 18066 | |
| 17786 | 18067 | break; |
| ... | ... | @@ -17824,8 +18105,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, |
| 17824 | 18105 | |
| 17825 | 18106 | if (payload != nullptr) { |
| 17826 | 18107 | assert(payload->type->id == ZigTypeIdStruct); |
| 17827 | payload->data.x_struct.parent.id = ConstParentIdUnion; | |
| 17828 | payload->data.x_struct.parent.data.p_union.union_val = out_val; | |
| 18108 | payload->parent.id = ConstParentIdUnion; | |
| 18109 | payload->parent.data.p_union.union_val = out_val; | |
| 17829 | 18110 | } |
| 17830 | 18111 | |
| 17831 | 18112 | return result; |
| ... | ... | @@ -17897,10 +18178,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct |
| 17897 | 18178 | |
| 17898 | 18179 | // Execute the C import block like an inline function |
| 17899 | 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 | 18182 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, |
| 17902 | 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 | 18185 | return ira->codegen->invalid_instruction; |
| 17905 | 18186 | |
| 17906 | 18187 | find_libc_include_path(ira->codegen); |
| ... | ... | @@ -18050,7 +18331,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru |
| 18050 | 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 | 18335 | ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); |
| 18055 | 18336 | if (type_is_invalid(operand_type)) |
| 18056 | 18337 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -18122,9 +18403,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi |
| 18122 | 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, | |
| 18126 | nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak, | |
| 18127 | operand_type, success_order, failure_order); | |
| 18406 | IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, | |
| 18407 | casted_ptr, casted_cmp_value, casted_new_value, | |
| 18408 | success_order, failure_order, instruction->is_weak); | |
| 18128 | 18409 | result->value.type = get_optional_type(ira->codegen, operand_type); |
| 18129 | 18410 | ir_add_alloca(ira, result, result->value.type); |
| 18130 | 18411 | return result; |
| ... | ... | @@ -18296,18 +18577,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst |
| 18296 | 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 | 18580 | static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { |
| 18312 | 18581 | Error err; |
| 18313 | 18582 | |
| ... | ... | @@ -18426,6 +18695,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct |
| 18426 | 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 | 18712 | static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { |
| 18430 | 18713 | ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); |
| 18431 | 18714 | if (type_is_invalid(dest_type)) |
| ... | ... | @@ -18532,6 +18815,27 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct |
| 18532 | 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 | 18839 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| 18536 | 18840 | IrInstruction *value = instruction->value->child; |
| 18537 | 18841 | if (type_is_invalid(value->value.type)) |
| ... | ... | @@ -18630,10 +18934,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio |
| 18630 | 18934 | } |
| 18631 | 18935 | case ConstPtrSpecialBaseStruct: |
| 18632 | 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 | 18943 | case ConstPtrSpecialHardCodedAddr: |
| 18634 | 18944 | zig_unreachable(); |
| 18635 | 18945 | case ConstPtrSpecialFunction: |
| 18636 | 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 | 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 | 19057 | } |
| 18746 | 19058 | case ConstPtrSpecialBaseStruct: |
| 18747 | 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 | 19066 | case ConstPtrSpecialHardCodedAddr: |
| 18749 | 19067 | zig_unreachable(); |
| 18750 | 19068 | case ConstPtrSpecialFunction: |
| 18751 | 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 | 19074 | if (dest_start + count > dest_end) { |
| ... | ... | @@ -18781,10 +19101,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 18781 | 19101 | } |
| 18782 | 19102 | case ConstPtrSpecialBaseStruct: |
| 18783 | 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 | 19110 | case ConstPtrSpecialHardCodedAddr: |
| 18785 | 19111 | zig_unreachable(); |
| 18786 | 19112 | case ConstPtrSpecialFunction: |
| 18787 | 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 | 19118 | if (src_start + count > src_end) { |
| ... | ... | @@ -18812,9 +19140,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18812 | 19140 | if (type_is_invalid(ptr_ptr->value.type)) |
| 18813 | 19141 | return ira->codegen->invalid_instruction; |
| 18814 | 19142 | |
| 18815 | ZigType *ptr_type = ptr_ptr->value.type; | |
| 18816 | assert(ptr_type->id == ZigTypeIdPointer); | |
| 18817 | ZigType *array_type = ptr_type->data.pointer.child_type; | |
| 19143 | ZigType *ptr_ptr_type = ptr_ptr->value.type; | |
| 19144 | assert(ptr_ptr_type->id == ZigTypeIdPointer); | |
| 19145 | ZigType *array_type = ptr_ptr_type->data.pointer.child_type; | |
| 18818 | 19146 | |
| 18819 | 19147 | IrInstruction *start = instruction->start->child; |
| 18820 | 19148 | if (type_is_invalid(start->value.type)) |
| ... | ... | @@ -18843,10 +19171,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18843 | 19171 | bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && |
| 18844 | 19172 | ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; |
| 18845 | 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, | |
| 18847 | ptr_type->data.pointer.is_volatile, | |
| 19174 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, | |
| 19175 | ptr_ptr_type->data.pointer.is_volatile, | |
| 18848 | 19176 | PtrLenUnknown, |
| 18849 | ptr_type->data.pointer.explicit_alignment, 0, 0); | |
| 19177 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0); | |
| 18850 | 19178 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 18851 | 19179 | } else if (array_type->id == ZigTypeIdPointer) { |
| 18852 | 19180 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| ... | ... | @@ -18944,6 +19272,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18944 | 19272 | break; |
| 18945 | 19273 | case ConstPtrSpecialBaseStruct: |
| 18946 | 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 | 19281 | case ConstPtrSpecialHardCodedAddr: |
| 18948 | 19282 | array_val = nullptr; |
| 18949 | 19283 | abs_offset = 0; |
| ... | ... | @@ -18951,6 +19285,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18951 | 19285 | break; |
| 18952 | 19286 | case ConstPtrSpecialFunction: |
| 18953 | 19287 | zig_panic("TODO slice of ptr cast from function"); |
| 19288 | case ConstPtrSpecialNull: | |
| 19289 | zig_panic("TODO slice of null ptr"); | |
| 18954 | 19290 | } |
| 18955 | 19291 | } else if (is_slice(array_type)) { |
| 18956 | 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 | 19317 | break; |
| 18982 | 19318 | case ConstPtrSpecialBaseStruct: |
| 18983 | 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 | 19326 | case ConstPtrSpecialHardCodedAddr: |
| 18985 | 19327 | array_val = nullptr; |
| 18986 | 19328 | abs_offset = 0; |
| ... | ... | @@ -18988,6 +19330,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 18988 | 19330 | break; |
| 18989 | 19331 | case ConstPtrSpecialFunction: |
| 18990 | 19332 | zig_panic("TODO slice of slice cast from function"); |
| 19333 | case ConstPtrSpecialNull: | |
| 19334 | zig_panic("TODO slice of null"); | |
| 18991 | 19335 | } |
| 18992 | 19336 | } else { |
| 18993 | 19337 | zig_unreachable(); |
| ... | ... | @@ -19053,6 +19397,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 19053 | 19397 | zig_unreachable(); |
| 19054 | 19398 | case ConstPtrSpecialBaseStruct: |
| 19055 | 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 | 19406 | case ConstPtrSpecialHardCodedAddr: |
| 19057 | 19407 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, |
| 19058 | 19408 | parent_ptr->type->data.pointer.child_type, |
| ... | ... | @@ -19061,6 +19411,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 19061 | 19411 | break; |
| 19062 | 19412 | case ConstPtrSpecialFunction: |
| 19063 | 19413 | zig_panic("TODO"); |
| 19414 | case ConstPtrSpecialNull: | |
| 19415 | zig_panic("TODO"); | |
| 19064 | 19416 | } |
| 19065 | 19417 | |
| 19066 | 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 | 19639 | case ZigTypeIdEnum: |
| 19288 | 19640 | case ZigTypeIdUnion: |
| 19289 | 19641 | case ZigTypeIdFn: |
| 19642 | case ZigTypeIdVector: | |
| 19290 | 19643 | { |
| 19291 | 19644 | uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); |
| 19292 | 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 | 19769 | return ira->codegen->invalid_instruction; |
| 19417 | 19770 | |
| 19418 | 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 | 19796 | } |
| 19443 | 19797 | } |
| 19444 | 19798 | |
| 19445 | static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, | |
| 19446 | IrInstructionUnwrapErrCode *instruction) | |
| 19447 | { | |
| 19448 | IrInstruction *value = instruction->value->child; | |
| 19449 | if (type_is_invalid(value->value.type)) | |
| 19799 | static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { | |
| 19800 | IrInstruction *base_ptr = instruction->err_union->child; | |
| 19801 | if (type_is_invalid(base_ptr->value.type)) | |
| 19450 | 19802 | return ira->codegen->invalid_instruction; |
| 19451 | ZigType *ptr_type = value->value.type; | |
| 19803 | ZigType *ptr_type = base_ptr->value.type; | |
| 19452 | 19804 | |
| 19453 | 19805 | // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. |
| 19454 | 19806 | assert(ptr_type->id == ZigTypeIdPointer); |
| 19455 | 19807 | |
| 19456 | 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 | 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, | |
| 19472 | type_entry->data.error_union.err_set_type); | |
| 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, | |
| 19812 | if (type_entry->id != ZigTypeIdErrorUnion) { | |
| 19813 | ir_add_error(ira, base_ptr, | |
| 19484 | 19814 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| 19485 | 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 | 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 | 19852 | assert(ptr_type->id == ZigTypeIdPointer); |
| 19500 | 19853 | |
| 19501 | 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 | 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); | |
| 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 { | |
| 19858 | if (type_entry->id != ZigTypeIdErrorUnion) { | |
| 19539 | 19859 | ir_add_error(ira, value, |
| 19540 | 19860 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| 19541 | 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 | 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 | 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 | 20314 | copy_const_val(&result->value, val, false); |
| 19962 | 20315 | result->value.type = result_type; |
| 19963 | 20316 | return result; |
| ... | ... | @@ -20005,8 +20358,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20005 | 20358 | if (!val) |
| 20006 | 20359 | return ira->codegen->invalid_instruction; |
| 20007 | 20360 | |
| 20008 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, | |
| 20009 | dest_type); | |
| 20361 | IrInstruction *result = ir_const(ira, source_instr, dest_type); | |
| 20010 | 20362 | copy_const_val(&result->value, val, false); |
| 20011 | 20363 | result->value.type = dest_type; |
| 20012 | 20364 | return result; |
| ... | ... | @@ -20029,9 +20381,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20029 | 20381 | return ira->codegen->invalid_instruction; |
| 20030 | 20382 | } |
| 20031 | 20383 | |
| 20032 | IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope, | |
| 20033 | source_instr->source_node, nullptr, ptr); | |
| 20034 | casted_ptr->value.type = dest_type; | |
| 20384 | IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); | |
| 20035 | 20385 | |
| 20036 | 20386 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { |
| 20037 | 20387 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| ... | ... | @@ -20057,7 +20407,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20057 | 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 | 20411 | IrInstruction *dest_type_value = instruction->dest_type->child; |
| 20062 | 20412 | ZigType *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20063 | 20413 | if (type_is_invalid(dest_type)) |
| ... | ... | @@ -20071,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct |
| 20071 | 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 | 20435 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { |
| 20075 | 20436 | if (val->special == ConstValSpecialUndef) |
| 20076 | 20437 | val->special = ConstValSpecialStatic; |
| ... | ... | @@ -20116,17 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 20116 | 20477 | zig_unreachable(); |
| 20117 | 20478 | } |
| 20118 | 20479 | case ZigTypeIdArray: |
| 20119 | { | |
| 20120 | size_t buf_i = 0; | |
| 20121 | // TODO optimize the buf case | |
| 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; | |
| 20480 | return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); | |
| 20481 | case ZigTypeIdVector: | |
| 20482 | return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); | |
| 20130 | 20483 | case ZigTypeIdStruct: |
| 20131 | 20484 | zig_panic("TODO buf_write_value_bytes struct type"); |
| 20132 | 20485 | case ZigTypeIdOptional: |
| ... | ... | @@ -20143,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 20143 | 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 | 20524 | static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { |
| 20147 | 20525 | Error err; |
| 20148 | 20526 | assert(val->special == ConstValSpecialStatic); |
| ... | ... | @@ -20181,29 +20559,27 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 20181 | 20559 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); |
| 20182 | 20560 | return ErrorNone; |
| 20183 | 20561 | } |
| 20184 | case ZigTypeIdArray: { | |
| 20185 | uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); | |
| 20186 | size_t len = val->type->data.array.len; | |
| 20187 | ||
| 20188 | switch (val->data.x_array.special) { | |
| 20189 | case ConstArraySpecialNone: | |
| 20190 | val->data.x_array.data.s_none.elements = create_const_vals(len); | |
| 20191 | for (size_t i = 0; i < len; i++) { | |
| 20192 | ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; | |
| 20193 | elem->special = ConstValSpecialStatic; | |
| 20194 | elem->type = val->type->data.array.child_type; | |
| 20195 | if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) | |
| 20196 | return err; | |
| 20197 | } | |
| 20198 | break; | |
| 20199 | case ConstArraySpecialUndef: | |
| 20200 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); | |
| 20201 | case ConstArraySpecialBuf: | |
| 20202 | zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); | |
| 20562 | case ZigTypeIdArray: | |
| 20563 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, | |
| 20564 | val->type->data.array.len); | |
| 20565 | case ZigTypeIdVector: | |
| 20566 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, | |
| 20567 | val->type->data.vector.len); | |
| 20568 | case ZigTypeIdEnum: | |
| 20569 | switch (val->type->data.enumeration.layout) { | |
| 20570 | case ContainerLayoutAuto: | |
| 20571 | zig_panic("TODO buf_read_value_bytes enum auto"); | |
| 20572 | case ContainerLayoutPacked: | |
| 20573 | zig_panic("TODO buf_read_value_bytes enum packed"); | |
| 20574 | case ContainerLayoutExtern: { | |
| 20575 | ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; | |
| 20576 | assert(tag_int_type->id == ZigTypeIdInt); | |
| 20577 | bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, | |
| 20578 | codegen->is_big_endian, tag_int_type->data.integral.is_signed); | |
| 20579 | return ErrorNone; | |
| 20580 | } | |
| 20203 | 20581 | } |
| 20204 | ||
| 20205 | return ErrorNone; | |
| 20206 | } | |
| 20582 | zig_unreachable(); | |
| 20207 | 20583 | case ZigTypeIdStruct: |
| 20208 | 20584 | switch (val->type->data.structure.layout) { |
| 20209 | 20585 | case ContainerLayoutAuto: { |
| ... | ... | @@ -20242,8 +20618,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 20242 | 20618 | zig_panic("TODO buf_read_value_bytes error union"); |
| 20243 | 20619 | case ZigTypeIdErrorSet: |
| 20244 | 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 | 20621 | case ZigTypeIdFn: |
| 20248 | 20622 | zig_panic("TODO buf_read_value_bytes fn type"); |
| 20249 | 20623 | case ZigTypeIdUnion: |
| ... | ... | @@ -20264,10 +20638,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct |
| 20264 | 20638 | if (type_is_invalid(src_type)) |
| 20265 | 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 | 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 | 20645 | return ira->codegen->invalid_instruction; |
| 20272 | 20646 | |
| 20273 | 20647 | if (get_codegen_ptr_type(src_type) != nullptr) { |
| ... | ... | @@ -20330,6 +20704,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct |
| 20330 | 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 | 20717 | if (instr_is_comptime(value)) { |
| 20334 | 20718 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); |
| 20335 | 20719 | if (!val) |
| ... | ... | @@ -20410,8 +20794,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 20410 | 20794 | case TldIdContainer: |
| 20411 | 20795 | case TldIdCompTime: |
| 20412 | 20796 | zig_unreachable(); |
| 20413 | case TldIdVar: | |
| 20414 | { | |
| 20797 | case TldIdVar: { | |
| 20415 | 20798 | TldVar *tld_var = (TldVar *)tld; |
| 20416 | 20799 | ZigVar *var = tld_var->var; |
| 20417 | 20800 | |
| ... | ... | @@ -20429,8 +20812,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 20429 | 20812 | return ir_get_deref(ira, &instruction->base, var_ptr); |
| 20430 | 20813 | } |
| 20431 | 20814 | } |
| 20432 | case TldIdFn: | |
| 20433 | { | |
| 20815 | case TldIdFn: { | |
| 20434 | 20816 | TldFn *tld_fn = (TldFn *)tld; |
| 20435 | 20817 | ZigFn *fn_entry = tld_fn->fn_entry; |
| 20436 | 20818 | assert(fn_entry->type_entry); |
| ... | ... | @@ -20476,8 +20858,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru |
| 20476 | 20858 | if (!val) |
| 20477 | 20859 | return ira->codegen->invalid_instruction; |
| 20478 | 20860 | if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { |
| 20479 | IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, | |
| 20480 | instruction->base.source_node, usize); | |
| 20861 | IrInstruction *result = ir_const(ira, &instruction->base, usize); | |
| 20481 | 20862 | bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); |
| 20482 | 20863 | result->value.type = usize; |
| 20483 | 20864 | return result; |
| ... | ... | @@ -21315,6 +21696,11 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21315 | 21696 | case IrInstructionIdErrWrapCode: |
| 21316 | 21697 | case IrInstructionIdErrWrapPayload: |
| 21317 | 21698 | case IrInstructionIdCast: |
| 21699 | case IrInstructionIdDeclVarGen: | |
| 21700 | case IrInstructionIdPtrCastGen: | |
| 21701 | case IrInstructionIdCmpxchgGen: | |
| 21702 | case IrInstructionIdArrayToVector: | |
| 21703 | case IrInstructionIdVectorToArray: | |
| 21318 | 21704 | zig_unreachable(); |
| 21319 | 21705 | |
| 21320 | 21706 | case IrInstructionIdReturn: |
| ... | ... | @@ -21325,8 +21711,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21325 | 21711 | return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); |
| 21326 | 21712 | case IrInstructionIdBinOp: |
| 21327 | 21713 | return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); |
| 21328 | case IrInstructionIdDeclVar: | |
| 21329 | return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); | |
| 21714 | case IrInstructionIdDeclVarSrc: | |
| 21715 | return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction); | |
| 21330 | 21716 | case IrInstructionIdLoadPtr: |
| 21331 | 21717 | return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); |
| 21332 | 21718 | case IrInstructionIdStorePtr: |
| ... | ... | @@ -21371,8 +21757,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21371 | 21757 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| 21372 | 21758 | case IrInstructionIdTestNonNull: |
| 21373 | 21759 | return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); |
| 21374 | case IrInstructionIdUnwrapOptional: | |
| 21375 | return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction); | |
| 21760 | case IrInstructionIdOptionalUnwrapPtr: | |
| 21761 | return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction); | |
| 21376 | 21762 | case IrInstructionIdClz: |
| 21377 | 21763 | return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); |
| 21378 | 21764 | case IrInstructionIdCtz: |
| ... | ... | @@ -21413,8 +21799,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21413 | 21799 | return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); |
| 21414 | 21800 | case IrInstructionIdEmbedFile: |
| 21415 | 21801 | return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction); |
| 21416 | case IrInstructionIdCmpxchg: | |
| 21417 | return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction); | |
| 21802 | case IrInstructionIdCmpxchgSrc: | |
| 21803 | return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction); | |
| 21418 | 21804 | case IrInstructionIdFence: |
| 21419 | 21805 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); |
| 21420 | 21806 | case IrInstructionIdTruncate: |
| ... | ... | @@ -21437,6 +21823,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21437 | 21823 | return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction); |
| 21438 | 21824 | case IrInstructionIdIntType: |
| 21439 | 21825 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); |
| 21826 | case IrInstructionIdVectorType: | |
| 21827 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); | |
| 21440 | 21828 | case IrInstructionIdBoolNot: |
| 21441 | 21829 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 21442 | 21830 | case IrInstructionIdMemset: |
| ... | ... | @@ -21481,8 +21869,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21481 | 21869 | return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); |
| 21482 | 21870 | case IrInstructionIdPanic: |
| 21483 | 21871 | return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); |
| 21484 | case IrInstructionIdPtrCast: | |
| 21485 | return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction); | |
| 21872 | case IrInstructionIdPtrCastSrc: | |
| 21873 | return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); | |
| 21486 | 21874 | case IrInstructionIdBitCast: |
| 21487 | 21875 | return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); |
| 21488 | 21876 | case IrInstructionIdIntToPtr: |
| ... | ... | @@ -21666,7 +22054,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21666 | 22054 | case IrInstructionIdBr: |
| 21667 | 22055 | case IrInstructionIdCondBr: |
| 21668 | 22056 | case IrInstructionIdSwitchBr: |
| 21669 | case IrInstructionIdDeclVar: | |
| 22057 | case IrInstructionIdDeclVarSrc: | |
| 22058 | case IrInstructionIdDeclVarGen: | |
| 21670 | 22059 | case IrInstructionIdStorePtr: |
| 21671 | 22060 | case IrInstructionIdCall: |
| 21672 | 22061 | case IrInstructionIdReturn: |
| ... | ... | @@ -21681,7 +22070,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21681 | 22070 | case IrInstructionIdCInclude: |
| 21682 | 22071 | case IrInstructionIdCDefine: |
| 21683 | 22072 | case IrInstructionIdCUndef: |
| 21684 | case IrInstructionIdCmpxchg: | |
| 21685 | 22073 | case IrInstructionIdFence: |
| 21686 | 22074 | case IrInstructionIdMemset: |
| 21687 | 22075 | case IrInstructionIdMemcpy: |
| ... | ... | @@ -21709,6 +22097,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21709 | 22097 | case IrInstructionIdMergeErrRetTraces: |
| 21710 | 22098 | case IrInstructionIdMarkErrRetTracePtr: |
| 21711 | 22099 | case IrInstructionIdAtomicRmw: |
| 22100 | case IrInstructionIdCmpxchgGen: | |
| 22101 | case IrInstructionIdCmpxchgSrc: | |
| 21712 | 22102 | return true; |
| 21713 | 22103 | |
| 21714 | 22104 | case IrInstructionIdPhi: |
| ... | ... | @@ -21734,7 +22124,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21734 | 22124 | case IrInstructionIdSliceType: |
| 21735 | 22125 | case IrInstructionIdSizeOf: |
| 21736 | 22126 | case IrInstructionIdTestNonNull: |
| 21737 | case IrInstructionIdUnwrapOptional: | |
| 22127 | case IrInstructionIdOptionalUnwrapPtr: | |
| 21738 | 22128 | case IrInstructionIdClz: |
| 21739 | 22129 | case IrInstructionIdCtz: |
| 21740 | 22130 | case IrInstructionIdPopCount: |
| ... | ... | @@ -21745,6 +22135,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21745 | 22135 | case IrInstructionIdEmbedFile: |
| 21746 | 22136 | case IrInstructionIdTruncate: |
| 21747 | 22137 | case IrInstructionIdIntType: |
| 22138 | case IrInstructionIdVectorType: | |
| 21748 | 22139 | case IrInstructionIdBoolNot: |
| 21749 | 22140 | case IrInstructionIdSlice: |
| 21750 | 22141 | case IrInstructionIdMemberCount: |
| ... | ... | @@ -21761,7 +22152,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21761 | 22152 | case IrInstructionIdErrWrapPayload: |
| 21762 | 22153 | case IrInstructionIdFnProto: |
| 21763 | 22154 | case IrInstructionIdTestComptime: |
| 21764 | case IrInstructionIdPtrCast: | |
| 22155 | case IrInstructionIdPtrCastSrc: | |
| 22156 | case IrInstructionIdPtrCastGen: | |
| 21765 | 22157 | case IrInstructionIdBitCast: |
| 21766 | 22158 | case IrInstructionIdWidenOrShorten: |
| 21767 | 22159 | case IrInstructionIdPtrToInt: |
| ... | ... | @@ -21804,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21804 | 22196 | case IrInstructionIdFromBytes: |
| 21805 | 22197 | case IrInstructionIdToBytes: |
| 21806 | 22198 | case IrInstructionIdEnumToInt: |
| 22199 | case IrInstructionIdVectorToArray: | |
| 22200 | case IrInstructionIdArrayToVector: | |
| 21807 | 22201 | return false; |
| 21808 | 22202 | |
| 21809 | 22203 | case IrInstructionIdAsm: |
src/ir.hpp+1-1| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); |
| 14 | 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 | 17 | ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, |
| 18 | 18 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 19 | 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 | 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 | 176 | const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; |
| 177 | 177 | const char *name = buf_ptr(&decl_var_instruction->var->name); |
| 178 | 178 | if (decl_var_instruction->var_type) { |
| ... | ... | @@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | 334 | static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { |
| 335 | fprintf(irp->f, "*"); | |
| 336 | 335 | ir_print_other_instruction(irp, instruction->ptr); |
| 336 | fprintf(irp->f, ".*"); | |
| 337 | 337 | } |
| 338 | 338 | |
| 339 | 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 | 479 | fprintf(irp->f, ")"); |
| 480 | 480 | } |
| 481 | 481 | |
| 482 | static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { | |
| 483 | fprintf(irp->f, "*"); | |
| 482 | static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { | |
| 484 | 483 | ir_print_other_instruction(irp, instruction->value); |
| 485 | 484 | fprintf(irp->f, " != null"); |
| 486 | 485 | } |
| 487 | 486 | |
| 488 | static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) { | |
| 489 | fprintf(irp->f, "&??*"); | |
| 490 | ir_print_other_instruction(irp, instruction->value); | |
| 487 | static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) { | |
| 488 | fprintf(irp->f, "&"); | |
| 489 | ir_print_other_instruction(irp, instruction->base_ptr); | |
| 490 | fprintf(irp->f, ".*.?"); | |
| 491 | 491 | if (!instruction->safety_check_on) { |
| 492 | 492 | fprintf(irp->f, " // no safety"); |
| 493 | 493 | } |
| ... | ... | @@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio |
| 613 | 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 | 617 | fprintf(irp->f, "@cmpxchg("); |
| 618 | 618 | ir_print_other_instruction(irp, instruction->ptr); |
| 619 | 619 | fprintf(irp->f, ", "); |
| ... | ... | @@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { |
| 627 | 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 | 640 | static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { |
| 631 | 641 | fprintf(irp->f, "@fence("); |
| 632 | 642 | ir_print_other_instruction(irp, instruction->order_value); |
| ... | ... | @@ -709,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { |
| 709 | 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 | 730 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { |
| 713 | 731 | fprintf(irp->f, "! "); |
| 714 | 732 | ir_print_other_instruction(irp, instruction->value); |
| ... | ... | @@ -820,13 +838,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { |
| 820 | 838 | } |
| 821 | 839 | |
| 822 | 840 | static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { |
| 823 | fprintf(irp->f, "@unwrapErrorCode("); | |
| 824 | ir_print_other_instruction(irp, instruction->value); | |
| 841 | fprintf(irp->f, "UnwrapErrorCode("); | |
| 842 | ir_print_other_instruction(irp, instruction->err_union); | |
| 825 | 843 | fprintf(irp->f, ")"); |
| 826 | 844 | } |
| 827 | 845 | |
| 828 | 846 | static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { |
| 829 | fprintf(irp->f, "@unwrapErrorPayload("); | |
| 847 | fprintf(irp->f, "ErrorUnionFieldPayload("); | |
| 830 | 848 | ir_print_other_instruction(irp, instruction->value); |
| 831 | 849 | fprintf(irp->f, ")"); |
| 832 | 850 | if (!instruction->safety_check_on) { |
| ... | ... | @@ -879,7 +897,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst |
| 879 | 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 | 901 | fprintf(irp->f, "@ptrCast("); |
| 884 | 902 | if (instruction->dest_type) { |
| 885 | 903 | ir_print_other_instruction(irp, instruction->dest_type); |
| ... | ... | @@ -889,6 +907,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { |
| 889 | 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 | 916 | static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { |
| 893 | 917 | fprintf(irp->f, "@bitCast("); |
| 894 | 918 | if (instruction->dest_type) { |
| ... | ... | @@ -900,7 +924,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { |
| 900 | 924 | } |
| 901 | 925 | |
| 902 | 926 | static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { |
| 903 | fprintf(irp->f, "@widenOrShorten("); | |
| 927 | fprintf(irp->f, "WidenOrShorten("); | |
| 904 | 928 | ir_print_other_instruction(irp, instruction->target); |
| 905 | 929 | fprintf(irp->f, ")"); |
| 906 | 930 | } |
| ... | ... | @@ -948,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime |
| 948 | 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 | 987 | static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { |
| 952 | 988 | fprintf(irp->f, "inttoerr "); |
| 953 | 989 | ir_print_other_instruction(irp, instruction->target); |
| ... | ... | @@ -1323,6 +1359,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { |
| 1323 | 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 | 1376 | static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { |
| 1327 | 1377 | fprintf(irp->f, "@bswap("); |
| 1328 | 1378 | if (instruction->type != nullptr) { |
| ... | ... | @@ -1361,8 +1411,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1361 | 1411 | case IrInstructionIdBinOp: |
| 1362 | 1412 | ir_print_bin_op(irp, (IrInstructionBinOp *)instruction); |
| 1363 | 1413 | break; |
| 1364 | case IrInstructionIdDeclVar: | |
| 1365 | ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction); | |
| 1414 | case IrInstructionIdDeclVarSrc: | |
| 1415 | ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction); | |
| 1366 | 1416 | break; |
| 1367 | 1417 | case IrInstructionIdCast: |
| 1368 | 1418 | ir_print_cast(irp, (IrInstructionCast *)instruction); |
| ... | ... | @@ -1452,10 +1502,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1452 | 1502 | ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); |
| 1453 | 1503 | break; |
| 1454 | 1504 | case IrInstructionIdTestNonNull: |
| 1455 | ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction); | |
| 1505 | ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction); | |
| 1456 | 1506 | break; |
| 1457 | case IrInstructionIdUnwrapOptional: | |
| 1458 | ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction); | |
| 1507 | case IrInstructionIdOptionalUnwrapPtr: | |
| 1508 | ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction); | |
| 1459 | 1509 | break; |
| 1460 | 1510 | case IrInstructionIdCtz: |
| 1461 | 1511 | ir_print_ctz(irp, (IrInstructionCtz *)instruction); |
| ... | ... | @@ -1508,8 +1558,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1508 | 1558 | case IrInstructionIdEmbedFile: |
| 1509 | 1559 | ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction); |
| 1510 | 1560 | break; |
| 1511 | case IrInstructionIdCmpxchg: | |
| 1512 | ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction); | |
| 1561 | case IrInstructionIdCmpxchgSrc: | |
| 1562 | ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction); | |
| 1563 | break; | |
| 1564 | case IrInstructionIdCmpxchgGen: | |
| 1565 | ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction); | |
| 1513 | 1566 | break; |
| 1514 | 1567 | case IrInstructionIdFence: |
| 1515 | 1568 | ir_print_fence(irp, (IrInstructionFence *)instruction); |
| ... | ... | @@ -1544,6 +1597,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1544 | 1597 | case IrInstructionIdIntType: |
| 1545 | 1598 | ir_print_int_type(irp, (IrInstructionIntType *)instruction); |
| 1546 | 1599 | break; |
| 1600 | case IrInstructionIdVectorType: | |
| 1601 | ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); | |
| 1602 | break; | |
| 1547 | 1603 | case IrInstructionIdBoolNot: |
| 1548 | 1604 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); |
| 1549 | 1605 | break; |
| ... | ... | @@ -1607,8 +1663,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1607 | 1663 | case IrInstructionIdTestComptime: |
| 1608 | 1664 | ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); |
| 1609 | 1665 | break; |
| 1610 | case IrInstructionIdPtrCast: | |
| 1611 | ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction); | |
| 1666 | case IrInstructionIdPtrCastSrc: | |
| 1667 | ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction); | |
| 1668 | break; | |
| 1669 | case IrInstructionIdPtrCastGen: | |
| 1670 | ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); | |
| 1612 | 1671 | break; |
| 1613 | 1672 | case IrInstructionIdBitCast: |
| 1614 | 1673 | ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); |
| ... | ... | @@ -1775,6 +1834,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1775 | 1834 | case IrInstructionIdCheckRuntimeScope: |
| 1776 | 1835 | ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); |
| 1777 | 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 | 1847 | fprintf(irp->f, "\n"); |
| 1780 | 1848 | } |
src/main.cpp+6| ... | ... | @@ -59,6 +59,7 @@ static int print_full_usage(const char *arg0) { |
| 59 | 59 | " --release-fast build with optimizations on and safety off\n" |
| 60 | 60 | " --release-safe build with optimizations on and safety on\n" |
| 61 | 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 | 63 | " --static output will be statically linked\n" |
| 63 | 64 | " --strip exclude debug symbols\n" |
| 64 | 65 | " --target-arch [name] specify target architecture\n" |
| ... | ... | @@ -393,6 +394,7 @@ int main(int argc, char **argv) { |
| 393 | 394 | bool no_rosegment_workaround = false; |
| 394 | 395 | bool system_linker_hack = false; |
| 395 | 396 | TargetSubsystem subsystem = TargetSubsystemAuto; |
| 397 | bool is_single_threaded = false; | |
| 396 | 398 | |
| 397 | 399 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { |
| 398 | 400 | Buf zig_exe_path_buf = BUF_INIT; |
| ... | ... | @@ -550,6 +552,8 @@ int main(int argc, char **argv) { |
| 550 | 552 | disable_pic = true; |
| 551 | 553 | } else if (strcmp(arg, "--system-linker-hack") == 0) { |
| 552 | 554 | system_linker_hack = true; |
| 555 | } else if (strcmp(arg, "--single-threaded") == 0) { | |
| 556 | is_single_threaded = true; | |
| 553 | 557 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { |
| 554 | 558 | test_exec_args.append(nullptr); |
| 555 | 559 | } else if (arg[1] == 'L' && arg[2] != 0) { |
| ... | ... | @@ -816,6 +820,7 @@ int main(int argc, char **argv) { |
| 816 | 820 | switch (cmd) { |
| 817 | 821 | case CmdBuiltin: { |
| 818 | 822 | CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); |
| 823 | g->is_single_threaded = is_single_threaded; | |
| 819 | 824 | Buf *builtin_source = codegen_generate_builtin_source(g); |
| 820 | 825 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { |
| 821 | 826 | fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); |
| ... | ... | @@ -889,6 +894,7 @@ int main(int argc, char **argv) { |
| 889 | 894 | codegen_set_out_name(g, buf_out_name); |
| 890 | 895 | codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); |
| 891 | 896 | codegen_set_is_test(g, cmd == CmdTest); |
| 897 | g->is_single_threaded = is_single_threaded; | |
| 892 | 898 | codegen_set_linker_script(g, linker_script); |
| 893 | 899 | if (each_lib_rpath) |
| 894 | 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 | 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 | 1812 | #if defined(ZIG_OS_WINDOWS) |
| 1813 | 1813 | // TODO use CreateFileW |
| 1814 | 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 | 1834 | return ErrorUnexpected; |
| 1835 | 1835 | } |
| 1836 | 1836 | } |
| 1837 | ||
| 1838 | 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 | 1849 | return ErrorNone; |
| 1840 | 1850 | #else |
| 1841 | 1851 | for (;;) { |
| ... | ... | @@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { |
| 1858 | 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 | 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 | 1891 | return ErrorNone; |
| 1863 | 1892 | } |
| 1864 | 1893 | #endif |
| ... | ... | @@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1948 | 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 | 1980 | Error os_file_read(OsFile file, void *ptr, size_t *len) { |
| 1981 | 1981 | #if defined(ZIG_OS_WINDOWS) |
| 1982 | 1982 | DWORD amt_read; |
src/os.hpp+1-2| ... | ... | @@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path); |
| 101 | 101 | Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); |
| 102 | 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 | 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 | 106 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); |
| 108 | 107 | Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); |
| 109 | 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 | 381 | else_body = ast_expect(pc, body_parser); |
| 382 | 382 | } |
| 383 | 383 | |
| 384 | assert(res->type == NodeTypeTestExpr); | |
| 384 | assert(res->type == NodeTypeIfOptional); | |
| 385 | 385 | if (err_payload != nullptr) { |
| 386 | 386 | AstNodeTestExpr old = res->data.test_expr; |
| 387 | 387 | res->type = NodeTypeIfErrorExpr; |
| ... | ... | @@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { |
| 990 | 990 | if (requires_semi && else_body == nullptr) |
| 991 | 991 | expect_token(pc, TokenIdSemicolon); |
| 992 | 992 | |
| 993 | assert(res->type == NodeTypeTestExpr); | |
| 993 | assert(res->type == NodeTypeIfOptional); | |
| 994 | 994 | if (err_payload != nullptr) { |
| 995 | 995 | AstNodeTestExpr old = res->data.test_expr; |
| 996 | 996 | res->type = NodeTypeIfErrorExpr; |
| ... | ... | @@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { |
| 2204 | 2204 | Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc); |
| 2205 | 2205 | |
| 2206 | 2206 | PtrPayload payload; |
| 2207 | AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first); | |
| 2207 | AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); | |
| 2208 | 2208 | res->data.test_expr.target_node = condition; |
| 2209 | 2209 | if (opt_payload.unwrap(&payload)) { |
| 2210 | 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 | 2999 | visit_field(&node->data.if_err_expr.then_node, visit, context); |
| 3000 | 3000 | visit_field(&node->data.if_err_expr.else_node, visit, context); |
| 3001 | 3001 | break; |
| 3002 | case NodeTypeTestExpr: | |
| 3002 | case NodeTypeIfOptional: | |
| 3003 | 3003 | visit_field(&node->data.test_expr.target_node, visit, context); |
| 3004 | 3004 | visit_field(&node->data.test_expr.then_node, visit, context); |
| 3005 | 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 | 248 | static void tokenize_error(Tokenize *t, const char *format, ...) { |
| 249 | 249 | t->state = TokenizeStateError; |
| 250 | 250 | |
| 251 | if (t->cur_tok) { | |
| 252 | t->out->err_line = t->cur_tok->start_line; | |
| 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 | } | |
| 251 | t->out->err_line = t->line; | |
| 252 | t->out->err_column = t->column; | |
| 258 | 253 | |
| 259 | 254 | va_list ap; |
| 260 | 255 | va_start(ap, format); |
| ... | ... | @@ -886,6 +881,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 886 | 881 | break; |
| 887 | 882 | case TokenizeStateSawAmpersand: |
| 888 | 883 | switch (c) { |
| 884 | case '&': | |
| 885 | tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); | |
| 886 | break; | |
| 889 | 887 | case '=': |
| 890 | 888 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); |
| 891 | 889 | end_token(&t); |
src/zig_llvm.cpp+13| ... | ... | @@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch |
| 263 | 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 | 279 | ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits, |
| 267 | 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 | 191 | unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, |
| 192 | 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 | 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 | 170 | .get_count = 0, |
| 171 | 171 | }; |
| 172 | 172 | |
| 173 | var putters: [put_thread_count]*std.os.Thread = undefined; | |
| 174 | for (putters) |*t| { | |
| 175 | t.* = try std.os.spawnThread(&context, startPuts); | |
| 176 | } | |
| 177 | var getters: [put_thread_count]*std.os.Thread = undefined; | |
| 178 | for (getters) |*t| { | |
| 179 | t.* = try std.os.spawnThread(&context, startGets); | |
| 180 | } | |
| 173 | if (builtin.single_threaded) { | |
| 174 | { | |
| 175 | var i: usize = 0; | |
| 176 | while (i < put_thread_count) : (i += 1) { | |
| 177 | std.debug.assertOrPanic(startPuts(&context) == 0); | |
| 178 | } | |
| 179 | } | |
| 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| | |
| 183 | t.wait(); | |
| 184 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | |
| 185 | for (getters) |t| | |
| 186 | t.wait(); | |
| 197 | for (putters) |t| | |
| 198 | t.wait(); | |
| 199 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | |
| 200 | for (getters) |t| | |
| 201 | t.wait(); | |
| 202 | } | |
| 187 | 203 | |
| 188 | 204 | if (context.put_sum != context.get_sum) { |
| 189 | 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 | 221 | while (put_count != 0) : (put_count -= 1) { |
| 206 | 222 | std.os.time.sleep(1); // let the os scheduler be our fuzz |
| 207 | 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 | 226 | .prev = undefined, |
| 210 | 227 | .next = undefined, |
| 211 | 228 | .data = x, |
| 212 | }) catch unreachable; | |
| 229 | }; | |
| 213 | 230 | ctx.queue.put(node); |
| 214 | 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 | 4 | |
| 5 | 5 | /// Many reader, many writer, non-allocating, thread-safe |
| 6 | 6 | /// Uses a spinlock to protect push() and pop() |
| 7 | /// When building in single threaded mode, this is a simple linked list. | |
| 7 | 8 | pub fn Stack(comptime T: type) type { |
| 8 | 9 | return struct { |
| 9 | 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 | 15 | pub const Self = @This(); |
| 13 | 16 | |
| ... | ... | @@ -19,7 +22,7 @@ pub fn Stack(comptime T: type) type { |
| 19 | 22 | pub fn init() Self { |
| 20 | 23 | return Self{ |
| 21 | 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 | 34 | } |
| 32 | 35 | |
| 33 | 36 | pub fn push(self: *Self, node: *Node) void { |
| 34 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} | |
| 35 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | |
| 36 | ||
| 37 | node.next = self.root; | |
| 38 | self.root = node; | |
| 37 | if (builtin.single_threaded) { | |
| 38 | node.next = self.root; | |
| 39 | self.root = node; | |
| 40 | } else { | |
| 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 | 49 | pub fn pop(self: *Self) ?*Node { |
| 42 | while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} | |
| 43 | defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); | |
| 44 | ||
| 45 | const root = self.root orelse return null; | |
| 46 | self.root = root.next; | |
| 47 | return root; | |
| 50 | if (builtin.single_threaded) { | |
| 51 | const root = self.root orelse return null; | |
| 52 | self.root = root.next; | |
| 53 | return root; | |
| 54 | } else { | |
| 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 | 64 | pub fn isEmpty(self: *Self) bool { |
| ... | ... | @@ -90,20 +104,36 @@ test "std.atomic.stack" { |
| 90 | 104 | .get_count = 0, |
| 91 | 105 | }; |
| 92 | 106 | |
| 93 | var putters: [put_thread_count]*std.os.Thread = undefined; | |
| 94 | for (putters) |*t| { | |
| 95 | t.* = try std.os.spawnThread(&context, startPuts); | |
| 96 | } | |
| 97 | var getters: [put_thread_count]*std.os.Thread = undefined; | |
| 98 | for (getters) |*t| { | |
| 99 | t.* = try std.os.spawnThread(&context, startGets); | |
| 100 | } | |
| 107 | if (builtin.single_threaded) { | |
| 108 | { | |
| 109 | var i: usize = 0; | |
| 110 | while (i < put_thread_count) : (i += 1) { | |
| 111 | std.debug.assertOrPanic(startPuts(&context) == 0); | |
| 112 | } | |
| 113 | } | |
| 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| | |
| 103 | t.wait(); | |
| 104 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | |
| 105 | for (getters) |t| | |
| 106 | t.wait(); | |
| 131 | for (putters) |t| | |
| 132 | t.wait(); | |
| 133 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | |
| 134 | for (getters) |t| | |
| 135 | t.wait(); | |
| 136 | } | |
| 107 | 137 | |
| 108 | 138 | if (context.put_sum != context.get_sum) { |
| 109 | 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 | 155 | while (put_count != 0) : (put_count -= 1) { |
| 126 | 156 | std.os.time.sleep(1); // let the os scheduler be our fuzz |
| 127 | 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 | 160 | .next = undefined, |
| 130 | 161 | .data = x, |
| 131 | }) catch unreachable; | |
| 162 | }; | |
| 132 | 163 | ctx.stack.push(node); |
| 133 | 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 | 89 | }; |
| 90 | 90 | |
| 91 | 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 | 93 | env_map.* = os.getEnvMap(allocator) catch unreachable; |
| 94 | 94 | var self = Builder{ |
| 95 | 95 | .zig_exe = zig_exe, |
| ... | ... | @@ -170,7 +170,8 @@ pub const Builder = struct { |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 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 | 175 | return test_step; |
| 175 | 176 | } |
| 176 | 177 | |
| ... | ... | @@ -202,18 +203,21 @@ pub const Builder = struct { |
| 202 | 203 | } |
| 203 | 204 | |
| 204 | 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 | 208 | return write_file_step; |
| 207 | 209 | } |
| 208 | 210 | |
| 209 | 211 | pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { |
| 210 | 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 | 215 | return log_step; |
| 213 | 216 | } |
| 214 | 217 | |
| 215 | 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 | 221 | return remove_dir_step; |
| 218 | 222 | } |
| 219 | 223 | |
| ... | ... | @@ -320,7 +324,7 @@ pub const Builder = struct { |
| 320 | 324 | |
| 321 | 325 | fn processNixOSEnvVars(self: *Builder) void { |
| 322 | 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 | 328 | while (true) { |
| 325 | 329 | const word = it.next() orelse break; |
| 326 | 330 | if (mem.eql(u8, word, "-isystem")) { |
| ... | ... | @@ -338,7 +342,7 @@ pub const Builder = struct { |
| 338 | 342 | assert(err == error.EnvironmentVariableNotFound); |
| 339 | 343 | } |
| 340 | 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 | 346 | while (true) { |
| 343 | 347 | const word = it.next() orelse break; |
| 344 | 348 | if (mem.eql(u8, word, "-rpath")) { |
| ... | ... | @@ -414,10 +418,11 @@ pub const Builder = struct { |
| 414 | 418 | } |
| 415 | 419 | |
| 416 | 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 | 423 | .step = Step.initNoOp(name, self.allocator), |
| 419 | 424 | .description = description, |
| 420 | }) catch unreachable; | |
| 425 | }; | |
| 421 | 426 | self.top_level_steps.append(step_info) catch unreachable; |
| 422 | 427 | return &step_info.step; |
| 423 | 428 | } |
| ... | ... | @@ -616,7 +621,8 @@ pub const Builder = struct { |
| 616 | 621 | const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable; |
| 617 | 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 | 626 | return install_step; |
| 621 | 627 | } |
| 622 | 628 | |
| ... | ... | @@ -683,7 +689,7 @@ pub const Builder = struct { |
| 683 | 689 | if (os.path.isAbsolute(name)) { |
| 684 | 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 | 693 | while (it.next()) |path| { |
| 688 | 694 | const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); |
| 689 | 695 | if (os.path.real(self.allocator, full_path)) |real_path| { |
| ... | ... | @@ -865,43 +871,51 @@ pub const LibExeObjStep = struct { |
| 865 | 871 | }; |
| 866 | 872 | |
| 867 | 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 | 876 | return self; |
| 870 | 877 | } |
| 871 | 878 | |
| 872 | 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 | 882 | return self; |
| 875 | 883 | } |
| 876 | 884 | |
| 877 | 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 | 888 | return self; |
| 880 | 889 | } |
| 881 | 890 | |
| 882 | 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 | 894 | return self; |
| 885 | 895 | } |
| 886 | 896 | |
| 887 | 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 | 900 | return self; |
| 890 | 901 | } |
| 891 | 902 | |
| 892 | 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 | 906 | self.object_src = src; |
| 895 | 907 | return self; |
| 896 | 908 | } |
| 897 | 909 | |
| 898 | 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 | 913 | return self; |
| 901 | 914 | } |
| 902 | 915 | |
| 903 | 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 | 919 | return self; |
| 906 | 920 | } |
| 907 | 921 | |
| ... | ... | @@ -1914,13 +1928,14 @@ pub const CommandStep = struct { |
| 1914 | 1928 | |
| 1915 | 1929 | /// ::argv is copied. |
| 1916 | 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 | 1933 | .builder = builder, |
| 1919 | 1934 | .step = Step.init(argv[0], builder.allocator, make), |
| 1920 | 1935 | .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable, |
| 1921 | 1936 | .cwd = cwd, |
| 1922 | 1937 | .env_map = env_map, |
| 1923 | }) catch unreachable; | |
| 1938 | }; | |
| 1924 | 1939 | |
| 1925 | 1940 | mem.copy([]const u8, self.argv, argv); |
| 1926 | 1941 | self.step.name = self.argv[0]; |
| ... | ... | @@ -1949,12 +1964,13 @@ const InstallArtifactStep = struct { |
| 1949 | 1964 | LibExeObjStep.Kind.Exe => builder.exe_dir, |
| 1950 | 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 | 1969 | .builder = builder, |
| 1954 | 1970 | .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), |
| 1955 | 1971 | .artifact = artifact, |
| 1956 | 1972 | .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, |
| 1957 | }) catch unreachable; | |
| 1973 | }; | |
| 1958 | 1974 | self.step.dependOn(&artifact.step); |
| 1959 | 1975 | builder.pushInstalledFile(self.dest_file); |
| 1960 | 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 | 73 | }; |
| 74 | 74 | |
| 75 | 75 | pub const timeval = extern struct { |
| 76 | tv_sec: isize, | |
| 77 | tv_usec: isize, | |
| 76 | tv_sec: c_long, | |
| 77 | tv_usec: i32, | |
| 78 | 78 | }; |
| 79 | 79 | |
| 80 | 80 | pub const timezone = extern struct { |
| ... | ... | @@ -176,6 +176,24 @@ pub const kevent64_s = extern struct { |
| 176 | 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 | 197 | // sys/types.h on macos uses #pragma pack() so these checks are |
| 180 | 198 | // to make sure the struct is laid out the same. These values were |
| 181 | 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 | 44 | pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 45 | 45 | pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; |
| 46 | 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 | 48 | pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; |
| 49 | 49 | pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; |
| 50 | 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 | 751 | const self_file = try os.openSelfExe(); |
| 752 | 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 | 755 | coff_obj.* = coff.Coff{ |
| 756 | 756 | .in_file = self_file, |
| 757 | 757 | .allocator = allocator, |
| ... | ... | @@ -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 | 1040 | sentinel.* = macho.nlist_64{ |
| 1041 | 1041 | .n_strx = 0, |
| 1042 | 1042 | .n_type = 36, |
| ... | ... | @@ -1949,7 +1949,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 1949 | 1949 | |
| 1950 | 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 | 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 | 54 | const buffer_nodes = try loop.allocator.alloc(T, capacity); |
| 55 | 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 | 59 | .loop = loop, |
| 59 | 60 | .buffer_len = 0, |
| 60 | 61 | .buffer_nodes = buffer_nodes, |
| ... | ... | @@ -66,7 +67,7 @@ pub fn Channel(comptime T: type) type { |
| 66 | 67 | .or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(), |
| 67 | 68 | .get_count = 0, |
| 68 | 69 | .put_count = 0, |
| 69 | }); | |
| 70 | }; | |
| 70 | 71 | errdefer loop.allocator.destroy(self); |
| 71 | 72 | |
| 72 | 73 | return self; |
| ... | ... | @@ -319,6 +320,9 @@ pub fn Channel(comptime T: type) type { |
| 319 | 320 | } |
| 320 | 321 | |
| 321 | 322 | test "std.event.Channel" { |
| 323 | // https://github.com/ziglang/zig/issues/1908 | |
| 324 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 325 | ||
| 322 | 326 | var da = std.heap.DirectAllocator.init(); |
| 323 | 327 | defer da.deinit(); |
| 324 | 328 |
std/event/fs.zig+27-30| ... | ... | @@ -495,7 +495,7 @@ pub const CloseOperation = struct { |
| 495 | 495 | }; |
| 496 | 496 | |
| 497 | 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 | 499 | self.* = CloseOperation{ |
| 500 | 500 | .loop = loop, |
| 501 | 501 | .os_data = switch (builtin.os) { |
| ... | ... | @@ -787,7 +787,7 @@ pub fn Watch(comptime V: type) type { |
| 787 | 787 | }, |
| 788 | 788 | |
| 789 | 789 | builtin.Os.windows => { |
| 790 | const self = try loop.allocator.createOne(Self); | |
| 790 | const self = try loop.allocator.create(Self); | |
| 791 | 791 | errdefer loop.allocator.destroy(self); |
| 792 | 792 | self.* = Self{ |
| 793 | 793 | .channel = channel, |
| ... | ... | @@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type { |
| 802 | 802 | }, |
| 803 | 803 | |
| 804 | 804 | builtin.Os.macosx, builtin.Os.freebsd => { |
| 805 | const self = try loop.allocator.createOne(Self); | |
| 805 | const self = try loop.allocator.create(Self); | |
| 806 | 806 | errdefer loop.allocator.destroy(self); |
| 807 | 807 | |
| 808 | 808 | self.* = Self{ |
| ... | ... | @@ -1068,7 +1068,7 @@ pub fn Watch(comptime V: type) type { |
| 1068 | 1068 | } |
| 1069 | 1069 | } else { |
| 1070 | 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 | 1072 | errdefer self.channel.loop.allocator.destroy(dir); |
| 1073 | 1073 | |
| 1074 | 1074 | dir.* = OsData.Dir{ |
| ... | ... | @@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type { |
| 1307 | 1307 | |
| 1308 | 1308 | const test_tmp_dir = "std_event_fs_test"; |
| 1309 | 1309 | |
| 1310 | test "write a file, watch it, write it again" { | |
| 1311 | if (builtin.os == builtin.Os.windows) { | |
| 1312 | // TODO this test is disabled on windows until the coroutine rewrite is finished. | |
| 1313 | // https://github.com/ziglang/zig/issues/1363 | |
| 1314 | return error.SkipZigTest; | |
| 1315 | } | |
| 1316 | var da = std.heap.DirectAllocator.init(); | |
| 1317 | defer da.deinit(); | |
| 1318 | ||
| 1319 | const allocator = &da.allocator; | |
| 1320 | ||
| 1321 | // TODO move this into event loop too | |
| 1322 | try os.makePath(allocator, test_tmp_dir); | |
| 1323 | defer os.deleteTree(allocator, test_tmp_dir) catch {}; | |
| 1324 | ||
| 1325 | var loop: Loop = undefined; | |
| 1326 | try loop.initMultiThreaded(allocator); | |
| 1327 | defer loop.deinit(); | |
| 1328 | ||
| 1329 | var result: anyerror!void = error.ResultNeverWritten; | |
| 1330 | const handle = try async<allocator> testFsWatchCantFail(&loop, &result); | |
| 1331 | defer cancel handle; | |
| 1332 | ||
| 1333 | loop.run(); | |
| 1334 | return result; | |
| 1335 | } | |
| 1310 | // TODO this test is disabled until the coroutine rewrite is finished. | |
| 1311 | //test "write a file, watch it, write it again" { | |
| 1312 | // return error.SkipZigTest; | |
| 1313 | // var da = std.heap.DirectAllocator.init(); | |
| 1314 | // defer da.deinit(); | |
| 1315 | // | |
| 1316 | // const allocator = &da.allocator; | |
| 1317 | // | |
| 1318 | // // TODO move this into event loop too | |
| 1319 | // try os.makePath(allocator, test_tmp_dir); | |
| 1320 | // defer os.deleteTree(allocator, test_tmp_dir) catch {}; | |
| 1321 | // | |
| 1322 | // var loop: Loop = undefined; | |
| 1323 | // try loop.initMultiThreaded(allocator); | |
| 1324 | // defer loop.deinit(); | |
| 1325 | // | |
| 1326 | // var result: anyerror!void = error.ResultNeverWritten; | |
| 1327 | // const handle = try async<allocator> testFsWatchCantFail(&loop, &result); | |
| 1328 | // defer cancel handle; | |
| 1329 | // | |
| 1330 | // loop.run(); | |
| 1331 | // return result; | |
| 1332 | //} | |
| 1336 | 1333 | |
| 1337 | 1334 | async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { |
| 1338 | 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 | 84 | } |
| 85 | 85 | |
| 86 | 86 | test "std.event.Future" { |
| 87 | // https://github.com/ziglang/zig/issues/1908 | |
| 88 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 89 | ||
| 87 | 90 | var da = std.heap.DirectAllocator.init(); |
| 88 | 91 | defer da.deinit(); |
| 89 | 92 |
std/event/group.zig+6-2| ... | ... | @@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type { |
| 42 | 42 | |
| 43 | 43 | /// Add a promise to the group. Thread-safe. |
| 44 | 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 | 47 | .next = undefined, |
| 47 | 48 | .data = handle, |
| 48 | }); | |
| 49 | }; | |
| 49 | 50 | self.alloc_stack.push(node); |
| 50 | 51 | } |
| 51 | 52 | |
| ... | ... | @@ -121,6 +122,9 @@ pub fn Group(comptime ReturnType: type) type { |
| 121 | 122 | } |
| 122 | 123 | |
| 123 | 124 | test "std.event.Group" { |
| 125 | // https://github.com/ziglang/zig/issues/1908 | |
| 126 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 127 | ||
| 124 | 128 | var da = std.heap.DirectAllocator.init(); |
| 125 | 129 | defer da.deinit(); |
| 126 | 130 |
std/event/lock.zig+3| ... | ... | @@ -122,6 +122,9 @@ pub const Lock = struct { |
| 122 | 122 | }; |
| 123 | 123 | |
| 124 | 124 | test "std.event.Lock" { |
| 125 | // https://github.com/ziglang/zig/issues/1908 | |
| 126 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 127 | ||
| 125 | 128 | var da = std.heap.DirectAllocator.init(); |
| 126 | 129 | defer da.deinit(); |
| 127 | 130 |
std/event/loop.zig+22| ... | ... | @@ -97,6 +97,7 @@ pub const Loop = struct { |
| 97 | 97 | /// TODO copy elision / named return values so that the threads referencing *Loop |
| 98 | 98 | /// have the correct pointer value. |
| 99 | 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 | 101 | const core_count = try os.cpuCount(allocator); |
| 101 | 102 | return self.initInternal(allocator, core_count); |
| 102 | 103 | } |
| ... | ... | @@ -201,6 +202,11 @@ pub const Loop = struct { |
| 201 | 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 | 210 | var extra_thread_index: usize = 0; |
| 205 | 211 | errdefer { |
| 206 | 212 | // writing 8 bytes to an eventfd cannot fail |
| ... | ... | @@ -301,6 +307,11 @@ pub const Loop = struct { |
| 301 | 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 | 315 | var extra_thread_index: usize = 0; |
| 305 | 316 | errdefer { |
| 306 | 317 | _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable; |
| ... | ... | @@ -338,6 +349,11 @@ pub const Loop = struct { |
| 338 | 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 | 357 | var extra_thread_index: usize = 0; |
| 342 | 358 | errdefer { |
| 343 | 359 | var i: usize = 0; |
| ... | ... | @@ -845,6 +861,9 @@ pub const Loop = struct { |
| 845 | 861 | }; |
| 846 | 862 | |
| 847 | 863 | test "std.event.Loop - basic" { |
| 864 | // https://github.com/ziglang/zig/issues/1908 | |
| 865 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 866 | ||
| 848 | 867 | var da = std.heap.DirectAllocator.init(); |
| 849 | 868 | defer da.deinit(); |
| 850 | 869 | |
| ... | ... | @@ -858,6 +877,9 @@ test "std.event.Loop - basic" { |
| 858 | 877 | } |
| 859 | 878 | |
| 860 | 879 | test "std.event.Loop - call" { |
| 880 | // https://github.com/ziglang/zig/issues/1908 | |
| 881 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 882 | ||
| 861 | 883 | var da = std.heap.DirectAllocator.init(); |
| 862 | 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 | 269 | } |
| 270 | 270 | |
| 271 | 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 | 275 | if (builtin.os != builtin.Os.linux) { |
| 273 | 276 | // TODO build abstractions for other operating systems |
| 274 | 277 | return error.SkipZigTest; |
std/event/rwlock.zig+3| ... | ... | @@ -211,6 +211,9 @@ pub const RwLock = struct { |
| 211 | 211 | }; |
| 212 | 212 | |
| 213 | 213 | test "std.event.RwLock" { |
| 214 | // https://github.com/ziglang/zig/issues/1908 | |
| 215 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 216 | ||
| 214 | 217 | var da = std.heap.DirectAllocator.init(); |
| 215 | 218 | defer da.deinit(); |
| 216 | 219 |
std/fmt/index.zig-2| ... | ... | @@ -982,13 +982,11 @@ test "fmt.format" { |
| 982 | 982 | context = BufPrintContext{ .remaining = buf1[0..] }; |
| 983 | 983 | try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); |
| 984 | 984 | res = buf1[0 .. buf1.len - context.remaining.len]; |
| 985 | debug.warn("{}\n", res); | |
| 986 | 985 | assert(mem.eql(u8, res, "a")); |
| 987 | 986 | |
| 988 | 987 | context = BufPrintContext{ .remaining = buf1[0..] }; |
| 989 | 988 | try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); |
| 990 | 989 | res = buf1[0 .. buf1.len - context.remaining.len]; |
| 991 | debug.warn("{}\n", res); | |
| 992 | 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 | 508 | |
| 509 | 509 | builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), |
| 510 | 510 | builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), |
| 511 | builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"), | |
| 511 | 512 | builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), |
| 512 | 513 | builtin.TypeId.Union => @compileError("TODO auto hash for unions"), |
| 513 | 514 | builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), |
| ... | ... | @@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { |
| 555 | 556 | builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), |
| 556 | 557 | builtin.TypeId.Union => @compileError("TODO auto eql for unions"), |
| 557 | 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 | 518 | var slice = try allocator.alloc(*i32, 100); |
| 519 | 519 | assert(slice.len == 100); |
| 520 | 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 | 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 | 9 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 10 | 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; |
| 11 | 11 | pub const Mutex = @import("mutex.zig").Mutex; |
| 12 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; | |
| 12 | 13 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 13 | 14 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 14 | 15 | |
| ... | ... | @@ -55,6 +56,7 @@ test "std" { |
| 55 | 56 | _ = @import("hash_map.zig"); |
| 56 | 57 | _ = @import("linked_list.zig"); |
| 57 | 58 | _ = @import("mutex.zig"); |
| 59 | _ = @import("statically_initialized_mutex.zig"); | |
| 58 | 60 | _ = @import("segmented_list.zig"); |
| 59 | 61 | _ = @import("spinlock.zig"); |
| 60 | 62 |
std/io.zig+654-13| ... | ... | @@ -8,6 +8,8 @@ const debug = std.debug; |
| 8 | 8 | const assert = debug.assert; |
| 9 | 9 | const os = std.os; |
| 10 | 10 | const mem = std.mem; |
| 11 | const meta = std.meta; | |
| 12 | const trait = meta.trait; | |
| 11 | 13 | const Buffer = std.Buffer; |
| 12 | 14 | const fmt = std.fmt; |
| 13 | 15 | const File = std.os.File; |
| ... | ... | @@ -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 | 615 | /// This is a simple OutStream that writes to a slice, and returns an error |
| 467 | 616 | /// when it runs out of space. |
| 468 | 617 | pub const SliceOutStream = struct { |
| ... | ... | @@ -515,7 +664,7 @@ test "io.SliceOutStream" { |
| 515 | 664 | const stream = &slice_stream.stream; |
| 516 | 665 | |
| 517 | 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 | 670 | var null_out_stream_state = NullOutStream.init(); |
| ... | ... | @@ -577,7 +726,7 @@ test "io.CountingOutStream" { |
| 577 | 726 | |
| 578 | 727 | const bytes = "yay" ** 10000; |
| 579 | 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 | 732 | pub fn BufferedOutStream(comptime Error: type) type { |
| ... | ... | @@ -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 | 939 | pub const BufferedAtomicFile = struct { |
| 660 | 940 | atomic_file: os.AtomicFile, |
| 661 | 941 | file_stream: os.File.OutStream, |
| ... | ... | @@ -664,12 +944,13 @@ pub const BufferedAtomicFile = struct { |
| 664 | 944 | |
| 665 | 945 | pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile { |
| 666 | 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 | 949 | .atomic_file = undefined, |
| 669 | 950 | .file_stream = undefined, |
| 670 | 951 | .buffered_stream = undefined, |
| 671 | 952 | .allocator = allocator, |
| 672 | }); | |
| 953 | }; | |
| 673 | 954 | errdefer allocator.destroy(self); |
| 674 | 955 | |
| 675 | 956 | self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode); |
| ... | ... | @@ -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 | 981 | pub fn readLine(buf: *std.Buffer) ![]u8 { |
| 706 | 982 | var stdin = try getStdIn(); |
| ... | ... | @@ -738,10 +1014,10 @@ test "io.readLineFrom" { |
| 738 | 1014 | ); |
| 739 | 1015 | const stream = &mem_stream.stream; |
| 740 | 1016 | |
| 741 | debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); | |
| 742 | debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); | |
| 1017 | debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); | |
| 1018 | debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); | |
| 743 | 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 | 1023 | pub fn readLineSlice(slice: []u8) ![]u8 { |
| ... | ... | @@ -769,6 +1045,371 @@ test "io.readLineSliceFrom" { |
| 769 | 1045 | ); |
| 770 | 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 | 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 | 1 | const std = @import("index.zig"); |
| 2 | 2 | const io = std.io; |
| 3 | const meta = std.meta; | |
| 4 | const trait = std.trait; | |
| 3 | 5 | const DefaultPrng = std.rand.DefaultPrng; |
| 4 | 6 | const assert = std.debug.assert; |
| 5 | 7 | const assertError = std.debug.assertError; |
| ... | ... | @@ -132,3 +134,438 @@ test "SliceOutStream" { |
| 132 | 134 | assertError(ss.stream.write("Hello world!"), error.OutOfSpace); |
| 133 | 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 | 190 | /// Returns: |
| 191 | 191 | /// A pointer to the new node. |
| 192 | 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 | 196 | /// Deallocate a node. |
std/mem.zig+132-25| ... | ... | @@ -36,20 +36,9 @@ pub const Allocator = struct { |
| 36 | 36 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` |
| 37 | 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 | 39 | /// Call `destroy` with the result. |
| 51 | 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 | 42 | if (@sizeOf(T) == 0) return &(T{}); |
| 54 | 43 | const slice = try self.alloc(T, 1); |
| 55 | 44 | return &slice[0]; |
| ... | ... | @@ -700,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { |
| 700 | 689 | } |
| 701 | 690 | |
| 702 | 691 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
| 703 | /// any of the bytes in `split_bytes`. | |
| 704 | /// split(" abc def ghi ", " ") | |
| 692 | /// any of the bytes in `delimiter_bytes`. | |
| 693 | /// tokenize(" abc def ghi ", " ") | |
| 705 | 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 | 763 | return SplitIterator{ |
| 708 | 764 | .index = 0, |
| 709 | 765 | .buffer = buffer, |
| 710 | .split_bytes = split_bytes, | |
| 766 | .delimiter = delimiter, | |
| 711 | 767 | }; |
| 712 | 768 | } |
| 713 | 769 | |
| 714 | test "mem.split" { | |
| 715 | var it = split(" abc def ghi ", " "); | |
| 770 | test "mem.separate" { | |
| 771 | var it = separate("abc|def||ghi", "|"); | |
| 716 | 772 | assert(eql(u8, it.next().?, "abc")); |
| 717 | 773 | assert(eql(u8, it.next().?, "def")); |
| 774 | assert(eql(u8, it.next().?, "")); | |
| 718 | 775 | assert(eql(u8, it.next().?, "ghi")); |
| 719 | 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 | 802 | pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { |
| ... | ... | @@ -737,12 +817,13 @@ test "mem.endsWith" { |
| 737 | 817 | assert(!endsWith(u8, "Bob", "Bo")); |
| 738 | 818 | } |
| 739 | 819 | |
| 740 | pub const SplitIterator = struct { | |
| 820 | pub const TokenIterator = struct { | |
| 741 | 821 | buffer: []const u8, |
| 742 | split_bytes: []const u8, | |
| 822 | delimiter_bytes: []const u8, | |
| 743 | 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 | 827 | // move to beginning of token |
| 747 | 828 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 748 | 829 | const start = self.index; |
| ... | ... | @@ -758,16 +839,16 @@ pub const SplitIterator = struct { |
| 758 | 839 | } |
| 759 | 840 | |
| 760 | 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 | 843 | // move to beginning of token |
| 763 | 844 | var index: usize = self.index; |
| 764 | 845 | while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} |
| 765 | 846 | return self.buffer[index..]; |
| 766 | 847 | } |
| 767 | 848 | |
| 768 | fn isSplitByte(self: *const SplitIterator, byte: u8) bool { | |
| 769 | for (self.split_bytes) |split_byte| { | |
| 770 | if (byte == split_byte) { | |
| 849 | fn isSplitByte(self: TokenIterator, byte: u8) bool { | |
| 850 | for (self.delimiter_bytes) |delimiter_byte| { | |
| 851 | if (byte == delimiter_byte) { | |
| 771 | 852 | return true; |
| 772 | 853 | } |
| 773 | 854 | } |
| ... | ... | @@ -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 | 885 | /// Naively combines a series of strings with a separator. |
| 779 | 886 | /// Allocates memory for the result, which must be freed by the caller. |
| 780 | 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 | 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 | 99 | return switch (@typeInfo(T)) { |
| 100 | 100 | TypeId.Int => |info| info.bits, |
| 101 | 101 | TypeId.Float => |info| info.bits, |
| ... | ... | @@ -108,7 +108,7 @@ test "std.meta.bitCount" { |
| 108 | 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 | 112 | //@alignOf works on non-pointer types |
| 113 | 113 | const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T; |
| 114 | 114 | return @typeInfo(P).Pointer.alignment; |
| ... | ... | @@ -386,6 +386,33 @@ test "std.meta.activeTag" { |
| 386 | 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 | 416 | ///Compares two of any type for equality. Containers are compared on a field-by-field basis, |
| 390 | 417 | /// where possible. Pointers are not followed. |
| 391 | 418 | pub fn eql(a: var, b: @typeOf(a)) bool { |
| ... | ... | @@ -439,6 +466,11 @@ pub fn eql(a: var, b: @typeOf(a)) bool { |
| 439 | 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 | 474 | else => return a == b, |
| 443 | 475 | } |
| 444 | 476 | } |
| ... | ... | @@ -452,7 +484,7 @@ test "std.meta.eql" { |
| 452 | 484 | |
| 453 | 485 | const U = union(enum) { |
| 454 | 486 | s: S, |
| 455 | f: f32, | |
| 487 | f: ?f32, | |
| 456 | 488 | }; |
| 457 | 489 | |
| 458 | 490 | const s_1 = S{ |
std/meta/trait.zig+31| ... | ... | @@ -231,6 +231,37 @@ test "std.meta.trait.isPacked" { |
| 231 | 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 | 266 | pub fn isSingleItemPtr(comptime T: type) bool { |
| 236 | 267 | if (comptime is(builtin.TypeId.Pointer)(T)) { |
std/mutex.zig+104-47| ... | ... | @@ -5,74 +5,124 @@ const AtomicRmwOp = builtin.AtomicRmwOp; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const SpinLock = std.SpinLock; |
| 7 | 7 | const linux = std.os.linux; |
| 8 | const windows = std.os.windows; | |
| 8 | 9 | |
| 9 | 10 | /// Lock may be held only once. If the same thread |
| 10 | 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 | 15 | /// The Linux implementation is based on mutex3 from |
| 12 | 16 | /// https://www.akkadia.org/drepper/futex.pdf |
| 13 | pub const Mutex = struct { | |
| 14 | /// 0: unlocked | |
| 15 | /// 1: locked, no waiters | |
| 16 | /// 2: locked, one or more waiters | |
| 17 | linux_lock: @typeOf(linux_lock_init), | |
| 17 | /// When an application is built in single threaded release mode, all the functions are | |
| 18 | /// no-ops. In single threaded debug mode, there is deadlock detection. | |
| 19 | pub const Mutex = if (builtin.single_threaded) | |
| 20 | struct { | |
| 21 | lock: @typeOf(lock_init), | |
| 18 | 22 | |
| 19 | /// TODO better implementation than spin lock | |
| 20 | spin_lock: @typeOf(spin_lock_init), | |
| 23 | const lock_init = if (std.debug.runtime_safety) false else {}; | |
| 21 | 24 | |
| 22 | const linux_lock_init = if (builtin.os == builtin.Os.linux) i32(0) else {}; | |
| 23 | const spin_lock_init = if (builtin.os != builtin.Os.linux) SpinLock.init() else {}; | |
| 25 | pub const Held = struct { | |
| 26 | mutex: *Mutex, | |
| 24 | 27 | |
| 25 | pub const Held = struct { | |
| 26 | mutex: *Mutex, | |
| 28 | pub fn release(self: Held) void { | |
| 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 { | |
| 29 | if (builtin.os == builtin.Os.linux) { | |
| 30 | const c = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); | |
| 39 | pub fn acquire(self: *Mutex) Held { | |
| 40 | if (std.debug.runtime_safety and self.lock) { | |
| 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 | 58 | if (c != 1) { |
| 32 | _ = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); | |
| 33 | const rc = linux.futex_wake(&self.mutex.linux_lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); | |
| 59 | _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); | |
| 60 | const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); | |
| 34 | 61 | switch (linux.getErrno(rc)) { |
| 35 | 62 | 0 => {}, |
| 36 | 63 | linux.EINVAL => unreachable, |
| 37 | 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 { | |
| 47 | return Mutex{ | |
| 48 | .linux_lock = linux_lock_init, | |
| 49 | .spin_lock = spin_lock_init, | |
| 50 | }; | |
| 51 | } | |
| 74 | pub fn deinit(self: *Mutex) void {} | |
| 52 | 75 | |
| 53 | pub fn acquire(self: *Mutex) Held { | |
| 54 | if (builtin.os == builtin.Os.linux) { | |
| 55 | var c = @cmpxchgWeak(i32, &self.linux_lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse | |
| 76 | pub fn acquire(self: *Mutex) Held { | |
| 77 | var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse | |
| 56 | 78 | return Held{ .mutex = self }; |
| 57 | 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 | 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 | 83 | switch (linux.getErrno(rc)) { |
| 62 | 84 | 0, linux.EINTR, linux.EAGAIN => {}, |
| 63 | 85 | linux.EINVAL => unreachable, |
| 64 | 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 { | |
| 69 | _ = self.spin_lock.acquire(); | |
| 90 | return Held{ .mutex = self }; | |
| 70 | 91 | } |
| 71 | return Held{ .mutex = self }; | |
| 72 | } | |
| 92 | }, | |
| 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 | 126 | mutex: *Mutex, |
| 77 | 127 | data: i128, |
| 78 | 128 | |
| ... | ... | @@ -90,25 +140,32 @@ test "std.Mutex" { |
| 90 | 140 | var a = &fixed_buffer_allocator.allocator; |
| 91 | 141 | |
| 92 | 142 | var mutex = Mutex.init(); |
| 93 | var context = Context{ | |
| 143 | defer mutex.deinit(); | |
| 144 | ||
| 145 | var context = TestContext{ | |
| 94 | 146 | .mutex = &mutex, |
| 95 | 147 | .data = 0, |
| 96 | 148 | }; |
| 97 | 149 | |
| 98 | const thread_count = 10; | |
| 99 | var threads: [thread_count]*std.os.Thread = undefined; | |
| 100 | for (threads) |*t| { | |
| 101 | t.* = try std.os.spawnThread(&context, worker); | |
| 102 | } | |
| 103 | for (threads) |t| | |
| 104 | t.wait(); | |
| 150 | if (builtin.single_threaded) { | |
| 151 | worker(&context); | |
| 152 | std.debug.assertOrPanic(context.data == TestContext.incr_count); | |
| 153 | } else { | |
| 154 | const thread_count = 10; | |
| 155 | var threads: [thread_count]*std.os.Thread = undefined; | |
| 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 | 167 | var i: usize = 0; |
| 111 | while (i != Context.incr_count) : (i += 1) { | |
| 168 | while (i != TestContext.incr_count) : (i += 1) { | |
| 112 | 169 | const held = ctx.mutex.acquire(); |
| 113 | 170 | defer held.release(); |
| 114 | 171 |
std/os/child_process.zig+4-3| ... | ... | @@ -88,7 +88,8 @@ pub const ChildProcess = struct { |
| 88 | 88 | /// First argument in argv is the executable. |
| 89 | 89 | /// On success must call deinit. |
| 90 | 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 | 93 | .allocator = allocator, |
| 93 | 94 | .argv = argv, |
| 94 | 95 | .pid = undefined, |
| ... | ... | @@ -109,7 +110,7 @@ pub const ChildProcess = struct { |
| 109 | 110 | .stdin_behavior = StdIo.Inherit, |
| 110 | 111 | .stdout_behavior = StdIo.Inherit, |
| 111 | 112 | .stderr_behavior = StdIo.Inherit, |
| 112 | }); | |
| 113 | }; | |
| 113 | 114 | errdefer allocator.destroy(child); |
| 114 | 115 | return child; |
| 115 | 116 | } |
| ... | ... | @@ -594,7 +595,7 @@ pub const ChildProcess = struct { |
| 594 | 595 | const PATH = try os.getEnvVarOwned(self.allocator, "PATH"); |
| 595 | 596 | defer self.allocator.free(PATH); |
| 596 | 597 | |
| 597 | var it = mem.split(PATH, ";"); | |
| 598 | var it = mem.tokenize(PATH, ";"); | |
| 598 | 599 | while (it.next()) |search_path| { |
| 599 | 600 | const joined_path = try os.path.join(self.allocator, search_path, app_name); |
| 600 | 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 | 608 | // +1 for the null terminating byte |
| 609 | 609 | const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2); |
| 610 | 610 | defer allocator.free(path_buf); |
| 611 | var it = mem.split(PATH, ":"); | |
| 611 | var it = mem.tokenize(PATH, ":"); | |
| 612 | 612 | var seen_eacces = false; |
| 613 | 613 | var err: usize = undefined; |
| 614 | 614 | while (it.next()) |search_path| { |
| ... | ... | @@ -3013,6 +3013,7 @@ pub const SpawnThreadError = error{ |
| 3013 | 3013 | /// where T is u8, noreturn, void, or !void |
| 3014 | 3014 | /// caller must call wait on the returned thread |
| 3015 | 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 | 3017 | // TODO compile-time call graph analysis to determine stack upper bound |
| 3017 | 3018 | // https://github.com/ziglang/zig/issues/157 |
| 3018 | 3019 | const default_stack_size = 8 * 1024 * 1024; |
| ... | ... | @@ -3046,7 +3047,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 3046 | 3047 | const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory; |
| 3047 | 3048 | errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0); |
| 3048 | 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 | 3052 | .thread = Thread{ |
| 3051 | 3053 | .data = Thread.Data{ |
| 3052 | 3054 | .heap_handle = heap_handle, |
| ... | ... | @@ -3055,7 +3057,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 3055 | 3057 | }, |
| 3056 | 3058 | }, |
| 3057 | 3059 | .inner = context, |
| 3058 | }) catch unreachable; | |
| 3060 | }; | |
| 3059 | 3061 | |
| 3060 | 3062 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); |
| 3061 | 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 | 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 | 188 | _ = (it.next() orelse return relative_path); |
| 189 | 189 | _ = (it.next() orelse return relative_path); |
| 190 | 190 | return WindowsPath{ |
| ... | ... | @@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { |
| 202 | 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 | 206 | _ = (it.next() orelse return relative_path); |
| 207 | 207 | _ = (it.next() orelse return relative_path); |
| 208 | 208 | return WindowsPath{ |
| ... | ... | @@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { |
| 264 | 264 | const sep1 = ns1[0]; |
| 265 | 265 | const sep2 = ns2[0]; |
| 266 | 266 | |
| 267 | var it1 = mem.split(ns1, []u8{sep1}); | |
| 268 | var it2 = mem.split(ns2, []u8{sep2}); | |
| 267 | var it1 = mem.tokenize(ns1, []u8{sep1}); | |
| 268 | var it2 = mem.tokenize(ns2, []u8{sep2}); | |
| 269 | 269 | |
| 270 | 270 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. |
| 271 | 271 | return asciiEqlIgnoreCase(it1.next().?, it2.next().?); |
| ... | ... | @@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 |
| 285 | 285 | const sep1 = p1[0]; |
| 286 | 286 | const sep2 = p2[0]; |
| 287 | 287 | |
| 288 | var it1 = mem.split(p1, []u8{sep1}); | |
| 289 | var it2 = mem.split(p2, []u8{sep2}); | |
| 288 | var it1 = mem.tokenize(p1, []u8{sep1}); | |
| 289 | var it2 = mem.tokenize(p2, []u8{sep2}); | |
| 290 | 290 | |
| 291 | 291 | // TODO ASCII is wrong, we actually need full unicode support to compare paths. |
| 292 | 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 | 337 | /// If all paths are relative it uses the current working directory as a starting point. |
| 338 | 338 | /// Each drive has its own current working directory. |
| 339 | 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 | 342 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 341 | 343 | if (paths.len == 0) { |
| 342 | 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 | 418 | }, |
| 417 | 419 | WindowsPath.Kind.NetworkShare => { |
| 418 | 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 | 422 | const server_name = it.next().?; |
| 421 | 423 | const other_name = it.next().?; |
| 422 | 424 | |
| ... | ... | @@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 483 | 485 | if (!correct_disk_designator) { |
| 484 | 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 | 489 | while (it.next()) |component| { |
| 488 | 490 | if (mem.eql(u8, component, ".")) { |
| 489 | 491 | continue; |
| ... | ... | @@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 516 | 518 | /// It resolves "." and "..". |
| 517 | 519 | /// The result does not have a trailing path separator. |
| 518 | 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 | 523 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 520 | 524 | if (paths.len == 0) { |
| 521 | 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 | 554 | errdefer allocator.free(result); |
| 551 | 555 | |
| 552 | 556 | for (paths[first_index..]) |p, i| { |
| 553 | var it = mem.split(p, "/"); | |
| 557 | var it = mem.tokenize(p, "/"); | |
| 554 | 558 | while (it.next()) |component| { |
| 555 | 559 | if (mem.eql(u8, component, ".")) { |
| 556 | 560 | continue; |
| ... | ... | @@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) |
| 937 | 941 | return resolved_to; |
| 938 | 942 | } |
| 939 | 943 | |
| 940 | var from_it = mem.split(resolved_from, "/\\"); | |
| 941 | var to_it = mem.split(resolved_to, "/\\"); | |
| 944 | var from_it = mem.tokenize(resolved_from, "/\\"); | |
| 945 | var to_it = mem.tokenize(resolved_to, "/\\"); | |
| 942 | 946 | while (true) { |
| 943 | 947 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); |
| 944 | 948 | const to_rest = to_it.rest(); |
| ... | ... | @@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) |
| 967 | 971 | // shave off the trailing slash |
| 968 | 972 | result_index -= 1; |
| 969 | 973 | |
| 970 | var rest_it = mem.split(to_rest, "/\\"); | |
| 974 | var rest_it = mem.tokenize(to_rest, "/\\"); | |
| 971 | 975 | while (rest_it.next()) |to_component| { |
| 972 | 976 | result[result_index] = '\\'; |
| 973 | 977 | result_index += 1; |
| ... | ... | @@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ |
| 988 | 992 | const resolved_to = try resolvePosix(allocator, [][]const u8{to}); |
| 989 | 993 | defer allocator.free(resolved_to); |
| 990 | 994 | |
| 991 | var from_it = mem.split(resolved_from, "/"); | |
| 992 | var to_it = mem.split(resolved_to, "/"); | |
| 995 | var from_it = mem.tokenize(resolved_from, "/"); | |
| 996 | var to_it = mem.tokenize(resolved_to, "/"); | |
| 993 | 997 | while (true) { |
| 994 | 998 | const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); |
| 995 | 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 | 40 | } |
| 41 | 41 | |
| 42 | 42 | test "std.os.Thread.getCurrentId" { |
| 43 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 44 | ||
| 43 | 45 | var thread_current_id: os.Thread.Id = undefined; |
| 44 | 46 | const thread = try os.spawnThread(&thread_current_id, testThreadIdFn); |
| 45 | 47 | const thread_id = thread.handle(); |
| ... | ... | @@ -53,6 +55,8 @@ test "std.os.Thread.getCurrentId" { |
| 53 | 55 | } |
| 54 | 56 | |
| 55 | 57 | test "spawn threads" { |
| 58 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 59 | ||
| 56 | 60 | var shared_ctx: i32 = 1; |
| 57 | 61 | |
| 58 | 62 | const thread1 = try std.os.spawnThread({}, start1); |
std/os/time.zig+3-5| ... | ... | @@ -79,14 +79,12 @@ fn milliTimestampWindows() u64 { |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | fn milliTimestampDarwin() u64 { |
| 82 | //Sources suggest MacOS 10.12 has support for | |
| 83 | // posix clock_gettime. | |
| 84 | 82 | var tv: darwin.timeval = undefined; |
| 85 | 83 | var err = darwin.gettimeofday(&tv, null); |
| 86 | 84 | debug.assert(err == 0); |
| 87 | const sec_ms = @intCast(u64, tv.tv_sec) * ms_per_s; | |
| 88 | const usec_ms = @divFloor(@intCast(u64, tv.tv_usec), us_per_s / ms_per_s); | |
| 89 | return u64(sec_ms) + u64(usec_ms); | |
| 85 | const sec_ms = tv.tv_sec * ms_per_s; | |
| 86 | const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s); | |
| 87 | return @intCast(u64, sec_ms + usec_ms); | |
| 90 | 88 | } |
| 91 | 89 | |
| 92 | 90 | fn milliTimestampPosix() u64 { |
std/os/windows/index.zig+1| ... | ... | @@ -49,6 +49,7 @@ pub const UNICODE = false; |
| 49 | 49 | pub const WCHAR = u16; |
| 50 | 50 | pub const WORD = u16; |
| 51 | 51 | pub const LARGE_INTEGER = i64; |
| 52 | pub const LONG = c_long; | |
| 52 | 53 | |
| 53 | 54 | pub const TRUE = 1; |
| 54 | 55 | pub const FALSE = 0; |
std/os/windows/kernel32.zig+47| ... | ... | @@ -220,3 +220,50 @@ pub const FOREGROUND_BLUE = 1; |
| 220 | 220 | pub const FOREGROUND_GREEN = 2; |
| 221 | 221 | pub const FOREGROUND_RED = 4; |
| 222 | 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 | 17 | defer stack.deinit(); |
| 18 | 18 | |
| 19 | 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 | 22 | .base = ast.Node{ .id = ast.Node.Id.Root }, |
| 22 | 23 | .decls = ast.Node.Root.DeclList.init(arena), |
| 23 | 24 | .doc_comments = null, |
| 24 | 25 | .shebang = null, |
| 25 | 26 | // initialized when we get the eof token |
| 26 | 27 | .eof_token = undefined, |
| 27 | }); | |
| 28 | }; | |
| 28 | 29 | |
| 29 | 30 | var tree = ast.Tree{ |
| 30 | 31 | .source = source, |
| ... | ... | @@ -75,20 +76,22 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 75 | 76 | Token.Id.Keyword_test => { |
| 76 | 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 | 81 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 80 | 82 | .label = null, |
| 81 | 83 | .lbrace = undefined, |
| 82 | 84 | .statements = ast.Node.Block.StatementList.init(arena), |
| 83 | 85 | .rbrace = undefined, |
| 84 | }); | |
| 85 | const test_node = try arena.create(ast.Node.TestDecl{ | |
| 86 | }; | |
| 87 | const test_node = try arena.create(ast.Node.TestDecl); | |
| 88 | test_node.* = ast.Node.TestDecl{ | |
| 86 | 89 | .base = ast.Node{ .id = ast.Node.Id.TestDecl }, |
| 87 | 90 | .doc_comments = comments, |
| 88 | 91 | .test_token = token_index, |
| 89 | 92 | .name = undefined, |
| 90 | 93 | .body_node = &block.base, |
| 91 | }); | |
| 94 | }; | |
| 92 | 95 | try root_node.decls.push(&test_node.base); |
| 93 | 96 | try stack.append(State{ .Block = block }); |
| 94 | 97 | try stack.append(State{ |
| ... | ... | @@ -119,19 +122,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 119 | 122 | continue; |
| 120 | 123 | }, |
| 121 | 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 | 127 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 124 | 128 | .label = null, |
| 125 | 129 | .lbrace = undefined, |
| 126 | 130 | .statements = ast.Node.Block.StatementList.init(arena), |
| 127 | 131 | .rbrace = undefined, |
| 128 | }); | |
| 129 | const node = try arena.create(ast.Node.Comptime{ | |
| 132 | }; | |
| 133 | const node = try arena.create(ast.Node.Comptime); | |
| 134 | node.* = ast.Node.Comptime{ | |
| 130 | 135 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, |
| 131 | 136 | .comptime_token = token_index, |
| 132 | 137 | .expr = &block.base, |
| 133 | 138 | .doc_comments = comments, |
| 134 | }); | |
| 139 | }; | |
| 135 | 140 | try root_node.decls.push(&node.base); |
| 136 | 141 | |
| 137 | 142 | stack.append(State.TopLevel) catch unreachable; |
| ... | ... | @@ -235,14 +240,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 235 | 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 | 245 | .base = ast.Node{ .id = ast.Node.Id.Use }, |
| 240 | 246 | .use_token = token_index, |
| 241 | 247 | .visib_token = ctx.visib_token, |
| 242 | 248 | .expr = undefined, |
| 243 | 249 | .semicolon_token = undefined, |
| 244 | 250 | .doc_comments = ctx.comments, |
| 245 | }); | |
| 251 | }; | |
| 246 | 252 | try ctx.decls.push(&node.base); |
| 247 | 253 | |
| 248 | 254 | stack.append(State{ |
| ... | ... | @@ -276,7 +282,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 276 | 282 | continue; |
| 277 | 283 | }, |
| 278 | 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 | 287 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 281 | 288 | .doc_comments = ctx.comments, |
| 282 | 289 | .visib_token = ctx.visib_token, |
| ... | ... | @@ -292,7 +299,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 292 | 299 | .lib_name = ctx.lib_name, |
| 293 | 300 | .align_expr = null, |
| 294 | 301 | .section_expr = null, |
| 295 | }); | |
| 302 | }; | |
| 296 | 303 | try ctx.decls.push(&fn_proto.base); |
| 297 | 304 | stack.append(State{ .FnDef = fn_proto }) catch unreachable; |
| 298 | 305 | try stack.append(State{ .FnProto = fn_proto }); |
| ... | ... | @@ -309,12 +316,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 309 | 316 | continue; |
| 310 | 317 | }, |
| 311 | 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 | 321 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, |
| 314 | 322 | .async_token = token_index, |
| 315 | 323 | .allocator_type = null, |
| 316 | 324 | .rangle_bracket = null, |
| 317 | }); | |
| 325 | }; | |
| 318 | 326 | fn_proto.async_attr = async_node; |
| 319 | 327 | |
| 320 | 328 | try stack.append(State{ |
| ... | ... | @@ -341,13 +349,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 341 | 349 | }, |
| 342 | 350 | State.TopLevelExternOrField => |ctx| { |
| 343 | 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 | 354 | .base = ast.Node{ .id = ast.Node.Id.StructField }, |
| 346 | 355 | .doc_comments = ctx.comments, |
| 347 | 356 | .visib_token = ctx.visib_token, |
| 348 | 357 | .name_token = identifier, |
| 349 | 358 | .type_expr = undefined, |
| 350 | }); | |
| 359 | }; | |
| 351 | 360 | const node_ptr = try ctx.container_decl.fields_and_decls.addOne(); |
| 352 | 361 | node_ptr.* = &node.base; |
| 353 | 362 | |
| ... | ... | @@ -391,7 +400,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 391 | 400 | const token = nextToken(&tok_it, &tree); |
| 392 | 401 | const token_index = token.index; |
| 393 | 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 | 405 | .base = ast.Node{ .id = ast.Node.Id.ContainerDecl }, |
| 396 | 406 | .layout_token = ctx.layout_token, |
| 397 | 407 | .kind_token = switch (token_ptr.id) { |
| ... | ... | @@ -405,7 +415,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 405 | 415 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), |
| 406 | 416 | .lbrace_token = undefined, |
| 407 | 417 | .rbrace_token = undefined, |
| 408 | }); | |
| 418 | }; | |
| 409 | 419 | ctx.opt_ctx.store(&node.base); |
| 410 | 420 | |
| 411 | 421 | stack.append(State{ .ContainerDecl = node }) catch unreachable; |
| ... | ... | @@ -464,13 +474,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 464 | 474 | Token.Id.Identifier => { |
| 465 | 475 | switch (tree.tokens.at(container_decl.kind_token).id) { |
| 466 | 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 | 479 | .base = ast.Node{ .id = ast.Node.Id.StructField }, |
| 469 | 480 | .doc_comments = comments, |
| 470 | 481 | .visib_token = null, |
| 471 | 482 | .name_token = token_index, |
| 472 | 483 | .type_expr = undefined, |
| 473 | }); | |
| 484 | }; | |
| 474 | 485 | const node_ptr = try container_decl.fields_and_decls.addOne(); |
| 475 | 486 | node_ptr.* = &node.base; |
| 476 | 487 | |
| ... | ... | @@ -485,13 +496,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 485 | 496 | continue; |
| 486 | 497 | }, |
| 487 | 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 | 501 | .base = ast.Node{ .id = ast.Node.Id.UnionTag }, |
| 490 | 502 | .name_token = token_index, |
| 491 | 503 | .type_expr = null, |
| 492 | 504 | .value_expr = null, |
| 493 | 505 | .doc_comments = comments, |
| 494 | }); | |
| 506 | }; | |
| 495 | 507 | try container_decl.fields_and_decls.push(&node.base); |
| 496 | 508 | |
| 497 | 509 | try stack.append(State{ |
| ... | ... | @@ -506,12 +518,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 506 | 518 | continue; |
| 507 | 519 | }, |
| 508 | 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 | 523 | .base = ast.Node{ .id = ast.Node.Id.EnumTag }, |
| 511 | 524 | .name_token = token_index, |
| 512 | 525 | .value = null, |
| 513 | 526 | .doc_comments = comments, |
| 514 | }); | |
| 527 | }; | |
| 515 | 528 | try container_decl.fields_and_decls.push(&node.base); |
| 516 | 529 | |
| 517 | 530 | try stack.append(State{ |
| ... | ... | @@ -593,7 +606,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 593 | 606 | }, |
| 594 | 607 | |
| 595 | 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 | 611 | .base = ast.Node{ .id = ast.Node.Id.VarDecl }, |
| 598 | 612 | .doc_comments = ctx.comments, |
| 599 | 613 | .visib_token = ctx.visib_token, |
| ... | ... | @@ -609,7 +623,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 609 | 623 | .name_token = undefined, |
| 610 | 624 | .eq_token = undefined, |
| 611 | 625 | .semicolon_token = undefined, |
| 612 | }); | |
| 626 | }; | |
| 613 | 627 | try ctx.list.push(&var_decl.base); |
| 614 | 628 | |
| 615 | 629 | try stack.append(State{ .VarDeclAlign = var_decl }); |
| ... | ... | @@ -708,13 +722,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 708 | 722 | const token_ptr = token.ptr; |
| 709 | 723 | switch (token_ptr.id) { |
| 710 | 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 | 727 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 713 | 728 | .label = null, |
| 714 | 729 | .lbrace = token_index, |
| 715 | 730 | .statements = ast.Node.Block.StatementList.init(arena), |
| 716 | 731 | .rbrace = undefined, |
| 717 | }); | |
| 732 | }; | |
| 718 | 733 | fn_proto.body_node = &block.base; |
| 719 | 734 | stack.append(State{ .Block = block }) catch unreachable; |
| 720 | 735 | continue; |
| ... | ... | @@ -770,10 +785,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 770 | 785 | // TODO: this is a special case. Remove this when #760 is fixed |
| 771 | 786 | if (token_ptr.id == Token.Id.Keyword_anyerror) { |
| 772 | 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 | 790 | .base = ast.Node{ .id = ast.Node.Id.ErrorType }, |
| 775 | 791 | .token = token_index, |
| 776 | }); | |
| 792 | }; | |
| 777 | 793 | fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base }; |
| 778 | 794 | continue; |
| 779 | 795 | } |
| ... | ... | @@ -791,14 +807,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 791 | 807 | if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| { |
| 792 | 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 | 812 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| 796 | 813 | .comptime_token = null, |
| 797 | 814 | .noalias_token = null, |
| 798 | 815 | .name_token = null, |
| 799 | 816 | .type_node = undefined, |
| 800 | 817 | .var_args_token = null, |
| 801 | }); | |
| 818 | }; | |
| 802 | 819 | try fn_proto.params.push(&param_decl.base); |
| 803 | 820 | |
| 804 | 821 | stack.append(State{ |
| ... | ... | @@ -877,13 +894,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 877 | 894 | const token_ptr = token.ptr; |
| 878 | 895 | switch (token_ptr.id) { |
| 879 | 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 | 899 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 882 | 900 | .label = ctx.label, |
| 883 | 901 | .lbrace = token_index, |
| 884 | 902 | .statements = ast.Node.Block.StatementList.init(arena), |
| 885 | 903 | .rbrace = undefined, |
| 886 | }); | |
| 904 | }; | |
| 887 | 905 | ctx.opt_ctx.store(&block.base); |
| 888 | 906 | stack.append(State{ .Block = block }) catch unreachable; |
| 889 | 907 | continue; |
| ... | ... | @@ -970,7 +988,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 970 | 988 | } |
| 971 | 989 | }, |
| 972 | 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 | 993 | .base = ast.Node{ .id = ast.Node.Id.While }, |
| 975 | 994 | .label = ctx.label, |
| 976 | 995 | .inline_token = ctx.inline_token, |
| ... | ... | @@ -980,7 +999,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 980 | 999 | .continue_expr = null, |
| 981 | 1000 | .body = undefined, |
| 982 | 1001 | .@"else" = null, |
| 983 | }); | |
| 1002 | }; | |
| 984 | 1003 | ctx.opt_ctx.store(&node.base); |
| 985 | 1004 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; |
| 986 | 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 | 1018 | continue; |
| 1000 | 1019 | }, |
| 1001 | 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 | 1023 | .base = ast.Node{ .id = ast.Node.Id.For }, |
| 1004 | 1024 | .label = ctx.label, |
| 1005 | 1025 | .inline_token = ctx.inline_token, |
| ... | ... | @@ -1008,7 +1028,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1008 | 1028 | .payload = null, |
| 1009 | 1029 | .body = undefined, |
| 1010 | 1030 | .@"else" = null, |
| 1011 | }); | |
| 1031 | }; | |
| 1012 | 1032 | ctx.opt_ctx.store(&node.base); |
| 1013 | 1033 | stack.append(State{ .Else = &node.@"else" }) catch unreachable; |
| 1014 | 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 | 1040 | }, |
| 1021 | 1041 | State.Else => |dest| { |
| 1022 | 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 | 1045 | .base = ast.Node{ .id = ast.Node.Id.Else }, |
| 1025 | 1046 | .else_token = else_token, |
| 1026 | 1047 | .payload = null, |
| 1027 | 1048 | .body = undefined, |
| 1028 | }); | |
| 1049 | }; | |
| 1029 | 1050 | dest.* = node; |
| 1030 | 1051 | |
| 1031 | 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 | 1104 | continue; |
| 1084 | 1105 | }, |
| 1085 | 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 | 1109 | .base = ast.Node{ .id = ast.Node.Id.Defer }, |
| 1088 | 1110 | .defer_token = token_index, |
| 1089 | 1111 | .expr = undefined, |
| 1090 | }); | |
| 1112 | }; | |
| 1091 | 1113 | const node_ptr = try block.statements.addOne(); |
| 1092 | 1114 | node_ptr.* = &node.base; |
| 1093 | 1115 | |
| ... | ... | @@ -1096,13 +1118,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1096 | 1118 | continue; |
| 1097 | 1119 | }, |
| 1098 | 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 | 1123 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 1101 | 1124 | .label = null, |
| 1102 | 1125 | .lbrace = token_index, |
| 1103 | 1126 | .statements = ast.Node.Block.StatementList.init(arena), |
| 1104 | 1127 | .rbrace = undefined, |
| 1105 | }); | |
| 1128 | }; | |
| 1106 | 1129 | try block.statements.push(&inner_block.base); |
| 1107 | 1130 | |
| 1108 | 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 | 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 | 1192 | .base = ast.Node{ .id = ast.Node.Id.AsmOutput }, |
| 1169 | 1193 | .lbracket = lbracket_index, |
| 1170 | 1194 | .symbolic_name = undefined, |
| 1171 | 1195 | .constraint = undefined, |
| 1172 | 1196 | .kind = undefined, |
| 1173 | 1197 | .rparen = undefined, |
| 1174 | }); | |
| 1198 | }; | |
| 1175 | 1199 | try items.push(node); |
| 1176 | 1200 | |
| 1177 | 1201 | stack.append(State{ .AsmOutputItems = items }) catch unreachable; |
| ... | ... | @@ -1218,14 +1242,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1218 | 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 | 1247 | .base = ast.Node{ .id = ast.Node.Id.AsmInput }, |
| 1223 | 1248 | .lbracket = lbracket_index, |
| 1224 | 1249 | .symbolic_name = undefined, |
| 1225 | 1250 | .constraint = undefined, |
| 1226 | 1251 | .expr = undefined, |
| 1227 | 1252 | .rparen = undefined, |
| 1228 | }); | |
| 1253 | }; | |
| 1229 | 1254 | try items.push(node); |
| 1230 | 1255 | |
| 1231 | 1256 | stack.append(State{ .AsmInputItems = items }) catch unreachable; |
| ... | ... | @@ -1283,12 +1308,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1283 | 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 | 1313 | .base = ast.Node{ .id = ast.Node.Id.FieldInitializer }, |
| 1288 | 1314 | .period_token = undefined, |
| 1289 | 1315 | .name_token = undefined, |
| 1290 | 1316 | .expr = undefined, |
| 1291 | }); | |
| 1317 | }; | |
| 1292 | 1318 | try list_state.list.push(&node.base); |
| 1293 | 1319 | |
| 1294 | 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 | 1416 | } |
| 1391 | 1417 | |
| 1392 | 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 | 1421 | .base = ast.Node{ .id = ast.Node.Id.SwitchCase }, |
| 1395 | 1422 | .items = ast.Node.SwitchCase.ItemList.init(arena), |
| 1396 | 1423 | .payload = null, |
| 1397 | 1424 | .expr = undefined, |
| 1398 | 1425 | .arrow_token = undefined, |
| 1399 | }); | |
| 1426 | }; | |
| 1400 | 1427 | try list_state.list.push(&node.base); |
| 1401 | 1428 | try stack.append(State{ .SwitchCaseCommaOrEnd = list_state }); |
| 1402 | 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 | 1454 | const token_index = token.index; |
| 1428 | 1455 | const token_ptr = token.ptr; |
| 1429 | 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 | 1459 | .base = ast.Node{ .id = ast.Node.Id.SwitchElse }, |
| 1432 | 1460 | .token = token_index, |
| 1433 | }); | |
| 1461 | }; | |
| 1434 | 1462 | try switch_case.items.push(&else_node.base); |
| 1435 | 1463 | |
| 1436 | 1464 | try stack.append(State{ |
| ... | ... | @@ -1537,7 +1565,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1537 | 1565 | |
| 1538 | 1566 | State.ExternType => |ctx| { |
| 1539 | 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 | 1570 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 1542 | 1571 | .doc_comments = ctx.comments, |
| 1543 | 1572 | .visib_token = null, |
| ... | ... | @@ -1553,7 +1582,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1553 | 1582 | .lib_name = null, |
| 1554 | 1583 | .align_expr = null, |
| 1555 | 1584 | .section_expr = null, |
| 1556 | }); | |
| 1585 | }; | |
| 1557 | 1586 | ctx.opt_ctx.store(&fn_proto.base); |
| 1558 | 1587 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 1559 | 1588 | continue; |
| ... | ... | @@ -1711,12 +1740,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1711 | 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 | 1745 | .base = ast.Node{ .id = ast.Node.Id.Payload }, |
| 1716 | 1746 | .lpipe = token_index, |
| 1717 | 1747 | .error_symbol = undefined, |
| 1718 | 1748 | .rpipe = undefined, |
| 1719 | }); | |
| 1749 | }; | |
| 1720 | 1750 | opt_ctx.store(&node.base); |
| 1721 | 1751 | |
| 1722 | 1752 | stack.append(State{ |
| ... | ... | @@ -1747,13 +1777,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1747 | 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 | 1782 | .base = ast.Node{ .id = ast.Node.Id.PointerPayload }, |
| 1752 | 1783 | .lpipe = token_index, |
| 1753 | 1784 | .ptr_token = null, |
| 1754 | 1785 | .value_symbol = undefined, |
| 1755 | 1786 | .rpipe = undefined, |
| 1756 | }); | |
| 1787 | }; | |
| 1757 | 1788 | opt_ctx.store(&node.base); |
| 1758 | 1789 | |
| 1759 | 1790 | try stack.append(State{ |
| ... | ... | @@ -1790,14 +1821,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1790 | 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 | 1826 | .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload }, |
| 1795 | 1827 | .lpipe = token_index, |
| 1796 | 1828 | .ptr_token = null, |
| 1797 | 1829 | .value_symbol = undefined, |
| 1798 | 1830 | .index_symbol = null, |
| 1799 | 1831 | .rpipe = undefined, |
| 1800 | }); | |
| 1832 | }; | |
| 1801 | 1833 | opt_ctx.store(&node.base); |
| 1802 | 1834 | |
| 1803 | 1835 | stack.append(State{ |
| ... | ... | @@ -1824,12 +1856,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1824 | 1856 | const token_ptr = token.ptr; |
| 1825 | 1857 | switch (token_ptr.id) { |
| 1826 | 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 | 1861 | .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression }, |
| 1829 | 1862 | .ltoken = token_index, |
| 1830 | 1863 | .kind = undefined, |
| 1831 | 1864 | .rhs = null, |
| 1832 | }); | |
| 1865 | }; | |
| 1833 | 1866 | opt_ctx.store(&node.base); |
| 1834 | 1867 | |
| 1835 | 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 | 1886 | continue; |
| 1854 | 1887 | }, |
| 1855 | 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 | 1891 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 1858 | 1892 | .op_token = token_index, |
| 1859 | 1893 | .op = switch (token_ptr.id) { |
| ... | ... | @@ -1863,7 +1897,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1863 | 1897 | else => unreachable, |
| 1864 | 1898 | }, |
| 1865 | 1899 | .rhs = undefined, |
| 1866 | }); | |
| 1900 | }; | |
| 1867 | 1901 | opt_ctx.store(&node.base); |
| 1868 | 1902 | |
| 1869 | 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 | 1921 | const lhs = opt_ctx.get() orelse continue; |
| 1888 | 1922 | |
| 1889 | 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 | 1926 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1892 | 1927 | .lhs = lhs, |
| 1893 | 1928 | .op_token = ellipsis3, |
| 1894 | 1929 | .op = ast.Node.InfixOp.Op.Range, |
| 1895 | 1930 | .rhs = undefined, |
| 1896 | }); | |
| 1931 | }; | |
| 1897 | 1932 | opt_ctx.store(&node.base); |
| 1898 | 1933 | stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; |
| 1899 | 1934 | continue; |
| ... | ... | @@ -1912,13 +1947,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1912 | 1947 | const token_index = token.index; |
| 1913 | 1948 | const token_ptr = token.ptr; |
| 1914 | 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 | 1952 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1917 | 1953 | .lhs = lhs, |
| 1918 | 1954 | .op_token = token_index, |
| 1919 | 1955 | .op = ass_id, |
| 1920 | 1956 | .rhs = undefined, |
| 1921 | }); | |
| 1957 | }; | |
| 1922 | 1958 | opt_ctx.store(&node.base); |
| 1923 | 1959 | stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 1924 | 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 | 1978 | const token_index = token.index; |
| 1943 | 1979 | const token_ptr = token.ptr; |
| 1944 | 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 | 1983 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1947 | 1984 | .lhs = lhs, |
| 1948 | 1985 | .op_token = token_index, |
| 1949 | 1986 | .op = unwrap_id, |
| 1950 | 1987 | .rhs = undefined, |
| 1951 | }); | |
| 1988 | }; | |
| 1952 | 1989 | opt_ctx.store(&node.base); |
| 1953 | 1990 | |
| 1954 | 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 | 2011 | const lhs = opt_ctx.get() orelse continue; |
| 1975 | 2012 | |
| 1976 | 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 | 2016 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 1979 | 2017 | .lhs = lhs, |
| 1980 | 2018 | .op_token = or_token, |
| 1981 | 2019 | .op = ast.Node.InfixOp.Op.BoolOr, |
| 1982 | 2020 | .rhs = undefined, |
| 1983 | }); | |
| 2021 | }; | |
| 1984 | 2022 | opt_ctx.store(&node.base); |
| 1985 | 2023 | stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 1986 | 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 | 2036 | const lhs = opt_ctx.get() orelse continue; |
| 1999 | 2037 | |
| 2000 | 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 | 2041 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2003 | 2042 | .lhs = lhs, |
| 2004 | 2043 | .op_token = and_token, |
| 2005 | 2044 | .op = ast.Node.InfixOp.Op.BoolAnd, |
| 2006 | 2045 | .rhs = undefined, |
| 2007 | }); | |
| 2046 | }; | |
| 2008 | 2047 | opt_ctx.store(&node.base); |
| 2009 | 2048 | stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2010 | 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 | 2064 | const token_index = token.index; |
| 2026 | 2065 | const token_ptr = token.ptr; |
| 2027 | 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 | 2069 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2030 | 2070 | .lhs = lhs, |
| 2031 | 2071 | .op_token = token_index, |
| 2032 | 2072 | .op = comp_id, |
| 2033 | 2073 | .rhs = undefined, |
| 2034 | }); | |
| 2074 | }; | |
| 2035 | 2075 | opt_ctx.store(&node.base); |
| 2036 | 2076 | stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2037 | 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 | 2092 | const lhs = opt_ctx.get() orelse continue; |
| 2053 | 2093 | |
| 2054 | 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 | 2097 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2057 | 2098 | .lhs = lhs, |
| 2058 | 2099 | .op_token = pipe, |
| 2059 | 2100 | .op = ast.Node.InfixOp.Op.BitOr, |
| 2060 | 2101 | .rhs = undefined, |
| 2061 | }); | |
| 2102 | }; | |
| 2062 | 2103 | opt_ctx.store(&node.base); |
| 2063 | 2104 | stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2064 | 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 | 2117 | const lhs = opt_ctx.get() orelse continue; |
| 2077 | 2118 | |
| 2078 | 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 | 2122 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2081 | 2123 | .lhs = lhs, |
| 2082 | 2124 | .op_token = caret, |
| 2083 | 2125 | .op = ast.Node.InfixOp.Op.BitXor, |
| 2084 | 2126 | .rhs = undefined, |
| 2085 | }); | |
| 2127 | }; | |
| 2086 | 2128 | opt_ctx.store(&node.base); |
| 2087 | 2129 | stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2088 | 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 | 2142 | const lhs = opt_ctx.get() orelse continue; |
| 2101 | 2143 | |
| 2102 | 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 | 2147 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2105 | 2148 | .lhs = lhs, |
| 2106 | 2149 | .op_token = ampersand, |
| 2107 | 2150 | .op = ast.Node.InfixOp.Op.BitAnd, |
| 2108 | 2151 | .rhs = undefined, |
| 2109 | }); | |
| 2152 | }; | |
| 2110 | 2153 | opt_ctx.store(&node.base); |
| 2111 | 2154 | stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2112 | 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 | 2170 | const token_index = token.index; |
| 2128 | 2171 | const token_ptr = token.ptr; |
| 2129 | 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 | 2175 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2132 | 2176 | .lhs = lhs, |
| 2133 | 2177 | .op_token = token_index, |
| 2134 | 2178 | .op = bitshift_id, |
| 2135 | 2179 | .rhs = undefined, |
| 2136 | }); | |
| 2180 | }; | |
| 2137 | 2181 | opt_ctx.store(&node.base); |
| 2138 | 2182 | stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2139 | 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 | 2201 | const token_index = token.index; |
| 2158 | 2202 | const token_ptr = token.ptr; |
| 2159 | 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 | 2206 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2162 | 2207 | .lhs = lhs, |
| 2163 | 2208 | .op_token = token_index, |
| 2164 | 2209 | .op = add_id, |
| 2165 | 2210 | .rhs = undefined, |
| 2166 | }); | |
| 2211 | }; | |
| 2167 | 2212 | opt_ctx.store(&node.base); |
| 2168 | 2213 | stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2169 | 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 | 2232 | const token_index = token.index; |
| 2188 | 2233 | const token_ptr = token.ptr; |
| 2189 | 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 | 2237 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2192 | 2238 | .lhs = lhs, |
| 2193 | 2239 | .op_token = token_index, |
| 2194 | 2240 | .op = mult_id, |
| 2195 | 2241 | .rhs = undefined, |
| 2196 | }); | |
| 2242 | }; | |
| 2197 | 2243 | opt_ctx.store(&node.base); |
| 2198 | 2244 | stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2199 | 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 | 2261 | const lhs = opt_ctx.get() orelse continue; |
| 2216 | 2262 | |
| 2217 | 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 | 2266 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2220 | 2267 | .lhs = lhs, |
| 2221 | 2268 | .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, |
| 2222 | 2269 | .rtoken = undefined, |
| 2223 | }); | |
| 2270 | }; | |
| 2224 | 2271 | opt_ctx.store(&node.base); |
| 2225 | 2272 | |
| 2226 | 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 | 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 | 2286 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2239 | 2287 | .lhs = lhs, |
| 2240 | 2288 | .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, |
| 2241 | 2289 | .rtoken = undefined, |
| 2242 | }); | |
| 2290 | }; | |
| 2243 | 2291 | opt_ctx.store(&node.base); |
| 2244 | 2292 | stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2245 | 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 | 2311 | const lhs = opt_ctx.get() orelse continue; |
| 2264 | 2312 | |
| 2265 | 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 | 2316 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2268 | 2317 | .lhs = lhs, |
| 2269 | 2318 | .op_token = bang, |
| 2270 | 2319 | .op = ast.Node.InfixOp.Op.ErrorUnion, |
| 2271 | 2320 | .rhs = undefined, |
| 2272 | }); | |
| 2321 | }; | |
| 2273 | 2322 | opt_ctx.store(&node.base); |
| 2274 | 2323 | stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2275 | 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 | 2331 | const token_index = token.index; |
| 2283 | 2332 | const token_ptr = token.ptr; |
| 2284 | 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 | 2336 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2287 | 2337 | .op_token = token_index, |
| 2288 | 2338 | .op = prefix_id, |
| 2289 | 2339 | .rhs = undefined, |
| 2290 | }); | |
| 2340 | }; | |
| 2291 | 2341 | opt_ctx.store(&node.base); |
| 2292 | 2342 | |
| 2293 | 2343 | // Treat '**' token as two pointer types |
| 2294 | 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 | 2347 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2297 | 2348 | .op_token = token_index, |
| 2298 | 2349 | .op = prefix_id, |
| 2299 | 2350 | .rhs = undefined, |
| 2300 | }); | |
| 2351 | }; | |
| 2301 | 2352 | node.rhs = &child.base; |
| 2302 | 2353 | node = child; |
| 2303 | 2354 | } |
| ... | ... | @@ -2316,12 +2367,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2316 | 2367 | |
| 2317 | 2368 | State.SuffixOpExpressionBegin => |opt_ctx| { |
| 2318 | 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 | 2372 | .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, |
| 2321 | 2373 | .async_token = async_token, |
| 2322 | 2374 | .allocator_type = null, |
| 2323 | 2375 | .rangle_bracket = null, |
| 2324 | }); | |
| 2376 | }; | |
| 2325 | 2377 | stack.append(State{ |
| 2326 | 2378 | .AsyncEnd = AsyncEndCtx{ |
| 2327 | 2379 | .ctx = opt_ctx, |
| ... | ... | @@ -2347,7 +2399,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2347 | 2399 | const token_ptr = token.ptr; |
| 2348 | 2400 | switch (token_ptr.id) { |
| 2349 | 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 | 2404 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2352 | 2405 | .lhs = lhs, |
| 2353 | 2406 | .op = ast.Node.SuffixOp.Op{ |
| ... | ... | @@ -2357,7 +2410,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2357 | 2410 | }, |
| 2358 | 2411 | }, |
| 2359 | 2412 | .rtoken = undefined, |
| 2360 | }); | |
| 2413 | }; | |
| 2361 | 2414 | opt_ctx.store(&node.base); |
| 2362 | 2415 | |
| 2363 | 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 | 2424 | continue; |
| 2372 | 2425 | }, |
| 2373 | 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 | 2429 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2376 | 2430 | .lhs = lhs, |
| 2377 | 2431 | .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined }, |
| 2378 | 2432 | .rtoken = undefined, |
| 2379 | }); | |
| 2433 | }; | |
| 2380 | 2434 | opt_ctx.store(&node.base); |
| 2381 | 2435 | |
| 2382 | 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 | 2440 | }, |
| 2387 | 2441 | Token.Id.Period => { |
| 2388 | 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 | 2445 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2391 | 2446 | .lhs = lhs, |
| 2392 | 2447 | .op = ast.Node.SuffixOp.Op.Deref, |
| 2393 | 2448 | .rtoken = asterisk_token, |
| 2394 | }); | |
| 2449 | }; | |
| 2395 | 2450 | opt_ctx.store(&node.base); |
| 2396 | 2451 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2397 | 2452 | continue; |
| 2398 | 2453 | } |
| 2399 | 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 | 2457 | .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, |
| 2402 | 2458 | .lhs = lhs, |
| 2403 | 2459 | .op = ast.Node.SuffixOp.Op.UnwrapOptional, |
| 2404 | 2460 | .rtoken = question_token, |
| 2405 | }); | |
| 2461 | }; | |
| 2406 | 2462 | opt_ctx.store(&node.base); |
| 2407 | 2463 | stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; |
| 2408 | 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 | 2468 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2412 | 2469 | .lhs = lhs, |
| 2413 | 2470 | .op_token = token_index, |
| 2414 | 2471 | .op = ast.Node.InfixOp.Op.Period, |
| 2415 | 2472 | .rhs = undefined, |
| 2416 | }); | |
| 2473 | }; | |
| 2417 | 2474 | opt_ctx.store(&node.base); |
| 2418 | 2475 | |
| 2419 | 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 | 2524 | continue; |
| 2468 | 2525 | }, |
| 2469 | 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 | 2529 | .base = ast.Node{ .id = ast.Node.Id.PromiseType }, |
| 2472 | 2530 | .promise_token = token.index, |
| 2473 | 2531 | .result = null, |
| 2474 | }); | |
| 2532 | }; | |
| 2475 | 2533 | opt_ctx.store(&node.base); |
| 2476 | 2534 | const next_token = nextToken(&tok_it, &tree); |
| 2477 | 2535 | const next_token_index = next_token.index; |
| ... | ... | @@ -2493,12 +2551,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2493 | 2551 | continue; |
| 2494 | 2552 | }, |
| 2495 | 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 | 2556 | .base = ast.Node{ .id = ast.Node.Id.GroupedExpression }, |
| 2498 | 2557 | .lparen = token.index, |
| 2499 | 2558 | .expr = undefined, |
| 2500 | 2559 | .rparen = undefined, |
| 2501 | }); | |
| 2560 | }; | |
| 2502 | 2561 | opt_ctx.store(&node.base); |
| 2503 | 2562 | |
| 2504 | 2563 | stack.append(State{ |
| ... | ... | @@ -2511,12 +2570,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2511 | 2570 | continue; |
| 2512 | 2571 | }, |
| 2513 | 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 | 2575 | .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, |
| 2516 | 2576 | .builtin_token = token.index, |
| 2517 | 2577 | .params = ast.Node.BuiltinCall.ParamList.init(arena), |
| 2518 | 2578 | .rparen_token = undefined, |
| 2519 | }); | |
| 2579 | }; | |
| 2520 | 2580 | opt_ctx.store(&node.base); |
| 2521 | 2581 | |
| 2522 | 2582 | stack.append(State{ |
| ... | ... | @@ -2530,12 +2590,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2530 | 2590 | continue; |
| 2531 | 2591 | }, |
| 2532 | 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 | 2595 | .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, |
| 2535 | 2596 | .op_token = token.index, |
| 2536 | 2597 | .op = undefined, |
| 2537 | 2598 | .rhs = undefined, |
| 2538 | }); | |
| 2599 | }; | |
| 2539 | 2600 | opt_ctx.store(&node.base); |
| 2540 | 2601 | |
| 2541 | 2602 | stack.append(State{ .SliceOrArrayType = node }) catch unreachable; |
| ... | ... | @@ -2593,7 +2654,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2593 | 2654 | continue; |
| 2594 | 2655 | }, |
| 2595 | 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 | 2659 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 2598 | 2660 | .doc_comments = null, |
| 2599 | 2661 | .visib_token = null, |
| ... | ... | @@ -2609,13 +2671,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2609 | 2671 | .lib_name = null, |
| 2610 | 2672 | .align_expr = null, |
| 2611 | 2673 | .section_expr = null, |
| 2612 | }); | |
| 2674 | }; | |
| 2613 | 2675 | opt_ctx.store(&fn_proto.base); |
| 2614 | 2676 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 2615 | 2677 | continue; |
| 2616 | 2678 | }, |
| 2617 | 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 | 2682 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 2620 | 2683 | .doc_comments = null, |
| 2621 | 2684 | .visib_token = null, |
| ... | ... | @@ -2631,7 +2694,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2631 | 2694 | .lib_name = null, |
| 2632 | 2695 | .align_expr = null, |
| 2633 | 2696 | .section_expr = null, |
| 2634 | }); | |
| 2697 | }; | |
| 2635 | 2698 | opt_ctx.store(&fn_proto.base); |
| 2636 | 2699 | stack.append(State{ .FnProto = fn_proto }) catch unreachable; |
| 2637 | 2700 | try stack.append(State{ |
| ... | ... | @@ -2643,7 +2706,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2643 | 2706 | continue; |
| 2644 | 2707 | }, |
| 2645 | 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 | 2711 | .base = ast.Node{ .id = ast.Node.Id.Asm }, |
| 2648 | 2712 | .asm_token = token.index, |
| 2649 | 2713 | .volatile_token = null, |
| ... | ... | @@ -2652,7 +2716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2652 | 2716 | .inputs = ast.Node.Asm.InputList.init(arena), |
| 2653 | 2717 | .clobbers = ast.Node.Asm.ClobberList.init(arena), |
| 2654 | 2718 | .rparen = undefined, |
| 2655 | }); | |
| 2719 | }; | |
| 2656 | 2720 | opt_ctx.store(&node.base); |
| 2657 | 2721 | |
| 2658 | 2722 | stack.append(State{ |
| ... | ... | @@ -2701,13 +2765,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2701 | 2765 | |
| 2702 | 2766 | State.ErrorTypeOrSetDecl => |ctx| { |
| 2703 | 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 | 2770 | .base = ast.Node{ .id = ast.Node.Id.InfixOp }, |
| 2706 | 2771 | .lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base, |
| 2707 | 2772 | .op_token = undefined, |
| 2708 | 2773 | .op = ast.Node.InfixOp.Op.Period, |
| 2709 | 2774 | .rhs = undefined, |
| 2710 | }); | |
| 2775 | }; | |
| 2711 | 2776 | ctx.opt_ctx.store(&node.base); |
| 2712 | 2777 | stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; |
| 2713 | 2778 | try stack.append(State{ |
| ... | ... | @@ -2719,12 +2784,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2719 | 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 | 2789 | .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl }, |
| 2724 | 2790 | .error_token = ctx.error_token, |
| 2725 | 2791 | .decls = ast.Node.ErrorSetDecl.DeclList.init(arena), |
| 2726 | 2792 | .rbrace_token = undefined, |
| 2727 | }); | |
| 2793 | }; | |
| 2728 | 2794 | ctx.opt_ctx.store(&node.base); |
| 2729 | 2795 | |
| 2730 | 2796 | stack.append(State{ |
| ... | ... | @@ -2785,11 +2851,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 2785 | 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 | 2856 | .base = ast.Node{ .id = ast.Node.Id.ErrorTag }, |
| 2790 | 2857 | .doc_comments = comments, |
| 2791 | 2858 | .name_token = ident_token_index, |
| 2792 | }); | |
| 2859 | }; | |
| 2793 | 2860 | node_ptr.* = &node.base; |
| 2794 | 2861 | continue; |
| 2795 | 2862 | }, |
| ... | ... | @@ -3129,10 +3196,11 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as |
| 3129 | 3196 | if (result.*) |comment_node| { |
| 3130 | 3197 | break :blk comment_node; |
| 3131 | 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 | 3201 | .base = ast.Node{ .id = ast.Node.Id.DocComment }, |
| 3134 | 3202 | .lines = ast.Node.DocComment.LineList.init(arena), |
| 3135 | }); | |
| 3203 | }; | |
| 3136 | 3204 | result.* = comment_node; |
| 3137 | 3205 | break :blk comment_node; |
| 3138 | 3206 | } |
| ... | ... | @@ -3158,10 +3226,11 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato |
| 3158 | 3226 | return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base; |
| 3159 | 3227 | }, |
| 3160 | 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 | 3231 | .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral }, |
| 3163 | 3232 | .lines = ast.Node.MultilineStringLiteral.LineList.init(arena), |
| 3164 | }); | |
| 3233 | }; | |
| 3165 | 3234 | try node.lines.push(token_index); |
| 3166 | 3235 | while (true) { |
| 3167 | 3236 | const multiline_str = nextToken(tok_it, tree); |
| ... | ... | @@ -3186,25 +3255,27 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato |
| 3186 | 3255 | fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool { |
| 3187 | 3256 | switch (token_ptr.id) { |
| 3188 | 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 | 3260 | .base = ast.Node{ .id = ast.Node.Id.Suspend }, |
| 3191 | 3261 | .suspend_token = token_index, |
| 3192 | 3262 | .body = null, |
| 3193 | }); | |
| 3263 | }; | |
| 3194 | 3264 | ctx.store(&node.base); |
| 3195 | 3265 | |
| 3196 | 3266 | stack.append(State{ .SuspendBody = node }) catch unreachable; |
| 3197 | 3267 | return true; |
| 3198 | 3268 | }, |
| 3199 | 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 | 3272 | .base = ast.Node{ .id = ast.Node.Id.If }, |
| 3202 | 3273 | .if_token = token_index, |
| 3203 | 3274 | .condition = undefined, |
| 3204 | 3275 | .payload = null, |
| 3205 | 3276 | .body = undefined, |
| 3206 | 3277 | .@"else" = null, |
| 3207 | }); | |
| 3278 | }; | |
| 3208 | 3279 | ctx.store(&node.base); |
| 3209 | 3280 | |
| 3210 | 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 | 3309 | return true; |
| 3239 | 3310 | }, |
| 3240 | 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 | 3314 | .base = ast.Node{ .id = ast.Node.Id.Switch }, |
| 3243 | 3315 | .switch_token = token_index, |
| 3244 | 3316 | .expr = undefined, |
| 3245 | 3317 | .cases = ast.Node.Switch.CaseList.init(arena), |
| 3246 | 3318 | .rbrace = undefined, |
| 3247 | }); | |
| 3319 | }; | |
| 3248 | 3320 | ctx.store(&node.base); |
| 3249 | 3321 | |
| 3250 | 3322 | stack.append(State{ |
| ... | ... | @@ -3260,25 +3332,27 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti |
| 3260 | 3332 | return true; |
| 3261 | 3333 | }, |
| 3262 | 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 | 3337 | .base = ast.Node{ .id = ast.Node.Id.Comptime }, |
| 3265 | 3338 | .comptime_token = token_index, |
| 3266 | 3339 | .expr = undefined, |
| 3267 | 3340 | .doc_comments = null, |
| 3268 | }); | |
| 3341 | }; | |
| 3269 | 3342 | ctx.store(&node.base); |
| 3270 | 3343 | |
| 3271 | 3344 | try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } }); |
| 3272 | 3345 | return true; |
| 3273 | 3346 | }, |
| 3274 | 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 | 3350 | .base = ast.Node{ .id = ast.Node.Id.Block }, |
| 3277 | 3351 | .label = null, |
| 3278 | 3352 | .lbrace = token_index, |
| 3279 | 3353 | .statements = ast.Node.Block.StatementList.init(arena), |
| 3280 | 3354 | .rbrace = undefined, |
| 3281 | }); | |
| 3355 | }; | |
| 3282 | 3356 | ctx.store(&block.base); |
| 3283 | 3357 | stack.append(State{ .Block = block }) catch unreachable; |
| 3284 | 3358 | return true; |
| ... | ... | @@ -3412,10 +3486,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { |
| 3412 | 3486 | } |
| 3413 | 3487 | |
| 3414 | 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 | 3491 | .base = ast.Node{ .id = ast.Node.typeToId(T) }, |
| 3417 | 3492 | .token = token_index, |
| 3418 | }); | |
| 3493 | }; | |
| 3494 | return result; | |
| 3419 | 3495 | } |
| 3420 | 3496 | |
| 3421 | 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 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 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 | 38 | cases.add( |
| 5 | 39 | "compile log a pointer to an opaque value", |
| 6 | 40 | \\export fn entry() void { |
| ... | ... | @@ -267,8 +301,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 267 | 301 | \\ const Errors = error{} || u16; |
| 268 | 302 | \\} |
| 269 | 303 | , |
| 270 | ".tmp_source.zig:2:20: error: expected error set type, found 'u8'", | |
| 271 | ".tmp_source.zig:5:31: error: expected error set type, found 'u16'", | |
| 304 | ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'", | |
| 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 | 310 | cases.add( |
| ... | ... | @@ -2618,7 +2654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2618 | 2654 | \\ |
| 2619 | 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 | 2660 | cases.add( |
| ... | ... | @@ -3193,7 +3229,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3193 | 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 | 3235 | cases.add( |
| ... | ... | @@ -3539,7 +3575,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3539 | 3575 | \\ |
| 3540 | 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 | 3581 | cases.add( |
| ... | ... | @@ -5331,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5331 | 5367 | , |
| 5332 | 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 | 48 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
| 49 | 49 | |
| 50 | 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 | 53 | .b = b, |
| 53 | 54 | .step = b.step("test-compare-output", "Run the compare output tests"), |
| 54 | 55 | .test_index = 0, |
| 55 | 56 | .test_filter = test_filter, |
| 56 | 57 | .modes = modes, |
| 57 | }) catch unreachable; | |
| 58 | }; | |
| 58 | 59 | |
| 59 | 60 | compare_output.addCases(cases); |
| 60 | 61 | |
| ... | ... | @@ -62,13 +63,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 62 | 63 | } |
| 63 | 64 | |
| 64 | 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 | 68 | .b = b, |
| 67 | 69 | .step = b.step("test-runtime-safety", "Run the runtime safety tests"), |
| 68 | 70 | .test_index = 0, |
| 69 | 71 | .test_filter = test_filter, |
| 70 | 72 | .modes = modes, |
| 71 | }) catch unreachable; | |
| 73 | }; | |
| 72 | 74 | |
| 73 | 75 | runtime_safety.addCases(cases); |
| 74 | 76 | |
| ... | ... | @@ -76,13 +78,14 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 76 | 78 | } |
| 77 | 79 | |
| 78 | 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 | 83 | .b = b, |
| 81 | 84 | .step = b.step("test-compile-errors", "Run the compile error tests"), |
| 82 | 85 | .test_index = 0, |
| 83 | 86 | .test_filter = test_filter, |
| 84 | 87 | .modes = modes, |
| 85 | }) catch unreachable; | |
| 88 | }; | |
| 86 | 89 | |
| 87 | 90 | compile_errors.addCases(cases); |
| 88 | 91 | |
| ... | ... | @@ -90,13 +93,14 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 90 | 93 | } |
| 91 | 94 | |
| 92 | 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 | 98 | .b = b, |
| 95 | 99 | .step = b.step("test-build-examples", "Build the examples"), |
| 96 | 100 | .test_index = 0, |
| 97 | 101 | .test_filter = test_filter, |
| 98 | 102 | .modes = modes, |
| 99 | }) catch unreachable; | |
| 103 | }; | |
| 100 | 104 | |
| 101 | 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 | 123 | } |
| 120 | 124 | |
| 121 | 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 | 128 | .b = b, |
| 124 | 129 | .step = b.step("test-asm-link", "Run the assemble and link tests"), |
| 125 | 130 | .test_index = 0, |
| 126 | 131 | .test_filter = test_filter, |
| 127 | 132 | .modes = modes, |
| 128 | }) catch unreachable; | |
| 133 | }; | |
| 129 | 134 | |
| 130 | 135 | assemble_and_link.addCases(cases); |
| 131 | 136 | |
| ... | ... | @@ -133,12 +138,13 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, mode |
| 133 | 138 | } |
| 134 | 139 | |
| 135 | 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 | 143 | .b = b, |
| 138 | 144 | .step = b.step("test-translate-c", "Run the C transation tests"), |
| 139 | 145 | .test_index = 0, |
| 140 | 146 | .test_filter = test_filter, |
| 141 | }) catch unreachable; | |
| 147 | }; | |
| 142 | 148 | |
| 143 | 149 | translate_c.addCases(cases); |
| 144 | 150 | |
| ... | ... | @@ -146,12 +152,13 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St |
| 146 | 152 | } |
| 147 | 153 | |
| 148 | 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 | 157 | .b = b, |
| 151 | 158 | .step = b.step("test-gen-h", "Run the C header file generation tests"), |
| 152 | 159 | .test_index = 0, |
| 153 | 160 | .test_filter = test_filter, |
| 154 | }) catch unreachable; | |
| 161 | }; | |
| 155 | 162 | |
| 156 | 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 | 170 | for (test_targets) |test_target| { |
| 164 | 171 | const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch); |
| 165 | 172 | for (modes) |mode| { |
| 166 | for ([]bool{ | |
| 167 | false, | |
| 168 | true, | |
| 169 | }) |link_libc| { | |
| 170 | if (link_libc and !is_native) { | |
| 171 | // don't assume we have a cross-compiling libc set up | |
| 172 | continue; | |
| 173 | } | |
| 174 | const these_tests = b.addTest(root_src); | |
| 175 | these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare")); | |
| 176 | these_tests.setFilter(test_filter); | |
| 177 | these_tests.setBuildMode(mode); | |
| 178 | if (!is_native) { | |
| 179 | these_tests.setTarget(test_target.arch, test_target.os, test_target.environ); | |
| 180 | } | |
| 181 | if (link_libc) { | |
| 182 | these_tests.linkSystemLibrary("c"); | |
| 173 | for ([]bool{ false, true }) |link_libc| { | |
| 174 | for ([]bool{ false, true }) |single_threaded| { | |
| 175 | if (link_libc and !is_native) { | |
| 176 | // don't assume we have a cross-compiling libc set up | |
| 177 | continue; | |
| 178 | } | |
| 179 | const these_tests = b.addTest(root_src); | |
| 180 | these_tests.setNamePrefix(b.fmt( | |
| 181 | "{}-{}-{}-{}-{}-{} ", | |
| 182 | name, | |
| 183 | @tagName(test_target.os), | |
| 184 | @tagName(test_target.arch), | |
| 185 | @tagName(mode), | |
| 186 | if (link_libc) "c" else "bare", | |
| 187 | if (single_threaded) "single" else "multi", | |
| 188 | )); | |
| 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 | 251 | |
| 238 | 252 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep { |
| 239 | 253 | const allocator = context.b.allocator; |
| 240 | const ptr = allocator.create(RunCompareOutputStep{ | |
| 254 | const ptr = allocator.create(RunCompareOutputStep) catch unreachable; | |
| 255 | ptr.* = RunCompareOutputStep{ | |
| 241 | 256 | .context = context, |
| 242 | 257 | .exe_path = exe_path, |
| 243 | 258 | .name = name, |
| ... | ... | @@ -245,7 +260,7 @@ pub const CompareOutputContext = struct { |
| 245 | 260 | .test_index = context.test_index, |
| 246 | 261 | .step = build.Step.init("RunCompareOutput", allocator, make), |
| 247 | 262 | .cli_args = cli_args, |
| 248 | }) catch unreachable; | |
| 263 | }; | |
| 249 | 264 | context.test_index += 1; |
| 250 | 265 | return ptr; |
| 251 | 266 | } |
| ... | ... | @@ -324,13 +339,14 @@ pub const CompareOutputContext = struct { |
| 324 | 339 | |
| 325 | 340 | pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep { |
| 326 | 341 | const allocator = context.b.allocator; |
| 327 | const ptr = allocator.create(RuntimeSafetyRunStep{ | |
| 342 | const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable; | |
| 343 | ptr.* = RuntimeSafetyRunStep{ | |
| 328 | 344 | .context = context, |
| 329 | 345 | .exe_path = exe_path, |
| 330 | 346 | .name = name, |
| 331 | 347 | .test_index = context.test_index, |
| 332 | 348 | .step = build.Step.init("RuntimeSafetyRun", allocator, make), |
| 333 | }) catch unreachable; | |
| 349 | }; | |
| 334 | 350 | |
| 335 | 351 | context.test_index += 1; |
| 336 | 352 | return ptr; |
| ... | ... | @@ -535,14 +551,15 @@ pub const CompileErrorContext = struct { |
| 535 | 551 | |
| 536 | 552 | pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep { |
| 537 | 553 | const allocator = context.b.allocator; |
| 538 | const ptr = allocator.create(CompileCmpOutputStep{ | |
| 554 | const ptr = allocator.create(CompileCmpOutputStep) catch unreachable; | |
| 555 | ptr.* = CompileCmpOutputStep{ | |
| 539 | 556 | .step = build.Step.init("CompileCmpOutput", allocator, make), |
| 540 | 557 | .context = context, |
| 541 | 558 | .name = name, |
| 542 | 559 | .test_index = context.test_index, |
| 543 | 560 | .case = case, |
| 544 | 561 | .build_mode = build_mode, |
| 545 | }) catch unreachable; | |
| 562 | }; | |
| 546 | 563 | |
| 547 | 564 | context.test_index += 1; |
| 548 | 565 | return ptr; |
| ... | ... | @@ -654,13 +671,14 @@ pub const CompileErrorContext = struct { |
| 654 | 671 | } |
| 655 | 672 | |
| 656 | 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 | 676 | .name = name, |
| 659 | 677 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 660 | 678 | .expected_errors = ArrayList([]const u8).init(self.b.allocator), |
| 661 | 679 | .link_libc = false, |
| 662 | 680 | .is_exe = false, |
| 663 | }) catch unreachable; | |
| 681 | }; | |
| 664 | 682 | |
| 665 | 683 | tc.addSourceFile(".tmp_source.zig", source); |
| 666 | 684 | comptime var arg_i = 0; |
| ... | ... | @@ -814,13 +832,14 @@ pub const TranslateCContext = struct { |
| 814 | 832 | |
| 815 | 833 | pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep { |
| 816 | 834 | const allocator = context.b.allocator; |
| 817 | const ptr = allocator.create(TranslateCCmpOutputStep{ | |
| 835 | const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable; | |
| 836 | ptr.* = TranslateCCmpOutputStep{ | |
| 818 | 837 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 819 | 838 | .context = context, |
| 820 | 839 | .name = name, |
| 821 | 840 | .test_index = context.test_index, |
| 822 | 841 | .case = case, |
| 823 | }) catch unreachable; | |
| 842 | }; | |
| 824 | 843 | |
| 825 | 844 | context.test_index += 1; |
| 826 | 845 | return ptr; |
| ... | ... | @@ -921,12 +940,13 @@ pub const TranslateCContext = struct { |
| 921 | 940 | } |
| 922 | 941 | |
| 923 | 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 | 945 | .name = name, |
| 926 | 946 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 927 | 947 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), |
| 928 | 948 | .allow_warnings = allow_warnings, |
| 929 | }) catch unreachable; | |
| 949 | }; | |
| 930 | 950 | |
| 931 | 951 | tc.addSourceFile(filename, source); |
| 932 | 952 | comptime var arg_i = 0; |
| ... | ... | @@ -1008,14 +1028,15 @@ pub const GenHContext = struct { |
| 1008 | 1028 | |
| 1009 | 1029 | pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep { |
| 1010 | 1030 | const allocator = context.b.allocator; |
| 1011 | const ptr = allocator.create(GenHCmpOutputStep{ | |
| 1031 | const ptr = allocator.create(GenHCmpOutputStep) catch unreachable; | |
| 1032 | ptr.* = GenHCmpOutputStep{ | |
| 1012 | 1033 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 1013 | 1034 | .context = context, |
| 1014 | 1035 | .h_path = h_path, |
| 1015 | 1036 | .name = name, |
| 1016 | 1037 | .test_index = context.test_index, |
| 1017 | 1038 | .case = case, |
| 1018 | }) catch unreachable; | |
| 1039 | }; | |
| 1019 | 1040 | |
| 1020 | 1041 | context.test_index += 1; |
| 1021 | 1042 | return ptr; |
| ... | ... | @@ -1055,11 +1076,12 @@ pub const GenHContext = struct { |
| 1055 | 1076 | } |
| 1056 | 1077 | |
| 1057 | 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 | 1081 | .name = name, |
| 1060 | 1082 | .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), |
| 1061 | 1083 | .expected_lines = ArrayList([]const u8).init(self.b.allocator), |
| 1062 | }) catch unreachable; | |
| 1084 | }; | |
| 1063 | 1085 | |
| 1064 | 1086 | tc.addSourceFile(filename, source); |
| 1065 | 1087 | comptime var arg_i = 0; |