diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index c7d92712b02655001c95e0f5bf393a2a3c566081..934b8a4f4a83007b3e27e51ced31175dc35b0c13 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -12,28 +12,28 @@ tasks:
ninja install
- test: |
cd zig/build
- bin/zig test ../test/behavior.zig
+ bin/zig test ../test/stage1/behavior.zig
bin/zig test ../std/special/compiler_rt/index.zig
- bin/zig test ../test/behavior.zig --library c
+ bin/zig test ../test/stage1/behavior.zig --library c
bin/zig test ../std/special/compiler_rt/index.zig --library c
- bin/zig test ../test/behavior.zig --release-fast
+ bin/zig test ../test/stage1/behavior.zig --release-fast
bin/zig test ../std/special/compiler_rt/index.zig --release-fast
- bin/zig test ../test/behavior.zig --release-fast --library c
+ bin/zig test ../test/stage1/behavior.zig --release-fast --library c
bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c
- bin/zig test ../test/behavior.zig --release-small --library c
+ bin/zig test ../test/stage1/behavior.zig --release-small --library c
bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c
- bin/zig test ../test/behavior.zig --release-small
+ bin/zig test ../test/stage1/behavior.zig --release-small
bin/zig test ../std/special/compiler_rt/index.zig --release-small
- bin/zig test ../test/behavior.zig --release-safe
+ bin/zig test ../test/stage1/behavior.zig --release-safe
bin/zig test ../std/special/compiler_rt/index.zig --release-safe
- bin/zig test ../test/behavior.zig --release-safe --library c
+ bin/zig test ../test/stage1/behavior.zig --release-safe --library c
bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c
# TODO enable all tests
#bin/zig build --build-file ../build.zig test
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3841519f295f72ea624c92f59cbbc71b4a97c47b..4dd6a1dcfa620c3796801b895101402d2f5c66d6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -454,10 +454,10 @@ set(ZIG_STD_FILES
"crypto/hmac.zig"
"crypto/index.zig"
"crypto/md5.zig"
+ "crypto/poly1305.zig"
"crypto/sha1.zig"
"crypto/sha2.zig"
"crypto/sha3.zig"
- "crypto/poly1305.zig"
"crypto/x25519.zig"
"cstr.zig"
"debug/failing_allocator.zig"
@@ -566,9 +566,9 @@ set(ZIG_STD_FILES
"math/tan.zig"
"math/tanh.zig"
"math/trunc.zig"
+ "mem.zig"
"meta/index.zig"
"meta/trait.zig"
- "mem.zig"
"mutex.zig"
"net.zig"
"os/child_process.zig"
@@ -576,16 +576,16 @@ set(ZIG_STD_FILES
"os/darwin/errno.zig"
"os/epoch.zig"
"os/file.zig"
+ "os/freebsd/errno.zig"
+ "os/freebsd/index.zig"
"os/get_app_data_dir.zig"
"os/get_user_id.zig"
"os/index.zig"
+ "os/linux/arm64.zig"
"os/linux/errno.zig"
"os/linux/index.zig"
"os/linux/vdso.zig"
"os/linux/x86_64.zig"
- "os/linux/arm64.zig"
- "os/freebsd/errno.zig"
- "os/freebsd/index.zig"
"os/path.zig"
"os/time.zig"
"os/uefi.zig"
@@ -612,6 +612,16 @@ set(ZIG_STD_FILES
"special/compiler_rt/comparetf2.zig"
"special/compiler_rt/divti3.zig"
"special/compiler_rt/extendXfYf2.zig"
+ "special/compiler_rt/fixdfdi.zig"
+ "special/compiler_rt/fixdfsi.zig"
+ "special/compiler_rt/fixdfti.zig"
+ "special/compiler_rt/fixint.zig"
+ "special/compiler_rt/fixsfdi.zig"
+ "special/compiler_rt/fixsfsi.zig"
+ "special/compiler_rt/fixsfti.zig"
+ "special/compiler_rt/fixtfdi.zig"
+ "special/compiler_rt/fixtfsi.zig"
+ "special/compiler_rt/fixtfti.zig"
"special/compiler_rt/fixuint.zig"
"special/compiler_rt/fixunsdfdi.zig"
"special/compiler_rt/fixunsdfsi.zig"
@@ -622,16 +632,6 @@ set(ZIG_STD_FILES
"special/compiler_rt/fixunstfdi.zig"
"special/compiler_rt/fixunstfsi.zig"
"special/compiler_rt/fixunstfti.zig"
- "special/compiler_rt/fixint.zig"
- "special/compiler_rt/fixdfdi.zig"
- "special/compiler_rt/fixdfsi.zig"
- "special/compiler_rt/fixdfti.zig"
- "special/compiler_rt/fixsfdi.zig"
- "special/compiler_rt/fixsfsi.zig"
- "special/compiler_rt/fixsfti.zig"
- "special/compiler_rt/fixtfdi.zig"
- "special/compiler_rt/fixtfsi.zig"
- "special/compiler_rt/fixtfti.zig"
"special/compiler_rt/floattidf.zig"
"special/compiler_rt/floattisf.zig"
"special/compiler_rt/floattitf.zig"
@@ -656,6 +656,7 @@ set(ZIG_STD_FILES
"special/panic.zig"
"special/test_runner.zig"
"spinlock.zig"
+ "statically_initialized_mutex.zig"
"unicode.zig"
"zig/ast.zig"
"zig/index.zig"
diff --git a/build.zig b/build.zig
index 16185eebf4fdeb645d5c7379c4ae6ea9055a9cbd..a41a5f808ba3a08c4606bfee5ab2255aff36669d 100644
--- a/build.zig
+++ b/build.zig
@@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void {
}
const modes = chosen_modes[0..chosen_mode_index];
- test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
@@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" });
var result = LibraryDep{
- .prefix = mem.split(prefix_output, " \r\n").next().?,
+ .prefix = mem.tokenize(prefix_output, " \r\n").next().?,
.libs = ArrayList([]const u8).init(b.allocator),
.system_libs = ArrayList([]const u8).init(b.allocator),
.includes = ArrayList([]const u8).init(b.allocator),
.libdirs = ArrayList([]const u8).init(b.allocator),
};
{
- var it = mem.split(libs_output, " \r\n");
+ var it = mem.tokenize(libs_output, " \r\n");
while (it.next()) |lib_arg| {
if (mem.startsWith(u8, lib_arg, "-l")) {
try result.system_libs.append(lib_arg[2..]);
@@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
}
}
{
- var it = mem.split(includes_output, " \r\n");
+ var it = mem.tokenize(includes_output, " \r\n");
while (it.next()) |include_arg| {
if (mem.startsWith(u8, include_arg, "-I")) {
try result.includes.append(include_arg[2..]);
@@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
}
}
{
- var it = mem.split(libdir_output, " \r\n");
+ var it = mem.tokenize(libdir_output, " \r\n");
while (it.next()) |libdir| {
if (mem.startsWith(u8, libdir, "-L")) {
try result.libdirs.append(libdir[2..]);
@@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
}
pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
- var it = mem.split(stdlib_files, ";");
+ var it = mem.tokenize(stdlib_files, ";");
while (it.next()) |stdlib_file| {
const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
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 {
}
pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
- var it = mem.split(c_header_files, ";");
+ var it = mem.tokenize(c_header_files, ";");
while (it.next()) |c_header_file| {
const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
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 {
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
if (ctx.lld_include_dir.len != 0) {
exe.addIncludeDir(ctx.lld_include_dir);
- var it = mem.split(ctx.lld_libraries, ";");
+ var it = mem.tokenize(ctx.lld_libraries, ";");
while (it.next()) |lib| {
exe.addObjectFile(lib);
}
@@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
} else if (exe.target.isFreeBSD()) {
try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
exe.linkSystemLibrary("pthread");
- }
- else if (exe.target.isDarwin()) {
+ } else if (exe.target.isDarwin()) {
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
// Compiler is GCC.
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
@@ -335,7 +334,7 @@ fn addCxxKnownPath(
ctx.cxx_compiler,
b.fmt("-print-file-name={}", objname),
});
- const path_unpadded = mem.split(path_padded, "\r\n").next().?;
+ const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?;
if (mem.eql(u8, path_unpadded, objname)) {
if (errtxt) |msg| {
warn("{}", msg);
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 6e03d3ec6d676d64a2ac30e2dcb60e3dffe84247..144c8571c430ab0ac51dff2ff25424632f0906c7 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -1531,6 +1531,29 @@ test "array initialization with function calls" {
{#code_end#}
{#see_also|for|Slices#}
{#header_close#}
+
+ {#header_open|Vectors#}
+
+ A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on
+ in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin
+ function {#link|@Vector#}.
+
+
+ TODO talk about C ABI interop
+
+ {#header_open|SIMD#}
+
+ TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the
+ docs with:
+ * What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector?
+ * How to convert to/from vectors/arrays
+ * How to access individual elements from vectors, how to loop over the elements
+ * "shuffle"
+ * Advice on writing high perf software, how to abstract the best way
+
+ {#header_close#}
+ {#header_close#}
+
{#header_open|Pointers#}
Zig has two kinds of pointers:
@@ -4327,7 +4350,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
For example, if we were to introduce another function to the above snippet:
- {#code_begin|test_err|unable to evaluate constant expression#}
+ {#code_begin|test_err|values of type 'type' must be comptime known#}
fn max(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
@@ -5905,13 +5928,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
This function is a low level intrinsic with no safety mechanisms. Most code
should not use this function, instead using something like this:
- {#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
+ {#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memcpy.
There is also a standard library function for this:
{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}
{#header_close#}
{#header_open|@memset#}
@@ -5923,7 +5946,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
This function is a low level intrinsic with no safety mechanisms. Most
code should not use this function, instead using something like this:
- {#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
+ {#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memset.
@@ -6592,9 +6615,10 @@ pub const TypeInfo = union(TypeId) {
{#header_close#}
{#header_open|@typeName#}
- {#syntax#}@typeName(T: type) []u8{#endsyntax#}
+ {#syntax#}@typeName(T: type) [N]u8{#endsyntax#}
- This function returns the string representation of a type.
+ This function returns the string representation of a type, as
+ an array. It is equivalent to a string literal of the type name.
{#header_close#}
@@ -6606,6 +6630,17 @@ pub const TypeInfo = union(TypeId) {
expression passed as an argument. The expression is evaluated.
+ {#header_close#}
+
+ {#header_open|@Vector#}
+ {#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}
+
+ This function returns a vector type for {#link|SIMD#}.
+
+
+ {#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a
+ {#link|pointer|Pointers#}.
+
{#header_close#}
{#header_close#}
@@ -6679,6 +6714,25 @@ pub fn build(b: *Builder) void {
{#header_close#}
{#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
{#header_close#}
+
+ {#header_open|Single Threaded Builds#}
+ Zig has a compile option --single-threaded which has the following effects:
+
+ - {#link|@atomicLoad#} is emitted as a normal load.
+ - {#link|@atomicRmw#} is emitted as a normal memory load, modify, store.
+ - {#link|@fence#} becomes a no-op.
+ - Variables which have Thread Local Storage instead become globals. TODO thread local variables
+ are not implemented yet.
+ - The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.
+ TODO: please note this will not be implemented until the upcoming Coroutine Rewrite
+ - The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
+ and therefore various userland APIs which read this variable become more efficient.
+ For example {#syntax#}std.Mutex{#endsyntax#} becomes
+ an empty data structure and all of its functions become no-ops.
+
+
+ {#header_close#}
+
{#header_open|Undefined Behavior#}
Zig has many instances of undefined behavior. If undefined behavior is
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index c00c7c1d412e31ed49571a87d4214e046b8601b9..d60892432ee3322a5bc8d9ef6c24601d961a6d6f 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -83,10 +83,11 @@ pub const ZigCompiler = struct {
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
errdefer c.LLVMContextDispose(context_ref);
- const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{
+ const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node);
+ node.* = std.atomic.Stack(llvm.ContextRef).Node{
.next = undefined,
.data = context_ref,
- });
+ };
errdefer self.loop.allocator.destroy(node);
return LlvmHandle{ .node = node };
@@ -596,7 +597,8 @@ pub const Compilation = struct {
}
fn initTypes(comp: *Compilation) !void {
- comp.meta_type = try comp.arena().create(Type.MetaType{
+ comp.meta_type = try comp.arena().create(Type.MetaType);
+ comp.meta_type.* = Type.MetaType{
.base = Type{
.name = "type",
.base = Value{
@@ -608,12 +610,13 @@ pub const Compilation = struct {
.abi_alignment = Type.AbiAlignment.init(comp.loop),
},
.value = undefined,
- });
+ };
comp.meta_type.value = &comp.meta_type.base;
comp.meta_type.base.base.typ = &comp.meta_type.base;
assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
- comp.void_type = try comp.arena().create(Type.Void{
+ comp.void_type = try comp.arena().create(Type.Void);
+ comp.void_type.* = Type.Void{
.base = Type{
.name = "void",
.base = Value{
@@ -624,10 +627,11 @@ pub const Compilation = struct {
.id = builtin.TypeId.Void,
.abi_alignment = Type.AbiAlignment.init(comp.loop),
},
- });
+ };
assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
- comp.noreturn_type = try comp.arena().create(Type.NoReturn{
+ comp.noreturn_type = try comp.arena().create(Type.NoReturn);
+ comp.noreturn_type.* = Type.NoReturn{
.base = Type{
.name = "noreturn",
.base = Value{
@@ -638,10 +642,11 @@ pub const Compilation = struct {
.id = builtin.TypeId.NoReturn,
.abi_alignment = Type.AbiAlignment.init(comp.loop),
},
- });
+ };
assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
- comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{
+ comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt);
+ comp.comptime_int_type.* = Type.ComptimeInt{
.base = Type{
.name = "comptime_int",
.base = Value{
@@ -652,10 +657,11 @@ pub const Compilation = struct {
.id = builtin.TypeId.ComptimeInt,
.abi_alignment = Type.AbiAlignment.init(comp.loop),
},
- });
+ };
assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
- comp.bool_type = try comp.arena().create(Type.Bool{
+ comp.bool_type = try comp.arena().create(Type.Bool);
+ comp.bool_type.* = Type.Bool{
.base = Type{
.name = "bool",
.base = Value{
@@ -666,45 +672,50 @@ pub const Compilation = struct {
.id = builtin.TypeId.Bool,
.abi_alignment = Type.AbiAlignment.init(comp.loop),
},
- });
+ };
assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
- comp.void_value = try comp.arena().create(Value.Void{
+ comp.void_value = try comp.arena().create(Value.Void);
+ comp.void_value.* = Value.Void{
.base = Value{
.id = Value.Id.Void,
.typ = &Type.Void.get(comp).base,
.ref_count = std.atomic.Int(usize).init(1),
},
- });
+ };
- comp.true_value = try comp.arena().create(Value.Bool{
+ comp.true_value = try comp.arena().create(Value.Bool);
+ comp.true_value.* = Value.Bool{
.base = Value{
.id = Value.Id.Bool,
.typ = &Type.Bool.get(comp).base,
.ref_count = std.atomic.Int(usize).init(1),
},
.x = true,
- });
+ };
- comp.false_value = try comp.arena().create(Value.Bool{
+ comp.false_value = try comp.arena().create(Value.Bool);
+ comp.false_value.* = Value.Bool{
.base = Value{
.id = Value.Id.Bool,
.typ = &Type.Bool.get(comp).base,
.ref_count = std.atomic.Int(usize).init(1),
},
.x = false,
- });
+ };
- comp.noreturn_value = try comp.arena().create(Value.NoReturn{
+ comp.noreturn_value = try comp.arena().create(Value.NoReturn);
+ comp.noreturn_value.* = Value.NoReturn{
.base = Value{
.id = Value.Id.NoReturn,
.typ = &Type.NoReturn.get(comp).base,
.ref_count = std.atomic.Int(usize).init(1),
},
- });
+ };
for (CInt.list) |cint, i| {
- const c_int_type = try comp.arena().create(Type.Int{
+ const c_int_type = try comp.arena().create(Type.Int);
+ c_int_type.* = Type.Int{
.base = Type{
.name = cint.zig_name,
.base = Value{
@@ -720,11 +731,12 @@ pub const Compilation = struct {
.bit_count = comp.target.cIntTypeSizeInBits(cint.id),
},
.garbage_node = undefined,
- });
+ };
comp.c_int_types[i] = c_int_type;
assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
}
- comp.u8_type = try comp.arena().create(Type.Int{
+ comp.u8_type = try comp.arena().create(Type.Int);
+ comp.u8_type.* = Type.Int{
.base = Type{
.name = "u8",
.base = Value{
@@ -740,7 +752,7 @@ pub const Compilation = struct {
.bit_count = 8,
},
.garbage_node = undefined,
- });
+ };
assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null);
}
@@ -829,7 +841,7 @@ pub const Compilation = struct {
};
errdefer self.gpa().free(source_code);
- const tree = try self.gpa().createOne(ast.Tree);
+ const tree = try self.gpa().create(ast.Tree);
tree.* = try std.zig.parse(self.gpa(), source_code);
errdefer {
tree.deinit();
@@ -925,7 +937,8 @@ pub const Compilation = struct {
}
} else {
// add new decl
- const fn_decl = try self.gpa().create(Decl.Fn{
+ const fn_decl = try self.gpa().create(Decl.Fn);
+ fn_decl.* = Decl.Fn{
.base = Decl{
.id = Decl.Id.Fn,
.name = name,
@@ -936,7 +949,7 @@ pub const Compilation = struct {
},
.value = Decl.Fn.Val{ .Unresolved = {} },
.fn_proto = fn_proto,
- });
+ };
tree_scope.base.ref();
errdefer self.gpa().destroy(fn_decl);
@@ -1140,12 +1153,13 @@ pub const Compilation = struct {
}
}
- const link_lib = try self.gpa().create(LinkLib{
+ const link_lib = try self.gpa().create(LinkLib);
+ link_lib.* = LinkLib{
.name = name,
.path = null,
.provided_explicitly = provided_explicitly,
.symbols = ArrayList([]u8).init(self.gpa()),
- });
+ };
try self.link_libs_list.append(link_lib);
if (is_libc) {
self.libc_link_lib = link_lib;
diff --git a/src-self-hosted/errmsg.zig b/src-self-hosted/errmsg.zig
index 0e552fde7ef5fd047aa1c3c806362336a7952d11..fc49fad410b6423f3fa481d534f5b400c1c90ef5 100644
--- a/src-self-hosted/errmsg.zig
+++ b/src-self-hosted/errmsg.zig
@@ -118,7 +118,8 @@ pub const Msg = struct {
const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath);
errdefer comp.gpa().free(realpath);
- const msg = try comp.gpa().create(Msg{
+ const msg = try comp.gpa().create(Msg);
+ msg.* = Msg{
.text = text,
.realpath = realpath,
.data = Data{
@@ -128,7 +129,7 @@ pub const Msg = struct {
.span = span,
},
},
- });
+ };
tree_scope.base.ref();
return msg;
}
@@ -139,13 +140,14 @@ pub const Msg = struct {
const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath);
errdefer comp.gpa().free(realpath_copy);
- const msg = try comp.gpa().create(Msg{
+ const msg = try comp.gpa().create(Msg);
+ msg.* = Msg{
.text = text,
.realpath = realpath_copy,
.data = Data{
.Cli = Cli{ .allocator = comp.gpa() },
},
- });
+ };
return msg;
}
@@ -164,7 +166,8 @@ pub const Msg = struct {
var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
try parse_error.render(&tree_scope.tree.tokens, out_stream);
- const msg = try comp.gpa().create(Msg{
+ const msg = try comp.gpa().create(Msg);
+ msg.* = Msg{
.text = undefined,
.realpath = realpath_copy,
.data = Data{
@@ -177,7 +180,7 @@ pub const Msg = struct {
},
},
},
- });
+ };
tree_scope.base.ref();
msg.text = text_buf.toOwnedSlice();
return msg;
@@ -203,7 +206,8 @@ pub const Msg = struct {
var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
try parse_error.render(&tree.tokens, out_stream);
- const msg = try allocator.create(Msg{
+ const msg = try allocator.create(Msg);
+ msg.* = Msg{
.text = undefined,
.realpath = realpath_copy,
.data = Data{
@@ -216,7 +220,7 @@ pub const Msg = struct {
},
},
},
- });
+ };
msg.text = text_buf.toOwnedSlice();
errdefer allocator.destroy(msg);
diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig
index 562765b354d5a68b23fa696d67a68ab63b32763e..0362bb4ef83f604764f16b97ba5198804788542c 100644
--- a/src-self-hosted/ir.zig
+++ b/src-self-hosted/ir.zig
@@ -1021,12 +1021,13 @@ pub const Builder = struct {
pub const Error = Analyze.Error;
pub fn init(comp: *Compilation, tree_scope: *Scope.AstTree, begin_scope: ?*Scope) !Builder {
- const code = try comp.gpa().create(Code{
+ const code = try comp.gpa().create(Code);
+ code.* = Code{
.basic_block_list = undefined,
.arena = std.heap.ArenaAllocator.init(comp.gpa()),
.return_type = null,
.tree_scope = tree_scope,
- });
+ };
code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator);
errdefer code.destroy(comp.gpa());
@@ -1052,7 +1053,8 @@ pub const Builder = struct {
/// No need to clean up resources thanks to the arena allocator.
pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock {
- const basic_block = try self.arena().create(BasicBlock{
+ const basic_block = try self.arena().create(BasicBlock);
+ basic_block.* = BasicBlock{
.ref_count = 0,
.name_hint = name_hint,
.debug_id = self.next_debug_id,
@@ -1063,7 +1065,7 @@ pub const Builder = struct {
.ref_instruction = null,
.llvm_block = undefined,
.llvm_exit_block = undefined,
- });
+ };
self.next_debug_id += 1;
return basic_block;
}
@@ -1774,7 +1776,8 @@ pub const Builder = struct {
params: I.Params,
is_generated: bool,
) !*Inst {
- const inst = try self.arena().create(I{
+ const inst = try self.arena().create(I);
+ inst.* = I{
.base = Inst{
.id = Inst.typeToId(I),
.is_generated = is_generated,
@@ -1793,7 +1796,7 @@ pub const Builder = struct {
.owner_bb = self.current_basic_block,
},
.params = params,
- });
+ };
// Look at the params and ref() other instructions
comptime var i = 0;
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 1c5d111c5ae69d919d4ba90cdcd986ee53007cf1..18d2daf0c2e894ebfb51fb691c272ea16b4d9508 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -57,10 +57,10 @@ pub const LibCInstallation = struct {
const contents = try std.io.readFileAlloc(allocator, libc_file);
defer allocator.free(contents);
- var it = std.mem.split(contents, "\n");
+ var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
if (line.len == 0 or line[0] == '#') continue;
- var line_it = std.mem.split(line, "=");
+ var line_it = std.mem.separate(line, "=");
const name = line_it.next() orelse {
try stderr.print("missing equal sign after field name\n");
return error.ParseError;
@@ -213,7 +213,7 @@ pub const LibCInstallation = struct {
},
}
- var it = std.mem.split(exec_result.stderr, "\n\r");
+ var it = std.mem.tokenize(exec_result.stderr, "\n\r");
var search_paths = std.ArrayList([]const u8).init(loop.allocator);
defer search_paths.deinit();
while (it.next()) |line| {
@@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo
return error.CCompilerCrashed;
},
}
- var it = std.mem.split(exec_result.stdout, "\n\r");
+ var it = std.mem.tokenize(exec_result.stdout, "\n\r");
const line = it.next() orelse return error.LibCRuntimeNotFound;
const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index 0742cbfe6507f7deada6b82ce15aac847ab2d84e..f6ee9a0513d029474685786181d6103ff232b93e 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
const root_name = if (provided_name) |n| n else blk: {
if (root_source_file) |file| {
const basename = os.path.basename(file);
- var it = mem.split(basename, ".");
+ var it = mem.separate(basename, ".");
break :blk it.next() orelse basename;
} else {
try stderr.write("--name [name] not provided and unable to infer\n");
@@ -944,12 +944,13 @@ const CliPkg = struct {
parent: ?*CliPkg,
pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {
- var pkg = try allocator.create(CliPkg{
+ var pkg = try allocator.create(CliPkg);
+ pkg.* = CliPkg{
.name = name,
.path = path,
.children = ArrayList(*CliPkg).init(allocator),
.parent = parent,
- });
+ };
return pkg;
}
diff --git a/src-self-hosted/package.zig b/src-self-hosted/package.zig
index 720b2796510518b7895cce7eca7e5c5c13707529..0d31731b551e6dd730aaf379c989dc3a8f098244 100644
--- a/src-self-hosted/package.zig
+++ b/src-self-hosted/package.zig
@@ -15,11 +15,13 @@ pub const Package = struct {
/// makes internal copies of root_src_dir and root_src_path
/// allocator should be an arena allocator because Package never frees anything
pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package {
- return allocator.create(Package{
+ const ptr = try allocator.create(Package);
+ ptr.* = Package{
.root_src_dir = try Buffer.init(allocator, root_src_dir),
.root_src_path = try Buffer.init(allocator, root_src_path),
.table = Table.init(allocator),
- });
+ };
+ return ptr;
}
pub fn add(self: *Package, name: []const u8, package: *Package) !void {
diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig
index 43d3b5a784e0d3ee4bf32a79036247bf2e9c5f94..b14c073a9e4c8fccd35a897b15f9e41a59e6f60c 100644
--- a/src-self-hosted/scope.zig
+++ b/src-self-hosted/scope.zig
@@ -120,7 +120,7 @@ pub const Scope = struct {
/// Creates a Root scope with 1 reference
/// Takes ownership of realpath
pub fn create(comp: *Compilation, realpath: []u8) !*Root {
- const self = try comp.gpa().createOne(Root);
+ const self = try comp.gpa().create(Root);
self.* = Root{
.base = Scope{
.id = Id.Root,
@@ -150,7 +150,7 @@ pub const Scope = struct {
/// Creates a scope with 1 reference
/// Takes ownership of tree, will deinit and destroy when done.
pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree {
- const self = try comp.gpa().createOne(AstTree);
+ const self = try comp.gpa().create(AstTree);
self.* = AstTree{
.base = undefined,
.tree = tree,
@@ -182,7 +182,7 @@ pub const Scope = struct {
/// Creates a Decls scope with 1 reference
pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
- const self = try comp.gpa().createOne(Decls);
+ const self = try comp.gpa().create(Decls);
self.* = Decls{
.base = undefined,
.table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
@@ -235,7 +235,7 @@ pub const Scope = struct {
/// Creates a Block scope with 1 reference
pub fn create(comp: *Compilation, parent: *Scope) !*Block {
- const self = try comp.gpa().createOne(Block);
+ const self = try comp.gpa().create(Block);
self.* = Block{
.base = undefined,
.incoming_values = undefined,
@@ -262,7 +262,7 @@ pub const Scope = struct {
/// Creates a FnDef scope with 1 reference
/// Must set the fn_val later
pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
- const self = try comp.gpa().createOne(FnDef);
+ const self = try comp.gpa().create(FnDef);
self.* = FnDef{
.base = undefined,
.fn_val = null,
@@ -281,7 +281,7 @@ pub const Scope = struct {
/// Creates a CompTime scope with 1 reference
pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
- const self = try comp.gpa().createOne(CompTime);
+ const self = try comp.gpa().create(CompTime);
self.* = CompTime{ .base = undefined };
self.base.init(Id.CompTime, parent);
return self;
@@ -309,7 +309,7 @@ pub const Scope = struct {
kind: Kind,
defer_expr_scope: *DeferExpr,
) !*Defer {
- const self = try comp.gpa().createOne(Defer);
+ const self = try comp.gpa().create(Defer);
self.* = Defer{
.base = undefined,
.defer_expr_scope = defer_expr_scope,
@@ -333,7 +333,7 @@ pub const Scope = struct {
/// Creates a DeferExpr scope with 1 reference
pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
- const self = try comp.gpa().createOne(DeferExpr);
+ const self = try comp.gpa().create(DeferExpr);
self.* = DeferExpr{
.base = undefined,
.expr_node = expr_node,
@@ -398,7 +398,7 @@ pub const Scope = struct {
}
fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var {
- const self = try comp.gpa().createOne(Var);
+ const self = try comp.gpa().create(Var);
self.* = Var{
.base = undefined,
.name = name,
diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig
index aa00bb876d54b2d4d0e600434bb0565497dfd443..8a05594b301bfcbe80f7400053bb5a950d0666e5 100644
--- a/src-self-hosted/type.zig
+++ b/src-self-hosted/type.zig
@@ -44,6 +44,7 @@ pub const Type = struct {
Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp),
+ Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp),
}
}
@@ -77,6 +78,7 @@ pub const Type = struct {
Id.ArgTuple => unreachable,
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
+ Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context),
}
}
@@ -103,6 +105,7 @@ pub const Type = struct {
Id.Enum,
Id.Fn,
Id.Promise,
+ Id.Vector,
=> return false,
Id.Struct => @panic("TODO"),
@@ -135,6 +138,7 @@ pub const Type = struct {
Id.Float,
Id.Fn,
Id.Promise,
+ Id.Vector,
=> return true,
Id.Pointer => {
@@ -409,7 +413,7 @@ pub const Type = struct {
key.ref();
errdefer key.deref(comp);
- const self = try comp.gpa().createOne(Fn);
+ const self = try comp.gpa().create(Fn);
self.* = Fn{
.base = undefined,
.key = key,
@@ -611,11 +615,12 @@ pub const Type = struct {
}
}
- const self = try comp.gpa().create(Int{
+ const self = try comp.gpa().create(Int);
+ self.* = Int{
.base = undefined,
.key = key,
.garbage_node = undefined,
- });
+ };
errdefer comp.gpa().destroy(self);
const u_or_i = "ui"[@boolToInt(key.is_signed)];
@@ -777,11 +782,12 @@ pub const Type = struct {
}
}
- const self = try comp.gpa().create(Pointer{
+ const self = try comp.gpa().create(Pointer);
+ self.* = Pointer{
.base = undefined,
.key = normal_key,
.garbage_node = undefined,
- });
+ };
errdefer comp.gpa().destroy(self);
const size_str = switch (self.key.size) {
@@ -875,11 +881,12 @@ pub const Type = struct {
}
}
- const self = try comp.gpa().create(Array{
+ const self = try comp.gpa().create(Array);
+ self.* = Array{
.base = undefined,
.key = key,
.garbage_node = undefined,
- });
+ };
errdefer comp.gpa().destroy(self);
const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name);
@@ -902,6 +909,18 @@ pub const Type = struct {
}
};
+ pub const Vector = struct {
+ base: Type,
+
+ pub fn destroy(self: *Vector, comp: *Compilation) void {
+ comp.gpa().destroy(self);
+ }
+
+ pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+ @panic("TODO");
+ }
+ };
+
pub const ComptimeFloat = struct {
base: Type,
diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig
index e6dca4eff77e1b8c634b117635f9551316193b91..9431c614b92eeed292e15af6fa0039d30475d757 100644
--- a/src-self-hosted/value.zig
+++ b/src-self-hosted/value.zig
@@ -135,14 +135,15 @@ pub const Value = struct {
symbol_name: Buffer,
pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto {
- const self = try comp.gpa().create(FnProto{
+ const self = try comp.gpa().create(FnProto);
+ self.* = FnProto{
.base = Value{
.id = Value.Id.FnProto,
.typ = &fn_type.base,
.ref_count = std.atomic.Int(usize).init(1),
},
.symbol_name = symbol_name,
- });
+ };
fn_type.base.base.ref();
return self;
}
@@ -190,14 +191,16 @@ pub const Value = struct {
/// Creates a Fn value with 1 ref
/// Takes ownership of symbol_name
pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn {
- const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{
+ const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node);
+ link_set_node.* = Compilation.FnLinkSet.Node{
.data = null,
.next = undefined,
.prev = undefined,
- });
+ };
errdefer comp.gpa().destroy(link_set_node);
- const self = try comp.gpa().create(Fn{
+ const self = try comp.gpa().create(Fn);
+ self.* = Fn{
.base = Value{
.id = Value.Id.Fn,
.typ = &fn_type.base,
@@ -209,7 +212,7 @@ pub const Value = struct {
.symbol_name = symbol_name,
.containing_object = Buffer.initNull(comp.gpa()),
.link_set_node = link_set_node,
- });
+ };
fn_type.base.base.ref();
fndef_scope.fn_val = self;
fndef_scope.base.ref();
@@ -353,7 +356,8 @@ pub const Value = struct {
var ptr_type_consumed = false;
errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
- const self = try comp.gpa().create(Value.Ptr{
+ const self = try comp.gpa().create(Value.Ptr);
+ self.* = Value.Ptr{
.base = Value{
.id = Value.Id.Ptr,
.typ = &ptr_type.base,
@@ -366,7 +370,7 @@ pub const Value = struct {
},
},
.mut = Mut.CompTimeConst,
- });
+ };
ptr_type_consumed = true;
errdefer comp.gpa().destroy(self);
@@ -430,14 +434,15 @@ pub const Value = struct {
}) catch unreachable);
errdefer array_type.base.base.deref(comp);
- const self = try comp.gpa().create(Value.Array{
+ const self = try comp.gpa().create(Value.Array);
+ self.* = Value.Array{
.base = Value{
.id = Value.Id.Array,
.typ = &array_type.base,
.ref_count = std.atomic.Int(usize).init(1),
},
.special = Special{ .OwnedBuffer = buffer },
- });
+ };
errdefer comp.gpa().destroy(self);
return self;
@@ -509,14 +514,15 @@ pub const Value = struct {
big_int: std.math.big.Int,
pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int {
- const self = try comp.gpa().create(Value.Int{
+ const self = try comp.gpa().create(Value.Int);
+ self.* = Value.Int{
.base = Value{
.id = Value.Id.Int,
.typ = typ,
.ref_count = std.atomic.Int(usize).init(1),
},
.big_int = undefined,
- });
+ };
typ.base.ref();
errdefer comp.gpa().destroy(self);
@@ -557,14 +563,15 @@ pub const Value = struct {
old.base.typ.base.ref();
errdefer old.base.typ.base.deref(comp);
- const new = try comp.gpa().create(Value.Int{
+ const new = try comp.gpa().create(Value.Int);
+ new.* = Value.Int{
.base = Value{
.id = Value.Id.Int,
.typ = old.base.typ,
.ref_count = std.atomic.Int(usize).init(1),
},
.big_int = undefined,
- });
+ };
errdefer comp.gpa().destroy(new);
new.big_int = try old.big_int.clone();
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 91b24e311059c83605cd8486002f1b841846f060..c4c9e13cfb4c2427c9261d76d2c33ac588b6408e 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -56,9 +56,6 @@ struct IrExecutable {
size_t next_debug_id;
size_t *backward_branch_count;
size_t backward_branch_quota;
- bool invalid;
- bool is_inline;
- bool is_generic_instantiation;
ZigFn *fn_entry;
Buf *c_import_buf;
AstNode *source_node;
@@ -78,6 +75,10 @@ struct IrExecutable {
IrBasicBlock *coro_suspend_block;
IrBasicBlock *coro_final_cleanup_block;
ZigVar *coro_allocator_var;
+
+ bool invalid;
+ bool is_inline;
+ bool is_generic_instantiation;
};
enum OutType {
@@ -90,6 +91,9 @@ enum OutType {
enum ConstParentId {
ConstParentIdNone,
ConstParentIdStruct,
+ ConstParentIdErrUnionCode,
+ ConstParentIdErrUnionPayload,
+ ConstParentIdOptionalPayload,
ConstParentIdArray,
ConstParentIdUnion,
ConstParentIdScalar,
@@ -107,6 +111,15 @@ struct ConstParent {
ConstExprValue *struct_val;
size_t field_index;
} p_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_payload;
+ struct {
+ ConstExprValue *optional_val;
+ } p_optional_payload;
struct {
ConstExprValue *union_val;
} p_union;
@@ -118,13 +131,11 @@ struct ConstParent {
struct ConstStructValue {
ConstExprValue *fields;
- ConstParent parent;
};
struct ConstUnionValue {
BigInt tag;
ConstExprValue *payload;
- ConstParent parent;
};
enum ConstArraySpecial {
@@ -138,7 +149,6 @@ struct ConstArrayValue {
union {
struct {
ConstExprValue *elements;
- ConstParent parent;
} s_none;
Buf *s_buf;
} data;
@@ -153,19 +163,29 @@ enum ConstPtrSpecial {
ConstPtrSpecialBaseArray,
// The pointer points to a field in an underlying struct.
ConstPtrSpecialBaseStruct,
+ // The pointer points to the error set field of an error union
+ ConstPtrSpecialBaseErrorUnionCode,
+ // The pointer points to the payload field of an error union
+ ConstPtrSpecialBaseErrorUnionPayload,
+ // The pointer points to the payload field of an optional
+ ConstPtrSpecialBaseOptionalPayload,
// This means that we did a compile-time pointer reinterpret and we cannot
// understand the value of pointee at compile time. However, we will still
// emit a binary with a compile time known address.
// In this case index is the numeric address value.
- // We also use this for null pointer. We need the data layout for ConstCastOnly == true
- // types to be the same, so all optionals of pointer types use x_ptr
- // instead of x_optional
ConstPtrSpecialHardCodedAddr,
// This means that the pointer represents memory of assigning to _.
// That is, storing discards the data, and loading is invalid.
ConstPtrSpecialDiscard,
// This is actually a function.
ConstPtrSpecialFunction,
+ // This means the pointer is null. This is only allowed when the type is ?*T.
+ // We use this instead of ConstPtrSpecialHardCodedAddr because often we check
+ // for that value to avoid doing comptime work.
+ // We need the data layout for ConstCastOnly == true
+ // types to be the same, so all optionals of pointer types use x_ptr
+ // instead of x_optional.
+ ConstPtrSpecialNull,
};
enum ConstPtrMut {
@@ -199,6 +219,15 @@ struct ConstPtrValue {
ConstExprValue *struct_val;
size_t field_index;
} base_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_payload;
+ struct {
+ ConstExprValue *optional_val;
+ } base_optional_payload;
struct {
uint64_t addr;
} hard_coded_addr;
@@ -209,7 +238,7 @@ struct ConstPtrValue {
};
struct ConstErrValue {
- ErrorTableEntry *err;
+ ConstExprValue *error_set;
ConstExprValue *payload;
};
@@ -265,6 +294,7 @@ struct ConstGlobalRefs {
struct ConstExprValue {
ZigType *type;
ConstValSpecial special;
+ ConstParent parent;
ConstGlobalRefs *global_refs;
union {
@@ -433,7 +463,7 @@ enum NodeType {
NodeTypeArrayType,
NodeTypeErrorType,
NodeTypeIfErrorExpr,
- NodeTypeTestExpr,
+ NodeTypeIfOptional,
NodeTypeErrorSetDecl,
NodeTypeCancel,
NodeTypeResume,
@@ -677,7 +707,7 @@ struct AstNodeUse {
AstNode *expr;
TldResolution resolution;
- IrInstruction *value;
+ ConstExprValue *value;
};
struct AstNodeIfBoolExpr {
@@ -1180,6 +1210,12 @@ struct ZigTypePromise {
ZigType *result_type;
};
+struct ZigTypeVector {
+ // The type must be a pointer, integer, or float
+ ZigType *elem_type;
+ uint32_t len;
+};
+
enum ZigTypeId {
ZigTypeIdInvalid,
ZigTypeIdMetaType,
@@ -1206,6 +1242,7 @@ enum ZigTypeId {
ZigTypeIdArgTuple,
ZigTypeIdOpaque,
ZigTypeIdPromise,
+ ZigTypeIdVector,
};
struct ZigType {
@@ -1232,6 +1269,7 @@ struct ZigType {
ZigTypeFn fn;
ZigTypeBoundFn bound_fn;
ZigTypePromise promise;
+ ZigTypeVector vector;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
@@ -1385,6 +1423,7 @@ enum BuiltinFnId {
BuiltinFnIdEnumToInt,
BuiltinFnIdIntToEnum,
BuiltinFnIdIntType,
+ BuiltinFnIdVectorType,
BuiltinFnIdSetCold,
BuiltinFnIdSetRuntimeSafety,
BuiltinFnIdSetFloatMode,
@@ -1475,6 +1514,10 @@ struct TypeId {
ZigType *err_set_type;
ZigType *payload_type;
} error_union;
+ struct {
+ ZigType *elem_type;
+ uint32_t len;
+ } vector;
} data;
};
@@ -1610,7 +1653,7 @@ struct CodeGen {
HashMap fn_type_table;
HashMap error_table;
HashMap generic_table;
- HashMap memoized_fn_eval_table;
+ HashMap memoized_fn_eval_table;
HashMap llvm_fn_table;
HashMap exported_symbol_names;
HashMap external_prototypes;
@@ -1760,6 +1803,7 @@ struct CodeGen {
bool is_static;
bool strip_debug_symbols;
bool is_test_build;
+ bool is_single_threaded;
bool is_native_target;
bool linker_rdynamic;
bool no_rosegment_workaround;
@@ -1802,10 +1846,9 @@ enum VarLinkage {
struct ZigVar {
Buf name;
- ConstExprValue *value;
+ ConstExprValue *const_value;
+ ZigType *var_type;
LLVMValueRef value_ref;
- bool src_is_const;
- bool gen_is_const;
IrInstruction *is_comptime;
// which node is the declaration of the variable
AstNode *decl_node;
@@ -1815,17 +1858,21 @@ struct ZigVar {
Scope *parent_scope;
Scope *child_scope;
LLVMValueRef param_value_ref;
- bool shadowable;
size_t mem_slot_index;
IrExecutable *owner_exec;
size_t ref_count;
- VarLinkage linkage;
- uint32_t align_bytes;
// In an inline loop, multiple variables may be created,
// In this case, a reference to a variable should follow
// this pointer to the redefined variable.
ZigVar *next_var;
+
+ uint32_t align_bytes;
+ VarLinkage linkage;
+
+ bool shadowable;
+ bool src_is_const;
+ bool gen_is_const;
};
struct ErrorTableEntry {
@@ -1891,10 +1938,11 @@ struct ScopeBlock {
ZigList *incoming_values;
ZigList *incoming_blocks;
- bool safety_off;
AstNode *safety_set_node;
- bool fast_math_on;
AstNode *fast_math_set_node;
+
+ bool safety_off;
+ bool fast_math_on;
};
// This scope is created from every defer expression.
@@ -2030,8 +2078,19 @@ struct IrBasicBlock {
IrInstruction *must_be_comptime_source_instr;
};
+// These instructions are in transition to having "pass 1" instructions
+// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
+// and pass 2 are suffixed with Gen.
+// Once all instructions are separated in this way, they'll have different
+// base types for better type safety.
+// Src instructions are generated by ir_gen_* functions in ir.cpp from AST.
+// ir_analyze_* functions consume Src instructions and produce Gen instructions.
+// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
+// Src instructions do not have type information; Gen instructions do.
enum IrInstructionId {
IrInstructionIdInvalid,
+ IrInstructionIdDeclVarSrc,
+ IrInstructionIdDeclVarGen,
IrInstructionIdBr,
IrInstructionIdCondBr,
IrInstructionIdSwitchBr,
@@ -2040,7 +2099,6 @@ enum IrInstructionId {
IrInstructionIdPhi,
IrInstructionIdUnOp,
IrInstructionIdBinOp,
- IrInstructionIdDeclVar,
IrInstructionIdLoadPtr,
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
@@ -2069,7 +2127,7 @@ enum IrInstructionId {
IrInstructionIdAsm,
IrInstructionIdSizeOf,
IrInstructionIdTestNonNull,
- IrInstructionIdUnwrapOptional,
+ IrInstructionIdOptionalUnwrapPtr,
IrInstructionIdOptionalWrap,
IrInstructionIdUnionTag,
IrInstructionIdClz,
@@ -2085,7 +2143,8 @@ enum IrInstructionId {
IrInstructionIdCompileLog,
IrInstructionIdErrName,
IrInstructionIdEmbedFile,
- IrInstructionIdCmpxchg,
+ IrInstructionIdCmpxchgSrc,
+ IrInstructionIdCmpxchgGen,
IrInstructionIdFence,
IrInstructionIdTruncate,
IrInstructionIdIntCast,
@@ -2094,6 +2153,7 @@ enum IrInstructionId {
IrInstructionIdFloatToInt,
IrInstructionIdBoolToInt,
IrInstructionIdIntType,
+ IrInstructionIdVectorType,
IrInstructionIdBoolNot,
IrInstructionIdMemset,
IrInstructionIdMemcpy,
@@ -2114,7 +2174,8 @@ enum IrInstructionId {
IrInstructionIdErrWrapPayload,
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
- IrInstructionIdPtrCast,
+ IrInstructionIdPtrCastSrc,
+ IrInstructionIdPtrCastGen,
IrInstructionIdBitCast,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
@@ -2173,6 +2234,8 @@ enum IrInstructionId {
IrInstructionIdToBytes,
IrInstructionIdFromBytes,
IrInstructionIdCheckRuntimeScope,
+ IrInstructionIdVectorToArray,
+ IrInstructionIdArrayToVector,
};
struct IrInstruction {
@@ -2194,6 +2257,22 @@ struct IrInstruction {
bool is_gen;
};
+struct IrInstructionDeclVarSrc {
+ IrInstruction base;
+
+ ZigVar *var;
+ IrInstruction *var_type;
+ IrInstruction *align_value;
+ IrInstruction *init_value;
+};
+
+struct IrInstructionDeclVarGen {
+ IrInstruction base;
+
+ ZigVar *var;
+ IrInstruction *init_value;
+};
+
struct IrInstructionCondBr {
IrInstruction base;
@@ -2302,20 +2381,11 @@ struct IrInstructionBinOp {
IrInstruction base;
IrInstruction *op1;
+ IrInstruction *op2;
IrBinOp op_id;
- IrInstruction *op2;
bool safety_check_on;
};
-struct IrInstructionDeclVar {
- IrInstruction base;
-
- ZigVar *var;
- IrInstruction *var_type;
- IrInstruction *align_value;
- IrInstruction *init_value;
-};
-
struct IrInstructionLoadPtr {
IrInstruction base;
@@ -2335,7 +2405,6 @@ struct IrInstructionFieldPtr {
IrInstruction *container_ptr;
Buf *field_name_buffer;
IrInstruction *field_name_expr;
- bool is_const;
};
struct IrInstructionStructFieldPtr {
@@ -2378,13 +2447,13 @@ struct IrInstructionCall {
ZigFn *fn_entry;
size_t arg_count;
IrInstruction **args;
- bool is_comptime;
LLVMValueRef tmp_ptr;
- FnInline fn_inline;
- bool is_async;
IrInstruction *async_allocator;
IrInstruction *new_stack;
+ FnInline fn_inline;
+ bool is_async;
+ bool is_comptime;
};
struct IrInstructionConst {
@@ -2527,9 +2596,9 @@ struct IrInstructionSliceType {
IrInstruction base;
IrInstruction *align_value;
+ IrInstruction *child_type;
bool is_const;
bool is_volatile;
- IrInstruction *child_type;
};
struct IrInstructionAsm {
@@ -2557,10 +2626,12 @@ struct IrInstructionTestNonNull {
IrInstruction *value;
};
-struct IrInstructionUnwrapOptional {
+// Takes a pointer to an optional value, returns a pointer
+// to the payload.
+struct IrInstructionOptionalUnwrapPtr {
IrInstruction base;
- IrInstruction *value;
+ IrInstruction *base_ptr;
bool safety_check_on;
};
@@ -2651,7 +2722,7 @@ struct IrInstructionEmbedFile {
IrInstruction *name;
};
-struct IrInstructionCmpxchg {
+struct IrInstructionCmpxchgSrc {
IrInstruction base;
IrInstruction *type_value;
@@ -2661,14 +2732,19 @@ struct IrInstructionCmpxchg {
IrInstruction *success_order_value;
IrInstruction *failure_order_value;
- // if this instruction gets to runtime then we know these values:
- ZigType *type;
+ bool is_weak;
+};
+
+struct IrInstructionCmpxchgGen {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+ IrInstruction *cmp_value;
+ IrInstruction *new_value;
+ LLVMValueRef tmp_ptr;
AtomicOrder success_order;
AtomicOrder failure_order;
-
bool is_weak;
-
- LLVMValueRef tmp_ptr;
};
struct IrInstructionFence {
@@ -2748,6 +2824,13 @@ struct IrInstructionIntType {
IrInstruction *bit_count;
};
+struct IrInstructionVectorType {
+ IrInstruction base;
+
+ IrInstruction *len;
+ IrInstruction *elem_type;
+};
+
struct IrInstructionBoolNot {
IrInstruction base;
@@ -2851,7 +2934,7 @@ struct IrInstructionTestErr {
struct IrInstructionUnwrapErrCode {
IrInstruction base;
- IrInstruction *value;
+ IrInstruction *err_union;
};
struct IrInstructionUnwrapErrPayload {
@@ -2899,13 +2982,19 @@ struct IrInstructionTestComptime {
IrInstruction *value;
};
-struct IrInstructionPtrCast {
+struct IrInstructionPtrCastSrc {
IrInstruction base;
IrInstruction *dest_type;
IrInstruction *ptr;
};
+struct IrInstructionPtrCastGen {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+};
+
struct IrInstructionBitCast {
IrInstruction base;
@@ -3276,6 +3365,19 @@ struct IrInstructionBitReverse {
IrInstruction *op;
};
+struct IrInstructionArrayToVector {
+ IrInstruction base;
+
+ IrInstruction *array;
+};
+
+struct IrInstructionVectorToArray {
+ IrInstruction base;
+
+ IrInstruction *vector;
+ LLVMValueRef tmp_ptr;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 15370983fcb5409eaa77ef502601a83811a9304a..ff961a704448aa8b4bac7e13574b2a9fd47c14bd 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) {
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return nullptr;
}
zig_unreachable();
@@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return true;
}
zig_unreachable();
@@ -570,7 +572,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
if (child_type->zero_bits) {
entry->type_ref = LLVMInt1Type();
entry->di_type = g->builtin_types.entry_bool->di_type;
- } else if (type_is_codegen_pointer(child_type)) {
+ } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
assert(child_type->di_type);
// this is an optimization but also is necessary for calling C
// functions where all pointers are maybe pointers
@@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
}
if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
- if (abi_class == X64CABIClass_MEMORY) {
- return true;
- }
- zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481",
- buf_ptr(&fn_type_id->return_type->name));
+ return abi_class == X64CABIClass_MEMORY;
} else if (target_is_arm(&g->zig_target)) {
return type_size(g, fn_type_id->return_type) > 16;
}
@@ -1278,7 +1276,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
return entry;
}
-static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) {
+static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
+ Buf *type_name)
+{
size_t backward_branch_count = 0;
return ir_eval_const_value(g, scope, node, type_entry,
&backward_branch_count, default_backward_branch_quota,
@@ -1286,12 +1286,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
}
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
- IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
- if (result->value.type->id == ZigTypeIdInvalid)
+ ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
+ if (type_is_invalid(result->type))
return g->builtin_types.entry_invalid;
- assert(result->value.special != ConstValSpecialRuntime);
- return result->value.data.x_type;
+ assert(result->special != ConstValSpecialRuntime);
+ return result->data.x_type;
}
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
}
static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
- IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
- if (type_is_invalid(align_result->value.type))
+ ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
+ if (type_is_invalid(align_result->type))
return false;
- uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
+ uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint);
if (align_bytes == 0) {
add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
return false;
@@ -1364,12 +1364,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
PtrLenUnknown, 0, 0, 0);
ZigType *str_type = get_slice_type(g, ptr_type);
- IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
- if (type_is_invalid(instr->value.type))
+ ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr);
+ if (type_is_invalid(result_val->type))
return false;
- ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index];
- ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index];
+ ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index];
assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray);
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) {
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdFn:
+ case ZigTypeIdVector:
return true;
case ZigTypeIdStruct:
return type_entry->data.structure.layout == ContainerLayoutPacked;
@@ -1470,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
default:
return false;
}
+ case ZigTypeIdVector:
+ return type_allowed_in_extern(g, type_entry->data.vector.elem_type);
case ZigTypeIdFloat:
return true;
case ZigTypeIdArray:
@@ -1623,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
switch (type_requires_comptime(g, type_entry)) {
case ReqCompTimeNo:
break;
@@ -1718,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
switch (type_requires_comptime(g, fn_type_id.return_type)) {
case ReqCompTimeInvalid:
return g->builtin_types.entry_invalid;
@@ -2504,20 +2509,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
// In this first pass we resolve explicit tag values.
// In a second pass we will fill in the unspecified ones.
if (tag_value != nullptr) {
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (type_is_invalid(result->type)) {
enum_type->data.enumeration.is_invalid = true;
continue;
}
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == ZigTypeIdInt ||
- result_inst->value.type->id == ZigTypeIdComptimeInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ assert(result->special != ConstValSpecialRuntime);
+ assert(result->type->id == ZigTypeIdInt ||
+ result->type->id == ZigTypeIdComptimeInt);
+ auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
if (entry == nullptr) {
- bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
+ bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint);
} else {
Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+ bigint_append_buf(val_buf, &result->data.x_bigint, 10);
ErrorMsg *msg = add_node_error(g, tag_value,
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) {
// In a second pass we will fill in the unspecified ones.
if (tag_value != nullptr) {
ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type;
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (type_is_invalid(result->type)) {
union_type->data.unionation.is_invalid = true;
continue;
}
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == ZigTypeIdInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ assert(result->special != ConstValSpecialRuntime);
+ assert(result->type->id == ZigTypeIdInt);
+ auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
if (entry == nullptr) {
- bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+ bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint);
} else {
Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+ bigint_append_buf(val_buf, &result->data.x_bigint, 10);
ErrorMsg *msg = add_node_error(g, tag_value,
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) {
resolve_top_level_decl(g, tld, false, tld->source_node);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
- tld_var->var->value = value;
+ tld_var->var->const_value = value;
+ tld_var->var->var_type = value->type;
tld_var->var->align_bytes = get_abi_alignment(g, value->type);
}
@@ -3513,7 +3519,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeArrayType:
case NodeTypeErrorType:
case NodeTypeIfErrorExpr:
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
case NodeTypeErrorSetDecl:
case NodeTypeCancel:
case NodeTypeResume:
@@ -3574,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return type_entry;
}
zig_unreachable();
@@ -3582,13 +3589,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
// Set name to nullptr to make the variable anonymous (not visible to programmer).
// TODO merge with definition of add_local_var in ir.cpp
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
- bool is_const, ConstExprValue *value, Tld *src_tld)
+ bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type)
{
Error err;
- assert(value);
+ assert(const_value != nullptr);
+ assert(var_type != nullptr);
ZigVar *variable_entry = allocate(1);
- variable_entry->value = value;
+ variable_entry->const_value = const_value;
+ variable_entry->var_type = var_type;
variable_entry->parent_scope = parent_scope;
variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
@@ -3597,23 +3606,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
assert(name);
buf_init_from_buf(&variable_entry->name, name);
- if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) {
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) {
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
- variable_entry->align_bytes = get_abi_alignment(g, value->type);
+ variable_entry->align_bytes = get_abi_alignment(g, var_type);
ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr);
if (existing_var && !existing_var->shadowable) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
ZigType *type;
if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) {
add_node_error(g, source_node,
buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
Scope *search_scope = nullptr;
if (src_tld == nullptr) {
@@ -3627,7 +3636,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
}
}
}
@@ -3677,7 +3686,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
linkage = VarLinkageInternal;
}
- IrInstruction *init_value = nullptr;
+ ConstExprValue *init_value = nullptr;
// TODO more validation for types that can't be used for export/extern variables
ZigType *implicit_type = nullptr;
@@ -3686,7 +3695,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
} else if (var_decl->expr) {
init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
assert(init_value);
- implicit_type = init_value->value.type;
+ implicit_type = init_value->type;
if (implicit_type->id == ZigTypeIdUnreachable) {
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) {
add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
implicit_type = g->builtin_types.entry_invalid;
}
- assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime);
+ assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime);
} else if (linkage != VarLinkageExternal) {
add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
implicit_type = g->builtin_types.entry_invalid;
@@ -3713,19 +3722,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
ZigType *type = explicit_type ? explicit_type : implicit_type;
assert(type != nullptr); // should have been caught by the parser
- ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
+ ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type);
tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol,
- is_const, init_val, &tld_var->base);
+ is_const, init_val, &tld_var->base, type);
tld_var->var->linkage = linkage;
if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
- tld_var->var->value->type = g->builtin_types.entry_invalid;
+ tld_var->var->var_type = g->builtin_types.entry_invalid;
}
if (var_decl->align_expr != nullptr) {
if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) {
- tld_var->var->value->type = g->builtin_types.entry_invalid;
+ tld_var->var->var_type = g->builtin_types.entry_invalid;
}
}
@@ -3938,6 +3947,7 @@ static bool is_container(ZigType *type_entry) {
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return false;
}
zig_unreachable();
@@ -3997,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
zig_unreachable();
}
}
@@ -4090,7 +4101,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) {
}
ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
- param_name, true, create_const_runtime(param_type), nullptr);
+ param_name, true, create_const_runtime(param_type), nullptr, param_type);
var->src_arg_index = i;
fn_table_entry->child_scope = var->child_scope;
var->shadowable = var->shadowable || is_var_args;
@@ -4228,18 +4239,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
preview_use_decl(g, src_use_node);
}
- IrInstruction *use_target_value = src_use_node->data.use.value;
- if (use_target_value->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *use_target_value = src_use_node->data.use.value;
+ if (type_is_invalid(use_target_value->type)) {
dst_use_node->owner->any_imports_failed = true;
return;
}
dst_use_node->data.use.resolution = TldResolutionOk;
- ConstExprValue *const_val = &use_target_value->value;
- assert(const_val->special != ConstValSpecialRuntime);
+ assert(use_target_value->special != ConstValSpecialRuntime);
- ImportTableEntry *target_import = const_val->data.x_import;
+ ImportTableEntry *target_import = use_target_value->data.x_import;
assert(target_import);
if (target_import->any_imports_failed) {
@@ -4302,10 +4312,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
}
node->data.use.resolution = TldResolutionResolving;
- IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
+ ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,
node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
- if (result->value.type->id == ZigTypeIdInvalid)
+ if (type_is_invalid(result->type))
node->owner->any_imports_failed = true;
node->data.use.value = result;
@@ -4447,6 +4457,42 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
return new_entry;
}
+bool is_valid_vector_elem_type(ZigType *elem_type) {
+ return elem_type->id == ZigTypeIdInt ||
+ elem_type->id == ZigTypeIdFloat ||
+ get_codegen_ptr_type(elem_type) != nullptr;
+}
+
+ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
+ assert(is_valid_vector_elem_type(elem_type));
+
+ TypeId type_id = {};
+ type_id.id = ZigTypeIdVector;
+ type_id.data.vector.len = len;
+ type_id.data.vector.elem_type = elem_type;
+
+ {
+ auto entry = g->type_table.maybe_get(type_id);
+ if (entry)
+ return entry->value;
+ }
+
+ ZigType *entry = new_type_table_entry(ZigTypeIdVector);
+ entry->zero_bits = (len == 0) || !type_has_bits(elem_type);
+ entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len);
+ entry->data.vector.len = len;
+ entry->data.vector.elem_type = elem_type;
+
+ buf_resize(&entry->name, 0);
+ buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name));
+
+ entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len,
+ LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type);
+
+ g->type_table.put(type_id, entry);
+ return entry;
+}
+
ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) {
return &g->builtin_types.entry_c_int[c_int_type];
}
@@ -4478,6 +4524,7 @@ bool handle_is_ptr(ZigType *type_entry) {
case ZigTypeIdFn:
case ZigTypeIdEnum:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return false;
case ZigTypeIdArray:
case ZigTypeIdStruct:
@@ -4486,7 +4533,8 @@ bool handle_is_ptr(ZigType *type_entry) {
return type_has_bits(type_entry->data.error_union.payload_type);
case ZigTypeIdOptional:
return type_has_bits(type_entry->data.maybe.child_type) &&
- !type_is_codegen_pointer(type_entry->data.maybe.child_type);
+ !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&
+ type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
case ZigTypeIdUnion:
assert(type_entry->data.unionation.zero_bits_known);
if (type_entry->data.unionation.gen_field_count == 0)
@@ -4732,6 +4780,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
return true;
}
+static uint32_t hash_const_val_error_set(ConstExprValue *const_val) {
+ assert(const_val->data.x_err_set != nullptr);
+ return const_val->data.x_err_set->value ^ 2630160122;
+}
+
static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
uint32_t hash_val = 0;
switch (const_val->data.x_ptr.mut) {
@@ -4763,6 +4816,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
return hash_val;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ hash_val += (uint32_t)2994743799;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val);
+ return hash_val;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ hash_val += (uint32_t)3456080131;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val);
+ return hash_val;
+ case ConstPtrSpecialBaseOptionalPayload:
+ hash_val += (uint32_t)3163140517;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val);
+ return hash_val;
case ConstPtrSpecialHardCodedAddr:
hash_val += (uint32_t)4048518294;
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) {
hash_val += (uint32_t)2590901619;
hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
return hash_val;
+ case ConstPtrSpecialNull:
+ hash_val += (uint32_t)1486246455;
+ return hash_val;
}
zig_unreachable();
}
@@ -4872,7 +4940,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
return 2709806591;
case ZigTypeIdOptional:
if (get_codegen_ptr_type(const_val->type) != nullptr) {
- return hash_const_val(const_val) * 1992916303;
+ return hash_const_val_ptr(const_val) * 1992916303;
+ } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) {
+ return hash_const_val_error_set(const_val) * 3147031929;
} else {
if (const_val->data.x_optional) {
return hash_const_val(const_val->data.x_optional) * 1992916303;
@@ -4884,10 +4954,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
// TODO better hashing algorithm
return 3415065496;
case ZigTypeIdErrorSet:
- assert(const_val->data.x_err_set != nullptr);
- return const_val->data.x_err_set->value ^ 2630160122;
+ return hash_const_val_error_set(const_val);
case ZigTypeIdNamespace:
return hash_ptr(const_val->data.x_import);
+ case ZigTypeIdVector:
+ // TODO better hashing algorithm
+ return 3647867726;
case ZigTypeIdBoundFn:
case ZigTypeIdInvalid:
case ZigTypeIdUnreachable:
@@ -4940,6 +5012,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
case ZigTypeIdBool:
case ZigTypeIdUnreachable:
case ZigTypeIdInt:
+ case ZigTypeIdVector:
case ZigTypeIdFloat:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
@@ -4987,7 +5060,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
return can_mutate_comptime_var_state(value->data.x_optional);
case ZigTypeIdErrorUnion:
- if (value->data.x_err_union.err != nullptr)
+ if (value->data.x_err_union.error_set->data.x_err_set != nullptr)
return false;
assert(value->data.x_err_union.payload != nullptr);
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) {
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdPointer:
+ case ZigTypeIdVector:
return true;
case ZigTypeIdArray:
@@ -5048,9 +5122,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
- if (type_is_invalid(var_scope->var->value->type))
+ if (type_is_invalid(var_scope->var->var_type))
return false;
- if (can_mutate_comptime_var_state(var_scope->var->value))
+ if (can_mutate_comptime_var_state(var_scope->var->const_value))
return false;
} else if (scope->id == ScopeIdFnDef) {
return true;
@@ -5068,7 +5142,7 @@ uint32_t fn_eval_hash(Scope* scope) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
- result += hash_const_val(var_scope->var->value);
+ result += hash_const_val(var_scope->var->const_value);
} else if (scope->id == ScopeIdFnDef) {
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
result += hash_ptr(fn_scope->fn_entry);
@@ -5092,10 +5166,16 @@ bool fn_eval_eql(Scope *a, Scope *b) {
if (a->id == ScopeIdVarDecl) {
ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
- if (a_var_scope->var->value->type != b_var_scope->var->value->type)
- return false;
- if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value))
+ if (a_var_scope->var->var_type != b_var_scope->var->var_type)
return false;
+ if (a_var_scope->var->var_type == a_var_scope->var->const_value->type &&
+ b_var_scope->var->var_type == b_var_scope->var->const_value->type)
+ {
+ if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value))
+ return false;
+ } else {
+ zig_panic("TODO comptime ptr reinterpret for fn_eval_eql");
+ }
} else if (a->id == ScopeIdFnDef) {
ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
ScopeFnDef *b_fn_scope = (ScopeFnDef *)b;
@@ -5113,6 +5193,7 @@ bool fn_eval_eql(Scope *a, Scope *b) {
return false;
}
+// Whether the type has bits at runtime.
bool type_has_bits(ZigType *type_entry) {
assert(type_entry);
assert(!type_is_invalid(type_entry));
@@ -5120,6 +5201,66 @@ bool type_has_bits(ZigType *type_entry) {
return !type_entry->zero_bits;
}
+// Whether you can infer the value based solely on the type.
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
+ assert(type_entry != nullptr);
+ Error err;
+ if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
+ return OnePossibleValueInvalid;
+ switch (type_entry->id) {
+ case ZigTypeIdInvalid:
+ zig_unreachable();
+ case ZigTypeIdOpaque:
+ case ZigTypeIdComptimeFloat:
+ case ZigTypeIdComptimeInt:
+ case ZigTypeIdMetaType:
+ case ZigTypeIdNamespace:
+ case ZigTypeIdBoundFn:
+ case ZigTypeIdArgTuple:
+ case ZigTypeIdOptional:
+ case ZigTypeIdFn:
+ case ZigTypeIdBool:
+ case ZigTypeIdFloat:
+ case ZigTypeIdPromise:
+ case ZigTypeIdErrorUnion:
+ return OnePossibleValueNo;
+ case ZigTypeIdUndefined:
+ case ZigTypeIdNull:
+ case ZigTypeIdVoid:
+ case ZigTypeIdUnreachable:
+ return OnePossibleValueYes;
+ case ZigTypeIdArray:
+ if (type_entry->data.array.len == 0)
+ return OnePossibleValueYes;
+ return type_has_one_possible_value(g, type_entry->data.array.child_type);
+ case ZigTypeIdStruct:
+ for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
+ TypeStructField *field = &type_entry->data.structure.fields[i];
+ switch (type_has_one_possible_value(g, field->type_entry)) {
+ case OnePossibleValueInvalid:
+ return OnePossibleValueInvalid;
+ case OnePossibleValueNo:
+ return OnePossibleValueNo;
+ case OnePossibleValueYes:
+ continue;
+ }
+ }
+ return OnePossibleValueYes;
+ case ZigTypeIdErrorSet:
+ case ZigTypeIdEnum:
+ case ZigTypeIdInt:
+ case ZigTypeIdVector:
+ return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
+ case ZigTypeIdPointer:
+ return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
+ case ZigTypeIdUnion:
+ if (type_entry->data.unionation.src_field_count > 1)
+ return OnePossibleValueNo;
+ return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry);
+ }
+ zig_unreachable();
+}
+
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
@@ -5159,6 +5300,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdErrorSet:
case ZigTypeIdBool:
case ZigTypeIdInt:
+ case ZigTypeIdVector:
case ZigTypeIdFloat:
case ZigTypeIdVoid:
case ZigTypeIdUnreachable:
@@ -5574,6 +5716,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
return false;
return true;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ if (a->data.x_ptr.data.base_err_union_code.err_union_val !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val &&
+ a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ if (a->data.x_ptr.data.base_err_union_payload.err_union_val !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val &&
+ a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
+ case ConstPtrSpecialBaseOptionalPayload:
+ if (a->data.x_ptr.data.base_optional_payload.optional_val !=
+ b->data.x_ptr.data.base_optional_payload.optional_val &&
+ a->data.x_ptr.data.base_optional_payload.optional_val->global_refs !=
+ b->data.x_ptr.data.base_optional_payload.optional_val->global_refs)
+ {
+ return false;
+ }
+ return true;
case ConstPtrSpecialHardCodedAddr:
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
return false;
@@ -5582,10 +5751,34 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
return true;
case ConstPtrSpecialFunction:
return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
+ case ConstPtrSpecialNull:
+ return true;
}
zig_unreachable();
}
+static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprValue *b, size_t len) {
+ assert(a->data.x_array.special != ConstArraySpecialUndef);
+ assert(b->data.x_array.special != ConstArraySpecialUndef);
+ if (a->data.x_array.special == ConstArraySpecialBuf &&
+ b->data.x_array.special == ConstArraySpecialBuf)
+ {
+ return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf);
+ }
+ expand_undef_array(g, a);
+ expand_undef_array(g, b);
+
+ ConstExprValue *a_elems = a->data.x_array.data.s_none.elements;
+ ConstExprValue *b_elems = b->data.x_array.data.s_none.elements;
+
+ for (size_t i = 0; i < len; i += 1) {
+ if (!const_values_equal(g, &a_elems[i], &b_elems[i]))
+ return false;
+ }
+
+ return true;
+}
+
bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
assert(a->type->id == b->type->id);
assert(a->special == ConstValSpecialStatic);
@@ -5640,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
case ZigTypeIdPointer:
case ZigTypeIdFn:
return const_values_equal_ptr(a, b);
+ case ZigTypeIdVector:
+ assert(a->type->data.vector.len == b->type->data.vector.len);
+ return const_values_equal_array(g, a, b, a->type->data.vector.len);
case ZigTypeIdArray: {
assert(a->type->data.array.len == b->type->data.array.len);
- assert(a->data.x_array.special != ConstArraySpecialUndef);
- assert(b->data.x_array.special != ConstArraySpecialUndef);
- if (a->data.x_array.special == ConstArraySpecialBuf &&
- b->data.x_array.special == ConstArraySpecialBuf)
- {
- return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf);
- }
- expand_undef_array(g, a);
- expand_undef_array(g, b);
-
- size_t len = a->type->data.array.len;
- ConstExprValue *a_elems = a->data.x_array.data.s_none.elements;
- ConstExprValue *b_elems = b->data.x_array.data.s_none.elements;
-
- for (size_t i = 0; i < len; ++i) {
- if (!const_values_equal(g, &a_elems[i], &b_elems[i]))
- return false;
- }
-
- return true;
+ return const_values_equal_array(g, a, b, a->type->data.array.len);
}
case ZigTypeIdStruct:
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
}
}
-void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
assert(type_entry->id == ZigTypeIdPointer);
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
zig_unreachable();
case ConstPtrSpecialRef:
case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialBaseErrorUnionCode:
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ case ConstPtrSpecialBaseOptionalPayload:
buf_appendf(buf, "*");
// TODO we need a source node for const_ptr_pointee because it can generate compile errors
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
buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
return;
}
+ case ConstPtrSpecialNull:
+ buf_append_str(buf, "null");
+ return;
+ }
+ zig_unreachable();
+}
+
+static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+ if (const_val->data.x_err_set == nullptr) {
+ buf_append_str(buf, "null");
+ } else {
+ buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
+ }
+}
+
+static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) {
+ switch (const_val->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ buf_append_str(buf, "undefined");
+ return;
+ case ConstArraySpecialBuf: {
+ Buf *array_buf = const_val->data.x_array.data.s_buf;
+ buf_append_char(buf, '"');
+ for (size_t i = 0; i < buf_len(array_buf); i += 1) {
+ uint8_t c = buf_ptr(array_buf)[i];
+ if (c == '"') {
+ buf_append_str(buf, "\\\"");
+ } else {
+ buf_append_char(buf, c);
+ }
+ }
+ buf_append_char(buf, '"');
+ return;
+ }
+ case ConstArraySpecialNone: {
+ buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name));
+ for (uint64_t i = 0; i < len; i += 1) {
+ if (i != 0)
+ buf_appendf(buf, ",");
+ ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i];
+ render_const_value(g, buf, child_value);
+ }
+ buf_appendf(buf, "}");
+ return;
+ }
}
zig_unreachable();
}
@@ -5874,39 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
case ZigTypeIdPointer:
return render_const_val_ptr(g, buf, const_val, type_entry);
+ case ZigTypeIdVector:
+ return render_const_val_array(g, buf, const_val, type_entry->data.vector.len);
case ZigTypeIdArray:
- switch (const_val->data.x_array.special) {
- case ConstArraySpecialUndef:
- buf_append_str(buf, "undefined");
- return;
- case ConstArraySpecialBuf: {
- Buf *array_buf = const_val->data.x_array.data.s_buf;
- buf_append_char(buf, '"');
- for (size_t i = 0; i < buf_len(array_buf); i += 1) {
- uint8_t c = buf_ptr(array_buf)[i];
- if (c == '"') {
- buf_append_str(buf, "\\\"");
- } else {
- buf_append_char(buf, c);
- }
- }
- buf_append_char(buf, '"');
- return;
- }
- case ConstArraySpecialNone: {
- buf_appendf(buf, "%s{", buf_ptr(&type_entry->name));
- uint64_t len = type_entry->data.array.len;
- for (uint64_t i = 0; i < len; i += 1) {
- if (i != 0)
- buf_appendf(buf, ",");
- ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i];
- render_const_value(g, buf, child_value);
- }
- buf_appendf(buf, "}");
- return;
- }
- }
- zig_unreachable();
+ return render_const_val_array(g, buf, const_val, type_entry->data.array.len);
case ZigTypeIdNull:
{
buf_appendf(buf, "null");
@@ -5921,6 +6117,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
{
if (get_codegen_ptr_type(const_val->type) != nullptr)
return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
+ if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet)
+ return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type);
if (const_val->data.x_optional) {
render_const_value(g, buf, const_val->data.x_optional);
} else {
@@ -5958,11 +6156,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
case ZigTypeIdErrorUnion:
{
buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
- if (const_val->data.x_err_union.err == nullptr) {
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set == nullptr) {
render_const_value(g, buf, const_val->data.x_err_union.payload);
} else {
buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
- buf_ptr(&const_val->data.x_err_union.err->name));
+ buf_ptr(&err_set->name));
}
buf_appendf(buf, ")");
return;
@@ -5977,10 +6176,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
return;
}
case ZigTypeIdErrorSet:
- {
- buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
- return;
- }
+ return render_const_val_err_set(g, buf, const_val, type_entry);
case ZigTypeIdArgTuple:
{
buf_appendf(buf, "(args value)");
@@ -6065,6 +6261,8 @@ uint32_t type_id_hash(TypeId x) {
case ZigTypeIdInt:
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
(((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
+ case ZigTypeIdVector:
+ return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681);
}
zig_unreachable();
}
@@ -6113,6 +6311,9 @@ bool type_id_eql(TypeId a, TypeId b) {
case ZigTypeIdInt:
return a.data.integer.is_signed == b.data.integer.is_signed &&
a.data.integer.bit_count == b.data.integer.bit_count;
+ case ZigTypeIdVector:
+ return a.data.vector.elem_type == b.data.vector.elem_type &&
+ a.data.vector.len == b.data.vector.len;
}
zig_unreachable();
}
@@ -6171,24 +6372,34 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
// Canonicalize the array value as ConstArraySpecialNone
void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
- assert(const_val->type->id == ZigTypeIdArray);
+ size_t elem_count;
+ ZigType *elem_type;
+ if (const_val->type->id == ZigTypeIdArray) {
+ elem_count = const_val->type->data.array.len;
+ elem_type = const_val->type->data.array.child_type;
+ } else if (const_val->type->id == ZigTypeIdVector) {
+ elem_count = const_val->type->data.vector.len;
+ elem_type = const_val->type->data.vector.elem_type;
+ } else {
+ zig_unreachable();
+ }
+ if (const_val->special == ConstValSpecialUndef) {
+ const_val->special = ConstValSpecialStatic;
+ const_val->data.x_array.special = ConstArraySpecialUndef;
+ }
switch (const_val->data.x_array.special) {
case ConstArraySpecialNone:
return;
case ConstArraySpecialUndef: {
const_val->data.x_array.special = ConstArraySpecialNone;
- size_t elem_count = const_val->type->data.array.len;
const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count);
for (size_t i = 0; i < elem_count; i += 1) {
ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i];
- element_val->type = const_val->type->data.array.child_type;
+ element_val->type = elem_type;
init_const_undefined(g, element_val);
- ConstParent *parent = get_const_val_parent(g, element_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdArray;
- parent->data.p_array.array_val = const_val;
- parent->data.p_array.elem_index = i;
- }
+ element_val->parent.id = ConstParentIdArray;
+ element_val->parent.data.p_array.array_val = const_val;
+ element_val->parent.data.p_array.elem_index = i;
}
return;
}
@@ -6199,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
g->string_literals_table.maybe_remove(buf);
const_val->data.x_array.special = ConstArraySpecialNone;
- size_t elem_count = const_val->type->data.array.len;
assert(elem_count == buf_len(buf));
const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count);
for (size_t i = 0; i < elem_count; i += 1) {
@@ -6207,6 +6417,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
this_char->special = ConstValSpecialStatic;
this_char->type = g->builtin_types.entry_u8;
bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]);
+ this_char->parent.id = ConstParentIdArray;
+ this_char->parent.data.p_array.array_val = const_val;
+ this_char->parent.data.p_array.elem_index = i;
}
return;
}
@@ -6214,18 +6427,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
zig_unreachable();
}
+// Deprecated. Reference the parent field directly.
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
- assert(value->type);
- ZigType *type_entry = value->type;
- if (type_entry->id == ZigTypeIdArray) {
- expand_undef_array(g, value);
- return &value->data.x_array.data.s_none.parent;
- } else if (type_entry->id == ZigTypeIdStruct) {
- return &value->data.x_struct.parent;
- } else if (type_entry->id == ZigTypeIdUnion) {
- return &value->data.x_union.parent;
- }
- return nullptr;
+ return &value->parent;
}
static const ZigTypeId all_type_ids[] = {
@@ -6253,6 +6457,7 @@ static const ZigTypeId all_type_ids[] = {
ZigTypeIdArgTuple,
ZigTypeIdOpaque,
ZigTypeIdPromise,
+ ZigTypeIdVector,
};
ZigTypeId type_id_at_index(size_t index) {
@@ -6318,6 +6523,8 @@ size_t type_id_index(ZigType *entry) {
return 22;
case ZigTypeIdPromise:
return 23;
+ case ZigTypeIdVector:
+ return 24;
}
zig_unreachable();
}
@@ -6374,6 +6581,8 @@ const char *type_id_name(ZigTypeId id) {
return "Opaque";
case ZigTypeIdPromise:
return "Promise";
+ case ZigTypeIdVector:
+ return "Vector";
}
zig_unreachable();
}
@@ -6453,7 +6662,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
resolve_top_level_decl(codegen, tld, false, nullptr);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
- ConstExprValue *var_value = tld_var->var->value;
+ ConstExprValue *var_value = tld_var->var->const_value;
assert(var_value != nullptr);
return var_value;
}
@@ -6529,6 +6738,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
case ZigTypeIdBool:
return X64CABIClass_INTEGER;
case ZigTypeIdFloat:
+ case ZigTypeIdVector:
return X64CABIClass_SSE;
case ZigTypeIdStruct: {
// "If the size of an object is larger than four eightbytes, or it contains unaligned
diff --git a/src/analyze.hpp b/src/analyze.hpp
index efbc065a633aac92738d6b124ec04b72e08847f5..f558fa44b0647266cdce174f95658b3199117bf1 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
uint64_t type_size(CodeGen *g, ZigType *type_entry);
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
+ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type);
ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
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);
bool is_ref(ZigType *type_entry);
bool is_array_ref(ZigType *type_entry);
bool is_container_ref(ZigType *type_entry);
+bool is_valid_vector_elem_type(ZigType *elem_type);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
void scan_import(CodeGen *g, ImportTableEntry *import);
void preview_use_decl(CodeGen *g, AstNode *node);
@@ -81,7 +83,7 @@ ZigFn *scope_fn_entry(Scope *scope);
ImportTableEntry *get_scope_import(Scope *scope);
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
- bool is_const, ConstExprValue *init_value, Tld *src_tld);
+ bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
@@ -222,6 +224,13 @@ enum ReqCompTime {
};
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
+enum OnePossibleValue {
+ OnePossibleValueInvalid,
+ OnePossibleValueNo,
+ OnePossibleValueYes,
+};
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
+
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
ConstExprValue *const_val, ZigType *wanted_type);
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index f7eb646e16d7111d1899d0fd7a046cfdefebd535..994ba5f5b139fe32e884a69f7837784c3dddc5a5 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) {
return "ErrorType";
case NodeTypeIfErrorExpr:
return "IfErrorExpr";
- case NodeTypeTestExpr:
- return "TestExpr";
+ case NodeTypeIfOptional:
+ return "IfOptional";
case NodeTypeErrorSetDecl:
return "ErrorSetDecl";
case NodeTypeCancel:
@@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
if (node->data.if_err_expr.else_node)
return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
return node->data.if_err_expr.then_node->type == NodeTypeBlock;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
if (node->data.test_expr.else_node)
return statement_terminates_without_semicolon(node->data.test_expr.else_node);
return node->data.test_expr.then_node->type == NodeTypeBlock;
@@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
break;
}
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
{
fprintf(ar->f, "if (");
render_node_grouped(ar, node->data.test_expr.target_node);
diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp
index 5e6c3b9a9d50848435a071c3412dbe9d237c4b0a..4526a83c27023955b9137ed921aad44e8a0fdd73 100644
--- a/src/cache_hash.cpp
+++ b/src/cache_hash.cpp
@@ -222,14 +222,9 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents
assert(chf->path != nullptr);
OsFile this_file;
- if ((err = os_file_open_r(chf->path, &this_file)))
+ if ((err = os_file_open_r(chf->path, &this_file, &chf->mtime)))
return err;
- if ((err = os_file_mtime(this_file, &chf->mtime))) {
- os_file_close(this_file);
- return err;
- }
-
if ((err = hash_file(chf->bin_digest, this_file, contents))) {
os_file_close(this_file);
return err;
@@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
// if the mtime matches we can trust the digest
OsFile this_file;
- if ((err = os_file_open_r(chf->path, &this_file))) {
+ OsTimeStamp actual_mtime;
+ if ((err = os_file_open_r(chf->path, &this_file, &actual_mtime))) {
fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err));
os_file_close(ch->manifest_file);
return ErrorCacheUnavailable;
}
- OsTimeStamp actual_mtime;
- if ((err = os_file_mtime(this_file, &actual_mtime))) {
- os_file_close(this_file);
- os_file_close(ch->manifest_file);
- return err;
- }
if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) {
os_file_close(this_file);
} else {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index e180b69215013037a3dad65972f811da5d4b4679..1a70901cf07769519ce32007a43cded1d5223b2b 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -118,6 +118,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->string_literals_table.init(16);
g->type_info_cache.init(32);
g->is_test_build = false;
+ g->is_single_threaded = false;
buf_resize(&g->global_asm, 0);
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 *
static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name);
static void generate_error_name_table(CodeGen *g);
+static bool value_is_all_undef(ConstExprValue *const_val);
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr);
static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
@@ -461,6 +464,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag
}
}
+static bool cc_want_sret_attr(CallingConvention cc) {
+ switch (cc) {
+ case CallingConventionNaked:
+ zig_unreachable();
+ case CallingConventionC:
+ case CallingConventionCold:
+ case CallingConventionStdcall:
+ return true;
+ case CallingConventionAsync:
+ case CallingConventionUnspecified:
+ return false;
+ }
+ zig_unreachable();
+}
+
static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
@@ -598,9 +616,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
} else if (type_is_codegen_pointer(return_type)) {
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
- addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
- if (cc == CallingConventionC) {
+ addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
+ if (cc_want_sret_attr(cc)) {
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
}
init_gen_i = 1;
@@ -1903,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
}
static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
- assert(alignment > 0);
LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
- LLVMSetAlignment(result, alignment);
+ LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment);
return result;
}
@@ -1963,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
break;
}
- if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
+ if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector ||
ty->id == ZigTypeIdInt // TODO investigate if we need to change this
) {
switch (fn_walk->id) {
@@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
assert(variable);
assert(variable->value_ref);
- if (!handle_is_ptr(variable->value->type)) {
+ if (!handle_is_ptr(variable->var_type)) {
clear_debug_source_node(g);
- gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
- variable->align_bytes, false);
+ gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index),
+ variable->value_ref, variable->align_bytes, false);
}
if (variable->decl_node) {
@@ -2643,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
} else {
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
}
+ } else if (type_entry->id == ZigTypeIdVector) {
+ ZigType *elem_type = type_entry->data.vector.elem_type;
+ if (elem_type->id == ZigTypeIdFloat) {
+ ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
+ return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
+ } else if (elem_type->id == ZigTypeIdPointer) {
+ zig_panic("TODO codegen for pointers in vectors");
+ } else if (elem_type->id == ZigTypeIdInt) {
+ bool is_wrapping = (op_id == IrBinOpAddWrap);
+ if (is_wrapping) {
+ return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
+ } else if (want_runtime_safety) {
+ zig_panic("TODO runtime safety for vector integer addition");
+ } else if (elem_type->data.integral.is_signed) {
+ return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
+ } else {
+ return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
+ }
+ } else {
+ zig_unreachable();
+ }
} else {
zig_unreachable();
}
@@ -2961,7 +2999,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
}
static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionPtrCast *instruction)
+ IrInstructionPtrCastGen *instruction)
{
ZigType *wanted_type = instruction->base.value.type;
if (!type_has_bits(wanted_type)) {
@@ -3149,11 +3187,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
- IrInstructionDeclVar *decl_var_instruction)
+ IrInstructionDeclVarGen *decl_var_instruction)
{
ZigVar *var = decl_var_instruction->var;
- if (!type_has_bits(var->value->type))
+ if (!type_has_bits(var->var_type))
return nullptr;
if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
@@ -3161,34 +3199,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
IrInstruction *init_value = decl_var_instruction->init_value;
- bool have_init_expr = false;
-
- ConstExprValue *const_val = &init_value->value;
- if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
- have_init_expr = true;
+ bool have_init_expr = !value_is_all_undef(&init_value->value);
if (have_init_expr) {
- assert(var->value->type == init_value->value.type);
- ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
+ ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false,
PtrLenSingle, var->align_bytes, 0, 0);
LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
- } else {
- bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
- if (want_safe) {
- ZigType *usize = g->builtin_types.entry_usize;
- uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
- assert(size_bytes > 0);
-
- assert(var->align_bytes > 0);
-
- // memset uninitialized memory to 0xa
- LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
- LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, "");
- LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
- ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false);
- }
+ } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) {
+ uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes;
+ gen_undef_init(g, align_bytes, var->var_type, var->value_ref);
}
gen_var_debug_decl(g, var);
@@ -3225,21 +3245,81 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
}
+static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
+ switch (const_val->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ return true;
+ case ConstArraySpecialBuf:
+ return false;
+ case ConstArraySpecialNone:
+ for (size_t i = 0; i < len; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i]))
+ return false;
+ }
+ return true;
+ }
+ zig_unreachable();
+}
+
+static bool value_is_all_undef(ConstExprValue *const_val) {
+ switch (const_val->special) {
+ case ConstValSpecialRuntime:
+ return false;
+ case ConstValSpecialUndef:
+ return true;
+ case ConstValSpecialStatic:
+ if (const_val->type->id == ZigTypeIdStruct) {
+ for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_struct.fields[i]))
+ return false;
+ }
+ return true;
+ } else if (const_val->type->id == ZigTypeIdArray) {
+ return value_is_all_undef_array(const_val, const_val->type->data.array.len);
+ } else if (const_val->type->id == ZigTypeIdVector) {
+ return value_is_all_undef_array(const_val, const_val->type->data.vector.len);
+ } else {
+ return false;
+ }
+ }
+ zig_unreachable();
+}
+
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
+ assert(type_has_bits(value_type));
+ uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
+ assert(size_bytes > 0);
+ assert(ptr_align_bytes > 0);
+ // memset uninitialized memory to 0xaa
+ LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+ LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+ LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
+ ZigType *usize = g->builtin_types.entry_usize;
+ LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+ ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
+}
+
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
- LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
-
- assert(instruction->ptr->value.type->id == ZigTypeIdPointer);
ZigType *ptr_type = instruction->ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ if (!type_has_bits(ptr_type))
+ return nullptr;
- gen_assign_raw(g, ptr, ptr_type, value);
-
+ bool have_init_expr = !value_is_all_undef(&instruction->value->value);
+ if (have_init_expr) {
+ LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+ LLVMValueRef value = ir_llvm_value(g, instruction->value);
+ gen_assign_raw(g, ptr, ptr_type, value);
+ } else if (ir_want_runtime_safety(g, &instruction->base)) {
+ gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
+ ir_llvm_value(g, instruction->ptr));
+ }
return nullptr;
}
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
ZigVar *var = instruction->var;
- if (type_has_bits(var->value->type)) {
+ if (type_has_bits(var->var_type)) {
assert(var->value_ref);
return var->value_ref;
} else {
@@ -3553,7 +3633,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
- LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+ union_type->data.unionation.gen_union_index, "");
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
return bitcasted_union_field_ptr;
}
@@ -3715,8 +3796,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
if (child_type->zero_bits) {
return maybe_handle;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
} else {
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
return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
}
-static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
- IrInstructionUnwrapOptional *instruction)
+static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionOptionalUnwrapPtr *instruction)
{
- ZigType *ptr_type = instruction->value->value.type;
+ ZigType *ptr_type = instruction->base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == ZigTypeIdOptional);
ZigType *child_type = maybe_type->data.maybe.child_type;
- LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
+ LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr);
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
+ LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
@@ -3755,8 +3836,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
if (child_type->zero_bits) {
return nullptr;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return maybe_ptr;
} else {
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)
zig_unreachable();
}
-static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
+static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) {
LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
@@ -4189,18 +4270,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
assert(maybe_type->id == ZigTypeIdOptional);
ZigType *child_type = maybe_type->data.maybe.child_type;
- if (type_is_codegen_pointer(child_type)) {
+ if (!handle_is_ptr(maybe_type)) {
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
}
assert(instruction->tmp_ptr != nullptr);
- assert(type_has_bits(instruction->type));
+ assert(type_has_bits(child_type));
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
- gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
+ gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
@@ -4351,6 +4432,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
assert(array_type->data.structure.is_slice);
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
+ assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
assert(ptr_index != SIZE_MAX);
@@ -4540,12 +4622,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
}
-static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
- ZigType *ptr_type = instruction->value->value.type;
+static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnwrapErrCode *instruction)
+{
+ ZigType *ptr_type = instruction->err_union->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *err_union_type = ptr_type->data.pointer.child_type;
ZigType *payload_type = err_union_type->data.error_union.payload_type;
- LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
if (type_has_bits(payload_type)) {
@@ -4556,7 +4640,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
}
}
-static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
+static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on &&
+ g->errors_by_index.length > 1;
+ if (!want_safety && !type_has_bits(instruction->base.value.type))
+ return nullptr;
ZigType *ptr_type = instruction->value->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
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
return err_union_handle;
}
- if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
+ if (want_safety) {
LLVMValueRef err_val;
if (type_has_bits(payload_type)) {
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
}
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- if (type_is_codegen_pointer(child_type)) {
+ if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
return payload_val;
}
@@ -5109,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable,
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
+static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executable,
+ IrInstructionVectorToArray *instruction)
+{
+ ZigType *array_type = instruction->base.value.type;
+ assert(array_type->id == ZigTypeIdArray);
+ assert(handle_is_ptr(array_type));
+ assert(instruction->tmp_ptr);
+ LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
+ LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
+ LLVMPointerType(instruction->vector->value.type->type_ref, 0), "");
+ gen_store_untyped(g, vector, casted_ptr, 0, false);
+ return instruction->tmp_ptr;
+}
+
+static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable,
+ IrInstructionArrayToVector *instruction)
+{
+ ZigType *vector_type = instruction->base.value.type;
+ assert(vector_type->id == ZigTypeIdVector);
+ assert(!handle_is_ptr(vector_type));
+ LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
+ LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
+ LLVMPointerType(vector_type->type_ref, 0), "");
+ return gen_load_untyped(g, casted_ptr, 0, false, "");
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5148,6 +5264,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdCUndef:
case IrInstructionIdEmbedFile:
case IrInstructionIdIntType:
+ case IrInstructionIdVectorType:
case IrInstructionIdMemberCount:
case IrInstructionIdMemberType:
case IrInstructionIdMemberName:
@@ -5184,12 +5301,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
case IrInstructionIdCheckRuntimeScope:
+ case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdCmpxchgSrc:
zig_unreachable();
+ case IrInstructionIdDeclVarGen:
+ return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction);
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
- case IrInstructionIdDeclVar:
- return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
case IrInstructionIdCast:
@@ -5220,8 +5340,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNonNull:
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
- case IrInstructionIdUnwrapOptional:
- return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction);
case IrInstructionIdClz:
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -5236,8 +5356,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
case IrInstructionIdErrName:
return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgGen:
+ return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction);
case IrInstructionIdFence:
return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -5278,8 +5398,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
case IrInstructionIdUnionInit:
return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
- case IrInstructionIdPtrCast:
- return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastGen:
+ return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
case IrInstructionIdBitCast:
return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
case IrInstructionIdWidenOrShorten:
@@ -5350,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
case IrInstructionIdBitReverse:
return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction);
+ case IrInstructionIdArrayToVector:
+ return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);
+ case IrInstructionIdVectorToArray:
+ return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);
}
zig_unreachable();
}
@@ -5377,6 +5501,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -5387,6 +5514,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
case ConstParentIdStruct:
return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
parent->data.p_struct.field_index);
+ case ConstParentIdErrUnionCode:
+ return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
+ case ConstParentIdErrUnionPayload:
+ return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val);
+ case ConstParentIdOptionalPayload:
+ return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val);
case ConstParentIdArray:
return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
parent->data.p_array.elem_index);
@@ -5402,7 +5535,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) {
expand_undef_array(g, array_const_val);
- ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent;
+ ConstParent *parent = &array_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent);
LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr)));
@@ -5427,7 +5560,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
}
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) {
- ConstParent *parent = &struct_const_val->data.x_struct.parent;
+ ConstParent *parent = &struct_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent);
ZigType *u32 = g->builtin_types.entry_u32;
@@ -5438,8 +5571,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_err_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_payload_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) {
+ ConstParent *parent = &optional_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, maybe_child_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
- ConstParent *parent = &union_const_val->data.x_union.parent;
+ ConstParent *parent = &union_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
ZigType *u32 = g->builtin_types.entry_u32;
@@ -5509,6 +5678,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
}
case ZigTypeIdArray:
zig_panic("TODO bit pack an array");
+ case ZigTypeIdVector:
+ zig_panic("TODO bit pack a vector");
case ZigTypeIdUnion:
zig_panic("TODO bit pack a union");
case ZigTypeIdStruct:
@@ -5609,6 +5780,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
render_const_val_global(g, const_val, "");
return ptr_val;
}
+ case ConstPtrSpecialBaseErrorUnionCode:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialBaseOptionalPayload:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val;
+ assert(optional_const_val->type->id == ZigTypeIdOptional);
+ if (optional_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
case ConstPtrSpecialHardCodedAddr:
{
render_const_val_global(g, const_val, name);
@@ -5621,10 +5849,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
}
case ConstPtrSpecialFunction:
return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
+ case ConstPtrSpecialNull:
+ return LLVMConstNull(const_val->type->type_ref);
}
zig_unreachable();
}
+static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) {
+ uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value;
+ return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false);
+}
+
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
Error err;
@@ -5644,9 +5879,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
case ZigTypeIdInt:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
case ZigTypeIdErrorSet:
- assert(const_val->data.x_err_set != nullptr);
- return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
- const_val->data.x_err_set->value, false);
+ return gen_const_val_err_set(g, const_val, name);
case ZigTypeIdFloat:
switch (type_entry->data.floating.bit_count) {
case 16:
@@ -5680,6 +5913,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
} else if (type_is_codegen_pointer(child_type)) {
return gen_const_val_ptr(g, const_val, name);
+ } else if (child_type->id == ZigTypeIdErrorSet) {
+ return gen_const_val_err_set(g, const_val, name);
} else {
LLVMValueRef child_val;
LLVMValueRef maybe_val;
@@ -5816,7 +6051,33 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true);
}
}
+ zig_unreachable();
}
+ case ZigTypeIdVector: {
+ uint32_t len = type_entry->data.vector.len;
+ switch (const_val->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ return LLVMGetUndef(type_entry->type_ref);
+ case ConstArraySpecialNone: {
+ LLVMValueRef *values = allocate(len);
+ for (uint64_t i = 0; i < len; i += 1) {
+ ConstExprValue *elem_value = &const_val->data.x_array.data.s_none.elements[i];
+ values[i] = gen_const_val(g, elem_value, "");
+ }
+ return LLVMConstVector(values, len);
+ }
+ case ConstArraySpecialBuf: {
+ Buf *buf = const_val->data.x_array.data.s_buf;
+ assert(buf_len(buf) == len);
+ LLVMValueRef *values = allocate(len);
+ for (uint64_t i = 0; i < len; i += 1) {
+ values[i] = LLVMConstInt(g->builtin_types.entry_u8->type_ref, buf_ptr(buf)[i], false);
+ }
+ return LLVMConstVector(values, len);
+ }
+ }
+ zig_unreachable();
+ }
case ZigTypeIdUnion:
{
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
ZigType *err_set_type = type_entry->data.error_union.err_set_type;
if (!type_has_bits(payload_type)) {
assert(type_has_bits(err_set_type));
- uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ uint64_t value = (err_set == nullptr) ? 0 : err_set->value;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
} else if (!type_has_bits(err_set_type)) {
assert(type_has_bits(payload_type));
@@ -5923,8 +6185,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
LLVMValueRef err_tag_value;
LLVMValueRef err_payload_value;
bool make_unnamed_struct;
- if (const_val->data.x_err_union.err) {
- err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set != nullptr) {
+ err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false);
err_payload_value = LLVMConstNull(payload_type->type_ref);
make_unnamed_struct = false;
} else {
@@ -6130,10 +6393,13 @@ static void do_code_gen(CodeGen *g) {
TldVar *tld_var = g->global_vars.at(i);
ZigVar *var = tld_var->var;
- if (var->value->type->id == ZigTypeIdComptimeFloat) {
+ if (var->var_type->id == ZigTypeIdComptimeFloat) {
// Generate debug info for it but that's it.
- ConstExprValue *const_val = var->value;
+ ConstExprValue *const_val = var->const_value;
assert(const_val->special != ConstValSpecialRuntime);
+ if (const_val->type != var->var_type) {
+ zig_panic("TODO debug info for var with ptr casted value");
+ }
ZigType *var_type = g->builtin_types.entry_f128;
ConstExprValue coerced_value;
coerced_value.special = ConstValSpecialStatic;
@@ -6144,10 +6410,13 @@ static void do_code_gen(CodeGen *g) {
continue;
}
- if (var->value->type->id == ZigTypeIdComptimeInt) {
+ if (var->var_type->id == ZigTypeIdComptimeInt) {
// Generate debug info for it but that's it.
- ConstExprValue *const_val = var->value;
+ ConstExprValue *const_val = var->const_value;
assert(const_val->special != ConstValSpecialRuntime);
+ if (const_val->type != var->var_type) {
+ zig_panic("TODO debug info for var with ptr casted value");
+ }
size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint);
if (bits_needed < 8) {
bits_needed = 8;
@@ -6158,7 +6427,7 @@ static void do_code_gen(CodeGen *g) {
continue;
}
- if (!type_has_bits(var->value->type))
+ if (!type_has_bits(var->var_type))
continue;
assert(var->decl_node);
@@ -6167,9 +6436,9 @@ static void do_code_gen(CodeGen *g) {
if (var->linkage == VarLinkageExternal) {
LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name));
if (existing_llvm_var) {
- global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0));
+ global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0));
} else {
- global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name));
+ global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6180,9 +6449,9 @@ static void do_code_gen(CodeGen *g) {
} else {
bool exported = (var->linkage == VarLinkageExport);
const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
- render_const_val(g, var->value, mangled_name);
- render_const_val_global(g, var->value, mangled_name);
- global_value = var->value->global_refs->llvm_global;
+ render_const_val(g, var->const_value, mangled_name);
+ render_const_val_global(g, var->const_value, mangled_name);
+ global_value = var->const_value->global_refs->llvm_global;
if (exported) {
LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6194,8 +6463,10 @@ static void do_code_gen(CodeGen *g) {
LLVMSetAlignment(global_value, var->align_bytes);
// TODO debug info for function pointers
- if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) {
- gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type);
+ // Here we use const_value->type because that's the type of the llvm global,
+ // which we const ptr cast upon use to whatever it needs to be.
+ if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) {
+ gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type);
}
LLVMSetGlobalConstant(global_value, var->gen_is_const);
@@ -6249,6 +6520,7 @@ static void do_code_gen(CodeGen *g) {
IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
LLVMValueRef *slot;
ZigType *slot_type = instruction->value.type;
+ uint32_t alignment_bytes = 0;
if (instruction->id == IrInstructionIdCast) {
IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction;
slot = &cast_instruction->tmp_ptr;
@@ -6281,13 +6553,17 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdErrWrapCode) {
IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
slot = &err_wrap_code_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdCmpxchg) {
- IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
+ } else if (instruction->id == IrInstructionIdCmpxchgGen) {
+ IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction;
slot = &cmpxchg_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdVectorToArray) {
+ IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
+ alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);
+ slot = &vector_to_array_instruction->tmp_ptr;
} else {
zig_unreachable();
}
- *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
+ *slot = build_alloca(g, slot_type, "", alignment_bytes);
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
@@ -6304,12 +6580,12 @@ static void do_code_gen(CodeGen *g) {
for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
ZigVar *var = fn_table_entry->variable_list.at(var_i);
- if (!type_has_bits(var->value->type)) {
+ if (!type_has_bits(var->var_type)) {
continue;
}
if (ir_get_var_is_comptime(var))
continue;
- switch (type_requires_comptime(g, var->value->type)) {
+ switch (type_requires_comptime(g, var->var_type)) {
case ReqCompTimeInvalid:
zig_unreachable();
case ReqCompTimeYes:
@@ -6319,11 +6595,11 @@ static void do_code_gen(CodeGen *g) {
}
if (var->src_arg_index == SIZE_MAX) {
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
+ var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
- var->value->type->di_type, !g->strip_debug_symbols, 0);
+ var->var_type->di_type, !g->strip_debug_symbols, 0);
} else if (is_c_abi) {
fn_walk_var.data.vars.var = var;
@@ -6333,16 +6609,16 @@ static void do_code_gen(CodeGen *g) {
ZigType *gen_type;
FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
- if (handle_is_ptr(var->value->type)) {
+ if (handle_is_ptr(var->var_type)) {
if (gen_info->is_byval) {
- gen_type = var->value->type;
+ gen_type = var->var_type;
} else {
gen_type = gen_info->type;
}
var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index);
} else {
- gen_type = var->value->type;
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
+ gen_type = var->var_type;
+ var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
}
if (var->decl_node) {
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) {
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
+ create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
@@ -6967,6 +7244,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" ArgTuple: void,\n"
" Opaque: void,\n"
" Promise: Promise,\n"
+ " Vector: Vector,\n"
"\n\n"
" pub const Int = struct {\n"
" is_signed: bool,\n"
@@ -7085,6 +7363,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" child: ?type,\n"
" };\n"
"\n"
+ " pub const Vector = struct {\n"
+ " len: u32,\n"
+ " child: type,\n"
+ " };\n"
+ "\n"
" pub const Definition = struct {\n"
" name: []const u8,\n"
" is_pub: bool,\n"
@@ -7153,6 +7436,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
buf_appendf(contents, "pub const endian = %s;\n", endian_str);
}
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
+ buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);
@@ -7187,6 +7471,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_buf(&cache_hash, compiler_id);
cache_int(&cache_hash, g->build_mode);
cache_bool(&cache_hash, g->is_test_build);
+ cache_bool(&cache_hash, g->is_single_threaded);
cache_int(&cache_hash, g->zig_target.arch.arch);
cache_int(&cache_hash, g->zig_target.arch.sub_arch);
cache_int(&cache_hash, g->zig_target.vendor);
@@ -7458,9 +7743,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i];
this_val->special = ConstValSpecialStatic;
this_val->type = struct_type;
- this_val->data.x_struct.parent.id = ConstParentIdArray;
- this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array;
- this_val->data.x_struct.parent.data.p_array.elem_index = i;
+ this_val->parent.id = ConstParentIdArray;
+ this_val->parent.data.p_array.array_val = test_fn_array;
+ this_val->parent.data.p_array.elem_index = i;
this_val->data.x_struct.fields = create_const_vals(2);
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
case ZigTypeIdArray:
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
return;
+ case ZigTypeIdVector:
+ prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type);
+ return;
case ZigTypeIdOptional:
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
return;
@@ -7787,6 +8075,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
buf_appendf(out_buf, "%s", buf_ptr(child_buf));
return;
}
+ case ZigTypeIdVector:
+ zig_panic("TODO implement get_c_type for vector types");
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
@@ -7952,6 +8242,7 @@ static void gen_h_file(CodeGen *g) {
case ZigTypeIdOptional:
case ZigTypeIdFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
zig_unreachable();
case ZigTypeIdEnum:
if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
@@ -8099,6 +8390,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_bool(ch, g->is_static);
cache_bool(ch, g->strip_debug_symbols);
cache_bool(ch, g->is_test_build);
+ cache_bool(ch, g->is_single_threaded);
cache_bool(ch, g->is_native_target);
cache_bool(ch, g->linker_rdynamic);
cache_bool(ch, g->no_rosegment_workaround);
diff --git a/src/ir.cpp b/src/ir.cpp
index c651f30dd54f41ba963a0bb6ca9945f7d5b75db4..3cbbdc810307581a0ca990285fee5b8da1e49885 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -167,6 +167,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
ZigType *dest_type, IrInstruction *dest_type_src);
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs);
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align);
+static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -178,15 +180,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
case ConstPtrSpecialRef:
result = const_val->data.x_ptr.data.ref.pointee;
break;
- case ConstPtrSpecialBaseArray:
- expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val);
- result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[
- const_val->data.x_ptr.data.base_array.elem_index];
+ case ConstPtrSpecialBaseArray: {
+ ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
+ expand_undef_array(g, array_val);
+ result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
break;
+ }
case ConstPtrSpecialBaseStruct:
result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
const_val->data.x_ptr.data.base_struct.field_index];
break;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
+ break;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload;
+ break;
+ case ConstPtrSpecialBaseOptionalPayload:
+ result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional;
+ break;
+ case ConstPtrSpecialNull:
+ result = const_val;
+ break;
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialDiscard:
@@ -198,6 +213,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
return result;
}
+static bool is_opt_err_set(ZigType *ty) {
+ return ty->id == ZigTypeIdErrorSet ||
+ (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet);
+}
+
static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (a == b)
return true;
@@ -208,15 +228,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
return true;
- return false;
-}
+ if (is_opt_err_set(a) && is_opt_err_set(b))
+ return true;
-ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
- ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val);
- if (const_val->type->id == ZigTypeIdPointer) {
- assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type));
- }
- return result;
+ return false;
}
static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
@@ -305,6 +320,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
return new_bb;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) {
+ return IrInstructionIdDeclVarSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) {
+ return IrInstructionIdDeclVarGen;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
return IrInstructionIdCondBr;
}
@@ -337,10 +360,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) {
return IrInstructionIdBinOp;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) {
- return IrInstructionIdDeclVar;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
return IrInstructionIdExport;
}
@@ -449,8 +468,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
return IrInstructionIdTestNonNull;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) {
- return IrInstructionIdUnwrapOptional;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) {
+ return IrInstructionIdOptionalUnwrapPtr;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) {
@@ -517,8 +536,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
return IrInstructionIdEmbedFile;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
- return IrInstructionIdCmpxchg;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) {
+ return IrInstructionIdCmpxchgSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) {
+ return IrInstructionIdCmpxchgGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
@@ -565,6 +588,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) {
return IrInstructionIdIntType;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) {
+ return IrInstructionIdVectorType;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
return IrInstructionIdBoolNot;
}
@@ -649,8 +676,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
return IrInstructionIdTestComptime;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
- return IrInstructionIdPtrCast;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) {
+ return IrInstructionIdPtrCastSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
+ return IrInstructionIdPtrCastGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
@@ -869,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop
return IrInstructionIdCheckRuntimeScope;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorToArray *) {
+ return IrInstructionIdVectorToArray;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) {
+ return IrInstructionIdArrayToVector;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -915,7 +954,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
ir_ref_instruction(condition, irb->current_basic_block);
ir_ref_bb(then_block);
ir_ref_bb(else_block);
- if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
+ if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block);
return &cond_br_instruction->base;
}
@@ -931,16 +970,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou
return &return_instruction->base;
}
-static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *type_entry)
-{
- assert(type_entry);
- IrInstructionConst *const_instruction = ir_create_instruction(irb, scope, source_node);
- const_instruction->base.value.type = type_entry;
- const_instruction->base.value.special = ConstValSpecialStatic;
- return &const_instruction->base;
-}
-
static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node);
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
call_instruction->async_allocator = async_allocator;
call_instruction->new_stack = new_stack;
- if (fn_ref)
- ir_ref_instruction(fn_ref, irb->current_basic_block);
+ if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
for (size_t i = 0; i < arg_count; i += 1)
ir_ref_instruction(args[i], irb->current_basic_block);
- if (async_allocator)
- ir_ref_instruction(async_allocator, irb->current_basic_block);
- if (new_stack != nullptr)
- ir_ref_instruction(new_stack, irb->current_basic_block);
+ if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
+ if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
return &call_instruction->base;
}
@@ -1280,7 +1306,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope,
container_init_list_instruction->item_count = item_count;
container_init_list_instruction->items = items;
- ir_ref_instruction(container_type, irb->current_basic_block);
+ if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block);
for (size_t i = 0; i < item_count; i += 1) {
ir_ref_instruction(items[i], irb->current_basic_block);
}
@@ -1355,10 +1381,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
{
- IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
decl_var_instruction->base.value.special = ConstValSpecialStatic;
decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
decl_var_instruction->var = var;
@@ -1366,13 +1392,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s
decl_var_instruction->align_value = align_value;
decl_var_instruction->init_value = init_value;
- if (var_type) ir_ref_instruction(var_type, irb->current_basic_block);
- if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
+ if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block);
+ if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
ir_ref_instruction(init_value, irb->current_basic_block);
return &decl_var_instruction->base;
}
+static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+ ZigVar *var, IrInstruction *init_value)
+{
+ IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ decl_var_instruction->base.value.special = ConstValSpecialStatic;
+ decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void;
+ decl_var_instruction->var = var;
+ decl_var_instruction->init_value = init_value;
+
+ ir_ref_instruction(init_value, ira->new_irb.current_basic_block);
+
+ return &decl_var_instruction->base;
+}
+
static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *name, IrInstruction *target, IrInstruction *linkage)
{
@@ -1542,14 +1583,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
-static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
- bool safety_check_on)
+static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *base_ptr, bool safety_check_on)
{
- IrInstructionUnwrapOptional *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->value = value;
+ IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->base_ptr = base_ptr;
instruction->safety_check_on = safety_check_on;
- ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(base_ptr, irb->current_basic_block);
return &instruction->base;
}
@@ -1765,13 +1806,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
- IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
IrInstruction *success_order_value, IrInstruction *failure_order_value,
- bool is_weak,
- ZigType *type, AtomicOrder success_order, AtomicOrder failure_order)
+ bool is_weak)
{
- IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type_value = type_value;
instruction->ptr = ptr;
instruction->cmp_value = cmp_value;
@@ -1779,16 +1819,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so
instruction->success_order_value = success_order_value;
instruction->failure_order_value = failure_order_value;
instruction->is_weak = is_weak;
- instruction->type = type;
- instruction->success_order = success_order;
- instruction->failure_order = failure_order;
- if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
+ ir_ref_instruction(type_value, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(cmp_value, irb->current_basic_block);
ir_ref_instruction(new_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
+ ir_ref_instruction(success_order_value, irb->current_basic_block);
+ ir_ref_instruction(failure_order_value, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+ AtomicOrder success_order, AtomicOrder failure_order, bool is_weak)
+{
+ IrInstructionCmpxchgGen *instruction = ir_build_instruction(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->ptr = ptr;
+ instruction->cmp_value = cmp_value;
+ instruction->new_value = new_value;
+ instruction->success_order = success_order;
+ instruction->failure_order = failure_order;
+ instruction->is_weak = is_weak;
+
+ ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+ ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block);
+ ir_ref_instruction(new_value, ira->new_irb.current_basic_block);
return &instruction->base;
}
@@ -1909,6 +1966,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s
return &instruction->base;
}
+static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *len,
+ IrInstruction *elem_type)
+{
+ IrInstructionVectorType *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->len = len;
+ instruction->elem_type = elem_type;
+
+ ir_ref_instruction(len, irb->current_basic_block);
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
IrInstructionBoolNot *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
@@ -2060,12 +2130,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s
}
static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *value)
+ IrInstruction *err_union)
{
IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->value = value;
+ instruction->err_union = err_union;
- ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(err_union, irb->current_basic_block);
return &instruction->base;
}
@@ -2115,20 +2185,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *ptr)
{
- IrInstructionPtrCast *instruction = ir_build_instruction(
+ IrInstructionPtrCastSrc *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->dest_type = dest_type;
instruction->ptr = ptr;
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
+ ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
return &instruction->base;
}
+static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+ ZigType *ptr_type, IrInstruction *ptr)
+{
+ IrInstructionPtrCastGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = ptr_type;
+ instruction->ptr = ptr;
+
+ ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *value)
{
@@ -2747,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
+static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *vector, ZigType *result_type)
+{
+ IrInstructionVectorToArray *instruction = ir_build_instruction(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = result_type;
+ instruction->vector = vector;
+
+ ir_ref_instruction(vector, ira->new_irb.current_basic_block);
+
+ ir_add_alloca(ira, &instruction->base, result_type);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *array, ZigType *result_type)
+{
+ IrInstructionArrayToVector *instruction = ir_build_instruction(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = result_type;
+ instruction->array = array;
+
+ ir_ref_instruction(array, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -2807,10 +2918,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
if (defer_expr_value != irb->codegen->invalid_instruction) {
- if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) {
+ if (defer_expr_value->value.type != nullptr &&
+ defer_expr_value->value.type->id == ZigTypeIdUnreachable)
+ {
is_noreturn = true;
} else {
- ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
+ ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node,
+ defer_expr_value));
}
}
}
@@ -3065,7 +3179,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->is_comptime = is_comptime;
variable_entry->src_arg_index = SIZE_MAX;
- variable_entry->value = create_const_vals(1);
+ variable_entry->const_value = create_const_vals(1);
if (is_comptime != nullptr) {
is_comptime->ref_count += 1;
@@ -3080,20 +3194,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
} else {
ZigType *type;
if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) {
add_node_error(codegen, node,
buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
} else {
Tld *tld = find_decl(codegen, parent_scope, name);
if (tld != nullptr) {
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
}
}
}
@@ -3156,7 +3270,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
- scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
+ scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
+ ir_should_inline(irb->exec, parent_scope));
}
bool is_continuation_unreachable = false;
@@ -3174,9 +3289,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
// defer starts a new scope
child_scope = statement_node->data.defer.child_scope;
assert(child_scope);
- } else if (statement_value->id == IrInstructionIdDeclVar) {
+ } else if (statement_value->id == IrInstructionIdDeclVarSrc) {
// variable declarations start a new scope
- IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
+ IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value;
child_scope = decl_var_instruction->var->child_scope;
} else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) {
// this statement's value must be void
@@ -3331,7 +3446,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
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
ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, ok_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false);
+ IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false);
IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
IrBasicBlock *after_ok_block = irb->current_basic_block;
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)
case BinOpTypeMergeErrorSets:
return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
case BinOpTypeUnwrapOptional:
- return ir_gen_maybe_ok_or(irb, scope, node);
+ return ir_gen_orelse(irb, scope, node);
case BinOpTypeErrorUnion:
return ir_gen_error_union(irb, scope, node);
}
@@ -3542,6 +3657,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
buf_ptr(variable_name)));
return irb->codegen->invalid_instruction;
}
+ assert(err == ErrorPrimitiveTypeNotFound);
} else {
IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
if (lval == LValPtr) {
@@ -3904,9 +4020,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg5_value == irb->codegen->invalid_instruction)
return arg5_value;
- IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
- arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
- nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
+ IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value,
+ arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak));
return ir_lval_wrap(irb, scope, cmpxchg, lval);
}
case BuiltinFnIdFence:
@@ -4169,6 +4284,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
return ir_lval_wrap(irb, scope, int_type, lval);
}
+ case BuiltinFnIdVectorType:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value);
+ return ir_lval_wrap(irb, scope, vector_type, lval);
+ }
case BuiltinFnIdMemcpy:
{
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
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value);
return ir_lval_wrap(irb, scope, ptr_cast, lval);
}
case BuiltinFnIdBitCast:
@@ -4784,7 +4914,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
}
}
- IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
+ IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
+ is_async, async_allocator, nullptr);
return ir_lval_wrap(irb, scope, fn_call, lval);
}
@@ -4793,7 +4924,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope);
if (condition == irb->codegen->invalid_instruction)
- return condition;
+ return irb->codegen->invalid_instruction;
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, scope)) {
@@ -4816,7 +4947,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope);
if (then_expr_result == irb->codegen->invalid_instruction)
- return then_expr_result;
+ return irb->codegen->invalid_instruction;
IrBasicBlock *after_then_block = irb->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
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
if (else_node) {
else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
if (else_expr_result == irb->codegen->invalid_instruction)
- return else_expr_result;
+ return irb->codegen->invalid_instruction;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
@@ -4927,7 +5058,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
ptr_len, align_value, bit_offset_start, host_int_bytes);
}
-static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
+static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
LVal lval)
{
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
ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
is_const, is_const, is_shadowable, is_comptime);
- // we detect IrInstructionIdDeclVar in gen_block to make sure the next node
+ // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node
// is inside var->child_scope
if (!is_extern && !variable_declaration->expr) {
- var->value->type = irb->codegen->builtin_types.entry_invalid;
+ var->var_type = irb->codegen->builtin_types.entry_invalid;
add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized"));
return irb->codegen->invalid_instruction;
}
@@ -5084,7 +5215,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
if (init_value == irb->codegen->invalid_instruction)
return init_value;
- return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
+ return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value);
}
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
err_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
}
ZigList incoming_values = {0};
@@ -5180,7 +5311,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
true, false, false, is_comptime);
Scope *err_scope = err_var->child_scope;
IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
- ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
+ ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
if (else_result == irb->codegen->invalid_instruction)
@@ -5220,10 +5351,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
+ IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5380,7 +5511,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
Scope *child_scope = elem_var->child_scope;
IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
- ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
+ ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
AstNode *index_var_source_node;
@@ -5398,7 +5529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
- ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
+ ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
@@ -5622,8 +5753,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
}
-static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
- assert(node->type == NodeTypeTestExpr);
+static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+ assert(node->type == NodeTypeIfOptional);
Buf *var_symbol = node->data.test_expr.var_symbol;
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
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
+ IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
@@ -5738,7 +5869,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
@@ -5763,7 +5894,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
err_symbol, is_const, is_const, is_shadowable, is_comptime);
IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
err_var_scope = var->child_scope;
} else {
err_var_scope = subexpr_scope;
@@ -5818,7 +5949,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
}
IrInstruction *var_type = nullptr; // infer the type
- ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
+ ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
} else {
child_scope = scope;
}
@@ -6228,7 +6359,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true);
}
-static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
assert(node->type == NodeTypeUnwrapErrorExpr);
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
add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name)));
return irb->codegen->invalid_instruction;
}
- return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
+ return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone);
}
@@ -6276,7 +6407,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
- ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
+ ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
} else {
err_scope = parent_scope;
}
@@ -6312,7 +6443,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope;
if (need_comma)
buf_append_char(name, ',');
- render_const_value(codegen, name, var_scope->var->value);
+ // TODO: const ptr reinterpret here to make the var type agree with the value?
+ render_const_value(codegen, name, var_scope->var->const_value);
return true;
}
@@ -6562,7 +6694,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
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
get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
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
IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
- ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
+ ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
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
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
+ IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true);
if (lval == LValPtr)
return unwrapped_ptr;
@@ -7074,8 +7206,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
case NodeTypeIfErrorExpr:
return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval);
- case NodeTypeTestExpr:
- return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval);
+ case NodeTypeIfOptional:
+ return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval);
case NodeTypeSwitchExpr:
return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval);
case NodeTypeCompTime:
@@ -7093,7 +7225,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSliceExpr:
return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
case NodeTypeUnwrapErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval);
case NodeTypeContainerDecl:
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
@@ -7152,6 +7284,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_ref_bb(irb->current_basic_block);
ZigFn *fn_entry = exec_fn_entry(irb->exec);
+
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
IrInstruction *coro_id;
IrInstruction *u8_ptr_type;
@@ -7172,27 +7305,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
- ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
+ ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
- ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
+ ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
- IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
+ IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
- ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
+ ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
ImplicitAllocatorIdArg);
irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
- ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
+ ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
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
ir_build_return(irb, coro_scope, node, undef);
ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
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
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
- IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
- IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
+ IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
+ IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
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
// Before we destroy the coroutine frame, we need to load the target promise into
// a register or local variable which does not get spilled into the frame,
// otherwise llvm tries to access memory inside the destroyed frame.
- IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
+ IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
irb->exec->await_handle_var_ptr, false);
IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
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
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
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
return val;
}
-static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
+static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
IrBasicBlock *bb = exec->basic_block_list.at(0);
for (size_t i = 0; i < bb->instruction_list.length; i += 1) {
IrInstruction *instruction = bb->instruction_list.at(i);
@@ -7445,16 +7578,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec)
if (value->value.special == ConstValSpecialRuntime) {
exec_add_error_node(codegen, exec, value->source_node,
buf_sprintf("unable to evaluate constant expression"));
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
- return value;
+ return &value->value;
} else if (ir_has_side_effects(instruction)) {
exec_add_error_node(codegen, exec, instruction->source_node,
buf_sprintf("unable to evaluate constant expression"));
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
}
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
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
bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt);
bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat);
+ assert(const_val_is_int || const_val_is_float);
if (other_type->id == ZigTypeIdFloat) {
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
size_t errors_count = 0;
ZigType *err_set_type = nullptr;
if (prev_inst->value.type->id == ZigTypeIdErrorSet) {
+ if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
if (type_is_global_error_set(prev_inst->value.type)) {
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
} else {
err_set_type = prev_inst->value.type;
- if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
update_errors_helper(ira->codegen, &errors, &errors_count);
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
if (prev_type->id == ZigTypeIdArray) {
convert_to_const_slice = true;
}
+ if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
if (type_is_global_error_set(cur_type)) {
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
continue;
@@ -8940,9 +9077,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
continue;
}
- if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
update_errors_helper(ira->codegen, &errors, &errors_count);
@@ -9432,14 +9566,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
}
return true;
}
+
+static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
+ IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
+ old_instruction->scope, old_instruction->source_node);
+ IrInstruction *new_instruction = &const_instruction->base;
+ new_instruction->value.type = ty;
+ new_instruction->value.special = ConstValSpecialStatic;
+ return new_instruction;
+}
+
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type, CastOp cast_op, bool need_alloca)
{
if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
cast_op != CastOpResizeSlice)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
&result->value, wanted_type))
{
@@ -9476,9 +9619,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.type = wanted_type;
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
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
assert(is_slice(wanted_type));
bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
value->value.data.x_ptr.mut;
@@ -9653,15 +9793,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction)
return instruction;
}
-static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
- IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
- old_instruction->scope, old_instruction->source_node);
- IrInstruction *new_instruction = &const_instruction->base;
- new_instruction->value.type = ty;
- new_instruction->value.special = ConstValSpecialStatic;
- return new_instruction;
-}
-
static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) {
IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type);
result->value.data.x_type = ty;
@@ -9719,13 +9850,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
zig_unreachable();
}
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec)
{
if (expected_type != nullptr && type_is_invalid(expected_type))
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
IrExecutable *ir_executable = allocate(1);
ir_executable->source_node = source_node;
@@ -9738,13 +9869,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
ir_gen(codegen, node, scope, ir_executable);
if (ir_executable->invalid)
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
if (codegen->verbose_ir) {
fprintf(stderr, "\nSource: ");
ast_render(codegen, stderr, node, 4);
fprintf(stderr, "\n{ // (IR)\n");
- ir_print(codegen, stderr, ir_executable, 4);
+ ir_print(codegen, stderr, ir_executable, 2);
fprintf(stderr, "}\n");
}
IrExecutable *analyzed_executable = allocate(1);
@@ -9760,11 +9891,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
analyzed_executable->begin_scope = scope;
ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
if (type_is_invalid(result_type))
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
if (codegen->verbose_ir) {
fprintf(stderr, "{ // (analyzed)\n");
- ir_print(codegen, stderr, analyzed_executable, 4);
+ ir_print(codegen, stderr, analyzed_executable, 2);
fprintf(stderr, "}\n");
}
@@ -9789,6 +9920,34 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
return const_val->data.x_type;
}
+static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, IrInstruction *op_source, IrInstruction *type_value) {
+ if (type_is_invalid(type_value->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (type_value->value.type->id != ZigTypeIdMetaType) {
+ ErrorMsg *msg = ir_add_error(ira, type_value,
+ buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value.type->name)));
+ add_error_note(ira->codegen, msg, op_source->source_node,
+ buf_sprintf("`||` merges error sets; `or` performs boolean OR"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad);
+ if (!const_val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ assert(const_val->data.x_type != nullptr);
+ ZigType *result_type = const_val->data.x_type;
+ if (result_type->id != ZigTypeIdErrorSet) {
+ ErrorMsg *msg = ir_add_error(ira, type_value,
+ buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name)));
+ add_error_note(ira->codegen, msg, op_source->source_node,
+ buf_sprintf("`||` merges error sets; `or` performs boolean OR"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ return result_type;
+}
+
static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
if (fn_value == ira->codegen->invalid_instruction)
return nullptr;
@@ -9810,7 +9969,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
return const_val->data.x_ptr.data.fn.fn_entry;
}
-static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) {
+static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ ZigType *wanted_type)
+{
assert(wanted_type->id == ZigTypeIdOptional);
if (instr_is_comptime(value)) {
@@ -9826,7 +9987,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.special = ConstValSpecialStatic;
- if (get_codegen_ptr_type(wanted_type) != nullptr) {
+ if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) {
copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
} else {
const_instruction->base.value.data.x_optional = val;
@@ -9857,11 +10018,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->data.x_err_set = nullptr;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = nullptr;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = val;
return &const_instruction->base;
}
@@ -9926,11 +10092,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->data.x_err_set = val->data.x_err_set;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = nullptr;
return &const_instruction->base;
}
@@ -9952,8 +10123,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node);
const_instruction->base.value.special = ConstValSpecialStatic;
if (get_codegen_ptr_type(wanted_type) != nullptr) {
- const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
- const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0;
+ const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull;
+ } else if (is_opt_err_set(wanted_type)) {
+ const_instruction->base.value.data.x_err_set = nullptr;
} else {
const_instruction->base.value.data.x_optional = nullptr;
}
@@ -9986,7 +10158,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
source_instruction->source_node, value, is_const, is_volatile);
new_instruction->value.type = ptr_type;
new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
- if (type_has_bits(ptr_type)) {
+ if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) {
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
assert(fn_entry);
fn_entry->alloca_list.append(new_instruction);
@@ -10012,20 +10184,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
ZigType *array_type = array->value.type;
assert(array_type->id == ZigTypeIdArray);
- if (instr_is_comptime(array)) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ if (instr_is_comptime(array) || array_type->data.array.len == 0) {
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true);
result->value.type = wanted_type;
return result;
}
- IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+ IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
init_const_usize(ira->codegen, &start->value, 0);
- IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+ IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
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
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
return result;
}
@@ -10075,8 +10243,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
actual_type->data.enumeration.src_field_count == 1)
{
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type,
&actual_type->data.enumeration.fields[0].value);
return result;
@@ -10099,8 +10266,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
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
if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
wanted_type->data.enumeration.src_field_count == 1)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
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
static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, ZigType *wanted_type)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_undefined(ira->codegen, &result->value);
return result;
}
@@ -10162,8 +10326,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
buf_sprintf("field '%s' declared here", buf_ptr(union_field->name)));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
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
return ira->codegen->invalid_instruction;
}
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
if (wanted_type->id == ZigTypeIdInt) {
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
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
return result;
}
@@ -10292,8 +10453,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (wanted_type->id == ZigTypeIdComptimeFloat) {
float_init_float(&result->value, val);
} else if (wanted_type->id == ZigTypeIdComptimeInt) {
@@ -10316,8 +10476,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
@@ -10381,12 +10540,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
ErrorTableEntry *err;
if (err_type->id == ZigTypeIdErrorUnion) {
- err = val->data.x_err_union.err;
+ err = val->data.x_err_union.error_set->data.x_err_set;
} else if (err_type->id == ZigTypeIdErrorSet) {
err = val->data.x_err_set;
} else {
@@ -10421,15 +10579,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
return ira->codegen->invalid_instruction;
}
if (err_set_type->data.error_set.err_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.type = wanted_type;
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
bigint_init_unsigned(&result->value.data.x_bigint, 0);
return result;
} else if (err_set_type->data.error_set.err_count == 1) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.type = wanted_type;
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
bigint_init_unsigned(&result->value.data.x_bigint, err->value);
return result;
@@ -10476,8 +10630,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
array_val->type = array_type;
array_val->data.x_array.special = ConstArraySpecialNone;
array_val->data.x_array.data.s_none.elements = pointee;
- array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar;
- array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee;
+ array_val->parent.id = ConstParentIdScalar;
+ array_val->parent.data.p_scalar.scalar_val = pointee;
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
@@ -10598,6 +10752,32 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
}
}
+static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *array, ZigType *vector_type)
+{
+ if (instr_is_comptime(array)) {
+ // arrays and vectors have the same ConstExprValue representation
+ IrInstruction *result = ir_const(ira, source_instr, vector_type);
+ copy_const_val(&result->value, &array->value, false);
+ result->value.type = vector_type;
+ return result;
+ }
+ return ir_build_array_to_vector(ira, source_instr, array, vector_type);
+}
+
+static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *vector, ZigType *array_type)
+{
+ if (instr_is_comptime(vector)) {
+ // arrays and vectors have the same ConstExprValue representation
+ IrInstruction *result = ir_const(ira, source_instr, array_type);
+ copy_const_val(&result->value, &vector->value, false);
+ result->value.type = array_type;
+ return result;
+ }
+ return ir_build_vector_to_array(ira, source_instr, vector, array_type);
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
ZigType *wanted_type, IrInstruction *value)
{
@@ -10625,12 +10805,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
false).id == ConstCastResultIdOk)
{
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else if (actual_type->id == ZigTypeIdComptimeInt ||
actual_type->id == ZigTypeIdComptimeFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
}
@@ -10654,7 +10834,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_child_type);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
- return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type);
}
}
}
@@ -10707,6 +10887,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt ||
wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat))
{
+ if (value->value.special == ConstValSpecialUndef) {
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
+ result->value.special = ConstValSpecialUndef;
+ return result;
+ }
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
@@ -10760,6 +10945,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// cast from [N]T to []const T
+ // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) {
ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == ZigTypeIdPointer);
@@ -10772,6 +10958,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
// cast from [N]T to ?[]const T
+ // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
if (wanted_type->id == ZigTypeIdOptional &&
is_slice(wanted_type->data.maybe.child_type) &&
actual_type->id == ZigTypeIdArray)
@@ -10866,7 +11053,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // cast from error set to error union type
+ // cast from E to E!T
if (wanted_type->id == ZigTypeIdErrorUnion &&
actual_type->id == ZigTypeIdErrorSet)
{
@@ -10979,6 +11166,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
+ // cast from @Vector(N, T) to [N]T
+ if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector &&
+ wanted_type->data.array.len == actual_type->data.vector.len &&
+ types_match_const_cast_only(ira, wanted_type->data.array.child_type,
+ actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type);
+ }
+
+ // cast from [N]T to @Vector(N, T)
+ if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector &&
+ actual_type->data.array.len == wanted_type->data.vector.len &&
+ types_match_const_cast_only(ira, actual_type->data.array.child_type,
+ wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type);
+ }
// cast from undefined to anything
if (actual_type->id == ZigTypeIdUndefined) {
@@ -11018,8 +11222,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
ZigType *child_type = type_entry->data.pointer.child_type;
// dereferencing a *u0 is comptime known to be 0
if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
init_const_unsigned_negative(&result->value, child_type, 0, false);
return result;
}
@@ -11033,8 +11236,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
{
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
&ptr->value)))
@@ -11046,7 +11248,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
}
}
- // TODO if the instruction is a const ref instruction we can skip it
+ // if the instruction is a const ref instruction we can skip it
+ if (ptr->id == IrInstructionIdRef) {
+ IrInstructionRef *ref_inst = reinterpret_cast(ptr);
+ return ref_inst->value;
+ }
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
source_instruction->source_node, ptr);
load_ptr_instruction->value.type = child_type;
@@ -11293,8 +11499,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) {
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
- // TODO determine if we need to use copy_const_val here
- result->value = instruction->base.value;
+ copy_const_val(&result->value, &instruction->base.value, true);
return result;
}
@@ -11369,6 +11574,8 @@ static bool optional_value_is_null(ConstExprValue *val) {
if (get_codegen_ptr_type(val->type) != nullptr) {
return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
val->data.x_ptr.data.hard_coded_addr.addr == 0;
+ } else if (is_opt_err_set(val->type)) {
+ return val->data.x_err_set == nullptr;
} else {
return val->data.x_optional == nullptr;
}
@@ -11523,6 +11730,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
case ZigTypeIdComptimeInt:
case ZigTypeIdInt:
case ZigTypeIdFloat:
+ case ZigTypeIdVector:
operator_allowed = true;
break;
@@ -11568,19 +11776,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
if (casted_op2 == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
- bool requires_comptime;
- switch (type_requires_comptime(ira->codegen, resolved_type)) {
- case ReqCompTimeYes:
- requires_comptime = true;
- break;
- case ReqCompTimeNo:
- requires_comptime = false;
- break;
- case ReqCompTimeInvalid:
+ bool one_possible_value;
+ switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+ case OnePossibleValueInvalid:
return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ one_possible_value = true;
+ break;
+ case OnePossibleValueNo:
+ one_possible_value = false;
+ break;
}
- bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type);
if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
if (op1_val == nullptr)
@@ -11654,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
return result;
}
-static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val,
- IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val)
+static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry,
+ ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val)
{
bool is_int;
bool is_float;
@@ -11677,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val,
if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod ||
op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ)
{
- return ErrorDivByZero;
+ return ir_add_error(ira, source_instr, buf_sprintf("division by zero"));
}
if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) {
- return ErrorNegativeDenominator;
+ return ir_add_error(ira, source_instr, buf_sprintf("negative denominator"));
}
switch (op_id) {
@@ -11726,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val,
BigInt orig_bigint;
bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint);
if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) {
- return ErrorShiftedOutOneBits;
+ return ir_add_error(ira, source_instr, buf_sprintf("exact shift shifted out 1 bits"));
}
break;
}
@@ -11794,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val,
BigInt remainder;
bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
if (bigint_cmp_zero(&remainder) != CmpEQ) {
- return ErrorExactDivRemainder;
+ return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder"));
}
} else {
float_div_trunc(out_val, op1_val, op2_val);
ConstExprValue remainder;
float_rem(&remainder, op1_val, op2_val);
if (float_cmp_zero(&remainder) != CmpEQ) {
- return ErrorExactDivRemainder;
+ return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder"));
}
}
break;
@@ -11825,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val,
if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count,
type_entry->data.integral.is_signed))
{
- return ErrorOverflow;
+ return ir_add_error(ira, source_instr, buf_sprintf("operation caused overflow"));
}
}
out_val->type = type_entry;
out_val->special = ConstValSpecialStatic;
- return 0;
+ return nullptr;
+}
+
+// This works on operands that have already been checked to be comptime known.
+static IrInstruction *ir_analyze_math_op(IrAnalyze *ira, IrInstruction *source_instr,
+ ZigType *type_entry, ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val)
+{
+ IrInstruction *result_instruction = ir_const(ira, source_instr, type_entry);
+ ConstExprValue *out_val = &result_instruction->value;
+ if (type_entry->id == ZigTypeIdVector) {
+ expand_undef_array(ira->codegen, op1_val);
+ expand_undef_array(ira->codegen, op2_val);
+ out_val->special = ConstValSpecialUndef;
+ expand_undef_array(ira->codegen, out_val);
+ size_t len = type_entry->data.vector.len;
+ ZigType *scalar_type = type_entry->data.vector.elem_type;
+ for (size_t i = 0; i < len; i += 1) {
+ ConstExprValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i];
+ ConstExprValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i];
+ ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
+ assert(scalar_op1_val->type == scalar_type);
+ assert(scalar_op2_val->type == scalar_type);
+ assert(scalar_out_val->type == scalar_type);
+ ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,
+ scalar_op1_val, op_id, scalar_op2_val, scalar_out_val);
+ if (msg != nullptr) {
+ add_error_note(ira->codegen, msg, source_instr->source_node,
+ buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i));
+ return ira->codegen->invalid_instruction;
+ }
+ }
+ out_val->type = type_entry;
+ out_val->special = ConstValSpecialStatic;
+ } else {
+ if (ir_eval_math_op_scalar(ira, source_instr, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+ return ir_implicit_cast(ira, result_instruction, type_entry);
}
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
if (op2_val == nullptr)
return ira->codegen->invalid_instruction;
- IrInstruction *result_instruction = ir_const(ira, &bin_op_instruction->base, op1->value.type);
-
- int err;
- if ((err = ir_eval_math_op(op1->value.type, op1_val, op_id, op2_val, &result_instruction->value))) {
- if (err == ErrorOverflow) {
- ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow"));
- return ira->codegen->invalid_instruction;
- } else if (err == ErrorShiftedOutOneBits) {
- ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits"));
- return ira->codegen->invalid_instruction;
- } else {
- zig_unreachable();
- }
- return ira->codegen->invalid_instruction;
- }
-
- ir_num_lit_fits_in_other_type(ira, result_instruction, op1->value.type, false);
- return result_instruction;
+ return ir_analyze_math_op(ira, &bin_op_instruction->base, op1->value.type, op1_val, op_id, op2_val);
} else if (op1->value.type->id == ZigTypeIdComptimeInt) {
ir_add_error(ira, &bin_op_instruction->base,
buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known"));
@@ -11939,6 +12167,48 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b
return result;
}
+static bool ok_float_op(IrBinOp op) {
+ switch (op) {
+ case IrBinOpInvalid:
+ zig_unreachable();
+ case IrBinOpAdd:
+ case IrBinOpSub:
+ case IrBinOpMult:
+ case IrBinOpDivUnspecified:
+ case IrBinOpDivTrunc:
+ case IrBinOpDivFloor:
+ case IrBinOpDivExact:
+ case IrBinOpRemRem:
+ case IrBinOpRemMod:
+ return true;
+
+ case IrBinOpBoolOr:
+ case IrBinOpBoolAnd:
+ case IrBinOpCmpEq:
+ case IrBinOpCmpNotEq:
+ case IrBinOpCmpLessThan:
+ case IrBinOpCmpGreaterThan:
+ case IrBinOpCmpLessOrEq:
+ case IrBinOpCmpGreaterOrEq:
+ case IrBinOpBinOr:
+ case IrBinOpBinXor:
+ case IrBinOpBinAnd:
+ case IrBinOpBitShiftLeftLossy:
+ case IrBinOpBitShiftLeftExact:
+ case IrBinOpBitShiftRightLossy:
+ case IrBinOpBitShiftRightExact:
+ case IrBinOpAddWrap:
+ case IrBinOpSubWrap:
+ case IrBinOpMultWrap:
+ case IrBinOpRemUnspecified:
+ case IrBinOpArrayCat:
+ case IrBinOpArrayMult:
+ case IrBinOpMergeErrorSets:
+ return false;
+ }
+ zig_unreachable();
+}
+
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
IrInstruction *op1 = instruction->op1->child;
if (type_is_invalid(op1->value.type))
@@ -12076,21 +12346,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
op_id = IrBinOpRemRem;
}
+ bool ok = false;
if (is_int) {
- // int
- } else if (is_float &&
- (op_id == IrBinOpAdd ||
- op_id == IrBinOpSub ||
- op_id == IrBinOpMult ||
- op_id == IrBinOpDivUnspecified ||
- op_id == IrBinOpDivTrunc ||
- op_id == IrBinOpDivFloor ||
- op_id == IrBinOpDivExact ||
- op_id == IrBinOpRemRem ||
- op_id == IrBinOpRemMod))
- {
- // float
- } else {
+ ok = true;
+ } else if (is_float && ok_float_op(op_id)) {
+ ok = true;
+ } else if (resolved_type->id == ZigTypeIdVector) {
+ ZigType *elem_type = resolved_type->data.vector.elem_type;
+ if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) {
+ ok = true;
+ } else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) {
+ ok = true;
+ }
+ }
+ if (!ok) {
AstNode *source_node = instruction->base.source_node;
ir_add_error_node(ira, source_node,
buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
@@ -12125,30 +12394,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
if (op2_val == nullptr)
return ira->codegen->invalid_instruction;
- IrInstruction *result_instruction = ir_const(ira, &instruction->base, resolved_type);
-
- int err;
- if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, &result_instruction->value))) {
- if (err == ErrorDivByZero) {
- ir_add_error(ira, &instruction->base, buf_sprintf("division by zero"));
- return ira->codegen->invalid_instruction;
- } else if (err == ErrorOverflow) {
- ir_add_error(ira, &instruction->base, buf_sprintf("operation caused overflow"));
- return ira->codegen->invalid_instruction;
- } else if (err == ErrorExactDivRemainder) {
- ir_add_error(ira, &instruction->base, buf_sprintf("exact division had a remainder"));
- return ira->codegen->invalid_instruction;
- } else if (err == ErrorNegativeDenominator) {
- ir_add_error(ira, &instruction->base, buf_sprintf("negative denominator"));
- return ira->codegen->invalid_instruction;
- } else {
- zig_unreachable();
- }
- return ira->codegen->invalid_instruction;
- }
-
- ir_num_lit_fits_in_other_type(ira, result_instruction, resolved_type, false);
- return result_instruction;
+ return ir_analyze_math_op(ira, &instruction->base, resolved_type, op1_val, op_id, op2_val);
}
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
op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val;
op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index];
- op1_array_end = bigint_as_unsigned(&len_val->data.x_bigint);
+ op1_array_end = op1_array_index + bigint_as_unsigned(&len_val->data.x_bigint);
} else {
ir_add_error(ira, op1,
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
ConstExprValue *op2_array_val;
size_t op2_array_index;
size_t op2_array_end;
+ bool op2_type_valid;
if (op2_type->id == ZigTypeIdArray) {
- if (op2_type->data.array.child_type != child_type) {
- ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
- buf_ptr(&child_type->name),
- buf_ptr(&op2->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
+ op2_type_valid = op2_type->data.array.child_type == child_type;
op2_array_val = op2_val;
op2_array_index = 0;
op2_array_end = op2_array_val->type->data.array.len;
@@ -12227,35 +12469,30 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray &&
op2_val->data.x_ptr.data.base_array.is_cstr)
{
- if (child_type != ira->codegen->builtin_types.entry_u8) {
- ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
- buf_ptr(&child_type->name),
- buf_ptr(&op2->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
+ op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8;
op2_array_val = op2_val->data.x_ptr.data.base_array.array_val;
op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index;
op2_array_end = op2_array_val->type->data.array.len - 1;
} else if (is_slice(op2_type)) {
ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry;
- if (ptr_type->data.pointer.child_type != child_type) {
- ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
- buf_ptr(&child_type->name),
- buf_ptr(&op2->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
+ op2_type_valid = ptr_type->data.pointer.child_type == child_type;
ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index];
assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray);
op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val;
op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
- op2_array_end = op2_array_val->type->data.array.len;
ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index];
- op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint);
+ op2_array_end = op2_array_index + bigint_as_unsigned(&len_val->data.x_bigint);
} else {
ir_add_error(ira, op2,
buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name)));
return ira->codegen->invalid_instruction;
}
+ if (!op2_type_valid) {
+ ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
+ buf_ptr(&child_type->name),
+ buf_ptr(&op2->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
// The type of result is populated in the following if blocks
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
@@ -12388,26 +12625,14 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
}
static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) {
- ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child);
+ ZigType *op1_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op1->child);
if (type_is_invalid(op1_type))
return ira->codegen->invalid_instruction;
- if (op1_type->id != ZigTypeIdErrorSet) {
- ir_add_error(ira, instruction->op1,
- buf_sprintf("expected error set type, found '%s'", buf_ptr(&op1_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child);
+ ZigType *op2_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op2->child);
if (type_is_invalid(op2_type))
return ira->codegen->invalid_instruction;
- if (op2_type->id != ZigTypeIdErrorSet) {
- ir_add_error(ira, instruction->op2,
- buf_sprintf("expected error set type, found '%s'", buf_ptr(&op2_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
if (type_is_global_error_set(op1_type) ||
type_is_global_error_set(op2_type))
{
@@ -12481,13 +12706,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
+static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
+ IrInstructionDeclVarSrc *decl_var_instruction)
+{
Error err;
ZigVar *var = decl_var_instruction->var;
IrInstruction *init_value = decl_var_instruction->init_value->child;
if (type_is_invalid(init_value->value.type)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ira->codegen->invalid_instruction;
}
@@ -12498,7 +12725,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
ZigType *proposed_type = ir_resolve_type(ira, var_type);
explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
if (type_is_invalid(explicit_type)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ira->codegen->invalid_instruction;
}
}
@@ -12523,7 +12750,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
case ReqCompTimeInvalid:
result_type = ira->codegen->builtin_types.entry_invalid;
break;
- case ReqCompTimeYes: {
+ case ReqCompTimeYes:
var_class_requires_const = true;
if (!var->gen_is_const && !is_comptime_var) {
ir_add_error_node(ira, source_node,
@@ -12532,7 +12759,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
- }
case ReqCompTimeNo:
if (casted_init_value->value.special == ConstValSpecialStatic &&
casted_init_value->value.type->id == ZigTypeIdFn &&
@@ -12551,7 +12777,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
break;
}
- if (var->value->type != nullptr && !is_comptime_var) {
+ if (var->var_type != nullptr && !is_comptime_var) {
// This is at least the second time we've seen this variable declaration during analysis.
// This means that this is actually a different variable due to, e.g. an inline while loop.
// 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
// This must be done after possibly creating a new variable above
var->ref_count = 0;
- var->value->type = result_type;
- assert(var->value->type);
+ var->var_type = result_type;
+ assert(var->var_type);
if (type_is_invalid(result_type)) {
return ir_const_void(ira, &decl_var_instruction->base);
@@ -12582,13 +12808,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
if (decl_var_instruction->align_value == nullptr) {
if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ir_const_void(ira, &decl_var_instruction->base);
}
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
} else {
if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
}
}
@@ -12605,7 +12831,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
} else if (is_comptime_var) {
ir_add_error(ira, &decl_var_instruction->base,
buf_sprintf("cannot store runtime value in compile time variable"));
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ira->codegen->invalid_instruction;
}
@@ -12613,11 +12839,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
if (fn_entry)
fn_entry->variable_list.append(var);
- IrInstruction *result = ir_build_var_decl(&ira->new_irb,
- decl_var_instruction->base.scope, decl_var_instruction->base.source_node,
- var, var_type, nullptr, casted_init_value);
- result->value.type = ira->codegen->builtin_types.entry_void;
- return result;
+ return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
}
static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
@@ -12739,6 +12961,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdBool:
+ case ZigTypeIdVector:
break;
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
@@ -12773,6 +12996,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
+ case ZigTypeIdVector:
zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
@@ -12947,7 +13171,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
Buf *param_name = param_decl_node->data.param_decl.name;
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- *exec_scope, param_name, true, arg_val, nullptr);
+ *exec_scope, param_name, true, arg_val, nullptr, arg_val->type);
*exec_scope = var->child_scope;
*next_proto_i += 1;
@@ -13005,7 +13229,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
if (!param_name) return false;
if (!is_var_args) {
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- *child_scope, param_name, true, arg_val, nullptr);
+ *child_scope, param_name, true, arg_val, nullptr, arg_val->type);
*child_scope = var->child_scope;
var->shadowable = !comptime_arg;
@@ -13059,9 +13283,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) {
return fn_entry->variable_list.at(next_var_i);
}
-static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
- ZigVar *var)
-{
+static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) {
while (var->next_var != nullptr) {
var = var->next_var;
}
@@ -13070,14 +13292,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
assert(ira->codegen->errors.length != 0);
return ira->codegen->invalid_instruction;
}
- if (var->value->type == nullptr || type_is_invalid(var->value->type))
+ if (var->var_type == nullptr || type_is_invalid(var->var_type))
return ira->codegen->invalid_instruction;
bool comptime_var_mem = ir_get_var_is_comptime(var);
ConstExprValue *mem_slot = nullptr;
- if (var->value->special == ConstValSpecialStatic) {
- mem_slot = var->value;
+ if (var->const_value->special == ConstValSpecialStatic) {
+ mem_slot = var->const_value;
} else {
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
// find the relevant exec_context
@@ -13106,7 +13328,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
assert(!comptime_var_mem);
ptr_mut = ConstPtrMutRuntimeVar;
}
- return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
+ return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type,
ptr_mut, is_const, is_volatile, var->align_bytes);
}
}
@@ -13117,7 +13339,7 @@ no_mem_slot:
IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
instruction->scope, instruction->source_node, var);
- var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
+ var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type,
var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
@@ -13126,6 +13348,96 @@ no_mem_slot:
return var_ptr_instruction;
}
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *ptr, IrInstruction *uncasted_value)
+{
+ if (ptr->value.type->id != ZigTypeIdPointer) {
+ ir_add_error(ira, ptr,
+ buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+ return ir_const_void(ira, source_instr);
+ }
+
+ if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *child_type = ptr->value.type->data.pointer.child_type;
+ IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type);
+ if (value == ira->codegen->invalid_instruction)
+ return ira->codegen->invalid_instruction;
+
+ if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
+ if (instr_is_comptime(value)) {
+ ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node);
+ if (dest_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (dest_val->special != ConstValSpecialRuntime) {
+ // TODO this allows a value stored to have the original value modified and then
+ // have that affect what should be a copy. We need some kind of advanced copy-on-write
+ // system to make these two tests pass at the same time:
+ // * "string literal used as comptime slice is memoized"
+ // * "comptime modification of const struct field" - except modified to avoid
+ // ConstPtrMutComptimeVar, thus defeating the logic below.
+ bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar;
+ copy_const_val(dest_val, &value->value, same_global_refs);
+ if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
+ switch (type_has_one_possible_value(ira->codegen, child_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
+ break;
+ case OnePossibleValueYes:
+ break;
+ }
+ }
+ return ir_const_void(ira, source_instr);
+ }
+ }
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in compile time variable"));
+ ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+ dest_val->type = ira->codegen->builtin_types.entry_invalid;
+
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ switch (type_requires_comptime(ira->codegen, child_type)) {
+ case ReqCompTimeInvalid:
+ return ira->codegen->invalid_instruction;
+ case ReqCompTimeYes:
+ switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name)));
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ return ir_const_void(ira, source_instr);
+ }
+ zig_unreachable();
+ case ReqCompTimeNo:
+ break;
+ }
+
+ IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ ptr, value);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result;
+}
+
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
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
}
bool cacheable = fn_eval_cacheable(exec_scope, return_type);
- IrInstruction *result = nullptr;
+ ConstExprValue *result = nullptr;
if (cacheable) {
auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
if (entry)
@@ -13286,18 +13598,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
if (inferred_err_set_type != nullptr) {
inferred_err_set_type->data.error_set.infer_fn = nullptr;
- if (result->value.type->id == ZigTypeIdErrorUnion) {
- if (result->value.data.x_err_union.err != nullptr) {
+ if (result->type->id == ZigTypeIdErrorUnion) {
+ ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
inferred_err_set_type->data.error_set.err_count = 1;
inferred_err_set_type->data.error_set.errors = allocate(1);
- inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
+ inferred_err_set_type->data.error_set.errors[0] = err;
}
- ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
+ ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type;
inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
- } else if (result->value.type->id == ZigTypeIdErrorSet) {
- inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
- inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
+ } else if (result->type->id == ZigTypeIdErrorSet) {
+ inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count;
+ inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors;
}
}
@@ -13305,13 +13618,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
}
- if (type_is_invalid(result->value.type))
+ if (type_is_invalid(result->type))
return ira->codegen->invalid_instruction;
}
- IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type);
- // TODO should we use copy_const_val?
- new_instruction->value = result->value;
+ IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type);
+ copy_const_val(&new_instruction->value, result, true);
new_instruction->value.type = return_type;
return ir_finish_anal(ira, new_instruction);
}
@@ -13470,18 +13782,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
first_var_arg, inst_fn_type_id.param_count);
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- impl_fn->child_scope, param_name, true, var_args_val, nullptr);
+ impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type);
impl_fn->child_scope = var->child_scope;
}
if (fn_proto_node->data.fn_proto.align_expr != nullptr) {
- IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
+ ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
+ IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
+ impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr);
+ const_instruction->base.value = *align_result;
uint32_t align_bytes = 0;
- ir_resolve_align(ira, align_result, &align_bytes);
+ ir_resolve_align(ira, &const_instruction->base, &align_bytes);
impl_fn->align_bytes = align_bytes;
inst_fn_type_id.alignment = align_bytes;
}
@@ -13559,12 +13874,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ira->codegen->fn_defs.append(impl_fn);
}
- ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
- if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {
+ FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id;
+ if (fn_type_can_fail(impl_fn_type_id)) {
parent_fn_entry->calls_or_awaits_errorable_fn = true;
}
- size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
+ size_t impl_param_count = impl_fn_type_id->param_count;
if (call_instruction->is_async) {
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
fn_ref, casted_args, impl_param_count, async_allocator_inst);
@@ -13577,9 +13892,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
call_instruction->base.scope, call_instruction->base.source_node,
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
call_instruction->is_async, nullptr, casted_new_stack);
- new_call_instruction->value.type = return_type;
+ new_call_instruction->value.type = impl_fn_type_id->return_type;
- ir_add_alloca(ira, new_call_instruction, return_type);
+ ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type);
return ir_finish_anal(ira, new_call_instruction);
}
@@ -13774,6 +14089,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
switch (ptr_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
zig_unreachable();
+ case ConstPtrSpecialNull:
+ if (dst_size == 0)
+ return ErrorNone;
+ opt_ir_add_error_node(ira, codegen, source_node,
+ buf_sprintf("attempt to read %zu bytes from null pointer",
+ dst_size));
+ return ErrorSemanticAnalyzeFail;
case ConstPtrSpecialRef: {
opt_ir_add_error_node(ira, codegen, source_node,
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
return ErrorNone;
}
case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialBaseErrorUnionCode:
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ case ConstPtrSpecialBaseOptionalPayload:
case ConstPtrSpecialDiscard:
case ConstPtrSpecialHardCodedAddr:
case ConstPtrSpecialFunction:
@@ -13830,6 +14155,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
case ZigTypeIdVoid:
case ZigTypeIdBool:
case ZigTypeIdInt:
+ case ZigTypeIdVector:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
case ZigTypeIdArray:
@@ -14001,9 +14327,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime))
return ir_unreach_error(ira);
- if (is_comptime || instr_is_comptime(condition)) {
+ ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
+ IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
+ if (type_is_invalid(casted_condition->value.type))
+ return ir_unreach_error(ira);
+
+ if (is_comptime || instr_is_comptime(casted_condition)) {
bool cond_is_true;
- if (!ir_resolve_bool(ira, condition, &cond_is_true))
+ if (!ir_resolve_bool(ira, casted_condition, &cond_is_true))
return ir_unreach_error(ira);
IrBasicBlock *old_dest_block = cond_is_true ?
@@ -14022,11 +14353,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
return ir_finish_anal(ira, result);
}
- ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
- IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
- if (casted_condition == ira->codegen->invalid_instruction)
- return ir_unreach_error(ira);
-
assert(cond_br_instruction->then_block != cond_br_instruction->else_block);
IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base);
if (new_then_block == nullptr)
@@ -14065,8 +14391,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
if (value->value.special != ConstValSpecialRuntime) {
IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr);
- // TODO use copy_const_val?
- result->value = value->value;
+ copy_const_val(&result->value, &value->value, true);
return result;
} else {
return value;
@@ -14115,14 +14440,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
if (type_is_invalid(resolved_type))
return ira->codegen->invalid_instruction;
- if (resolved_type->id == ZigTypeIdComptimeFloat ||
- resolved_type->id == ZigTypeIdComptimeInt ||
- resolved_type->id == ZigTypeIdNull ||
- resolved_type->id == ZigTypeIdUndefined)
- {
+ switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ return ir_const(ira, &phi_instruction->base, resolved_type);
+ case OnePossibleValueNo:
+ break;
+ }
+
+ switch (type_requires_comptime(ira->codegen, resolved_type)) {
+ case ReqCompTimeInvalid:
+ return ira->codegen->invalid_instruction;
+ case ReqCompTimeYes:
ir_add_error_node(ira, phi_instruction->base.source_node,
- buf_sprintf("unable to infer expression type"));
+ buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name)));
return ira->codegen->invalid_instruction;
+ case ReqCompTimeNo:
+ break;
}
bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer);
@@ -14412,10 +14747,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO elem ptr on a const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO element ptr of a function casted to a ptr");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO elem ptr on a null pointer");
}
if (new_index >= mem_size) {
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
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a slice backed by const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO elem ptr on a slice backed by const optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO elem ptr on a slice has a null pointer");
}
return result;
} else if (array_type->id == ZigTypeIdArray) {
@@ -15155,74 +15506,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
}
}
-static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
- IrInstruction *ptr = load_ptr_instruction->ptr->child;
+static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
+ IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- return ir_get_deref(ira, &load_ptr_instruction->base, ptr);
-}
-static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
- IrInstruction *ptr = store_ptr_instruction->ptr->child;
- if (type_is_invalid(ptr->value.type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *value = store_ptr_instruction->value->child;
+ IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- if (ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, ptr,
- buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
- return ir_const_void(ira, &store_ptr_instruction->base);
- }
-
- if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
+ return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
+}
- ZigType *child_type = ptr->value.type->data.pointer.child_type;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
- if (casted_value == ira->codegen->invalid_instruction)
+static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
+ IrInstruction *ptr = instruction->ptr->child;
+ if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
-
- if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
- if (instr_is_comptime(casted_value)) {
- ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node);
- if (dest_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (dest_val->special != ConstValSpecialRuntime) {
- *dest_val = casted_value->value;
- if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
- ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base;
- }
- return ir_const_void(ira, &store_ptr_instruction->base);
- }
- }
- ir_add_error(ira, &store_ptr_instruction->base,
- buf_sprintf("cannot store runtime value in compile time variable"));
- ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
- dest_val->type = ira->codegen->builtin_types.entry_invalid;
-
- return ira->codegen->invalid_instruction;
- }
- }
-
- IrInstruction *result = ir_build_store_ptr(&ira->new_irb,
- store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node,
- ptr, casted_value);
- result->value.type = ira->codegen->builtin_types.entry_void;
- return result;
+ return ir_get_deref(ira, &instruction->base, ptr);
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -15230,37 +15530,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio
ZigType *type_entry = expr_value->value.type;
if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- switch (type_entry->id) {
- case ZigTypeIdInvalid:
- zig_unreachable(); // handled above
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- case ZigTypeIdNamespace:
- case ZigTypeIdBoundFn:
- case ZigTypeIdMetaType:
- case ZigTypeIdVoid:
- case ZigTypeIdBool:
- case ZigTypeIdUnreachable:
- case ZigTypeIdInt:
- case ZigTypeIdFloat:
- case ZigTypeIdPointer:
- case ZigTypeIdArray:
- case ZigTypeIdStruct:
- case ZigTypeIdOptional:
- case ZigTypeIdErrorUnion:
- case ZigTypeIdErrorSet:
- case ZigTypeIdEnum:
- case ZigTypeIdUnion:
- case ZigTypeIdFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdOpaque:
- case ZigTypeIdPromise:
- return ir_const_type(ira, &typeof_instruction->base, type_entry);
- }
-
- zig_unreachable();
+ return ir_const_type(ira, &typeof_instruction->base, type_entry);
}
static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
@@ -15499,6 +15769,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
{
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
@@ -15619,6 +15890,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
{
if ((err = ensure_complete_type(ira->codegen, child_type)))
return ira->codegen->invalid_instruction;
@@ -15685,6 +15957,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
+ case ZigTypeIdVector:
{
uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
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,
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
-
+static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {
ZigType *type_entry = value->value.type;
if (type_entry->id == ZigTypeIdOptional) {
@@ -15706,60 +15975,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
if (!maybe_val)
return ira->codegen->invalid_instruction;
- return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val));
+ return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val));
}
IrInstruction *result = ir_build_test_nonnull(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value);
+ source_inst->scope, source_inst->source_node, value);
result->value.type = ira->codegen->builtin_types.entry_bool;
return result;
} else if (type_entry->id == ZigTypeIdNull) {
- return ir_const_bool(ira, &instruction->base, false);
+ return ir_const_bool(ira, source_inst, false);
} else {
- return ir_const_bool(ira, &instruction->base, true);
+ return ir_const_bool(ira, source_inst, true);
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
- IrInstructionUnwrapOptional *unwrap_maybe_instruction)
-{
- IrInstruction *value = unwrap_maybe_instruction->value->child;
+static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
+ IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
+ return ir_analyze_test_non_null(ira, &instruction->base, value);
+}
+
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on)
+{
+ ZigType *ptr_type = base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id != ZigTypeIdOptional) {
- ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
+
+ if (type_entry->id != ZigTypeIdOptional) {
+ ir_add_error_node(ira, base_ptr->source_node,
buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+
ZigType *child_type = type_entry->data.maybe.child_type;
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node);
+ ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node);
if (maybe_val == nullptr)
return ira->codegen->invalid_instruction;
if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
if (optional_value_is_null(maybe_val)) {
- ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
+ ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null"));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type);
+ IrInstruction *result = ir_const(ira, source_instr, result_type);
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.mut = val->data.x_ptr.mut;
- if (type_is_codegen_pointer(child_type)) {
+ if (types_have_same_zig_comptime_repr(type_entry, child_type)) {
out_val->data.x_ptr.data.ref.pointee = maybe_val;
} else {
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,
}
}
- IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb,
- unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node,
- value, unwrap_maybe_instruction->safety_check_on);
+ IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, safety_check_on);
result->value.type = result_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira,
+ IrInstructionOptionalUnwrapPtr *instruction)
+{
+ IrInstruction *base_ptr = instruction->base_ptr->child;
+ if (type_is_invalid(base_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on);
+}
+
static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) {
IrInstruction *value = ctz_instruction->value->child;
if (type_is_invalid(value->value.type)) {
@@ -16075,9 +16359,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr);
+ IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
result->value.type = target_type;
return result;
}
@@ -16107,8 +16389,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
union_value->value.type = target_type;
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,
return result;
}
- IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
enum_value->value.type = target_type;
return enum_value;
}
@@ -16147,6 +16427,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
+ case ZigTypeIdVector:
ir_add_error(ira, &switch_target_instruction->base,
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
return ira->codegen->invalid_instruction;
@@ -16290,7 +16571,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
Error err;
assert(container_type->id == ZigTypeIdUnion);
- if ((err = ensure_complete_type(ira->codegen, container_type)))
+ if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
if (instr_field_count != 1) {
@@ -16322,7 +16603,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
+ bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope)
+ || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes;
if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
!type_has_bits(casted_field_value->value.type))
{
@@ -16334,12 +16616,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
ConstExprValue *out_val = &result->value;
out_val->data.x_union.payload = field_val;
out_val->data.x_union.tag = type_field->enum_field->value;
-
- ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdUnion;
- parent->data.p_union.union_val = out_val;
- }
+ out_val->parent.id = ConstParentIdUnion;
+ out_val->parent.data.p_union.union_val = out_val;
return result;
}
@@ -16366,7 +16644,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
}
- if ((err = ensure_complete_type(ira->codegen, container_type)))
+ if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
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
IrInstructionStructInitField *new_fields = allocate(actual_field_count);
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
+ bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope)
+ || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes;
ConstExprValue const_val = {};
const_val.special = ConstValSpecialStatic;
@@ -16445,9 +16724,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (const_val.special == ConstValSpecialStatic) {
IrInstruction *result = ir_const(ira, instruction, nullptr);
ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = container_type;
+ copy_const_val(out_val, &const_val, true);
+ out_val->type = container_type;
for (size_t i = 0; i < instr_field_count; i += 1) {
ConstExprValue *field_val = &out_val->data.x_struct.fields[i];
@@ -16479,127 +16757,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
IrInstructionContainerInitList *instruction)
{
- IrInstruction *container_type_value = instruction->container_type->child;
- if (type_is_invalid(container_type_value->value.type))
+ ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child);
+ if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
size_t elem_count = instruction->item_count;
- if (container_type_value->value.type->id == ZigTypeIdMetaType) {
- ZigType *container_type = ir_resolve_type(ira, container_type_value);
- if (type_is_invalid(container_type))
- return ira->codegen->invalid_instruction;
- if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
- return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- 0, nullptr);
- } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
- // array is same as slice init but we make a compile error if the length is wrong
- ZigType *child_type;
- if (container_type->id == ZigTypeIdArray) {
- child_type = container_type->data.array.child_type;
- if (container_type->data.array.len != elem_count) {
- ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
-
- ir_add_error(ira, &instruction->base,
- buf_sprintf("expected %s literal, found %s literal",
- buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
- return ira->codegen->invalid_instruction;
- }
- } else {
- ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
- assert(pointer_type->id == ZigTypeIdPointer);
- child_type = pointer_type->data.pointer.child_type;
+ if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
+ return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
+ 0, nullptr);
+ } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
+ // array is same as slice init but we make a compile error if the length is wrong
+ ZigType *child_type;
+ if (container_type->id == ZigTypeIdArray) {
+ child_type = container_type->data.array.child_type;
+ if (container_type->data.array.len != elem_count) {
+ ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
+
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("expected %s literal, found %s literal",
+ buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
+ return ira->codegen->invalid_instruction;
}
+ } else {
+ ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(pointer_type->id == ZigTypeIdPointer);
+ child_type = pointer_type->data.pointer.child_type;
+ }
- ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
-
- ConstExprValue const_val = {};
- const_val.special = ConstValSpecialStatic;
- const_val.type = fixed_size_array_type;
- const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
+ ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+ ConstExprValue const_val = {};
+ const_val.special = ConstValSpecialStatic;
+ const_val.type = fixed_size_array_type;
+ const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
- IrInstruction **new_items = allocate(elem_count);
+ bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
- IrInstruction *first_non_const_instruction = nullptr;
+ IrInstruction **new_items = allocate(elem_count);
- for (size_t i = 0; i < elem_count; i += 1) {
- IrInstruction *arg_value = instruction->items[i]->child;
- if (type_is_invalid(arg_value->value.type))
- return ira->codegen->invalid_instruction;
+ IrInstruction *first_non_const_instruction = nullptr;
- IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
- if (casted_arg == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
+ for (size_t i = 0; i < elem_count; i += 1) {
+ IrInstruction *arg_value = instruction->items[i]->child;
+ if (type_is_invalid(arg_value->value.type))
+ return ira->codegen->invalid_instruction;
- new_items[i] = casted_arg;
+ IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
+ if (casted_arg == ira->codegen->invalid_instruction)
+ return ira->codegen->invalid_instruction;
- if (const_val.special == ConstValSpecialStatic) {
- if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
- ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
- if (!elem_val)
- return ira->codegen->invalid_instruction;
-
- copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
- } else {
- first_non_const_instruction = casted_arg;
- const_val.special = ConstValSpecialRuntime;
- }
- }
- }
+ new_items[i] = casted_arg;
if (const_val.special == ConstValSpecialStatic) {
- IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
- ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = fixed_size_array_type;
- for (size_t i = 0; i < elem_count; i += 1) {
- ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
- ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdArray;
- parent->data.p_array.array_val = out_val;
- parent->data.p_array.elem_index = i;
- }
+ if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
+ ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
+ if (!elem_val)
+ return ira->codegen->invalid_instruction;
+
+ copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
+ } else {
+ first_non_const_instruction = casted_arg;
+ const_val.special = ConstValSpecialRuntime;
}
- return result;
}
+ }
- if (is_comptime) {
- ir_add_error_node(ira, first_non_const_instruction->source_node,
- buf_sprintf("unable to evaluate constant expression"));
- return ira->codegen->invalid_instruction;
+ if (const_val.special == ConstValSpecialStatic) {
+ IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+ ConstExprValue *out_val = &result->value;
+ copy_const_val(out_val, &const_val, true);
+ result->value.type = fixed_size_array_type;
+ for (size_t i = 0; i < elem_count; i += 1) {
+ ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
+ ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdArray;
+ parent->data.p_array.array_val = out_val;
+ parent->data.p_array.elem_index = i;
+ }
}
+ return result;
+ }
- IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node,
- container_type_value, elem_count, new_items);
- new_instruction->value.type = fixed_size_array_type;
- ir_add_alloca(ira, new_instruction, fixed_size_array_type);
- return new_instruction;
- } else if (container_type->id == ZigTypeIdVoid) {
- if (elem_count != 0) {
- ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("void expression expects no arguments"));
- return ira->codegen->invalid_instruction;
- }
- return ir_const_void(ira, &instruction->base);
- } else {
+ if (is_comptime) {
+ ir_add_error_node(ira, first_non_const_instruction->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
+ instruction->base.scope, instruction->base.source_node,
+ nullptr, elem_count, new_items);
+ new_instruction->value.type = fixed_size_array_type;
+ ir_add_alloca(ira, new_instruction, fixed_size_array_type);
+ return new_instruction;
+ } else if (container_type->id == ZigTypeIdVoid) {
+ if (elem_count != 0) {
ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("type '%s' does not support array initialization",
- buf_ptr(&container_type->name)));
+ buf_sprintf("void expression expects no arguments"));
return ira->codegen->invalid_instruction;
}
+ return ir_const_void(ira, &instruction->base);
} else {
- ir_add_error(ira, container_type_value,
- buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
+ ir_add_error_node(ira, instruction->base.source_node,
+ buf_sprintf("type '%s' does not support array initialization",
+ buf_ptr(&container_type->name)));
return ira->codegen->invalid_instruction;
}
}
-static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
+static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
+ IrInstructionContainerInitFields *instruction)
+{
IrInstruction *container_type_value = instruction->container_type->child;
ZigType *container_type = ir_resolve_type(ira, container_type_value);
if (type_is_invalid(container_type))
@@ -16659,7 +16929,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type);
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set);
if (type_is_invalid(casted_value->value.type))
return ira->codegen->invalid_instruction;
@@ -16920,10 +17190,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
ZigVar *var = tld->var;
- if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+ if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
return ira->codegen->builtin_types.entry_invalid;
- assert(var->value->type->id == ZigTypeIdMetaType);
- return var->value->data.x_type;
+
+ assert(var->const_value->type->id == ZigTypeIdMetaType);
+ return var->const_value->data.x_type;
}
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
definition_array->special = ConstValSpecialStatic;
definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count);
definition_array->data.x_array.special = ConstArraySpecialNone;
- definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count);
init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false);
@@ -17009,33 +17279,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub;
inner_fields[2].special = ConstValSpecialStatic;
inner_fields[2].type = type_info_definition_data_type;
- inner_fields[2].data.x_union.parent.id = ConstParentIdStruct;
- inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
- inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
+ inner_fields[2].parent.id = ConstParentIdStruct;
+ inner_fields[2].parent.data.p_struct.struct_val = definition_val;
+ inner_fields[2].parent.data.p_struct.field_index = 1;
switch (curr_entry->value->id) {
case TldIdVar:
{
ZigVar *var = ((TldVar *)curr_entry->value)->var;
- if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+ if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
return ErrorSemanticAnalyzeFail;
- if (var->value->type->id == ZigTypeIdMetaType)
- {
+ if (var->const_value->type->id == ZigTypeIdMetaType) {
// We have a variable of type 'type', so it's actually a type definition.
// 0: Data.Type: type
bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
- inner_fields[2].data.x_union.payload = var->value;
- }
- else
- {
+ inner_fields[2].data.x_union.payload = var->const_value;
+ } else {
// We have a variable of another type, so we store the type of the variable.
// 1: Data.Var: type
bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1);
ConstExprValue *payload = create_const_vals(1);
payload->type = ira->codegen->builtin_types.entry_type;
- payload->data.x_type = var->value->type;
+ payload->data.x_type = var->const_value->type;
inner_fields[2].data.x_union.payload = payload;
}
@@ -17055,8 +17322,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
ConstExprValue *fn_def_val = create_const_vals(1);
fn_def_val->special = ConstValSpecialStatic;
fn_def_val->type = type_info_fn_def_type;
- fn_def_val->data.x_struct.parent.id = ConstParentIdUnion;
- fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2];
+ fn_def_val->parent.id = ConstParentIdUnion;
+ fn_def_val->parent.data.p_union.union_val = &inner_fields[2];
ConstExprValue *fn_def_fields = create_const_vals(9);
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
fn_arg_name_array->type = get_array_type(ira->codegen,
get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
- fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false);
- for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
- {
+ for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index);
ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
- fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray;
- fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array;
- fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+ fn_arg_name_val->parent.id = ConstParentIdArray;
+ fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
+ fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index;
}
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
break;
}
+ case ZigTypeIdVector: {
+ result = create_const_vals(1);
+ result->special = ConstValSpecialStatic;
+ result->type = ir_type_info_get_type(ira, "Vector", nullptr);
+
+ ConstExprValue *fields = create_const_vals(2);
+ result->data.x_struct.fields = fields;
+
+ // len: usize
+ ensure_field_index(result->type, "len", 0);
+ fields[0].special = ConstValSpecialStatic;
+ fields[0].type = ira->codegen->builtin_types.entry_u32;
+ bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);
+ // child: type
+ ensure_field_index(result->type, "child", 1);
+ fields[1].special = ConstValSpecialStatic;
+ fields[1].type = ira->codegen->builtin_types.entry_type;
+ fields[1].data.x_type = type_entry->data.vector.elem_type;
+
+ break;
+ }
case ZigTypeIdOptional:
{
result = create_const_vals(1);
@@ -17426,7 +17712,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
enum_field_array->special = ConstValSpecialStatic;
enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
enum_field_array->data.x_array.special = ConstArraySpecialNone;
- enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
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
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index];
make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type);
- enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
- enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
- enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
+ enum_field_val->parent.id = ConstParentIdArray;
+ enum_field_val->parent.data.p_array.array_val = enum_field_array;
+ enum_field_val->parent.data.p_array.elem_index = enum_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
@@ -17465,7 +17750,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
error_array->special = ConstValSpecialStatic;
error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
error_array->data.x_array.special = ConstArraySpecialNone;
- error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
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
bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value);
error_val->data.x_struct.fields = inner_fields;
- error_val->data.x_struct.parent.id = ConstParentIdArray;
- error_val->data.x_struct.parent.data.p_array.array_val = error_array;
- error_val->data.x_struct.parent.data.p_array.elem_index = error_index;
+ error_val->parent.id = ConstParentIdArray;
+ error_val->parent.data.p_array.array_val = error_array;
+ error_val->parent.data.p_array.elem_index = error_index;
}
break;
@@ -17560,7 +17844,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
union_field_array->special = ConstValSpecialStatic;
union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
union_field_array->data.x_array.special = ConstArraySpecialNone;
- union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
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
init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true);
union_field_val->data.x_struct.fields = inner_fields;
- union_field_val->data.x_struct.parent.id = ConstParentIdArray;
- union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array;
- union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index;
+ union_field_val->parent.id = ConstParentIdArray;
+ union_field_val->parent.data.p_array.array_val = union_field_array;
+ union_field_val->parent.data.p_array.elem_index = union_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
@@ -17635,7 +17918,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
struct_field_array->special = ConstValSpecialStatic;
struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
struct_field_array->data.x_array.special = ConstArraySpecialNone;
- struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
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
init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true);
struct_field_val->data.x_struct.fields = inner_fields;
- struct_field_val->data.x_struct.parent.id = ConstParentIdArray;
- struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array;
- struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index;
+ struct_field_val->parent.id = ConstParentIdArray;
+ struct_field_val->parent.data.p_array.array_val = struct_field_array;
+ struct_field_val->parent.data.p_array.elem_index = struct_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 2);
@@ -17741,7 +18023,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
fn_arg_array->special = ConstValSpecialStatic;
fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
fn_arg_array->data.x_array.special = ConstArraySpecialNone;
- fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
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
}
fn_arg_val->data.x_struct.fields = inner_fields;
- fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
- fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array;
- fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+ fn_arg_val->parent.id = ConstParentIdArray;
+ fn_arg_val->parent.data.p_array.array_val = fn_arg_array;
+ fn_arg_val->parent.data.p_array.elem_index = fn_arg_index;
}
break;
@@ -17824,8 +18105,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
if (payload != nullptr) {
assert(payload->type->id == ZigTypeIdStruct);
- payload->data.x_struct.parent.id = ConstParentIdUnion;
- payload->data.x_struct.parent.data.p_union.union_val = out_val;
+ payload->parent.id = ConstParentIdUnion;
+ payload->parent.data.p_union.union_val = out_val;
}
return result;
@@ -17897,10 +18178,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
// Execute the C import block like an inline function
ZigType *void_type = ira->codegen->builtin_types.entry_void;
- IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
+ ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
&cimport_scope->buf, block_node, nullptr, nullptr);
- if (type_is_invalid(cimport_result->value.type))
+ if (type_is_invalid(cimport_result->type))
return ira->codegen->invalid_instruction;
find_libc_include_path(ira->codegen);
@@ -18050,7 +18331,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
return result;
}
-static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
+static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) {
ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_instruction;
@@ -18122,9 +18403,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
zig_panic("TODO compile-time execution of cmpxchg");
}
- IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
- nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
- operand_type, success_order, failure_order);
+ IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base,
+ casted_ptr, casted_cmp_value, casted_new_value,
+ success_order, failure_order, instruction->is_weak);
result->value.type = get_optional_type(ira->codegen, operand_type);
ir_add_alloca(ira, result, result->value.type);
return result;
@@ -18296,18 +18577,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst
return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
}
-static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
- Error err;
-
- if (ty->id == ZigTypeIdPointer) {
- if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown)))
- return err;
- }
-
- *result_align = get_ptr_align(ira->codegen, ty);
- return ErrorNone;
-}
-
static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
Error err;
@@ -18426,6 +18695,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
}
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
+ Error err;
+
+ ZigType *ptr_type = get_src_ptr_type(ty);
+ assert(ptr_type != nullptr);
+ if (ptr_type->id == ZigTypeIdPointer) {
+ if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+ return err;
+ }
+
+ *result_align = get_ptr_align(ira->codegen, ty);
+ return ErrorNone;
+}
+
static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
if (type_is_invalid(dest_type))
@@ -18532,6 +18815,27 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct
return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count));
}
+static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstructionVectorType *instruction) {
+ uint64_t len;
+ if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ if (!is_valid_vector_elem_type(elem_type)) {
+ ir_add_error(ira, instruction->elem_type,
+ buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",
+ buf_ptr(&elem_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type);
+
+ return ir_const_type(ira, &instruction->base, vector_type);
+}
+
static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
@@ -18630,10 +18934,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memset on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memset on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memset on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memset on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memset on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memset on null ptr");
}
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
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memcpy on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memcpy on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memcpy on null ptr");
}
if (dest_start + count > dest_end) {
@@ -18781,10 +19101,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memcpy on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memcpy on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memcpy on null ptr");
}
if (src_start + count > src_end) {
@@ -18812,9 +19140,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = ptr_ptr->value.type;
- assert(ptr_type->id == ZigTypeIdPointer);
- ZigType *array_type = ptr_type->data.pointer.child_type;
+ ZigType *ptr_ptr_type = ptr_ptr->value.type;
+ assert(ptr_ptr_type->id == ZigTypeIdPointer);
+ ZigType *array_type = ptr_ptr_type->data.pointer.child_type;
IrInstruction *start = instruction->start->child;
if (type_is_invalid(start->value.type))
@@ -18843,10 +19171,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
- ptr_type->data.pointer.is_const || is_comptime_const,
- ptr_type->data.pointer.is_volatile,
+ ptr_ptr_type->data.pointer.is_const || is_comptime_const,
+ ptr_ptr_type->data.pointer.is_volatile,
PtrLenUnknown,
- ptr_type->data.pointer.explicit_alignment, 0, 0);
+ ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
return_type = get_slice_type(ira->codegen, slice_ptr_type);
} else if (array_type->id == ZigTypeIdPointer) {
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
@@ -18944,6 +19272,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO slice const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -18951,6 +19285,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO slice of ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO slice of null ptr");
}
} else if (is_slice(array_type)) {
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
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO slice const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -18988,6 +19330,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO slice of slice cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO slice of null");
}
} else {
zig_unreachable();
@@ -19053,6 +19397,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
zig_unreachable();
case ConstPtrSpecialBaseStruct:
zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO");
case ConstPtrSpecialHardCodedAddr:
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
parent_ptr->type->data.pointer.child_type,
@@ -19061,6 +19411,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO");
}
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
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
+ case ZigTypeIdVector:
{
uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
@@ -19416,7 +19769,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
- return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr));
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ return ir_const_bool(ira, &instruction->base, (err != nullptr));
}
}
@@ -19442,48 +19796,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
- IrInstructionUnwrapErrCode *instruction)
-{
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
+static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) {
+ IrInstruction *base_ptr = instruction->err_union->child;
+ if (type_is_invalid(base_ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
+ ZigType *ptr_type = base_ptr->value.type;
// This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id == ZigTypeIdErrorUnion) {
- if (instr_is_comptime(value)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
- if (!ptr_val)
- return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
- if (err_union_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
- assert(err);
- IrInstruction *result = ir_const(ira, &instruction->base,
- type_entry->data.error_union.err_set_type);
- result->value.data.x_err_set = err;
- return result;
- }
- }
-
- IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value);
- result->value.type = type_entry->data.error_union.err_set_type;
- return result;
- } else {
- ir_add_error(ira, value,
+ if (type_entry->id != ZigTypeIdErrorUnion) {
+ ir_add_error(ira, base_ptr,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
+ if (err_union_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ assert(err);
+
+ IrInstruction *result = ir_const(ira, &instruction->base,
+ type_entry->data.error_union.err_set_type);
+ result->value.data.x_err_set = err;
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb,
+ instruction->base.scope, instruction->base.source_node, base_ptr);
+ result->value.type = type_entry->data.error_union.err_set_type;
+ return result;
}
static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
@@ -19499,48 +19852,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id == ZigTypeIdErrorUnion) {
- ZigType *payload_type = type_entry->data.error_union.payload_type;
- if (type_is_invalid(payload_type)) {
- return ira->codegen->invalid_instruction;
- }
- ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
- if (!ptr_val)
- return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
- if (err_union_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
- if (err != nullptr) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
- return ira->codegen->invalid_instruction;
- }
- IrInstruction *result = ir_const(ira, &instruction->base, result_type);
- result->value.data.x_ptr.special = ConstPtrSpecialRef;
- result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
- return result;
- }
- }
-
- IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
- result->value.type = result_type;
- return result;
- } else {
+ if (type_entry->id != ZigTypeIdErrorUnion) {
ir_add_error(ira, value,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+ ZigType *payload_type = type_entry->data.error_union.payload_type;
+ if (type_is_invalid(payload_type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(value)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
+ if (err_union_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *result = ir_const(ira, &instruction->base, result_type);
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
+ instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
+ result->value.type = result_type;
+ return result;
}
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
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
+ IrInstruction *result = ir_const(ira, target, result_type);
copy_const_val(&result->value, val, false);
result->value.type = result_type;
return result;
@@ -20005,8 +20358,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
- dest_type);
+ IrInstruction *result = ir_const(ira, source_instr, dest_type);
copy_const_val(&result->value, val, false);
result->value.type = dest_type;
return result;
@@ -20029,9 +20381,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
- source_instr->source_node, nullptr, ptr);
- casted_ptr->value.type = dest_type;
+ IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -20057,7 +20407,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return result;
}
-static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->child;
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
if (type_is_invalid(dest_type))
@@ -20071,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct
return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value);
}
+static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) {
+ size_t buf_i = 0;
+ // TODO optimize the buf case
+ expand_undef_array(codegen, val);
+ for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) {
+ ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i];
+ buf_write_value_bytes(codegen, &buf[buf_i], elem);
+ buf_i += type_size(codegen, elem->type);
+ }
+}
+
static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {
if (val->special == ConstValSpecialUndef)
val->special = ConstValSpecialStatic;
@@ -20116,17 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_unreachable();
}
case ZigTypeIdArray:
- {
- size_t buf_i = 0;
- // TODO optimize the buf case
- expand_undef_array(codegen, val);
- for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) {
- ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i];
- buf_write_value_bytes(codegen, &buf[buf_i], elem);
- buf_i += type_size(codegen, elem->type);
- }
- }
- return;
+ return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len);
+ case ZigTypeIdVector:
+ return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len);
case ZigTypeIdStruct:
zig_panic("TODO buf_write_value_bytes struct type");
case ZigTypeIdOptional:
@@ -20143,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_unreachable();
}
+static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf,
+ ConstExprValue *val, ZigType *elem_type, size_t len)
+{
+ Error err;
+ uint64_t elem_size = type_size(codegen, elem_type);
+
+ switch (val->data.x_array.special) {
+ case ConstArraySpecialNone:
+ val->data.x_array.data.s_none.elements = create_const_vals(len);
+ for (size_t i = 0; i < len; i++) {
+ ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i];
+ elem->special = ConstValSpecialStatic;
+ elem->type = elem_type;
+ if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem)))
+ return err;
+ }
+ return ErrorNone;
+ case ConstArraySpecialUndef:
+ zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type");
+ case ConstArraySpecialBuf:
+ zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type");
+ }
+ zig_unreachable();
+}
+
static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) {
Error err;
assert(val->special == ConstValSpecialStatic);
@@ -20181,29 +20559,27 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn);
return ErrorNone;
}
- case ZigTypeIdArray: {
- uint64_t elem_size = type_size(codegen, val->type->data.array.child_type);
- size_t len = val->type->data.array.len;
-
- switch (val->data.x_array.special) {
- case ConstArraySpecialNone:
- val->data.x_array.data.s_none.elements = create_const_vals(len);
- for (size_t i = 0; i < len; i++) {
- ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i];
- elem->special = ConstValSpecialStatic;
- elem->type = val->type->data.array.child_type;
- if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem)))
- return err;
- }
- break;
- case ConstArraySpecialUndef:
- zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type");
- case ConstArraySpecialBuf:
- zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type");
+ case ZigTypeIdArray:
+ return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type,
+ val->type->data.array.len);
+ case ZigTypeIdVector:
+ return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type,
+ val->type->data.vector.len);
+ case ZigTypeIdEnum:
+ switch (val->type->data.enumeration.layout) {
+ case ContainerLayoutAuto:
+ zig_panic("TODO buf_read_value_bytes enum auto");
+ case ContainerLayoutPacked:
+ zig_panic("TODO buf_read_value_bytes enum packed");
+ case ContainerLayoutExtern: {
+ ZigType *tag_int_type = val->type->data.enumeration.tag_int_type;
+ assert(tag_int_type->id == ZigTypeIdInt);
+ bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count,
+ codegen->is_big_endian, tag_int_type->data.integral.is_signed);
+ return ErrorNone;
+ }
}
-
- return ErrorNone;
- }
+ zig_unreachable();
case ZigTypeIdStruct:
switch (val->type->data.structure.layout) {
case ContainerLayoutAuto: {
@@ -20242,8 +20618,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
zig_panic("TODO buf_read_value_bytes error union");
case ZigTypeIdErrorSet:
zig_panic("TODO buf_read_value_bytes pure error type");
- case ZigTypeIdEnum:
- zig_panic("TODO buf_read_value_bytes enum type");
case ZigTypeIdFn:
zig_panic("TODO buf_read_value_bytes fn type");
case ZigTypeIdUnion:
@@ -20264,10 +20638,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
if (type_is_invalid(src_type))
return ira->codegen->invalid_instruction;
- if ((err = ensure_complete_type(ira->codegen, dest_type)))
+ if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
- if ((err = ensure_complete_type(ira->codegen, src_type)))
+ if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
if (get_codegen_ptr_type(src_type) != nullptr) {
@@ -20330,6 +20704,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
}
+ uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type);
+ uint64_t src_size_bits = type_size_bits(ira->codegen, src_type);
+ if (dest_size_bits != src_size_bits) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits",
+ buf_ptr(&dest_type->name), dest_size_bits,
+ buf_ptr(&src_type->name), src_size_bits));
+ return ira->codegen->invalid_instruction;
+ }
+
if (instr_is_comptime(value)) {
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
if (!val)
@@ -20410,8 +20794,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
case TldIdContainer:
case TldIdCompTime:
zig_unreachable();
- case TldIdVar:
- {
+ case TldIdVar: {
TldVar *tld_var = (TldVar *)tld;
ZigVar *var = tld_var->var;
@@ -20429,8 +20812,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
return ir_get_deref(ira, &instruction->base, var_ptr);
}
}
- case TldIdFn:
- {
+ case TldIdFn: {
TldFn *tld_fn = (TldFn *)tld;
ZigFn *fn_entry = tld_fn->fn_entry;
assert(fn_entry->type_entry);
@@ -20476,8 +20858,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru
if (!val)
return ira->codegen->invalid_instruction;
if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
- IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, usize);
+ IrInstruction *result = ir_const(ira, &instruction->base, usize);
bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
result->value.type = usize;
return result;
@@ -21315,6 +21696,11 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
case IrInstructionIdCast:
+ case IrInstructionIdDeclVarGen:
+ case IrInstructionIdPtrCastGen:
+ case IrInstructionIdCmpxchgGen:
+ case IrInstructionIdArrayToVector:
+ case IrInstructionIdVectorToArray:
zig_unreachable();
case IrInstructionIdReturn:
@@ -21325,8 +21711,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
case IrInstructionIdBinOp:
return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
- case IrInstructionIdDeclVar:
- return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction);
case IrInstructionIdLoadPtr:
return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
case IrInstructionIdStorePtr:
@@ -21371,8 +21757,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
case IrInstructionIdTestNonNull:
return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
- case IrInstructionIdUnwrapOptional:
- return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction);
case IrInstructionIdClz:
return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -21413,8 +21799,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
case IrInstructionIdEmbedFile:
return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction);
case IrInstructionIdFence:
return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -21437,6 +21823,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction);
case IrInstructionIdIntType:
return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
+ case IrInstructionIdVectorType:
+ return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
case IrInstructionIdBoolNot:
return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
case IrInstructionIdMemset:
@@ -21481,8 +21869,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
case IrInstructionIdPanic:
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
- case IrInstructionIdPtrCast:
- return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
case IrInstructionIdBitCast:
return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
case IrInstructionIdIntToPtr:
@@ -21666,7 +22054,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBr:
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
- case IrInstructionIdDeclVar:
+ case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdDeclVarGen:
case IrInstructionIdStorePtr:
case IrInstructionIdCall:
case IrInstructionIdReturn:
@@ -21681,7 +22070,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCInclude:
case IrInstructionIdCDefine:
case IrInstructionIdCUndef:
- case IrInstructionIdCmpxchg:
case IrInstructionIdFence:
case IrInstructionIdMemset:
case IrInstructionIdMemcpy:
@@ -21709,6 +22097,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdMergeErrRetTraces:
case IrInstructionIdMarkErrRetTracePtr:
case IrInstructionIdAtomicRmw:
+ case IrInstructionIdCmpxchgGen:
+ case IrInstructionIdCmpxchgSrc:
return true;
case IrInstructionIdPhi:
@@ -21734,7 +22124,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdSliceType:
case IrInstructionIdSizeOf:
case IrInstructionIdTestNonNull:
- case IrInstructionIdUnwrapOptional:
+ case IrInstructionIdOptionalUnwrapPtr:
case IrInstructionIdClz:
case IrInstructionIdCtz:
case IrInstructionIdPopCount:
@@ -21745,6 +22135,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdEmbedFile:
case IrInstructionIdTruncate:
case IrInstructionIdIntType:
+ case IrInstructionIdVectorType:
case IrInstructionIdBoolNot:
case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
@@ -21761,7 +22152,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdErrWrapPayload:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
- case IrInstructionIdPtrCast:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdPtrCastGen:
case IrInstructionIdBitCast:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
@@ -21804,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdFromBytes:
case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
+ case IrInstructionIdVectorToArray:
+ case IrInstructionIdArrayToVector:
return false;
case IrInstructionIdAsm:
diff --git a/src/ir.hpp b/src/ir.hpp
index 7af1d7f52ba8b05e0c8185a47142e3812912d92b..0a7c614812b424c817c98b1b8ce2919a6f56df5c 100644
--- a/src/ir.hpp
+++ b/src/ir.hpp
@@ -13,7 +13,7 @@
bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable);
bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec);
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b5099db86aaf868658627c3dab4c2eab3a65684b..e19aa6dda832b21d2a5a4cd1588ee36a4f72dce5 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
}
}
-static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) {
+static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
const char *name = buf_ptr(&decl_var_instruction->var->name);
if (decl_var_instruction->var_type) {
@@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
}
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
- fprintf(irp->f, "*");
ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ".*");
}
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
@@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
- fprintf(irp->f, "*");
+static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, " != null");
}
-static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
- fprintf(irp->f, "&??*");
- ir_print_other_instruction(irp, instruction->value);
+static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) {
+ fprintf(irp->f, "&");
+ ir_print_other_instruction(irp, instruction->base_ptr);
+ fprintf(irp->f, ".*.?");
if (!instruction->safety_check_on) {
fprintf(irp->f, " // no safety");
}
@@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
fprintf(irp->f, ")");
}
-static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
+static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) {
fprintf(irp->f, "@cmpxchg(");
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ", ");
@@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
+ fprintf(irp->f, "@cmpxchg(");
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->cmp_value);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->new_value);
+ fprintf(irp->f, ", TODO print atomic orders)");
+}
+
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
fprintf(irp->f, "@fence(");
ir_print_other_instruction(irp, instruction->order_value);
@@ -709,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) {
+ fprintf(irp->f, "@Vector(");
+ ir_print_other_instruction(irp, instruction->len);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->elem_type);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
fprintf(irp->f, "! ");
ir_print_other_instruction(irp, instruction->value);
@@ -820,13 +838,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
}
static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
- fprintf(irp->f, "@unwrapErrorCode(");
- ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, "UnwrapErrorCode(");
+ ir_print_other_instruction(irp, instruction->err_union);
fprintf(irp->f, ")");
}
static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
- fprintf(irp->f, "@unwrapErrorPayload(");
+ fprintf(irp->f, "ErrorUnionFieldPayload(");
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")");
if (!instruction->safety_check_on) {
@@ -879,7 +897,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
fprintf(irp->f, ")");
}
-static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
+static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) {
fprintf(irp->f, "@ptrCast(");
if (instruction->dest_type) {
ir_print_other_instruction(irp, instruction->dest_type);
@@ -889,6 +907,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) {
+ fprintf(irp->f, "@ptrCast(");
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
fprintf(irp->f, "@bitCast(");
if (instruction->dest_type) {
@@ -900,7 +924,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
}
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
- fprintf(irp->f, "@widenOrShorten(");
+ fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target);
fprintf(irp->f, ")");
}
@@ -948,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime
fprintf(irp->f, ")");
}
+static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *instruction) {
+ fprintf(irp->f, "ArrayToVector(");
+ ir_print_other_instruction(irp, instruction->array);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) {
+ fprintf(irp->f, "VectorToArray(");
+ ir_print_other_instruction(irp, instruction->vector);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
fprintf(irp->f, "inttoerr ");
ir_print_other_instruction(irp, instruction->target);
@@ -1323,6 +1359,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) {
+ ZigVar *var = decl_var_instruction->var;
+ const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
+ const char *name = buf_ptr(&decl_var_instruction->var->name);
+ fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name),
+ var->align_bytes);
+
+ ir_print_other_instruction(irp, decl_var_instruction->init_value);
+ if (decl_var_instruction->var->is_comptime != nullptr) {
+ fprintf(irp->f, " // comptime = ");
+ ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
+ }
+}
+
static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
fprintf(irp->f, "@bswap(");
if (instruction->type != nullptr) {
@@ -1361,8 +1411,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBinOp:
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
break;
- case IrInstructionIdDeclVar:
- ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction);
break;
case IrInstructionIdCast:
ir_print_cast(irp, (IrInstructionCast *)instruction);
@@ -1452,10 +1502,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
break;
case IrInstructionIdTestNonNull:
- ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
+ ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction);
break;
- case IrInstructionIdUnwrapOptional:
- ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction);
break;
case IrInstructionIdCtz:
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
@@ -1508,8 +1558,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdEmbedFile:
ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
break;
- case IrInstructionIdCmpxchg:
- ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction);
+ break;
+ case IrInstructionIdCmpxchgGen:
+ ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction);
break;
case IrInstructionIdFence:
ir_print_fence(irp, (IrInstructionFence *)instruction);
@@ -1544,6 +1597,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdIntType:
ir_print_int_type(irp, (IrInstructionIntType *)instruction);
break;
+ case IrInstructionIdVectorType:
+ ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);
+ break;
case IrInstructionIdBoolNot:
ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
break;
@@ -1607,8 +1663,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTestComptime:
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
break;
- case IrInstructionIdPtrCast:
- ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction);
+ break;
+ case IrInstructionIdPtrCastGen:
+ ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
break;
case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
@@ -1775,6 +1834,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdCheckRuntimeScope:
ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
break;
+ case IrInstructionIdDeclVarGen:
+ ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
+ break;
+ case IrInstructionIdArrayToVector:
+ ir_print_array_to_vector(irp, (IrInstructionArrayToVector *)instruction);
+ break;
+ case IrInstructionIdVectorToArray:
+ ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/main.cpp b/src/main.cpp
index fd8e3db2fae23fae491d0dd8179786e8d0c29f01..81f49089be13055598b6d58259c7a57762b79ac6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -59,6 +59,7 @@ static int print_full_usage(const char *arg0) {
" --release-fast build with optimizations on and safety off\n"
" --release-safe build with optimizations on and safety on\n"
" --release-small build with size optimizations on and safety off\n"
+ " --single-threaded source may assume it is only used single-threaded\n"
" --static output will be statically linked\n"
" --strip exclude debug symbols\n"
" --target-arch [name] specify target architecture\n"
@@ -393,6 +394,7 @@ int main(int argc, char **argv) {
bool no_rosegment_workaround = false;
bool system_linker_hack = false;
TargetSubsystem subsystem = TargetSubsystemAuto;
+ bool is_single_threaded = false;
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
Buf zig_exe_path_buf = BUF_INIT;
@@ -550,6 +552,8 @@ int main(int argc, char **argv) {
disable_pic = true;
} else if (strcmp(arg, "--system-linker-hack") == 0) {
system_linker_hack = true;
+ } else if (strcmp(arg, "--single-threaded") == 0) {
+ is_single_threaded = true;
} else if (strcmp(arg, "--test-cmd-bin") == 0) {
test_exec_args.append(nullptr);
} else if (arg[1] == 'L' && arg[2] != 0) {
@@ -816,6 +820,7 @@ int main(int argc, char **argv) {
switch (cmd) {
case CmdBuiltin: {
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir());
+ g->is_single_threaded = is_single_threaded;
Buf *builtin_source = codegen_generate_builtin_source(g);
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
@@ -889,6 +894,7 @@ int main(int argc, char **argv) {
codegen_set_out_name(g, buf_out_name);
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
codegen_set_is_test(g, cmd == CmdTest);
+ g->is_single_threaded = is_single_threaded;
codegen_set_linker_script(g, linker_script);
if (each_lib_rpath)
codegen_set_each_lib_rpath(g, each_lib_rpath);
diff --git a/src/os.cpp b/src/os.cpp
index 2f0379c09b2ee6403bd173025c5c85928f208384..8eb6b346541c2fe2b8105418c994d055e40facd3 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -1808,7 +1808,7 @@ Error os_self_exe_shared_libs(ZigList &paths) {
#endif
}
-Error os_file_open_r(Buf *full_path, OsFile *out_file) {
+Error os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime) {
#if defined(ZIG_OS_WINDOWS)
// TODO use CreateFileW
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) {
return ErrorUnexpected;
}
}
-
*out_file = result;
+
+ if (mtime != nullptr) {
+ FILETIME last_write_time;
+ if (!GetFileTime(result, nullptr, nullptr, &last_write_time)) {
+ CloseHandle(result);
+ return ErrorUnexpected;
+ }
+ mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime;
+ mtime->nsec = 0;
+ }
+
return ErrorNone;
#else
for (;;) {
@@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) {
return ErrorFileSystem;
}
}
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) == -1) {
+ close(fd);
+ return ErrorFileSystem;
+ }
+ if (S_ISDIR(statbuf.st_mode)) {
+ close(fd);
+ return ErrorIsDir;
+ }
*out_file = fd;
+
+ if (mtime != nullptr) {
+#if defined(ZIG_OS_DARWIN)
+ mtime->sec = statbuf.st_mtimespec.tv_sec;
+ mtime->nsec = statbuf.st_mtimespec.tv_nsec;
+#else
+ mtime->sec = statbuf.st_mtim.tv_sec;
+ mtime->nsec = statbuf.st_mtim.tv_nsec;
+#endif
+ }
return ErrorNone;
}
#endif
@@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
#endif
}
-Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
-#if defined(ZIG_OS_WINDOWS)
- FILETIME last_write_time;
- if (!GetFileTime(file, nullptr, nullptr, &last_write_time))
- return ErrorUnexpected;
- mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime;
- mtime->nsec = 0;
- return ErrorNone;
-#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
- struct stat statbuf;
- if (fstat(file, &statbuf) == -1)
- return ErrorFileSystem;
-
- mtime->sec = statbuf.st_mtim.tv_sec;
- mtime->nsec = statbuf.st_mtim.tv_nsec;
- return ErrorNone;
-#elif defined(ZIG_OS_DARWIN)
- struct stat statbuf;
- if (fstat(file, &statbuf) == -1)
- return ErrorFileSystem;
-
- mtime->sec = statbuf.st_mtimespec.tv_sec;
- mtime->nsec = statbuf.st_mtimespec.tv_nsec;
- return ErrorNone;
-#else
-#error unimplemented
-#endif
-}
-
Error os_file_read(OsFile file, void *ptr, size_t *len) {
#if defined(ZIG_OS_WINDOWS)
DWORD amt_read;
diff --git a/src/os.hpp b/src/os.hpp
index d81a2362a559a0671204d06cf808cd4828d5587d..68ac6e017163f4967037b852e9b3ac84da1d5f8c 100644
--- a/src/os.hpp
+++ b/src/os.hpp
@@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path);
Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
-Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file);
+Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime);
Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
-Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime);
Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
diff --git a/src/parser.cpp b/src/parser.cpp
index 077365995e87d5d38f491d87ef121f68cb0f90c9..81bd469d1c084bbd4c2b21c41c0608c0b4dd785d 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse
else_body = ast_expect(pc, body_parser);
}
- assert(res->type == NodeTypeTestExpr);
+ assert(res->type == NodeTypeIfOptional);
if (err_payload != nullptr) {
AstNodeTestExpr old = res->data.test_expr;
res->type = NodeTypeIfErrorExpr;
@@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
if (requires_semi && else_body == nullptr)
expect_token(pc, TokenIdSemicolon);
- assert(res->type == NodeTypeTestExpr);
+ assert(res->type == NodeTypeIfOptional);
if (err_payload != nullptr) {
AstNodeTestExpr old = res->data.test_expr;
res->type = NodeTypeIfErrorExpr;
@@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) {
Optional opt_payload = ast_parse_ptr_payload(pc);
PtrPayload payload;
- AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first);
+ AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first);
res->data.test_expr.target_node = condition;
if (opt_payload.unwrap(&payload)) {
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
visit_field(&node->data.if_err_expr.then_node, visit, context);
visit_field(&node->data.if_err_expr.else_node, visit, context);
break;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
visit_field(&node->data.test_expr.target_node, visit, context);
visit_field(&node->data.test_expr.then_node, visit, context);
visit_field(&node->data.test_expr.else_node, visit, context);
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 921ee4de09b5d022f40b3014303307aa78312f07..d43bfabf6de6a11321ffc84f52e70f0a0439f860 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -248,13 +248,8 @@ ATTRIBUTE_PRINTF(2, 3)
static void tokenize_error(Tokenize *t, const char *format, ...) {
t->state = TokenizeStateError;
- if (t->cur_tok) {
- t->out->err_line = t->cur_tok->start_line;
- t->out->err_column = t->cur_tok->start_column;
- } else {
- t->out->err_line = t->line;
- t->out->err_column = t->column;
- }
+ t->out->err_line = t->line;
+ t->out->err_column = t->column;
va_list ap;
va_start(ap, format);
@@ -886,6 +881,9 @@ void tokenize(Buf *buf, Tokenization *out) {
break;
case TokenizeStateSawAmpersand:
switch (c) {
+ case '&':
+ tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND.");
+ break;
case '=':
set_token_id(&t, t.cur_tok, TokenIdBitAndEq);
end_token(&t);
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index 6ba8356ddbf7b70ae0b298e3c478fe8e1150c2f3..7c16d3af02f9d1d075b271876fa8eefed7757f95 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch
return reinterpret_cast(di_type);
}
+struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
+ uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty)
+{
+ SmallVector subrange;
+ subrange.push_back(reinterpret_cast(dibuilder)->getOrCreateSubrange(0, Size));
+ DIType *di_type = reinterpret_cast(dibuilder)->createVectorType(
+ Size,
+ AlignInBits,
+ reinterpret_cast(Ty),
+ reinterpret_cast(dibuilder)->getOrCreateArray(subrange));
+ return reinterpret_cast(di_type);
+}
+
ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits,
uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count)
{
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
index 8588b7e2726b624f9b1730e295c55b5ec7a18aa3..824736824001b6f9152fe06f9197b7dd6a7a0e53 100644
--- a/src/zig_llvm.h
+++ b/src/zig_llvm.h
@@ -191,6 +191,8 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB
unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition,
unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram);
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
+ uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty);
ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram);
diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig
index 1aab4c32def93d41b8b7284e2867fa68c10763d1..183c434dc574fdf1a78c6910b5e52c2145054346 100644
--- a/std/atomic/queue.zig
+++ b/std/atomic/queue.zig
@@ -170,20 +170,36 @@ test "std.atomic.Queue" {
.get_count = 0,
};
- var putters: [put_thread_count]*std.os.Thread = undefined;
- for (putters) |*t| {
- t.* = try std.os.spawnThread(&context, startPuts);
- }
- var getters: [put_thread_count]*std.os.Thread = undefined;
- for (getters) |*t| {
- t.* = try std.os.spawnThread(&context, startGets);
- }
+ if (builtin.single_threaded) {
+ {
+ var i: usize = 0;
+ while (i < put_thread_count) : (i += 1) {
+ std.debug.assertOrPanic(startPuts(&context) == 0);
+ }
+ }
+ context.puts_done = 1;
+ {
+ var i: usize = 0;
+ while (i < put_thread_count) : (i += 1) {
+ std.debug.assertOrPanic(startGets(&context) == 0);
+ }
+ }
+ } else {
+ var putters: [put_thread_count]*std.os.Thread = undefined;
+ for (putters) |*t| {
+ t.* = try std.os.spawnThread(&context, startPuts);
+ }
+ var getters: [put_thread_count]*std.os.Thread = undefined;
+ for (getters) |*t| {
+ t.* = try std.os.spawnThread(&context, startGets);
+ }
- for (putters) |t|
- t.wait();
- _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
- for (getters) |t|
- t.wait();
+ for (putters) |t|
+ t.wait();
+ _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
+ for (getters) |t|
+ t.wait();
+ }
if (context.put_sum != context.get_sum) {
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
@@ -205,11 +221,12 @@ fn startPuts(ctx: *Context) u8 {
while (put_count != 0) : (put_count -= 1) {
std.os.time.sleep(1); // let the os scheduler be our fuzz
const x = @bitCast(i32, r.random.scalar(u32));
- const node = ctx.allocator.create(Queue(i32).Node{
+ const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
+ node.* = Queue(i32).Node{
.prev = undefined,
.next = undefined,
.data = x,
- }) catch unreachable;
+ };
ctx.queue.put(node);
_ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
}
diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig
index b69a93733cbe88f1738d3785e75844db43142c59..503fa0c0ceb4fc4dbceadb86cde1e4705c0ad2d4 100644
--- a/std/atomic/stack.zig
+++ b/std/atomic/stack.zig
@@ -4,10 +4,13 @@ const AtomicOrder = builtin.AtomicOrder;
/// Many reader, many writer, non-allocating, thread-safe
/// Uses a spinlock to protect push() and pop()
+/// When building in single threaded mode, this is a simple linked list.
pub fn Stack(comptime T: type) type {
return struct {
root: ?*Node,
- lock: u8,
+ lock: @typeOf(lock_init),
+
+ const lock_init = if (builtin.single_threaded) {} else u8(0);
pub const Self = @This();
@@ -19,7 +22,7 @@ pub fn Stack(comptime T: type) type {
pub fn init() Self {
return Self{
.root = null,
- .lock = 0,
+ .lock = lock_init,
};
}
@@ -31,20 +34,31 @@ pub fn Stack(comptime T: type) type {
}
pub fn push(self: *Self, node: *Node) void {
- while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
- defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
+ if (builtin.single_threaded) {
+ node.next = self.root;
+ self.root = node;
+ } else {
+ while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
+ defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
- node.next = self.root;
- self.root = node;
+ node.next = self.root;
+ self.root = node;
+ }
}
pub fn pop(self: *Self) ?*Node {
- while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
- defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
+ if (builtin.single_threaded) {
+ const root = self.root orelse return null;
+ self.root = root.next;
+ return root;
+ } else {
+ while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
+ defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
- const root = self.root orelse return null;
- self.root = root.next;
- return root;
+ const root = self.root orelse return null;
+ self.root = root.next;
+ return root;
+ }
}
pub fn isEmpty(self: *Self) bool {
@@ -90,20 +104,36 @@ test "std.atomic.stack" {
.get_count = 0,
};
- var putters: [put_thread_count]*std.os.Thread = undefined;
- for (putters) |*t| {
- t.* = try std.os.spawnThread(&context, startPuts);
- }
- var getters: [put_thread_count]*std.os.Thread = undefined;
- for (getters) |*t| {
- t.* = try std.os.spawnThread(&context, startGets);
- }
+ if (builtin.single_threaded) {
+ {
+ var i: usize = 0;
+ while (i < put_thread_count) : (i += 1) {
+ std.debug.assertOrPanic(startPuts(&context) == 0);
+ }
+ }
+ context.puts_done = 1;
+ {
+ var i: usize = 0;
+ while (i < put_thread_count) : (i += 1) {
+ std.debug.assertOrPanic(startGets(&context) == 0);
+ }
+ }
+ } else {
+ var putters: [put_thread_count]*std.os.Thread = undefined;
+ for (putters) |*t| {
+ t.* = try std.os.spawnThread(&context, startPuts);
+ }
+ var getters: [put_thread_count]*std.os.Thread = undefined;
+ for (getters) |*t| {
+ t.* = try std.os.spawnThread(&context, startGets);
+ }
- for (putters) |t|
- t.wait();
- _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
- for (getters) |t|
- t.wait();
+ for (putters) |t|
+ t.wait();
+ _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
+ for (getters) |t|
+ t.wait();
+ }
if (context.put_sum != context.get_sum) {
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
@@ -125,10 +155,11 @@ fn startPuts(ctx: *Context) u8 {
while (put_count != 0) : (put_count -= 1) {
std.os.time.sleep(1); // let the os scheduler be our fuzz
const x = @bitCast(i32, r.random.scalar(u32));
- const node = ctx.allocator.create(Stack(i32).Node{
+ const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
+ node.* = Stack(i32).Node{
.next = undefined,
.data = x,
- }) catch unreachable;
+ };
ctx.stack.push(node);
_ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
}
diff --git a/std/build.zig b/std/build.zig
index 90f5bec656314860926fa62c811fc9ff5c2700c2..5246d973398fd1f4bf2b1e308ebe0b47f38c8432 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -89,7 +89,7 @@ pub const Builder = struct {
};
pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
- const env_map = allocator.createOne(BufMap) catch unreachable;
+ const env_map = allocator.create(BufMap) catch unreachable;
env_map.* = os.getEnvMap(allocator) catch unreachable;
var self = Builder{
.zig_exe = zig_exe,
@@ -170,7 +170,8 @@ pub const Builder = struct {
}
pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
- const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable;
+ const test_step = self.allocator.create(TestStep) catch unreachable;
+ test_step.* = TestStep.init(self, root_src);
return test_step;
}
@@ -202,18 +203,21 @@ pub const Builder = struct {
}
pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
- const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable;
+ const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
+ write_file_step.* = WriteFileStep.init(self, file_path, data);
return write_file_step;
}
pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {
const data = self.fmt(format, args);
- const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable;
+ const log_step = self.allocator.create(LogStep) catch unreachable;
+ log_step.* = LogStep.init(self, data);
return log_step;
}
pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
- const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable;
+ const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
+ remove_dir_step.* = RemoveDirStep.init(self, dir_path);
return remove_dir_step;
}
@@ -320,7 +324,7 @@ pub const Builder = struct {
fn processNixOSEnvVars(self: *Builder) void {
if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
- var it = mem.split(nix_cflags_compile, " ");
+ var it = mem.tokenize(nix_cflags_compile, " ");
while (true) {
const word = it.next() orelse break;
if (mem.eql(u8, word, "-isystem")) {
@@ -338,7 +342,7 @@ pub const Builder = struct {
assert(err == error.EnvironmentVariableNotFound);
}
if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
- var it = mem.split(nix_ldflags, " ");
+ var it = mem.tokenize(nix_ldflags, " ");
while (true) {
const word = it.next() orelse break;
if (mem.eql(u8, word, "-rpath")) {
@@ -414,10 +418,11 @@ pub const Builder = struct {
}
pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
- const step_info = self.allocator.create(TopLevelStep{
+ const step_info = self.allocator.create(TopLevelStep) catch unreachable;
+ step_info.* = TopLevelStep{
.step = Step.initNoOp(name, self.allocator),
.description = description,
- }) catch unreachable;
+ };
self.top_level_steps.append(step_info) catch unreachable;
return &step_info.step;
}
@@ -616,7 +621,8 @@ pub const Builder = struct {
const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
self.pushInstalledFile(full_dest_path);
- const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable;
+ const install_step = self.allocator.create(InstallFileStep) catch unreachable;
+ install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
return install_step;
}
@@ -683,7 +689,7 @@ pub const Builder = struct {
if (os.path.isAbsolute(name)) {
return name;
}
- var it = mem.split(PATH, []u8{os.path.delimiter});
+ var it = mem.tokenize(PATH, []u8{os.path.delimiter});
while (it.next()) |path| {
const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
if (os.path.real(self.allocator, full_path)) |real_path| {
@@ -865,43 +871,51 @@ pub const LibExeObjStep = struct {
};
pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
- const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
return self;
}
pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep {
- const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initC(builder, name, Kind.Lib, version, false);
return self;
}
pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
- const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
return self;
}
pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
return self;
}
pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
return self;
}
pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
self.object_src = src;
return self;
}
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
- const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
return self;
}
pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable;
+ const self = builder.allocator.create(LibExeObjStep) catch unreachable;
+ self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
return self;
}
@@ -1914,13 +1928,14 @@ pub const CommandStep = struct {
/// ::argv is copied.
pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
- const self = builder.allocator.create(CommandStep{
+ const self = builder.allocator.create(CommandStep) catch unreachable;
+ self.* = CommandStep{
.builder = builder,
.step = Step.init(argv[0], builder.allocator, make),
.argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
.cwd = cwd,
.env_map = env_map,
- }) catch unreachable;
+ };
mem.copy([]const u8, self.argv, argv);
self.step.name = self.argv[0];
@@ -1949,12 +1964,13 @@ const InstallArtifactStep = struct {
LibExeObjStep.Kind.Exe => builder.exe_dir,
LibExeObjStep.Kind.Lib => builder.lib_dir,
};
- const self = builder.allocator.create(Self{
+ const self = builder.allocator.create(Self) catch unreachable;
+ self.* = Self{
.builder = builder,
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
.artifact = artifact,
.dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
- }) catch unreachable;
+ };
self.step.dependOn(&artifact.step);
builder.pushInstalledFile(self.dest_file);
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
diff --git a/std/c/darwin.zig b/std/c/darwin.zig
index 86c5e4828e5ad5d37c8574e06444899eb37ec39a..4f0ea4a02bd95c24c30e2cbf723418e4978446ea 100644
--- a/std/c/darwin.zig
+++ b/std/c/darwin.zig
@@ -73,8 +73,8 @@ pub const sockaddr_in6 = extern struct {
};
pub const timeval = extern struct {
- tv_sec: isize,
- tv_usec: isize,
+ tv_sec: c_long,
+ tv_usec: i32,
};
pub const timezone = extern struct {
@@ -176,6 +176,24 @@ pub const kevent64_s = extern struct {
ext: [2]u64,
};
+pub const mach_port_t = c_uint;
+pub const clock_serv_t = mach_port_t;
+pub const clock_res_t = c_int;
+pub const mach_port_name_t = natural_t;
+pub const natural_t = c_uint;
+pub const mach_timespec_t = extern struct {
+ tv_sec: c_uint,
+ tv_nsec: clock_res_t,
+};
+pub const kern_return_t = c_int;
+pub const host_t = mach_port_t;
+pub const CALENDAR_CLOCK = 1;
+
+pub extern fn mach_host_self() mach_port_t;
+pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
+pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
+pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
+
// sys/types.h on macos uses #pragma pack() so these checks are
// to make sure the struct is laid out the same. These values were
// produced from C code using the offsetof macro.
diff --git a/std/c/index.zig b/std/c/index.zig
index 4aab39d931d9a5548382df931146aff18a9cbca8..058d879c093e1a65ed40c8e2d76ae6868f692e27 100644
--- a/std/c/index.zig
+++ b/std/c/index.zig
@@ -44,7 +44,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
-pub extern "c" fn gettimeofday(tv: ?*timeval, tz: ?*timezone) c_int;
+pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 445f943594cd24f9ba73df3e053ea91b41a7ff3e..838bd0c166fdfb58866b3dd28e85552d91517904 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -751,7 +751,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
const self_file = try os.openSelfExe();
defer self_file.close();
- const coff_obj = try allocator.createOne(coff.Coff);
+ const coff_obj = try allocator.create(coff.Coff);
coff_obj.* = coff.Coff{
.in_file = self_file,
.allocator = allocator,
@@ -1036,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
}
}
}
- const sentinel = try allocator.createOne(macho.nlist_64);
+ const sentinel = try allocator.create(macho.nlist_64);
sentinel.* = macho.nlist_64{
.n_strx = 0,
.n_type = 36,
@@ -1949,7 +1949,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
- const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
+ const compile_unit_die = try di.allocator().create(Die);
+ compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
diff --git a/std/event/channel.zig b/std/event/channel.zig
index 133ce1c69c483fbeb6d148e87bcc2d68c5f64d44..f8cdae6208906a949ff3fcce6660cba2bbe9fc2c 100644
--- a/std/event/channel.zig
+++ b/std/event/channel.zig
@@ -54,7 +54,8 @@ pub fn Channel(comptime T: type) type {
const buffer_nodes = try loop.allocator.alloc(T, capacity);
errdefer loop.allocator.free(buffer_nodes);
- const self = try loop.allocator.create(SelfChannel{
+ const self = try loop.allocator.create(SelfChannel);
+ self.* = SelfChannel{
.loop = loop,
.buffer_len = 0,
.buffer_nodes = buffer_nodes,
@@ -66,7 +67,7 @@ pub fn Channel(comptime T: type) type {
.or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(),
.get_count = 0,
.put_count = 0,
- });
+ };
errdefer loop.allocator.destroy(self);
return self;
@@ -319,6 +320,9 @@ pub fn Channel(comptime T: type) type {
}
test "std.event.Channel" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/fs.zig b/std/event/fs.zig
index 1b8e1aa5dc0c19fe703fd62c4c9208150899e2a5..097f2beddcd3901aa4785f1956930400cec45452 100644
--- a/std/event/fs.zig
+++ b/std/event/fs.zig
@@ -495,7 +495,7 @@ pub const CloseOperation = struct {
};
pub fn start(loop: *Loop) (error{OutOfMemory}!*CloseOperation) {
- const self = try loop.allocator.createOne(CloseOperation);
+ const self = try loop.allocator.create(CloseOperation);
self.* = CloseOperation{
.loop = loop,
.os_data = switch (builtin.os) {
@@ -787,7 +787,7 @@ pub fn Watch(comptime V: type) type {
},
builtin.Os.windows => {
- const self = try loop.allocator.createOne(Self);
+ const self = try loop.allocator.create(Self);
errdefer loop.allocator.destroy(self);
self.* = Self{
.channel = channel,
@@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type {
},
builtin.Os.macosx, builtin.Os.freebsd => {
- const self = try loop.allocator.createOne(Self);
+ const self = try loop.allocator.create(Self);
errdefer loop.allocator.destroy(self);
self.* = Self{
@@ -1068,7 +1068,7 @@ pub fn Watch(comptime V: type) type {
}
} else {
errdefer _ = self.os_data.dir_table.remove(dirname);
- const dir = try self.channel.loop.allocator.createOne(OsData.Dir);
+ const dir = try self.channel.loop.allocator.create(OsData.Dir);
errdefer self.channel.loop.allocator.destroy(dir);
dir.* = OsData.Dir{
@@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type {
const test_tmp_dir = "std_event_fs_test";
-test "write a file, watch it, write it again" {
- if (builtin.os == builtin.Os.windows) {
- // TODO this test is disabled on windows until the coroutine rewrite is finished.
- // https://github.com/ziglang/zig/issues/1363
- return error.SkipZigTest;
- }
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- const allocator = &da.allocator;
-
- // TODO move this into event loop too
- try os.makePath(allocator, test_tmp_dir);
- defer os.deleteTree(allocator, test_tmp_dir) catch {};
-
- var loop: Loop = undefined;
- try loop.initMultiThreaded(allocator);
- defer loop.deinit();
-
- var result: anyerror!void = error.ResultNeverWritten;
- const handle = try async testFsWatchCantFail(&loop, &result);
- defer cancel handle;
-
- loop.run();
- return result;
-}
+// TODO this test is disabled until the coroutine rewrite is finished.
+//test "write a file, watch it, write it again" {
+// return error.SkipZigTest;
+// var da = std.heap.DirectAllocator.init();
+// defer da.deinit();
+//
+// const allocator = &da.allocator;
+//
+// // TODO move this into event loop too
+// try os.makePath(allocator, test_tmp_dir);
+// defer os.deleteTree(allocator, test_tmp_dir) catch {};
+//
+// var loop: Loop = undefined;
+// try loop.initMultiThreaded(allocator);
+// defer loop.deinit();
+//
+// var result: anyerror!void = error.ResultNeverWritten;
+// const handle = try async testFsWatchCantFail(&loop, &result);
+// defer cancel handle;
+//
+// loop.run();
+// return result;
+//}
async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
result.* = await (async testFsWatch(loop) catch unreachable);
diff --git a/std/event/future.zig b/std/event/future.zig
index d61768b1983164ca64873859186d8db3dc678060..55ed01046d030a859e3a0c5cbe16e32369590ea5 100644
--- a/std/event/future.zig
+++ b/std/event/future.zig
@@ -84,6 +84,9 @@ pub fn Future(comptime T: type) type {
}
test "std.event.Future" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/group.zig b/std/event/group.zig
index 9f2687a5b371a5ee43c07d6b5a90062783cf8360..7f6b5d953ba375c92667cd8e95288c2d544728ef 100644
--- a/std/event/group.zig
+++ b/std/event/group.zig
@@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type {
/// Add a promise to the group. Thread-safe.
pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
- const node = try self.lock.loop.allocator.create(Stack.Node{
+ const node = try self.lock.loop.allocator.create(Stack.Node);
+ node.* = Stack.Node{
.next = undefined,
.data = handle,
- });
+ };
self.alloc_stack.push(node);
}
@@ -121,6 +122,9 @@ pub fn Group(comptime ReturnType: type) type {
}
test "std.event.Group" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/lock.zig b/std/event/lock.zig
index 46e0d134680112e4b925823595ee3d66628fa9f5..01978e1909dde0aa4d8df71c59cfcfb666da945b 100644
--- a/std/event/lock.zig
+++ b/std/event/lock.zig
@@ -122,6 +122,9 @@ pub const Lock = struct {
};
test "std.event.Lock" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/loop.zig b/std/event/loop.zig
index 43965e8293acd09964a18b8849df757a518d2bf6..d5228db6047851418ee71c349aa8960d964d87e0 100644
--- a/std/event/loop.zig
+++ b/std/event/loop.zig
@@ -97,6 +97,7 @@ pub const Loop = struct {
/// TODO copy elision / named return values so that the threads referencing *Loop
/// have the correct pointer value.
pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
+ if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
const core_count = try os.cpuCount(allocator);
return self.initInternal(allocator, core_count);
}
@@ -201,6 +202,11 @@ pub const Loop = struct {
self.os_data.fs_thread.wait();
}
+ if (builtin.single_threaded) {
+ assert(extra_thread_count == 0);
+ return;
+ }
+
var extra_thread_index: usize = 0;
errdefer {
// writing 8 bytes to an eventfd cannot fail
@@ -301,6 +307,11 @@ pub const Loop = struct {
self.os_data.fs_thread.wait();
}
+ if (builtin.single_threaded) {
+ assert(extra_thread_count == 0);
+ return;
+ }
+
var extra_thread_index: usize = 0;
errdefer {
_ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;
@@ -338,6 +349,11 @@ pub const Loop = struct {
self.available_eventfd_resume_nodes.push(eventfd_node);
}
+ if (builtin.single_threaded) {
+ assert(extra_thread_count == 0);
+ return;
+ }
+
var extra_thread_index: usize = 0;
errdefer {
var i: usize = 0;
@@ -845,6 +861,9 @@ pub const Loop = struct {
};
test "std.event.Loop - basic" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
@@ -858,6 +877,9 @@ test "std.event.Loop - basic" {
}
test "std.event.Loop - call" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/event/net.zig b/std/event/net.zig
index 6838704084cfa9296260cfea20cbc1d40aec4d48..9dac6aa5661f3a164d978cbcb9e281b9b4043cd6 100644
--- a/std/event/net.zig
+++ b/std/event/net.zig
@@ -269,6 +269,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File {
}
test "listen on a port, send bytes, receive bytes" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
if (builtin.os != builtin.Os.linux) {
// TODO build abstractions for other operating systems
return error.SkipZigTest;
diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig
index 5d48ea893ebfe35b2648dc8caac11529cb33aa0e..f272ac71eaff04e6841b098820f452df9e5eadea 100644
--- a/std/event/rwlock.zig
+++ b/std/event/rwlock.zig
@@ -211,6 +211,9 @@ pub const RwLock = struct {
};
test "std.event.RwLock" {
+ // https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var da = std.heap.DirectAllocator.init();
defer da.deinit();
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
index b010072273b5a359ed8bf5d59dcc59507dad935d..6097a12c23e8f5e99a2b8359ad78a02f33c72324 100644
--- a/std/fmt/index.zig
+++ b/std/fmt/index.zig
@@ -982,13 +982,11 @@ test "fmt.format" {
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
res = buf1[0 .. buf1.len - context.remaining.len];
- debug.warn("{}\n", res);
assert(mem.eql(u8, res, "a"));
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
res = buf1[0 .. buf1.len - context.remaining.len];
- debug.warn("{}\n", res);
assert(mem.eql(u8, res, "1100"));
}
{
diff --git a/std/hash_map.zig b/std/hash_map.zig
index 99237047e008b0a42464f1c295babe9e44a191f1..a63a549814fbc17262a5adfb596db1a7cf5d9b56 100644
--- a/std/hash_map.zig
+++ b/std/hash_map.zig
@@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"),
builtin.TypeId.Array => @compileError("TODO auto hash for arrays"),
+ builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"),
builtin.TypeId.Struct => @compileError("TODO auto hash for structs"),
builtin.TypeId.Union => @compileError("TODO auto hash for unions"),
builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"),
@@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
builtin.TypeId.Struct => @compileError("TODO auto eql for structs"),
builtin.TypeId.Union => @compileError("TODO auto eql for unions"),
builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"),
+ builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"),
}
}
diff --git a/std/heap.zig b/std/heap.zig
index 46b247fa7eadf63e725260de9f911cc055085017..fd2ce1e965fa44382a4f4ac83ddfc34d6401ec50 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -518,7 +518,8 @@ fn testAllocator(allocator: *mem.Allocator) !void {
var slice = try allocator.alloc(*i32, 100);
assert(slice.len == 100);
for (slice) |*item, i| {
- item.* = try allocator.create(@intCast(i32, i));
+ item.* = try allocator.create(i32);
+ item.*.* = @intCast(i32, i);
}
slice = try allocator.realloc(*i32, slice, 20000);
diff --git a/std/index.zig b/std/index.zig
index 33eec14b0e58935dffcd40b81e2c025456ac29c1..80d1e46bb6cb069874d79f251f726b15e7cfbc5d 100644
--- a/std/index.zig
+++ b/std/index.zig
@@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
pub const HashMap = @import("hash_map.zig").HashMap;
pub const LinkedList = @import("linked_list.zig").LinkedList;
pub const Mutex = @import("mutex.zig").Mutex;
+pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
pub const SpinLock = @import("spinlock.zig").SpinLock;
@@ -55,6 +56,7 @@ test "std" {
_ = @import("hash_map.zig");
_ = @import("linked_list.zig");
_ = @import("mutex.zig");
+ _ = @import("statically_initialized_mutex.zig");
_ = @import("segmented_list.zig");
_ = @import("spinlock.zig");
diff --git a/std/io.zig b/std/io.zig
index 428d95725d2f433eedf0607f98c466a9c63a13a1..c8701aeda60d2d69c80bcfc4aa4e4ca1753c2349 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -8,6 +8,8 @@ const debug = std.debug;
const assert = debug.assert;
const os = std.os;
const mem = std.mem;
+const meta = std.meta;
+const trait = meta.trait;
const Buffer = std.Buffer;
const fmt = std.fmt;
const File = std.os.File;
@@ -463,6 +465,153 @@ pub const SliceInStream = struct {
}
};
+/// Creates a stream which allows for reading bit fields from another stream
+pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
+ return struct {
+ const Self = @This();
+
+ in_stream: *Stream,
+ bit_buffer: u7,
+ bit_count: u3,
+ stream: Stream,
+
+ pub const Stream = InStream(Error);
+ const u8_bit_count = comptime meta.bitCount(u8);
+ const u7_bit_count = comptime meta.bitCount(u7);
+ const u4_bit_count = comptime meta.bitCount(u4);
+
+ pub fn init(in_stream: *Stream) Self {
+ return Self{
+ .in_stream = in_stream,
+ .bit_buffer = 0,
+ .bit_count = 0,
+ .stream = Stream{ .readFn = read },
+ };
+ }
+
+ /// Reads `bits` bits from the stream and returns a specified unsigned int type
+ /// containing them in the least significant end, returning an error if the
+ /// specified number of bits could not be read.
+ pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
+ var n: usize = undefined;
+ const result = try self.readBits(U, bits, &n);
+ if (n < bits) return error.EndOfStream;
+ return result;
+ }
+
+ /// Reads `bits` bits from the stream and returns a specified unsigned int type
+ /// containing them in the least significant end. The number of bits successfully
+ /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
+ pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
+ comptime assert(trait.isUnsignedInt(U));
+
+ //by extending the buffer to a minimum of u8 we can cover a number of edge cases
+ // related to shifting and casting.
+ const u_bit_count = comptime meta.bitCount(U);
+ const buf_bit_count = bc: {
+ assert(u_bit_count >= bits);
+ break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
+ };
+ const Buf = @IntType(false, buf_bit_count);
+ const BufShift = math.Log2Int(Buf);
+
+ out_bits.* = usize(0);
+ if (U == u0 or bits == 0) return 0;
+ var out_buffer = Buf(0);
+
+ if (self.bit_count > 0) {
+ const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
+ const shift = u7_bit_count - n;
+ switch (endian) {
+ builtin.Endian.Big => {
+ out_buffer = Buf(self.bit_buffer >> shift);
+ self.bit_buffer <<= n;
+ },
+ builtin.Endian.Little => {
+ const value = (self.bit_buffer << shift) >> shift;
+ out_buffer = Buf(value);
+ self.bit_buffer >>= n;
+ },
+ }
+ self.bit_count -= n;
+ out_bits.* = n;
+ }
+ //at this point we know bit_buffer is empty
+
+ //copy bytes until we have enough bits, then leave the rest in bit_buffer
+ while (out_bits.* < bits) {
+ const n = bits - out_bits.*;
+ const next_byte = self.in_stream.readByte() catch |err| {
+ if (err == error.EndOfStream) {
+ return @intCast(U, out_buffer);
+ }
+ //@BUG: See #1810. Not sure if the bug is that I have to do this for some
+ // streams, or that I don't for streams with emtpy errorsets.
+ return @errSetCast(Error, err);
+ };
+
+ switch (endian) {
+ builtin.Endian.Big => {
+ if (n >= u8_bit_count) {
+ out_buffer <<= @intCast(u3, u8_bit_count - 1);
+ out_buffer <<= 1;
+ out_buffer |= Buf(next_byte);
+ out_bits.* += u8_bit_count;
+ continue;
+ }
+
+ const shift = @intCast(u3, u8_bit_count - n);
+ out_buffer <<= @intCast(BufShift, n);
+ out_buffer |= Buf(next_byte >> shift);
+ out_bits.* += n;
+ self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
+ self.bit_count = shift;
+ },
+ builtin.Endian.Little => {
+ if (n >= u8_bit_count) {
+ out_buffer |= Buf(next_byte) << @intCast(BufShift, out_bits.*);
+ out_bits.* += u8_bit_count;
+ continue;
+ }
+
+ const shift = @intCast(u3, u8_bit_count - n);
+ const value = (next_byte << shift) >> shift;
+ out_buffer |= Buf(value) << @intCast(BufShift, out_bits.*);
+ out_bits.* += n;
+ self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
+ self.bit_count = shift;
+ },
+ }
+ }
+
+ return @intCast(U, out_buffer);
+ }
+
+ pub fn alignToByte(self: *Self) void {
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+
+ pub fn read(self_stream: *Stream, buffer: []u8) Error!usize {
+ var self = @fieldParentPtr(Self, "stream", self_stream);
+
+ var out_bits: usize = undefined;
+ var out_bits_total = usize(0);
+ //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
+ if (self.bit_count > 0) {
+ for (buffer) |*b, i| {
+ b.* = try self.readBits(u8, u8_bit_count, &out_bits);
+ out_bits_total += out_bits;
+ }
+ const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
+ return (out_bits_total / u8_bit_count) + incomplete_byte;
+ }
+
+ return self.in_stream.read(buffer);
+ }
+ };
+}
+
/// This is a simple OutStream that writes to a slice, and returns an error
/// when it runs out of space.
pub const SliceOutStream = struct {
@@ -515,7 +664,7 @@ test "io.SliceOutStream" {
const stream = &slice_stream.stream;
try stream.print("{}{}!", "Hello", "World");
- debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten()));
+ debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten()));
}
var null_out_stream_state = NullOutStream.init();
@@ -577,7 +726,7 @@ test "io.CountingOutStream" {
const bytes = "yay" ** 10000;
stream.write(bytes) catch unreachable;
- debug.assert(counting_stream.bytes_written == bytes.len);
+ debug.assertOrPanic(counting_stream.bytes_written == bytes.len);
}
pub fn BufferedOutStream(comptime Error: type) type {
@@ -656,6 +805,137 @@ pub const BufferOutStream = struct {
}
};
+/// Creates a stream which allows for writing bit fields to another stream
+pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
+ return struct {
+ const Self = @This();
+
+ out_stream: *Stream,
+ bit_buffer: u8,
+ bit_count: u4,
+ stream: Stream,
+
+ pub const Stream = OutStream(Error);
+ const u8_bit_count = comptime meta.bitCount(u8);
+ const u4_bit_count = comptime meta.bitCount(u4);
+
+ pub fn init(out_stream: *Stream) Self {
+ return Self{
+ .out_stream = out_stream,
+ .bit_buffer = 0,
+ .bit_count = 0,
+ .stream = Stream{ .writeFn = write },
+ };
+ }
+
+ /// Write the specified number of bits to the stream from the least significant bits of
+ /// the specified unsigned int value. Bits will only be written to the stream when there
+ /// are enough to fill a byte.
+ pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
+ if (bits == 0) return;
+
+ const U = @typeOf(value);
+ comptime assert(trait.isUnsignedInt(U));
+
+ //by extending the buffer to a minimum of u8 we can cover a number of edge cases
+ // related to shifting and casting.
+ const u_bit_count = comptime meta.bitCount(U);
+ const buf_bit_count = bc: {
+ assert(u_bit_count >= bits);
+ break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
+ };
+ const Buf = @IntType(false, buf_bit_count);
+ const BufShift = math.Log2Int(Buf);
+
+ const buf_value = @intCast(Buf, value);
+
+ const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
+ var in_buffer = switch (endian) {
+ builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
+ builtin.Endian.Little => buf_value,
+ };
+ var in_bits = bits;
+
+ if (self.bit_count > 0) {
+ const bits_remaining = u8_bit_count - self.bit_count;
+ const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
+ switch (endian) {
+ builtin.Endian.Big => {
+ const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
+ const v = @intCast(u8, in_buffer >> shift);
+ self.bit_buffer |= v;
+ in_buffer <<= n;
+ },
+ builtin.Endian.Little => {
+ const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
+ self.bit_buffer |= v;
+ in_buffer >>= n;
+ },
+ }
+ self.bit_count += n;
+ in_bits -= n;
+
+ //if we didn't fill the buffer, it's because bits < bits_remaining;
+ if (self.bit_count != u8_bit_count) return;
+ try self.out_stream.writeByte(self.bit_buffer);
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+ //at this point we know bit_buffer is empty
+
+ //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
+ while (in_bits >= u8_bit_count) {
+ switch (endian) {
+ builtin.Endian.Big => {
+ const v = @intCast(u8, in_buffer >> high_byte_shift);
+ try self.out_stream.writeByte(v);
+ in_buffer <<= @intCast(u3, u8_bit_count - 1);
+ in_buffer <<= 1;
+ },
+ builtin.Endian.Little => {
+ const v = @truncate(u8, in_buffer);
+ try self.out_stream.writeByte(v);
+ in_buffer >>= @intCast(u3, u8_bit_count - 1);
+ in_buffer >>= 1;
+ },
+ }
+ in_bits -= u8_bit_count;
+ }
+
+ if (in_bits > 0) {
+ self.bit_count = @intCast(u4, in_bits);
+ self.bit_buffer = switch (endian) {
+ builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift),
+ builtin.Endian.Little => @truncate(u8, in_buffer),
+ };
+ }
+ }
+
+ /// Flush any remaining bits to the stream.
+ pub fn flushBits(self: *Self) !void {
+ if (self.bit_count == 0) return;
+ try self.out_stream.writeByte(self.bit_buffer);
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+
+ pub fn write(self_stream: *Stream, buffer: []const u8) Error!void {
+ var self = @fieldParentPtr(Self, "stream", self_stream);
+
+ //@NOTE: I'm not sure this is a good idea, maybe flushBits should be forced
+ if (self.bit_count > 0) {
+ for (buffer) |b, i|
+ try self.writeBits(b, u8_bit_count);
+ return;
+ }
+
+ return self.out_stream.write(buffer);
+ }
+ };
+}
+
+
+
pub const BufferedAtomicFile = struct {
atomic_file: os.AtomicFile,
file_stream: os.File.OutStream,
@@ -664,12 +944,13 @@ pub const BufferedAtomicFile = struct {
pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
// TODO with well defined copy elision we don't need this allocation
- var self = try allocator.create(BufferedAtomicFile{
+ var self = try allocator.create(BufferedAtomicFile);
+ self.* = BufferedAtomicFile{
.atomic_file = undefined,
.file_stream = undefined,
.buffered_stream = undefined,
.allocator = allocator,
- });
+ };
errdefer allocator.destroy(self);
self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode);
@@ -696,11 +977,6 @@ pub const BufferedAtomicFile = struct {
}
};
-test "import io tests" {
- comptime {
- _ = @import("io_test.zig");
- }
-}
pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn();
@@ -738,10 +1014,10 @@ test "io.readLineFrom" {
);
const stream = &mem_stream.stream;
- debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
- debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
+ debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
+ debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
- debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
+ debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
}
pub fn readLineSlice(slice: []u8) ![]u8 {
@@ -769,6 +1045,371 @@ test "io.readLineSliceFrom" {
);
const stream = &mem_stream.stream;
- debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
+ debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
}
+
+/// Creates a deserializer that deserializes types from any stream.
+/// If `is_packed` is true, the data stream is treated as bit-packed,
+/// otherwise data is expected to be packed to the smallest byte.
+/// Types may implement a custom deserialization routine with a
+/// function named `deserialize` in the form of:
+/// pub fn deserialize(self: *Self, deserializer: var) !void
+/// which will be called when the deserializer is used to deserialize
+/// that type. It will pass a pointer to the type instance to deserialize
+/// into and a pointer to the deserializer struct.
+pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type {
+ return struct {
+ const Self = @This();
+
+ in_stream: if (is_packed) BitInStream(endian, Stream.Error) else *Stream,
+
+ pub const Stream = InStream(Error);
+
+ pub fn init(in_stream: *Stream) Self {
+ return Self{ .in_stream = switch (is_packed) {
+ true => BitInStream(endian, Stream.Error).init(in_stream),
+ else => in_stream,
+ } };
+ }
+
+ pub fn alignToByte(self: *Self) void {
+ if(!is_packed) return;
+ self.in_stream.alignToByte();
+ }
+
+ //@BUG: inferred error issue. See: #1386
+ fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T {
+ comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
+
+ const u8_bit_count = 8;
+ const t_bit_count = comptime meta.bitCount(T);
+
+ const U = @IntType(false, t_bit_count);
+ const Log2U = math.Log2Int(U);
+ const int_size = @sizeOf(U);
+
+ if (is_packed) {
+ const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
+ return @bitCast(T, result);
+ }
+
+ var buffer: [int_size]u8 = undefined;
+ const read_size = try self.in_stream.read(buffer[0..]);
+ if (read_size < int_size) return error.EndOfStream;
+
+ if (int_size == 1) {
+ if (t_bit_count == 8) return @bitCast(T, buffer[0]);
+ const PossiblySignedByte = @IntType(T.is_signed, 8);
+ return @truncate(T, @bitCast(PossiblySignedByte, buffer[0]));
+ }
+
+ var result = U(0);
+ for (buffer) |byte, i| {
+ switch (endian) {
+ builtin.Endian.Big => {
+ result = (result << u8_bit_count) | byte;
+ },
+ builtin.Endian.Little => {
+ result |= U(byte) << @intCast(Log2U, u8_bit_count * i);
+ },
+ }
+ }
+
+ return @bitCast(T, result);
+ }
+
+ //@TODO: Replace this with @unionInit or whatever when it is added
+ // see: #1315
+ fn setTag(ptr: var, tag: var) void {
+ const T = @typeOf(ptr);
+ comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T));
+ const U = meta.Child(T);
+
+ const info = @typeInfo(U).Union;
+ if (info.tag_type) |TagType| {
+ comptime assert(TagType == @typeOf(tag));
+
+ var ptr_tag = ptr: {
+ if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr);
+ const offset = comptime max: {
+ var max_field_size: comptime_int = 0;
+ for (info.fields) |field_info| {
+ const field_size = @sizeOf(field_info.field_type);
+ max_field_size = math.max(max_field_size, field_size);
+ }
+ break :max math.max(max_field_size, @alignOf(U));
+ };
+ break :ptr @intToPtr(*TagType, @ptrToInt(ptr) + offset);
+ };
+ ptr_tag.* = tag;
+ }
+ }
+
+ /// Deserializes and returns data of the specified type from the stream
+ pub fn deserialize(self: *Self, comptime T: type) !T {
+ var value: T = undefined;
+ try self.deserializeInto(&value);
+ return value;
+ }
+
+ /// Deserializes data into the type pointed to by `ptr`
+ pub fn deserializeInto(self: *Self, ptr: var) !void {
+ const T = @typeOf(ptr);
+ comptime assert(trait.is(builtin.TypeId.Pointer)(T));
+
+ if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) {
+ for (ptr) |*v|
+ try self.deserializeInto(v);
+ return;
+ }
+
+ comptime assert(trait.isSingleItemPtr(T));
+
+ const C = comptime meta.Child(T);
+ const child_type_id = @typeId(C);
+
+ //custom deserializer: fn(self: *Self, deserializer: var) !void
+ if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);
+
+ if (comptime trait.isPacked(C) and !is_packed) {
+ var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream);
+ return packed_deserializer.deserializeInto(ptr);
+ }
+
+ switch (child_type_id) {
+ builtin.TypeId.Void => return,
+ builtin.TypeId.Bool => ptr.* = (try self.deserializeInt(u1)) > 0,
+ builtin.TypeId.Float, builtin.TypeId.Int => ptr.* = try self.deserializeInt(C),
+ builtin.TypeId.Struct => {
+ const info = @typeInfo(C).Struct;
+
+ inline for (info.fields) |*field_info| {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+
+ if (FieldType == void or FieldType == u0) continue;
+
+ //it doesn't make any sense to read pointers
+ if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) {
+ @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++
+ @typeName(C) ++ " because it " ++ "is of pointer-type " ++
+ @typeName(FieldType) ++ ".");
+ }
+
+ try self.deserializeInto(&@field(ptr, name));
+ }
+ },
+ builtin.TypeId.Union => {
+ const info = @typeInfo(C).Union;
+ if (info.tag_type) |TagType| {
+ //we avoid duplicate iteration over the enum tags
+ // by getting the int directly and casting it without
+ // safety. If it is bad, it will be caught anyway.
+ const TagInt = @TagType(TagType);
+ const tag = try self.deserializeInt(TagInt);
+
+ {
+ @setRuntimeSafety(false);
+ //See: #1315
+ setTag(ptr, @intToEnum(TagType, tag));
+ }
+
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == tag) {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+ @field(ptr, name) = FieldType(undefined);
+ try self.deserializeInto(&@field(ptr, name));
+ return;
+ }
+ }
+ //This is reachable if the enum data is bad
+ return error.InvalidEnumTag;
+ }
+ @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++
+ " because it is an untagged union Use a custom deserialize().");
+ },
+ builtin.TypeId.Optional => {
+ const OC = comptime meta.Child(C);
+ const exists = (try self.deserializeInt(u1)) > 0;
+ if (!exists) {
+ ptr.* = null;
+ return;
+ }
+
+ //The way non-pointer optionals are implemented ensures a pointer to them
+ // will point to the value. The flag is stored at the end of that data.
+ var val_ptr = @ptrCast(*OC, ptr);
+ try self.deserializeInto(val_ptr);
+ //This bit ensures the null flag isn't set. Any actual copying should be
+ // optimized out... I hope.
+ ptr.* = val_ptr.*;
+ },
+ builtin.TypeId.Enum => {
+ var value = try self.deserializeInt(@TagType(C));
+ ptr.* = try meta.intToEnum(C, value);
+ },
+ else => {
+ @compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented).");
+ },
+ }
+ }
+ };
+}
+
+/// Creates a serializer that serializes types to any stream.
+/// If `is_packed` is true, the data will be bit-packed into the stream.
+/// Note that the you must call `serializer.flush()` when you are done
+/// writing bit-packed data in order ensure any unwritten bits are committed.
+/// If `is_packed` is false, data is packed to the smallest byte. In the case
+/// of packed structs, the struct will written bit-packed and with the specified
+/// endianess, after which data will resume being written at the next byte boundary.
+/// Types may implement a custom serialization routine with a
+/// function named `serialize` in the form of:
+/// pub fn serialize(self: Self, serializer: var) !void
+/// which will be called when the serializer is used to serialize that type. It will
+/// pass a const pointer to the type instance to be serialized and a pointer
+/// to the serializer struct.
+pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type {
+ return struct {
+ const Self = @This();
+
+ out_stream: if (is_packed) BitOutStream(endian, Stream.Error) else *Stream,
+
+ pub const Stream = OutStream(Error);
+
+ pub fn init(out_stream: *Stream) Self {
+ return Self{ .out_stream = switch (is_packed) {
+ true => BitOutStream(endian, Stream.Error).init(out_stream),
+ else => out_stream,
+ } };
+ }
+
+ /// Flushes any unwritten bits to the stream
+ pub fn flush(self: *Self) Stream.Error!void {
+ if (is_packed) return self.out_stream.flushBits();
+ }
+
+ fn serializeInt(self: *Self, value: var) !void {
+ const T = @typeOf(value);
+ comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
+
+ const t_bit_count = comptime meta.bitCount(T);
+ const u8_bit_count = comptime meta.bitCount(u8);
+
+ const U = @IntType(false, t_bit_count);
+ const Log2U = math.Log2Int(U);
+ const int_size = @sizeOf(U);
+
+ const u_value = @bitCast(U, value);
+
+ if (is_packed) return self.out_stream.writeBits(u_value, t_bit_count);
+
+ var buffer: [int_size]u8 = undefined;
+ if (int_size == 1) buffer[0] = u_value;
+
+ for (buffer) |*byte, i| {
+ const idx = switch (endian) {
+ builtin.Endian.Big => int_size - i - 1,
+ builtin.Endian.Little => i,
+ };
+ const shift = @intCast(Log2U, idx * u8_bit_count);
+ const v = u_value >> shift;
+ byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);
+ }
+
+ try self.out_stream.write(buffer);
+ }
+
+ /// Serializes the passed value into the stream
+ pub fn serialize(self: *Self, value: var) !void {
+ const T = comptime @typeOf(value);
+
+ if (comptime trait.isIndexable(T)) {
+ for (value) |v|
+ try self.serialize(v);
+ return;
+ }
+
+ //custom serializer: fn(self: Self, serializer: var) !void
+ if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);
+
+ if (comptime trait.isPacked(T) and !is_packed) {
+ var packed_serializer = Serializer(endian, true, Error).init(self.out_stream);
+ try packed_serializer.serialize(value);
+ try packed_serializer.flush();
+ return;
+ }
+
+ switch (@typeId(T)) {
+ builtin.TypeId.Void => return,
+ builtin.TypeId.Bool => try self.serializeInt(u1(@boolToInt(value))),
+ builtin.TypeId.Float, builtin.TypeId.Int => try self.serializeInt(value),
+ builtin.TypeId.Struct => {
+ const info = @typeInfo(T);
+
+ inline for (info.Struct.fields) |*field_info| {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+
+ if (FieldType == void or FieldType == u0) continue;
+
+ //It doesn't make sense to write pointers
+ if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) {
+ @compileError("Will not " ++ "serialize field " ++ name ++
+ " of struct " ++ @typeName(T) ++ " because it " ++
+ "is of pointer-type " ++ @typeName(FieldType) ++ ".");
+ }
+ try self.serialize(@field(value, name));
+ }
+ },
+ builtin.TypeId.Union => {
+ const info = @typeInfo(T).Union;
+ if (info.tag_type) |TagType| {
+ const active_tag = meta.activeTag(value);
+ try self.serialize(active_tag);
+ //This inline loop is necessary because active_tag is a runtime
+ // value, but @field requires a comptime value. Our alternative
+ // is to check each field for a match
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+ try self.serialize(@field(value, name));
+ return;
+ }
+ }
+ unreachable;
+ }
+ @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++
+ " because it is an untagged union Use a custom serialize().");
+ },
+ builtin.TypeId.Optional => {
+ if (value == null) {
+ try self.serializeInt(u1(@boolToInt(false)));
+ return;
+ }
+ try self.serializeInt(u1(@boolToInt(true)));
+
+ const OC = comptime meta.Child(T);
+
+ //The way non-pointer optionals are implemented ensures a pointer to them
+ // will point to the value. The flag is stored at the end of that data.
+ var val_ptr = @ptrCast(*const OC, &value);
+ try self.serialize(val_ptr.*);
+ },
+ builtin.TypeId.Enum => {
+ try self.serializeInt(@enumToInt(value));
+ },
+ else => @compileError("Cannot serialize " ++ @tagName(@typeId(T)) ++ " types (unimplemented)."),
+ }
+ }
+ };
+}
+
+test "import io tests" {
+ comptime {
+ _ = @import("io_test.zig");
+ }
+}
diff --git a/std/io_test.zig b/std/io_test.zig
index 52241995275ece21ffae0add6aad535c7b30e988..0bee0ddaf0c2f8fe146d08e011c7c2b6550b8859 100644
--- a/std/io_test.zig
+++ b/std/io_test.zig
@@ -1,5 +1,7 @@
const std = @import("index.zig");
const io = std.io;
+const meta = std.meta;
+const trait = std.trait;
const DefaultPrng = std.rand.DefaultPrng;
const assert = std.debug.assert;
const assertError = std.debug.assertError;
@@ -132,3 +134,438 @@ test "SliceOutStream" {
assertError(ss.stream.write("Hello world!"), error.OutOfSpace);
assert(mem.eql(u8, ss.getWritten(), "Hello worl"));
}
+
+test "BitInStream" {
+ const mem_be = []u8{ 0b11001101, 0b00001011 };
+ const mem_le = []u8{ 0b00011101, 0b10010101 };
+
+ var mem_in_be = io.SliceInStream.init(mem_be[0..]);
+ const InError = io.SliceInStream.Error;
+ var bit_stream_be = io.BitInStream(builtin.Endian.Big, InError).init(&mem_in_be.stream);
+
+ var out_bits: usize = undefined;
+
+ assert(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
+ assert(out_bits == 1);
+ assert(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
+ assert(out_bits == 2);
+ assert(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
+ assert(out_bits == 3);
+ assert(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
+ assert(out_bits == 4);
+ assert(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
+ assert(out_bits == 5);
+ assert(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
+ assert(out_bits == 1);
+
+ mem_in_be.pos = 0;
+ bit_stream_be.bit_count = 0;
+ assert(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
+ assert(out_bits == 15);
+
+ mem_in_be.pos = 0;
+ bit_stream_be.bit_count = 0;
+ assert(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
+ assert(out_bits == 16);
+
+ _ = try bit_stream_be.readBits(u0, 0, &out_bits);
+
+ assert(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
+ assert(out_bits == 0);
+ assertError(bit_stream_be.readBitsNoEof(u1, 1), error.EndOfStream);
+
+ var mem_in_le = io.SliceInStream.init(mem_le[0..]);
+ var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream);
+
+ assert(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
+ assert(out_bits == 1);
+ assert(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
+ assert(out_bits == 2);
+ assert(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
+ assert(out_bits == 3);
+ assert(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
+ assert(out_bits == 4);
+ assert(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
+ assert(out_bits == 5);
+ assert(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
+ assert(out_bits == 1);
+
+ mem_in_le.pos = 0;
+ bit_stream_le.bit_count = 0;
+ assert(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
+ assert(out_bits == 15);
+
+ mem_in_le.pos = 0;
+ bit_stream_le.bit_count = 0;
+ assert(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
+ assert(out_bits == 16);
+
+ _ = try bit_stream_le.readBits(u0, 0, &out_bits);
+
+ assert(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
+ assert(out_bits == 0);
+ assertError(bit_stream_le.readBitsNoEof(u1, 1), error.EndOfStream);
+}
+
+test "BitOutStream" {
+ var mem_be = []u8{0} ** 2;
+ var mem_le = []u8{0} ** 2;
+
+ var mem_out_be = io.SliceOutStream.init(mem_be[0..]);
+ const OutError = io.SliceOutStream.Error;
+ var bit_stream_be = io.BitOutStream(builtin.Endian.Big, OutError).init(&mem_out_be.stream);
+
+ try bit_stream_be.writeBits(u2(1), 1);
+ try bit_stream_be.writeBits(u5(2), 2);
+ try bit_stream_be.writeBits(u128(3), 3);
+ try bit_stream_be.writeBits(u8(4), 4);
+ try bit_stream_be.writeBits(u9(5), 5);
+ try bit_stream_be.writeBits(u1(1), 1);
+
+ assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
+
+ mem_out_be.pos = 0;
+
+ try bit_stream_be.writeBits(u15(0b110011010000101), 15);
+ try bit_stream_be.flushBits();
+ assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
+
+ mem_out_be.pos = 0;
+ try bit_stream_be.writeBits(u32(0b110011010000101), 16);
+ assert(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
+
+ try bit_stream_be.writeBits(u0(0), 0);
+
+ var mem_out_le = io.SliceOutStream.init(mem_le[0..]);
+ var bit_stream_le = io.BitOutStream(builtin.Endian.Little, OutError).init(&mem_out_le.stream);
+
+ try bit_stream_le.writeBits(u2(1), 1);
+ try bit_stream_le.writeBits(u5(2), 2);
+ try bit_stream_le.writeBits(u128(3), 3);
+ try bit_stream_le.writeBits(u8(4), 4);
+ try bit_stream_le.writeBits(u9(5), 5);
+ try bit_stream_le.writeBits(u1(1), 1);
+
+ assert(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
+
+ mem_out_le.pos = 0;
+ try bit_stream_le.writeBits(u15(0b110011010000101), 15);
+ try bit_stream_le.flushBits();
+ assert(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
+
+ mem_out_le.pos = 0;
+ try bit_stream_le.writeBits(u32(0b1100110100001011), 16);
+ assert(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
+
+ try bit_stream_le.writeBits(u0(0), 0);
+}
+
+test "BitStreams with File Stream" {
+ const tmp_file_name = "temp_test_file.txt";
+ {
+ var file = try os.File.openWrite(tmp_file_name);
+ defer file.close();
+
+ var file_out = file.outStream();
+ var file_out_stream = &file_out.stream;
+ const OutError = os.File.WriteError;
+ var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);
+
+ try bit_stream.writeBits(u2(1), 1);
+ try bit_stream.writeBits(u5(2), 2);
+ try bit_stream.writeBits(u128(3), 3);
+ try bit_stream.writeBits(u8(4), 4);
+ try bit_stream.writeBits(u9(5), 5);
+ try bit_stream.writeBits(u1(1), 1);
+ try bit_stream.flushBits();
+ }
+ {
+ var file = try os.File.openRead(tmp_file_name);
+ defer file.close();
+
+ var file_in = file.inStream();
+ var file_in_stream = &file_in.stream;
+ const InError = os.File.ReadError;
+ var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);
+
+ var out_bits: usize = undefined;
+
+ assert(1 == try bit_stream.readBits(u2, 1, &out_bits));
+ assert(out_bits == 1);
+ assert(2 == try bit_stream.readBits(u5, 2, &out_bits));
+ assert(out_bits == 2);
+ assert(3 == try bit_stream.readBits(u128, 3, &out_bits));
+ assert(out_bits == 3);
+ assert(4 == try bit_stream.readBits(u8, 4, &out_bits));
+ assert(out_bits == 4);
+ assert(5 == try bit_stream.readBits(u9, 5, &out_bits));
+ assert(out_bits == 5);
+ assert(1 == try bit_stream.readBits(u1, 1, &out_bits));
+ assert(out_bits == 1);
+
+ assertError(bit_stream.readBitsNoEof(u1, 1), error.EndOfStream);
+ }
+ try os.deleteFile(tmp_file_name);
+}
+
+fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
+ //@NOTE: if this test is taking too long, reduce the maximum tested bitsize
+ const max_test_bitsize = 128;
+
+ const total_bytes = comptime blk: {
+ var bytes = 0;
+ comptime var i = 0;
+ while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0);
+ break :blk bytes * 2;
+ };
+
+ var data_mem: [total_bytes]u8 = undefined;
+ var out = io.SliceOutStream.init(data_mem[0..]);
+ const OutError = io.SliceOutStream.Error;
+ var out_stream = &out.stream;
+ var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
+
+ var in = io.SliceInStream.init(data_mem[0..]);
+ const InError = io.SliceInStream.Error;
+ var in_stream = &in.stream;
+ var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
+
+ comptime var i = 0;
+ inline while (i <= max_test_bitsize) : (i += 1) {
+ const U = @IntType(false, i);
+ const S = @IntType(true, i);
+ try serializer.serializeInt(U(i));
+ if (i != 0) try serializer.serializeInt(S(-1)) else try serializer.serialize(S(0));
+ }
+ try serializer.flush();
+
+ i = 0;
+ inline while (i <= max_test_bitsize) : (i += 1) {
+ const U = @IntType(false, i);
+ const S = @IntType(true, i);
+ const x = try deserializer.deserializeInt(U);
+ const y = try deserializer.deserializeInt(S);
+ assert(x == U(i));
+ if (i != 0) assert(y == S(-1)) else assert(y == 0);
+ }
+
+ const u8_bit_count = comptime meta.bitCount(u8);
+ //0 + 1 + 2 + ... n = (n * (n + 1)) / 2
+ //and we have each for unsigned and signed, so * 2
+ const total_bits = (max_test_bitsize * (max_test_bitsize + 1));
+ const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);
+ const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
+
+ assert(in.pos == if (is_packed) total_packed_bytes else total_bytes);
+}
+
+test "Serializer/Deserializer Int" {
+ try testIntSerializerDeserializer(builtin.Endian.Big, false);
+ try testIntSerializerDeserializer(builtin.Endian.Little, false);
+ try testIntSerializerDeserializer(builtin.Endian.Big, true);
+ try testIntSerializerDeserializer(builtin.Endian.Little, true);
+}
+
+fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian,
+ comptime is_packed: bool) !void
+{
+ const mem_size = (16*2 + 32*2 + 64*2 + 128*2) / comptime meta.bitCount(u8);
+ var data_mem: [mem_size]u8 = undefined;
+
+ var out = io.SliceOutStream.init(data_mem[0..]);
+ const OutError = io.SliceOutStream.Error;
+ var out_stream = &out.stream;
+ var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
+
+ var in = io.SliceInStream.init(data_mem[0..]);
+ const InError = io.SliceInStream.Error;
+ var in_stream = &in.stream;
+ var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
+
+ //@TODO: isInf/isNan not currently implemented for f128.
+ try serializer.serialize(std.math.nan(f16));
+ try serializer.serialize(std.math.inf(f16));
+ try serializer.serialize(std.math.nan(f32));
+ try serializer.serialize(std.math.inf(f32));
+ try serializer.serialize(std.math.nan(f64));
+ try serializer.serialize(std.math.inf(f64));
+ //try serializer.serialize(std.math.nan(f128));
+ //try serializer.serialize(std.math.inf(f128));
+ const nan_check_f16 = try deserializer.deserialize(f16);
+ const inf_check_f16 = try deserializer.deserialize(f16);
+ const nan_check_f32 = try deserializer.deserialize(f32);
+ const inf_check_f32 = try deserializer.deserialize(f32);
+ const nan_check_f64 = try deserializer.deserialize(f64);
+ const inf_check_f64 = try deserializer.deserialize(f64);
+ //const nan_check_f128 = try deserializer.deserialize(f128);
+ //const inf_check_f128 = try deserializer.deserialize(f128);
+ assert(std.math.isNan(nan_check_f16));
+ assert(std.math.isInf(inf_check_f16));
+ assert(std.math.isNan(nan_check_f32));
+ assert(std.math.isInf(inf_check_f32));
+ assert(std.math.isNan(nan_check_f64));
+ assert(std.math.isInf(inf_check_f64));
+ //assert(std.math.isNan(nan_check_f128));
+ //assert(std.math.isInf(inf_check_f128));
+}
+
+test "Serializer/Deserializer Int: Inf/NaN" {
+ try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, false);
+ try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, false);
+ try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, true);
+ try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true);
+}
+
+fn testAlternateSerializer(self: var, serializer: var) !void {
+ try serializer.serialize(self.f_f16);
+}
+
+fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
+ const ColorType = enum(u4) {
+ RGB8 = 1,
+ RA16 = 2,
+ R32 = 3,
+ };
+
+ const TagAlign = union(enum(u32)) {
+ A: u8,
+ B: u8,
+ C: u8,
+ };
+
+ const Color = union(ColorType) {
+ RGB8: struct {
+ r: u8,
+ g: u8,
+ b: u8,
+ a: u8,
+ },
+ RA16: struct {
+ r: u16,
+ a: u16,
+ },
+ R32: u32,
+ };
+
+ const PackedStruct = packed struct {
+ f_i3: i3,
+ f_u2: u2,
+ };
+
+
+
+ //to test custom serialization
+ const Custom = struct {
+ f_f16: f16,
+ f_unused_u32: u32,
+
+ pub fn deserialize(self: *@This(), deserializer: var) !void {
+ try deserializer.deserializeInto(&self.f_f16);
+ self.f_unused_u32 = 47;
+ }
+
+ pub const serialize = testAlternateSerializer;
+ };
+
+ const MyStruct = struct {
+ f_i3: i3,
+ f_u8: u8,
+ f_tag_align: TagAlign,
+ f_u24: u24,
+ f_i19: i19,
+ f_void: void,
+ f_f32: f32,
+ f_f128: f128,
+ f_packed_0: PackedStruct,
+ f_i7arr: [10]i7,
+ f_of64n: ?f64,
+ f_of64v: ?f64,
+ f_color_type: ColorType,
+ f_packed_1: PackedStruct,
+ f_custom: Custom,
+ f_color: Color,
+ };
+
+ const my_inst = MyStruct{
+ .f_i3 = -1,
+ .f_u8 = 8,
+ .f_tag_align = TagAlign{ .B = 148 },
+ .f_u24 = 24,
+ .f_i19 = 19,
+ .f_void = {},
+ .f_f32 = 32.32,
+ .f_f128 = 128.128,
+ .f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 },
+ .f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ .f_of64n = null,
+ .f_of64v = 64.64,
+ .f_color_type = ColorType.R32,
+ .f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 },
+ .f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 },
+ .f_color = Color{ .R32 = 123822 },
+ };
+
+ var data_mem: [@sizeOf(MyStruct)]u8 = undefined;
+ var out = io.SliceOutStream.init(data_mem[0..]);
+ const OutError = io.SliceOutStream.Error;
+ var out_stream = &out.stream;
+ var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
+
+ var in = io.SliceInStream.init(data_mem[0..]);
+ const InError = io.SliceInStream.Error;
+ var in_stream = &in.stream;
+ var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
+
+ try serializer.serialize(my_inst);
+
+ const my_copy = try deserializer.deserialize(MyStruct);
+ assert(meta.eql(my_copy, my_inst));
+}
+
+test "Serializer/Deserializer generic" {
+ try testSerializerDeserializer(builtin.Endian.Big, false);
+ try testSerializerDeserializer(builtin.Endian.Little, false);
+ try testSerializerDeserializer(builtin.Endian.Big, true);
+ try testSerializerDeserializer(builtin.Endian.Little, true);
+}
+
+fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
+ const E = enum(u14) {
+ One = 1,
+ Two = 2,
+ };
+
+ const A = struct {
+ e: E,
+ };
+
+ const C = union(E) {
+ One: u14,
+ Two: f16,
+ };
+
+ var data_mem: [4]u8 = undefined;
+ var out = io.SliceOutStream.init(data_mem[0..]);
+ const OutError = io.SliceOutStream.Error;
+ var out_stream = &out.stream;
+ var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
+
+ var in = io.SliceInStream.init(data_mem[0..]);
+ const InError = io.SliceInStream.Error;
+ var in_stream = &in.stream;
+ var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
+
+ try serializer.serialize(u14(3));
+ assertError(deserializer.deserialize(A), error.InvalidEnumTag);
+ out.pos = 0;
+ try serializer.serialize(u14(3));
+ try serializer.serialize(u14(88));
+ assertError(deserializer.deserialize(C), error.InvalidEnumTag);
+}
+
+test "Deserializer bad data" {
+ try testBadData(builtin.Endian.Big, false);
+ try testBadData(builtin.Endian.Little, false);
+ try testBadData(builtin.Endian.Big, true);
+ try testBadData(builtin.Endian.Little, true);
+}
\ No newline at end of file
diff --git a/std/linked_list.zig b/std/linked_list.zig
index c3db55b5a67cebf94d7bd3238c859bc6852538bf..7021cac70752ed4c2c96e695c90d2069021efc5d 100644
--- a/std/linked_list.zig
+++ b/std/linked_list.zig
@@ -190,7 +190,7 @@ pub fn LinkedList(comptime T: type) type {
/// Returns:
/// A pointer to the new node.
pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
- return allocator.create(Node(undefined));
+ return allocator.create(Node);
}
/// Deallocate a node.
diff --git a/std/mem.zig b/std/mem.zig
index fb5f6fd5da62cd402f856c1c87c08aebd4ab0c14..26ae4ef089626223bdabebfa20a7005f4eb81d09 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -36,20 +36,9 @@ pub const Allocator = struct {
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
freeFn: fn (self: *Allocator, old_mem: []u8) void,
- /// Call `destroy` with the result
- /// TODO this is deprecated. use createOne instead
- pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {
- const T = @typeOf(init);
- if (@sizeOf(T) == 0) return &(T{});
- const slice = try self.alloc(T, 1);
- const ptr = &slice[0];
- ptr.* = init;
- return ptr;
- }
-
/// Call `destroy` with the result.
/// Returns undefined memory.
- pub fn createOne(self: *Allocator, comptime T: type) Error!*T {
+ pub fn create(self: *Allocator, comptime T: type) Error!*T {
if (@sizeOf(T) == 0) return &(T{});
const slice = try self.alloc(T, 1);
return &slice[0];
@@ -700,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
}
/// Returns an iterator that iterates over the slices of `buffer` that are not
-/// any of the bytes in `split_bytes`.
-/// split(" abc def ghi ", " ")
+/// any of the bytes in `delimiter_bytes`.
+/// tokenize(" abc def ghi ", " ")
/// Will return slices for "abc", "def", "ghi", null, in that order.
-pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
+/// If `buffer` is empty, the iterator will return null.
+/// If `delimiter_bytes` does not exist in buffer,
+/// the iterator will return `buffer`, null, in that order.
+/// See also the related function `separate`.
+pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator {
+ return TokenIterator{
+ .index = 0,
+ .buffer = buffer,
+ .delimiter_bytes = delimiter_bytes,
+ };
+}
+
+test "mem.tokenize" {
+ var it = tokenize(" abc def ghi ", " ");
+ assert(eql(u8, it.next().?, "abc"));
+ assert(eql(u8, it.next().?, "def"));
+ assert(eql(u8, it.next().?, "ghi"));
+ assert(it.next() == null);
+
+ it = tokenize("..\\bob", "\\");
+ assert(eql(u8, it.next().?, ".."));
+ assert(eql(u8, "..", "..\\bob"[0..it.index]));
+ assert(eql(u8, it.next().?, "bob"));
+ assert(it.next() == null);
+
+ it = tokenize("//a/b", "/");
+ assert(eql(u8, it.next().?, "a"));
+ assert(eql(u8, it.next().?, "b"));
+ assert(eql(u8, "//a/b", "//a/b"[0..it.index]));
+ assert(it.next() == null);
+
+ it = tokenize("|", "|");
+ assert(it.next() == null);
+
+ it = tokenize("", "|");
+ assert(it.next() == null);
+
+ it = tokenize("hello", "");
+ assert(eql(u8, it.next().?, "hello"));
+ assert(it.next() == null);
+
+ it = tokenize("hello", " ");
+ assert(eql(u8, it.next().?, "hello"));
+ assert(it.next() == null);
+}
+
+test "mem.tokenize (multibyte)" {
+ var it = tokenize("a|b,c/d e", " /,|");
+ assert(eql(u8, it.next().?, "a"));
+ assert(eql(u8, it.next().?, "b"));
+ assert(eql(u8, it.next().?, "c"));
+ assert(eql(u8, it.next().?, "d"));
+ assert(eql(u8, it.next().?, "e"));
+ assert(it.next() == null);
+}
+
+/// Returns an iterator that iterates over the slices of `buffer` that
+/// are separated by bytes in `delimiter`.
+/// separate("abc|def||ghi", "|")
+/// will return slices for "abc", "def", "", "ghi", null, in that order.
+/// If `delimiter` does not exist in buffer,
+/// the iterator will return `buffer`, null, in that order.
+/// The delimiter length must not be zero.
+/// See also the related function `tokenize`.
+/// It is planned to rename this function to `split` before 1.0.0, like this:
+/// pub fn split(buffer: []const u8, delimiter: []const u8) SplitIterator {
+pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator {
+ assert(delimiter.len != 0);
return SplitIterator{
.index = 0,
.buffer = buffer,
- .split_bytes = split_bytes,
+ .delimiter = delimiter,
};
}
-test "mem.split" {
- var it = split(" abc def ghi ", " ");
+test "mem.separate" {
+ var it = separate("abc|def||ghi", "|");
assert(eql(u8, it.next().?, "abc"));
assert(eql(u8, it.next().?, "def"));
+ assert(eql(u8, it.next().?, ""));
assert(eql(u8, it.next().?, "ghi"));
assert(it.next() == null);
+
+ it = separate("", "|");
+ assert(eql(u8, it.next().?, ""));
+ assert(it.next() == null);
+
+ it = separate("|", "|");
+ assert(eql(u8, it.next().?, ""));
+ assert(eql(u8, it.next().?, ""));
+ assert(it.next() == null);
+
+ it = separate("hello", " ");
+ assert(eql(u8, it.next().?, "hello"));
+ assert(it.next() == null);
+}
+
+test "mem.separate (multibyte)" {
+ var it = separate("a, b ,, c, d, e", ", ");
+ assert(eql(u8, it.next().?, "a"));
+ assert(eql(u8, it.next().?, "b ,"));
+ assert(eql(u8, it.next().?, "c"));
+ assert(eql(u8, it.next().?, "d"));
+ assert(eql(u8, it.next().?, "e"));
+ assert(it.next() == null);
}
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
@@ -737,12 +817,13 @@ test "mem.endsWith" {
assert(!endsWith(u8, "Bob", "Bo"));
}
-pub const SplitIterator = struct {
+pub const TokenIterator = struct {
buffer: []const u8,
- split_bytes: []const u8,
+ delimiter_bytes: []const u8,
index: usize,
- pub fn next(self: *SplitIterator) ?[]const u8 {
+ /// Returns a slice of the next token, or null if tokenization is complete.
+ pub fn next(self: *TokenIterator) ?[]const u8 {
// move to beginning of token
while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
const start = self.index;
@@ -758,16 +839,16 @@ pub const SplitIterator = struct {
}
/// Returns a slice of the remaining bytes. Does not affect iterator state.
- pub fn rest(self: *const SplitIterator) []const u8 {
+ pub fn rest(self: TokenIterator) []const u8 {
// move to beginning of token
var index: usize = self.index;
while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {}
return self.buffer[index..];
}
- fn isSplitByte(self: *const SplitIterator, byte: u8) bool {
- for (self.split_bytes) |split_byte| {
- if (byte == split_byte) {
+ fn isSplitByte(self: TokenIterator, byte: u8) bool {
+ for (self.delimiter_bytes) |delimiter_byte| {
+ if (byte == delimiter_byte) {
return true;
}
}
@@ -775,6 +856,32 @@ pub const SplitIterator = struct {
}
};
+pub const SplitIterator = struct {
+ buffer: []const u8,
+ index: ?usize,
+ delimiter: []const u8,
+
+ /// Returns a slice of the next field, or null if splitting is complete.
+ pub fn next(self: *SplitIterator) ?[]const u8 {
+ const start = self.index orelse return null;
+ const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: {
+ self.index = delim_start + self.delimiter.len;
+ break :blk delim_start;
+ } else blk: {
+ self.index = null;
+ break :blk self.buffer.len;
+ };
+ return self.buffer[start..end];
+ }
+
+ /// Returns a slice of the remaining bytes. Does not affect iterator state.
+ pub fn rest(self: SplitIterator) []const u8 {
+ const end = self.buffer.len;
+ const start = self.index orelse end;
+ return self.buffer[start..end];
+ }
+};
+
/// Naively combines a series of strings with a separator.
/// Allocates memory for the result, which must be freed by the caller.
pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {
diff --git a/std/meta/index.zig b/std/meta/index.zig
index 69a30972888712272e435cd6d2da61e4c1aa51fc..4d195a6a12ac53f8a8e31151dbe5b4b352b0d62c 100644
--- a/std/meta/index.zig
+++ b/std/meta/index.zig
@@ -95,7 +95,7 @@ test "std.meta.stringToEnum" {
debug.assert(null == stringToEnum(E1, "C"));
}
-pub fn bitCount(comptime T: type) u32 {
+pub fn bitCount(comptime T: type) comptime_int {
return switch (@typeInfo(T)) {
TypeId.Int => |info| info.bits,
TypeId.Float => |info| info.bits,
@@ -108,7 +108,7 @@ test "std.meta.bitCount" {
debug.assert(bitCount(f32) == 32);
}
-pub fn alignment(comptime T: type) u29 {
+pub fn alignment(comptime T: type) comptime_int {
//@alignOf works on non-pointer types
const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
return @typeInfo(P).Pointer.alignment;
@@ -386,6 +386,33 @@ test "std.meta.activeTag" {
debug.assert(activeTag(u) == UE.Float);
}
+///Given a tagged union type, and an enum, return the type of the union
+/// field corresponding to the enum tag.
+pub fn TagPayloadType(comptime U: type, tag: var) type {
+ const Tag = @typeOf(tag);
+ debug.assert(trait.is(builtin.TypeId.Union)(U));
+ debug.assert(trait.is(builtin.TypeId.Enum)(Tag));
+
+ const info = @typeInfo(U).Union;
+
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
+ }
+ unreachable;
+}
+
+test "std.meta.TagPayloadType" {
+ const Event = union(enum) {
+ Moved: struct {
+ from: i32,
+ to: i32,
+ },
+ };
+ const MovedEvent = TagPayloadType(Event, Event.Moved);
+ var e: Event = undefined;
+ debug.assert(MovedEvent == @typeOf(e.Moved));
+}
+
///Compares two of any type for equality. Containers are compared on a field-by-field basis,
/// where possible. Pointers are not followed.
pub fn eql(a: var, b: @typeOf(a)) bool {
@@ -439,6 +466,11 @@ pub fn eql(a: var, b: @typeOf(a)) bool {
builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
}
},
+ builtin.TypeId.Optional => {
+ if(a == null and b == null) return true;
+ if(a == null or b == null) return false;
+ return eql(a.?, b.?);
+ },
else => return a == b,
}
}
@@ -452,7 +484,7 @@ test "std.meta.eql" {
const U = union(enum) {
s: S,
- f: f32,
+ f: ?f32,
};
const s_1 = S{
diff --git a/std/meta/trait.zig b/std/meta/trait.zig
index caf7f1be04447740e86fac9f8f504a75340477c1..c9d9e971c9f78562820d30fd4d29fb7c30e68ef3 100644
--- a/std/meta/trait.zig
+++ b/std/meta/trait.zig
@@ -231,6 +231,37 @@ test "std.meta.trait.isPacked" {
debug.assert(!isPacked(u8));
}
+///
+pub fn isUnsignedInt(comptime T: type) bool {
+ return switch (@typeId(T)) {
+ builtin.TypeId.Int => !@typeInfo(T).Int.is_signed,
+ else => false,
+ };
+}
+
+test "isUnsignedInt" {
+ debug.assert(isUnsignedInt(u32) == true);
+ debug.assert(isUnsignedInt(comptime_int) == false);
+ debug.assert(isUnsignedInt(i64) == false);
+ debug.assert(isUnsignedInt(f64) == false);
+}
+
+///
+pub fn isSignedInt(comptime T: type) bool {
+ return switch (@typeId(T)) {
+ builtin.TypeId.ComptimeInt => true,
+ builtin.TypeId.Int => @typeInfo(T).Int.is_signed,
+ else => false,
+ };
+}
+
+test "isSignedInt" {
+ debug.assert(isSignedInt(u32) == false);
+ debug.assert(isSignedInt(comptime_int) == true);
+ debug.assert(isSignedInt(i64) == true);
+ debug.assert(isSignedInt(f64) == false);
+}
+
///
pub fn isSingleItemPtr(comptime T: type) bool {
if (comptime is(builtin.TypeId.Pointer)(T)) {
diff --git a/std/mutex.zig b/std/mutex.zig
index e35bd81bc43250c9691463270d8f15a7d5072be3..54173fa38ad167114693d6a595eac7f92e250a4c 100644
--- a/std/mutex.zig
+++ b/std/mutex.zig
@@ -5,74 +5,124 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
const assert = std.debug.assert;
const SpinLock = std.SpinLock;
const linux = std.os.linux;
+const windows = std.os.windows;
/// Lock may be held only once. If the same thread
/// tries to acquire the same mutex twice, it deadlocks.
+/// This type must be initialized at runtime, and then deinitialized when no
+/// longer needed, to free resources.
+/// If you need static initialization, use std.StaticallyInitializedMutex.
/// The Linux implementation is based on mutex3 from
/// https://www.akkadia.org/drepper/futex.pdf
-pub const Mutex = struct {
- /// 0: unlocked
- /// 1: locked, no waiters
- /// 2: locked, one or more waiters
- linux_lock: @typeOf(linux_lock_init),
+/// When an application is built in single threaded release mode, all the functions are
+/// no-ops. In single threaded debug mode, there is deadlock detection.
+pub const Mutex = if (builtin.single_threaded)
+ struct {
+ lock: @typeOf(lock_init),
- /// TODO better implementation than spin lock
- spin_lock: @typeOf(spin_lock_init),
+ const lock_init = if (std.debug.runtime_safety) false else {};
- const linux_lock_init = if (builtin.os == builtin.Os.linux) i32(0) else {};
- const spin_lock_init = if (builtin.os != builtin.Os.linux) SpinLock.init() else {};
+ pub const Held = struct {
+ mutex: *Mutex,
- pub const Held = struct {
- mutex: *Mutex,
+ pub fn release(self: Held) void {
+ if (std.debug.runtime_safety) {
+ self.mutex.lock = false;
+ }
+ }
+ };
+ pub fn init() Mutex {
+ return Mutex{ .lock = lock_init };
+ }
+ pub fn deinit(self: *Mutex) void {}
- pub fn release(self: Held) void {
- if (builtin.os == builtin.Os.linux) {
- const c = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release);
+ pub fn acquire(self: *Mutex) Held {
+ if (std.debug.runtime_safety and self.lock) {
+ @panic("deadlock detected");
+ }
+ return Held{ .mutex = self };
+ }
+ }
+else switch (builtin.os) {
+ builtin.Os.linux => struct {
+ /// 0: unlocked
+ /// 1: locked, no waiters
+ /// 2: locked, one or more waiters
+ lock: i32,
+
+ pub const Held = struct {
+ mutex: *Mutex,
+
+ pub fn release(self: Held) void {
+ const c = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release);
if (c != 1) {
- _ = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release);
- const rc = linux.futex_wake(&self.mutex.linux_lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1);
+ _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release);
+ const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1);
switch (linux.getErrno(rc)) {
0 => {},
linux.EINVAL => unreachable,
else => unreachable,
}
}
- } else {
- SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.spin_lock });
}
- }
- };
-
- pub fn init() Mutex {
- return Mutex{
- .linux_lock = linux_lock_init,
- .spin_lock = spin_lock_init,
};
- }
- pub fn acquire(self: *Mutex) Held {
- if (builtin.os == builtin.Os.linux) {
- var c = @cmpxchgWeak(i32, &self.linux_lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse
+ pub fn init() Mutex {
+ return Mutex{ .lock = 0 };
+ }
+
+ pub fn deinit(self: *Mutex) void {}
+
+ pub fn acquire(self: *Mutex) Held {
+ var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse
return Held{ .mutex = self };
if (c != 2)
- c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire);
+ c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire);
while (c != 0) {
- const rc = linux.futex_wait(&self.linux_lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null);
+ const rc = linux.futex_wait(&self.lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null);
switch (linux.getErrno(rc)) {
0, linux.EINTR, linux.EAGAIN => {},
linux.EINVAL => unreachable,
else => unreachable,
}
- c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire);
+ c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire);
}
- } else {
- _ = self.spin_lock.acquire();
+ return Held{ .mutex = self };
}
- return Held{ .mutex = self };
- }
+ },
+ // TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a
+ // better implementation of this. The problem is we need the init() function to have access to
+ // the address of the CRITICAL_SECTION, and then have it not move.
+ builtin.Os.windows => std.StaticallyInitializedMutex,
+ else => struct {
+ /// TODO better implementation than spin lock.
+ /// When changing this, one must also change the corresponding
+ /// std.StaticallyInitializedMutex code, since it aliases this type,
+ /// under the assumption that it works both statically and at runtime.
+ lock: SpinLock,
+
+ pub const Held = struct {
+ mutex: *Mutex,
+
+ pub fn release(self: Held) void {
+ SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.lock });
+ }
+ };
+
+ pub fn init() Mutex {
+ return Mutex{ .lock = SpinLock.init() };
+ }
+
+ pub fn deinit(self: *Mutex) void {}
+
+ pub fn acquire(self: *Mutex) Held {
+ _ = self.lock.acquire();
+ return Held{ .mutex = self };
+ }
+ },
};
-const Context = struct {
+const TestContext = struct {
mutex: *Mutex,
data: i128,
@@ -90,25 +140,32 @@ test "std.Mutex" {
var a = &fixed_buffer_allocator.allocator;
var mutex = Mutex.init();
- var context = Context{
+ defer mutex.deinit();
+
+ var context = TestContext{
.mutex = &mutex,
.data = 0,
};
- const thread_count = 10;
- var threads: [thread_count]*std.os.Thread = undefined;
- for (threads) |*t| {
- t.* = try std.os.spawnThread(&context, worker);
+ if (builtin.single_threaded) {
+ worker(&context);
+ std.debug.assertOrPanic(context.data == TestContext.incr_count);
+ } else {
+ const thread_count = 10;
+ var threads: [thread_count]*std.os.Thread = undefined;
+ for (threads) |*t| {
+ t.* = try std.os.spawnThread(&context, worker);
+ }
+ for (threads) |t|
+ t.wait();
+
+ std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count);
}
- for (threads) |t|
- t.wait();
-
- std.debug.assertOrPanic(context.data == thread_count * Context.incr_count);
}
-fn worker(ctx: *Context) void {
+fn worker(ctx: *TestContext) void {
var i: usize = 0;
- while (i != Context.incr_count) : (i += 1) {
+ while (i != TestContext.incr_count) : (i += 1) {
const held = ctx.mutex.acquire();
defer held.release();
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 0aa896ff1be209a37c522af72f08b1031a64502d..7aa85823692825ff14e8fdb9c910f88ea71c9850 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -88,7 +88,8 @@ pub const ChildProcess = struct {
/// First argument in argv is the executable.
/// On success must call deinit.
pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
- const child = try allocator.create(ChildProcess{
+ const child = try allocator.create(ChildProcess);
+ child.* = ChildProcess{
.allocator = allocator,
.argv = argv,
.pid = undefined,
@@ -109,7 +110,7 @@ pub const ChildProcess = struct {
.stdin_behavior = StdIo.Inherit,
.stdout_behavior = StdIo.Inherit,
.stderr_behavior = StdIo.Inherit,
- });
+ };
errdefer allocator.destroy(child);
return child;
}
@@ -594,7 +595,7 @@ pub const ChildProcess = struct {
const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
defer self.allocator.free(PATH);
- var it = mem.split(PATH, ";");
+ var it = mem.tokenize(PATH, ";");
while (it.next()) |search_path| {
const joined_path = try os.path.join(self.allocator, search_path, app_name);
defer self.allocator.free(joined_path);
diff --git a/std/os/index.zig b/std/os/index.zig
index 78d543583d8160d9e271334c3f4dc5da54681af6..451c0a3436644feffdd72b97a6b775d394edb14d 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
// +1 for the null terminating byte
const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
defer allocator.free(path_buf);
- var it = mem.split(PATH, ":");
+ var it = mem.tokenize(PATH, ":");
var seen_eacces = false;
var err: usize = undefined;
while (it.next()) |search_path| {
@@ -3013,6 +3013,7 @@ pub const SpawnThreadError = error{
/// where T is u8, noreturn, void, or !void
/// caller must call wait on the returned thread
pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
+ if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
// TODO compile-time call graph analysis to determine stack upper bound
// https://github.com/ziglang/zig/issues/157
const default_stack_size = 8 * 1024 * 1024;
@@ -3046,7 +3047,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
- const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext{
+ const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
+ outer_context.* = WinThread.OuterContext{
.thread = Thread{
.data = Thread.Data{
.heap_handle = heap_handle,
@@ -3055,7 +3057,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
},
},
.inner = context,
- }) catch unreachable;
+ };
const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
diff --git a/std/os/path.zig b/std/os/path.zig
index 31f949f0d6437876625d85dd39c0736f22a4e3b5..0b960fa2da73db41b4401eaf33c63653007bf727 100644
--- a/std/os/path.zig
+++ b/std/os/path.zig
@@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
return relative_path;
}
- var it = mem.split(path, []u8{this_sep});
+ var it = mem.tokenize(path, []u8{this_sep});
_ = (it.next() orelse return relative_path);
_ = (it.next() orelse return relative_path);
return WindowsPath{
@@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
return relative_path;
}
- var it = mem.split(path, []u8{this_sep});
+ var it = mem.tokenize(path, []u8{this_sep});
_ = (it.next() orelse return relative_path);
_ = (it.next() orelse return relative_path);
return WindowsPath{
@@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
const sep1 = ns1[0];
const sep2 = ns2[0];
- var it1 = mem.split(ns1, []u8{sep1});
- var it2 = mem.split(ns2, []u8{sep2});
+ var it1 = mem.tokenize(ns1, []u8{sep1});
+ var it2 = mem.tokenize(ns2, []u8{sep2});
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
@@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
const sep1 = p1[0];
const sep2 = p2[0];
- var it1 = mem.split(p1, []u8{sep1});
- var it2 = mem.split(p2, []u8{sep2});
+ var it1 = mem.tokenize(p1, []u8{sep1});
+ var it2 = mem.tokenize(p2, []u8{sep2});
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
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 {
/// If all paths are relative it uses the current working directory as a starting point.
/// Each drive has its own current working directory.
/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
+/// Note: all usage of this function should be audited due to the existence of symlinks.
+/// Without performing actual syscalls, resolving `..` could be incorrect.
pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (paths.len == 0) {
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 {
},
WindowsPath.Kind.NetworkShare => {
result = try allocator.alloc(u8, max_size);
- var it = mem.split(paths[first_index], "/\\");
+ var it = mem.tokenize(paths[first_index], "/\\");
const server_name = it.next().?;
const other_name = it.next().?;
@@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (!correct_disk_designator) {
continue;
}
- var it = mem.split(p[parsed.disk_designator.len..], "/\\");
+ var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\");
while (it.next()) |component| {
if (mem.eql(u8, component, ".")) {
continue;
@@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
/// It resolves "." and "..".
/// The result does not have a trailing path separator.
/// If all paths are relative it uses the current working directory as a starting point.
+/// Note: all usage of this function should be audited due to the existence of symlinks.
+/// Without performing actual syscalls, resolving `..` could be incorrect.
pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (paths.len == 0) {
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 {
errdefer allocator.free(result);
for (paths[first_index..]) |p, i| {
- var it = mem.split(p, "/");
+ var it = mem.tokenize(p, "/");
while (it.next()) |component| {
if (mem.eql(u8, component, ".")) {
continue;
@@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
return resolved_to;
}
- var from_it = mem.split(resolved_from, "/\\");
- var to_it = mem.split(resolved_to, "/\\");
+ var from_it = mem.tokenize(resolved_from, "/\\");
+ var to_it = mem.tokenize(resolved_to, "/\\");
while (true) {
const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
const to_rest = to_it.rest();
@@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
// shave off the trailing slash
result_index -= 1;
- var rest_it = mem.split(to_rest, "/\\");
+ var rest_it = mem.tokenize(to_rest, "/\\");
while (rest_it.next()) |to_component| {
result[result_index] = '\\';
result_index += 1;
@@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![
const resolved_to = try resolvePosix(allocator, [][]const u8{to});
defer allocator.free(resolved_to);
- var from_it = mem.split(resolved_from, "/");
- var to_it = mem.split(resolved_to, "/");
+ var from_it = mem.tokenize(resolved_from, "/");
+ var to_it = mem.tokenize(resolved_to, "/");
while (true) {
const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
const to_rest = to_it.rest();
diff --git a/std/os/test.zig b/std/os/test.zig
index 5142920687105dcd534c109aaa163a39995b1813..f14cf477862b60ffaa4294fd53fb600f375084c6 100644
--- a/std/os/test.zig
+++ b/std/os/test.zig
@@ -40,6 +40,8 @@ fn testThreadIdFn(thread_id: *os.Thread.Id) void {
}
test "std.os.Thread.getCurrentId" {
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var thread_current_id: os.Thread.Id = undefined;
const thread = try os.spawnThread(&thread_current_id, testThreadIdFn);
const thread_id = thread.handle();
@@ -53,6 +55,8 @@ test "std.os.Thread.getCurrentId" {
}
test "spawn threads" {
+ if (builtin.single_threaded) return error.SkipZigTest;
+
var shared_ctx: i32 = 1;
const thread1 = try std.os.spawnThread({}, start1);
diff --git a/std/os/time.zig b/std/os/time.zig
index 42f32f8fee230c35dc1d6eed40ed01c32640a6ae..4b11a69376ff1799ed7cfb58be566f6dcdd749d2 100644
--- a/std/os/time.zig
+++ b/std/os/time.zig
@@ -79,14 +79,12 @@ fn milliTimestampWindows() u64 {
}
fn milliTimestampDarwin() u64 {
- //Sources suggest MacOS 10.12 has support for
- // posix clock_gettime.
var tv: darwin.timeval = undefined;
var err = darwin.gettimeofday(&tv, null);
debug.assert(err == 0);
- const sec_ms = @intCast(u64, tv.tv_sec) * ms_per_s;
- const usec_ms = @divFloor(@intCast(u64, tv.tv_usec), us_per_s / ms_per_s);
- return u64(sec_ms) + u64(usec_ms);
+ const sec_ms = tv.tv_sec * ms_per_s;
+ const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s);
+ return @intCast(u64, sec_ms + usec_ms);
}
fn milliTimestampPosix() u64 {
diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig
index 3d6ee6711356d93d0a04a64e4d92f5ab40ebf836..3f19905835d8a16162aee213818b716345c3126c 100644
--- a/std/os/windows/index.zig
+++ b/std/os/windows/index.zig
@@ -49,6 +49,7 @@ pub const UNICODE = false;
pub const WCHAR = u16;
pub const WORD = u16;
pub const LARGE_INTEGER = i64;
+pub const LONG = c_long;
pub const TRUE = 1;
pub const FALSE = 0;
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
index 202b8bffeb7272dca8347830f69c6abd4814b926..66b9552c5fff674ace0f921e153d65ab3fbba259 100644
--- a/std/os/windows/kernel32.zig
+++ b/std/os/windows/kernel32.zig
@@ -220,3 +220,50 @@ pub const FOREGROUND_BLUE = 1;
pub const FOREGROUND_GREEN = 2;
pub const FOREGROUND_RED = 4;
pub const FOREGROUND_INTENSITY = 8;
+
+pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
+pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
+pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
+pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
+
+pub const LIST_ENTRY = extern struct {
+ Flink: *LIST_ENTRY,
+ Blink: *LIST_ENTRY,
+};
+
+pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
+ Type: WORD,
+ CreatorBackTraceIndex: WORD,
+ CriticalSection: *RTL_CRITICAL_SECTION,
+ ProcessLocksList: LIST_ENTRY,
+ EntryCount: DWORD,
+ ContentionCount: DWORD,
+ Flags: DWORD,
+ CreatorBackTraceIndexHigh: WORD,
+ SpareWORD: WORD,
+};
+
+pub const RTL_CRITICAL_SECTION = extern struct {
+ DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
+ LockCount: LONG,
+ RecursionCount: LONG,
+ OwningThread: HANDLE,
+ LockSemaphore: HANDLE,
+ SpinCount: ULONG_PTR,
+};
+
+pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
+pub const INIT_ONCE = RTL_RUN_ONCE;
+pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
+
+pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
+
+pub const INIT_ONCE_FN = extern fn(InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
+
+pub const RTL_RUN_ONCE = extern struct {
+ Ptr: ?*c_void,
+};
+
+pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE {
+ .Ptr = null,
+};
diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig
new file mode 100644
index 0000000000000000000000000000000000000000..37582d49c1b35132138493192dc151504039143b
--- /dev/null
+++ b/std/statically_initialized_mutex.zig
@@ -0,0 +1,110 @@
+const std = @import("index.zig");
+const builtin = @import("builtin");
+const AtomicOrder = builtin.AtomicOrder;
+const AtomicRmwOp = builtin.AtomicRmwOp;
+const assert = std.debug.assert;
+const windows = std.os.windows;
+
+/// Lock may be held only once. If the same thread
+/// tries to acquire the same mutex twice, it deadlocks.
+/// This type is intended to be initialized statically. If you don't
+/// require static initialization, use std.Mutex.
+/// On Windows, this mutex allocates resources when it is
+/// first used, and the resources cannot be freed.
+/// On Linux, this is an alias of std.Mutex.
+pub const StaticallyInitializedMutex = switch(builtin.os) {
+ builtin.Os.linux => std.Mutex,
+ builtin.Os.windows => struct {
+ lock: windows.CRITICAL_SECTION,
+ init_once: windows.RTL_RUN_ONCE,
+
+ pub const Held = struct {
+ mutex: *StaticallyInitializedMutex,
+
+ pub fn release(self: Held) void {
+ windows.LeaveCriticalSection(&self.mutex.lock);
+ }
+ };
+
+ pub fn init() StaticallyInitializedMutex {
+ return StaticallyInitializedMutex {
+ .lock = undefined,
+ .init_once = windows.INIT_ONCE_STATIC_INIT,
+ };
+ }
+
+ extern fn initCriticalSection(
+ InitOnce: *windows.RTL_RUN_ONCE,
+ Parameter: ?*c_void,
+ Context: ?*c_void,
+ ) windows.BOOL {
+ const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter));
+ windows.InitializeCriticalSection(lock);
+ return windows.TRUE;
+ }
+
+ /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better
+ /// implementation of a runtime initialized mutex, remove this function.
+ pub fn deinit(self: *StaticallyInitializedMutex) void {
+ assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
+ windows.DeleteCriticalSection(&self.lock);
+ }
+
+ pub fn acquire(self: *StaticallyInitializedMutex) Held {
+ assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
+ windows.EnterCriticalSection(&self.lock);
+ return Held { .mutex = self };
+ }
+ },
+ else => std.Mutex,
+};
+
+test "std.StaticallyInitializedMutex" {
+ const TestContext = struct {
+ data: i128,
+
+ const TestContext = @This();
+ const incr_count = 10000;
+
+ var mutex = StaticallyInitializedMutex.init();
+
+ fn worker(ctx: *TestContext) void {
+ var i: usize = 0;
+ while (i != TestContext.incr_count) : (i += 1) {
+ const held = mutex.acquire();
+ defer held.release();
+
+ ctx.data += 1;
+ }
+ }
+ };
+
+ var direct_allocator = std.heap.DirectAllocator.init();
+ defer direct_allocator.deinit();
+
+ var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
+ defer direct_allocator.allocator.free(plenty_of_memory);
+
+ var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
+ var a = &fixed_buffer_allocator.allocator;
+
+
+ var context = TestContext{
+ .data = 0,
+ };
+
+ if (builtin.single_threaded) {
+ TestContext.worker(&context);
+ std.debug.assertOrPanic(context.data == TestContext.incr_count);
+ } else {
+ const thread_count = 10;
+ var threads: [thread_count]*std.os.Thread = undefined;
+ for (threads) |*t| {
+ t.* = try std.os.spawnThread(&context, TestContext.worker);
+ }
+ for (threads) |t|
+ t.wait();
+
+ std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count);
+ }
+}
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
index a216484d7d669ba61a7f8ce0f012960866f01209..783464c620709cd4bd0470bbf9b284e213fd653d 100644
--- a/std/zig/parse.zig
+++ b/std/zig/parse.zig
@@ -17,14 +17,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
defer stack.deinit();
const arena = &tree_arena.allocator;
- const root_node = try arena.create(ast.Node.Root{
+ const root_node = try arena.create(ast.Node.Root);
+ root_node.* = ast.Node.Root{
.base = ast.Node{ .id = ast.Node.Id.Root },
.decls = ast.Node.Root.DeclList.init(arena),
.doc_comments = null,
.shebang = null,
// initialized when we get the eof token
.eof_token = undefined,
- });
+ };
var tree = ast.Tree{
.source = source,
@@ -75,20 +76,22 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
Token.Id.Keyword_test => {
stack.append(State.TopLevel) catch unreachable;
- const block = try arena.create(ast.Node.Block{
+ const block = try arena.create(ast.Node.Block);
+ block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = null,
.lbrace = undefined,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
- const test_node = try arena.create(ast.Node.TestDecl{
+ };
+ const test_node = try arena.create(ast.Node.TestDecl);
+ test_node.* = ast.Node.TestDecl{
.base = ast.Node{ .id = ast.Node.Id.TestDecl },
.doc_comments = comments,
.test_token = token_index,
.name = undefined,
.body_node = &block.base,
- });
+ };
try root_node.decls.push(&test_node.base);
try stack.append(State{ .Block = block });
try stack.append(State{
@@ -119,19 +122,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_comptime => {
- const block = try arena.create(ast.Node.Block{
+ const block = try arena.create(ast.Node.Block);
+ block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = null,
.lbrace = undefined,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
- const node = try arena.create(ast.Node.Comptime{
+ };
+ const node = try arena.create(ast.Node.Comptime);
+ node.* = ast.Node.Comptime{
.base = ast.Node{ .id = ast.Node.Id.Comptime },
.comptime_token = token_index,
.expr = &block.base,
.doc_comments = comments,
- });
+ };
try root_node.decls.push(&node.base);
stack.append(State.TopLevel) catch unreachable;
@@ -235,14 +240,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
return tree;
}
- const node = try arena.create(ast.Node.Use{
+ const node = try arena.create(ast.Node.Use);
+ node.* = ast.Node.Use{
.base = ast.Node{ .id = ast.Node.Id.Use },
.use_token = token_index,
.visib_token = ctx.visib_token,
.expr = undefined,
.semicolon_token = undefined,
.doc_comments = ctx.comments,
- });
+ };
try ctx.decls.push(&node.base);
stack.append(State{
@@ -276,7 +282,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
- const fn_proto = try arena.create(ast.Node.FnProto{
+ const fn_proto = try arena.create(ast.Node.FnProto);
+ fn_proto.* = ast.Node.FnProto{
.base = ast.Node{ .id = ast.Node.Id.FnProto },
.doc_comments = ctx.comments,
.visib_token = ctx.visib_token,
@@ -292,7 +299,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.lib_name = ctx.lib_name,
.align_expr = null,
.section_expr = null,
- });
+ };
try ctx.decls.push(&fn_proto.base);
stack.append(State{ .FnDef = fn_proto }) catch unreachable;
try stack.append(State{ .FnProto = fn_proto });
@@ -309,12 +316,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_async => {
- const async_node = try arena.create(ast.Node.AsyncAttribute{
+ const async_node = try arena.create(ast.Node.AsyncAttribute);
+ async_node.* = ast.Node.AsyncAttribute{
.base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
.async_token = token_index,
.allocator_type = null,
.rangle_bracket = null,
- });
+ };
fn_proto.async_attr = async_node;
try stack.append(State{
@@ -341,13 +349,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
State.TopLevelExternOrField => |ctx| {
if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
- const node = try arena.create(ast.Node.StructField{
+ const node = try arena.create(ast.Node.StructField);
+ node.* = ast.Node.StructField{
.base = ast.Node{ .id = ast.Node.Id.StructField },
.doc_comments = ctx.comments,
.visib_token = ctx.visib_token,
.name_token = identifier,
.type_expr = undefined,
- });
+ };
const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
node_ptr.* = &node.base;
@@ -391,7 +400,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token = nextToken(&tok_it, &tree);
const token_index = token.index;
const token_ptr = token.ptr;
- const node = try arena.create(ast.Node.ContainerDecl{
+ const node = try arena.create(ast.Node.ContainerDecl);
+ node.* = ast.Node.ContainerDecl{
.base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
.layout_token = ctx.layout_token,
.kind_token = switch (token_ptr.id) {
@@ -405,7 +415,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
.lbrace_token = undefined,
.rbrace_token = undefined,
- });
+ };
ctx.opt_ctx.store(&node.base);
stack.append(State{ .ContainerDecl = node }) catch unreachable;
@@ -464,13 +474,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
Token.Id.Identifier => {
switch (tree.tokens.at(container_decl.kind_token).id) {
Token.Id.Keyword_struct => {
- const node = try arena.create(ast.Node.StructField{
+ const node = try arena.create(ast.Node.StructField);
+ node.* = ast.Node.StructField{
.base = ast.Node{ .id = ast.Node.Id.StructField },
.doc_comments = comments,
.visib_token = null,
.name_token = token_index,
.type_expr = undefined,
- });
+ };
const node_ptr = try container_decl.fields_and_decls.addOne();
node_ptr.* = &node.base;
@@ -485,13 +496,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_union => {
- const node = try arena.create(ast.Node.UnionTag{
+ const node = try arena.create(ast.Node.UnionTag);
+ node.* = ast.Node.UnionTag{
.base = ast.Node{ .id = ast.Node.Id.UnionTag },
.name_token = token_index,
.type_expr = null,
.value_expr = null,
.doc_comments = comments,
- });
+ };
try container_decl.fields_and_decls.push(&node.base);
try stack.append(State{
@@ -506,12 +518,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_enum => {
- const node = try arena.create(ast.Node.EnumTag{
+ const node = try arena.create(ast.Node.EnumTag);
+ node.* = ast.Node.EnumTag{
.base = ast.Node{ .id = ast.Node.Id.EnumTag },
.name_token = token_index,
.value = null,
.doc_comments = comments,
- });
+ };
try container_decl.fields_and_decls.push(&node.base);
try stack.append(State{
@@ -593,7 +606,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
State.VarDecl => |ctx| {
- const var_decl = try arena.create(ast.Node.VarDecl{
+ const var_decl = try arena.create(ast.Node.VarDecl);
+ var_decl.* = ast.Node.VarDecl{
.base = ast.Node{ .id = ast.Node.Id.VarDecl },
.doc_comments = ctx.comments,
.visib_token = ctx.visib_token,
@@ -609,7 +623,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.name_token = undefined,
.eq_token = undefined,
.semicolon_token = undefined,
- });
+ };
try ctx.list.push(&var_decl.base);
try stack.append(State{ .VarDeclAlign = var_decl });
@@ -708,13 +722,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_ptr = token.ptr;
switch (token_ptr.id) {
Token.Id.LBrace => {
- const block = try arena.create(ast.Node.Block{
+ const block = try arena.create(ast.Node.Block);
+ block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = null,
.lbrace = token_index,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
+ };
fn_proto.body_node = &block.base;
stack.append(State{ .Block = block }) catch unreachable;
continue;
@@ -770,10 +785,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
// TODO: this is a special case. Remove this when #760 is fixed
if (token_ptr.id == Token.Id.Keyword_anyerror) {
if (tok_it.peek().?.id == Token.Id.LBrace) {
- const error_type_node = try arena.create(ast.Node.ErrorType{
+ const error_type_node = try arena.create(ast.Node.ErrorType);
+ error_type_node.* = ast.Node.ErrorType{
.base = ast.Node{ .id = ast.Node.Id.ErrorType },
.token = token_index,
- });
+ };
fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base };
continue;
}
@@ -791,14 +807,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
continue;
}
- const param_decl = try arena.create(ast.Node.ParamDecl{
+ const param_decl = try arena.create(ast.Node.ParamDecl);
+ param_decl.* = ast.Node.ParamDecl{
.base = ast.Node{ .id = ast.Node.Id.ParamDecl },
.comptime_token = null,
.noalias_token = null,
.name_token = null,
.type_node = undefined,
.var_args_token = null,
- });
+ };
try fn_proto.params.push(¶m_decl.base);
stack.append(State{
@@ -877,13 +894,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_ptr = token.ptr;
switch (token_ptr.id) {
Token.Id.LBrace => {
- const block = try arena.create(ast.Node.Block{
+ const block = try arena.create(ast.Node.Block);
+ block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = ctx.label,
.lbrace = token_index,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
+ };
ctx.opt_ctx.store(&block.base);
stack.append(State{ .Block = block }) catch unreachable;
continue;
@@ -970,7 +988,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
}
},
State.While => |ctx| {
- const node = try arena.create(ast.Node.While{
+ const node = try arena.create(ast.Node.While);
+ node.* = ast.Node.While{
.base = ast.Node{ .id = ast.Node.Id.While },
.label = ctx.label,
.inline_token = ctx.inline_token,
@@ -980,7 +999,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.continue_expr = null,
.body = undefined,
.@"else" = null,
- });
+ };
ctx.opt_ctx.store(&node.base);
stack.append(State{ .Else = &node.@"else" }) catch unreachable;
try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
@@ -999,7 +1018,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
State.For => |ctx| {
- const node = try arena.create(ast.Node.For{
+ const node = try arena.create(ast.Node.For);
+ node.* = ast.Node.For{
.base = ast.Node{ .id = ast.Node.Id.For },
.label = ctx.label,
.inline_token = ctx.inline_token,
@@ -1008,7 +1028,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.payload = null,
.body = undefined,
.@"else" = null,
- });
+ };
ctx.opt_ctx.store(&node.base);
stack.append(State{ .Else = &node.@"else" }) catch unreachable;
try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
@@ -1020,12 +1040,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
State.Else => |dest| {
if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
- const node = try arena.create(ast.Node.Else{
+ const node = try arena.create(ast.Node.Else);
+ node.* = ast.Node.Else{
.base = ast.Node{ .id = ast.Node.Id.Else },
.else_token = else_token,
.payload = null,
.body = undefined,
- });
+ };
dest.* = node;
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 {
continue;
},
Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
- const node = try arena.create(ast.Node.Defer{
+ const node = try arena.create(ast.Node.Defer);
+ node.* = ast.Node.Defer{
.base = ast.Node{ .id = ast.Node.Id.Defer },
.defer_token = token_index,
.expr = undefined,
- });
+ };
const node_ptr = try block.statements.addOne();
node_ptr.* = &node.base;
@@ -1096,13 +1118,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.LBrace => {
- const inner_block = try arena.create(ast.Node.Block{
+ const inner_block = try arena.create(ast.Node.Block);
+ inner_block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = null,
.lbrace = token_index,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
+ };
try block.statements.push(&inner_block.base);
stack.append(State{ .Block = inner_block }) catch unreachable;
@@ -1164,14 +1187,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.AsmOutput{
+ const node = try arena.create(ast.Node.AsmOutput);
+ node.* = ast.Node.AsmOutput{
.base = ast.Node{ .id = ast.Node.Id.AsmOutput },
.lbracket = lbracket_index,
.symbolic_name = undefined,
.constraint = undefined,
.kind = undefined,
.rparen = undefined,
- });
+ };
try items.push(node);
stack.append(State{ .AsmOutputItems = items }) catch unreachable;
@@ -1218,14 +1242,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.AsmInput{
+ const node = try arena.create(ast.Node.AsmInput);
+ node.* = ast.Node.AsmInput{
.base = ast.Node{ .id = ast.Node.Id.AsmInput },
.lbracket = lbracket_index,
.symbolic_name = undefined,
.constraint = undefined,
.expr = undefined,
.rparen = undefined,
- });
+ };
try items.push(node);
stack.append(State{ .AsmInputItems = items }) catch unreachable;
@@ -1283,12 +1308,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.FieldInitializer{
+ const node = try arena.create(ast.Node.FieldInitializer);
+ node.* = ast.Node.FieldInitializer{
.base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
.period_token = undefined,
.name_token = undefined,
.expr = undefined,
- });
+ };
try list_state.list.push(&node.base);
stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable;
@@ -1390,13 +1416,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
}
const comments = try eatDocComments(arena, &tok_it, &tree);
- const node = try arena.create(ast.Node.SwitchCase{
+ const node = try arena.create(ast.Node.SwitchCase);
+ node.* = ast.Node.SwitchCase{
.base = ast.Node{ .id = ast.Node.Id.SwitchCase },
.items = ast.Node.SwitchCase.ItemList.init(arena),
.payload = null,
.expr = undefined,
.arrow_token = undefined,
- });
+ };
try list_state.list.push(&node.base);
try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
@@ -1427,10 +1454,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (token_ptr.id == Token.Id.Keyword_else) {
- const else_node = try arena.create(ast.Node.SwitchElse{
+ const else_node = try arena.create(ast.Node.SwitchElse);
+ else_node.* = ast.Node.SwitchElse{
.base = ast.Node{ .id = ast.Node.Id.SwitchElse },
.token = token_index,
- });
+ };
try switch_case.items.push(&else_node.base);
try stack.append(State{
@@ -1537,7 +1565,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
State.ExternType => |ctx| {
if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
- const fn_proto = try arena.create(ast.Node.FnProto{
+ const fn_proto = try arena.create(ast.Node.FnProto);
+ fn_proto.* = ast.Node.FnProto{
.base = ast.Node{ .id = ast.Node.Id.FnProto },
.doc_comments = ctx.comments,
.visib_token = null,
@@ -1553,7 +1582,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.lib_name = null,
.align_expr = null,
.section_expr = null,
- });
+ };
ctx.opt_ctx.store(&fn_proto.base);
stack.append(State{ .FnProto = fn_proto }) catch unreachable;
continue;
@@ -1711,12 +1740,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.Payload{
+ const node = try arena.create(ast.Node.Payload);
+ node.* = ast.Node.Payload{
.base = ast.Node{ .id = ast.Node.Id.Payload },
.lpipe = token_index,
.error_symbol = undefined,
.rpipe = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{
@@ -1747,13 +1777,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.PointerPayload{
+ const node = try arena.create(ast.Node.PointerPayload);
+ node.* = ast.Node.PointerPayload{
.base = ast.Node{ .id = ast.Node.Id.PointerPayload },
.lpipe = token_index,
.ptr_token = null,
.value_symbol = undefined,
.rpipe = undefined,
- });
+ };
opt_ctx.store(&node.base);
try stack.append(State{
@@ -1790,14 +1821,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.PointerIndexPayload{
+ const node = try arena.create(ast.Node.PointerIndexPayload);
+ node.* = ast.Node.PointerIndexPayload{
.base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
.lpipe = token_index,
.ptr_token = null,
.value_symbol = undefined,
.index_symbol = null,
.rpipe = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{
@@ -1824,12 +1856,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_ptr = token.ptr;
switch (token_ptr.id) {
Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
- const node = try arena.create(ast.Node.ControlFlowExpression{
+ const node = try arena.create(ast.Node.ControlFlowExpression);
+ node.* = ast.Node.ControlFlowExpression{
.base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
.ltoken = token_index,
.kind = undefined,
.rhs = null,
- });
+ };
opt_ctx.store(&node.base);
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 {
continue;
},
Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
- const node = try arena.create(ast.Node.PrefixOp{
+ const node = try arena.create(ast.Node.PrefixOp);
+ node.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = ast.Node.Id.PrefixOp },
.op_token = token_index,
.op = switch (token_ptr.id) {
@@ -1863,7 +1897,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
else => unreachable,
},
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
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 {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = ellipsis3,
.op = ast.Node.InfixOp.Op.Range,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
continue;
@@ -1912,13 +1947,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = ass_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
@@ -1942,13 +1978,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = unwrap_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
@@ -1974,13 +2011,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = or_token,
.op = ast.Node.InfixOp.Op.BoolOr,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -1998,13 +2036,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = and_token,
.op = ast.Node.InfixOp.Op.BoolAnd,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2025,13 +2064,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToComparison(token_ptr.id)) |comp_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = comp_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2052,13 +2092,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = pipe,
.op = ast.Node.InfixOp.Op.BitOr,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2076,13 +2117,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = caret,
.op = ast.Node.InfixOp.Op.BitXor,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2100,13 +2142,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = ampersand,
.op = ast.Node.InfixOp.Op.BitAnd,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2127,13 +2170,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = bitshift_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2157,13 +2201,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToAddition(token_ptr.id)) |add_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = add_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2187,13 +2232,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = mult_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
@@ -2215,12 +2261,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (tok_it.peek().?.id == Token.Id.Period) {
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
.rtoken = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
@@ -2234,12 +2281,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
.rtoken = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .IfToken = Token.Id.LBrace });
@@ -2263,13 +2311,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const lhs = opt_ctx.get() orelse continue;
if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = bang,
.op = ast.Node.InfixOp.Op.ErrorUnion,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } });
@@ -2282,22 +2331,24 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_index = token.index;
const token_ptr = token.ptr;
if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
- var node = try arena.create(ast.Node.PrefixOp{
+ var node = try arena.create(ast.Node.PrefixOp);
+ node.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = ast.Node.Id.PrefixOp },
.op_token = token_index,
.op = prefix_id,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
// Treat '**' token as two pointer types
if (token_ptr.id == Token.Id.AsteriskAsterisk) {
- const child = try arena.create(ast.Node.PrefixOp{
+ const child = try arena.create(ast.Node.PrefixOp);
+ child.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = ast.Node.Id.PrefixOp },
.op_token = token_index,
.op = prefix_id,
.rhs = undefined,
- });
+ };
node.rhs = &child.base;
node = child;
}
@@ -2316,12 +2367,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
State.SuffixOpExpressionBegin => |opt_ctx| {
if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
- const async_node = try arena.create(ast.Node.AsyncAttribute{
+ const async_node = try arena.create(ast.Node.AsyncAttribute);
+ async_node.* = ast.Node.AsyncAttribute{
.base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
.async_token = async_token,
.allocator_type = null,
.rangle_bracket = null,
- });
+ };
stack.append(State{
.AsyncEnd = AsyncEndCtx{
.ctx = opt_ctx,
@@ -2347,7 +2399,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
const token_ptr = token.ptr;
switch (token_ptr.id) {
Token.Id.LParen => {
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op{
@@ -2357,7 +2410,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
},
.rtoken = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
@@ -2371,12 +2424,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.LBracket => {
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
.rtoken = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
@@ -2386,34 +2440,37 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
Token.Id.Period => {
if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| {
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op.Deref,
.rtoken = asterisk_token,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
continue;
}
if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {
- const node = try arena.create(ast.Node.SuffixOp{
+ const node = try arena.create(ast.Node.SuffixOp);
+ node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
.lhs = lhs,
.op = ast.Node.SuffixOp.Op.UnwrapOptional,
.rtoken = question_token,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
continue;
}
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = lhs,
.op_token = token_index,
.op = ast.Node.InfixOp.Op.Period,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
@@ -2467,11 +2524,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_promise => {
- const node = try arena.create(ast.Node.PromiseType{
+ const node = try arena.create(ast.Node.PromiseType);
+ node.* = ast.Node.PromiseType{
.base = ast.Node{ .id = ast.Node.Id.PromiseType },
.promise_token = token.index,
.result = null,
- });
+ };
opt_ctx.store(&node.base);
const next_token = nextToken(&tok_it, &tree);
const next_token_index = next_token.index;
@@ -2493,12 +2551,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.LParen => {
- const node = try arena.create(ast.Node.GroupedExpression{
+ const node = try arena.create(ast.Node.GroupedExpression);
+ node.* = ast.Node.GroupedExpression{
.base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
.lparen = token.index,
.expr = undefined,
.rparen = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{
@@ -2511,12 +2570,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Builtin => {
- const node = try arena.create(ast.Node.BuiltinCall{
+ const node = try arena.create(ast.Node.BuiltinCall);
+ node.* = ast.Node.BuiltinCall{
.base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
.builtin_token = token.index,
.params = ast.Node.BuiltinCall.ParamList.init(arena),
.rparen_token = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{
@@ -2530,12 +2590,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.LBracket => {
- const node = try arena.create(ast.Node.PrefixOp{
+ const node = try arena.create(ast.Node.PrefixOp);
+ node.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = ast.Node.Id.PrefixOp },
.op_token = token.index,
.op = undefined,
.rhs = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{ .SliceOrArrayType = node }) catch unreachable;
@@ -2593,7 +2654,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_fn => {
- const fn_proto = try arena.create(ast.Node.FnProto{
+ const fn_proto = try arena.create(ast.Node.FnProto);
+ fn_proto.* = ast.Node.FnProto{
.base = ast.Node{ .id = ast.Node.Id.FnProto },
.doc_comments = null,
.visib_token = null,
@@ -2609,13 +2671,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.lib_name = null,
.align_expr = null,
.section_expr = null,
- });
+ };
opt_ctx.store(&fn_proto.base);
stack.append(State{ .FnProto = fn_proto }) catch unreachable;
continue;
},
Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
- const fn_proto = try arena.create(ast.Node.FnProto{
+ const fn_proto = try arena.create(ast.Node.FnProto);
+ fn_proto.* = ast.Node.FnProto{
.base = ast.Node{ .id = ast.Node.Id.FnProto },
.doc_comments = null,
.visib_token = null,
@@ -2631,7 +2694,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.lib_name = null,
.align_expr = null,
.section_expr = null,
- });
+ };
opt_ctx.store(&fn_proto.base);
stack.append(State{ .FnProto = fn_proto }) catch unreachable;
try stack.append(State{
@@ -2643,7 +2706,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
},
Token.Id.Keyword_asm => {
- const node = try arena.create(ast.Node.Asm{
+ const node = try arena.create(ast.Node.Asm);
+ node.* = ast.Node.Asm{
.base = ast.Node{ .id = ast.Node.Id.Asm },
.asm_token = token.index,
.volatile_token = null,
@@ -2652,7 +2716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
.inputs = ast.Node.Asm.InputList.init(arena),
.clobbers = ast.Node.Asm.ClobberList.init(arena),
.rparen = undefined,
- });
+ };
opt_ctx.store(&node.base);
stack.append(State{
@@ -2701,13 +2765,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
State.ErrorTypeOrSetDecl => |ctx| {
if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
- const node = try arena.create(ast.Node.InfixOp{
+ const node = try arena.create(ast.Node.InfixOp);
+ node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
.lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base,
.op_token = undefined,
.op = ast.Node.InfixOp.Op.Period,
.rhs = undefined,
- });
+ };
ctx.opt_ctx.store(&node.base);
stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
try stack.append(State{
@@ -2719,12 +2784,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
continue;
}
- const node = try arena.create(ast.Node.ErrorSetDecl{
+ const node = try arena.create(ast.Node.ErrorSetDecl);
+ node.* = ast.Node.ErrorSetDecl{
.base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
.error_token = ctx.error_token,
.decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
.rbrace_token = undefined,
- });
+ };
ctx.opt_ctx.store(&node.base);
stack.append(State{
@@ -2785,11 +2851,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
return tree;
}
- const node = try arena.create(ast.Node.ErrorTag{
+ const node = try arena.create(ast.Node.ErrorTag);
+ node.* = ast.Node.ErrorTag{
.base = ast.Node{ .id = ast.Node.Id.ErrorTag },
.doc_comments = comments,
.name_token = ident_token_index,
- });
+ };
node_ptr.* = &node.base;
continue;
},
@@ -3129,10 +3196,11 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as
if (result.*) |comment_node| {
break :blk comment_node;
} else {
- const comment_node = try arena.create(ast.Node.DocComment{
+ const comment_node = try arena.create(ast.Node.DocComment);
+ comment_node.* = ast.Node.DocComment{
.base = ast.Node{ .id = ast.Node.Id.DocComment },
.lines = ast.Node.DocComment.LineList.init(arena),
- });
+ };
result.* = comment_node;
break :blk comment_node;
}
@@ -3158,10 +3226,11 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
},
Token.Id.MultilineStringLiteralLine => {
- const node = try arena.create(ast.Node.MultilineStringLiteral{
+ const node = try arena.create(ast.Node.MultilineStringLiteral);
+ node.* = ast.Node.MultilineStringLiteral{
.base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
.lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
- });
+ };
try node.lines.push(token_index);
while (true) {
const multiline_str = nextToken(tok_it, tree);
@@ -3186,25 +3255,27 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool {
switch (token_ptr.id) {
Token.Id.Keyword_suspend => {
- const node = try arena.create(ast.Node.Suspend{
+ const node = try arena.create(ast.Node.Suspend);
+ node.* = ast.Node.Suspend{
.base = ast.Node{ .id = ast.Node.Id.Suspend },
.suspend_token = token_index,
.body = null,
- });
+ };
ctx.store(&node.base);
stack.append(State{ .SuspendBody = node }) catch unreachable;
return true;
},
Token.Id.Keyword_if => {
- const node = try arena.create(ast.Node.If{
+ const node = try arena.create(ast.Node.If);
+ node.* = ast.Node.If{
.base = ast.Node{ .id = ast.Node.Id.If },
.if_token = token_index,
.condition = undefined,
.payload = null,
.body = undefined,
.@"else" = null,
- });
+ };
ctx.store(&node.base);
stack.append(State{ .Else = &node.@"else" }) catch unreachable;
@@ -3238,13 +3309,14 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti
return true;
},
Token.Id.Keyword_switch => {
- const node = try arena.create(ast.Node.Switch{
+ const node = try arena.create(ast.Node.Switch);
+ node.* = ast.Node.Switch{
.base = ast.Node{ .id = ast.Node.Id.Switch },
.switch_token = token_index,
.expr = undefined,
.cases = ast.Node.Switch.CaseList.init(arena),
.rbrace = undefined,
- });
+ };
ctx.store(&node.base);
stack.append(State{
@@ -3260,25 +3332,27 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti
return true;
},
Token.Id.Keyword_comptime => {
- const node = try arena.create(ast.Node.Comptime{
+ const node = try arena.create(ast.Node.Comptime);
+ node.* = ast.Node.Comptime{
.base = ast.Node{ .id = ast.Node.Id.Comptime },
.comptime_token = token_index,
.expr = undefined,
.doc_comments = null,
- });
+ };
ctx.store(&node.base);
try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
return true;
},
Token.Id.LBrace => {
- const block = try arena.create(ast.Node.Block{
+ const block = try arena.create(ast.Node.Block);
+ block.* = ast.Node.Block{
.base = ast.Node{ .id = ast.Node.Id.Block },
.label = null,
.lbrace = token_index,
.statements = ast.Node.Block.StatementList.init(arena),
.rbrace = undefined,
- });
+ };
ctx.store(&block.base);
stack.append(State{ .Block = block }) catch unreachable;
return true;
@@ -3412,10 +3486,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
}
fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {
- return arena.create(T{
+ const result = try arena.create(T);
+ result.* = T{
.base = ast.Node{ .id = ast.Node.typeToId(T) },
.token = token_index,
- });
+ };
+ return result;
}
fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: OptionalCtx, comptime T: type, token_index: TokenIndex) !*T {
diff --git a/test/behavior.zig b/test/behavior.zig
deleted file mode 100644
index 10cd08dad717eb75f3aa68eabd2ad684d56a292b..0000000000000000000000000000000000000000
--- a/test/behavior.zig
+++ /dev/null
@@ -1,82 +0,0 @@
-const builtin = @import("builtin");
-
-comptime {
- _ = @import("cases/align.zig");
- _ = @import("cases/alignof.zig");
- _ = @import("cases/array.zig");
- _ = @import("cases/asm.zig");
- _ = @import("cases/atomics.zig");
- _ = @import("cases/bitcast.zig");
- _ = @import("cases/bool.zig");
- _ = @import("cases/bswap.zig");
- _ = @import("cases/bitreverse.zig");
- _ = @import("cases/bugs/1076.zig");
- _ = @import("cases/bugs/1111.zig");
- _ = @import("cases/bugs/1277.zig");
- _ = @import("cases/bugs/1322.zig");
- _ = @import("cases/bugs/1381.zig");
- _ = @import("cases/bugs/1421.zig");
- _ = @import("cases/bugs/1442.zig");
- _ = @import("cases/bugs/1486.zig");
- _ = @import("cases/bugs/394.zig");
- _ = @import("cases/bugs/655.zig");
- _ = @import("cases/bugs/656.zig");
- _ = @import("cases/bugs/726.zig");
- _ = @import("cases/bugs/828.zig");
- _ = @import("cases/bugs/920.zig");
- _ = @import("cases/byval_arg_var.zig");
- _ = @import("cases/cancel.zig");
- _ = @import("cases/cast.zig");
- _ = @import("cases/const_slice_child.zig");
- _ = @import("cases/coroutine_await_struct.zig");
- _ = @import("cases/coroutines.zig");
- _ = @import("cases/defer.zig");
- _ = @import("cases/enum.zig");
- _ = @import("cases/enum_with_members.zig");
- _ = @import("cases/error.zig");
- _ = @import("cases/eval.zig");
- _ = @import("cases/field_parent_ptr.zig");
- _ = @import("cases/fn.zig");
- _ = @import("cases/fn_in_struct_in_comptime.zig");
- _ = @import("cases/for.zig");
- _ = @import("cases/generics.zig");
- _ = @import("cases/if.zig");
- _ = @import("cases/import.zig");
- _ = @import("cases/incomplete_struct_param_tld.zig");
- _ = @import("cases/inttoptr.zig");
- _ = @import("cases/ir_block_deps.zig");
- _ = @import("cases/math.zig");
- _ = @import("cases/merge_error_sets.zig");
- _ = @import("cases/misc.zig");
- _ = @import("cases/namespace_depends_on_compile_var/index.zig");
- _ = @import("cases/new_stack_call.zig");
- _ = @import("cases/null.zig");
- _ = @import("cases/optional.zig");
- _ = @import("cases/pointers.zig");
- _ = @import("cases/popcount.zig");
- _ = @import("cases/ptrcast.zig");
- _ = @import("cases/pub_enum/index.zig");
- _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
- _ = @import("cases/reflection.zig");
- _ = @import("cases/sizeof_and_typeof.zig");
- _ = @import("cases/slice.zig");
- _ = @import("cases/struct.zig");
- _ = @import("cases/struct_contains_null_ptr_itself.zig");
- _ = @import("cases/struct_contains_slice_of_itself.zig");
- _ = @import("cases/switch.zig");
- _ = @import("cases/switch_prong_err_enum.zig");
- _ = @import("cases/switch_prong_implicit_cast.zig");
- _ = @import("cases/syntax.zig");
- _ = @import("cases/this.zig");
- _ = @import("cases/truncate.zig");
- _ = @import("cases/try.zig");
- _ = @import("cases/type_info.zig");
- _ = @import("cases/undefined.zig");
- _ = @import("cases/underscore.zig");
- _ = @import("cases/union.zig");
- _ = @import("cases/var_args.zig");
- _ = @import("cases/void.zig");
- _ = @import("cases/while.zig");
- _ = @import("cases/widening.zig");
- _ = @import("cases/bit_shifting.zig");
-}
diff --git a/test/cases/align.zig b/test/cases/align.zig
deleted file mode 100644
index 3dff57feb882141a8f9e7cabc1f710542310beb1..0000000000000000000000000000000000000000
--- a/test/cases/align.zig
+++ /dev/null
@@ -1,230 +0,0 @@
-const assert = @import("std").debug.assert;
-const builtin = @import("builtin");
-
-var foo: u8 align(4) = 100;
-
-test "global variable alignment" {
- assert(@typeOf(&foo).alignment == 4);
- assert(@typeOf(&foo) == *align(4) u8);
- const slice = (*[1]u8)(&foo)[0..];
- assert(@typeOf(slice) == []align(4) u8);
-}
-
-fn derp() align(@sizeOf(usize) * 2) i32 {
- return 1234;
-}
-fn noop1() align(1) void {}
-fn noop4() align(4) void {}
-
-test "function alignment" {
- assert(derp() == 1234);
- assert(@typeOf(noop1) == fn () align(1) void);
- assert(@typeOf(noop4) == fn () align(4) void);
- noop1();
- noop4();
-}
-
-var baz: packed struct {
- a: u32,
- b: u32,
-} = undefined;
-
-test "packed struct alignment" {
- assert(@typeOf(&baz.b) == *align(1) u32);
-}
-
-const blah: packed struct {
- a: u3,
- b: u3,
- c: u2,
-} = undefined;
-
-test "bit field alignment" {
- assert(@typeOf(&blah.b) == *align(1:3:1) const u3);
-}
-
-test "default alignment allows unspecified in type syntax" {
- assert(*u32 == *align(@alignOf(u32)) u32);
-}
-
-test "implicitly decreasing pointer alignment" {
- const a: u32 align(4) = 3;
- const b: u32 align(8) = 4;
- assert(addUnaligned(&a, &b) == 7);
-}
-
-fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
- return a.* + b.*;
-}
-
-test "implicitly decreasing slice alignment" {
- const a: u32 align(4) = 3;
- const b: u32 align(8) = 4;
- assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
-}
-fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
- return a[0] + b[0];
-}
-
-test "specifying alignment allows pointer cast" {
- testBytesAlign(0x33);
-}
-fn testBytesAlign(b: u8) void {
- var bytes align(4) = []u8{
- b,
- b,
- b,
- b,
- };
- const ptr = @ptrCast(*u32, &bytes[0]);
- assert(ptr.* == 0x33333333);
-}
-
-test "specifying alignment allows slice cast" {
- testBytesAlignSlice(0x33);
-}
-fn testBytesAlignSlice(b: u8) void {
- var bytes align(4) = []u8{
- b,
- b,
- b,
- b,
- };
- const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
- assert(slice[0] == 0x33333333);
-}
-
-test "@alignCast pointers" {
- var x: u32 align(4) = 1;
- expectsOnly1(&x);
- assert(x == 2);
-}
-fn expectsOnly1(x: *align(1) u32) void {
- expects4(@alignCast(4, x));
-}
-fn expects4(x: *align(4) u32) void {
- x.* += 1;
-}
-
-test "@alignCast slices" {
- var array align(4) = []u32{
- 1,
- 1,
- };
- const slice = array[0..];
- sliceExpectsOnly1(slice);
- assert(slice[0] == 2);
-}
-fn sliceExpectsOnly1(slice: []align(1) u32) void {
- sliceExpects4(@alignCast(4, slice));
-}
-fn sliceExpects4(slice: []align(4) u32) void {
- slice[0] += 1;
-}
-
-test "implicitly decreasing fn alignment" {
- testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
- testImplicitlyDecreaseFnAlign(alignedBig, 5678);
-}
-
-fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
- assert(ptr() == answer);
-}
-
-fn alignedSmall() align(8) i32 {
- return 1234;
-}
-fn alignedBig() align(16) i32 {
- return 5678;
-}
-
-test "@alignCast functions" {
- assert(fnExpectsOnly1(simple4) == 0x19);
-}
-fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 {
- return fnExpects4(@alignCast(4, ptr));
-}
-fn fnExpects4(ptr: fn () align(4) i32) i32 {
- return ptr();
-}
-fn simple4() align(4) i32 {
- return 0x19;
-}
-
-test "generic function with align param" {
- assert(whyWouldYouEverDoThis(1) == 0x1);
- assert(whyWouldYouEverDoThis(4) == 0x1);
- assert(whyWouldYouEverDoThis(8) == 0x1);
-}
-
-fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
- return 0x1;
-}
-
-test "@ptrCast preserves alignment of bigger source" {
- var x: u32 align(16) = 1234;
- const ptr = @ptrCast(*u8, &x);
- assert(@typeOf(ptr) == *align(16) u8);
-}
-
-test "runtime known array index has best alignment possible" {
- // take full advantage of over-alignment
- var array align(4) = []u8{ 1, 2, 3, 4 };
- assert(@typeOf(&array[0]) == *align(4) u8);
- assert(@typeOf(&array[1]) == *u8);
- assert(@typeOf(&array[2]) == *align(2) u8);
- assert(@typeOf(&array[3]) == *u8);
-
- // because align is too small but we still figure out to use 2
- var bigger align(2) = []u64{ 1, 2, 3, 4 };
- assert(@typeOf(&bigger[0]) == *align(2) u64);
- assert(@typeOf(&bigger[1]) == *align(2) u64);
- assert(@typeOf(&bigger[2]) == *align(2) u64);
- assert(@typeOf(&bigger[3]) == *align(2) u64);
-
- // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
- var smaller align(2) = []u32{ 1, 2, 3, 4 };
- comptime assert(@typeOf(smaller[0..]) == []align(2) u32);
- comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
- testIndex(smaller[0..].ptr, 0, *align(2) u32);
- testIndex(smaller[0..].ptr, 1, *align(2) u32);
- testIndex(smaller[0..].ptr, 2, *align(2) u32);
- testIndex(smaller[0..].ptr, 3, *align(2) u32);
-
- // has to use ABI alignment because index known at runtime only
- testIndex2(array[0..].ptr, 0, *u8);
- testIndex2(array[0..].ptr, 1, *u8);
- testIndex2(array[0..].ptr, 2, *u8);
- testIndex2(array[0..].ptr, 3, *u8);
-}
-fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
- comptime assert(@typeOf(&smaller[index]) == T);
-}
-fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void {
- comptime assert(@typeOf(&ptr[index]) == T);
-}
-
-test "alignstack" {
- assert(fnWithAlignedStack() == 1234);
-}
-
-fn fnWithAlignedStack() i32 {
- @setAlignStack(256);
- return 1234;
-}
-
-test "alignment of structs" {
- assert(@alignOf(struct {
- a: i32,
- b: *i32,
- }) == @alignOf(usize));
-}
-
-test "alignment of extern() void" {
- var runtime_nothing = nothing;
- const casted1 = @ptrCast(*const u8, runtime_nothing);
- const casted2 = @ptrCast(extern fn () void, casted1);
- casted2();
-}
-
-extern fn nothing() void {}
diff --git a/test/cases/alignof.zig b/test/cases/alignof.zig
deleted file mode 100644
index 433e86e45edfa3c1d3d41b4a519f24cf2f19a579..0000000000000000000000000000000000000000
--- a/test/cases/alignof.zig
+++ /dev/null
@@ -1,17 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-
-const Foo = struct {
- x: u32,
- y: u32,
- z: u32,
-};
-
-test "@alignOf(T) before referencing T" {
- comptime assert(@alignOf(Foo) != maxInt(usize));
- if (builtin.arch == builtin.Arch.x86_64) {
- comptime assert(@alignOf(Foo) == 4);
- }
-}
diff --git a/test/cases/array.zig b/test/cases/array.zig
deleted file mode 100644
index 7c63a649a8f322fe335039aa6717fea1333b3fcd..0000000000000000000000000000000000000000
--- a/test/cases/array.zig
+++ /dev/null
@@ -1,173 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-test "arrays" {
- var array: [5]u32 = undefined;
-
- var i: u32 = 0;
- while (i < 5) {
- array[i] = i + 1;
- i = array[i];
- }
-
- i = 0;
- var accumulator = u32(0);
- while (i < 5) {
- accumulator += array[i];
-
- i += 1;
- }
-
- assert(accumulator == 15);
- assert(getArrayLen(array) == 5);
-}
-fn getArrayLen(a: []const u32) usize {
- return a.len;
-}
-
-test "void arrays" {
- var array: [4]void = undefined;
- array[0] = void{};
- array[1] = array[2];
- assert(@sizeOf(@typeOf(array)) == 0);
- assert(array.len == 4);
-}
-
-test "array literal" {
- const hex_mult = []u16{
- 4096,
- 256,
- 16,
- 1,
- };
-
- assert(hex_mult.len == 4);
- assert(hex_mult[1] == 256);
-}
-
-test "array dot len const expr" {
- assert(comptime x: {
- break :x some_array.len == 4;
- });
-}
-
-const ArrayDotLenConstExpr = struct {
- y: [some_array.len]u8,
-};
-const some_array = []u8{
- 0,
- 1,
- 2,
- 3,
-};
-
-test "nested arrays" {
- const array_of_strings = [][]const u8{
- "hello",
- "this",
- "is",
- "my",
- "thing",
- };
- for (array_of_strings) |s, i| {
- if (i == 0) assert(mem.eql(u8, s, "hello"));
- if (i == 1) assert(mem.eql(u8, s, "this"));
- if (i == 2) assert(mem.eql(u8, s, "is"));
- if (i == 3) assert(mem.eql(u8, s, "my"));
- if (i == 4) assert(mem.eql(u8, s, "thing"));
- }
-}
-
-var s_array: [8]Sub = undefined;
-const Sub = struct {
- b: u8,
-};
-const Str = struct {
- a: []Sub,
-};
-test "set global var array via slice embedded in struct" {
- var s = Str{ .a = s_array[0..] };
-
- s.a[0].b = 1;
- s.a[1].b = 2;
- s.a[2].b = 3;
-
- assert(s_array[0].b == 1);
- assert(s_array[1].b == 2);
- assert(s_array[2].b == 3);
-}
-
-test "array literal with specified size" {
- var array = [2]u8{
- 1,
- 2,
- };
- assert(array[0] == 1);
- assert(array[1] == 2);
-}
-
-test "array child property" {
- var x: [5]i32 = undefined;
- assert(@typeOf(x).Child == i32);
-}
-
-test "array len property" {
- var x: [5]i32 = undefined;
- assert(@typeOf(x).len == 5);
-}
-
-test "array len field" {
- var arr = [4]u8{ 0, 0, 0, 0 };
- var ptr = &arr;
- assert(arr.len == 4);
- comptime assert(arr.len == 4);
- assert(ptr.len == 4);
- comptime assert(ptr.len == 4);
-}
-
-test "single-item pointer to array indexing and slicing" {
- testSingleItemPtrArrayIndexSlice();
- comptime testSingleItemPtrArrayIndexSlice();
-}
-
-fn testSingleItemPtrArrayIndexSlice() void {
- var array = "aaaa";
- doSomeMangling(&array);
- assert(mem.eql(u8, "azya", array));
-}
-
-fn doSomeMangling(array: *[4]u8) void {
- array[1] = 'z';
- array[2..3][0] = 'y';
-}
-
-test "implicit cast single-item pointer" {
- testImplicitCastSingleItemPtr();
- comptime testImplicitCastSingleItemPtr();
-}
-
-fn testImplicitCastSingleItemPtr() void {
- var byte: u8 = 100;
- const slice = (*[1]u8)(&byte)[0..];
- slice[0] += 1;
- assert(byte == 101);
-}
-
-fn testArrayByValAtComptime(b: [2]u8) u8 {
- return b[0];
-}
-
-test "comptime evalutating function that takes array by value" {
- const arr = []u8{ 0, 1 };
- _ = comptime testArrayByValAtComptime(arr);
- _ = comptime testArrayByValAtComptime(arr);
-}
-
-test "implicit comptime in array type size" {
- var arr: [plusOne(10)]bool = undefined;
- assert(arr.len == 11);
-}
-
-fn plusOne(x: u32) u32 {
- return x + 1;
-}
diff --git a/test/cases/asm.zig b/test/cases/asm.zig
deleted file mode 100644
index 63e37c857c1dd1440e5c2ceed002c2ac86743dc7..0000000000000000000000000000000000000000
--- a/test/cases/asm.zig
+++ /dev/null
@@ -1,48 +0,0 @@
-const config = @import("builtin");
-const assert = @import("std").debug.assert;
-
-comptime {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
- asm volatile (
- \\.globl aoeu;
- \\.type aoeu, @function;
- \\.set aoeu, derp;
- );
- }
-}
-
-test "module level assembly" {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
- assert(aoeu() == 1234);
- }
-}
-
-test "output constraint modifiers" {
- // This is only testing compilation.
- var a: u32 = 3;
- asm volatile ("" : [_]"=m,r"(a) : : "");
- asm volatile ("" : [_]"=r,m"(a) : : "");
-}
-
-test "alternative constraints" {
- // Make sure we allow commas as a separator for alternative constraints.
- var a: u32 = 3;
- asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : "");
-}
-
-test "sized integer/float in asm input" {
- asm volatile ("" : : [_]"m"(usize(3)) : "");
- asm volatile ("" : : [_]"m"(i15(-3)) : "");
- asm volatile ("" : : [_]"m"(u3(3)) : "");
- asm volatile ("" : : [_]"m"(i3(3)) : "");
- asm volatile ("" : : [_]"m"(u121(3)) : "");
- asm volatile ("" : : [_]"m"(i121(3)) : "");
- asm volatile ("" : : [_]"m"(f32(3.17)) : "");
- asm volatile ("" : : [_]"m"(f64(3.17)) : "");
-}
-
-extern fn aoeu() i32;
-
-export fn derp() i32 {
- return 1234;
-}
diff --git a/test/cases/atomics.zig b/test/cases/atomics.zig
deleted file mode 100644
index 67c9ab3dd117be1faf552e66fc1670a69b717fe2..0000000000000000000000000000000000000000
--- a/test/cases/atomics.zig
+++ /dev/null
@@ -1,71 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-const AtomicRmwOp = builtin.AtomicRmwOp;
-const AtomicOrder = builtin.AtomicOrder;
-
-test "cmpxchg" {
- var x: i32 = 1234;
- if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == 1234);
- } else {
- @panic("cmpxchg should have failed");
- }
-
- while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == 1234);
- }
- assert(x == 5678);
-
- assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
- assert(x == 42);
-}
-
-test "fence" {
- var x: i32 = 1234;
- @fence(AtomicOrder.SeqCst);
- x = 5678;
-}
-
-test "atomicrmw and atomicload" {
- var data: u8 = 200;
- testAtomicRmw(&data);
- assert(data == 42);
- testAtomicLoad(&data);
-}
-
-fn testAtomicRmw(ptr: *u8) void {
- const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
- assert(prev_value == 200);
- comptime {
- var x: i32 = 1234;
- const y: i32 = 12345;
- assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
- assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
- }
-}
-
-fn testAtomicLoad(ptr: *u8) void {
- const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
- assert(x == 42);
-}
-
-test "cmpxchg with ptr" {
- var data1: i32 = 1234;
- var data2: i32 = 5678;
- var data3: i32 = 9101;
- var x: *i32 = &data1;
- if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == &data1);
- } else {
- @panic("cmpxchg should have failed");
- }
-
- while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == &data1);
- }
- assert(x == &data3);
-
- assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
- assert(x == &data2);
-}
diff --git a/test/cases/bit_shifting.zig b/test/cases/bit_shifting.zig
deleted file mode 100644
index 325e765bb0a5e19400450982dfa0389462cdc2e3..0000000000000000000000000000000000000000
--- a/test/cases/bit_shifting.zig
+++ /dev/null
@@ -1,88 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {
- assert(Key == @IntType(false, Key.bit_count));
- assert(Key.bit_count >= mask_bit_count);
- const ShardKey = @IntType(false, mask_bit_count);
- const shift_amount = Key.bit_count - ShardKey.bit_count;
- return struct {
- const Self = @This();
- shards: [1 << ShardKey.bit_count]?*Node,
-
- pub fn create() Self {
- return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) };
- }
-
- fn getShardKey(key: Key) ShardKey {
- // https://github.com/ziglang/zig/issues/1544
- // this special case is needed because you can't u32 >> 32.
- if (ShardKey == u0) return 0;
-
- // this can be u1 >> u0
- const shard_key = key >> shift_amount;
-
- // TODO: https://github.com/ziglang/zig/issues/1544
- // This cast could be implicit if we teach the compiler that
- // u32 >> 30 -> u2
- return @intCast(ShardKey, shard_key);
- }
-
- pub fn put(self: *Self, node: *Node) void {
- const shard_key = Self.getShardKey(node.key);
- node.next = self.shards[shard_key];
- self.shards[shard_key] = node;
- }
-
- pub fn get(self: *Self, key: Key) ?*Node {
- const shard_key = Self.getShardKey(key);
- var maybe_node = self.shards[shard_key];
- while (maybe_node) |node| : (maybe_node = node.next) {
- if (node.key == key) return node;
- }
- return null;
- }
-
- pub const Node = struct {
- key: Key,
- value: V,
- next: ?*Node,
-
- pub fn init(self: *Node, key: Key, value: V) void {
- self.key = key;
- self.value = value;
- self.next = null;
- }
- };
- };
-}
-
-test "sharded table" {
- // realistic 16-way sharding
- testShardedTable(u32, 4, 8);
-
- testShardedTable(u5, 0, 32); // ShardKey == u0
- testShardedTable(u5, 2, 32);
- testShardedTable(u5, 5, 32);
-
- testShardedTable(u1, 0, 2);
- testShardedTable(u1, 1, 2); // this does u1 >> u0
-
- testShardedTable(u0, 0, 1);
-}
-fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void {
- const Table = ShardedTable(Key, mask_bit_count, void);
-
- var table = Table.create();
- var node_buffer: [node_count]Table.Node = undefined;
- for (node_buffer) |*node, i| {
- const key = @intCast(Key, i);
- assert(table.get(key) == null);
- node.init(key, {});
- table.put(node);
- }
-
- for (node_buffer) |*node, i| {
- assert(table.get(@intCast(Key, i)) == node);
- }
-}
diff --git a/test/cases/bitcast.zig b/test/cases/bitcast.zig
deleted file mode 100644
index d85a84ed225ea1f5b660952bbd7f80f69f0465c0..0000000000000000000000000000000000000000
--- a/test/cases/bitcast.zig
+++ /dev/null
@@ -1,37 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-
-test "@bitCast i32 -> u32" {
- testBitCast_i32_u32();
- comptime testBitCast_i32_u32();
-}
-
-fn testBitCast_i32_u32() void {
- assert(conv(-1) == maxInt(u32));
- assert(conv2(maxInt(u32)) == -1);
-}
-
-fn conv(x: i32) u32 {
- return @bitCast(u32, x);
-}
-fn conv2(x: u32) i32 {
- return @bitCast(i32, x);
-}
-
-test "@bitCast extern enum to its integer type" {
- const SOCK = extern enum {
- A,
- B,
-
- fn testBitCastExternEnum() void {
- var SOCK_DGRAM = @This().B;
- var sock_dgram = @bitCast(c_int, SOCK_DGRAM);
- assert(sock_dgram == 1);
- }
- };
-
- SOCK.testBitCastExternEnum();
- comptime SOCK.testBitCastExternEnum();
-}
-
diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig
deleted file mode 100644
index 3721e68a9431fa4fec723ff1ca53fc5f411f344d..0000000000000000000000000000000000000000
--- a/test/cases/bitreverse.zig
+++ /dev/null
@@ -1,81 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const minInt = std.math.minInt;
-
-test "@bitreverse" {
- comptime testBitReverse();
- testBitReverse();
-}
-
-fn testBitReverse() void {
- // using comptime_ints, unsigned
- assert(@bitreverse(u0, 0) == 0);
- assert(@bitreverse(u5, 0x12) == 0x9);
- assert(@bitreverse(u8, 0x12) == 0x48);
- assert(@bitreverse(u16, 0x1234) == 0x2c48);
- assert(@bitreverse(u24, 0x123456) == 0x6a2c48);
- assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48);
- assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48);
- assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48);
- assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48);
- assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
- assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
-
- // using runtime uints, unsigned
- var num0: u0 = 0;
- assert(@bitreverse(u0, num0) == 0);
- var num5: u5 = 0x12;
- assert(@bitreverse(u5, num5) == 0x9);
- var num8: u8 = 0x12;
- assert(@bitreverse(u8, num8) == 0x48);
- var num16: u16 = 0x1234;
- assert(@bitreverse(u16, num16) == 0x2c48);
- var num24: u24 = 0x123456;
- assert(@bitreverse(u24, num24) == 0x6a2c48);
- var num32: u32 = 0x12345678;
- assert(@bitreverse(u32, num32) == 0x1e6a2c48);
- var num40: u40 = 0x123456789a;
- assert(@bitreverse(u40, num40) == 0x591e6a2c48);
- var num48: u48 = 0x123456789abc;
- assert(@bitreverse(u48, num48) == 0x3d591e6a2c48);
- var num56: u56 = 0x123456789abcde;
- assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48);
- var num64: u64 = 0x123456789abcdef1;
- assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48);
- var num128: u128 = 0x123456789abcdef11121314151617181;
- assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
-
- // using comptime_ints, signed, positive
- assert(@bitreverse(i0, 0) == 0);
- assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49)));
- assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48)));
- assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48)));
- assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48)));
- assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48)));
- assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48)));
- assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48)));
- assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48)));
- assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48)));
-
- // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
- var neg5: i5 = minInt(i5) + 1;
- assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5));
- var neg8: i8 = -18;
- assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8));
- var neg16: i16 = -32694;
- assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16));
- var neg24: i24 = -6773785;
- assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24));
- var neg32: i32 = -16773785;
- assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32));
- var neg40: i40 = minInt(i40) + 12345;
- assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40));
- var neg48: i48 = minInt(i48) + 12345;
- assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48));
- var neg56: i56 = minInt(i56) + 12345;
- assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56));
- var neg64: i64 = minInt(i64) + 12345;
- assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64));
- var neg128: i128 = minInt(i128) + 12345;
- assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128));
-}
diff --git a/test/cases/bool.zig b/test/cases/bool.zig
deleted file mode 100644
index 3e4ac9c1cfe4d30f72189c27d47e6b4949ead971..0000000000000000000000000000000000000000
--- a/test/cases/bool.zig
+++ /dev/null
@@ -1,35 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "bool literals" {
- assert(true);
- assert(!false);
-}
-
-test "cast bool to int" {
- const t = true;
- const f = false;
- assert(@boolToInt(t) == u32(1));
- assert(@boolToInt(f) == u32(0));
- nonConstCastBoolToInt(t, f);
-}
-
-fn nonConstCastBoolToInt(t: bool, f: bool) void {
- assert(@boolToInt(t) == u32(1));
- assert(@boolToInt(f) == u32(0));
-}
-
-test "bool cmp" {
- assert(testBoolCmp(true, false) == false);
-}
-fn testBoolCmp(a: bool, b: bool) bool {
- return a == b;
-}
-
-const global_f = false;
-const global_t = true;
-const not_global_f = !global_f;
-const not_global_t = !global_t;
-test "compile time bool not" {
- assert(not_global_f);
- assert(!not_global_t);
-}
diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig
deleted file mode 100644
index 57993077e1a855fa9af487b136132d8bc0fa86ea..0000000000000000000000000000000000000000
--- a/test/cases/bswap.zig
+++ /dev/null
@@ -1,32 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "@bswap" {
- comptime testByteSwap();
- testByteSwap();
-}
-
-fn testByteSwap() void {
- assert(@bswap(u0, 0) == 0);
- assert(@bswap(u8, 0x12) == 0x12);
- assert(@bswap(u16, 0x1234) == 0x3412);
- assert(@bswap(u24, 0x123456) == 0x563412);
- assert(@bswap(u32, 0x12345678) == 0x78563412);
- assert(@bswap(u40, 0x123456789a) == 0x9a78563412);
- assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
- assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
- assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
- assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
-
- assert(@bswap(i0, 0) == 0);
- assert(@bswap(i8, -50) == -50);
- assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
- assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
- assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
- assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
- assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
- assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
- assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
- assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
- @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
-}
diff --git a/test/cases/bugs/1076.zig b/test/cases/bugs/1076.zig
deleted file mode 100644
index 7b843123104e5a2268e5a47081b44473e7ec4391..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1076.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-const assert = std.debug.assert;
-
-test "comptime code should not modify constant data" {
- testCastPtrOfArrayToSliceAndPtr();
- comptime testCastPtrOfArrayToSliceAndPtr();
-}
-
-fn testCastPtrOfArrayToSliceAndPtr() void {
- var array = "aoeu";
- const x: [*]u8 = &array;
- x[0] += 1;
- assert(mem.eql(u8, array[0..], "boeu"));
-}
-
diff --git a/test/cases/bugs/1111.zig b/test/cases/bugs/1111.zig
deleted file mode 100644
index f62107f9a3311864f7861e88713fc2b59a1f6297..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1111.zig
+++ /dev/null
@@ -1,12 +0,0 @@
-const Foo = extern enum {
- Bar = -1,
-};
-
-test "issue 1111 fixed" {
- const v = Foo.Bar;
-
- switch (v) {
- Foo.Bar => return,
- else => return,
- }
-}
diff --git a/test/cases/bugs/1277.zig b/test/cases/bugs/1277.zig
deleted file mode 100644
index a83e7653e27ac6604a725fb6fbf8b898434145d5..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1277.zig
+++ /dev/null
@@ -1,15 +0,0 @@
-const std = @import("std");
-
-const S = struct {
- f: ?fn () i32,
-};
-
-const s = S{ .f = f };
-
-fn f() i32 {
- return 1234;
-}
-
-test "don't emit an LLVM global for a const function when it's in an optional in a struct" {
- std.debug.assertOrPanic(s.f.?() == 1234);
-}
diff --git a/test/cases/bugs/1322.zig b/test/cases/bugs/1322.zig
deleted file mode 100644
index 2de92191ec17f36c0857ae320184412a9b7faee9..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1322.zig
+++ /dev/null
@@ -1,19 +0,0 @@
-const std = @import("std");
-
-const B = union(enum) {
- c: C,
- None,
-};
-
-const A = struct {
- b: B,
-};
-
-const C = struct {};
-
-test "tagged union with all void fields but a meaningful tag" {
- var a: A = A{ .b = B{ .c = C{} } };
- std.debug.assert(@TagType(B)(a.b) == @TagType(B).c);
- a = A{ .b = B.None };
- std.debug.assert(@TagType(B)(a.b) == @TagType(B).None);
-}
diff --git a/test/cases/bugs/1381.zig b/test/cases/bugs/1381.zig
deleted file mode 100644
index 2d452da15610e28f13c2a5d9811791435f0b757b..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1381.zig
+++ /dev/null
@@ -1,21 +0,0 @@
-const std = @import("std");
-
-const B = union(enum) {
- D: u8,
- E: u16,
-};
-
-const A = union(enum) {
- B: B,
- C: u8,
-};
-
-test "union that needs padding bytes inside an array" {
- var as = []A{
- A{ .B = B{ .D = 1 } },
- A{ .B = B{ .D = 1 } },
- };
-
- const a = as[0].B;
- std.debug.assertOrPanic(a.D == 1);
-}
diff --git a/test/cases/bugs/1421.zig b/test/cases/bugs/1421.zig
deleted file mode 100644
index fcbb8b70e4f8483fd8037025e6f6f155d75d7d42..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1421.zig
+++ /dev/null
@@ -1,14 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-
-const S = struct {
- fn method() builtin.TypeInfo {
- return @typeInfo(S);
- }
-};
-
-test "functions with return type required to be comptime are generic" {
- const ti = S.method();
- assert(builtin.TypeId(ti) == builtin.TypeId.Struct);
-}
diff --git a/test/cases/bugs/1442.zig b/test/cases/bugs/1442.zig
deleted file mode 100644
index e9dfd5d2ce031b532534d0b7ff6196a92f748ec5..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1442.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const std = @import("std");
-
-const Union = union(enum) {
- Text: []const u8,
- Color: u32,
-};
-
-test "const error union field alignment" {
- var union_or_err: anyerror!Union = Union{ .Color = 1234 };
- std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234);
-}
diff --git a/test/cases/bugs/1486.zig b/test/cases/bugs/1486.zig
deleted file mode 100644
index 98fae36d3a0f58223f4c4a62d310fab044a05f2e..0000000000000000000000000000000000000000
--- a/test/cases/bugs/1486.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const ptr = &global;
-var global: u64 = 123;
-
-test "constant pointer to global variable causes runtime load" {
- global = 1234;
- assert(&global == ptr);
- assert(ptr.* == 1234);
-}
-
diff --git a/test/cases/bugs/394.zig b/test/cases/bugs/394.zig
deleted file mode 100644
index b0afec23572a912a8185d871b733376ea448f25c..0000000000000000000000000000000000000000
--- a/test/cases/bugs/394.zig
+++ /dev/null
@@ -1,18 +0,0 @@
-const E = union(enum) {
- A: [9]u8,
- B: u64,
-};
-const S = struct {
- x: u8,
- y: E,
-};
-
-const assert = @import("std").debug.assert;
-
-test "bug 394 fixed" {
- const x = S{
- .x = 3,
- .y = E{ .B = 1 },
- };
- assert(x.x == 3);
-}
diff --git a/test/cases/bugs/655.zig b/test/cases/bugs/655.zig
deleted file mode 100644
index ebb8da0658d4c8d6bed4b281b386a2f7e122c828..0000000000000000000000000000000000000000
--- a/test/cases/bugs/655.zig
+++ /dev/null
@@ -1,12 +0,0 @@
-const std = @import("std");
-const other_file = @import("655_other_file.zig");
-
-test "function with *const parameter with type dereferenced by namespace" {
- const x: other_file.Integer = 1234;
- comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer);
- foo(&x);
-}
-
-fn foo(x: *const other_file.Integer) void {
- std.debug.assert(x.* == 1234);
-}
diff --git a/test/cases/bugs/655_other_file.zig b/test/cases/bugs/655_other_file.zig
deleted file mode 100644
index df1df44955229dbdab1b04022e754c670b6714c3..0000000000000000000000000000000000000000
--- a/test/cases/bugs/655_other_file.zig
+++ /dev/null
@@ -1 +0,0 @@
-pub const Integer = u32;
diff --git a/test/cases/bugs/656.zig b/test/cases/bugs/656.zig
deleted file mode 100644
index f93f0ac4d51f4cc9acb1c304183dbe3519d1b935..0000000000000000000000000000000000000000
--- a/test/cases/bugs/656.zig
+++ /dev/null
@@ -1,31 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const PrefixOp = union(enum) {
- Return,
- AddrOf: Value,
-};
-
-const Value = struct {
- align_expr: ?u32,
-};
-
-test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
- foo(false, true);
-}
-
-fn foo(a: bool, b: bool) void {
- var prefix_op = PrefixOp{
- .AddrOf = Value{ .align_expr = 1234 },
- };
- if (a) {} else {
- switch (prefix_op) {
- PrefixOp.AddrOf => |addr_of_info| {
- if (b) {}
- if (addr_of_info.align_expr) |align_expr| {
- assert(align_expr == 1234);
- }
- },
- PrefixOp.Return => {},
- }
- }
-}
diff --git a/test/cases/bugs/726.zig b/test/cases/bugs/726.zig
deleted file mode 100644
index 2acc91eb26c17d98239b1650cdae614296012526..0000000000000000000000000000000000000000
--- a/test/cases/bugs/726.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "@ptrCast from const to nullable" {
- const c: u8 = 4;
- var x: ?*const u8 = @ptrCast(?*const u8, &c);
- assert(x.?.* == 4);
-}
-
-test "@ptrCast from var in empty struct to nullable" {
- const container = struct {
- var c: u8 = 4;
- };
- var x: ?*const u8 = @ptrCast(?*const u8, &container.c);
- assert(x.?.* == 4);
-}
-
diff --git a/test/cases/bugs/828.zig b/test/cases/bugs/828.zig
deleted file mode 100644
index 50ae0fd279fdcf52c46f016ee2d274928c0d5231..0000000000000000000000000000000000000000
--- a/test/cases/bugs/828.zig
+++ /dev/null
@@ -1,33 +0,0 @@
-const CountBy = struct {
- a: usize,
-
- const One = CountBy{ .a = 1 };
-
- pub fn counter(self: *const CountBy) Counter {
- return Counter{ .i = 0 };
- }
-};
-
-const Counter = struct {
- i: usize,
-
- pub fn count(self: *Counter) bool {
- self.i += 1;
- return self.i <= 10;
- }
-};
-
-fn constCount(comptime cb: *const CountBy, comptime unused: u32) void {
- comptime {
- var cnt = cb.counter();
- if (cnt.i != 0) @compileError("Counter instance reused!");
- while (cnt.count()) {}
- }
-}
-
-test "comptime struct return should not return the same instance" {
- //the first parameter must be passed by reference to trigger the bug
- //a second parameter is required to trigger the bug
- const ValA = constCount(&CountBy.One, 12);
- const ValB = constCount(&CountBy.One, 15);
-}
diff --git a/test/cases/bugs/920.zig b/test/cases/bugs/920.zig
deleted file mode 100644
index 2903f05a29abcb0a0d85ca4bb262e8a6455e83cf..0000000000000000000000000000000000000000
--- a/test/cases/bugs/920.zig
+++ /dev/null
@@ -1,65 +0,0 @@
-const std = @import("std");
-const math = std.math;
-const Random = std.rand.Random;
-
-const ZigTable = struct {
- r: f64,
- x: [257]f64,
- f: [257]f64,
-
- pdf: fn (f64) f64,
- is_symmetric: bool,
- zero_case: fn (*Random, f64) f64,
-};
-
-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 {
- var tables: ZigTable = undefined;
-
- tables.is_symmetric = is_symmetric;
- tables.r = r;
- tables.pdf = f;
- tables.zero_case = zero_case;
-
- tables.x[0] = v / f(r);
- tables.x[1] = r;
-
- for (tables.x[2..256]) |*entry, i| {
- const last = tables.x[2 + i - 1];
- entry.* = f_inv(v / last + f(last));
- }
- tables.x[256] = 0;
-
- for (tables.f[0..]) |*entry, i| {
- entry.* = f(tables.x[i]);
- }
-
- return tables;
-}
-
-const norm_r = 3.6541528853610088;
-const norm_v = 0.00492867323399;
-
-fn norm_f(x: f64) f64 {
- return math.exp(-x * x / 2.0);
-}
-fn norm_f_inv(y: f64) f64 {
- return math.sqrt(-2.0 * math.ln(y));
-}
-fn norm_zero_case(random: *Random, u: f64) f64 {
- return 0.0;
-}
-
-const NormalDist = blk: {
- @setEvalBranchQuota(30000);
- break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
-};
-
-test "bug 920 fixed" {
- const NormalDist1 = blk: {
- break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
- };
-
- for (NormalDist1.f) |_, i| {
- std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]);
- }
-}
diff --git a/test/cases/byval_arg_var.zig b/test/cases/byval_arg_var.zig
deleted file mode 100644
index 826b9cc9e59334d4c67300ac5740929539c6217d..0000000000000000000000000000000000000000
--- a/test/cases/byval_arg_var.zig
+++ /dev/null
@@ -1,27 +0,0 @@
-const std = @import("std");
-
-var result: []const u8 = "wrong";
-
-test "aoeu" {
- start();
- blowUpStack(10);
-
- std.debug.assert(std.mem.eql(u8, result, "string literal"));
-}
-
-fn start() void {
- foo("string literal");
-}
-
-fn foo(x: var) void {
- bar(x);
-}
-
-fn bar(x: var) void {
- result = x;
-}
-
-fn blowUpStack(x: u32) void {
- if (x == 0) return;
- blowUpStack(x - 1);
-}
diff --git a/test/cases/cancel.zig b/test/cases/cancel.zig
deleted file mode 100644
index c0f74fd34f4430b1a145aa51230cdb26c4a7a45f..0000000000000000000000000000000000000000
--- a/test/cases/cancel.zig
+++ /dev/null
@@ -1,92 +0,0 @@
-const std = @import("std");
-
-var defer_f1: bool = false;
-var defer_f2: bool = false;
-var defer_f3: bool = false;
-
-test "cancel forwards" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- const p = async<&da.allocator> f1() catch unreachable;
- cancel p;
- std.debug.assert(defer_f1);
- std.debug.assert(defer_f2);
- std.debug.assert(defer_f3);
-}
-
-async fn f1() void {
- defer {
- defer_f1 = true;
- }
- await (async f2() catch unreachable);
-}
-
-async fn f2() void {
- defer {
- defer_f2 = true;
- }
- await (async f3() catch unreachable);
-}
-
-async fn f3() void {
- defer {
- defer_f3 = true;
- }
- suspend;
-}
-
-var defer_b1: bool = false;
-var defer_b2: bool = false;
-var defer_b3: bool = false;
-var defer_b4: bool = false;
-
-test "cancel backwards" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- const p = async<&da.allocator> b1() catch unreachable;
- cancel p;
- std.debug.assert(defer_b1);
- std.debug.assert(defer_b2);
- std.debug.assert(defer_b3);
- std.debug.assert(defer_b4);
-}
-
-async fn b1() void {
- defer {
- defer_b1 = true;
- }
- await (async b2() catch unreachable);
-}
-
-var b4_handle: promise = undefined;
-
-async fn b2() void {
- const b3_handle = async b3() catch unreachable;
- resume b4_handle;
- cancel b4_handle;
- defer {
- defer_b2 = true;
- }
- const value = await b3_handle;
- @panic("unreachable");
-}
-
-async fn b3() i32 {
- defer {
- defer_b3 = true;
- }
- await (async b4() catch unreachable);
- return 1234;
-}
-
-async fn b4() void {
- defer {
- defer_b4 = true;
- }
- suspend {
- b4_handle = @handle();
- }
- suspend;
-}
diff --git a/test/cases/cast.zig b/test/cases/cast.zig
deleted file mode 100644
index bd45bbc00f089ee1998b4327fe1ced55efc49e60..0000000000000000000000000000000000000000
--- a/test/cases/cast.zig
+++ /dev/null
@@ -1,472 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const mem = std.mem;
-const maxInt = std.math.maxInt;
-
-test "int to ptr cast" {
- const x = usize(13);
- const y = @intToPtr(*u8, x);
- const z = @ptrToInt(y);
- assert(z == 13);
-}
-
-test "integer literal to pointer cast" {
- const vga_mem = @intToPtr(*u16, 0xB8000);
- assert(@ptrToInt(vga_mem) == 0xB8000);
-}
-
-test "pointer reinterpret const float to int" {
- const float: f64 = 5.99999999999994648725e-01;
- const float_ptr = &float;
- const int_ptr = @ptrCast(*const i32, float_ptr);
- const int_val = int_ptr.*;
- assert(int_val == 858993411);
-}
-
-test "implicitly cast indirect pointer to maybe-indirect pointer" {
- const S = struct {
- const Self = @This();
- x: u8,
- fn constConst(p: *const *const Self) u8 {
- return p.*.x;
- }
- fn maybeConstConst(p: ?*const *const Self) u8 {
- return p.?.*.x;
- }
- fn constConstConst(p: *const *const *const Self) u8 {
- return p.*.*.x;
- }
- fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
- return p.?.*.*.x;
- }
- };
- const s = S{ .x = 42 };
- const p = &s;
- const q = &p;
- const r = &q;
- assert(42 == S.constConst(q));
- assert(42 == S.maybeConstConst(q));
- assert(42 == S.constConstConst(r));
- assert(42 == S.maybeConstConstConst(r));
-}
-
-test "explicit cast from integer to error type" {
- testCastIntToErr(error.ItBroke);
- comptime testCastIntToErr(error.ItBroke);
-}
-fn testCastIntToErr(err: anyerror) void {
- const x = @errorToInt(err);
- const y = @intToError(x);
- assert(error.ItBroke == y);
-}
-
-test "peer resolve arrays of different size to const slice" {
- assert(mem.eql(u8, boolToStr(true), "true"));
- assert(mem.eql(u8, boolToStr(false), "false"));
- comptime assert(mem.eql(u8, boolToStr(true), "true"));
- comptime assert(mem.eql(u8, boolToStr(false), "false"));
-}
-fn boolToStr(b: bool) []const u8 {
- return if (b) "true" else "false";
-}
-
-test "peer resolve array and const slice" {
- testPeerResolveArrayConstSlice(true);
- comptime testPeerResolveArrayConstSlice(true);
-}
-fn testPeerResolveArrayConstSlice(b: bool) void {
- const value1 = if (b) "aoeu" else ([]const u8)("zz");
- const value2 = if (b) ([]const u8)("zz") else "aoeu";
- assert(mem.eql(u8, value1, "aoeu"));
- assert(mem.eql(u8, value2, "zz"));
-}
-
-test "implicitly cast from T to anyerror!?T" {
- castToOptionalTypeError(1);
- comptime castToOptionalTypeError(1);
-}
-const A = struct {
- a: i32,
-};
-fn castToOptionalTypeError(z: i32) void {
- const x = i32(1);
- const y: anyerror!?i32 = x;
- assert((try y).? == 1);
-
- const f = z;
- const g: anyerror!?i32 = f;
-
- const a = A{ .a = z };
- const b: anyerror!?A = a;
- assert((b catch unreachable).?.a == 1);
-}
-
-test "implicitly cast from int to anyerror!?T" {
- implicitIntLitToOptional();
- comptime implicitIntLitToOptional();
-}
-fn implicitIntLitToOptional() void {
- const f: ?i32 = 1;
- const g: anyerror!?i32 = 1;
-}
-
-test "return null from fn() anyerror!?&T" {
- const a = returnNullFromOptionalTypeErrorRef();
- const b = returnNullLitFromOptionalTypeErrorRef();
- assert((try a) == null and (try b) == null);
-}
-fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
- const a: ?*A = null;
- return a;
-}
-fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
- return null;
-}
-
-test "peer type resolution: ?T and T" {
- assert(peerTypeTAndOptionalT(true, false).? == 0);
- assert(peerTypeTAndOptionalT(false, false).? == 3);
- comptime {
- assert(peerTypeTAndOptionalT(true, false).? == 0);
- assert(peerTypeTAndOptionalT(false, false).? == 3);
- }
-}
-fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
- if (c) {
- return if (b) null else usize(0);
- }
-
- return usize(3);
-}
-
-test "peer type resolution: [0]u8 and []const u8" {
- assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
- assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
- comptime {
- assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
- assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
- }
-}
-fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
- if (a) {
- return []const u8{};
- }
-
- return slice[0..1];
-}
-
-test "implicitly cast from [N]T to ?[]const T" {
- assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
- comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
-}
-
-fn castToOptionalSlice() ?[]const u8 {
- return "hi";
-}
-
-test "implicitly cast from [0]T to anyerror![]T" {
- testCastZeroArrayToErrSliceMut();
- comptime testCastZeroArrayToErrSliceMut();
-}
-
-fn testCastZeroArrayToErrSliceMut() void {
- assert((gimmeErrOrSlice() catch unreachable).len == 0);
-}
-
-fn gimmeErrOrSlice() anyerror![]u8 {
- return []u8{};
-}
-
-test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
- {
- var data = "hi";
- const slice = data[0..];
- assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
- }
- comptime {
- var data = "hi";
- const slice = data[0..];
- assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
- }
-}
-fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
- if (a) {
- return []u8{};
- }
-
- return slice[0..1];
-}
-
-test "resolve undefined with integer" {
- testResolveUndefWithInt(true, 1234);
- comptime testResolveUndefWithInt(true, 1234);
-}
-fn testResolveUndefWithInt(b: bool, x: i32) void {
- const value = if (b) x else undefined;
- if (b) {
- assert(value == x);
- }
-}
-
-test "implicit cast from &const [N]T to []const T" {
- testCastConstArrayRefToConstSlice();
- comptime testCastConstArrayRefToConstSlice();
-}
-
-fn testCastConstArrayRefToConstSlice() void {
- const blah = "aoeu";
- const const_array_ref = &blah;
- assert(@typeOf(const_array_ref) == *const [4]u8);
- const slice: []const u8 = const_array_ref;
- assert(mem.eql(u8, slice, "aoeu"));
-}
-
-test "peer type resolution: error and [N]T" {
- // TODO: implicit error!T to error!U where T can implicitly cast to U
- //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
- //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
- assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
- comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
-}
-
-//fn testPeerErrorAndArray(x: u8) error![]const u8 {
-// return switch (x) {
-// 0x00 => "OK",
-// else => error.BadValue,
-// };
-//}
-fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
- return switch (x) {
- 0x00 => "OK",
- 0x01 => "OKK",
- else => error.BadValue,
- };
-}
-
-test "@floatToInt" {
- testFloatToInts();
- comptime testFloatToInts();
-}
-
-fn testFloatToInts() void {
- const x = i32(1e4);
- assert(x == 10000);
- const y = @floatToInt(i32, f32(1e4));
- assert(y == 10000);
- expectFloatToInt(f16, 255.1, u8, 255);
- expectFloatToInt(f16, 127.2, i8, 127);
- expectFloatToInt(f16, -128.2, i8, -128);
- expectFloatToInt(f32, 255.1, u8, 255);
- expectFloatToInt(f32, 127.2, i8, 127);
- expectFloatToInt(f32, -128.2, i8, -128);
- expectFloatToInt(comptime_int, 1234, i16, 1234);
-}
-
-fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
- assert(@floatToInt(I, f) == i);
-}
-
-test "cast u128 to f128 and back" {
- comptime testCast128();
- testCast128();
-}
-
-fn testCast128() void {
- assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
-}
-
-fn cast128Int(x: f128) u128 {
- return @bitCast(u128, x);
-}
-
-fn cast128Float(x: u128) f128 {
- return @bitCast(f128, x);
-}
-
-test "const slice widen cast" {
- const bytes align(4) = []u8{
- 0x12,
- 0x12,
- 0x12,
- 0x12,
- };
-
- const u32_value = @bytesToSlice(u32, bytes[0..])[0];
- assert(u32_value == 0x12121212);
-
- assert(@bitCast(u32, bytes) == 0x12121212);
-}
-
-test "single-item pointer of array to slice and to unknown length pointer" {
- testCastPtrOfArrayToSliceAndPtr();
- comptime testCastPtrOfArrayToSliceAndPtr();
-}
-
-fn testCastPtrOfArrayToSliceAndPtr() void {
- var array = "aoeu";
- const x: [*]u8 = &array;
- x[0] += 1;
- assert(mem.eql(u8, array[0..], "boeu"));
- const y: []u8 = &array;
- y[0] += 1;
- assert(mem.eql(u8, array[0..], "coeu"));
-}
-
-test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
- const window_name = [1][*]const u8{c"window name"};
- const x: [*]const ?[*]const u8 = &window_name;
- assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
-}
-
-test "@intCast comptime_int" {
- const result = @intCast(i32, 1234);
- assert(@typeOf(result) == i32);
- assert(result == 1234);
-}
-
-test "@floatCast comptime_int and comptime_float" {
- {
- const result = @floatCast(f16, 1234);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
- }
- {
- const result = @floatCast(f16, 1234.0);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
- }
- {
- const result = @floatCast(f32, 1234);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
- }
- {
- const result = @floatCast(f32, 1234.0);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
- }
-}
-
-test "comptime_int @intToFloat" {
- {
- const result = @intToFloat(f16, 1234);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
- }
- {
- const result = @intToFloat(f32, 1234);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
- }
-}
-
-test "@bytesToSlice keeps pointer alignment" {
- var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
- const numbers = @bytesToSlice(u32, bytes[0..]);
- comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
-}
-
-test "@intCast i32 to u7" {
- var x: u128 = maxInt(u128);
- var y: i32 = 120;
- var z = x >> @intCast(u7, y);
- assert(z == 0xff);
-}
-
-test "implicit cast undefined to optional" {
- assert(MakeType(void).getNull() == null);
- assert(MakeType(void).getNonNull() != null);
-}
-
-fn MakeType(comptime T: type) type {
- return struct {
- fn getNull() ?T {
- return null;
- }
-
- fn getNonNull() ?T {
- return T(undefined);
- }
- };
-}
-
-test "implicit cast from *[N]T to ?[*]T" {
- var x: ?[*]u16 = null;
- var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
-
- x = &y;
- assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
- x.?[0] = 8;
- y[3] = 6;
- assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
-}
-
-test "implicit cast from *T to ?*c_void" {
- var a: u8 = 1;
- incrementVoidPtrValue(&a);
- std.debug.assert(a == 2);
-}
-
-fn incrementVoidPtrValue(value: ?*c_void) void {
- @ptrCast(*u8, value.?).* += 1;
-}
-
-test "implicit cast from [*]T to ?*c_void" {
- var a = []u8{ 3, 2, 1 };
- incrementVoidPtrArray(a[0..].ptr, 3);
- assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
-}
-
-fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
- var n: usize = 0;
- while (n < len) : (n += 1) {
- @ptrCast([*]u8, array.?)[n] += 1;
- }
-}
-
-test "*usize to *void" {
- var i = usize(0);
- var v = @ptrCast(*void, &i);
- v.* = {};
-}
-
-test "compile time int to ptr of function" {
- foobar(FUNCTION_CONSTANT);
-}
-
-pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
-pub const PFN_void = extern fn (*c_void) void;
-
-fn foobar(func: PFN_void) void {
- std.debug.assert(@ptrToInt(func) == maxInt(usize));
-}
-
-test "implicit ptr to *c_void" {
- var a: u32 = 1;
- var ptr: *c_void = &a;
- var b: *u32 = @ptrCast(*u32, ptr);
- assert(b.* == 1);
- var ptr2: ?*c_void = &a;
- var c: *u32 = @ptrCast(*u32, ptr2.?);
- assert(c.* == 1);
-}
-
-test "@intCast to comptime_int" {
- assert(@intCast(comptime_int, 0) == 0);
-}
-
-test "implicit cast comptime numbers to any type when the value fits" {
- const a: u64 = 255;
- var b: u8 = a;
- assert(b == 255);
-}
-
-test "@intToEnum passed a comptime_int to an enum with one item" {
- const E = enum {
- A,
- };
- const x = @intToEnum(E, 0);
- assert(x == E.A);
-}
diff --git a/test/cases/const_slice_child.zig b/test/cases/const_slice_child.zig
deleted file mode 100644
index 07d02d5df06fd7e0f32d2f03acbf0a0a99c1990a..0000000000000000000000000000000000000000
--- a/test/cases/const_slice_child.zig
+++ /dev/null
@@ -1,45 +0,0 @@
-const debug = @import("std").debug;
-const assert = debug.assert;
-
-var argv: [*]const [*]const u8 = undefined;
-
-test "const slice child" {
- const strs = ([][*]const u8){
- c"one",
- c"two",
- c"three",
- };
- // TODO this should implicitly cast
- argv = @ptrCast([*]const [*]const u8, &strs);
- bar(strs.len);
-}
-
-fn foo(args: [][]const u8) void {
- assert(args.len == 3);
- assert(streql(args[0], "one"));
- assert(streql(args[1], "two"));
- assert(streql(args[2], "three"));
-}
-
-fn bar(argc: usize) void {
- const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable;
- for (args) |_, i| {
- const ptr = argv[i];
- args[i] = ptr[0..strlen(ptr)];
- }
- foo(args);
-}
-
-fn strlen(ptr: [*]const u8) usize {
- var count: usize = 0;
- while (ptr[count] != 0) : (count += 1) {}
- return count;
-}
-
-fn streql(a: []const u8, b: []const u8) bool {
- if (a.len != b.len) return false;
- for (a) |item, index| {
- if (b[index] != item) return false;
- }
- return true;
-}
diff --git a/test/cases/coroutine_await_struct.zig b/test/cases/coroutine_await_struct.zig
deleted file mode 100644
index 79168715d8e25e43550e7ee770ebcba0be9be2f6..0000000000000000000000000000000000000000
--- a/test/cases/coroutine_await_struct.zig
+++ /dev/null
@@ -1,47 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-
-const Foo = struct {
- x: i32,
-};
-
-var await_a_promise: promise = undefined;
-var await_final_result = Foo{ .x = 0 };
-
-test "coroutine await struct" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- await_seq('a');
- const p = async<&da.allocator> await_amain() catch unreachable;
- await_seq('f');
- resume await_a_promise;
- await_seq('i');
- assert(await_final_result.x == 1234);
- assert(std.mem.eql(u8, await_points, "abcdefghi"));
-}
-async fn await_amain() void {
- await_seq('b');
- const p = async await_another() catch unreachable;
- await_seq('e');
- await_final_result = await p;
- await_seq('h');
-}
-async fn await_another() Foo {
- await_seq('c');
- suspend {
- await_seq('d');
- await_a_promise = @handle();
- }
- await_seq('g');
- return Foo{ .x = 1234 };
-}
-
-var await_points = []u8{0} ** "abcdefghi".len;
-var await_seq_index: usize = 0;
-
-fn await_seq(c: u8) void {
- await_points[await_seq_index] = c;
- await_seq_index += 1;
-}
diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig
deleted file mode 100644
index 89490ebc2c1c01e28fccadcab16ccf69c4c3bd3b..0000000000000000000000000000000000000000
--- a/test/cases/coroutines.zig
+++ /dev/null
@@ -1,258 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-
-var x: i32 = 1;
-
-test "create a coroutine and cancel it" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- const p = try async<&da.allocator> simpleAsyncFn();
- comptime assert(@typeOf(p) == promise->void);
- cancel p;
- assert(x == 2);
-}
-async fn simpleAsyncFn() void {
- x += 1;
- suspend;
- x += 1;
-}
-
-test "coroutine suspend, resume, cancel" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- seq('a');
- const p = try async<&da.allocator> testAsyncSeq();
- seq('c');
- resume p;
- seq('f');
- cancel p;
- seq('g');
-
- assert(std.mem.eql(u8, points, "abcdefg"));
-}
-async fn testAsyncSeq() void {
- defer seq('e');
-
- seq('b');
- suspend;
- seq('d');
-}
-var points = []u8{0} ** "abcdefg".len;
-var index: usize = 0;
-
-fn seq(c: u8) void {
- points[index] = c;
- index += 1;
-}
-
-test "coroutine suspend with block" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- const p = try async<&da.allocator> testSuspendBlock();
- std.debug.assert(!result);
- resume a_promise;
- std.debug.assert(result);
- cancel p;
-}
-
-var a_promise: promise = undefined;
-var result = false;
-async fn testSuspendBlock() void {
- suspend {
- comptime assert(@typeOf(@handle()) == promise->void);
- a_promise = @handle();
- }
-
- //Test to make sure that @handle() works as advertised (issue #1296)
- //var our_handle: promise = @handle();
- assert( a_promise == @handle() );
-
- result = true;
-}
-
-var await_a_promise: promise = undefined;
-var await_final_result: i32 = 0;
-
-test "coroutine await" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- await_seq('a');
- const p = async<&da.allocator> await_amain() catch unreachable;
- await_seq('f');
- resume await_a_promise;
- await_seq('i');
- assert(await_final_result == 1234);
- assert(std.mem.eql(u8, await_points, "abcdefghi"));
-}
-async fn await_amain() void {
- await_seq('b');
- const p = async await_another() catch unreachable;
- await_seq('e');
- await_final_result = await p;
- await_seq('h');
-}
-async fn await_another() i32 {
- await_seq('c');
- suspend {
- await_seq('d');
- await_a_promise = @handle();
- }
- await_seq('g');
- return 1234;
-}
-
-var await_points = []u8{0} ** "abcdefghi".len;
-var await_seq_index: usize = 0;
-
-fn await_seq(c: u8) void {
- await_points[await_seq_index] = c;
- await_seq_index += 1;
-}
-
-var early_final_result: i32 = 0;
-
-test "coroutine await early return" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
-
- early_seq('a');
- const p = async<&da.allocator> early_amain() catch @panic("out of memory");
- early_seq('f');
- assert(early_final_result == 1234);
- assert(std.mem.eql(u8, early_points, "abcdef"));
-}
-async fn early_amain() void {
- early_seq('b');
- const p = async early_another() catch @panic("out of memory");
- early_seq('d');
- early_final_result = await p;
- early_seq('e');
-}
-async fn early_another() i32 {
- early_seq('c');
- return 1234;
-}
-
-var early_points = []u8{0} ** "abcdef".len;
-var early_seq_index: usize = 0;
-
-fn early_seq(c: u8) void {
- early_points[early_seq_index] = c;
- early_seq_index += 1;
-}
-
-test "coro allocation failure" {
- var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
- if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
- @panic("expected allocation failure");
- } else |err| switch (err) {
- error.OutOfMemory => {},
- }
-}
-async fn asyncFuncThatNeverGetsRun() void {
- @panic("coro frame allocation should fail");
-}
-
-test "async function with dot syntax" {
- const S = struct {
- var y: i32 = 1;
- async fn foo() void {
- y += 1;
- suspend;
- }
- };
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
- const p = try async<&da.allocator> S.foo();
- cancel p;
- assert(S.y == 2);
-}
-
-test "async fn pointer in a struct field" {
- var data: i32 = 1;
- const Foo = struct {
- bar: async<*std.mem.Allocator> fn (*i32) void,
- };
- var foo = Foo{ .bar = simpleAsyncFn2 };
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
- const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
- assert(data == 2);
- cancel p;
- assert(data == 4);
-}
-async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
- defer y.* += 2;
- y.* += 1;
- suspend;
-}
-
-test "async fn with inferred error set" {
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
- const p = (async<&da.allocator> failing()) catch unreachable;
- resume p;
- cancel p;
-}
-async fn failing() !void {
- suspend;
- return error.Fail;
-}
-
-test "error return trace across suspend points - early return" {
- const p = nonFailing();
- resume p;
- var da = std.heap.DirectAllocator.init();
- defer da.deinit();
- const p2 = try async<&da.allocator> printTrace(p);
- cancel p2;
-}
-
-test "error return trace across suspend points - async return" {
- const p = nonFailing();
- const p2 = try async printTrace(p);
- resume p;
- cancel p2;
-}
-
-// TODO https://github.com/ziglang/zig/issues/760
-fn nonFailing() promise->(anyerror!void) {
- return async suspendThenFail() catch unreachable;
-}
-async fn suspendThenFail() anyerror!void {
- suspend;
- return error.Fail;
-}
-async fn printTrace(p: promise->(anyerror!void)) void {
- (await p) catch |e| {
- std.debug.assert(e == error.Fail);
- if (@errorReturnTrace()) |trace| {
- assert(trace.index == 1);
- } else switch (builtin.mode) {
- builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
- builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
- }
- };
-}
-
-test "break from suspend" {
- var buf: [500]u8 = undefined;
- var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
- var my_result: i32 = 1;
- const p = try async testBreakFromSuspend(&my_result);
- cancel p;
- std.debug.assert(my_result == 2);
-}
-async fn testBreakFromSuspend(my_result: *i32) void {
- suspend {
- resume @handle();
- }
- my_result.* += 1;
- suspend;
- my_result.* += 1;
-}
diff --git a/test/cases/defer.zig b/test/cases/defer.zig
deleted file mode 100644
index f9a2b69cd94b7513f0eb220653c7bbc562f73ea9..0000000000000000000000000000000000000000
--- a/test/cases/defer.zig
+++ /dev/null
@@ -1,78 +0,0 @@
-const assert = @import("std").debug.assert;
-
-var result: [3]u8 = undefined;
-var index: usize = undefined;
-
-fn runSomeErrorDefers(x: bool) !bool {
- index = 0;
- defer {
- result[index] = 'a';
- index += 1;
- }
- errdefer {
- result[index] = 'b';
- index += 1;
- }
- defer {
- result[index] = 'c';
- index += 1;
- }
- return if (x) x else error.FalseNotAllowed;
-}
-
-test "mixing normal and error defers" {
- assert(runSomeErrorDefers(true) catch unreachable);
- assert(result[0] == 'c');
- assert(result[1] == 'a');
-
- const ok = runSomeErrorDefers(false) catch |err| x: {
- assert(err == error.FalseNotAllowed);
- break :x true;
- };
- assert(ok);
- assert(result[0] == 'c');
- assert(result[1] == 'b');
- assert(result[2] == 'a');
-}
-
-test "break and continue inside loop inside defer expression" {
- testBreakContInDefer(10);
- comptime testBreakContInDefer(10);
-}
-
-fn testBreakContInDefer(x: usize) void {
- defer {
- var i: usize = 0;
- while (i < x) : (i += 1) {
- if (i < 5) continue;
- if (i == 5) break;
- }
- assert(i == 5);
- }
-}
-
-test "defer and labeled break" {
- var i = usize(0);
-
- blk: {
- defer i += 1;
- break :blk;
- }
-
- assert(i == 1);
-}
-
-test "errdefer does not apply to fn inside fn" {
- if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
-}
-
-fn testNestedFnErrDefer() anyerror!void {
- var a: i32 = 0;
- errdefer a += 1;
- const S = struct {
- fn baz() anyerror {
- return error.Bad;
- }
- };
- return S.baz();
-}
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
deleted file mode 100644
index 2dd552488c9461f81b3c4f138a7de36bb8640be8..0000000000000000000000000000000000000000
--- a/test/cases/enum.zig
+++ /dev/null
@@ -1,894 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-test "enum type" {
- const foo1 = Foo{ .One = 13 };
- const foo2 = Foo{
- .Two = Point{
- .x = 1234,
- .y = 5678,
- },
- };
- const bar = Bar.B;
-
- assert(bar == Bar.B);
- assert(@memberCount(Foo) == 3);
- assert(@memberCount(Bar) == 4);
- assert(@sizeOf(Foo) == @sizeOf(FooNoVoid));
- assert(@sizeOf(Bar) == 1);
-}
-
-test "enum as return value" {
- switch (returnAnInt(13)) {
- Foo.One => |value| assert(value == 13),
- else => unreachable,
- }
-}
-
-const Point = struct {
- x: u64,
- y: u64,
-};
-const Foo = union(enum) {
- One: i32,
- Two: Point,
- Three: void,
-};
-const FooNoVoid = union(enum) {
- One: i32,
- Two: Point,
-};
-const Bar = enum {
- A,
- B,
- C,
- D,
-};
-
-fn returnAnInt(x: i32) Foo {
- return Foo{ .One = x };
-}
-
-test "constant enum with payload" {
- var empty = AnEnumWithPayload{ .Empty = {} };
- var full = AnEnumWithPayload{ .Full = 13 };
- shouldBeEmpty(empty);
- shouldBeNotEmpty(full);
-}
-
-fn shouldBeEmpty(x: AnEnumWithPayload) void {
- switch (x) {
- AnEnumWithPayload.Empty => {},
- else => unreachable,
- }
-}
-
-fn shouldBeNotEmpty(x: AnEnumWithPayload) void {
- switch (x) {
- AnEnumWithPayload.Empty => unreachable,
- else => {},
- }
-}
-
-const AnEnumWithPayload = union(enum) {
- Empty: void,
- Full: i32,
-};
-
-const Number = enum {
- Zero,
- One,
- Two,
- Three,
- Four,
-};
-
-test "enum to int" {
- shouldEqual(Number.Zero, 0);
- shouldEqual(Number.One, 1);
- shouldEqual(Number.Two, 2);
- shouldEqual(Number.Three, 3);
- shouldEqual(Number.Four, 4);
-}
-
-fn shouldEqual(n: Number, expected: u3) void {
- assert(@enumToInt(n) == expected);
-}
-
-test "int to enum" {
- testIntToEnumEval(3);
-}
-fn testIntToEnumEval(x: i32) void {
- assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
-}
-const IntToEnumNumber = enum {
- Zero,
- One,
- Two,
- Three,
- Four,
-};
-
-test "@tagName" {
- assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
- comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
-}
-
-fn testEnumTagNameBare(n: BareNumber) []const u8 {
- return @tagName(n);
-}
-
-const BareNumber = enum {
- One,
- Two,
- Three,
-};
-
-test "enum alignment" {
- comptime {
- assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
- assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
- }
-}
-
-const AlignTestEnum = union(enum) {
- A: [9]u8,
- B: u64,
-};
-
-const ValueCount1 = enum {
- I0,
-};
-const ValueCount2 = enum {
- I0,
- I1,
-};
-const ValueCount256 = enum {
- I0,
- I1,
- I2,
- I3,
- I4,
- I5,
- I6,
- I7,
- I8,
- I9,
- I10,
- I11,
- I12,
- I13,
- I14,
- I15,
- I16,
- I17,
- I18,
- I19,
- I20,
- I21,
- I22,
- I23,
- I24,
- I25,
- I26,
- I27,
- I28,
- I29,
- I30,
- I31,
- I32,
- I33,
- I34,
- I35,
- I36,
- I37,
- I38,
- I39,
- I40,
- I41,
- I42,
- I43,
- I44,
- I45,
- I46,
- I47,
- I48,
- I49,
- I50,
- I51,
- I52,
- I53,
- I54,
- I55,
- I56,
- I57,
- I58,
- I59,
- I60,
- I61,
- I62,
- I63,
- I64,
- I65,
- I66,
- I67,
- I68,
- I69,
- I70,
- I71,
- I72,
- I73,
- I74,
- I75,
- I76,
- I77,
- I78,
- I79,
- I80,
- I81,
- I82,
- I83,
- I84,
- I85,
- I86,
- I87,
- I88,
- I89,
- I90,
- I91,
- I92,
- I93,
- I94,
- I95,
- I96,
- I97,
- I98,
- I99,
- I100,
- I101,
- I102,
- I103,
- I104,
- I105,
- I106,
- I107,
- I108,
- I109,
- I110,
- I111,
- I112,
- I113,
- I114,
- I115,
- I116,
- I117,
- I118,
- I119,
- I120,
- I121,
- I122,
- I123,
- I124,
- I125,
- I126,
- I127,
- I128,
- I129,
- I130,
- I131,
- I132,
- I133,
- I134,
- I135,
- I136,
- I137,
- I138,
- I139,
- I140,
- I141,
- I142,
- I143,
- I144,
- I145,
- I146,
- I147,
- I148,
- I149,
- I150,
- I151,
- I152,
- I153,
- I154,
- I155,
- I156,
- I157,
- I158,
- I159,
- I160,
- I161,
- I162,
- I163,
- I164,
- I165,
- I166,
- I167,
- I168,
- I169,
- I170,
- I171,
- I172,
- I173,
- I174,
- I175,
- I176,
- I177,
- I178,
- I179,
- I180,
- I181,
- I182,
- I183,
- I184,
- I185,
- I186,
- I187,
- I188,
- I189,
- I190,
- I191,
- I192,
- I193,
- I194,
- I195,
- I196,
- I197,
- I198,
- I199,
- I200,
- I201,
- I202,
- I203,
- I204,
- I205,
- I206,
- I207,
- I208,
- I209,
- I210,
- I211,
- I212,
- I213,
- I214,
- I215,
- I216,
- I217,
- I218,
- I219,
- I220,
- I221,
- I222,
- I223,
- I224,
- I225,
- I226,
- I227,
- I228,
- I229,
- I230,
- I231,
- I232,
- I233,
- I234,
- I235,
- I236,
- I237,
- I238,
- I239,
- I240,
- I241,
- I242,
- I243,
- I244,
- I245,
- I246,
- I247,
- I248,
- I249,
- I250,
- I251,
- I252,
- I253,
- I254,
- I255,
-};
-const ValueCount257 = enum {
- I0,
- I1,
- I2,
- I3,
- I4,
- I5,
- I6,
- I7,
- I8,
- I9,
- I10,
- I11,
- I12,
- I13,
- I14,
- I15,
- I16,
- I17,
- I18,
- I19,
- I20,
- I21,
- I22,
- I23,
- I24,
- I25,
- I26,
- I27,
- I28,
- I29,
- I30,
- I31,
- I32,
- I33,
- I34,
- I35,
- I36,
- I37,
- I38,
- I39,
- I40,
- I41,
- I42,
- I43,
- I44,
- I45,
- I46,
- I47,
- I48,
- I49,
- I50,
- I51,
- I52,
- I53,
- I54,
- I55,
- I56,
- I57,
- I58,
- I59,
- I60,
- I61,
- I62,
- I63,
- I64,
- I65,
- I66,
- I67,
- I68,
- I69,
- I70,
- I71,
- I72,
- I73,
- I74,
- I75,
- I76,
- I77,
- I78,
- I79,
- I80,
- I81,
- I82,
- I83,
- I84,
- I85,
- I86,
- I87,
- I88,
- I89,
- I90,
- I91,
- I92,
- I93,
- I94,
- I95,
- I96,
- I97,
- I98,
- I99,
- I100,
- I101,
- I102,
- I103,
- I104,
- I105,
- I106,
- I107,
- I108,
- I109,
- I110,
- I111,
- I112,
- I113,
- I114,
- I115,
- I116,
- I117,
- I118,
- I119,
- I120,
- I121,
- I122,
- I123,
- I124,
- I125,
- I126,
- I127,
- I128,
- I129,
- I130,
- I131,
- I132,
- I133,
- I134,
- I135,
- I136,
- I137,
- I138,
- I139,
- I140,
- I141,
- I142,
- I143,
- I144,
- I145,
- I146,
- I147,
- I148,
- I149,
- I150,
- I151,
- I152,
- I153,
- I154,
- I155,
- I156,
- I157,
- I158,
- I159,
- I160,
- I161,
- I162,
- I163,
- I164,
- I165,
- I166,
- I167,
- I168,
- I169,
- I170,
- I171,
- I172,
- I173,
- I174,
- I175,
- I176,
- I177,
- I178,
- I179,
- I180,
- I181,
- I182,
- I183,
- I184,
- I185,
- I186,
- I187,
- I188,
- I189,
- I190,
- I191,
- I192,
- I193,
- I194,
- I195,
- I196,
- I197,
- I198,
- I199,
- I200,
- I201,
- I202,
- I203,
- I204,
- I205,
- I206,
- I207,
- I208,
- I209,
- I210,
- I211,
- I212,
- I213,
- I214,
- I215,
- I216,
- I217,
- I218,
- I219,
- I220,
- I221,
- I222,
- I223,
- I224,
- I225,
- I226,
- I227,
- I228,
- I229,
- I230,
- I231,
- I232,
- I233,
- I234,
- I235,
- I236,
- I237,
- I238,
- I239,
- I240,
- I241,
- I242,
- I243,
- I244,
- I245,
- I246,
- I247,
- I248,
- I249,
- I250,
- I251,
- I252,
- I253,
- I254,
- I255,
- I256,
-};
-
-test "enum sizes" {
- comptime {
- assert(@sizeOf(ValueCount1) == 0);
- assert(@sizeOf(ValueCount2) == 1);
- assert(@sizeOf(ValueCount256) == 1);
- assert(@sizeOf(ValueCount257) == 2);
- }
-}
-
-const Small2 = enum(u2) {
- One,
- Two,
-};
-const Small = enum(u2) {
- One,
- Two,
- Three,
- Four,
-};
-
-test "set enum tag type" {
- {
- var x = Small.One;
- x = Small.Two;
- comptime assert(@TagType(Small) == u2);
- }
- {
- var x = Small2.One;
- x = Small2.Two;
- comptime assert(@TagType(Small2) == u2);
- }
-}
-
-const A = enum(u3) {
- One,
- Two,
- Three,
- Four,
- One2,
- Two2,
- Three2,
- Four2,
-};
-
-const B = enum(u3) {
- One3,
- Two3,
- Three3,
- Four3,
- One23,
- Two23,
- Three23,
- Four23,
-};
-
-const C = enum(u2) {
- One4,
- Two4,
- Three4,
- Four4,
-};
-
-const BitFieldOfEnums = packed struct {
- a: A,
- b: B,
- c: C,
-};
-
-const bit_field_1 = BitFieldOfEnums{
- .a = A.Two,
- .b = B.Three3,
- .c = C.Four4,
-};
-
-test "bit field access with enum fields" {
- var data = bit_field_1;
- assert(getA(&data) == A.Two);
- assert(getB(&data) == B.Three3);
- assert(getC(&data) == C.Four4);
- comptime assert(@sizeOf(BitFieldOfEnums) == 1);
-
- data.b = B.Four3;
- assert(data.b == B.Four3);
-
- data.a = A.Three;
- assert(data.a == A.Three);
- assert(data.b == B.Four3);
-}
-
-fn getA(data: *const BitFieldOfEnums) A {
- return data.a;
-}
-
-fn getB(data: *const BitFieldOfEnums) B {
- return data.b;
-}
-
-fn getC(data: *const BitFieldOfEnums) C {
- return data.c;
-}
-
-test "casting enum to its tag type" {
- testCastEnumToTagType(Small2.Two);
- comptime testCastEnumToTagType(Small2.Two);
-}
-
-fn testCastEnumToTagType(value: Small2) void {
- assert(@enumToInt(value) == 1);
-}
-
-const MultipleChoice = enum(u32) {
- A = 20,
- B = 40,
- C = 60,
- D = 1000,
-};
-
-test "enum with specified tag values" {
- testEnumWithSpecifiedTagValues(MultipleChoice.C);
- comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
-}
-
-fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
- assert(@enumToInt(x) == 60);
- assert(1234 == switch (x) {
- MultipleChoice.A => 1,
- MultipleChoice.B => 2,
- MultipleChoice.C => u32(1234),
- MultipleChoice.D => 4,
- });
-}
-
-const MultipleChoice2 = enum(u32) {
- Unspecified1,
- A = 20,
- Unspecified2,
- B = 40,
- Unspecified3,
- C = 60,
- Unspecified4,
- D = 1000,
- Unspecified5,
-};
-
-test "enum with specified and unspecified tag values" {
- testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
- comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
- assert(@enumToInt(x) == 1000);
- assert(1234 == switch (x) {
- MultipleChoice2.A => 1,
- MultipleChoice2.B => 2,
- MultipleChoice2.C => 3,
- MultipleChoice2.D => u32(1234),
- MultipleChoice2.Unspecified1 => 5,
- MultipleChoice2.Unspecified2 => 6,
- MultipleChoice2.Unspecified3 => 7,
- MultipleChoice2.Unspecified4 => 8,
- MultipleChoice2.Unspecified5 => 9,
- });
-}
-
-test "cast integer literal to enum" {
- assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
- assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
-}
-
-const EnumWithOneMember = enum {
- Eof,
-};
-
-fn doALoopThing(id: EnumWithOneMember) void {
- while (true) {
- if (id == EnumWithOneMember.Eof) {
- break;
- }
- @compileError("above if condition should be comptime");
- }
-}
-
-test "comparison operator on enum with one member is comptime known" {
- doALoopThing(EnumWithOneMember.Eof);
-}
-
-const State = enum {
- Start,
-};
-test "switch on enum with one member is comptime known" {
- var state = State.Start;
- switch (state) {
- State.Start => return,
- }
- @compileError("analysis should not reach here");
-}
-
-const EnumWithTagValues = enum(u4) {
- A = 1 << 0,
- B = 1 << 1,
- C = 1 << 2,
- D = 1 << 3,
-};
-test "enum with tag values don't require parens" {
- assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
-}
-
-test "enum with 1 field but explicit tag type should still have the tag type" {
- const Enum = enum(u8) {
- B = 2,
- };
- comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
-}
-
-test "empty extern enum with members" {
- const E = extern enum {
- A,
- B,
- C,
- };
- assert(@sizeOf(E) == @sizeOf(c_int));
-}
-
-test "aoeu" {
- const LocalFoo = enum {
- A = 1,
- B = 0,
- };
- var b = LocalFoo.B;
- assert(mem.eql(u8, @tagName(b), "B"));
-}
diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig
deleted file mode 100644
index 088496bd2f414128e74596c172df2cc3c2aab429..0000000000000000000000000000000000000000
--- a/test/cases/enum_with_members.zig
+++ /dev/null
@@ -1,27 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const fmt = @import("std").fmt;
-
-const ET = union(enum) {
- SINT: i32,
- UINT: u32,
-
- pub fn print(a: *const ET, buf: []u8) anyerror!usize {
- return switch (a.*) {
- ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
- ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
- };
- }
-};
-
-test "enum with members" {
- const a = ET{ .SINT = -42 };
- const b = ET{ .UINT = 42 };
- var buf: [20]u8 = undefined;
-
- assert((a.print(buf[0..]) catch unreachable) == 3);
- assert(mem.eql(u8, buf[0..3], "-42"));
-
- assert((b.print(buf[0..]) catch unreachable) == 2);
- assert(mem.eql(u8, buf[0..2], "42"));
-}
diff --git a/test/cases/error.zig b/test/cases/error.zig
deleted file mode 100644
index a731f39021f73f5e8e0f3baee83b5832738834d4..0000000000000000000000000000000000000000
--- a/test/cases/error.zig
+++ /dev/null
@@ -1,245 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const mem = std.mem;
-const builtin = @import("builtin");
-
-pub fn foo() anyerror!i32 {
- const x = try bar();
- return x + 1;
-}
-
-pub fn bar() anyerror!i32 {
- return 13;
-}
-
-pub fn baz() anyerror!i32 {
- const y = foo() catch 1234;
- return y + 1;
-}
-
-test "error wrapping" {
- assert((baz() catch unreachable) == 15);
-}
-
-fn gimmeItBroke() []const u8 {
- return @errorName(error.ItBroke);
-}
-
-test "@errorName" {
- assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
- assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
-}
-
-test "error values" {
- const a = @errorToInt(error.err1);
- const b = @errorToInt(error.err2);
- assert(a != b);
-}
-
-test "redefinition of error values allowed" {
- shouldBeNotEqual(error.AnError, error.SecondError);
-}
-fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
- if (a == b) unreachable;
-}
-
-test "error binary operator" {
- const a = errBinaryOperatorG(true) catch 3;
- const b = errBinaryOperatorG(false) catch 3;
- assert(a == 3);
- assert(b == 10);
-}
-fn errBinaryOperatorG(x: bool) anyerror!isize {
- return if (x) error.ItBroke else isize(10);
-}
-
-test "unwrap simple value from error" {
- const i = unwrapSimpleValueFromErrorDo() catch unreachable;
- assert(i == 13);
-}
-fn unwrapSimpleValueFromErrorDo() anyerror!isize {
- return 13;
-}
-
-test "error return in assignment" {
- doErrReturnInAssignment() catch unreachable;
-}
-
-fn doErrReturnInAssignment() anyerror!void {
- var x: i32 = undefined;
- x = try makeANonErr();
-}
-
-fn makeANonErr() anyerror!i32 {
- return 1;
-}
-
-test "error union type " {
- testErrorUnionType();
- comptime testErrorUnionType();
-}
-
-fn testErrorUnionType() void {
- const x: anyerror!i32 = 1234;
- if (x) |value| assert(value == 1234) else |_| unreachable;
- assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
- assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
- assert(@typeOf(x).ErrorSet == anyerror);
-}
-
-test "error set type " {
- testErrorSetType();
- comptime testErrorSetType();
-}
-
-const MyErrSet = error{
- OutOfMemory,
- FileNotFound,
-};
-
-fn testErrorSetType() void {
- assert(@memberCount(MyErrSet) == 2);
-
- const a: MyErrSet!i32 = 5678;
- const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
-
- if (a) |value| assert(value == 5678) else |err| switch (err) {
- error.OutOfMemory => unreachable,
- error.FileNotFound => unreachable,
- }
-}
-
-test "explicit error set cast" {
- testExplicitErrorSetCast(Set1.A);
- comptime testExplicitErrorSetCast(Set1.A);
-}
-
-const Set1 = error{
- A,
- B,
-};
-const Set2 = error{
- A,
- C,
-};
-
-fn testExplicitErrorSetCast(set1: Set1) void {
- var x = @errSetCast(Set2, set1);
- var y = @errSetCast(Set1, x);
- assert(y == error.A);
-}
-
-test "comptime test error for empty error set" {
- testComptimeTestErrorEmptySet(1234);
- comptime testComptimeTestErrorEmptySet(1234);
-}
-
-const EmptyErrorSet = error{};
-
-fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
- if (x) |v| assert(v == 1234) else |err| @compileError("bad");
-}
-
-test "syntax: optional operator in front of error union operator" {
- comptime {
- assert(?(anyerror!i32) == ?(anyerror!i32));
- }
-}
-
-test "comptime err to int of error set with only 1 possible value" {
- testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
- comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
-}
-fn testErrToIntWithOnePossibleValue(
- x: error{A},
- comptime value: u32,
-) void {
- if (@errorToInt(x) != value) {
- @compileError("bad");
- }
-}
-
-test "error union peer type resolution" {
- testErrorUnionPeerTypeResolution(1);
- comptime testErrorUnionPeerTypeResolution(1);
-}
-
-fn testErrorUnionPeerTypeResolution(x: i32) void {
- const y = switch (x) {
- 1 => bar_1(),
- 2 => baz_1(),
- else => quux_1(),
- };
-}
-
-fn bar_1() anyerror {
- return error.A;
-}
-
-fn baz_1() !i32 {
- return error.B;
-}
-
-fn quux_1() !i32 {
- return error.C;
-}
-
-test "error: fn returning empty error set can be passed as fn returning any error" {
- entry();
- comptime entry();
-}
-
-fn entry() void {
- foo2(bar2);
-}
-
-fn foo2(f: fn () anyerror!void) void {
- const x = f();
-}
-
-fn bar2() (error{}!void) {}
-
-test "error: Zero sized error set returned with value payload crash" {
- _ = foo3(0);
- _ = comptime foo3(0);
-}
-
-const Error = error{};
-fn foo3(b: usize) Error!usize {
- return b;
-}
-
-test "error: Infer error set from literals" {
- _ = nullLiteral("n") catch |err| handleErrors(err);
- _ = floatLiteral("n") catch |err| handleErrors(err);
- _ = intLiteral("n") catch |err| handleErrors(err);
- _ = comptime nullLiteral("n") catch |err| handleErrors(err);
- _ = comptime floatLiteral("n") catch |err| handleErrors(err);
- _ = comptime intLiteral("n") catch |err| handleErrors(err);
-}
-
-fn handleErrors(err: var) noreturn {
- switch (err) {
- error.T => {},
- }
-
- unreachable;
-}
-
-fn nullLiteral(str: []const u8) !?i64 {
- if (str[0] == 'n') return null;
-
- return error.T;
-}
-
-fn floatLiteral(str: []const u8) !?f64 {
- if (str[0] == 'n') return 1.0;
-
- return error.T;
-}
-
-fn intLiteral(str: []const u8) !?i64 {
- if (str[0] == 'n') return 1;
-
- return error.T;
-}
diff --git a/test/cases/eval.zig b/test/cases/eval.zig
deleted file mode 100644
index a9eded151ebc8f77f92bd174cb04553815fda3e2..0000000000000000000000000000000000000000
--- a/test/cases/eval.zig
+++ /dev/null
@@ -1,782 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-
-test "compile time recursion" {
- assert(some_data.len == 21);
-}
-var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
-fn fibonacci(x: i32) i32 {
- if (x <= 1) return 1;
- return fibonacci(x - 1) + fibonacci(x - 2);
-}
-
-fn unwrapAndAddOne(blah: ?i32) i32 {
- return blah.? + 1;
-}
-const should_be_1235 = unwrapAndAddOne(1234);
-test "static add one" {
- assert(should_be_1235 == 1235);
-}
-
-test "inlined loop" {
- comptime var i = 0;
- comptime var sum = 0;
- inline while (i <= 5) : (i += 1)
- sum += i;
- assert(sum == 15);
-}
-
-fn gimme1or2(comptime a: bool) i32 {
- const x: i32 = 1;
- const y: i32 = 2;
- comptime var z: i32 = if (a) x else y;
- return z;
-}
-test "inline variable gets result of const if" {
- assert(gimme1or2(true) == 1);
- assert(gimme1or2(false) == 2);
-}
-
-test "static function evaluation" {
- assert(statically_added_number == 3);
-}
-const statically_added_number = staticAdd(1, 2);
-fn staticAdd(a: i32, b: i32) i32 {
- return a + b;
-}
-
-test "const expr eval on single expr blocks" {
- assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
-}
-
-fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
- const literal = 3;
-
- const result = if (b) b: {
- break :b literal;
- } else b: {
- break :b x;
- };
-
- return result;
-}
-
-test "statically initialized list" {
- assert(static_point_list[0].x == 1);
- assert(static_point_list[0].y == 2);
- assert(static_point_list[1].x == 3);
- assert(static_point_list[1].y == 4);
-}
-const Point = struct {
- x: i32,
- y: i32,
-};
-const static_point_list = []Point{
- makePoint(1, 2),
- makePoint(3, 4),
-};
-fn makePoint(x: i32, y: i32) Point {
- return Point{
- .x = x,
- .y = y,
- };
-}
-
-test "static eval list init" {
- assert(static_vec3.data[2] == 1.0);
- assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
-}
-const static_vec3 = vec3(0.0, 0.0, 1.0);
-pub const Vec3 = struct {
- data: [3]f32,
-};
-pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
- return Vec3{ .data = []f32{
- x,
- y,
- z,
- } };
-}
-
-test "constant expressions" {
- var array: [array_size]u8 = undefined;
- assert(@sizeOf(@typeOf(array)) == 20);
-}
-const array_size: u8 = 20;
-
-test "constant struct with negation" {
- assert(vertices[0].x == -0.6);
-}
-const Vertex = struct {
- x: f32,
- y: f32,
- r: f32,
- g: f32,
- b: f32,
-};
-const vertices = []Vertex{
- Vertex{
- .x = -0.6,
- .y = -0.4,
- .r = 1.0,
- .g = 0.0,
- .b = 0.0,
- },
- Vertex{
- .x = 0.6,
- .y = -0.4,
- .r = 0.0,
- .g = 1.0,
- .b = 0.0,
- },
- Vertex{
- .x = 0.0,
- .y = 0.6,
- .r = 0.0,
- .g = 0.0,
- .b = 1.0,
- },
-};
-
-test "statically initialized struct" {
- st_init_str_foo.x += 1;
- assert(st_init_str_foo.x == 14);
-}
-const StInitStrFoo = struct {
- x: i32,
- y: bool,
-};
-var st_init_str_foo = StInitStrFoo{
- .x = 13,
- .y = true,
-};
-
-test "statically initalized array literal" {
- const y: [4]u8 = st_init_arr_lit_x;
- assert(y[3] == 4);
-}
-const st_init_arr_lit_x = []u8{
- 1,
- 2,
- 3,
- 4,
-};
-
-test "const slice" {
- comptime {
- const a = "1234567890";
- assert(a.len == 10);
- const b = a[1..2];
- assert(b.len == 1);
- assert(b[0] == '2');
- }
-}
-
-test "try to trick eval with runtime if" {
- assert(testTryToTrickEvalWithRuntimeIf(true) == 10);
-}
-
-fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
- comptime var i: usize = 0;
- inline while (i < 10) : (i += 1) {
- const result = if (b) false else true;
- }
- comptime {
- return i;
- }
-}
-
-fn max(comptime T: type, a: T, b: T) T {
- if (T == bool) {
- return a or b;
- } else if (a > b) {
- return a;
- } else {
- return b;
- }
-}
-fn letsTryToCompareBools(a: bool, b: bool) bool {
- return max(bool, a, b);
-}
-test "inlined block and runtime block phi" {
- assert(letsTryToCompareBools(true, true));
- assert(letsTryToCompareBools(true, false));
- assert(letsTryToCompareBools(false, true));
- assert(!letsTryToCompareBools(false, false));
-
- comptime {
- assert(letsTryToCompareBools(true, true));
- assert(letsTryToCompareBools(true, false));
- assert(letsTryToCompareBools(false, true));
- assert(!letsTryToCompareBools(false, false));
- }
-}
-
-const CmdFn = struct {
- name: []const u8,
- func: fn (i32) i32,
-};
-
-const cmd_fns = []CmdFn{
- CmdFn{
- .name = "one",
- .func = one,
- },
- CmdFn{
- .name = "two",
- .func = two,
- },
- CmdFn{
- .name = "three",
- .func = three,
- },
-};
-fn one(value: i32) i32 {
- return value + 1;
-}
-fn two(value: i32) i32 {
- return value + 2;
-}
-fn three(value: i32) i32 {
- return value + 3;
-}
-
-fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
- var result: i32 = start_value;
- comptime var i = 0;
- inline while (i < cmd_fns.len) : (i += 1) {
- if (cmd_fns[i].name[0] == prefix_char) {
- result = cmd_fns[i].func(result);
- }
- }
- return result;
-}
-
-test "comptime iterate over fn ptr list" {
- assert(performFn('t', 1) == 6);
- assert(performFn('o', 0) == 1);
- assert(performFn('w', 99) == 99);
-}
-
-test "eval @setRuntimeSafety at compile-time" {
- const result = comptime fnWithSetRuntimeSafety();
- assert(result == 1234);
-}
-
-fn fnWithSetRuntimeSafety() i32 {
- @setRuntimeSafety(true);
- return 1234;
-}
-
-test "eval @setFloatMode at compile-time" {
- const result = comptime fnWithFloatMode();
- assert(result == 1234.0);
-}
-
-fn fnWithFloatMode() f32 {
- @setFloatMode(builtin.FloatMode.Strict);
- return 1234.0;
-}
-
-const SimpleStruct = struct {
- field: i32,
-
- fn method(self: *const SimpleStruct) i32 {
- return self.field + 3;
- }
-};
-
-var simple_struct = SimpleStruct{ .field = 1234 };
-
-const bound_fn = simple_struct.method;
-
-test "call method on bound fn referring to var instance" {
- assert(bound_fn() == 1237);
-}
-
-test "ptr to local array argument at comptime" {
- comptime {
- var bytes: [10]u8 = undefined;
- modifySomeBytes(bytes[0..]);
- assert(bytes[0] == 'a');
- assert(bytes[9] == 'b');
- }
-}
-
-fn modifySomeBytes(bytes: []u8) void {
- bytes[0] = 'a';
- bytes[9] = 'b';
-}
-
-test "comparisons 0 <= uint and 0 > uint should be comptime" {
- testCompTimeUIntComparisons(1234);
-}
-fn testCompTimeUIntComparisons(x: u32) void {
- if (!(0 <= x)) {
- @compileError("this condition should be comptime known");
- }
- if (0 > x) {
- @compileError("this condition should be comptime known");
- }
- if (!(x >= 0)) {
- @compileError("this condition should be comptime known");
- }
- if (x < 0) {
- @compileError("this condition should be comptime known");
- }
-}
-
-test "const ptr to variable data changes at runtime" {
- assert(foo_ref.name[0] == 'a');
- foo_ref.name = "b";
- assert(foo_ref.name[0] == 'b');
-}
-
-const Foo = struct {
- name: []const u8,
-};
-
-var foo_contents = Foo{ .name = "a" };
-const foo_ref = &foo_contents;
-
-test "create global array with for loop" {
- assert(global_array[5] == 5 * 5);
- assert(global_array[9] == 9 * 9);
-}
-
-const global_array = x: {
- var result: [10]usize = undefined;
- for (result) |*item, index| {
- item.* = index * index;
- }
- break :x result;
-};
-
-test "compile-time downcast when the bits fit" {
- comptime {
- const spartan_count: u16 = 255;
- const byte = @intCast(u8, spartan_count);
- assert(byte == 255);
- }
-}
-
-const hi1 = "hi";
-const hi2 = hi1;
-test "const global shares pointer with other same one" {
- assertEqualPtrs(&hi1[0], &hi2[0]);
- comptime assert(&hi1[0] == &hi2[0]);
-}
-fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void {
- assert(ptr1 == ptr2);
-}
-
-test "@setEvalBranchQuota" {
- comptime {
- // 1001 for the loop and then 1 more for the assert fn call
- @setEvalBranchQuota(1002);
- var i = 0;
- var sum = 0;
- while (i < 1001) : (i += 1) {
- sum += i;
- }
- assert(sum == 500500);
- }
-}
-
-// TODO test "float literal at compile time not lossy" {
-// TODO assert(16777216.0 + 1.0 == 16777217.0);
-// TODO assert(9007199254740992.0 + 1.0 == 9007199254740993.0);
-// TODO }
-
-test "f32 at compile time is lossy" {
- assert(f32(1 << 24) + 1 == 1 << 24);
-}
-
-test "f64 at compile time is lossy" {
- assert(f64(1 << 53) + 1 == 1 << 53);
-}
-
-test "f128 at compile time is lossy" {
- assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
-}
-
-// TODO need a better implementation of bigfloat_init_bigint
-// assert(f128(1 << 113) == 10384593717069655257060992658440192);
-
-pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
- return struct {
- pub const Node = struct {};
- };
-}
-
-test "string literal used as comptime slice is memoized" {
- const a = "link";
- const b = "link";
- comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
- comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
-}
-
-test "comptime slice of undefined pointer of length 0" {
- const slice1 = ([*]i32)(undefined)[0..0];
- assert(slice1.len == 0);
- const slice2 = ([*]i32)(undefined)[100..100];
- assert(slice2.len == 0);
-}
-
-fn copyWithPartialInline(s: []u32, b: []u8) void {
- comptime var i: usize = 0;
- inline while (i < 4) : (i += 1) {
- s[i] = 0;
- s[i] |= u32(b[i * 4 + 0]) << 24;
- s[i] |= u32(b[i * 4 + 1]) << 16;
- s[i] |= u32(b[i * 4 + 2]) << 8;
- s[i] |= u32(b[i * 4 + 3]) << 0;
- }
-}
-
-test "binary math operator in partially inlined function" {
- var s: [4]u32 = undefined;
- var b: [16]u8 = undefined;
-
- for (b) |*r, i|
- r.* = @intCast(u8, i + 1);
-
- copyWithPartialInline(s[0..], b[0..]);
- assert(s[0] == 0x1020304);
- assert(s[1] == 0x5060708);
- assert(s[2] == 0x90a0b0c);
- assert(s[3] == 0xd0e0f10);
-}
-
-test "comptime function with the same args is memoized" {
- comptime {
- assert(MakeType(i32) == MakeType(i32));
- assert(MakeType(i32) != MakeType(f64));
- }
-}
-
-fn MakeType(comptime T: type) type {
- return struct {
- field: T,
- };
-}
-
-test "comptime function with mutable pointer is not memoized" {
- comptime {
- var x: i32 = 1;
- const ptr = &x;
- increment(ptr);
- increment(ptr);
- assert(x == 3);
- }
-}
-
-fn increment(value: *i32) void {
- value.* += 1;
-}
-
-fn generateTable(comptime T: type) [1010]T {
- var res: [1010]T = undefined;
- var i: usize = 0;
- while (i < 1010) : (i += 1) {
- res[i] = @intCast(T, i);
- }
- return res;
-}
-
-fn doesAlotT(comptime T: type, value: usize) T {
- @setEvalBranchQuota(5000);
- const table = comptime blk: {
- break :blk generateTable(T);
- };
- return table[value];
-}
-
-test "@setEvalBranchQuota at same scope as generic function call" {
- assert(doesAlotT(u32, 2) == 2);
-}
-
-test "comptime slice of slice preserves comptime var" {
- comptime {
- var buff: [10]u8 = undefined;
- buff[0..][0..][0] = 1;
- assert(buff[0..][0..][0] == 1);
- }
-}
-
-test "comptime slice of pointer preserves comptime var" {
- comptime {
- var buff: [10]u8 = undefined;
- var a = buff[0..].ptr;
- a[0..1][0] = 1;
- assert(buff[0..][0..][0] == 1);
- }
-}
-
-const SingleFieldStruct = struct {
- x: i32,
-
- fn read_x(self: *const SingleFieldStruct) i32 {
- return self.x;
- }
-};
-test "const ptr to comptime mutable data is not memoized" {
- comptime {
- var foo = SingleFieldStruct{ .x = 1 };
- assert(foo.read_x() == 1);
- foo.x = 2;
- assert(foo.read_x() == 2);
- }
-}
-
-test "array concat of slices gives slice" {
- comptime {
- var a: []const u8 = "aoeu";
- var b: []const u8 = "asdf";
- const c = a ++ b;
- assert(std.mem.eql(u8, c, "aoeuasdf"));
- }
-}
-
-test "comptime shlWithOverflow" {
- const ct_shifted: u64 = comptime amt: {
- var amt = u64(0);
- _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
- break :amt amt;
- };
-
- const rt_shifted: u64 = amt: {
- var amt = u64(0);
- _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
- break :amt amt;
- };
-
- assert(ct_shifted == rt_shifted);
-}
-
-test "runtime 128 bit integer division" {
- var a: u128 = 152313999999999991610955792383;
- var b: u128 = 10000000000000000000;
- var c = a / b;
- assert(c == 15231399999);
-}
-
-pub const Info = struct {
- version: u8,
-};
-
-pub const diamond_info = Info{ .version = 0 };
-
-test "comptime modification of const struct field" {
- comptime {
- var res = diamond_info;
- res.version = 1;
- assert(diamond_info.version == 0);
- assert(res.version == 1);
- }
-}
-
-test "pointer to type" {
- comptime {
- var T: type = i32;
- assert(T == i32);
- var ptr = &T;
- assert(@typeOf(ptr) == *type);
- ptr.* = f32;
- assert(T == f32);
- assert(*T == *f32);
- }
-}
-
-test "slice of type" {
- comptime {
- var types_array = []type{ i32, f64, type };
- for (types_array) |T, i| {
- switch (i) {
- 0 => assert(T == i32),
- 1 => assert(T == f64),
- 2 => assert(T == type),
- else => unreachable,
- }
- }
- for (types_array[0..]) |T, i| {
- switch (i) {
- 0 => assert(T == i32),
- 1 => assert(T == f64),
- 2 => assert(T == type),
- else => unreachable,
- }
- }
- }
-}
-
-const Wrapper = struct {
- T: type,
-};
-
-fn wrap(comptime T: type) Wrapper {
- return Wrapper{ .T = T };
-}
-
-test "function which returns struct with type field causes implicit comptime" {
- const ty = wrap(i32).T;
- assert(ty == i32);
-}
-
-test "call method with comptime pass-by-non-copying-value self parameter" {
- const S = struct {
- a: u8,
-
- fn b(comptime s: @This()) u8 {
- return s.a;
- }
- };
-
- const s = S{ .a = 2 };
- var b = s.b();
- assert(b == 2);
-}
-
-test "@tagName of @typeId" {
- const str = @tagName(@typeId(u8));
- assert(std.mem.eql(u8, str, "Int"));
-}
-
-test "setting backward branch quota just before a generic fn call" {
- @setEvalBranchQuota(1001);
- loopNTimes(1001);
-}
-
-fn loopNTimes(comptime n: usize) void {
- comptime var i = 0;
- inline while (i < n) : (i += 1) {}
-}
-
-test "variable inside inline loop that has different types on different iterations" {
- testVarInsideInlineLoop(true, u32(42));
-}
-
-fn testVarInsideInlineLoop(args: ...) void {
- comptime var i = 0;
- inline while (i < args.len) : (i += 1) {
- const x = args[i];
- if (i == 0) assert(x);
- if (i == 1) assert(x == 42);
- }
-}
-
-test "inline for with same type but different values" {
- var res: usize = 0;
- inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| {
- var a: T = undefined;
- res += a.len;
- }
- assert(res == 5);
-}
-
-test "refer to the type of a generic function" {
- const Func = fn (type) void;
- const f: Func = doNothingWithType;
- f(i32);
-}
-
-fn doNothingWithType(comptime T: type) void {}
-
-test "zero extend from u0 to u1" {
- var zero_u0: u0 = 0;
- var zero_u1: u1 = zero_u0;
- assert(zero_u1 == 0);
-}
-
-test "bit shift a u1" {
- var x: u1 = 1;
- var y = x << 0;
- assert(y == 1);
-}
-
-test "@intCast to a u0" {
- var x: u8 = 0;
- var y: u0 = @intCast(u0, x);
- assert(y == 0);
-}
-
-test "@bytesToslice on a packed struct" {
- const F = packed struct {
- a: u8,
- };
-
- var b = [1]u8{9};
- var f = @bytesToSlice(F, b);
- assert(f[0].a == 9);
-}
-
-test "comptime pointer cast array and then slice" {
- const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
-
- const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
- const sliceA: []const u8 = ptrA[0..2];
-
- const ptrB: [*]const u8 = &array;
- const sliceB: []const u8 = ptrB[0..2];
-
- assert(sliceA[1] == 2);
- assert(sliceB[1] == 2);
-}
-
-test "slice bounds in comptime concatenation" {
- const bs = comptime blk: {
- const b = c"11";
- break :blk b[0..1];
- };
- const str = "" ++ bs;
- assert(str.len == 1);
- assert(std.mem.eql(u8, str, "1"));
-
- const str2 = bs ++ "";
- assert(str2.len == 1);
- assert(std.mem.eql(u8, str2, "1"));
-}
-
-test "comptime bitwise operators" {
- comptime {
- assert(3 & 1 == 1);
- assert(3 & -1 == 3);
- assert(-3 & -1 == -3);
- assert(3 | -1 == -1);
- assert(-3 | -1 == -1);
- assert(3 ^ -1 == -4);
- assert(-3 ^ -1 == 2);
- assert(~i8(-1) == 0);
- assert(~i128(-1) == 0);
- assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
- assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
- assert(~u128(0) == 0xffffffffffffffffffffffffffffffff);
- }
-}
-
-test "*align(1) u16 is the same as *align(1:0:2) u16" {
- comptime {
- assert(*align(1:0:2) u16 == *align(1) u16);
- // TODO add parsing support for this syntax
- //assert(*align(:0:2) u16 == *u16);
- }
-}
-
-test "array concatenation forces comptime" {
- var a = oneItem(3) ++ oneItem(4);
- assert(std.mem.eql(i32, a, []i32{3, 4}));
-}
-
-test "array multiplication forces comptime" {
- var a = oneItem(3) ** scalar(2);
- assert(std.mem.eql(i32, a, []i32{3, 3}));
-}
-
-fn oneItem(x: i32) [1]i32 {
- return []i32{x};
-}
-
-fn scalar(x: u32) u32 {
- return x;
-}
diff --git a/test/cases/field_parent_ptr.zig b/test/cases/field_parent_ptr.zig
deleted file mode 100644
index 00d4e0f367217fe7a38fdeabedad3f6b7b03a8a4..0000000000000000000000000000000000000000
--- a/test/cases/field_parent_ptr.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "@fieldParentPtr non-first field" {
- testParentFieldPtr(&foo.c);
- comptime testParentFieldPtr(&foo.c);
-}
-
-test "@fieldParentPtr first field" {
- testParentFieldPtrFirst(&foo.a);
- comptime testParentFieldPtrFirst(&foo.a);
-}
-
-const Foo = struct {
- a: bool,
- b: f32,
- c: i32,
- d: i32,
-};
-
-const foo = Foo{
- .a = true,
- .b = 0.123,
- .c = 1234,
- .d = -10,
-};
-
-fn testParentFieldPtr(c: *const i32) void {
- assert(c == &foo.c);
-
- const base = @fieldParentPtr(Foo, "c", c);
- assert(base == &foo);
- assert(&base.c == c);
-}
-
-fn testParentFieldPtrFirst(a: *const bool) void {
- assert(a == &foo.a);
-
- const base = @fieldParentPtr(Foo, "a", a);
- assert(base == &foo);
- assert(&base.a == a);
-}
diff --git a/test/cases/fn.zig b/test/cases/fn.zig
deleted file mode 100644
index 8908bd785475e01bff8951d5fc42ea3ad2721f9a..0000000000000000000000000000000000000000
--- a/test/cases/fn.zig
+++ /dev/null
@@ -1,207 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "params" {
- assert(testParamsAdd(22, 11) == 33);
-}
-fn testParamsAdd(a: i32, b: i32) i32 {
- return a + b;
-}
-
-test "local variables" {
- testLocVars(2);
-}
-fn testLocVars(b: i32) void {
- const a: i32 = 1;
- if (a + b != 3) unreachable;
-}
-
-test "void parameters" {
- voidFun(1, void{}, 2, {});
-}
-fn voidFun(a: i32, b: void, c: i32, d: void) void {
- const v = b;
- const vv: void = if (a == 1) v else {};
- assert(a + c == 3);
- return vv;
-}
-
-test "mutable local variables" {
- var zero: i32 = 0;
- assert(zero == 0);
-
- var i = i32(0);
- while (i != 3) {
- i += 1;
- }
- assert(i == 3);
-}
-
-test "separate block scopes" {
- {
- const no_conflict: i32 = 5;
- assert(no_conflict == 5);
- }
-
- const c = x: {
- const no_conflict = i32(10);
- break :x no_conflict;
- };
- assert(c == 10);
-}
-
-test "call function with empty string" {
- acceptsString("");
-}
-
-fn acceptsString(foo: []u8) void {}
-
-fn @"weird function name"() i32 {
- return 1234;
-}
-test "weird function name" {
- assert(@"weird function name"() == 1234);
-}
-
-test "implicit cast function unreachable return" {
- wantsFnWithVoid(fnWithUnreachable);
-}
-
-fn wantsFnWithVoid(f: fn () void) void {}
-
-fn fnWithUnreachable() noreturn {
- unreachable;
-}
-
-test "function pointers" {
- const fns = []@typeOf(fn1){
- fn1,
- fn2,
- fn3,
- fn4,
- };
- for (fns) |f, i| {
- assert(f() == @intCast(u32, i) + 5);
- }
-}
-fn fn1() u32 {
- return 5;
-}
-fn fn2() u32 {
- return 6;
-}
-fn fn3() u32 {
- return 7;
-}
-fn fn4() u32 {
- return 8;
-}
-
-test "inline function call" {
- assert(@inlineCall(add, 3, 9) == 12);
-}
-
-fn add(a: i32, b: i32) i32 {
- return a + b;
-}
-
-test "number literal as an argument" {
- numberLiteralArg(3);
- comptime numberLiteralArg(3);
-}
-
-fn numberLiteralArg(a: var) void {
- assert(a == 3);
-}
-
-test "assign inline fn to const variable" {
- const a = inlineFn;
- a();
-}
-
-inline fn inlineFn() void {}
-
-test "pass by non-copying value" {
- assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
-}
-
-const Point = struct {
- x: i32,
- y: i32,
-};
-
-fn addPointCoords(pt: Point) i32 {
- return pt.x + pt.y;
-}
-
-test "pass by non-copying value through var arg" {
- assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
-}
-
-fn addPointCoordsVar(pt: var) i32 {
- comptime assert(@typeOf(pt) == Point);
- return pt.x + pt.y;
-}
-
-test "pass by non-copying value as method" {
- var pt = Point2{ .x = 1, .y = 2 };
- assert(pt.addPointCoords() == 3);
-}
-
-const Point2 = struct {
- x: i32,
- y: i32,
-
- fn addPointCoords(self: Point2) i32 {
- return self.x + self.y;
- }
-};
-
-test "pass by non-copying value as method, which is generic" {
- var pt = Point3{ .x = 1, .y = 2 };
- assert(pt.addPointCoords(i32) == 3);
-}
-
-const Point3 = struct {
- x: i32,
- y: i32,
-
- fn addPointCoords(self: Point3, comptime T: type) i32 {
- return self.x + self.y;
- }
-};
-
-test "pass by non-copying value as method, at comptime" {
- comptime {
- var pt = Point2{ .x = 1, .y = 2 };
- assert(pt.addPointCoords() == 3);
- }
-}
-
-fn outer(y: u32) fn (u32) u32 {
- const Y = @typeOf(y);
- const st = struct {
- fn get(z: u32) u32 {
- return z + @sizeOf(Y);
- }
- };
- return st.get;
-}
-
-test "return inner function which references comptime variable of outer function" {
- var func = outer(10);
- assert(func(3) == 7);
-}
-
-test "extern struct with stdcallcc fn pointer" {
- const S = extern struct {
- ptr: stdcallcc fn () i32,
-
- stdcallcc fn foo() i32 {
- return 1234;
- }
- };
-
- var s: S = undefined;
- s.ptr = S.foo;
- assert(s.ptr() == 1234);
-}
diff --git a/test/cases/fn_in_struct_in_comptime.zig b/test/cases/fn_in_struct_in_comptime.zig
deleted file mode 100644
index fabb57e9cbcbb7110d284b0a14a0da7be93370bf..0000000000000000000000000000000000000000
--- a/test/cases/fn_in_struct_in_comptime.zig
+++ /dev/null
@@ -1,17 +0,0 @@
-const assert = @import("std").debug.assert;
-
-fn get_foo() fn (*u8) usize {
- comptime {
- return struct {
- fn func(ptr: *u8) usize {
- var u = @ptrToInt(ptr);
- return u;
- }
- }.func;
- }
-}
-
-test "define a function in an anonymous struct in comptime" {
- const foo = get_foo();
- assert(foo(@intToPtr(*u8, 12345)) == 12345);
-}
diff --git a/test/cases/for.zig b/test/cases/for.zig
deleted file mode 100644
index aecd8b9a078488015de99fb6aed25ac005c11cc1..0000000000000000000000000000000000000000
--- a/test/cases/for.zig
+++ /dev/null
@@ -1,106 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const mem = std.mem;
-
-test "continue in for loop" {
- const array = []i32{
- 1,
- 2,
- 3,
- 4,
- 5,
- };
- var sum: i32 = 0;
- for (array) |x| {
- sum += x;
- if (x < 3) {
- continue;
- }
- break;
- }
- if (sum != 6) unreachable;
-}
-
-test "for loop with pointer elem var" {
- const source = "abcdefg";
- var target: [source.len]u8 = undefined;
- mem.copy(u8, target[0..], source);
- mangleString(target[0..]);
- assert(mem.eql(u8, target, "bcdefgh"));
-}
-fn mangleString(s: []u8) void {
- for (s) |*c| {
- c.* += 1;
- }
-}
-
-test "basic for loop" {
- const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
-
- var buffer: [expected_result.len]u8 = undefined;
- var buf_index: usize = 0;
-
- const array = []u8{ 9, 8, 7, 6 };
- for (array) |item| {
- buffer[buf_index] = item;
- buf_index += 1;
- }
- for (array) |item, index| {
- buffer[buf_index] = @intCast(u8, index);
- buf_index += 1;
- }
- const array_ptr = &array;
- for (array_ptr) |item| {
- buffer[buf_index] = item;
- buf_index += 1;
- }
- for (array_ptr) |item, index| {
- buffer[buf_index] = @intCast(u8, index);
- buf_index += 1;
- }
- const unknown_size: []const u8 = array;
- for (unknown_size) |item| {
- buffer[buf_index] = item;
- buf_index += 1;
- }
- for (unknown_size) |item, index| {
- buffer[buf_index] = @intCast(u8, index);
- buf_index += 1;
- }
-
- assert(mem.eql(u8, buffer[0..buf_index], expected_result));
-}
-
-test "break from outer for loop" {
- testBreakOuter();
- comptime testBreakOuter();
-}
-
-fn testBreakOuter() void {
- var array = "aoeu";
- var count: usize = 0;
- outer: for (array) |_| {
- for (array) |_| {
- count += 1;
- break :outer;
- }
- }
- assert(count == 1);
-}
-
-test "continue outer for loop" {
- testContinueOuter();
- comptime testContinueOuter();
-}
-
-fn testContinueOuter() void {
- var array = "aoeu";
- var counter: usize = 0;
- outer: for (array) |_| {
- for (array) |_| {
- counter += 1;
- continue :outer;
- }
- }
- assert(counter == array.len);
-}
diff --git a/test/cases/generics.zig b/test/cases/generics.zig
deleted file mode 100644
index 52aa013989e137bfb68890cb010c42da2f413fab..0000000000000000000000000000000000000000
--- a/test/cases/generics.zig
+++ /dev/null
@@ -1,151 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "simple generic fn" {
- assert(max(i32, 3, -1) == 3);
- assert(max(f32, 0.123, 0.456) == 0.456);
- assert(add(2, 3) == 5);
-}
-
-fn max(comptime T: type, a: T, b: T) T {
- return if (a > b) a else b;
-}
-
-fn add(comptime a: i32, b: i32) i32 {
- return (comptime a) + b;
-}
-
-const the_max = max(u32, 1234, 5678);
-test "compile time generic eval" {
- assert(the_max == 5678);
-}
-
-fn gimmeTheBigOne(a: u32, b: u32) u32 {
- return max(u32, a, b);
-}
-
-fn shouldCallSameInstance(a: u32, b: u32) u32 {
- return max(u32, a, b);
-}
-
-fn sameButWithFloats(a: f64, b: f64) f64 {
- return max(f64, a, b);
-}
-
-test "fn with comptime args" {
- assert(gimmeTheBigOne(1234, 5678) == 5678);
- assert(shouldCallSameInstance(34, 12) == 34);
- assert(sameButWithFloats(0.43, 0.49) == 0.49);
-}
-
-test "var params" {
- assert(max_i32(12, 34) == 34);
- assert(max_f64(1.2, 3.4) == 3.4);
-}
-
-comptime {
- assert(max_i32(12, 34) == 34);
- assert(max_f64(1.2, 3.4) == 3.4);
-}
-
-fn max_var(a: var, b: var) @typeOf(a + b) {
- return if (a > b) a else b;
-}
-
-fn max_i32(a: i32, b: i32) i32 {
- return max_var(a, b);
-}
-
-fn max_f64(a: f64, b: f64) f64 {
- return max_var(a, b);
-}
-
-pub fn List(comptime T: type) type {
- return SmallList(T, 8);
-}
-
-pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type {
- return struct {
- items: []T,
- length: usize,
- prealloc_items: [STATIC_SIZE]T,
- };
-}
-
-test "function with return type type" {
- var list: List(i32) = undefined;
- var list2: List(i32) = undefined;
- list.length = 10;
- list2.length = 10;
- assert(list.prealloc_items.len == 8);
- assert(list2.prealloc_items.len == 8);
-}
-
-test "generic struct" {
- var a1 = GenNode(i32){
- .value = 13,
- .next = null,
- };
- var b1 = GenNode(bool){
- .value = true,
- .next = null,
- };
- assert(a1.value == 13);
- assert(a1.value == a1.getVal());
- assert(b1.getVal());
-}
-fn GenNode(comptime T: type) type {
- return struct {
- value: T,
- next: ?*GenNode(T),
- fn getVal(n: *const GenNode(T)) T {
- return n.value;
- }
- };
-}
-
-test "const decls in struct" {
- assert(GenericDataThing(3).count_plus_one == 4);
-}
-fn GenericDataThing(comptime count: isize) type {
- return struct {
- const count_plus_one = count + 1;
- };
-}
-
-test "use generic param in generic param" {
- assert(aGenericFn(i32, 3, 4) == 7);
-}
-fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
- return a + b;
-}
-
-test "generic fn with implicit cast" {
- assert(getFirstByte(u8, []u8{13}) == 13);
- assert(getFirstByte(u16, []u16{
- 0,
- 13,
- }) == 0);
-}
-fn getByte(ptr: ?*const u8) u8 {
- return ptr.?.*;
-}
-fn getFirstByte(comptime T: type, mem: []const T) u8 {
- return getByte(@ptrCast(*const u8, &mem[0]));
-}
-
-const foos = []fn (var) bool{
- foo1,
- foo2,
-};
-
-fn foo1(arg: var) bool {
- return arg;
-}
-fn foo2(arg: var) bool {
- return !arg;
-}
-
-test "array of generic fns" {
- assert(foos[0](true));
- assert(!foos[1](true));
-}
diff --git a/test/cases/if.zig b/test/cases/if.zig
deleted file mode 100644
index 808936bfa5fcf8dc01b1a5b326e3691ab59623a4..0000000000000000000000000000000000000000
--- a/test/cases/if.zig
+++ /dev/null
@@ -1,37 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "if statements" {
- shouldBeEqual(1, 1);
- firstEqlThird(2, 1, 2);
-}
-fn shouldBeEqual(a: i32, b: i32) void {
- if (a != b) {
- unreachable;
- } else {
- return;
- }
-}
-fn firstEqlThird(a: i32, b: i32, c: i32) void {
- if (a == b) {
- unreachable;
- } else if (b == c) {
- unreachable;
- } else if (a == c) {
- return;
- } else {
- unreachable;
- }
-}
-
-test "else if expression" {
- assert(elseIfExpressionF(1) == 1);
-}
-fn elseIfExpressionF(c: u8) u8 {
- if (c == 0) {
- return 0;
- } else if (c == 1) {
- return 1;
- } else {
- return u8(2);
- }
-}
diff --git a/test/cases/import.zig b/test/cases/import.zig
deleted file mode 100644
index 6d6d4b020860be13787cd862624e4bfdb4644bb3..0000000000000000000000000000000000000000
--- a/test/cases/import.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-const assert = @import("std").debug.assert;
-const a_namespace = @import("import/a_namespace.zig");
-
-test "call fn via namespace lookup" {
- assert(a_namespace.foo() == 1234);
-}
-
-test "importing the same thing gives the same import" {
- assert(@import("std") == @import("std"));
-}
diff --git a/test/cases/import/a_namespace.zig b/test/cases/import/a_namespace.zig
deleted file mode 100644
index 042f1867a5dd72fc0216b40f7f56962b7a8a8e9a..0000000000000000000000000000000000000000
--- a/test/cases/import/a_namespace.zig
+++ /dev/null
@@ -1,3 +0,0 @@
-pub fn foo() i32 {
- return 1234;
-}
diff --git a/test/cases/incomplete_struct_param_tld.zig b/test/cases/incomplete_struct_param_tld.zig
deleted file mode 100644
index f1ac03a29279abdfbd4a803642e6b69f908f2760..0000000000000000000000000000000000000000
--- a/test/cases/incomplete_struct_param_tld.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const A = struct {
- b: B,
-};
-
-const B = struct {
- c: C,
-};
-
-const C = struct {
- x: i32,
-
- fn d(c: *const C) i32 {
- return c.x;
- }
-};
-
-fn foo(a: A) i32 {
- return a.b.c.d();
-}
-
-test "incomplete struct param top level declaration" {
- const a = A{
- .b = B{
- .c = C{ .x = 13 },
- },
- };
- assert(foo(a) == 13);
-}
diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig
deleted file mode 100644
index ba3cc52f090501e041f7e1a7bc8f6b339aab50b9..0000000000000000000000000000000000000000
--- a/test/cases/inttoptr.zig
+++ /dev/null
@@ -1,27 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const assertOrPanic = std.debug.assertOrPanic;
-
-test "casting random address to function pointer" {
- randomAddressToFunction();
- comptime randomAddressToFunction();
-}
-
-fn randomAddressToFunction() void {
- var addr: usize = 0xdeadbeef;
- var ptr = @intToPtr(fn () void, addr);
-}
-
-test "mutate through ptr initialized with constant intToPtr value" {
- forceCompilerAnalyzeBranchHardCodedPtrDereference(false);
-}
-
-fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
- const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef);
- if (x) {
- hardCodedP.* = hardCodedP.* | 10;
- } else {
- return;
- }
-}
-
diff --git a/test/cases/ir_block_deps.zig b/test/cases/ir_block_deps.zig
deleted file mode 100644
index 5c1b18c00e45ae146208411eec6dee055fdcc10a..0000000000000000000000000000000000000000
--- a/test/cases/ir_block_deps.zig
+++ /dev/null
@@ -1,21 +0,0 @@
-const assert = @import("std").debug.assert;
-
-fn foo(id: u64) !i32 {
- return switch (id) {
- 1 => getErrInt(),
- 2 => {
- const size = try getErrInt();
- return try getErrInt();
- },
- else => error.ItBroke,
- };
-}
-
-fn getErrInt() anyerror!i32 {
- return 0;
-}
-
-test "ir block deps" {
- assert((foo(1) catch unreachable) == 0);
- assert((foo(2) catch unreachable) == 0);
-}
diff --git a/test/cases/math.zig b/test/cases/math.zig
deleted file mode 100644
index 7d6b1bd9acbcb454cbfa0d04e14755920da567ee..0000000000000000000000000000000000000000
--- a/test/cases/math.zig
+++ /dev/null
@@ -1,500 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-const minInt = std.math.minInt;
-
-test "division" {
- testDivision();
- comptime testDivision();
-}
-fn testDivision() void {
- assert(div(u32, 13, 3) == 4);
- assert(div(f16, 1.0, 2.0) == 0.5);
- assert(div(f32, 1.0, 2.0) == 0.5);
-
- assert(divExact(u32, 55, 11) == 5);
- assert(divExact(i32, -55, 11) == -5);
- assert(divExact(f16, 55.0, 11.0) == 5.0);
- assert(divExact(f16, -55.0, 11.0) == -5.0);
- assert(divExact(f32, 55.0, 11.0) == 5.0);
- assert(divExact(f32, -55.0, 11.0) == -5.0);
-
- assert(divFloor(i32, 5, 3) == 1);
- assert(divFloor(i32, -5, 3) == -2);
- assert(divFloor(f16, 5.0, 3.0) == 1.0);
- assert(divFloor(f16, -5.0, 3.0) == -2.0);
- assert(divFloor(f32, 5.0, 3.0) == 1.0);
- assert(divFloor(f32, -5.0, 3.0) == -2.0);
- assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
- assert(divFloor(i32, 0, -0x80000000) == 0);
- assert(divFloor(i32, -0x40000001, 0x40000000) == -2);
- assert(divFloor(i32, -0x80000000, 1) == -0x80000000);
-
- assert(divTrunc(i32, 5, 3) == 1);
- assert(divTrunc(i32, -5, 3) == -1);
- assert(divTrunc(f16, 5.0, 3.0) == 1.0);
- assert(divTrunc(f16, -5.0, 3.0) == -1.0);
- assert(divTrunc(f32, 5.0, 3.0) == 1.0);
- assert(divTrunc(f32, -5.0, 3.0) == -1.0);
- assert(divTrunc(f64, 5.0, 3.0) == 1.0);
- assert(divTrunc(f64, -5.0, 3.0) == -1.0);
-
- comptime {
- assert(
- 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600,
- );
- assert(
- @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600,
- );
- assert(
- 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2,
- );
- assert(
- @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2,
- );
- assert(
- @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2,
- );
- assert(
- @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2,
- );
- assert(
- 4126227191251978491697987544882340798050766755606969681711 % 10 == 1,
- );
- }
-}
-fn div(comptime T: type, a: T, b: T) T {
- return a / b;
-}
-fn divExact(comptime T: type, a: T, b: T) T {
- return @divExact(a, b);
-}
-fn divFloor(comptime T: type, a: T, b: T) T {
- return @divFloor(a, b);
-}
-fn divTrunc(comptime T: type, a: T, b: T) T {
- return @divTrunc(a, b);
-}
-
-test "@addWithOverflow" {
- var result: u8 = undefined;
- assert(@addWithOverflow(u8, 250, 100, &result));
- assert(!@addWithOverflow(u8, 100, 150, &result));
- assert(result == 250);
-}
-
-// TODO test mulWithOverflow
-// TODO test subWithOverflow
-
-test "@shlWithOverflow" {
- var result: u16 = undefined;
- assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
- assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
- assert(result == 0b1011111111111100);
-}
-
-test "@clz" {
- testClz();
- comptime testClz();
-}
-
-fn testClz() void {
- assert(clz(u8(0b00001010)) == 4);
- assert(clz(u8(0b10001010)) == 0);
- assert(clz(u8(0b00000000)) == 8);
- assert(clz(u128(0xffffffffffffffff)) == 64);
- assert(clz(u128(0x10000000000000000)) == 63);
-}
-
-fn clz(x: var) usize {
- return @clz(x);
-}
-
-test "@ctz" {
- testCtz();
- comptime testCtz();
-}
-
-fn testCtz() void {
- assert(ctz(u8(0b10100000)) == 5);
- assert(ctz(u8(0b10001010)) == 1);
- assert(ctz(u8(0b00000000)) == 8);
-}
-
-fn ctz(x: var) usize {
- return @ctz(x);
-}
-
-test "assignment operators" {
- var i: u32 = 0;
- i += 5;
- assert(i == 5);
- i -= 2;
- assert(i == 3);
- i *= 20;
- assert(i == 60);
- i /= 3;
- assert(i == 20);
- i %= 11;
- assert(i == 9);
- i <<= 1;
- assert(i == 18);
- i >>= 2;
- assert(i == 4);
- i = 6;
- i &= 5;
- assert(i == 4);
- i ^= 6;
- assert(i == 2);
- i = 6;
- i |= 3;
- assert(i == 7);
-}
-
-test "three expr in a row" {
- testThreeExprInARow(false, true);
- comptime testThreeExprInARow(false, true);
-}
-fn testThreeExprInARow(f: bool, t: bool) void {
- assertFalse(f or f or f);
- assertFalse(t and t and f);
- assertFalse(1 | 2 | 4 != 7);
- assertFalse(3 ^ 6 ^ 8 != 13);
- assertFalse(7 & 14 & 28 != 4);
- assertFalse(9 << 1 << 2 != 9 << 3);
- assertFalse(90 >> 1 >> 2 != 90 >> 3);
- assertFalse(100 - 1 + 1000 != 1099);
- assertFalse(5 * 4 / 2 % 3 != 1);
- assertFalse(i32(i32(5)) != 5);
- assertFalse(!!false);
- assertFalse(i32(7) != --(i32(7)));
-}
-fn assertFalse(b: bool) void {
- assert(!b);
-}
-
-test "const number literal" {
- const one = 1;
- const eleven = ten + one;
-
- assert(eleven == 11);
-}
-const ten = 10;
-
-test "unsigned wrapping" {
- testUnsignedWrappingEval(maxInt(u32));
- comptime testUnsignedWrappingEval(maxInt(u32));
-}
-fn testUnsignedWrappingEval(x: u32) void {
- const zero = x +% 1;
- assert(zero == 0);
- const orig = zero -% 1;
- assert(orig == maxInt(u32));
-}
-
-test "signed wrapping" {
- testSignedWrappingEval(maxInt(i32));
- comptime testSignedWrappingEval(maxInt(i32));
-}
-fn testSignedWrappingEval(x: i32) void {
- const min_val = x +% 1;
- assert(min_val == minInt(i32));
- const max_val = min_val -% 1;
- assert(max_val == maxInt(i32));
-}
-
-test "negation wrapping" {
- testNegationWrappingEval(minInt(i16));
- comptime testNegationWrappingEval(minInt(i16));
-}
-fn testNegationWrappingEval(x: i16) void {
- assert(x == -32768);
- const neg = -%x;
- assert(neg == -32768);
-}
-
-test "unsigned 64-bit division" {
- test_u64_div();
- comptime test_u64_div();
-}
-fn test_u64_div() void {
- const result = divWithResult(1152921504606846976, 34359738365);
- assert(result.quotient == 33554432);
- assert(result.remainder == 100663296);
-}
-fn divWithResult(a: u64, b: u64) DivResult {
- return DivResult{
- .quotient = a / b,
- .remainder = a % b,
- };
-}
-const DivResult = struct {
- quotient: u64,
- remainder: u64,
-};
-
-test "binary not" {
- assert(comptime x: {
- break :x ~u16(0b1010101010101010) == 0b0101010101010101;
- });
- assert(comptime x: {
- break :x ~u64(2147483647) == 18446744071562067968;
- });
- testBinaryNot(0b1010101010101010);
-}
-
-fn testBinaryNot(x: u16) void {
- assert(~x == 0b0101010101010101);
-}
-
-test "small int addition" {
- var x: @IntType(false, 2) = 0;
- assert(x == 0);
-
- x += 1;
- assert(x == 1);
-
- x += 1;
- assert(x == 2);
-
- x += 1;
- assert(x == 3);
-
- var result: @typeOf(x) = 3;
- assert(@addWithOverflow(@typeOf(x), x, 1, &result));
-
- assert(result == 0);
-}
-
-test "float equality" {
- const x: f64 = 0.012;
- const y: f64 = x + 1.0;
-
- testFloatEqualityImpl(x, y);
- comptime testFloatEqualityImpl(x, y);
-}
-
-fn testFloatEqualityImpl(x: f64, y: f64) void {
- const y2 = x + 1.0;
- assert(y == y2);
-}
-
-test "allow signed integer division/remainder when values are comptime known and positive or exact" {
- assert(5 / 3 == 1);
- assert(-5 / -3 == 1);
- assert(-6 / 3 == -2);
-
- assert(5 % 3 == 2);
- assert(-6 % 3 == 0);
-}
-
-test "hex float literal parsing" {
- comptime assert(0x1.0 == 1.0);
-}
-
-test "quad hex float literal parsing in range" {
- const a = 0x1.af23456789bbaaab347645365cdep+5;
- const b = 0x1.dedafcff354b6ae9758763545432p-9;
- const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
- const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
-}
-
-test "quad hex float literal parsing accurate" {
- const a: f128 = 0x1.1111222233334444555566667777p+0;
-
- // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
- const expected: u128 = 0x3fff1111222233334444555566667777;
- assert(@bitCast(u128, a) == expected);
-}
-
-test "hex float literal within range" {
- const a = 0x1.0p16383;
- const b = 0x0.1p16387;
- const c = 0x1.0p-16382;
-}
-
-test "truncating shift left" {
- testShlTrunc(maxInt(u16));
- comptime testShlTrunc(maxInt(u16));
-}
-fn testShlTrunc(x: u16) void {
- const shifted = x << 1;
- assert(shifted == 65534);
-}
-
-test "truncating shift right" {
- testShrTrunc(maxInt(u16));
- comptime testShrTrunc(maxInt(u16));
-}
-fn testShrTrunc(x: u16) void {
- const shifted = x >> 1;
- assert(shifted == 32767);
-}
-
-test "exact shift left" {
- testShlExact(0b00110101);
- comptime testShlExact(0b00110101);
-}
-fn testShlExact(x: u8) void {
- const shifted = @shlExact(x, 2);
- assert(shifted == 0b11010100);
-}
-
-test "exact shift right" {
- testShrExact(0b10110100);
- comptime testShrExact(0b10110100);
-}
-fn testShrExact(x: u8) void {
- const shifted = @shrExact(x, 2);
- assert(shifted == 0b00101101);
-}
-
-test "comptime_int addition" {
- comptime {
- assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
- assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
- }
-}
-
-test "comptime_int multiplication" {
- comptime {
- assert(
- 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
- );
- assert(
- 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
- );
- }
-}
-
-test "comptime_int shifting" {
- comptime {
- assert((u128(1) << 127) == 0x80000000000000000000000000000000);
- }
-}
-
-test "comptime_int multi-limb shift and mask" {
- comptime {
- var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
-
- assert(u32(a & 0xffffffff) == 0xaaaaaaab);
- a >>= 32;
- assert(u32(a & 0xffffffff) == 0xeeeeeeef);
- a >>= 32;
- assert(u32(a & 0xffffffff) == 0xa0000001);
- a >>= 32;
- assert(u32(a & 0xffffffff) == 0xefffffff);
- a >>= 32;
-
- assert(a == 0);
- }
-}
-
-test "comptime_int multi-limb partial shift right" {
- comptime {
- var a = 0x1ffffffffeeeeeeee;
- a >>= 16;
- assert(a == 0x1ffffffffeeee);
- }
-}
-
-test "xor" {
- test_xor();
- comptime test_xor();
-}
-
-fn test_xor() void {
- assert(0xFF ^ 0x00 == 0xFF);
- assert(0xF0 ^ 0x0F == 0xFF);
- assert(0xFF ^ 0xF0 == 0x0F);
- assert(0xFF ^ 0x0F == 0xF0);
- assert(0xFF ^ 0xFF == 0x00);
-}
-
-test "comptime_int xor" {
- comptime {
- assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
- assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
- assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
- assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
- assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
- }
-}
-
-test "f128" {
- test_f128();
- comptime test_f128();
-}
-
-fn make_f128(x: f128) f128 {
- return x;
-}
-
-fn test_f128() void {
- assert(@sizeOf(f128) == 16);
- assert(make_f128(1.0) == 1.0);
- assert(make_f128(1.0) != 1.1);
- assert(make_f128(1.0) > 0.9);
- assert(make_f128(1.0) >= 0.9);
- assert(make_f128(1.0) >= 1.0);
- should_not_be_zero(1.0);
-}
-
-fn should_not_be_zero(x: f128) void {
- assert(x != 0.0);
-}
-
-test "comptime float rem int" {
- comptime {
- var x = f32(1) % 2;
- assert(x == 1.0);
- }
-}
-
-test "remainder division" {
- comptime remdiv(f16);
- comptime remdiv(f32);
- comptime remdiv(f64);
- comptime remdiv(f128);
- remdiv(f16);
- remdiv(f64);
- remdiv(f128);
-}
-
-fn remdiv(comptime T: type) void {
- assert(T(1) == T(1) % T(2));
- assert(T(1) == T(7) % T(3));
-}
-
-test "@sqrt" {
- testSqrt(f64, 12.0);
- comptime testSqrt(f64, 12.0);
- testSqrt(f32, 13.0);
- comptime testSqrt(f32, 13.0);
- testSqrt(f16, 13.0);
- comptime testSqrt(f16, 13.0);
-
- const x = 14.0;
- const y = x * x;
- const z = @sqrt(@typeOf(y), y);
- comptime assert(z == x);
-}
-
-fn testSqrt(comptime T: type, x: T) void {
- assert(@sqrt(T, x * x) == x);
-}
-
-test "comptime_int param and return" {
- const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
- assert(a == 137114567242441932203689521744947848950);
-
- const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
- assert(b == 985095453608931032642182098849559179469148836107390954364380);
-}
-
-fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
- return a + b;
-}
diff --git a/test/cases/merge_error_sets.zig b/test/cases/merge_error_sets.zig
deleted file mode 100644
index 147b580232d10deaf9bc78715696c851aa92ae30..0000000000000000000000000000000000000000
--- a/test/cases/merge_error_sets.zig
+++ /dev/null
@@ -1,21 +0,0 @@
-const A = error{
- FileNotFound,
- NotDir,
-};
-const B = error{OutOfMemory};
-
-const C = A || B;
-
-fn foo() C!void {
- return error.NotDir;
-}
-
-test "merge error sets" {
- if (foo()) {
- @panic("unexpected");
- } else |err| switch (err) {
- error.OutOfMemory => @panic("unexpected"),
- error.FileNotFound => @panic("unexpected"),
- error.NotDir => {},
- }
-}
diff --git a/test/cases/misc.zig b/test/cases/misc.zig
deleted file mode 100644
index 1a34d54e9e15f974b645a4cbfdc6d0d61a63bd0b..0000000000000000000000000000000000000000
--- a/test/cases/misc.zig
+++ /dev/null
@@ -1,681 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const mem = std.mem;
-const cstr = std.cstr;
-const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-
-// normal comment
-
-/// this is a documentation comment
-/// doc comment line 2
-fn emptyFunctionWithComments() void {}
-
-test "empty function with comments" {
- emptyFunctionWithComments();
-}
-
-comptime {
- @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
-}
-
-extern fn disabledExternFn() void {}
-
-test "call disabled extern fn" {
- disabledExternFn();
-}
-
-test "@IntType builtin" {
- assert(@IntType(true, 8) == i8);
- assert(@IntType(true, 16) == i16);
- assert(@IntType(true, 32) == i32);
- assert(@IntType(true, 64) == i64);
-
- assert(@IntType(false, 8) == u8);
- assert(@IntType(false, 16) == u16);
- assert(@IntType(false, 32) == u32);
- assert(@IntType(false, 64) == u64);
-
- assert(i8.bit_count == 8);
- assert(i16.bit_count == 16);
- assert(i32.bit_count == 32);
- assert(i64.bit_count == 64);
-
- assert(i8.is_signed);
- assert(i16.is_signed);
- assert(i32.is_signed);
- assert(i64.is_signed);
- assert(isize.is_signed);
-
- assert(!u8.is_signed);
- assert(!u16.is_signed);
- assert(!u32.is_signed);
- assert(!u64.is_signed);
- assert(!usize.is_signed);
-}
-
-test "floating point primitive bit counts" {
- assert(f16.bit_count == 16);
- assert(f32.bit_count == 32);
- assert(f64.bit_count == 64);
-}
-
-test "short circuit" {
- testShortCircuit(false, true);
- comptime testShortCircuit(false, true);
-}
-
-fn testShortCircuit(f: bool, t: bool) void {
- var hit_1 = f;
- var hit_2 = f;
- var hit_3 = f;
- var hit_4 = f;
-
- if (t or x: {
- assert(f);
- break :x f;
- }) {
- hit_1 = t;
- }
- if (f or x: {
- hit_2 = t;
- break :x f;
- }) {
- assert(f);
- }
-
- if (t and x: {
- hit_3 = t;
- break :x f;
- }) {
- assert(f);
- }
- if (f and x: {
- assert(f);
- break :x f;
- }) {
- assert(f);
- } else {
- hit_4 = t;
- }
- assert(hit_1);
- assert(hit_2);
- assert(hit_3);
- assert(hit_4);
-}
-
-test "truncate" {
- assert(testTruncate(0x10fd) == 0xfd);
-}
-fn testTruncate(x: u32) u8 {
- return @truncate(u8, x);
-}
-
-fn first4KeysOfHomeRow() []const u8 {
- return "aoeu";
-}
-
-test "return string from function" {
- assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
-}
-
-const g1: i32 = 1233 + 1;
-var g2: i32 = 0;
-
-test "global variables" {
- assert(g2 == 0);
- g2 = g1;
- assert(g2 == 1234);
-}
-
-test "memcpy and memset intrinsics" {
- var foo: [20]u8 = undefined;
- var bar: [20]u8 = undefined;
-
- @memset(foo[0..].ptr, 'A', foo.len);
- @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);
-
- if (bar[11] != 'A') unreachable;
-}
-
-test "builtin static eval" {
- const x: i32 = comptime x: {
- break :x 1 + 2 + 3;
- };
- assert(x == comptime 6);
-}
-
-test "slicing" {
- var array: [20]i32 = undefined;
-
- array[5] = 1234;
-
- var slice = array[5..10];
-
- if (slice.len != 5) unreachable;
-
- const ptr = &slice[0];
- if (ptr.* != 1234) unreachable;
-
- var slice_rest = array[10..];
- if (slice_rest.len != 10) unreachable;
-}
-
-test "constant equal function pointers" {
- const alias = emptyFn;
- assert(comptime x: {
- break :x emptyFn == alias;
- });
-}
-
-fn emptyFn() void {}
-
-test "hex escape" {
- assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
-}
-
-test "string concatenation" {
- assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
-}
-
-test "array mult operator" {
- assert(mem.eql(u8, "ab" ** 5, "ababababab"));
-}
-
-test "string escapes" {
- assert(mem.eql(u8, "\"", "\x22"));
- assert(mem.eql(u8, "\'", "\x27"));
- assert(mem.eql(u8, "\n", "\x0a"));
- assert(mem.eql(u8, "\r", "\x0d"));
- assert(mem.eql(u8, "\t", "\x09"));
- assert(mem.eql(u8, "\\", "\x5c"));
- assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
-}
-
-test "multiline string" {
- const s1 =
- \\one
- \\two)
- \\three
- ;
- const s2 = "one\ntwo)\nthree";
- assert(mem.eql(u8, s1, s2));
-}
-
-test "multiline C string" {
- const s1 =
- c\\one
- c\\two)
- c\\three
- ;
- const s2 = c"one\ntwo)\nthree";
- assert(cstr.cmp(s1, s2) == 0);
-}
-
-test "type equality" {
- assert(*const u8 != *u8);
-}
-
-const global_a: i32 = 1234;
-const global_b: *const i32 = &global_a;
-const global_c: *const f32 = @ptrCast(*const f32, global_b);
-test "compile time global reinterpret" {
- const d = @ptrCast(*const i32, global_c);
- assert(d.* == 1234);
-}
-
-test "explicit cast maybe pointers" {
- const a: ?*i32 = undefined;
- const b: ?*f32 = @ptrCast(?*f32, a);
-}
-
-test "generic malloc free" {
- const a = memAlloc(u8, 10) catch unreachable;
- memFree(u8, a);
-}
-var some_mem: [100]u8 = undefined;
-fn memAlloc(comptime T: type, n: usize) anyerror![]T {
- return @ptrCast([*]T, &some_mem[0])[0..n];
-}
-fn memFree(comptime T: type, memory: []T) void {}
-
-test "cast undefined" {
- const array: [100]u8 = undefined;
- const slice = ([]const u8)(array);
- testCastUndefined(slice);
-}
-fn testCastUndefined(x: []const u8) void {}
-
-test "cast small unsigned to larger signed" {
- assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
- assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
-}
-fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
- return x;
-}
-fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
- return x;
-}
-
-test "implicit cast after unreachable" {
- assert(outer() == 1234);
-}
-fn inner() i32 {
- return 1234;
-}
-fn outer() i64 {
- return inner();
-}
-
-test "pointer dereferencing" {
- var x = i32(3);
- const y = &x;
-
- y.* += 1;
-
- assert(x == 4);
- assert(y.* == 4);
-}
-
-test "call result of if else expression" {
- assert(mem.eql(u8, f2(true), "a"));
- assert(mem.eql(u8, f2(false), "b"));
-}
-fn f2(x: bool) []const u8 {
- return (if (x) fA else fB)();
-}
-fn fA() []const u8 {
- return "a";
-}
-fn fB() []const u8 {
- return "b";
-}
-
-test "const expression eval handling of variables" {
- var x = true;
- while (x) {
- x = false;
- }
-}
-
-test "constant enum initialization with differing sizes" {
- test3_1(test3_foo);
- test3_2(test3_bar);
-}
-const Test3Foo = union(enum) {
- One: void,
- Two: f32,
- Three: Test3Point,
-};
-const Test3Point = struct {
- x: i32,
- y: i32,
-};
-const test3_foo = Test3Foo{
- .Three = Test3Point{
- .x = 3,
- .y = 4,
- },
-};
-const test3_bar = Test3Foo{ .Two = 13 };
-fn test3_1(f: Test3Foo) void {
- switch (f) {
- Test3Foo.Three => |pt| {
- assert(pt.x == 3);
- assert(pt.y == 4);
- },
- else => unreachable,
- }
-}
-fn test3_2(f: Test3Foo) void {
- switch (f) {
- Test3Foo.Two => |x| {
- assert(x == 13);
- },
- else => unreachable,
- }
-}
-
-test "character literals" {
- assert('\'' == single_quote);
-}
-const single_quote = '\'';
-
-test "take address of parameter" {
- testTakeAddressOfParameter(12.34);
-}
-fn testTakeAddressOfParameter(f: f32) void {
- const f_ptr = &f;
- assert(f_ptr.* == 12.34);
-}
-
-test "pointer comparison" {
- const a = ([]const u8)("a");
- const b = &a;
- assert(ptrEql(b, b));
-}
-fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
- return a == b;
-}
-
-test "C string concatenation" {
- const a = c"OK" ++ c" IT " ++ c"WORKED";
- const b = c"OK IT WORKED";
-
- const len = cstr.len(b);
- const len_with_null = len + 1;
- {
- var i: u32 = 0;
- while (i < len_with_null) : (i += 1) {
- assert(a[i] == b[i]);
- }
- }
- assert(a[len] == 0);
- assert(b[len] == 0);
-}
-
-test "cast slice to u8 slice" {
- assert(@sizeOf(i32) == 4);
- var big_thing_array = []i32{
- 1,
- 2,
- 3,
- 4,
- };
- const big_thing_slice: []i32 = big_thing_array[0..];
- const bytes = @sliceToBytes(big_thing_slice);
- assert(bytes.len == 4 * 4);
- bytes[4] = 0;
- bytes[5] = 0;
- bytes[6] = 0;
- bytes[7] = 0;
- assert(big_thing_slice[1] == 0);
- const big_thing_again = @bytesToSlice(i32, bytes);
- assert(big_thing_again[2] == 3);
- big_thing_again[2] = -1;
- assert(bytes[8] == maxInt(u8));
- assert(bytes[9] == maxInt(u8));
- assert(bytes[10] == maxInt(u8));
- assert(bytes[11] == maxInt(u8));
-}
-
-test "pointer to void return type" {
- testPointerToVoidReturnType() catch unreachable;
-}
-fn testPointerToVoidReturnType() anyerror!void {
- const a = testPointerToVoidReturnType2();
- return a.*;
-}
-const test_pointer_to_void_return_type_x = void{};
-fn testPointerToVoidReturnType2() *const void {
- return &test_pointer_to_void_return_type_x;
-}
-
-test "non const ptr to aliased type" {
- const int = i32;
- assert(?*int == ?*i32);
-}
-
-test "array 2D const double ptr" {
- const rect_2d_vertexes = [][1]f32{
- []f32{1.0},
- []f32{2.0},
- };
- testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
-}
-
-fn testArray2DConstDoublePtr(ptr: *const f32) void {
- const ptr2 = @ptrCast([*]const f32, ptr);
- assert(ptr2[0] == 1.0);
- assert(ptr2[1] == 2.0);
-}
-
-const Tid = builtin.TypeId;
-const AStruct = struct {
- x: i32,
-};
-const AnEnum = enum {
- One,
- Two,
-};
-const AUnionEnum = union(enum) {
- One: i32,
- Two: void,
-};
-const AUnion = union {
- One: void,
- Two: void,
-};
-
-test "@typeId" {
- comptime {
- assert(@typeId(type) == Tid.Type);
- assert(@typeId(void) == Tid.Void);
- assert(@typeId(bool) == Tid.Bool);
- assert(@typeId(noreturn) == Tid.NoReturn);
- assert(@typeId(i8) == Tid.Int);
- assert(@typeId(u8) == Tid.Int);
- assert(@typeId(i64) == Tid.Int);
- assert(@typeId(u64) == Tid.Int);
- assert(@typeId(f32) == Tid.Float);
- assert(@typeId(f64) == Tid.Float);
- assert(@typeId(*f32) == Tid.Pointer);
- assert(@typeId([2]u8) == Tid.Array);
- assert(@typeId(AStruct) == Tid.Struct);
- assert(@typeId(@typeOf(1)) == Tid.ComptimeInt);
- assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
- assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
- assert(@typeId(@typeOf(null)) == Tid.Null);
- assert(@typeId(?i32) == Tid.Optional);
- assert(@typeId(anyerror!i32) == Tid.ErrorUnion);
- assert(@typeId(anyerror) == Tid.ErrorSet);
- assert(@typeId(AnEnum) == Tid.Enum);
- assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
- assert(@typeId(AUnionEnum) == Tid.Union);
- assert(@typeId(AUnion) == Tid.Union);
- assert(@typeId(fn () void) == Tid.Fn);
- assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
- // TODO bound fn
- // TODO arg tuple
- // TODO opaque
- }
-}
-
-test "@typeName" {
- const Struct = struct {};
- const Union = union {
- unused: u8,
- };
- const Enum = enum {
- Unused,
- };
- comptime {
- assert(mem.eql(u8, @typeName(i64), "i64"));
- assert(mem.eql(u8, @typeName(*usize), "*usize"));
- // https://github.com/ziglang/zig/issues/675
- assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
- assert(mem.eql(u8, @typeName(Struct), "Struct"));
- assert(mem.eql(u8, @typeName(Union), "Union"));
- assert(mem.eql(u8, @typeName(Enum), "Enum"));
- }
-}
-
-fn TypeFromFn(comptime T: type) type {
- return struct {};
-}
-
-test "volatile load and store" {
- var number: i32 = 1234;
- const ptr = (*volatile i32)(&number);
- ptr.* += 1;
- assert(ptr.* == 1235);
-}
-
-test "slice string literal has type []const u8" {
- comptime {
- assert(@typeOf("aoeu"[0..]) == []const u8);
- const array = []i32{
- 1,
- 2,
- 3,
- 4,
- };
- assert(@typeOf(array[0..]) == []const i32);
- }
-}
-
-test "global variable initialized to global variable array element" {
- assert(global_ptr == &gdt[0]);
-}
-const GDTEntry = struct {
- field: i32,
-};
-var gdt = []GDTEntry{
- GDTEntry{ .field = 1 },
- GDTEntry{ .field = 2 },
-};
-var global_ptr = &gdt[0];
-
-// can't really run this test but we can make sure it has no compile error
-// and generates code
-const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000];
-export fn writeToVRam() void {
- vram[0] = 'X';
-}
-
-test "pointer child field" {
- assert((*u32).Child == u32);
-}
-
-const OpaqueA = @OpaqueType();
-const OpaqueB = @OpaqueType();
-test "@OpaqueType" {
- assert(*OpaqueA != *OpaqueB);
- assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
- assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
-}
-
-test "variable is allowed to be a pointer to an opaque type" {
- var x: i32 = 1234;
- _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
-}
-fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
- var a = ptr;
- return a;
-}
-
-test "comptime if inside runtime while which unconditionally breaks" {
- testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
- comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
-}
-fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
- while (cond) {
- if (false) {}
- break;
- }
-}
-
-test "implicit comptime while" {
- while (false) {
- @compileError("bad");
- }
-}
-
-test "struct inside function" {
- testStructInFn();
- comptime testStructInFn();
-}
-
-fn testStructInFn() void {
- const BlockKind = u32;
-
- const Block = struct {
- kind: BlockKind,
- };
-
- var block = Block{ .kind = 1234 };
-
- block.kind += 1;
-
- assert(block.kind == 1235);
-}
-
-fn fnThatClosesOverLocalConst() type {
- const c = 1;
- return struct {
- fn g() i32 {
- return c;
- }
- };
-}
-
-test "function closes over local const" {
- const x = fnThatClosesOverLocalConst().g();
- assert(x == 1);
-}
-
-test "cold function" {
- thisIsAColdFn();
- comptime thisIsAColdFn();
-}
-
-fn thisIsAColdFn() void {
- @setCold(true);
-}
-
-const PackedStruct = packed struct {
- a: u8,
- b: u8,
-};
-const PackedUnion = packed union {
- a: u8,
- b: u32,
-};
-const PackedEnum = packed enum {
- A,
- B,
-};
-
-test "packed struct, enum, union parameters in extern function" {
- testPackedStuff(&(PackedStruct{
- .a = 1,
- .b = 2,
- }), &(PackedUnion{ .a = 1 }), PackedEnum.A);
-}
-
-export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {}
-
-test "slicing zero length array" {
- const s1 = ""[0..];
- const s2 = ([]u32{})[0..];
- assert(s1.len == 0);
- assert(s2.len == 0);
- assert(mem.eql(u8, s1, ""));
- assert(mem.eql(u32, s2, []u32{}));
-}
-
-const addr1 = @ptrCast(*const u8, emptyFn);
-test "comptime cast fn to ptr" {
- const addr2 = @ptrCast(*const u8, emptyFn);
- comptime assert(addr1 == addr2);
-}
-
-test "equality compare fn ptrs" {
- var a = emptyFn;
- assert(a == a);
-}
-
-test "self reference through fn ptr field" {
- const S = struct {
- const A = struct {
- f: fn (A) u8,
- };
-
- fn foo(a: A) u8 {
- return 12;
- }
- };
- var a: S.A = undefined;
- a.f = S.foo;
- assert(a.f(a) == 12);
-}
diff --git a/test/cases/namespace_depends_on_compile_var/a.zig b/test/cases/namespace_depends_on_compile_var/a.zig
deleted file mode 100644
index 5ce0e94f8bcf7a4c4c00d79fd1e526294ce68d28..0000000000000000000000000000000000000000
--- a/test/cases/namespace_depends_on_compile_var/a.zig
+++ /dev/null
@@ -1 +0,0 @@
-pub const a_bool = true;
diff --git a/test/cases/namespace_depends_on_compile_var/b.zig b/test/cases/namespace_depends_on_compile_var/b.zig
deleted file mode 100644
index a12a54b5891baef53855a2c43f3ffef7b17a9d4d..0000000000000000000000000000000000000000
--- a/test/cases/namespace_depends_on_compile_var/b.zig
+++ /dev/null
@@ -1 +0,0 @@
-pub const a_bool = false;
diff --git a/test/cases/namespace_depends_on_compile_var/index.zig b/test/cases/namespace_depends_on_compile_var/index.zig
deleted file mode 100644
index ccc49d9367d83ba4c2e491e5539d7bcd31228cc6..0000000000000000000000000000000000000000
--- a/test/cases/namespace_depends_on_compile_var/index.zig
+++ /dev/null
@@ -1,14 +0,0 @@
-const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
-
-test "namespace depends on compile var" {
- if (some_namespace.a_bool) {
- assert(some_namespace.a_bool);
- } else {
- assert(!some_namespace.a_bool);
- }
-}
-const some_namespace = switch (builtin.os) {
- builtin.Os.linux => @import("a.zig"),
- else => @import("b.zig"),
-};
diff --git a/test/cases/new_stack_call.zig b/test/cases/new_stack_call.zig
deleted file mode 100644
index 5912550d545aa6b8369afcabf8995574d8541616..0000000000000000000000000000000000000000
--- a/test/cases/new_stack_call.zig
+++ /dev/null
@@ -1,26 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-var new_stack_bytes: [1024]u8 = undefined;
-
-test "calling a function with a new stack" {
- const arg = 1234;
-
- const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
- const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
- _ = targetFunction(arg);
-
- assert(arg == 1234);
- assert(a < b);
-}
-
-fn targetFunction(x: i32) usize {
- assert(x == 1234);
-
- var local_variable: i32 = 42;
- const ptr = &local_variable;
- ptr.* += 1;
-
- assert(local_variable == 43);
- return @ptrToInt(ptr);
-}
diff --git a/test/cases/null.zig b/test/cases/null.zig
deleted file mode 100644
index 825db88b1e58cc1a2f7b9ee26b634d1e0da6798b..0000000000000000000000000000000000000000
--- a/test/cases/null.zig
+++ /dev/null
@@ -1,162 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "optional type" {
- const x: ?bool = true;
-
- if (x) |y| {
- if (y) {
- // OK
- } else {
- unreachable;
- }
- } else {
- unreachable;
- }
-
- const next_x: ?i32 = null;
-
- const z = next_x orelse 1234;
-
- assert(z == 1234);
-
- const final_x: ?i32 = 13;
-
- const num = final_x orelse unreachable;
-
- assert(num == 13);
-}
-
-test "test maybe object and get a pointer to the inner value" {
- var maybe_bool: ?bool = true;
-
- if (maybe_bool) |*b| {
- b.* = false;
- }
-
- assert(maybe_bool.? == false);
-}
-
-test "rhs maybe unwrap return" {
- const x: ?bool = true;
- const y = x orelse return;
-}
-
-test "maybe return" {
- maybeReturnImpl();
- comptime maybeReturnImpl();
-}
-
-fn maybeReturnImpl() void {
- assert(foo(1235).?);
- if (foo(null) != null) unreachable;
- assert(!foo(1234).?);
-}
-
-fn foo(x: ?i32) ?bool {
- const value = x orelse return null;
- return value > 1234;
-}
-
-test "if var maybe pointer" {
- assert(shouldBeAPlus1(Particle{
- .a = 14,
- .b = 1,
- .c = 1,
- .d = 1,
- }) == 15);
-}
-fn shouldBeAPlus1(p: Particle) u64 {
- var maybe_particle: ?Particle = p;
- if (maybe_particle) |*particle| {
- particle.a += 1;
- }
- if (maybe_particle) |particle| {
- return particle.a;
- }
- return 0;
-}
-const Particle = struct {
- a: u64,
- b: u64,
- c: u64,
- d: u64,
-};
-
-test "null literal outside function" {
- const is_null = here_is_a_null_literal.context == null;
- assert(is_null);
-
- const is_non_null = here_is_a_null_literal.context != null;
- assert(!is_non_null);
-}
-const SillyStruct = struct {
- context: ?i32,
-};
-const here_is_a_null_literal = SillyStruct{ .context = null };
-
-test "test null runtime" {
- testTestNullRuntime(null);
-}
-fn testTestNullRuntime(x: ?i32) void {
- assert(x == null);
- assert(!(x != null));
-}
-
-test "optional void" {
- optionalVoidImpl();
- comptime optionalVoidImpl();
-}
-
-fn optionalVoidImpl() void {
- assert(bar(null) == null);
- assert(bar({}) != null);
-}
-
-fn bar(x: ?void) ?void {
- if (x) |_| {
- return {};
- } else {
- return null;
- }
-}
-
-const StructWithOptional = struct {
- field: ?i32,
-};
-
-var struct_with_optional: StructWithOptional = undefined;
-
-test "unwrap optional which is field of global var" {
- struct_with_optional.field = null;
- if (struct_with_optional.field) |payload| {
- unreachable;
- }
- struct_with_optional.field = 1234;
- if (struct_with_optional.field) |payload| {
- assert(payload == 1234);
- } else {
- unreachable;
- }
-}
-
-test "null with default unwrap" {
- const x: i32 = null orelse 1;
- assert(x == 1);
-}
-
-test "optional types" {
- comptime {
- const opt_type_struct = StructWithOptionalType{ .t = u8 };
- assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
- }
-}
-
-const StructWithOptionalType = struct {
- t: ?type,
-};
-
-test "optional pointer to 0 bit type null value at runtime" {
- const EmptyStruct = struct {};
- var x: ?*EmptyStruct = null;
- assert(x == null);
-}
diff --git a/test/cases/optional.zig b/test/cases/optional.zig
deleted file mode 100644
index d43682bbec3c676163007eb7b49677c3cc8a2a44..0000000000000000000000000000000000000000
--- a/test/cases/optional.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-pub const EmptyStruct = struct {};
-
-test "optional pointer to size zero struct" {
- var e = EmptyStruct{};
- var o: ?*EmptyStruct = &e;
- assert(o != null);
-}
-
-test "equality compare nullable pointers" {
- testNullPtrsEql();
- comptime testNullPtrsEql();
-}
-
-fn testNullPtrsEql() void {
- var number: i32 = 1234;
-
- var x: ?*i32 = null;
- var y: ?*i32 = null;
- assert(x == y);
- y = &number;
- assert(x != y);
- assert(x != &number);
- assert(&number != x);
- x = &number;
- assert(x == y);
- assert(x == &number);
- assert(&number == x);
-}
diff --git a/test/cases/pointers.zig b/test/cases/pointers.zig
deleted file mode 100644
index 47afb60a2efd90df70caa936fc957979a12a0033..0000000000000000000000000000000000000000
--- a/test/cases/pointers.zig
+++ /dev/null
@@ -1,44 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "dereference pointer" {
- comptime testDerefPtr();
- testDerefPtr();
-}
-
-fn testDerefPtr() void {
- var x: i32 = 1234;
- var y = &x;
- y.* += 1;
- assert(x == 1235);
-}
-
-test "pointer arithmetic" {
- var ptr = c"abcd";
-
- assert(ptr[0] == 'a');
- ptr += 1;
- assert(ptr[0] == 'b');
- ptr += 1;
- assert(ptr[0] == 'c');
- ptr += 1;
- assert(ptr[0] == 'd');
- ptr += 1;
- assert(ptr[0] == 0);
- ptr -= 1;
- assert(ptr[0] == 'd');
- ptr -= 1;
- assert(ptr[0] == 'c');
- ptr -= 1;
- assert(ptr[0] == 'b');
- ptr -= 1;
- assert(ptr[0] == 'a');
-}
-
-test "double pointer parsing" {
- comptime assert(PtrOf(PtrOf(i32)) == **i32);
-}
-
-fn PtrOf(comptime T: type) type {
- return *T;
-}
diff --git a/test/cases/popcount.zig b/test/cases/popcount.zig
deleted file mode 100644
index 7dc7f28c0e9cf48733267aa5b6cf961c33880e73..0000000000000000000000000000000000000000
--- a/test/cases/popcount.zig
+++ /dev/null
@@ -1,24 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "@popCount" {
- comptime testPopCount();
- testPopCount();
-}
-
-fn testPopCount() void {
- {
- var x: u32 = 0xaa;
- assert(@popCount(x) == 4);
- }
- {
- var x: u32 = 0xaaaaaaaa;
- assert(@popCount(x) == 16);
- }
- {
- var x: i16 = -1;
- assert(@popCount(x) == 16);
- }
- comptime {
- assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
- }
-}
diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig
deleted file mode 100644
index 54c3dda8493026f9547acf5570ee0fe64e4e87e3..0000000000000000000000000000000000000000
--- a/test/cases/ptrcast.zig
+++ /dev/null
@@ -1,52 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const assertOrPanic = std.debug.assertOrPanic;
-
-test "reinterpret bytes as integer with nonzero offset" {
- testReinterpretBytesAsInteger();
- comptime testReinterpretBytesAsInteger();
-}
-
-fn testReinterpretBytesAsInteger() void {
- const bytes = "\x12\x34\x56\x78\xab";
- const expected = switch (builtin.endian) {
- builtin.Endian.Little => 0xab785634,
- builtin.Endian.Big => 0x345678ab,
- };
- assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);
-}
-
-test "reinterpret bytes of an array into an extern struct" {
- testReinterpretBytesAsExternStruct();
- comptime testReinterpretBytesAsExternStruct();
-}
-
-fn testReinterpretBytesAsExternStruct() void {
- var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 };
-
- const S = extern struct {
- a: u8,
- b: u16,
- c: u8,
- };
-
- var ptr = @ptrCast(*const S, &bytes);
- var val = ptr.c;
- assertOrPanic(val == 5);
-}
-
-test "reinterpret struct field at comptime" {
- const numLittle = comptime Bytes.init(0x12345678);
- assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes));
-}
-
-const Bytes = struct {
- bytes: [4]u8,
-
- pub fn init(v: u32) Bytes {
- var res: Bytes = undefined;
- @ptrCast(*align(1) u32, &res.bytes).* = v;
-
- return res;
- }
-};
diff --git a/test/cases/pub_enum/index.zig b/test/cases/pub_enum/index.zig
deleted file mode 100644
index 7fdd07b8a3846fb23141d1821acd8ea35e2c4969..0000000000000000000000000000000000000000
--- a/test/cases/pub_enum/index.zig
+++ /dev/null
@@ -1,13 +0,0 @@
-const other = @import("other.zig");
-const assert = @import("std").debug.assert;
-
-test "pub enum" {
- pubEnumTest(other.APubEnum.Two);
-}
-fn pubEnumTest(foo: other.APubEnum) void {
- assert(foo == other.APubEnum.Two);
-}
-
-test "cast with imported symbol" {
- assert(other.size_t(42) == 42);
-}
diff --git a/test/cases/pub_enum/other.zig b/test/cases/pub_enum/other.zig
deleted file mode 100644
index c66395038397a4d91938ff3400613ae2d734bc14..0000000000000000000000000000000000000000
--- a/test/cases/pub_enum/other.zig
+++ /dev/null
@@ -1,6 +0,0 @@
-pub const APubEnum = enum {
- One,
- Two,
- Three,
-};
-pub const size_t = u64;
diff --git a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig
deleted file mode 100644
index 3c94bb0d49bfa5c060eb6bafa152cf227f63eb7f..0000000000000000000000000000000000000000
--- a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig
+++ /dev/null
@@ -1,37 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-var ok: bool = false;
-test "reference a variable in an if after an if in the 2nd switch prong" {
- foo(true, Num.Two, false, "aoeu");
- assert(!ok);
- foo(false, Num.One, false, "aoeu");
- assert(!ok);
- foo(true, Num.One, false, "aoeu");
- assert(ok);
-}
-
-const Num = enum {
- One,
- Two,
-};
-
-fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
- switch (k) {
- Num.Two => {},
- Num.One => {
- if (c) {
- const output_path = b;
-
- if (c2) {}
-
- a(output_path);
- }
- },
- }
-}
-
-fn a(x: []const u8) void {
- assert(mem.eql(u8, x, "aoeu"));
- ok = true;
-}
diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig
deleted file mode 100644
index b9b8aff4e16ad47a56d7dc486e4a96688d815af4..0000000000000000000000000000000000000000
--- a/test/cases/reflection.zig
+++ /dev/null
@@ -1,95 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const reflection = @This();
-
-test "reflection: array, pointer, optional, error union type child" {
- comptime {
- assert(([10]u8).Child == u8);
- assert((*u8).Child == u8);
- assert((anyerror!u8).Payload == u8);
- assert((?u8).Child == u8);
- }
-}
-
-test "reflection: function return type, var args, and param types" {
- comptime {
- assert(@typeOf(dummy).ReturnType == i32);
- assert(!@typeOf(dummy).is_var_args);
- assert(@typeOf(dummy_varargs).is_var_args);
- assert(@typeOf(dummy).arg_count == 3);
- assert(@ArgType(@typeOf(dummy), 0) == bool);
- assert(@ArgType(@typeOf(dummy), 1) == i32);
- assert(@ArgType(@typeOf(dummy), 2) == f32);
- }
-}
-
-fn dummy(a: bool, b: i32, c: f32) i32 {
- return 1234;
-}
-fn dummy_varargs(args: ...) void {}
-
-test "reflection: struct member types and names" {
- comptime {
- assert(@memberCount(Foo) == 3);
-
- assert(@memberType(Foo, 0) == i32);
- assert(@memberType(Foo, 1) == bool);
- assert(@memberType(Foo, 2) == void);
-
- assert(mem.eql(u8, @memberName(Foo, 0), "one"));
- assert(mem.eql(u8, @memberName(Foo, 1), "two"));
- assert(mem.eql(u8, @memberName(Foo, 2), "three"));
- }
-}
-
-test "reflection: enum member types and names" {
- comptime {
- assert(@memberCount(Bar) == 4);
-
- assert(@memberType(Bar, 0) == void);
- assert(@memberType(Bar, 1) == i32);
- assert(@memberType(Bar, 2) == bool);
- assert(@memberType(Bar, 3) == f64);
-
- assert(mem.eql(u8, @memberName(Bar, 0), "One"));
- assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
- assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
- assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
- }
-}
-
-test "reflection: @field" {
- var f = Foo{
- .one = 42,
- .two = true,
- .three = void{},
- };
-
- assert(f.one == f.one);
- assert(@field(f, "o" ++ "ne") == f.one);
- assert(@field(f, "t" ++ "wo") == f.two);
- assert(@field(f, "th" ++ "ree") == f.three);
- assert(@field(Foo, "const" ++ "ant") == Foo.constant);
- assert(@field(Bar, "O" ++ "ne") == Bar.One);
- assert(@field(Bar, "T" ++ "wo") == Bar.Two);
- assert(@field(Bar, "Th" ++ "ree") == Bar.Three);
- assert(@field(Bar, "F" ++ "our") == Bar.Four);
- assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
- @field(f, "o" ++ "ne") = 4;
- assert(f.one == 4);
-}
-
-const Foo = struct {
- const constant = 52;
-
- one: i32,
- two: bool,
- three: void,
-};
-
-const Bar = union(enum) {
- One: void,
- Two: i32,
- Three: bool,
- Four: f64,
-};
diff --git a/test/cases/sizeof_and_typeof.zig b/test/cases/sizeof_and_typeof.zig
deleted file mode 100644
index 11c6b2f6ba36c9c355b50dae4c724bc9d14ede34..0000000000000000000000000000000000000000
--- a/test/cases/sizeof_and_typeof.zig
+++ /dev/null
@@ -1,69 +0,0 @@
-const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
-
-test "@sizeOf and @typeOf" {
- const y: @typeOf(x) = 120;
- assert(@sizeOf(@typeOf(y)) == 2);
-}
-const x: u16 = 13;
-const z: @typeOf(x) = 19;
-
-const A = struct {
- a: u8,
- b: u32,
- c: u8,
- d: u3,
- e: u5,
- f: u16,
- g: u16,
-};
-
-const P = packed struct {
- a: u8,
- b: u32,
- c: u8,
- d: u3,
- e: u5,
- f: u16,
- g: u16,
-};
-
-test "@byteOffsetOf" {
- // Packed structs have fixed memory layout
- assert(@byteOffsetOf(P, "a") == 0);
- assert(@byteOffsetOf(P, "b") == 1);
- assert(@byteOffsetOf(P, "c") == 5);
- assert(@byteOffsetOf(P, "d") == 6);
- assert(@byteOffsetOf(P, "e") == 6);
- assert(@byteOffsetOf(P, "f") == 7);
- assert(@byteOffsetOf(P, "g") == 9);
-
- // Normal struct fields can be moved/padded
- var a: A = undefined;
- assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
- assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
- assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
- assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
- assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
- assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
- assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
-}
-
-test "@bitOffsetOf" {
- // Packed structs have fixed memory layout
- assert(@bitOffsetOf(P, "a") == 0);
- assert(@bitOffsetOf(P, "b") == 8);
- assert(@bitOffsetOf(P, "c") == 40);
- assert(@bitOffsetOf(P, "d") == 48);
- assert(@bitOffsetOf(P, "e") == 51);
- assert(@bitOffsetOf(P, "f") == 56);
- assert(@bitOffsetOf(P, "g") == 72);
-
- assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
- assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
- assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
- assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
- assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
- assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
- assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
-}
diff --git a/test/cases/slice.zig b/test/cases/slice.zig
deleted file mode 100644
index b4b43bdd1933b2053a0325225fca88324372e6a1..0000000000000000000000000000000000000000
--- a/test/cases/slice.zig
+++ /dev/null
@@ -1,40 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-const x = @intToPtr([*]i32, 0x1000)[0..0x500];
-const y = x[0x100..];
-test "compile time slice of pointer to hard coded address" {
- assert(@ptrToInt(x.ptr) == 0x1000);
- assert(x.len == 0x500);
-
- assert(@ptrToInt(y.ptr) == 0x1100);
- assert(y.len == 0x400);
-}
-
-test "slice child property" {
- var array: [5]i32 = undefined;
- var slice = array[0..];
- assert(@typeOf(slice).Child == i32);
-}
-
-test "runtime safety lets us slice from len..len" {
- var an_array = []u8{
- 1,
- 2,
- 3,
- };
- assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
-}
-
-fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
- return a_slice[start..end];
-}
-
-test "implicitly cast array of size 0 to slice" {
- var msg = []u8{};
- assertLenIsZero(msg);
-}
-
-fn assertLenIsZero(msg: []const u8) void {
- assert(msg.len == 0);
-}
diff --git a/test/cases/struct.zig b/test/cases/struct.zig
deleted file mode 100644
index bbbd21912c324a70dd25b34fd6f7dcb409599aa6..0000000000000000000000000000000000000000
--- a/test/cases/struct.zig
+++ /dev/null
@@ -1,470 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-
-const StructWithNoFields = struct {
- fn add(a: i32, b: i32) i32 {
- return a + b;
- }
-};
-const empty_global_instance = StructWithNoFields{};
-
-test "call struct static method" {
- const result = StructWithNoFields.add(3, 4);
- assert(result == 7);
-}
-
-test "return empty struct instance" {
- _ = returnEmptyStructInstance();
-}
-fn returnEmptyStructInstance() StructWithNoFields {
- return empty_global_instance;
-}
-
-const should_be_11 = StructWithNoFields.add(5, 6);
-
-test "invake static method in global scope" {
- assert(should_be_11 == 11);
-}
-
-test "void struct fields" {
- const foo = VoidStructFieldsFoo{
- .a = void{},
- .b = 1,
- .c = void{},
- };
- assert(foo.b == 1);
- assert(@sizeOf(VoidStructFieldsFoo) == 4);
-}
-const VoidStructFieldsFoo = struct {
- a: void,
- b: i32,
- c: void,
-};
-
-test "structs" {
- var foo: StructFoo = undefined;
- @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
- foo.a += 1;
- foo.b = foo.a == 1;
- testFoo(foo);
- testMutation(&foo);
- assert(foo.c == 100);
-}
-const StructFoo = struct {
- a: i32,
- b: bool,
- c: f32,
-};
-fn testFoo(foo: StructFoo) void {
- assert(foo.b);
-}
-fn testMutation(foo: *StructFoo) void {
- foo.c = 100;
-}
-
-const Node = struct {
- val: Val,
- next: *Node,
-};
-
-const Val = struct {
- x: i32,
-};
-
-test "struct point to self" {
- var root: Node = undefined;
- root.val.x = 1;
-
- var node: Node = undefined;
- node.next = &root;
- node.val.x = 2;
-
- root.next = &node;
-
- assert(node.next.next.next.val.x == 1);
-}
-
-test "struct byval assign" {
- var foo1: StructFoo = undefined;
- var foo2: StructFoo = undefined;
-
- foo1.a = 1234;
- foo2.a = 0;
- assert(foo2.a == 0);
- foo2 = foo1;
- assert(foo2.a == 1234);
-}
-
-fn structInitializer() void {
- const val = Val{ .x = 42 };
- assert(val.x == 42);
-}
-
-test "fn call of struct field" {
- assert(callStructField(Foo{ .ptr = aFunc }) == 13);
-}
-
-const Foo = struct {
- ptr: fn () i32,
-};
-
-fn aFunc() i32 {
- return 13;
-}
-
-fn callStructField(foo: Foo) i32 {
- return foo.ptr();
-}
-
-test "store member function in variable" {
- const instance = MemberFnTestFoo{ .x = 1234 };
- const memberFn = MemberFnTestFoo.member;
- const result = memberFn(instance);
- assert(result == 1234);
-}
-const MemberFnTestFoo = struct {
- x: i32,
- fn member(foo: MemberFnTestFoo) i32 {
- return foo.x;
- }
-};
-
-test "call member function directly" {
- const instance = MemberFnTestFoo{ .x = 1234 };
- const result = MemberFnTestFoo.member(instance);
- assert(result == 1234);
-}
-
-test "member functions" {
- const r = MemberFnRand{ .seed = 1234 };
- assert(r.getSeed() == 1234);
-}
-const MemberFnRand = struct {
- seed: u32,
- pub fn getSeed(r: *const MemberFnRand) u32 {
- return r.seed;
- }
-};
-
-test "return struct byval from function" {
- const bar = makeBar(1234, 5678);
- assert(bar.y == 5678);
-}
-const Bar = struct {
- x: i32,
- y: i32,
-};
-fn makeBar(x: i32, y: i32) Bar {
- return Bar{
- .x = x,
- .y = y,
- };
-}
-
-test "empty struct method call" {
- const es = EmptyStruct{};
- assert(es.method() == 1234);
-}
-const EmptyStruct = struct {
- fn method(es: *const EmptyStruct) i32 {
- return 1234;
- }
-};
-
-test "return empty struct from fn" {
- _ = testReturnEmptyStructFromFn();
-}
-const EmptyStruct2 = struct {};
-fn testReturnEmptyStructFromFn() EmptyStruct2 {
- return EmptyStruct2{};
-}
-
-test "pass slice of empty struct to fn" {
- assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
-}
-fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
- return slice.len;
-}
-
-const APackedStruct = packed struct {
- x: u8,
- y: u8,
-};
-
-test "packed struct" {
- var foo = APackedStruct{
- .x = 1,
- .y = 2,
- };
- foo.y += 1;
- const four = foo.x + foo.y;
- assert(four == 4);
-}
-
-const BitField1 = packed struct {
- a: u3,
- b: u3,
- c: u2,
-};
-
-const bit_field_1 = BitField1{
- .a = 1,
- .b = 2,
- .c = 3,
-};
-
-test "bit field access" {
- var data = bit_field_1;
- assert(getA(&data) == 1);
- assert(getB(&data) == 2);
- assert(getC(&data) == 3);
- comptime assert(@sizeOf(BitField1) == 1);
-
- data.b += 1;
- assert(data.b == 3);
-
- data.a += 1;
- assert(data.a == 2);
- assert(data.b == 3);
-}
-
-fn getA(data: *const BitField1) u3 {
- return data.a;
-}
-
-fn getB(data: *const BitField1) u3 {
- return data.b;
-}
-
-fn getC(data: *const BitField1) u2 {
- return data.c;
-}
-
-const Foo24Bits = packed struct {
- field: u24,
-};
-const Foo96Bits = packed struct {
- a: u24,
- b: u24,
- c: u24,
- d: u24,
-};
-
-test "packed struct 24bits" {
- comptime {
- assert(@sizeOf(Foo24Bits) == 3);
- assert(@sizeOf(Foo96Bits) == 12);
- }
-
- var value = Foo96Bits{
- .a = 0,
- .b = 0,
- .c = 0,
- .d = 0,
- };
- value.a += 1;
- assert(value.a == 1);
- assert(value.b == 0);
- assert(value.c == 0);
- assert(value.d == 0);
-
- value.b += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 0);
- assert(value.d == 0);
-
- value.c += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 1);
- assert(value.d == 0);
-
- value.d += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 1);
- assert(value.d == 1);
-}
-
-const FooArray24Bits = packed struct {
- a: u16,
- b: [2]Foo24Bits,
- c: u16,
-};
-
-test "packed array 24bits" {
- comptime {
- assert(@sizeOf([9]Foo24Bits) == 9 * 3);
- assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
- }
-
- var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
- bytes[bytes.len - 1] = 0xaa;
- const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
- assert(ptr.a == 0);
- assert(ptr.b[0].field == 0);
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
-
- ptr.a = maxInt(u16);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == 0);
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
-
- ptr.b[0].field = maxInt(u24);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
-
- ptr.b[1].field = maxInt(u24);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == maxInt(u24));
- assert(ptr.c == 0);
-
- ptr.c = maxInt(u16);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == maxInt(u24));
- assert(ptr.c == maxInt(u16));
-
- assert(bytes[bytes.len - 1] == 0xaa);
-}
-
-const FooStructAligned = packed struct {
- a: u8,
- b: u8,
-};
-
-const FooArrayOfAligned = packed struct {
- a: [2]FooStructAligned,
-};
-
-test "aligned array of packed struct" {
- comptime {
- assert(@sizeOf(FooStructAligned) == 2);
- assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
- }
-
- var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
- const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
-
- assert(ptr.a[0].a == 0xbb);
- assert(ptr.a[0].b == 0xbb);
- assert(ptr.a[1].a == 0xbb);
- assert(ptr.a[1].b == 0xbb);
-}
-
-test "runtime struct initialization of bitfield" {
- const s1 = Nibbles{
- .x = x1,
- .y = x1,
- };
- const s2 = Nibbles{
- .x = @intCast(u4, x2),
- .y = @intCast(u4, x2),
- };
-
- assert(s1.x == x1);
- assert(s1.y == x1);
- assert(s2.x == @intCast(u4, x2));
- assert(s2.y == @intCast(u4, x2));
-}
-
-var x1 = u4(1);
-var x2 = u8(2);
-
-const Nibbles = packed struct {
- x: u4,
- y: u4,
-};
-
-const Bitfields = packed struct {
- f1: u16,
- f2: u16,
- f3: u8,
- f4: u8,
- f5: u4,
- f6: u4,
- f7: u8,
-};
-
-test "native bit field understands endianness" {
- var all: u64 = 0x7765443322221111;
- var bytes: [8]u8 = undefined;
- @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
- var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
-
- assert(bitfields.f1 == 0x1111);
- assert(bitfields.f2 == 0x2222);
- assert(bitfields.f3 == 0x33);
- assert(bitfields.f4 == 0x44);
- assert(bitfields.f5 == 0x5);
- assert(bitfields.f6 == 0x6);
- assert(bitfields.f7 == 0x77);
-}
-
-test "align 1 field before self referential align 8 field as slice return type" {
- const result = alloc(Expr);
- assert(result.len == 0);
-}
-
-const Expr = union(enum) {
- Literal: u8,
- Question: *Expr,
-};
-
-fn alloc(comptime T: type) []T {
- return []T{};
-}
-
-test "call method with mutable reference to struct with no fields" {
- const S = struct {
- fn doC(s: *const @This()) bool {
- return true;
- }
- fn do(s: *@This()) bool {
- return true;
- }
- };
-
- var s = S{};
- assert(S.doC(&s));
- assert(s.doC());
- assert(S.do(&s));
- assert(s.do());
-}
-
-test "implicit cast packed struct field to const ptr" {
- const LevelUpMove = packed struct {
- move_id: u9,
- level: u7,
-
- fn toInt(value: u7) u7 {
- return value;
- }
- };
-
- var lup: LevelUpMove = undefined;
- lup.level = 12;
- const res = LevelUpMove.toInt(lup.level);
- assert(res == 12);
-}
-
-test "pointer to packed struct member in a stack variable" {
- const S = packed struct {
- a: u2,
- b: u2,
- };
-
- var s = S{ .a = 2, .b = 0 };
- var b_ptr = &s.b;
- assert(s.b == 0);
- b_ptr.* = 2;
- assert(s.b == 2);
-}
diff --git a/test/cases/struct_contains_null_ptr_itself.zig b/test/cases/struct_contains_null_ptr_itself.zig
deleted file mode 100644
index 21175974b3d82e988f03d0d6d542cb968262531f..0000000000000000000000000000000000000000
--- a/test/cases/struct_contains_null_ptr_itself.zig
+++ /dev/null
@@ -1,21 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "struct contains null pointer which contains original struct" {
- var x: ?*NodeLineComment = null;
- assert(x == null);
-}
-
-pub const Node = struct {
- id: Id,
- comment: ?*NodeLineComment,
-
- pub const Id = enum {
- Root,
- LineComment,
- };
-};
-
-pub const NodeLineComment = struct {
- base: Node,
-};
diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig
deleted file mode 100644
index aa3075312cc76c4f8b0f1be9d0891063c48a8258..0000000000000000000000000000000000000000
--- a/test/cases/struct_contains_slice_of_itself.zig
+++ /dev/null
@@ -1,85 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const Node = struct {
- payload: i32,
- children: []Node,
-};
-
-const NodeAligned = struct {
- payload: i32,
- children: []align(@alignOf(NodeAligned)) NodeAligned,
-};
-
-test "struct contains slice of itself" {
- var other_nodes = []Node{
- Node{
- .payload = 31,
- .children = []Node{},
- },
- Node{
- .payload = 32,
- .children = []Node{},
- },
- };
- var nodes = []Node{
- Node{
- .payload = 1,
- .children = []Node{},
- },
- Node{
- .payload = 2,
- .children = []Node{},
- },
- Node{
- .payload = 3,
- .children = other_nodes[0..],
- },
- };
- const root = Node{
- .payload = 1234,
- .children = nodes[0..],
- };
- assert(root.payload == 1234);
- assert(root.children[0].payload == 1);
- assert(root.children[1].payload == 2);
- assert(root.children[2].payload == 3);
- assert(root.children[2].children[0].payload == 31);
- assert(root.children[2].children[1].payload == 32);
-}
-
-test "struct contains aligned slice of itself" {
- var other_nodes = []NodeAligned{
- NodeAligned{
- .payload = 31,
- .children = []NodeAligned{},
- },
- NodeAligned{
- .payload = 32,
- .children = []NodeAligned{},
- },
- };
- var nodes = []NodeAligned{
- NodeAligned{
- .payload = 1,
- .children = []NodeAligned{},
- },
- NodeAligned{
- .payload = 2,
- .children = []NodeAligned{},
- },
- NodeAligned{
- .payload = 3,
- .children = other_nodes[0..],
- },
- };
- const root = NodeAligned{
- .payload = 1234,
- .children = nodes[0..],
- };
- assert(root.payload == 1234);
- assert(root.children[0].payload == 1);
- assert(root.children[1].payload == 2);
- assert(root.children[2].payload == 3);
- assert(root.children[2].children[0].payload == 31);
- assert(root.children[2].children[1].payload == 32);
-}
diff --git a/test/cases/switch.zig b/test/cases/switch.zig
deleted file mode 100644
index 1162fdd4b2eab7519bed9796d817389454af7291..0000000000000000000000000000000000000000
--- a/test/cases/switch.zig
+++ /dev/null
@@ -1,271 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "switch with numbers" {
- testSwitchWithNumbers(13);
-}
-
-fn testSwitchWithNumbers(x: u32) void {
- const result = switch (x) {
- 1, 2, 3, 4...8 => false,
- 13 => true,
- else => false,
- };
- assert(result);
-}
-
-test "switch with all ranges" {
- assert(testSwitchWithAllRanges(50, 3) == 1);
- assert(testSwitchWithAllRanges(101, 0) == 2);
- assert(testSwitchWithAllRanges(300, 5) == 3);
- assert(testSwitchWithAllRanges(301, 6) == 6);
-}
-
-fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
- return switch (x) {
- 0...100 => 1,
- 101...200 => 2,
- 201...300 => 3,
- else => y,
- };
-}
-
-test "implicit comptime switch" {
- const x = 3 + 4;
- const result = switch (x) {
- 3 => 10,
- 4 => 11,
- 5, 6 => 12,
- 7, 8 => 13,
- else => 14,
- };
-
- comptime {
- assert(result + 1 == 14);
- }
-}
-
-test "switch on enum" {
- const fruit = Fruit.Orange;
- nonConstSwitchOnEnum(fruit);
-}
-const Fruit = enum {
- Apple,
- Orange,
- Banana,
-};
-fn nonConstSwitchOnEnum(fruit: Fruit) void {
- switch (fruit) {
- Fruit.Apple => unreachable,
- Fruit.Orange => {},
- Fruit.Banana => unreachable,
- }
-}
-
-test "switch statement" {
- nonConstSwitch(SwitchStatmentFoo.C);
-}
-fn nonConstSwitch(foo: SwitchStatmentFoo) void {
- const val = switch (foo) {
- SwitchStatmentFoo.A => i32(1),
- SwitchStatmentFoo.B => 2,
- SwitchStatmentFoo.C => 3,
- SwitchStatmentFoo.D => 4,
- };
- assert(val == 3);
-}
-const SwitchStatmentFoo = enum {
- A,
- B,
- C,
- D,
-};
-
-test "switch prong with variable" {
- switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
- switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
- switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
-}
-const SwitchProngWithVarEnum = union(enum) {
- One: i32,
- Two: f32,
- Meh: void,
-};
-fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void {
- switch (a) {
- SwitchProngWithVarEnum.One => |x| {
- assert(x == 13);
- },
- SwitchProngWithVarEnum.Two => |x| {
- assert(x == 13.0);
- },
- SwitchProngWithVarEnum.Meh => |x| {
- const v: void = x;
- },
- }
-}
-
-test "switch on enum using pointer capture" {
- testSwitchEnumPtrCapture();
- comptime testSwitchEnumPtrCapture();
-}
-
-fn testSwitchEnumPtrCapture() void {
- var value = SwitchProngWithVarEnum{ .One = 1234 };
- switch (value) {
- SwitchProngWithVarEnum.One => |*x| x.* += 1,
- else => unreachable,
- }
- switch (value) {
- SwitchProngWithVarEnum.One => |x| assert(x == 1235),
- else => unreachable,
- }
-}
-
-test "switch with multiple expressions" {
- const x = switch (returnsFive()) {
- 1, 2, 3 => 1,
- 4, 5, 6 => 2,
- else => i32(3),
- };
- assert(x == 2);
-}
-fn returnsFive() i32 {
- return 5;
-}
-
-const Number = union(enum) {
- One: u64,
- Two: u8,
- Three: f32,
-};
-
-const number = Number{ .Three = 1.23 };
-
-fn returnsFalse() bool {
- switch (number) {
- Number.One => |x| return x > 1234,
- Number.Two => |x| return x == 'a',
- Number.Three => |x| return x > 12.34,
- }
-}
-test "switch on const enum with var" {
- assert(!returnsFalse());
-}
-
-test "switch on type" {
- assert(trueIfBoolFalseOtherwise(bool));
- assert(!trueIfBoolFalseOtherwise(i32));
-}
-
-fn trueIfBoolFalseOtherwise(comptime T: type) bool {
- return switch (T) {
- bool => true,
- else => false,
- };
-}
-
-test "switch handles all cases of number" {
- testSwitchHandleAllCases();
- comptime testSwitchHandleAllCases();
-}
-
-fn testSwitchHandleAllCases() void {
- assert(testSwitchHandleAllCasesExhaustive(0) == 3);
- assert(testSwitchHandleAllCasesExhaustive(1) == 2);
- assert(testSwitchHandleAllCasesExhaustive(2) == 1);
- assert(testSwitchHandleAllCasesExhaustive(3) == 0);
-
- assert(testSwitchHandleAllCasesRange(100) == 0);
- assert(testSwitchHandleAllCasesRange(200) == 1);
- assert(testSwitchHandleAllCasesRange(201) == 2);
- assert(testSwitchHandleAllCasesRange(202) == 4);
- assert(testSwitchHandleAllCasesRange(230) == 3);
-}
-
-fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
- return switch (x) {
- 0 => u2(3),
- 1 => 2,
- 2 => 1,
- 3 => 0,
- };
-}
-
-fn testSwitchHandleAllCasesRange(x: u8) u8 {
- return switch (x) {
- 0...100 => u8(0),
- 101...200 => 1,
- 201, 203 => 2,
- 202 => 4,
- 204...255 => 3,
- };
-}
-
-test "switch all prongs unreachable" {
- testAllProngsUnreachable();
- comptime testAllProngsUnreachable();
-}
-
-fn testAllProngsUnreachable() void {
- assert(switchWithUnreachable(1) == 2);
- assert(switchWithUnreachable(2) == 10);
-}
-
-fn switchWithUnreachable(x: i32) i32 {
- while (true) {
- switch (x) {
- 1 => return 2,
- 2 => break,
- else => continue,
- }
- }
- return 10;
-}
-
-fn return_a_number() anyerror!i32 {
- return 1;
-}
-
-test "capture value of switch with all unreachable prongs" {
- const x = return_a_number() catch |err| switch (err) {
- else => unreachable,
- };
- assert(x == 1);
-}
-
-test "switching on booleans" {
- testSwitchOnBools();
- comptime testSwitchOnBools();
-}
-
-fn testSwitchOnBools() void {
- assert(testSwitchOnBoolsTrueAndFalse(true) == false);
- assert(testSwitchOnBoolsTrueAndFalse(false) == true);
-
- assert(testSwitchOnBoolsTrueWithElse(true) == false);
- assert(testSwitchOnBoolsTrueWithElse(false) == true);
-
- assert(testSwitchOnBoolsFalseWithElse(true) == false);
- assert(testSwitchOnBoolsFalseWithElse(false) == true);
-}
-
-fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
- return switch (x) {
- true => false,
- false => true,
- };
-}
-
-fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
- return switch (x) {
- true => false,
- else => true,
- };
-}
-
-fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
- return switch (x) {
- false => true,
- else => false,
- };
-}
diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig
deleted file mode 100644
index 89060690fc0181e5ed640292b10177952f3f77a0..0000000000000000000000000000000000000000
--- a/test/cases/switch_prong_err_enum.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-var read_count: u64 = 0;
-
-fn readOnce() anyerror!u64 {
- read_count += 1;
- return read_count;
-}
-
-const FormValue = union(enum) {
- Address: u64,
- Other: bool,
-};
-
-fn doThing(form_id: u64) anyerror!FormValue {
- return switch (form_id) {
- 17 => FormValue{ .Address = try readOnce() },
- else => error.InvalidDebugInfo,
- };
-}
-
-test "switch prong returns error enum" {
- switch (doThing(17) catch unreachable) {
- FormValue.Address => |payload| {
- assert(payload == 1);
- },
- else => unreachable,
- }
- assert(read_count == 1);
-}
diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/cases/switch_prong_implicit_cast.zig
deleted file mode 100644
index 56d37e290f1cdb7203e555a5854e0d0cb966294e..0000000000000000000000000000000000000000
--- a/test/cases/switch_prong_implicit_cast.zig
+++ /dev/null
@@ -1,22 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const FormValue = union(enum) {
- One: void,
- Two: bool,
-};
-
-fn foo(id: u64) !FormValue {
- return switch (id) {
- 2 => FormValue{ .Two = true },
- 1 => FormValue{ .One = {} },
- else => return error.Whatever,
- };
-}
-
-test "switch prong implicit cast" {
- const result = switch (foo(2) catch unreachable) {
- FormValue.One => false,
- FormValue.Two => |x| x,
- };
- assert(result);
-}
diff --git a/test/cases/syntax.zig b/test/cases/syntax.zig
deleted file mode 100644
index 0c8c3c5ed314b414bbf06efe27ab64e949cb2536..0000000000000000000000000000000000000000
--- a/test/cases/syntax.zig
+++ /dev/null
@@ -1,59 +0,0 @@
-// Test trailing comma syntax
-// zig fmt: off
-
-const struct_trailing_comma = struct { x: i32, y: i32, };
-const struct_no_comma = struct { x: i32, y: i32 };
-const struct_fn_no_comma = struct { fn m() void {} y: i32 };
-
-const enum_no_comma = enum { A, B };
-
-fn container_init() void {
- const S = struct { x: i32, y: i32 };
- _ = S { .x = 1, .y = 2 };
- _ = S { .x = 1, .y = 2, };
-}
-
-fn type_expr_return1() if (true) A {}
-fn type_expr_return2() for (true) |_| A {}
-fn type_expr_return3() while (true) A {}
-fn type_expr_return4() comptime A {}
-
-fn switch_cases(x: i32) void {
- switch (x) {
- 1,2,3 => {},
- 4,5, => {},
- 6...8, => {},
- else => {},
- }
-}
-
-fn switch_prongs(x: i32) void {
- switch (x) {
- 0 => {},
- else => {},
- }
- switch (x) {
- 0 => {},
- else => {}
- }
-}
-
-const fn_no_comma = fn(i32, i32)void;
-const fn_trailing_comma = fn(i32, i32,)void;
-
-fn fn_calls() void {
- fn add(x: i32, y: i32,) i32 { x + y };
- _ = add(1, 2);
- _ = add(1, 2,);
-}
-
-fn asm_lists() void {
- if (false) { // Build AST but don't analyze
- asm ("not real assembly"
- :[a] "x" (x),);
- asm ("not real assembly"
- :[a] "x" (->i32),:[a] "x" (1),);
- asm ("still not real assembly"
- :::"a","b",);
- }
-}
diff --git a/test/cases/this.zig b/test/cases/this.zig
deleted file mode 100644
index c7be074f36c2e5ad0b2361a419a9356a2aa82233..0000000000000000000000000000000000000000
--- a/test/cases/this.zig
+++ /dev/null
@@ -1,34 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const module = @This();
-
-fn Point(comptime T: type) type {
- return struct {
- const Self = @This();
- x: T,
- y: T,
-
- fn addOne(self: *Self) void {
- self.x += 1;
- self.y += 1;
- }
- };
-}
-
-fn add(x: i32, y: i32) i32 {
- return x + y;
-}
-
-test "this refer to module call private fn" {
- assert(module.add(1, 2) == 3);
-}
-
-test "this refer to container" {
- var pt = Point(i32){
- .x = 12,
- .y = 34,
- };
- pt.addOne();
- assert(pt.x == 13);
- assert(pt.y == 35);
-}
diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig
deleted file mode 100644
index 02b5085ccd25cbb7136c2f352ba5d141d16ac84c..0000000000000000000000000000000000000000
--- a/test/cases/truncate.zig
+++ /dev/null
@@ -1,8 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "truncate u0 to larger integer allowed and has comptime known result" {
- var x: u0 = 0;
- const y = @truncate(u8, x);
- comptime assert(y == 0);
-}
diff --git a/test/cases/try.zig b/test/cases/try.zig
deleted file mode 100644
index 450a9af6ac0bb06a530dad4bf7923d4778844dec..0000000000000000000000000000000000000000
--- a/test/cases/try.zig
+++ /dev/null
@@ -1,43 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "try on error union" {
- tryOnErrorUnionImpl();
- comptime tryOnErrorUnionImpl();
-}
-
-fn tryOnErrorUnionImpl() void {
- const x = if (returnsTen()) |val| val + 1 else |err| switch (err) {
- error.ItBroke, error.NoMem => 1,
- error.CrappedOut => i32(2),
- else => unreachable,
- };
- assert(x == 11);
-}
-
-fn returnsTen() anyerror!i32 {
- return 10;
-}
-
-test "try without vars" {
- const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
- assert(result1 == 2);
-
- const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
- assert(result2 == 1);
-}
-
-fn failIfTrue(ok: bool) anyerror!void {
- if (ok) {
- return error.ItBroke;
- } else {
- return;
- }
-}
-
-test "try then not executed with assignment" {
- if (failIfTrue(true)) {
- unreachable;
- } else |err| {
- assert(err == error.ItBroke);
- }
-}
diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig
deleted file mode 100644
index cec532d5d30419b4de264c17b268c032c659ee01..0000000000000000000000000000000000000000
--- a/test/cases/type_info.zig
+++ /dev/null
@@ -1,264 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const TypeInfo = @import("builtin").TypeInfo;
-const TypeId = @import("builtin").TypeId;
-
-test "type info: tag type, void info" {
- testBasic();
- comptime testBasic();
-}
-
-fn testBasic() void {
- assert(@TagType(TypeInfo) == TypeId);
- const void_info = @typeInfo(void);
- assert(TypeId(void_info) == TypeId.Void);
- assert(void_info.Void == {});
-}
-
-test "type info: integer, floating point type info" {
- testIntFloat();
- comptime testIntFloat();
-}
-
-fn testIntFloat() void {
- const u8_info = @typeInfo(u8);
- assert(TypeId(u8_info) == TypeId.Int);
- assert(!u8_info.Int.is_signed);
- assert(u8_info.Int.bits == 8);
-
- const f64_info = @typeInfo(f64);
- assert(TypeId(f64_info) == TypeId.Float);
- assert(f64_info.Float.bits == 64);
-}
-
-test "type info: pointer type info" {
- testPointer();
- comptime testPointer();
-}
-
-fn testPointer() void {
- const u32_ptr_info = @typeInfo(*u32);
- assert(TypeId(u32_ptr_info) == TypeId.Pointer);
- assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
- assert(u32_ptr_info.Pointer.is_const == false);
- assert(u32_ptr_info.Pointer.is_volatile == false);
- assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
- assert(u32_ptr_info.Pointer.child == u32);
-}
-
-test "type info: unknown length pointer type info" {
- testUnknownLenPtr();
- comptime testUnknownLenPtr();
-}
-
-fn testUnknownLenPtr() void {
- const u32_ptr_info = @typeInfo([*]const volatile f64);
- assert(TypeId(u32_ptr_info) == TypeId.Pointer);
- assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
- assert(u32_ptr_info.Pointer.is_const == true);
- assert(u32_ptr_info.Pointer.is_volatile == true);
- assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
- assert(u32_ptr_info.Pointer.child == f64);
-}
-
-test "type info: slice type info" {
- testSlice();
- comptime testSlice();
-}
-
-fn testSlice() void {
- const u32_slice_info = @typeInfo([]u32);
- assert(TypeId(u32_slice_info) == TypeId.Pointer);
- assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
- assert(u32_slice_info.Pointer.is_const == false);
- assert(u32_slice_info.Pointer.is_volatile == false);
- assert(u32_slice_info.Pointer.alignment == 4);
- assert(u32_slice_info.Pointer.child == u32);
-}
-
-test "type info: array type info" {
- testArray();
- comptime testArray();
-}
-
-fn testArray() void {
- const arr_info = @typeInfo([42]bool);
- assert(TypeId(arr_info) == TypeId.Array);
- assert(arr_info.Array.len == 42);
- assert(arr_info.Array.child == bool);
-}
-
-test "type info: optional type info" {
- testOptional();
- comptime testOptional();
-}
-
-fn testOptional() void {
- const null_info = @typeInfo(?void);
- assert(TypeId(null_info) == TypeId.Optional);
- assert(null_info.Optional.child == void);
-}
-
-test "type info: promise info" {
- testPromise();
- comptime testPromise();
-}
-
-fn testPromise() void {
- const null_promise_info = @typeInfo(promise);
- assert(TypeId(null_promise_info) == TypeId.Promise);
- assert(null_promise_info.Promise.child == null);
-
- const promise_info = @typeInfo(promise->usize);
- assert(TypeId(promise_info) == TypeId.Promise);
- assert(promise_info.Promise.child.? == usize);
-}
-
-test "type info: error set, error union info" {
- testErrorSet();
- comptime testErrorSet();
-}
-
-fn testErrorSet() void {
- const TestErrorSet = error{
- First,
- Second,
- Third,
- };
-
- const error_set_info = @typeInfo(TestErrorSet);
- assert(TypeId(error_set_info) == TypeId.ErrorSet);
- assert(error_set_info.ErrorSet.errors.len == 3);
- assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
- assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
-
- const error_union_info = @typeInfo(TestErrorSet!usize);
- assert(TypeId(error_union_info) == TypeId.ErrorUnion);
- assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
- assert(error_union_info.ErrorUnion.payload == usize);
-}
-
-test "type info: enum info" {
- testEnum();
- comptime testEnum();
-}
-
-fn testEnum() void {
- const Os = enum {
- Windows,
- Macos,
- Linux,
- FreeBSD,
- };
-
- const os_info = @typeInfo(Os);
- assert(TypeId(os_info) == TypeId.Enum);
- assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
- assert(os_info.Enum.fields.len == 4);
- assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
- assert(os_info.Enum.fields[3].value == 3);
- assert(os_info.Enum.tag_type == u2);
- assert(os_info.Enum.defs.len == 0);
-}
-
-test "type info: union info" {
- testUnion();
- comptime testUnion();
-}
-
-fn testUnion() void {
- const typeinfo_info = @typeInfo(TypeInfo);
- assert(TypeId(typeinfo_info) == TypeId.Union);
- assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
- assert(typeinfo_info.Union.tag_type.? == TypeId);
- assert(typeinfo_info.Union.fields.len == 24);
- assert(typeinfo_info.Union.fields[4].enum_field != null);
- assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
- assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
- assert(typeinfo_info.Union.defs.len == 20);
-
- const TestNoTagUnion = union {
- Foo: void,
- Bar: u32,
- };
-
- const notag_union_info = @typeInfo(TestNoTagUnion);
- assert(TypeId(notag_union_info) == TypeId.Union);
- assert(notag_union_info.Union.tag_type == null);
- assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
- assert(notag_union_info.Union.fields.len == 2);
- assert(notag_union_info.Union.fields[0].enum_field == null);
- assert(notag_union_info.Union.fields[1].field_type == u32);
-
- const TestExternUnion = extern union {
- foo: *c_void,
- };
-
- const extern_union_info = @typeInfo(TestExternUnion);
- assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
- assert(extern_union_info.Union.tag_type == null);
- assert(extern_union_info.Union.fields[0].enum_field == null);
- assert(extern_union_info.Union.fields[0].field_type == *c_void);
-}
-
-test "type info: struct info" {
- testStruct();
- comptime testStruct();
-}
-
-fn testStruct() void {
- const struct_info = @typeInfo(TestStruct);
- assert(TypeId(struct_info) == TypeId.Struct);
- assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
- assert(struct_info.Struct.fields.len == 3);
- assert(struct_info.Struct.fields[1].offset == null);
- assert(struct_info.Struct.fields[2].field_type == *TestStruct);
- assert(struct_info.Struct.defs.len == 2);
- assert(struct_info.Struct.defs[0].is_pub);
- assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
- assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
- assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
- assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
-}
-
-const TestStruct = packed struct {
- const Self = @This();
-
- fieldA: usize,
- fieldB: void,
- fieldC: *Self,
-
- pub fn foo(self: *const Self) void {}
-};
-
-test "type info: function type info" {
- testFunction();
- comptime testFunction();
-}
-
-fn testFunction() void {
- const fn_info = @typeInfo(@typeOf(foo));
- assert(TypeId(fn_info) == TypeId.Fn);
- assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
- assert(fn_info.Fn.is_generic);
- assert(fn_info.Fn.args.len == 2);
- assert(fn_info.Fn.is_var_args);
- assert(fn_info.Fn.return_type == null);
- assert(fn_info.Fn.async_allocator_type == null);
-
- const test_instance: TestStruct = undefined;
- const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
- assert(TypeId(bound_fn_info) == TypeId.BoundFn);
- assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
-}
-
-fn foo(comptime a: usize, b: bool, args: ...) usize {
- return 0;
-}
-
-test "typeInfo with comptime parameter in struct fn def" {
- const S = struct {
- pub fn func(comptime x: f32) void {}
- };
- comptime var info = @typeInfo(S);
-}
diff --git a/test/cases/undefined.zig b/test/cases/undefined.zig
deleted file mode 100644
index 83c620d21159c99aee500ca1aa609c11da291d54..0000000000000000000000000000000000000000
--- a/test/cases/undefined.zig
+++ /dev/null
@@ -1,68 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-fn initStaticArray() [10]i32 {
- var array: [10]i32 = undefined;
- array[0] = 1;
- array[4] = 2;
- array[7] = 3;
- array[9] = 4;
- return array;
-}
-const static_array = initStaticArray();
-test "init static array to undefined" {
- assert(static_array[0] == 1);
- assert(static_array[4] == 2);
- assert(static_array[7] == 3);
- assert(static_array[9] == 4);
-
- comptime {
- assert(static_array[0] == 1);
- assert(static_array[4] == 2);
- assert(static_array[7] == 3);
- assert(static_array[9] == 4);
- }
-}
-
-const Foo = struct {
- x: i32,
-
- fn setFooXMethod(foo: *Foo) void {
- foo.x = 3;
- }
-};
-
-fn setFooX(foo: *Foo) void {
- foo.x = 2;
-}
-
-test "assign undefined to struct" {
- comptime {
- var foo: Foo = undefined;
- setFooX(&foo);
- assert(foo.x == 2);
- }
- {
- var foo: Foo = undefined;
- setFooX(&foo);
- assert(foo.x == 2);
- }
-}
-
-test "assign undefined to struct with method" {
- comptime {
- var foo: Foo = undefined;
- foo.setFooXMethod();
- assert(foo.x == 3);
- }
- {
- var foo: Foo = undefined;
- foo.setFooXMethod();
- assert(foo.x == 3);
- }
-}
-
-test "type name of undefined" {
- const x = undefined;
- assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
-}
diff --git a/test/cases/underscore.zig b/test/cases/underscore.zig
deleted file mode 100644
index da1c97659cf33eb65eecb3e6682fa44ad8358d70..0000000000000000000000000000000000000000
--- a/test/cases/underscore.zig
+++ /dev/null
@@ -1,28 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "ignore lval with underscore" {
- _ = false;
-}
-
-test "ignore lval with underscore (for loop)" {
- for ([]void{}) |_, i| {
- for ([]void{}) |_, j| {
- break;
- }
- break;
- }
-}
-
-test "ignore lval with underscore (while loop)" {
- while (optionalReturnError()) |_| {
- while (optionalReturnError()) |_| {
- break;
- } else |_| {}
- break;
- } else |_| {}
-}
-
-fn optionalReturnError() !?u32 {
- return error.optionalReturnError;
-}
diff --git a/test/cases/union.zig b/test/cases/union.zig
deleted file mode 100644
index 019a7012daf0ddce0fb10ae70e522126a262cafe..0000000000000000000000000000000000000000
--- a/test/cases/union.zig
+++ /dev/null
@@ -1,352 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const Value = union(enum) {
- Int: u64,
- Array: [9]u8,
-};
-
-const Agg = struct {
- val1: Value,
- val2: Value,
-};
-
-const v1 = Value{ .Int = 1234 };
-const v2 = Value{ .Array = []u8{3} ** 9 };
-
-const err = (anyerror!Agg)(Agg{
- .val1 = v1,
- .val2 = v2,
-});
-
-const array = []Value{
- v1,
- v2,
- v1,
- v2,
-};
-
-test "unions embedded in aggregate types" {
- switch (array[1]) {
- Value.Array => |arr| assert(arr[4] == 3),
- else => unreachable,
- }
- switch ((err catch unreachable).val1) {
- Value.Int => |x| assert(x == 1234),
- else => unreachable,
- }
-}
-
-const Foo = union {
- float: f64,
- int: i32,
-};
-
-test "basic unions" {
- var foo = Foo{ .int = 1 };
- assert(foo.int == 1);
- foo = Foo{ .float = 12.34 };
- assert(foo.float == 12.34);
-}
-
-test "comptime union field access" {
- comptime {
- var foo = Foo{ .int = 0 };
- assert(foo.int == 0);
-
- foo = Foo{ .float = 42.42 };
- assert(foo.float == 42.42);
- }
-}
-
-test "init union with runtime value" {
- var foo: Foo = undefined;
-
- setFloat(&foo, 12.34);
- assert(foo.float == 12.34);
-
- setInt(&foo, 42);
- assert(foo.int == 42);
-}
-
-fn setFloat(foo: *Foo, x: f64) void {
- foo.* = Foo{ .float = x };
-}
-
-fn setInt(foo: *Foo, x: i32) void {
- foo.* = Foo{ .int = x };
-}
-
-const FooExtern = extern union {
- float: f64,
- int: i32,
-};
-
-test "basic extern unions" {
- var foo = FooExtern{ .int = 1 };
- assert(foo.int == 1);
- foo.float = 12.34;
- assert(foo.float == 12.34);
-}
-
-const Letter = enum {
- A,
- B,
- C,
-};
-const Payload = union(Letter) {
- A: i32,
- B: f64,
- C: bool,
-};
-
-test "union with specified enum tag" {
- doTest();
- comptime doTest();
-}
-
-fn doTest() void {
- assert(bar(Payload{ .A = 1234 }) == -10);
-}
-
-fn bar(value: Payload) i32 {
- assert(Letter(value) == Letter.A);
- return switch (value) {
- Payload.A => |x| return x - 1244,
- Payload.B => |x| if (x == 12.34) i32(20) else 21,
- Payload.C => |x| if (x) i32(30) else 31,
- };
-}
-
-const MultipleChoice = union(enum(u32)) {
- A = 20,
- B = 40,
- C = 60,
- D = 1000,
-};
-test "simple union(enum(u32))" {
- var x = MultipleChoice.C;
- assert(x == MultipleChoice.C);
- assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
-}
-
-const MultipleChoice2 = union(enum(u32)) {
- Unspecified1: i32,
- A: f32 = 20,
- Unspecified2: void,
- B: bool = 40,
- Unspecified3: i32,
- C: i8 = 60,
- Unspecified4: void,
- D: void = 1000,
- Unspecified5: i32,
-};
-
-test "union(enum(u32)) with specified and unspecified tag values" {
- comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
- testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
- comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
- assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
- assert(1123 == switch (x) {
- MultipleChoice2.A => 1,
- MultipleChoice2.B => 2,
- MultipleChoice2.C => |v| i32(1000) + v,
- MultipleChoice2.D => 4,
- MultipleChoice2.Unspecified1 => 5,
- MultipleChoice2.Unspecified2 => 6,
- MultipleChoice2.Unspecified3 => 7,
- MultipleChoice2.Unspecified4 => 8,
- MultipleChoice2.Unspecified5 => 9,
- });
-}
-
-const ExternPtrOrInt = extern union {
- ptr: *u8,
- int: u64,
-};
-test "extern union size" {
- comptime assert(@sizeOf(ExternPtrOrInt) == 8);
-}
-
-const PackedPtrOrInt = packed union {
- ptr: *u8,
- int: u64,
-};
-test "extern union size" {
- comptime assert(@sizeOf(PackedPtrOrInt) == 8);
-}
-
-const ZeroBits = union {
- OnlyField: void,
-};
-test "union with only 1 field which is void should be zero bits" {
- comptime assert(@sizeOf(ZeroBits) == 0);
-}
-
-const TheTag = enum {
- A,
- B,
- C,
-};
-const TheUnion = union(TheTag) {
- A: i32,
- B: i32,
- C: i32,
-};
-test "union field access gives the enum values" {
- assert(TheUnion.A == TheTag.A);
- assert(TheUnion.B == TheTag.B);
- assert(TheUnion.C == TheTag.C);
-}
-
-test "cast union to tag type of union" {
- testCastUnionToTagType(TheUnion{ .B = 1234 });
- comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
-}
-
-fn testCastUnionToTagType(x: TheUnion) void {
- assert(TheTag(x) == TheTag.B);
-}
-
-test "cast tag type of union to union" {
- var x: Value2 = Letter2.B;
- assert(Letter2(x) == Letter2.B);
-}
-const Letter2 = enum {
- A,
- B,
- C,
-};
-const Value2 = union(Letter2) {
- A: i32,
- B,
- C,
-};
-
-test "implicit cast union to its tag type" {
- var x: Value2 = Letter2.B;
- assert(x == Letter2.B);
- giveMeLetterB(x);
-}
-fn giveMeLetterB(x: Letter2) void {
- assert(x == Value2.B);
-}
-
-pub const PackThis = union(enum) {
- Invalid: bool,
- StringLiteral: u2,
-};
-
-test "constant packed union" {
- testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }});
-}
-
-fn testConstPackedUnion(expected_tokens: []const PackThis) void {
- assert(expected_tokens[0].StringLiteral == 1);
-}
-
-test "switch on union with only 1 field" {
- var r: PartialInst = undefined;
- r = PartialInst.Compiled;
- switch (r) {
- PartialInst.Compiled => {
- var z: PartialInstWithPayload = undefined;
- z = PartialInstWithPayload{ .Compiled = 1234 };
- switch (z) {
- PartialInstWithPayload.Compiled => |x| {
- assert(x == 1234);
- return;
- },
- }
- },
- }
- unreachable;
-}
-
-const PartialInst = union(enum) {
- Compiled,
-};
-
-const PartialInstWithPayload = union(enum) {
- Compiled: i32,
-};
-
-test "access a member of tagged union with conflicting enum tag name" {
- const Bar = union(enum) {
- A: A,
- B: B,
-
- const A = u8;
- const B = void;
- };
-
- comptime assert(Bar.A == u8);
-}
-
-test "tagged union initialization with runtime void" {
- assert(testTaggedUnionInit({}));
-}
-
-const TaggedUnionWithAVoid = union(enum) {
- A,
- B: i32,
-};
-
-fn testTaggedUnionInit(x: var) bool {
- const y = TaggedUnionWithAVoid{ .A = x };
- return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A;
-}
-
-pub const UnionEnumNoPayloads = union(enum) {
- A,
- B,
-};
-
-test "tagged union with no payloads" {
- const a = UnionEnumNoPayloads{ .B = {} };
- switch (a) {
- @TagType(UnionEnumNoPayloads).A => @panic("wrong"),
- @TagType(UnionEnumNoPayloads).B => {},
- }
-}
-
-test "union with only 1 field casted to its enum type" {
- const Literal = union(enum) {
- Number: f64,
- Bool: bool,
- };
-
- const Expr = union(enum) {
- Literal: Literal,
- };
-
- var e = Expr{ .Literal = Literal{ .Bool = true } };
- const Tag = @TagType(Expr);
- comptime assert(@TagType(Tag) == comptime_int);
- var t = Tag(e);
- assert(t == Expr.Literal);
-}
-
-test "union with only 1 field casted to its enum type which has enum value specified" {
- const Literal = union(enum) {
- Number: f64,
- Bool: bool,
- };
-
- const Tag = enum {
- Literal = 33,
- };
-
- const Expr = union(Tag) {
- Literal: Literal,
- };
-
- var e = Expr{ .Literal = Literal{ .Bool = true } };
- comptime assert(@TagType(Tag) == comptime_int);
- var t = Tag(e);
- assert(t == Expr.Literal);
- assert(@enumToInt(t) == 33);
- comptime assert(@enumToInt(t) == 33);
-}
diff --git a/test/cases/var_args.zig b/test/cases/var_args.zig
deleted file mode 100644
index 3eb6e304486b22492c7a3470f8cc4aa61dcd8fb1..0000000000000000000000000000000000000000
--- a/test/cases/var_args.zig
+++ /dev/null
@@ -1,84 +0,0 @@
-const assert = @import("std").debug.assert;
-
-fn add(args: ...) i32 {
- var sum = i32(0);
- {
- comptime var i: usize = 0;
- inline while (i < args.len) : (i += 1) {
- sum += args[i];
- }
- }
- return sum;
-}
-
-test "add arbitrary args" {
- assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
- assert(add(i32(1234)) == 1234);
- assert(add() == 0);
-}
-
-fn readFirstVarArg(args: ...) void {
- const value = args[0];
-}
-
-test "send void arg to var args" {
- readFirstVarArg({});
-}
-
-test "pass args directly" {
- assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
- assert(addSomeStuff(i32(1234)) == 1234);
- assert(addSomeStuff() == 0);
-}
-
-fn addSomeStuff(args: ...) i32 {
- return add(args);
-}
-
-test "runtime parameter before var args" {
- assert(extraFn(10) == 0);
- assert(extraFn(10, false) == 1);
- assert(extraFn(10, false, true) == 2);
-
- // TODO issue #313
- //comptime {
- // assert(extraFn(10) == 0);
- // assert(extraFn(10, false) == 1);
- // assert(extraFn(10, false, true) == 2);
- //}
-}
-
-fn extraFn(extra: u32, args: ...) usize {
- if (args.len >= 1) {
- assert(args[0] == false);
- }
- if (args.len >= 2) {
- assert(args[1] == true);
- }
- return args.len;
-}
-
-const foos = []fn (...) bool{
- foo1,
- foo2,
-};
-
-fn foo1(args: ...) bool {
- return true;
-}
-fn foo2(args: ...) bool {
- return false;
-}
-
-test "array of var args functions" {
- assert(foos[0]());
- assert(!foos[1]());
-}
-
-test "pass zero length array to var args param" {
- doNothingWithFirstArg("");
-}
-
-fn doNothingWithFirstArg(args: ...) void {
- const a = args[0];
-}
diff --git a/test/cases/void.zig b/test/cases/void.zig
deleted file mode 100644
index 7121ac664b947f738c3c55b7825accb7ddbc0e0d..0000000000000000000000000000000000000000
--- a/test/cases/void.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-const Foo = struct {
- a: void,
- b: i32,
- c: void,
-};
-
-test "compare void with void compile time known" {
- comptime {
- const foo = Foo{
- .a = {},
- .b = 1,
- .c = {},
- };
- assert(foo.a == {});
- }
-}
-
-test "iterate over a void slice" {
- var j: usize = 0;
- for (times(10)) |_, i| {
- assert(i == j);
- j += 1;
- }
-}
-
-fn times(n: usize) []const void {
- return ([*]void)(undefined)[0..n];
-}
diff --git a/test/cases/while.zig b/test/cases/while.zig
deleted file mode 100644
index f774e0ec6b328fb83ff178f37b9196315f7de581..0000000000000000000000000000000000000000
--- a/test/cases/while.zig
+++ /dev/null
@@ -1,227 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "while loop" {
- var i: i32 = 0;
- while (i < 4) {
- i += 1;
- }
- assert(i == 4);
- assert(whileLoop1() == 1);
-}
-fn whileLoop1() i32 {
- return whileLoop2();
-}
-fn whileLoop2() i32 {
- while (true) {
- return 1;
- }
-}
-test "static eval while" {
- assert(static_eval_while_number == 1);
-}
-const static_eval_while_number = staticWhileLoop1();
-fn staticWhileLoop1() i32 {
- return whileLoop2();
-}
-fn staticWhileLoop2() i32 {
- while (true) {
- return 1;
- }
-}
-
-test "continue and break" {
- runContinueAndBreakTest();
- assert(continue_and_break_counter == 8);
-}
-var continue_and_break_counter: i32 = 0;
-fn runContinueAndBreakTest() void {
- var i: i32 = 0;
- while (true) {
- continue_and_break_counter += 2;
- i += 1;
- if (i < 4) {
- continue;
- }
- break;
- }
- assert(i == 4);
-}
-
-test "return with implicit cast from while loop" {
- returnWithImplicitCastFromWhileLoopTest() catch unreachable;
-}
-fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
- while (true) {
- return;
- }
-}
-
-test "while with continue expression" {
- var sum: i32 = 0;
- {
- var i: i32 = 0;
- while (i < 10) : (i += 1) {
- if (i == 5) continue;
- sum += i;
- }
- }
- assert(sum == 40);
-}
-
-test "while with else" {
- var sum: i32 = 0;
- var i: i32 = 0;
- var got_else: i32 = 0;
- while (i < 10) : (i += 1) {
- sum += 1;
- } else {
- got_else += 1;
- }
- assert(sum == 10);
- assert(got_else == 1);
-}
-
-test "while with optional as condition" {
- numbers_left = 10;
- var sum: i32 = 0;
- while (getNumberOrNull()) |value| {
- sum += value;
- }
- assert(sum == 45);
-}
-
-test "while with optional as condition with else" {
- numbers_left = 10;
- var sum: i32 = 0;
- var got_else: i32 = 0;
- while (getNumberOrNull()) |value| {
- sum += value;
- assert(got_else == 0);
- } else {
- got_else += 1;
- }
- assert(sum == 45);
- assert(got_else == 1);
-}
-
-test "while with error union condition" {
- numbers_left = 10;
- var sum: i32 = 0;
- var got_else: i32 = 0;
- while (getNumberOrErr()) |value| {
- sum += value;
- } else |err| {
- assert(err == error.OutOfNumbers);
- got_else += 1;
- }
- assert(sum == 45);
- assert(got_else == 1);
-}
-
-var numbers_left: i32 = undefined;
-fn getNumberOrErr() anyerror!i32 {
- return if (numbers_left == 0) error.OutOfNumbers else x: {
- numbers_left -= 1;
- break :x numbers_left;
- };
-}
-fn getNumberOrNull() ?i32 {
- return if (numbers_left == 0) null else x: {
- numbers_left -= 1;
- break :x numbers_left;
- };
-}
-
-test "while on optional with else result follow else prong" {
- const result = while (returnNull()) |value| {
- break value;
- } else
- i32(2);
- assert(result == 2);
-}
-
-test "while on optional with else result follow break prong" {
- const result = while (returnOptional(10)) |value| {
- break value;
- } else
- i32(2);
- assert(result == 10);
-}
-
-test "while on error union with else result follow else prong" {
- const result = while (returnError()) |value| {
- break value;
- } else |err|
- i32(2);
- assert(result == 2);
-}
-
-test "while on error union with else result follow break prong" {
- const result = while (returnSuccess(10)) |value| {
- break value;
- } else |err|
- i32(2);
- assert(result == 10);
-}
-
-test "while on bool with else result follow else prong" {
- const result = while (returnFalse()) {
- break i32(10);
- } else
- i32(2);
- assert(result == 2);
-}
-
-test "while on bool with else result follow break prong" {
- const result = while (returnTrue()) {
- break i32(10);
- } else
- i32(2);
- assert(result == 10);
-}
-
-test "break from outer while loop" {
- testBreakOuter();
- comptime testBreakOuter();
-}
-
-fn testBreakOuter() void {
- outer: while (true) {
- while (true) {
- break :outer;
- }
- }
-}
-
-test "continue outer while loop" {
- testContinueOuter();
- comptime testContinueOuter();
-}
-
-fn testContinueOuter() void {
- var i: usize = 0;
- outer: while (i < 10) : (i += 1) {
- while (true) {
- continue :outer;
- }
- }
-}
-
-fn returnNull() ?i32 {
- return null;
-}
-fn returnOptional(x: i32) ?i32 {
- return x;
-}
-fn returnError() anyerror!i32 {
- return error.YouWantedAnError;
-}
-fn returnSuccess(x: i32) anyerror!i32 {
- return x;
-}
-fn returnFalse() bool {
- return false;
-}
-fn returnTrue() bool {
- return true;
-}
diff --git a/test/cases/widening.zig b/test/cases/widening.zig
deleted file mode 100644
index cf6ab4ca0fb4eeacf06e8d334554b106ff231686..0000000000000000000000000000000000000000
--- a/test/cases/widening.zig
+++ /dev/null
@@ -1,27 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const mem = std.mem;
-
-test "integer widening" {
- var a: u8 = 250;
- var b: u16 = a;
- var c: u32 = b;
- var d: u64 = c;
- var e: u64 = d;
- var f: u128 = e;
- assert(f == a);
-}
-
-test "implicit unsigned integer to signed integer" {
- var a: u8 = 250;
- var b: i16 = a;
- assert(b == 250);
-}
-
-test "float widening" {
- var a: f16 = 12.34;
- var b: f32 = a;
- var c: f64 = b;
- var d: f128 = c;
- assert(d == a);
-}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index d9603ba4ff3a761d07aa0fc5d5e265dd95bef900..30d9ca5d702d5959011c34d94f51807c6717ffd6 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1,6 +1,40 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.add(
+ "@bitCast same size but bit count mismatch",
+ \\export fn entry(byte: u8) void {
+ \\ var oops = @bitCast(u7, byte);
+ \\}
+ ,
+ ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
+ );
+
+ cases.add(
+ "attempted `&&`",
+ \\export fn entry(a: bool, b: bool) i32 {
+ \\ if (a && b) {
+ \\ return 1234;
+ \\ }
+ \\ return 5678;
+ \\}
+ ,
+ ".tmp_source.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.",
+ );
+
+ cases.add(
+ "attempted `||` on boolean values",
+ \\export fn entry(a: bool, b: bool) i32 {
+ \\ if (a || b) {
+ \\ return 1234;
+ \\ }
+ \\ return 5678;
+ \\}
+ ,
+ ".tmp_source.zig:2:9: error: expected error set type, found 'bool'",
+ ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
+ );
+
cases.add(
"compile log a pointer to an opaque value",
\\export fn entry() void {
@@ -267,8 +301,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const Errors = error{} || u16;
\\}
,
- ".tmp_source.zig:2:20: error: expected error set type, found 'u8'",
- ".tmp_source.zig:5:31: error: expected error set type, found 'u16'",
+ ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'",
+ ".tmp_source.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
+ ".tmp_source.zig:5:31: error: expected error set type, found type 'u16'",
+ ".tmp_source.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
);
cases.add(
@@ -2618,7 +2654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:1:13: error: newline not allowed in string literal",
+ ".tmp_source.zig:1:15: error: newline not allowed in string literal",
);
cases.add(
@@ -3193,7 +3229,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 2;
\\}
,
- ".tmp_source.zig:2:15: error: unable to infer expression type",
+ ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known",
);
cases.add(
@@ -3539,7 +3575,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:2:11: error: expected type, found 'i32'",
+ ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'",
);
cases.add(
@@ -5331,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
,
".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float",
);
+
+ cases.add(
+ "runtime assignment to comptime struct type",
+ \\const Foo = struct {
+ \\ Bar: u8,
+ \\ Baz: type,
+ \\};
+ \\export fn f() void {
+ \\ var x: u8 = 0;
+ \\ const foo = Foo { .Bar = x, .Baz = u8 };
+ \\}
+ ,
+ ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
+ );
+
+ cases.add(
+ "runtime assignment to comptime union type",
+ \\const Foo = union {
+ \\ Bar: u8,
+ \\ Baz: type,
+ \\};
+ \\export fn f() void {
+ \\ var x: u8 = 0;
+ \\ const foo = Foo { .Bar = x };
+ \\}
+ ,
+ ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
+ );
}
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
new file mode 100644
index 0000000000000000000000000000000000000000..1fa00b34fd67197765d831982b974ac3e489f6d2
--- /dev/null
+++ b/test/stage1/behavior.zig
@@ -0,0 +1,81 @@
+comptime {
+ _ = @import("behavior/align.zig");
+ _ = @import("behavior/alignof.zig");
+ _ = @import("behavior/array.zig");
+ _ = @import("behavior/asm.zig");
+ _ = @import("behavior/atomics.zig");
+ _ = @import("behavior/bit_shifting.zig");
+ _ = @import("behavior/bitcast.zig");
+ _ = @import("behavior/bitreverse.zig");
+ _ = @import("behavior/bool.zig");
+ _ = @import("behavior/bswap.zig");
+ _ = @import("behavior/bugs/1076.zig");
+ _ = @import("behavior/bugs/1111.zig");
+ _ = @import("behavior/bugs/1277.zig");
+ _ = @import("behavior/bugs/1322.zig");
+ _ = @import("behavior/bugs/1381.zig");
+ _ = @import("behavior/bugs/1421.zig");
+ _ = @import("behavior/bugs/1442.zig");
+ _ = @import("behavior/bugs/1486.zig");
+ _ = @import("behavior/bugs/394.zig");
+ _ = @import("behavior/bugs/655.zig");
+ _ = @import("behavior/bugs/656.zig");
+ _ = @import("behavior/bugs/726.zig");
+ _ = @import("behavior/bugs/828.zig");
+ _ = @import("behavior/bugs/920.zig");
+ _ = @import("behavior/byval_arg_var.zig");
+ _ = @import("behavior/cancel.zig");
+ _ = @import("behavior/cast.zig");
+ _ = @import("behavior/const_slice_child.zig");
+ _ = @import("behavior/coroutine_await_struct.zig");
+ _ = @import("behavior/coroutines.zig");
+ _ = @import("behavior/defer.zig");
+ _ = @import("behavior/enum.zig");
+ _ = @import("behavior/enum_with_members.zig");
+ _ = @import("behavior/error.zig");
+ _ = @import("behavior/eval.zig");
+ _ = @import("behavior/field_parent_ptr.zig");
+ _ = @import("behavior/fn.zig");
+ _ = @import("behavior/fn_in_struct_in_comptime.zig");
+ _ = @import("behavior/for.zig");
+ _ = @import("behavior/generics.zig");
+ _ = @import("behavior/if.zig");
+ _ = @import("behavior/import.zig");
+ _ = @import("behavior/incomplete_struct_param_tld.zig");
+ _ = @import("behavior/inttoptr.zig");
+ _ = @import("behavior/ir_block_deps.zig");
+ _ = @import("behavior/math.zig");
+ _ = @import("behavior/merge_error_sets.zig");
+ _ = @import("behavior/misc.zig");
+ _ = @import("behavior/namespace_depends_on_compile_var/index.zig");
+ _ = @import("behavior/new_stack_call.zig");
+ _ = @import("behavior/null.zig");
+ _ = @import("behavior/optional.zig");
+ _ = @import("behavior/pointers.zig");
+ _ = @import("behavior/popcount.zig");
+ _ = @import("behavior/ptrcast.zig");
+ _ = @import("behavior/pub_enum/index.zig");
+ _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
+ _ = @import("behavior/reflection.zig");
+ _ = @import("behavior/sizeof_and_typeof.zig");
+ _ = @import("behavior/slice.zig");
+ _ = @import("behavior/struct.zig");
+ _ = @import("behavior/struct_contains_null_ptr_itself.zig");
+ _ = @import("behavior/struct_contains_slice_of_itself.zig");
+ _ = @import("behavior/switch.zig");
+ _ = @import("behavior/switch_prong_err_enum.zig");
+ _ = @import("behavior/switch_prong_implicit_cast.zig");
+ _ = @import("behavior/syntax.zig");
+ _ = @import("behavior/this.zig");
+ _ = @import("behavior/truncate.zig");
+ _ = @import("behavior/try.zig");
+ _ = @import("behavior/type_info.zig");
+ _ = @import("behavior/undefined.zig");
+ _ = @import("behavior/underscore.zig");
+ _ = @import("behavior/union.zig");
+ _ = @import("behavior/var_args.zig");
+ _ = @import("behavior/vector.zig");
+ _ = @import("behavior/void.zig");
+ _ = @import("behavior/while.zig");
+ _ = @import("behavior/widening.zig");
+}
diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig
new file mode 100644
index 0000000000000000000000000000000000000000..aa7a93ad848210b088ab33ab63d284c1e7a1ae56
--- /dev/null
+++ b/test/stage1/behavior/align.zig
@@ -0,0 +1,230 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const builtin = @import("builtin");
+
+var foo: u8 align(4) = 100;
+
+test "global variable alignment" {
+ assertOrPanic(@typeOf(&foo).alignment == 4);
+ assertOrPanic(@typeOf(&foo) == *align(4) u8);
+ const slice = (*[1]u8)(&foo)[0..];
+ assertOrPanic(@typeOf(slice) == []align(4) u8);
+}
+
+fn derp() align(@sizeOf(usize) * 2) i32 {
+ return 1234;
+}
+fn noop1() align(1) void {}
+fn noop4() align(4) void {}
+
+test "function alignment" {
+ assertOrPanic(derp() == 1234);
+ assertOrPanic(@typeOf(noop1) == fn () align(1) void);
+ assertOrPanic(@typeOf(noop4) == fn () align(4) void);
+ noop1();
+ noop4();
+}
+
+var baz: packed struct {
+ a: u32,
+ b: u32,
+} = undefined;
+
+test "packed struct alignment" {
+ assertOrPanic(@typeOf(&baz.b) == *align(1) u32);
+}
+
+const blah: packed struct {
+ a: u3,
+ b: u3,
+ c: u2,
+} = undefined;
+
+test "bit field alignment" {
+ assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3);
+}
+
+test "default alignment allows unspecified in type syntax" {
+ assertOrPanic(*u32 == *align(@alignOf(u32)) u32);
+}
+
+test "implicitly decreasing pointer alignment" {
+ const a: u32 align(4) = 3;
+ const b: u32 align(8) = 4;
+ assertOrPanic(addUnaligned(&a, &b) == 7);
+}
+
+fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
+ return a.* + b.*;
+}
+
+test "implicitly decreasing slice alignment" {
+ const a: u32 align(4) = 3;
+ const b: u32 align(8) = 4;
+ assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
+}
+fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
+ return a[0] + b[0];
+}
+
+test "specifying alignment allows pointer cast" {
+ testBytesAlign(0x33);
+}
+fn testBytesAlign(b: u8) void {
+ var bytes align(4) = []u8{
+ b,
+ b,
+ b,
+ b,
+ };
+ const ptr = @ptrCast(*u32, &bytes[0]);
+ assertOrPanic(ptr.* == 0x33333333);
+}
+
+test "specifying alignment allows slice cast" {
+ testBytesAlignSlice(0x33);
+}
+fn testBytesAlignSlice(b: u8) void {
+ var bytes align(4) = []u8{
+ b,
+ b,
+ b,
+ b,
+ };
+ const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
+ assertOrPanic(slice[0] == 0x33333333);
+}
+
+test "@alignCast pointers" {
+ var x: u32 align(4) = 1;
+ expectsOnly1(&x);
+ assertOrPanic(x == 2);
+}
+fn expectsOnly1(x: *align(1) u32) void {
+ expects4(@alignCast(4, x));
+}
+fn expects4(x: *align(4) u32) void {
+ x.* += 1;
+}
+
+test "@alignCast slices" {
+ var array align(4) = []u32{
+ 1,
+ 1,
+ };
+ const slice = array[0..];
+ sliceExpectsOnly1(slice);
+ assertOrPanic(slice[0] == 2);
+}
+fn sliceExpectsOnly1(slice: []align(1) u32) void {
+ sliceExpects4(@alignCast(4, slice));
+}
+fn sliceExpects4(slice: []align(4) u32) void {
+ slice[0] += 1;
+}
+
+test "implicitly decreasing fn alignment" {
+ testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
+ testImplicitlyDecreaseFnAlign(alignedBig, 5678);
+}
+
+fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
+ assertOrPanic(ptr() == answer);
+}
+
+fn alignedSmall() align(8) i32 {
+ return 1234;
+}
+fn alignedBig() align(16) i32 {
+ return 5678;
+}
+
+test "@alignCast functions" {
+ assertOrPanic(fnExpectsOnly1(simple4) == 0x19);
+}
+fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 {
+ return fnExpects4(@alignCast(4, ptr));
+}
+fn fnExpects4(ptr: fn () align(4) i32) i32 {
+ return ptr();
+}
+fn simple4() align(4) i32 {
+ return 0x19;
+}
+
+test "generic function with align param" {
+ assertOrPanic(whyWouldYouEverDoThis(1) == 0x1);
+ assertOrPanic(whyWouldYouEverDoThis(4) == 0x1);
+ assertOrPanic(whyWouldYouEverDoThis(8) == 0x1);
+}
+
+fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
+ return 0x1;
+}
+
+test "@ptrCast preserves alignment of bigger source" {
+ var x: u32 align(16) = 1234;
+ const ptr = @ptrCast(*u8, &x);
+ assertOrPanic(@typeOf(ptr) == *align(16) u8);
+}
+
+test "runtime known array index has best alignment possible" {
+ // take full advantage of over-alignment
+ var array align(4) = []u8{ 1, 2, 3, 4 };
+ assertOrPanic(@typeOf(&array[0]) == *align(4) u8);
+ assertOrPanic(@typeOf(&array[1]) == *u8);
+ assertOrPanic(@typeOf(&array[2]) == *align(2) u8);
+ assertOrPanic(@typeOf(&array[3]) == *u8);
+
+ // because align is too small but we still figure out to use 2
+ var bigger align(2) = []u64{ 1, 2, 3, 4 };
+ assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64);
+
+ // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
+ var smaller align(2) = []u32{ 1, 2, 3, 4 };
+ comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32);
+ comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
+ testIndex(smaller[0..].ptr, 0, *align(2) u32);
+ testIndex(smaller[0..].ptr, 1, *align(2) u32);
+ testIndex(smaller[0..].ptr, 2, *align(2) u32);
+ testIndex(smaller[0..].ptr, 3, *align(2) u32);
+
+ // has to use ABI alignment because index known at runtime only
+ testIndex2(array[0..].ptr, 0, *u8);
+ testIndex2(array[0..].ptr, 1, *u8);
+ testIndex2(array[0..].ptr, 2, *u8);
+ testIndex2(array[0..].ptr, 3, *u8);
+}
+fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
+ comptime assertOrPanic(@typeOf(&smaller[index]) == T);
+}
+fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void {
+ comptime assertOrPanic(@typeOf(&ptr[index]) == T);
+}
+
+test "alignstack" {
+ assertOrPanic(fnWithAlignedStack() == 1234);
+}
+
+fn fnWithAlignedStack() i32 {
+ @setAlignStack(256);
+ return 1234;
+}
+
+test "alignment of structs" {
+ assertOrPanic(@alignOf(struct {
+ a: i32,
+ b: *i32,
+ }) == @alignOf(usize));
+}
+
+test "alignment of extern() void" {
+ var runtime_nothing = nothing;
+ const casted1 = @ptrCast(*const u8, runtime_nothing);
+ const casted2 = @ptrCast(extern fn () void, casted1);
+ casted2();
+}
+
+extern fn nothing() void {}
diff --git a/test/stage1/behavior/alignof.zig b/test/stage1/behavior/alignof.zig
new file mode 100644
index 0000000000000000000000000000000000000000..98c805908b724e01907d24ba540a8434ebe91007
--- /dev/null
+++ b/test/stage1/behavior/alignof.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const builtin = @import("builtin");
+const maxInt = std.math.maxInt;
+
+const Foo = struct {
+ x: u32,
+ y: u32,
+ z: u32,
+};
+
+test "@alignOf(T) before referencing T" {
+ comptime assertOrPanic(@alignOf(Foo) != maxInt(usize));
+ if (builtin.arch == builtin.Arch.x86_64) {
+ comptime assertOrPanic(@alignOf(Foo) == 4);
+ }
+}
+
diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig
new file mode 100644
index 0000000000000000000000000000000000000000..118330520986bfc055fb640fa2793c239f9703f6
--- /dev/null
+++ b/test/stage1/behavior/array.zig
@@ -0,0 +1,270 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+test "arrays" {
+ var array: [5]u32 = undefined;
+
+ var i: u32 = 0;
+ while (i < 5) {
+ array[i] = i + 1;
+ i = array[i];
+ }
+
+ i = 0;
+ var accumulator = u32(0);
+ while (i < 5) {
+ accumulator += array[i];
+
+ i += 1;
+ }
+
+ assertOrPanic(accumulator == 15);
+ assertOrPanic(getArrayLen(array) == 5);
+}
+fn getArrayLen(a: []const u32) usize {
+ return a.len;
+}
+
+test "void arrays" {
+ var array: [4]void = undefined;
+ array[0] = void{};
+ array[1] = array[2];
+ assertOrPanic(@sizeOf(@typeOf(array)) == 0);
+ assertOrPanic(array.len == 4);
+}
+
+test "array literal" {
+ const hex_mult = []u16{
+ 4096,
+ 256,
+ 16,
+ 1,
+ };
+
+ assertOrPanic(hex_mult.len == 4);
+ assertOrPanic(hex_mult[1] == 256);
+}
+
+test "array dot len const expr" {
+ assertOrPanic(comptime x: {
+ break :x some_array.len == 4;
+ });
+}
+
+const ArrayDotLenConstExpr = struct {
+ y: [some_array.len]u8,
+};
+const some_array = []u8{
+ 0,
+ 1,
+ 2,
+ 3,
+};
+
+test "nested arrays" {
+ const array_of_strings = [][]const u8{
+ "hello",
+ "this",
+ "is",
+ "my",
+ "thing",
+ };
+ for (array_of_strings) |s, i| {
+ if (i == 0) assertOrPanic(mem.eql(u8, s, "hello"));
+ if (i == 1) assertOrPanic(mem.eql(u8, s, "this"));
+ if (i == 2) assertOrPanic(mem.eql(u8, s, "is"));
+ if (i == 3) assertOrPanic(mem.eql(u8, s, "my"));
+ if (i == 4) assertOrPanic(mem.eql(u8, s, "thing"));
+ }
+}
+
+var s_array: [8]Sub = undefined;
+const Sub = struct {
+ b: u8,
+};
+const Str = struct {
+ a: []Sub,
+};
+test "set global var array via slice embedded in struct" {
+ var s = Str{ .a = s_array[0..] };
+
+ s.a[0].b = 1;
+ s.a[1].b = 2;
+ s.a[2].b = 3;
+
+ assertOrPanic(s_array[0].b == 1);
+ assertOrPanic(s_array[1].b == 2);
+ assertOrPanic(s_array[2].b == 3);
+}
+
+test "array literal with specified size" {
+ var array = [2]u8{
+ 1,
+ 2,
+ };
+ assertOrPanic(array[0] == 1);
+ assertOrPanic(array[1] == 2);
+}
+
+test "array child property" {
+ var x: [5]i32 = undefined;
+ assertOrPanic(@typeOf(x).Child == i32);
+}
+
+test "array len property" {
+ var x: [5]i32 = undefined;
+ assertOrPanic(@typeOf(x).len == 5);
+}
+
+test "array len field" {
+ var arr = [4]u8{ 0, 0, 0, 0 };
+ var ptr = &arr;
+ assertOrPanic(arr.len == 4);
+ comptime assertOrPanic(arr.len == 4);
+ assertOrPanic(ptr.len == 4);
+ comptime assertOrPanic(ptr.len == 4);
+}
+
+test "single-item pointer to array indexing and slicing" {
+ testSingleItemPtrArrayIndexSlice();
+ comptime testSingleItemPtrArrayIndexSlice();
+}
+
+fn testSingleItemPtrArrayIndexSlice() void {
+ var array = "aaaa";
+ doSomeMangling(&array);
+ assertOrPanic(mem.eql(u8, "azya", array));
+}
+
+fn doSomeMangling(array: *[4]u8) void {
+ array[1] = 'z';
+ array[2..3][0] = 'y';
+}
+
+test "implicit cast single-item pointer" {
+ testImplicitCastSingleItemPtr();
+ comptime testImplicitCastSingleItemPtr();
+}
+
+fn testImplicitCastSingleItemPtr() void {
+ var byte: u8 = 100;
+ const slice = (*[1]u8)(&byte)[0..];
+ slice[0] += 1;
+ assertOrPanic(byte == 101);
+}
+
+fn testArrayByValAtComptime(b: [2]u8) u8 {
+ return b[0];
+}
+
+test "comptime evalutating function that takes array by value" {
+ const arr = []u8{ 0, 1 };
+ _ = comptime testArrayByValAtComptime(arr);
+ _ = comptime testArrayByValAtComptime(arr);
+}
+
+test "implicit comptime in array type size" {
+ var arr: [plusOne(10)]bool = undefined;
+ assertOrPanic(arr.len == 11);
+}
+
+fn plusOne(x: u32) u32 {
+ return x + 1;
+}
+
+test "array literal as argument to function" {
+ const S = struct {
+ fn entry(two: i32) void {
+ foo([]i32{
+ 1,
+ 2,
+ 3,
+ });
+ foo([]i32{
+ 1,
+ two,
+ 3,
+ });
+ foo2(true, []i32{
+ 1,
+ 2,
+ 3,
+ });
+ foo2(true, []i32{
+ 1,
+ two,
+ 3,
+ });
+ }
+ fn foo(x: []const i32) void {
+ assertOrPanic(x[0] == 1);
+ assertOrPanic(x[1] == 2);
+ assertOrPanic(x[2] == 3);
+ }
+ fn foo2(trash: bool, x: []const i32) void {
+ assertOrPanic(trash);
+ assertOrPanic(x[0] == 1);
+ assertOrPanic(x[1] == 2);
+ assertOrPanic(x[2] == 3);
+ }
+ };
+ S.entry(2);
+ comptime S.entry(2);
+}
+
+test "double nested array to const slice cast in array literal" {
+ const S = struct {
+ fn entry(two: i32) void {
+ const cases = [][]const []const i32{
+ [][]const i32{[]i32{1}},
+ [][]const i32{[]i32{ 2, 3 }},
+ [][]const i32{
+ []i32{4},
+ []i32{ 5, 6, 7 },
+ },
+ };
+ check(cases);
+
+ const cases2 = [][]const i32{
+ []i32{1},
+ []i32{ two, 3 },
+ };
+ assertOrPanic(cases2.len == 2);
+ assertOrPanic(cases2[0].len == 1);
+ assertOrPanic(cases2[0][0] == 1);
+ assertOrPanic(cases2[1].len == 2);
+ assertOrPanic(cases2[1][0] == 2);
+ assertOrPanic(cases2[1][1] == 3);
+
+ const cases3 = [][]const []const i32{
+ [][]const i32{[]i32{1}},
+ [][]const i32{[]i32{ two, 3 }},
+ [][]const i32{
+ []i32{4},
+ []i32{ 5, 6, 7 },
+ },
+ };
+ check(cases3);
+ }
+
+ fn check(cases: []const []const []const i32) void {
+ assertOrPanic(cases.len == 3);
+ assertOrPanic(cases[0].len == 1);
+ assertOrPanic(cases[0][0].len == 1);
+ assertOrPanic(cases[0][0][0] == 1);
+ assertOrPanic(cases[1].len == 1);
+ assertOrPanic(cases[1][0].len == 2);
+ assertOrPanic(cases[1][0][0] == 2);
+ assertOrPanic(cases[1][0][1] == 3);
+ assertOrPanic(cases[2].len == 2);
+ assertOrPanic(cases[2][0].len == 1);
+ assertOrPanic(cases[2][0][0] == 4);
+ assertOrPanic(cases[2][1].len == 3);
+ assertOrPanic(cases[2][1][0] == 5);
+ assertOrPanic(cases[2][1][1] == 6);
+ assertOrPanic(cases[2][1][2] == 7);
+ }
+ };
+ S.entry(2);
+ comptime S.entry(2);
+}
diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig
new file mode 100644
index 0000000000000000000000000000000000000000..48701c58362181a187436e997128208878f42b99
--- /dev/null
+++ b/test/stage1/behavior/asm.zig
@@ -0,0 +1,92 @@
+const config = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+comptime {
+ if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ asm volatile (
+ \\.globl aoeu;
+ \\.type aoeu, @function;
+ \\.set aoeu, derp;
+ );
+ }
+}
+
+test "module level assembly" {
+ if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ assertOrPanic(aoeu() == 1234);
+ }
+}
+
+test "output constraint modifiers" {
+ // This is only testing compilation.
+ var a: u32 = 3;
+ asm volatile (""
+ : [_] "=m,r" (a)
+ :
+ : ""
+ );
+ asm volatile (""
+ : [_] "=r,m" (a)
+ :
+ : ""
+ );
+}
+
+test "alternative constraints" {
+ // Make sure we allow commas as a separator for alternative constraints.
+ var a: u32 = 3;
+ asm volatile (""
+ : [_] "=r,m" (a)
+ : [_] "r,m" (a)
+ : ""
+ );
+}
+
+test "sized integer/float in asm input" {
+ asm volatile (""
+ :
+ : [_] "m" (usize(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i15(-3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (u3(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i3(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (u121(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i121(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (f32(3.17))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (f64(3.17))
+ : ""
+ );
+}
+
+extern fn aoeu() i32;
+
+export fn derp() i32 {
+ return 1234;
+}
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fa3c5f29a603a337e94eb4cfc0d74070e48f6726
--- /dev/null
+++ b/test/stage1/behavior/atomics.zig
@@ -0,0 +1,71 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const builtin = @import("builtin");
+const AtomicRmwOp = builtin.AtomicRmwOp;
+const AtomicOrder = builtin.AtomicOrder;
+
+test "cmpxchg" {
+ var x: i32 = 1234;
+ if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ assertOrPanic(x1 == 1234);
+ } else {
+ @panic("cmpxchg should have failed");
+ }
+
+ while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ assertOrPanic(x1 == 1234);
+ }
+ assertOrPanic(x == 5678);
+
+ assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ assertOrPanic(x == 42);
+}
+
+test "fence" {
+ var x: i32 = 1234;
+ @fence(AtomicOrder.SeqCst);
+ x = 5678;
+}
+
+test "atomicrmw and atomicload" {
+ var data: u8 = 200;
+ testAtomicRmw(&data);
+ assertOrPanic(data == 42);
+ testAtomicLoad(&data);
+}
+
+fn testAtomicRmw(ptr: *u8) void {
+ const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
+ assertOrPanic(prev_value == 200);
+ comptime {
+ var x: i32 = 1234;
+ const y: i32 = 12345;
+ assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
+ assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
+ }
+}
+
+fn testAtomicLoad(ptr: *u8) void {
+ const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
+ assertOrPanic(x == 42);
+}
+
+test "cmpxchg with ptr" {
+ var data1: i32 = 1234;
+ var data2: i32 = 5678;
+ var data3: i32 = 9101;
+ var x: *i32 = &data1;
+ if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ assertOrPanic(x1 == &data1);
+ } else {
+ @panic("cmpxchg should have failed");
+ }
+
+ while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ assertOrPanic(x1 == &data1);
+ }
+ assertOrPanic(x == &data3);
+
+ assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ assertOrPanic(x == &data2);
+}
diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig
new file mode 100644
index 0000000000000000000000000000000000000000..3290688358feac2159cdc205227bdb9ed91c1f72
--- /dev/null
+++ b/test/stage1/behavior/bit_shifting.zig
@@ -0,0 +1,88 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {
+ assertOrPanic(Key == @IntType(false, Key.bit_count));
+ assertOrPanic(Key.bit_count >= mask_bit_count);
+ const ShardKey = @IntType(false, mask_bit_count);
+ const shift_amount = Key.bit_count - ShardKey.bit_count;
+ return struct {
+ const Self = @This();
+ shards: [1 << ShardKey.bit_count]?*Node,
+
+ pub fn create() Self {
+ return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) };
+ }
+
+ fn getShardKey(key: Key) ShardKey {
+ // https://github.com/ziglang/zig/issues/1544
+ // this special case is needed because you can't u32 >> 32.
+ if (ShardKey == u0) return 0;
+
+ // this can be u1 >> u0
+ const shard_key = key >> shift_amount;
+
+ // TODO: https://github.com/ziglang/zig/issues/1544
+ // This cast could be implicit if we teach the compiler that
+ // u32 >> 30 -> u2
+ return @intCast(ShardKey, shard_key);
+ }
+
+ pub fn put(self: *Self, node: *Node) void {
+ const shard_key = Self.getShardKey(node.key);
+ node.next = self.shards[shard_key];
+ self.shards[shard_key] = node;
+ }
+
+ pub fn get(self: *Self, key: Key) ?*Node {
+ const shard_key = Self.getShardKey(key);
+ var maybe_node = self.shards[shard_key];
+ while (maybe_node) |node| : (maybe_node = node.next) {
+ if (node.key == key) return node;
+ }
+ return null;
+ }
+
+ pub const Node = struct {
+ key: Key,
+ value: V,
+ next: ?*Node,
+
+ pub fn init(self: *Node, key: Key, value: V) void {
+ self.key = key;
+ self.value = value;
+ self.next = null;
+ }
+ };
+ };
+}
+
+test "sharded table" {
+ // realistic 16-way sharding
+ testShardedTable(u32, 4, 8);
+
+ testShardedTable(u5, 0, 32); // ShardKey == u0
+ testShardedTable(u5, 2, 32);
+ testShardedTable(u5, 5, 32);
+
+ testShardedTable(u1, 0, 2);
+ testShardedTable(u1, 1, 2); // this does u1 >> u0
+
+ testShardedTable(u0, 0, 1);
+}
+fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void {
+ const Table = ShardedTable(Key, mask_bit_count, void);
+
+ var table = Table.create();
+ var node_buffer: [node_count]Table.Node = undefined;
+ for (node_buffer) |*node, i| {
+ const key = @intCast(Key, i);
+ assertOrPanic(table.get(key) == null);
+ node.init(key, {});
+ table.put(node);
+ }
+
+ for (node_buffer) |*node, i| {
+ assertOrPanic(table.get(@intCast(Key, i)) == node);
+ }
+}
diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig
new file mode 100644
index 0000000000000000000000000000000000000000..19030255e4f71fe2330e0027a194c8e815ebcf20
--- /dev/null
+++ b/test/stage1/behavior/bitcast.zig
@@ -0,0 +1,36 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const maxInt = std.math.maxInt;
+
+test "@bitCast i32 -> u32" {
+ testBitCast_i32_u32();
+ comptime testBitCast_i32_u32();
+}
+
+fn testBitCast_i32_u32() void {
+ assertOrPanic(conv(-1) == maxInt(u32));
+ assertOrPanic(conv2(maxInt(u32)) == -1);
+}
+
+fn conv(x: i32) u32 {
+ return @bitCast(u32, x);
+}
+fn conv2(x: u32) i32 {
+ return @bitCast(i32, x);
+}
+
+test "@bitCast extern enum to its integer type" {
+ const SOCK = extern enum {
+ A,
+ B,
+
+ fn testBitCastExternEnum() void {
+ var SOCK_DGRAM = @This().B;
+ var sock_dgram = @bitCast(c_int, SOCK_DGRAM);
+ assertOrPanic(sock_dgram == 1);
+ }
+ };
+
+ SOCK.testBitCastExternEnum();
+ comptime SOCK.testBitCastExternEnum();
+}
diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig
new file mode 100644
index 0000000000000000000000000000000000000000..97787ace84f20f45d2b01d1f5239ae773d2970a2
--- /dev/null
+++ b/test/stage1/behavior/bitreverse.zig
@@ -0,0 +1,81 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const minInt = std.math.minInt;
+
+test "@bitreverse" {
+ comptime testBitReverse();
+ testBitReverse();
+}
+
+fn testBitReverse() void {
+ // using comptime_ints, unsigned
+ assertOrPanic(@bitreverse(u0, 0) == 0);
+ assertOrPanic(@bitreverse(u5, 0x12) == 0x9);
+ assertOrPanic(@bitreverse(u8, 0x12) == 0x48);
+ assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48);
+ assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48);
+ assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48);
+ assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48);
+ assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48);
+ assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48);
+ assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
+ assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+ // using runtime uints, unsigned
+ var num0: u0 = 0;
+ assertOrPanic(@bitreverse(u0, num0) == 0);
+ var num5: u5 = 0x12;
+ assertOrPanic(@bitreverse(u5, num5) == 0x9);
+ var num8: u8 = 0x12;
+ assertOrPanic(@bitreverse(u8, num8) == 0x48);
+ var num16: u16 = 0x1234;
+ assertOrPanic(@bitreverse(u16, num16) == 0x2c48);
+ var num24: u24 = 0x123456;
+ assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48);
+ var num32: u32 = 0x12345678;
+ assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48);
+ var num40: u40 = 0x123456789a;
+ assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48);
+ var num48: u48 = 0x123456789abc;
+ assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48);
+ var num56: u56 = 0x123456789abcde;
+ assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48);
+ var num64: u64 = 0x123456789abcdef1;
+ assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48);
+ var num128: u128 = 0x123456789abcdef11121314151617181;
+ assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+ // using comptime_ints, signed, positive
+ assertOrPanic(@bitreverse(i0, 0) == 0);
+ assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49)));
+ assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48)));
+ assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48)));
+ assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48)));
+ assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48)));
+ assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48)));
+
+ // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
+ var neg5: i5 = minInt(i5) + 1;
+ assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5));
+ var neg8: i8 = -18;
+ assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8));
+ var neg16: i16 = -32694;
+ assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16));
+ var neg24: i24 = -6773785;
+ assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24));
+ var neg32: i32 = -16773785;
+ assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32));
+ var neg40: i40 = minInt(i40) + 12345;
+ assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40));
+ var neg48: i48 = minInt(i48) + 12345;
+ assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48));
+ var neg56: i56 = minInt(i56) + 12345;
+ assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56));
+ var neg64: i64 = minInt(i64) + 12345;
+ assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64));
+ var neg128: i128 = minInt(i128) + 12345;
+ assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128));
+}
diff --git a/test/stage1/behavior/bool.zig b/test/stage1/behavior/bool.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2d7241526f429e138e577a22c589a849eb1926d4
--- /dev/null
+++ b/test/stage1/behavior/bool.zig
@@ -0,0 +1,35 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "bool literals" {
+ assertOrPanic(true);
+ assertOrPanic(!false);
+}
+
+test "cast bool to int" {
+ const t = true;
+ const f = false;
+ assertOrPanic(@boolToInt(t) == u32(1));
+ assertOrPanic(@boolToInt(f) == u32(0));
+ nonConstCastBoolToInt(t, f);
+}
+
+fn nonConstCastBoolToInt(t: bool, f: bool) void {
+ assertOrPanic(@boolToInt(t) == u32(1));
+ assertOrPanic(@boolToInt(f) == u32(0));
+}
+
+test "bool cmp" {
+ assertOrPanic(testBoolCmp(true, false) == false);
+}
+fn testBoolCmp(a: bool, b: bool) bool {
+ return a == b;
+}
+
+const global_f = false;
+const global_t = true;
+const not_global_f = !global_f;
+const not_global_t = !global_t;
+test "compile time bool not" {
+ assertOrPanic(not_global_f);
+ assertOrPanic(!not_global_t);
+}
diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig
new file mode 100644
index 0000000000000000000000000000000000000000..8084538e03c02f5a6621b51ed8b0c52666cefaac
--- /dev/null
+++ b/test/stage1/behavior/bswap.zig
@@ -0,0 +1,32 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "@bswap" {
+ comptime testByteSwap();
+ testByteSwap();
+}
+
+fn testByteSwap() void {
+ assertOrPanic(@bswap(u0, 0) == 0);
+ assertOrPanic(@bswap(u8, 0x12) == 0x12);
+ assertOrPanic(@bswap(u16, 0x1234) == 0x3412);
+ assertOrPanic(@bswap(u24, 0x123456) == 0x563412);
+ assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412);
+ assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412);
+ assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
+ assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
+ assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
+ assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
+
+ assertOrPanic(@bswap(i0, 0) == 0);
+ assertOrPanic(@bswap(i8, -50) == -50);
+ assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
+ assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
+ assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
+ assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
+ assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
+ assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
+ assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
+ assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
+ @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
+}
diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig
new file mode 100644
index 0000000000000000000000000000000000000000..69a7e70f7dbb3b424c0740300703b12654acc807
--- /dev/null
+++ b/test/stage1/behavior/bugs/1076.zig
@@ -0,0 +1,16 @@
+const std = @import("std");
+const mem = std.mem;
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "comptime code should not modify constant data" {
+ testCastPtrOfArrayToSliceAndPtr();
+ comptime testCastPtrOfArrayToSliceAndPtr();
+}
+
+fn testCastPtrOfArrayToSliceAndPtr() void {
+ var array = "aoeu";
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ assertOrPanic(mem.eql(u8, array[0..], "boeu"));
+}
+
diff --git a/test/stage1/behavior/bugs/1111.zig b/test/stage1/behavior/bugs/1111.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f62107f9a3311864f7861e88713fc2b59a1f6297
--- /dev/null
+++ b/test/stage1/behavior/bugs/1111.zig
@@ -0,0 +1,12 @@
+const Foo = extern enum {
+ Bar = -1,
+};
+
+test "issue 1111 fixed" {
+ const v = Foo.Bar;
+
+ switch (v) {
+ Foo.Bar => return,
+ else => return,
+ }
+}
diff --git a/test/stage1/behavior/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a83e7653e27ac6604a725fb6fbf8b898434145d5
--- /dev/null
+++ b/test/stage1/behavior/bugs/1277.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+const S = struct {
+ f: ?fn () i32,
+};
+
+const s = S{ .f = f };
+
+fn f() i32 {
+ return 1234;
+}
+
+test "don't emit an LLVM global for a const function when it's in an optional in a struct" {
+ std.debug.assertOrPanic(s.f.?() == 1234);
+}
diff --git a/test/stage1/behavior/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2e67f4473fecd47e54015be00e94350dfce83101
--- /dev/null
+++ b/test/stage1/behavior/bugs/1322.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+const B = union(enum) {
+ c: C,
+ None,
+};
+
+const A = struct {
+ b: B,
+};
+
+const C = struct {};
+
+test "tagged union with all void fields but a meaningful tag" {
+ var a: A = A{ .b = B{ .c = C{} } };
+ std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c);
+ a = A{ .b = B.None };
+ std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None);
+}
diff --git a/test/stage1/behavior/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2d452da15610e28f13c2a5d9811791435f0b757b
--- /dev/null
+++ b/test/stage1/behavior/bugs/1381.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+
+const B = union(enum) {
+ D: u8,
+ E: u16,
+};
+
+const A = union(enum) {
+ B: B,
+ C: u8,
+};
+
+test "union that needs padding bytes inside an array" {
+ var as = []A{
+ A{ .B = B{ .D = 1 } },
+ A{ .B = B{ .D = 1 } },
+ };
+
+ const a = as[0].B;
+ std.debug.assertOrPanic(a.D == 1);
+}
diff --git a/test/stage1/behavior/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fbc932781ab9662e8820a0621940306cf0dfbe9e
--- /dev/null
+++ b/test/stage1/behavior/bugs/1421.zig
@@ -0,0 +1,14 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const assertOrPanic = std.debug.assertOrPanic;
+
+const S = struct {
+ fn method() builtin.TypeInfo {
+ return @typeInfo(S);
+ }
+};
+
+test "functions with return type required to be comptime are generic" {
+ const ti = S.method();
+ assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct);
+}
diff --git a/test/stage1/behavior/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e9dfd5d2ce031b532534d0b7ff6196a92f748ec5
--- /dev/null
+++ b/test/stage1/behavior/bugs/1442.zig
@@ -0,0 +1,11 @@
+const std = @import("std");
+
+const Union = union(enum) {
+ Text: []const u8,
+ Color: u32,
+};
+
+test "const error union field alignment" {
+ var union_or_err: anyerror!Union = Union{ .Color = 1234 };
+ std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234);
+}
diff --git a/test/stage1/behavior/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig
new file mode 100644
index 0000000000000000000000000000000000000000..0483e3828cde39dc0d245c4aa7690ee3ceb2c5ac
--- /dev/null
+++ b/test/stage1/behavior/bugs/1486.zig
@@ -0,0 +1,11 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const ptr = &global;
+var global: u64 = 123;
+
+test "constant pointer to global variable causes runtime load" {
+ global = 1234;
+ assertOrPanic(&global == ptr);
+ assertOrPanic(ptr.* == 1234);
+}
+
diff --git a/test/stage1/behavior/bugs/394.zig b/test/stage1/behavior/bugs/394.zig
new file mode 100644
index 0000000000000000000000000000000000000000..766ad9e15761335b3ce42fed34ba788349deddba
--- /dev/null
+++ b/test/stage1/behavior/bugs/394.zig
@@ -0,0 +1,18 @@
+const E = union(enum) {
+ A: [9]u8,
+ B: u64,
+};
+const S = struct {
+ x: u8,
+ y: E,
+};
+
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "bug 394 fixed" {
+ const x = S{
+ .x = 3,
+ .y = E{ .B = 1 },
+ };
+ assertOrPanic(x.x == 3);
+}
diff --git a/test/stage1/behavior/bugs/655.zig b/test/stage1/behavior/bugs/655.zig
new file mode 100644
index 0000000000000000000000000000000000000000..67ba6a231f33d4ffa50f63e77b86c5bee7cd947f
--- /dev/null
+++ b/test/stage1/behavior/bugs/655.zig
@@ -0,0 +1,12 @@
+const std = @import("std");
+const other_file = @import("655_other_file.zig");
+
+test "function with *const parameter with type dereferenced by namespace" {
+ const x: other_file.Integer = 1234;
+ comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer);
+ foo(&x);
+}
+
+fn foo(x: *const other_file.Integer) void {
+ std.debug.assertOrPanic(x.* == 1234);
+}
diff --git a/test/stage1/behavior/bugs/655_other_file.zig b/test/stage1/behavior/bugs/655_other_file.zig
new file mode 100644
index 0000000000000000000000000000000000000000..df1df44955229dbdab1b04022e754c670b6714c3
--- /dev/null
+++ b/test/stage1/behavior/bugs/655_other_file.zig
@@ -0,0 +1 @@
+pub const Integer = u32;
diff --git a/test/stage1/behavior/bugs/656.zig b/test/stage1/behavior/bugs/656.zig
new file mode 100644
index 0000000000000000000000000000000000000000..cb37fe67fe84a4dda7e46952ac4200d989fa3791
--- /dev/null
+++ b/test/stage1/behavior/bugs/656.zig
@@ -0,0 +1,31 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const PrefixOp = union(enum) {
+ Return,
+ AddrOf: Value,
+};
+
+const Value = struct {
+ align_expr: ?u32,
+};
+
+test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
+ foo(false, true);
+}
+
+fn foo(a: bool, b: bool) void {
+ var prefix_op = PrefixOp{
+ .AddrOf = Value{ .align_expr = 1234 },
+ };
+ if (a) {} else {
+ switch (prefix_op) {
+ PrefixOp.AddrOf => |addr_of_info| {
+ if (b) {}
+ if (addr_of_info.align_expr) |align_expr| {
+ assertOrPanic(align_expr == 1234);
+ }
+ },
+ PrefixOp.Return => {},
+ }
+ }
+}
diff --git a/test/stage1/behavior/bugs/726.zig b/test/stage1/behavior/bugs/726.zig
new file mode 100644
index 0000000000000000000000000000000000000000..ce20480c63325f23c4ae2bdb5218807887d00f58
--- /dev/null
+++ b/test/stage1/behavior/bugs/726.zig
@@ -0,0 +1,16 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@ptrCast from const to nullable" {
+ const c: u8 = 4;
+ var x: ?*const u8 = @ptrCast(?*const u8, &c);
+ assertOrPanic(x.?.* == 4);
+}
+
+test "@ptrCast from var in empty struct to nullable" {
+ const container = struct {
+ var c: u8 = 4;
+ };
+ var x: ?*const u8 = @ptrCast(?*const u8, &container.c);
+ assertOrPanic(x.?.* == 4);
+}
+
diff --git a/test/stage1/behavior/bugs/828.zig b/test/stage1/behavior/bugs/828.zig
new file mode 100644
index 0000000000000000000000000000000000000000..50ae0fd279fdcf52c46f016ee2d274928c0d5231
--- /dev/null
+++ b/test/stage1/behavior/bugs/828.zig
@@ -0,0 +1,33 @@
+const CountBy = struct {
+ a: usize,
+
+ const One = CountBy{ .a = 1 };
+
+ pub fn counter(self: *const CountBy) Counter {
+ return Counter{ .i = 0 };
+ }
+};
+
+const Counter = struct {
+ i: usize,
+
+ pub fn count(self: *Counter) bool {
+ self.i += 1;
+ return self.i <= 10;
+ }
+};
+
+fn constCount(comptime cb: *const CountBy, comptime unused: u32) void {
+ comptime {
+ var cnt = cb.counter();
+ if (cnt.i != 0) @compileError("Counter instance reused!");
+ while (cnt.count()) {}
+ }
+}
+
+test "comptime struct return should not return the same instance" {
+ //the first parameter must be passed by reference to trigger the bug
+ //a second parameter is required to trigger the bug
+ const ValA = constCount(&CountBy.One, 12);
+ const ValB = constCount(&CountBy.One, 15);
+}
diff --git a/test/stage1/behavior/bugs/920.zig b/test/stage1/behavior/bugs/920.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e29c5c4acf5a31a97ef06afdf1c5c4c6ececc83b
--- /dev/null
+++ b/test/stage1/behavior/bugs/920.zig
@@ -0,0 +1,65 @@
+const std = @import("std");
+const math = std.math;
+const Random = std.rand.Random;
+
+const ZigTable = struct {
+ r: f64,
+ x: [257]f64,
+ f: [257]f64,
+
+ pdf: fn (f64) f64,
+ is_symmetric: bool,
+ zero_case: fn (*Random, f64) f64,
+};
+
+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 {
+ var tables: ZigTable = undefined;
+
+ tables.is_symmetric = is_symmetric;
+ tables.r = r;
+ tables.pdf = f;
+ tables.zero_case = zero_case;
+
+ tables.x[0] = v / f(r);
+ tables.x[1] = r;
+
+ for (tables.x[2..256]) |*entry, i| {
+ const last = tables.x[2 + i - 1];
+ entry.* = f_inv(v / last + f(last));
+ }
+ tables.x[256] = 0;
+
+ for (tables.f[0..]) |*entry, i| {
+ entry.* = f(tables.x[i]);
+ }
+
+ return tables;
+}
+
+const norm_r = 3.6541528853610088;
+const norm_v = 0.00492867323399;
+
+fn norm_f(x: f64) f64 {
+ return math.exp(-x * x / 2.0);
+}
+fn norm_f_inv(y: f64) f64 {
+ return math.sqrt(-2.0 * math.ln(y));
+}
+fn norm_zero_case(random: *Random, u: f64) f64 {
+ return 0.0;
+}
+
+const NormalDist = blk: {
+ @setEvalBranchQuota(30000);
+ break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
+};
+
+test "bug 920 fixed" {
+ const NormalDist1 = blk: {
+ break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
+ };
+
+ for (NormalDist1.f) |_, i| {
+ std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]);
+ }
+}
diff --git a/test/stage1/behavior/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig
new file mode 100644
index 0000000000000000000000000000000000000000..14ee212ce07cb45cfcfcd27b0202e67d4ca808df
--- /dev/null
+++ b/test/stage1/behavior/byval_arg_var.zig
@@ -0,0 +1,27 @@
+const std = @import("std");
+
+var result: []const u8 = "wrong";
+
+test "pass string literal byvalue to a generic var param" {
+ start();
+ blowUpStack(10);
+
+ std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal"));
+}
+
+fn start() void {
+ foo("string literal");
+}
+
+fn foo(x: var) void {
+ bar(x);
+}
+
+fn bar(x: var) void {
+ result = x;
+}
+
+fn blowUpStack(x: u32) void {
+ if (x == 0) return;
+ blowUpStack(x - 1);
+}
diff --git a/test/stage1/behavior/cancel.zig b/test/stage1/behavior/cancel.zig
new file mode 100644
index 0000000000000000000000000000000000000000..863da4bdb831b9015d67a9fcf5284733b9c33e91
--- /dev/null
+++ b/test/stage1/behavior/cancel.zig
@@ -0,0 +1,92 @@
+const std = @import("std");
+
+var defer_f1: bool = false;
+var defer_f2: bool = false;
+var defer_f3: bool = false;
+
+test "cancel forwards" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ const p = async<&da.allocator> f1() catch unreachable;
+ cancel p;
+ std.debug.assertOrPanic(defer_f1);
+ std.debug.assertOrPanic(defer_f2);
+ std.debug.assertOrPanic(defer_f3);
+}
+
+async fn f1() void {
+ defer {
+ defer_f1 = true;
+ }
+ await (async f2() catch unreachable);
+}
+
+async fn f2() void {
+ defer {
+ defer_f2 = true;
+ }
+ await (async f3() catch unreachable);
+}
+
+async fn f3() void {
+ defer {
+ defer_f3 = true;
+ }
+ suspend;
+}
+
+var defer_b1: bool = false;
+var defer_b2: bool = false;
+var defer_b3: bool = false;
+var defer_b4: bool = false;
+
+test "cancel backwards" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ const p = async<&da.allocator> b1() catch unreachable;
+ cancel p;
+ std.debug.assertOrPanic(defer_b1);
+ std.debug.assertOrPanic(defer_b2);
+ std.debug.assertOrPanic(defer_b3);
+ std.debug.assertOrPanic(defer_b4);
+}
+
+async fn b1() void {
+ defer {
+ defer_b1 = true;
+ }
+ await (async b2() catch unreachable);
+}
+
+var b4_handle: promise = undefined;
+
+async fn b2() void {
+ const b3_handle = async b3() catch unreachable;
+ resume b4_handle;
+ cancel b4_handle;
+ defer {
+ defer_b2 = true;
+ }
+ const value = await b3_handle;
+ @panic("unreachable");
+}
+
+async fn b3() i32 {
+ defer {
+ defer_b3 = true;
+ }
+ await (async b4() catch unreachable);
+ return 1234;
+}
+
+async fn b4() void {
+ defer {
+ defer_b4 = true;
+ }
+ suspend {
+ b4_handle = @handle();
+ }
+ suspend;
+}
diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig
new file mode 100644
index 0000000000000000000000000000000000000000..61ddcd81355653c60e45c6ffdd401051a8b7c033
--- /dev/null
+++ b/test/stage1/behavior/cast.zig
@@ -0,0 +1,473 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const mem = std.mem;
+const maxInt = std.math.maxInt;
+
+test "int to ptr cast" {
+ const x = usize(13);
+ const y = @intToPtr(*u8, x);
+ const z = @ptrToInt(y);
+ assertOrPanic(z == 13);
+}
+
+test "integer literal to pointer cast" {
+ const vga_mem = @intToPtr(*u16, 0xB8000);
+ assertOrPanic(@ptrToInt(vga_mem) == 0xB8000);
+}
+
+test "pointer reinterpret const float to int" {
+ const float: f64 = 5.99999999999994648725e-01;
+ const float_ptr = &float;
+ const int_ptr = @ptrCast(*const i32, float_ptr);
+ const int_val = int_ptr.*;
+ assertOrPanic(int_val == 858993411);
+}
+
+test "implicitly cast indirect pointer to maybe-indirect pointer" {
+ const S = struct {
+ const Self = @This();
+ x: u8,
+ fn constConst(p: *const *const Self) u8 {
+ return p.*.x;
+ }
+ fn maybeConstConst(p: ?*const *const Self) u8 {
+ return p.?.*.x;
+ }
+ fn constConstConst(p: *const *const *const Self) u8 {
+ return p.*.*.x;
+ }
+ fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
+ return p.?.*.*.x;
+ }
+ };
+ const s = S{ .x = 42 };
+ const p = &s;
+ const q = &p;
+ const r = &q;
+ assertOrPanic(42 == S.constConst(q));
+ assertOrPanic(42 == S.maybeConstConst(q));
+ assertOrPanic(42 == S.constConstConst(r));
+ assertOrPanic(42 == S.maybeConstConstConst(r));
+}
+
+test "explicit cast from integer to error type" {
+ testCastIntToErr(error.ItBroke);
+ comptime testCastIntToErr(error.ItBroke);
+}
+fn testCastIntToErr(err: anyerror) void {
+ const x = @errorToInt(err);
+ const y = @intToError(x);
+ assertOrPanic(error.ItBroke == y);
+}
+
+test "peer resolve arrays of different size to const slice" {
+ assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+ assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
+ comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+ comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
+}
+fn boolToStr(b: bool) []const u8 {
+ return if (b) "true" else "false";
+}
+
+test "peer resolve array and const slice" {
+ testPeerResolveArrayConstSlice(true);
+ comptime testPeerResolveArrayConstSlice(true);
+}
+fn testPeerResolveArrayConstSlice(b: bool) void {
+ const value1 = if (b) "aoeu" else ([]const u8)("zz");
+ const value2 = if (b) ([]const u8)("zz") else "aoeu";
+ assertOrPanic(mem.eql(u8, value1, "aoeu"));
+ assertOrPanic(mem.eql(u8, value2, "zz"));
+}
+
+test "implicitly cast from T to anyerror!?T" {
+ castToOptionalTypeError(1);
+ comptime castToOptionalTypeError(1);
+}
+
+const A = struct {
+ a: i32,
+};
+fn castToOptionalTypeError(z: i32) void {
+ const x = i32(1);
+ const y: anyerror!?i32 = x;
+ assertOrPanic((try y).? == 1);
+
+ const f = z;
+ const g: anyerror!?i32 = f;
+
+ const a = A{ .a = z };
+ const b: anyerror!?A = a;
+ assertOrPanic((b catch unreachable).?.a == 1);
+}
+
+test "implicitly cast from int to anyerror!?T" {
+ implicitIntLitToOptional();
+ comptime implicitIntLitToOptional();
+}
+fn implicitIntLitToOptional() void {
+ const f: ?i32 = 1;
+ const g: anyerror!?i32 = 1;
+}
+
+test "return null from fn() anyerror!?&T" {
+ const a = returnNullFromOptionalTypeErrorRef();
+ const b = returnNullLitFromOptionalTypeErrorRef();
+ assertOrPanic((try a) == null and (try b) == null);
+}
+fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
+ const a: ?*A = null;
+ return a;
+}
+fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
+ return null;
+}
+
+test "peer type resolution: ?T and T" {
+ assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+ assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
+ comptime {
+ assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+ assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
+ }
+}
+fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
+ if (c) {
+ return if (b) null else usize(0);
+ }
+
+ return usize(3);
+}
+
+test "peer type resolution: [0]u8 and []const u8" {
+ assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+ comptime {
+ assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+ }
+}
+fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
+ if (a) {
+ return []const u8{};
+ }
+
+ return slice[0..1];
+}
+
+test "implicitly cast from [N]T to ?[]const T" {
+ assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
+ comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
+}
+
+fn castToOptionalSlice() ?[]const u8 {
+ return "hi";
+}
+
+test "implicitly cast from [0]T to anyerror![]T" {
+ testCastZeroArrayToErrSliceMut();
+ comptime testCastZeroArrayToErrSliceMut();
+}
+
+fn testCastZeroArrayToErrSliceMut() void {
+ assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0);
+}
+
+fn gimmeErrOrSlice() anyerror![]u8 {
+ return []u8{};
+}
+
+test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
+ {
+ var data = "hi";
+ const slice = data[0..];
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ }
+ comptime {
+ var data = "hi";
+ const slice = data[0..];
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ }
+}
+fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
+ if (a) {
+ return []u8{};
+ }
+
+ return slice[0..1];
+}
+
+test "resolve undefined with integer" {
+ testResolveUndefWithInt(true, 1234);
+ comptime testResolveUndefWithInt(true, 1234);
+}
+fn testResolveUndefWithInt(b: bool, x: i32) void {
+ const value = if (b) x else undefined;
+ if (b) {
+ assertOrPanic(value == x);
+ }
+}
+
+test "implicit cast from &const [N]T to []const T" {
+ testCastConstArrayRefToConstSlice();
+ comptime testCastConstArrayRefToConstSlice();
+}
+
+fn testCastConstArrayRefToConstSlice() void {
+ const blah = "aoeu";
+ const const_array_ref = &blah;
+ assertOrPanic(@typeOf(const_array_ref) == *const [4]u8);
+ const slice: []const u8 = const_array_ref;
+ assertOrPanic(mem.eql(u8, slice, "aoeu"));
+}
+
+test "peer type resolution: error and [N]T" {
+ // TODO: implicit error!T to error!U where T can implicitly cast to U
+ //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+ //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+ assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+ comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+}
+
+//fn testPeerErrorAndArray(x: u8) error![]const u8 {
+// return switch (x) {
+// 0x00 => "OK",
+// else => error.BadValue,
+// };
+//}
+fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
+ return switch (x) {
+ 0x00 => "OK",
+ 0x01 => "OKK",
+ else => error.BadValue,
+ };
+}
+
+test "@floatToInt" {
+ testFloatToInts();
+ comptime testFloatToInts();
+}
+
+fn testFloatToInts() void {
+ const x = i32(1e4);
+ assertOrPanic(x == 10000);
+ const y = @floatToInt(i32, f32(1e4));
+ assertOrPanic(y == 10000);
+ expectFloatToInt(f16, 255.1, u8, 255);
+ expectFloatToInt(f16, 127.2, i8, 127);
+ expectFloatToInt(f16, -128.2, i8, -128);
+ expectFloatToInt(f32, 255.1, u8, 255);
+ expectFloatToInt(f32, 127.2, i8, 127);
+ expectFloatToInt(f32, -128.2, i8, -128);
+ expectFloatToInt(comptime_int, 1234, i16, 1234);
+}
+
+fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
+ assertOrPanic(@floatToInt(I, f) == i);
+}
+
+test "cast u128 to f128 and back" {
+ comptime testCast128();
+ testCast128();
+}
+
+fn testCast128() void {
+ assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
+}
+
+fn cast128Int(x: f128) u128 {
+ return @bitCast(u128, x);
+}
+
+fn cast128Float(x: u128) f128 {
+ return @bitCast(f128, x);
+}
+
+test "const slice widen cast" {
+ const bytes align(4) = []u8{
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ };
+
+ const u32_value = @bytesToSlice(u32, bytes[0..])[0];
+ assertOrPanic(u32_value == 0x12121212);
+
+ assertOrPanic(@bitCast(u32, bytes) == 0x12121212);
+}
+
+test "single-item pointer of array to slice and to unknown length pointer" {
+ testCastPtrOfArrayToSliceAndPtr();
+ comptime testCastPtrOfArrayToSliceAndPtr();
+}
+
+fn testCastPtrOfArrayToSliceAndPtr() void {
+ var array = "aoeu";
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ assertOrPanic(mem.eql(u8, array[0..], "boeu"));
+ const y: []u8 = &array;
+ y[0] += 1;
+ assertOrPanic(mem.eql(u8, array[0..], "coeu"));
+}
+
+test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
+ const window_name = [1][*]const u8{c"window name"};
+ const x: [*]const ?[*]const u8 = &window_name;
+ assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
+}
+
+test "@intCast comptime_int" {
+ const result = @intCast(i32, 1234);
+ assertOrPanic(@typeOf(result) == i32);
+ assertOrPanic(result == 1234);
+}
+
+test "@floatCast comptime_int and comptime_float" {
+ {
+ const result = @floatCast(f16, 1234);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
+ }
+ {
+ const result = @floatCast(f16, 1234.0);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
+ }
+ {
+ const result = @floatCast(f32, 1234);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
+ }
+ {
+ const result = @floatCast(f32, 1234.0);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
+ }
+}
+
+test "comptime_int @intToFloat" {
+ {
+ const result = @intToFloat(f16, 1234);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
+ }
+ {
+ const result = @intToFloat(f32, 1234);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
+ }
+}
+
+test "@bytesToSlice keeps pointer alignment" {
+ var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
+ const numbers = @bytesToSlice(u32, bytes[0..]);
+ comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
+}
+
+test "@intCast i32 to u7" {
+ var x: u128 = maxInt(u128);
+ var y: i32 = 120;
+ var z = x >> @intCast(u7, y);
+ assertOrPanic(z == 0xff);
+}
+
+test "implicit cast undefined to optional" {
+ assertOrPanic(MakeType(void).getNull() == null);
+ assertOrPanic(MakeType(void).getNonNull() != null);
+}
+
+fn MakeType(comptime T: type) type {
+ return struct {
+ fn getNull() ?T {
+ return null;
+ }
+
+ fn getNonNull() ?T {
+ return T(undefined);
+ }
+ };
+}
+
+test "implicit cast from *[N]T to ?[*]T" {
+ var x: ?[*]u16 = null;
+ var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
+
+ x = &y;
+ assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
+ x.?[0] = 8;
+ y[3] = 6;
+ assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
+}
+
+test "implicit cast from *T to ?*c_void" {
+ var a: u8 = 1;
+ incrementVoidPtrValue(&a);
+ std.debug.assertOrPanic(a == 2);
+}
+
+fn incrementVoidPtrValue(value: ?*c_void) void {
+ @ptrCast(*u8, value.?).* += 1;
+}
+
+test "implicit cast from [*]T to ?*c_void" {
+ var a = []u8{ 3, 2, 1 };
+ incrementVoidPtrArray(a[0..].ptr, 3);
+ assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
+}
+
+fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
+ var n: usize = 0;
+ while (n < len) : (n += 1) {
+ @ptrCast([*]u8, array.?)[n] += 1;
+ }
+}
+
+test "*usize to *void" {
+ var i = usize(0);
+ var v = @ptrCast(*void, &i);
+ v.* = {};
+}
+
+test "compile time int to ptr of function" {
+ foobar(FUNCTION_CONSTANT);
+}
+
+pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
+pub const PFN_void = extern fn (*c_void) void;
+
+fn foobar(func: PFN_void) void {
+ std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize));
+}
+
+test "implicit ptr to *c_void" {
+ var a: u32 = 1;
+ var ptr: *c_void = &a;
+ var b: *u32 = @ptrCast(*u32, ptr);
+ assertOrPanic(b.* == 1);
+ var ptr2: ?*c_void = &a;
+ var c: *u32 = @ptrCast(*u32, ptr2.?);
+ assertOrPanic(c.* == 1);
+}
+
+test "@intCast to comptime_int" {
+ assertOrPanic(@intCast(comptime_int, 0) == 0);
+}
+
+test "implicit cast comptime numbers to any type when the value fits" {
+ const a: u64 = 255;
+ var b: u8 = a;
+ assertOrPanic(b == 255);
+}
+
+test "@intToEnum passed a comptime_int to an enum with one item" {
+ const E = enum {
+ A,
+ };
+ const x = @intToEnum(E, 0);
+ assertOrPanic(x == E.A);
+}
diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig
new file mode 100644
index 0000000000000000000000000000000000000000..5b9b70a558017b04cc2a0e805963bb5c05ae445e
--- /dev/null
+++ b/test/stage1/behavior/const_slice_child.zig
@@ -0,0 +1,45 @@
+const debug = @import("std").debug;
+const assertOrPanic = debug.assertOrPanic;
+
+var argv: [*]const [*]const u8 = undefined;
+
+test "const slice child" {
+ const strs = ([][*]const u8){
+ c"one",
+ c"two",
+ c"three",
+ };
+ // TODO this should implicitly cast
+ argv = @ptrCast([*]const [*]const u8, &strs);
+ bar(strs.len);
+}
+
+fn foo(args: [][]const u8) void {
+ assertOrPanic(args.len == 3);
+ assertOrPanic(streql(args[0], "one"));
+ assertOrPanic(streql(args[1], "two"));
+ assertOrPanic(streql(args[2], "three"));
+}
+
+fn bar(argc: usize) void {
+ const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable;
+ for (args) |_, i| {
+ const ptr = argv[i];
+ args[i] = ptr[0..strlen(ptr)];
+ }
+ foo(args);
+}
+
+fn strlen(ptr: [*]const u8) usize {
+ var count: usize = 0;
+ while (ptr[count] != 0) : (count += 1) {}
+ return count;
+}
+
+fn streql(a: []const u8, b: []const u8) bool {
+ if (a.len != b.len) return false;
+ for (a) |item, index| {
+ if (b[index] != item) return false;
+ }
+ return true;
+}
diff --git a/test/stage1/behavior/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6ca2a301eca5218568e8f9f375f026351a9ac708
--- /dev/null
+++ b/test/stage1/behavior/coroutine_await_struct.zig
@@ -0,0 +1,47 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const assertOrPanic = std.debug.assertOrPanic;
+
+const Foo = struct {
+ x: i32,
+};
+
+var await_a_promise: promise = undefined;
+var await_final_result = Foo{ .x = 0 };
+
+test "coroutine await struct" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ await_seq('a');
+ const p = async<&da.allocator> await_amain() catch unreachable;
+ await_seq('f');
+ resume await_a_promise;
+ await_seq('i');
+ assertOrPanic(await_final_result.x == 1234);
+ assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
+}
+async fn await_amain() void {
+ await_seq('b');
+ const p = async await_another() catch unreachable;
+ await_seq('e');
+ await_final_result = await p;
+ await_seq('h');
+}
+async fn await_another() Foo {
+ await_seq('c');
+ suspend {
+ await_seq('d');
+ await_a_promise = @handle();
+ }
+ await_seq('g');
+ return Foo{ .x = 1234 };
+}
+
+var await_points = []u8{0} ** "abcdefghi".len;
+var await_seq_index: usize = 0;
+
+fn await_seq(c: u8) void {
+ await_points[await_seq_index] = c;
+ await_seq_index += 1;
+}
diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a2327c506011df0892e72279bb8b5f2fc2c86b19
--- /dev/null
+++ b/test/stage1/behavior/coroutines.zig
@@ -0,0 +1,258 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const assertOrPanic = std.debug.assertOrPanic;
+
+var x: i32 = 1;
+
+test "create a coroutine and cancel it" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ const p = try async<&da.allocator> simpleAsyncFn();
+ comptime assertOrPanic(@typeOf(p) == promise->void);
+ cancel p;
+ assertOrPanic(x == 2);
+}
+async fn simpleAsyncFn() void {
+ x += 1;
+ suspend;
+ x += 1;
+}
+
+test "coroutine suspend, resume, cancel" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ seq('a');
+ const p = try async<&da.allocator> testAsyncSeq();
+ seq('c');
+ resume p;
+ seq('f');
+ cancel p;
+ seq('g');
+
+ assertOrPanic(std.mem.eql(u8, points, "abcdefg"));
+}
+async fn testAsyncSeq() void {
+ defer seq('e');
+
+ seq('b');
+ suspend;
+ seq('d');
+}
+var points = []u8{0} ** "abcdefg".len;
+var index: usize = 0;
+
+fn seq(c: u8) void {
+ points[index] = c;
+ index += 1;
+}
+
+test "coroutine suspend with block" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ const p = try async<&da.allocator> testSuspendBlock();
+ std.debug.assertOrPanic(!result);
+ resume a_promise;
+ std.debug.assertOrPanic(result);
+ cancel p;
+}
+
+var a_promise: promise = undefined;
+var result = false;
+async fn testSuspendBlock() void {
+ suspend {
+ comptime assertOrPanic(@typeOf(@handle()) == promise->void);
+ a_promise = @handle();
+ }
+
+ //Test to make sure that @handle() works as advertised (issue #1296)
+ //var our_handle: promise = @handle();
+ assertOrPanic(a_promise == @handle());
+
+ result = true;
+}
+
+var await_a_promise: promise = undefined;
+var await_final_result: i32 = 0;
+
+test "coroutine await" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ await_seq('a');
+ const p = async<&da.allocator> await_amain() catch unreachable;
+ await_seq('f');
+ resume await_a_promise;
+ await_seq('i');
+ assertOrPanic(await_final_result == 1234);
+ assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
+}
+async fn await_amain() void {
+ await_seq('b');
+ const p = async await_another() catch unreachable;
+ await_seq('e');
+ await_final_result = await p;
+ await_seq('h');
+}
+async fn await_another() i32 {
+ await_seq('c');
+ suspend {
+ await_seq('d');
+ await_a_promise = @handle();
+ }
+ await_seq('g');
+ return 1234;
+}
+
+var await_points = []u8{0} ** "abcdefghi".len;
+var await_seq_index: usize = 0;
+
+fn await_seq(c: u8) void {
+ await_points[await_seq_index] = c;
+ await_seq_index += 1;
+}
+
+var early_final_result: i32 = 0;
+
+test "coroutine await early return" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+
+ early_seq('a');
+ const p = async<&da.allocator> early_amain() catch @panic("out of memory");
+ early_seq('f');
+ assertOrPanic(early_final_result == 1234);
+ assertOrPanic(std.mem.eql(u8, early_points, "abcdef"));
+}
+async fn early_amain() void {
+ early_seq('b');
+ const p = async early_another() catch @panic("out of memory");
+ early_seq('d');
+ early_final_result = await p;
+ early_seq('e');
+}
+async fn early_another() i32 {
+ early_seq('c');
+ return 1234;
+}
+
+var early_points = []u8{0} ** "abcdef".len;
+var early_seq_index: usize = 0;
+
+fn early_seq(c: u8) void {
+ early_points[early_seq_index] = c;
+ early_seq_index += 1;
+}
+
+test "coro allocation failure" {
+ var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
+ if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
+ @panic("expected allocation failure");
+ } else |err| switch (err) {
+ error.OutOfMemory => {},
+ }
+}
+async fn asyncFuncThatNeverGetsRun() void {
+ @panic("coro frame allocation should fail");
+}
+
+test "async function with dot syntax" {
+ const S = struct {
+ var y: i32 = 1;
+ async fn foo() void {
+ y += 1;
+ suspend;
+ }
+ };
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+ const p = try async<&da.allocator> S.foo();
+ cancel p;
+ assertOrPanic(S.y == 2);
+}
+
+test "async fn pointer in a struct field" {
+ var data: i32 = 1;
+ const Foo = struct {
+ bar: async<*std.mem.Allocator> fn (*i32) void,
+ };
+ var foo = Foo{ .bar = simpleAsyncFn2 };
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+ const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
+ assertOrPanic(data == 2);
+ cancel p;
+ assertOrPanic(data == 4);
+}
+async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
+ defer y.* += 2;
+ y.* += 1;
+ suspend;
+}
+
+test "async fn with inferred error set" {
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+ const p = (async<&da.allocator> failing()) catch unreachable;
+ resume p;
+ cancel p;
+}
+
+async fn failing() !void {
+ suspend;
+ return error.Fail;
+}
+
+test "error return trace across suspend points - early return" {
+ const p = nonFailing();
+ resume p;
+ var da = std.heap.DirectAllocator.init();
+ defer da.deinit();
+ const p2 = try async<&da.allocator> printTrace(p);
+ cancel p2;
+}
+
+test "error return trace across suspend points - async return" {
+ const p = nonFailing();
+ const p2 = try async printTrace(p);
+ resume p;
+ cancel p2;
+}
+
+fn nonFailing() (promise->anyerror!void) {
+ return async suspendThenFail() catch unreachable;
+}
+async fn suspendThenFail() anyerror!void {
+ suspend;
+ return error.Fail;
+}
+async fn printTrace(p: promise->(anyerror!void)) void {
+ (await p) catch |e| {
+ std.debug.assertOrPanic(e == error.Fail);
+ if (@errorReturnTrace()) |trace| {
+ assertOrPanic(trace.index == 1);
+ } else switch (builtin.mode) {
+ builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
+ builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
+ }
+ };
+}
+
+test "break from suspend" {
+ var buf: [500]u8 = undefined;
+ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
+ var my_result: i32 = 1;
+ const p = try async testBreakFromSuspend(&my_result);
+ cancel p;
+ std.debug.assertOrPanic(my_result == 2);
+}
+async fn testBreakFromSuspend(my_result: *i32) void {
+ suspend {
+ resume @handle();
+ }
+ my_result.* += 1;
+ suspend;
+ my_result.* += 1;
+}
diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6c6c60311e67bf3a0b8f45c0e0d71106927c36a3
--- /dev/null
+++ b/test/stage1/behavior/defer.zig
@@ -0,0 +1,78 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+var result: [3]u8 = undefined;
+var index: usize = undefined;
+
+fn runSomeErrorDefers(x: bool) !bool {
+ index = 0;
+ defer {
+ result[index] = 'a';
+ index += 1;
+ }
+ errdefer {
+ result[index] = 'b';
+ index += 1;
+ }
+ defer {
+ result[index] = 'c';
+ index += 1;
+ }
+ return if (x) x else error.FalseNotAllowed;
+}
+
+test "mixing normal and error defers" {
+ assertOrPanic(runSomeErrorDefers(true) catch unreachable);
+ assertOrPanic(result[0] == 'c');
+ assertOrPanic(result[1] == 'a');
+
+ const ok = runSomeErrorDefers(false) catch |err| x: {
+ assertOrPanic(err == error.FalseNotAllowed);
+ break :x true;
+ };
+ assertOrPanic(ok);
+ assertOrPanic(result[0] == 'c');
+ assertOrPanic(result[1] == 'b');
+ assertOrPanic(result[2] == 'a');
+}
+
+test "break and continue inside loop inside defer expression" {
+ testBreakContInDefer(10);
+ comptime testBreakContInDefer(10);
+}
+
+fn testBreakContInDefer(x: usize) void {
+ defer {
+ var i: usize = 0;
+ while (i < x) : (i += 1) {
+ if (i < 5) continue;
+ if (i == 5) break;
+ }
+ assertOrPanic(i == 5);
+ }
+}
+
+test "defer and labeled break" {
+ var i = usize(0);
+
+ blk: {
+ defer i += 1;
+ break :blk;
+ }
+
+ assertOrPanic(i == 1);
+}
+
+test "errdefer does not apply to fn inside fn" {
+ if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad);
+}
+
+fn testNestedFnErrDefer() anyerror!void {
+ var a: i32 = 0;
+ errdefer a += 1;
+ const S = struct {
+ fn baz() anyerror {
+ return error.Bad;
+ }
+ };
+ return S.baz();
+}
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
new file mode 100644
index 0000000000000000000000000000000000000000..9de138ef78cd40707c66ae7ea208b44f4ca5fbfd
--- /dev/null
+++ b/test/stage1/behavior/enum.zig
@@ -0,0 +1,894 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+test "enum type" {
+ const foo1 = Foo{ .One = 13 };
+ const foo2 = Foo{
+ .Two = Point{
+ .x = 1234,
+ .y = 5678,
+ },
+ };
+ const bar = Bar.B;
+
+ assertOrPanic(bar == Bar.B);
+ assertOrPanic(@memberCount(Foo) == 3);
+ assertOrPanic(@memberCount(Bar) == 4);
+ assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid));
+ assertOrPanic(@sizeOf(Bar) == 1);
+}
+
+test "enum as return value" {
+ switch (returnAnInt(13)) {
+ Foo.One => |value| assertOrPanic(value == 13),
+ else => unreachable,
+ }
+}
+
+const Point = struct {
+ x: u64,
+ y: u64,
+};
+const Foo = union(enum) {
+ One: i32,
+ Two: Point,
+ Three: void,
+};
+const FooNoVoid = union(enum) {
+ One: i32,
+ Two: Point,
+};
+const Bar = enum {
+ A,
+ B,
+ C,
+ D,
+};
+
+fn returnAnInt(x: i32) Foo {
+ return Foo{ .One = x };
+}
+
+test "constant enum with payload" {
+ var empty = AnEnumWithPayload{ .Empty = {} };
+ var full = AnEnumWithPayload{ .Full = 13 };
+ shouldBeEmpty(empty);
+ shouldBeNotEmpty(full);
+}
+
+fn shouldBeEmpty(x: AnEnumWithPayload) void {
+ switch (x) {
+ AnEnumWithPayload.Empty => {},
+ else => unreachable,
+ }
+}
+
+fn shouldBeNotEmpty(x: AnEnumWithPayload) void {
+ switch (x) {
+ AnEnumWithPayload.Empty => unreachable,
+ else => {},
+ }
+}
+
+const AnEnumWithPayload = union(enum) {
+ Empty: void,
+ Full: i32,
+};
+
+const Number = enum {
+ Zero,
+ One,
+ Two,
+ Three,
+ Four,
+};
+
+test "enum to int" {
+ shouldEqual(Number.Zero, 0);
+ shouldEqual(Number.One, 1);
+ shouldEqual(Number.Two, 2);
+ shouldEqual(Number.Three, 3);
+ shouldEqual(Number.Four, 4);
+}
+
+fn shouldEqual(n: Number, expected: u3) void {
+ assertOrPanic(@enumToInt(n) == expected);
+}
+
+test "int to enum" {
+ testIntToEnumEval(3);
+}
+fn testIntToEnumEval(x: i32) void {
+ assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
+}
+const IntToEnumNumber = enum {
+ Zero,
+ One,
+ Two,
+ Three,
+ Four,
+};
+
+test "@tagName" {
+ assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+ comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+}
+
+fn testEnumTagNameBare(n: BareNumber) []const u8 {
+ return @tagName(n);
+}
+
+const BareNumber = enum {
+ One,
+ Two,
+ Three,
+};
+
+test "enum alignment" {
+ comptime {
+ assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
+ assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64));
+ }
+}
+
+const AlignTestEnum = union(enum) {
+ A: [9]u8,
+ B: u64,
+};
+
+const ValueCount1 = enum {
+ I0,
+};
+const ValueCount2 = enum {
+ I0,
+ I1,
+};
+const ValueCount256 = enum {
+ I0,
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8,
+ I9,
+ I10,
+ I11,
+ I12,
+ I13,
+ I14,
+ I15,
+ I16,
+ I17,
+ I18,
+ I19,
+ I20,
+ I21,
+ I22,
+ I23,
+ I24,
+ I25,
+ I26,
+ I27,
+ I28,
+ I29,
+ I30,
+ I31,
+ I32,
+ I33,
+ I34,
+ I35,
+ I36,
+ I37,
+ I38,
+ I39,
+ I40,
+ I41,
+ I42,
+ I43,
+ I44,
+ I45,
+ I46,
+ I47,
+ I48,
+ I49,
+ I50,
+ I51,
+ I52,
+ I53,
+ I54,
+ I55,
+ I56,
+ I57,
+ I58,
+ I59,
+ I60,
+ I61,
+ I62,
+ I63,
+ I64,
+ I65,
+ I66,
+ I67,
+ I68,
+ I69,
+ I70,
+ I71,
+ I72,
+ I73,
+ I74,
+ I75,
+ I76,
+ I77,
+ I78,
+ I79,
+ I80,
+ I81,
+ I82,
+ I83,
+ I84,
+ I85,
+ I86,
+ I87,
+ I88,
+ I89,
+ I90,
+ I91,
+ I92,
+ I93,
+ I94,
+ I95,
+ I96,
+ I97,
+ I98,
+ I99,
+ I100,
+ I101,
+ I102,
+ I103,
+ I104,
+ I105,
+ I106,
+ I107,
+ I108,
+ I109,
+ I110,
+ I111,
+ I112,
+ I113,
+ I114,
+ I115,
+ I116,
+ I117,
+ I118,
+ I119,
+ I120,
+ I121,
+ I122,
+ I123,
+ I124,
+ I125,
+ I126,
+ I127,
+ I128,
+ I129,
+ I130,
+ I131,
+ I132,
+ I133,
+ I134,
+ I135,
+ I136,
+ I137,
+ I138,
+ I139,
+ I140,
+ I141,
+ I142,
+ I143,
+ I144,
+ I145,
+ I146,
+ I147,
+ I148,
+ I149,
+ I150,
+ I151,
+ I152,
+ I153,
+ I154,
+ I155,
+ I156,
+ I157,
+ I158,
+ I159,
+ I160,
+ I161,
+ I162,
+ I163,
+ I164,
+ I165,
+ I166,
+ I167,
+ I168,
+ I169,
+ I170,
+ I171,
+ I172,
+ I173,
+ I174,
+ I175,
+ I176,
+ I177,
+ I178,
+ I179,
+ I180,
+ I181,
+ I182,
+ I183,
+ I184,
+ I185,
+ I186,
+ I187,
+ I188,
+ I189,
+ I190,
+ I191,
+ I192,
+ I193,
+ I194,
+ I195,
+ I196,
+ I197,
+ I198,
+ I199,
+ I200,
+ I201,
+ I202,
+ I203,
+ I204,
+ I205,
+ I206,
+ I207,
+ I208,
+ I209,
+ I210,
+ I211,
+ I212,
+ I213,
+ I214,
+ I215,
+ I216,
+ I217,
+ I218,
+ I219,
+ I220,
+ I221,
+ I222,
+ I223,
+ I224,
+ I225,
+ I226,
+ I227,
+ I228,
+ I229,
+ I230,
+ I231,
+ I232,
+ I233,
+ I234,
+ I235,
+ I236,
+ I237,
+ I238,
+ I239,
+ I240,
+ I241,
+ I242,
+ I243,
+ I244,
+ I245,
+ I246,
+ I247,
+ I248,
+ I249,
+ I250,
+ I251,
+ I252,
+ I253,
+ I254,
+ I255,
+};
+const ValueCount257 = enum {
+ I0,
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8,
+ I9,
+ I10,
+ I11,
+ I12,
+ I13,
+ I14,
+ I15,
+ I16,
+ I17,
+ I18,
+ I19,
+ I20,
+ I21,
+ I22,
+ I23,
+ I24,
+ I25,
+ I26,
+ I27,
+ I28,
+ I29,
+ I30,
+ I31,
+ I32,
+ I33,
+ I34,
+ I35,
+ I36,
+ I37,
+ I38,
+ I39,
+ I40,
+ I41,
+ I42,
+ I43,
+ I44,
+ I45,
+ I46,
+ I47,
+ I48,
+ I49,
+ I50,
+ I51,
+ I52,
+ I53,
+ I54,
+ I55,
+ I56,
+ I57,
+ I58,
+ I59,
+ I60,
+ I61,
+ I62,
+ I63,
+ I64,
+ I65,
+ I66,
+ I67,
+ I68,
+ I69,
+ I70,
+ I71,
+ I72,
+ I73,
+ I74,
+ I75,
+ I76,
+ I77,
+ I78,
+ I79,
+ I80,
+ I81,
+ I82,
+ I83,
+ I84,
+ I85,
+ I86,
+ I87,
+ I88,
+ I89,
+ I90,
+ I91,
+ I92,
+ I93,
+ I94,
+ I95,
+ I96,
+ I97,
+ I98,
+ I99,
+ I100,
+ I101,
+ I102,
+ I103,
+ I104,
+ I105,
+ I106,
+ I107,
+ I108,
+ I109,
+ I110,
+ I111,
+ I112,
+ I113,
+ I114,
+ I115,
+ I116,
+ I117,
+ I118,
+ I119,
+ I120,
+ I121,
+ I122,
+ I123,
+ I124,
+ I125,
+ I126,
+ I127,
+ I128,
+ I129,
+ I130,
+ I131,
+ I132,
+ I133,
+ I134,
+ I135,
+ I136,
+ I137,
+ I138,
+ I139,
+ I140,
+ I141,
+ I142,
+ I143,
+ I144,
+ I145,
+ I146,
+ I147,
+ I148,
+ I149,
+ I150,
+ I151,
+ I152,
+ I153,
+ I154,
+ I155,
+ I156,
+ I157,
+ I158,
+ I159,
+ I160,
+ I161,
+ I162,
+ I163,
+ I164,
+ I165,
+ I166,
+ I167,
+ I168,
+ I169,
+ I170,
+ I171,
+ I172,
+ I173,
+ I174,
+ I175,
+ I176,
+ I177,
+ I178,
+ I179,
+ I180,
+ I181,
+ I182,
+ I183,
+ I184,
+ I185,
+ I186,
+ I187,
+ I188,
+ I189,
+ I190,
+ I191,
+ I192,
+ I193,
+ I194,
+ I195,
+ I196,
+ I197,
+ I198,
+ I199,
+ I200,
+ I201,
+ I202,
+ I203,
+ I204,
+ I205,
+ I206,
+ I207,
+ I208,
+ I209,
+ I210,
+ I211,
+ I212,
+ I213,
+ I214,
+ I215,
+ I216,
+ I217,
+ I218,
+ I219,
+ I220,
+ I221,
+ I222,
+ I223,
+ I224,
+ I225,
+ I226,
+ I227,
+ I228,
+ I229,
+ I230,
+ I231,
+ I232,
+ I233,
+ I234,
+ I235,
+ I236,
+ I237,
+ I238,
+ I239,
+ I240,
+ I241,
+ I242,
+ I243,
+ I244,
+ I245,
+ I246,
+ I247,
+ I248,
+ I249,
+ I250,
+ I251,
+ I252,
+ I253,
+ I254,
+ I255,
+ I256,
+};
+
+test "enum sizes" {
+ comptime {
+ assertOrPanic(@sizeOf(ValueCount1) == 0);
+ assertOrPanic(@sizeOf(ValueCount2) == 1);
+ assertOrPanic(@sizeOf(ValueCount256) == 1);
+ assertOrPanic(@sizeOf(ValueCount257) == 2);
+ }
+}
+
+const Small2 = enum(u2) {
+ One,
+ Two,
+};
+const Small = enum(u2) {
+ One,
+ Two,
+ Three,
+ Four,
+};
+
+test "set enum tag type" {
+ {
+ var x = Small.One;
+ x = Small.Two;
+ comptime assertOrPanic(@TagType(Small) == u2);
+ }
+ {
+ var x = Small2.One;
+ x = Small2.Two;
+ comptime assertOrPanic(@TagType(Small2) == u2);
+ }
+}
+
+const A = enum(u3) {
+ One,
+ Two,
+ Three,
+ Four,
+ One2,
+ Two2,
+ Three2,
+ Four2,
+};
+
+const B = enum(u3) {
+ One3,
+ Two3,
+ Three3,
+ Four3,
+ One23,
+ Two23,
+ Three23,
+ Four23,
+};
+
+const C = enum(u2) {
+ One4,
+ Two4,
+ Three4,
+ Four4,
+};
+
+const BitFieldOfEnums = packed struct {
+ a: A,
+ b: B,
+ c: C,
+};
+
+const bit_field_1 = BitFieldOfEnums{
+ .a = A.Two,
+ .b = B.Three3,
+ .c = C.Four4,
+};
+
+test "bit field access with enum fields" {
+ var data = bit_field_1;
+ assertOrPanic(getA(&data) == A.Two);
+ assertOrPanic(getB(&data) == B.Three3);
+ assertOrPanic(getC(&data) == C.Four4);
+ comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1);
+
+ data.b = B.Four3;
+ assertOrPanic(data.b == B.Four3);
+
+ data.a = A.Three;
+ assertOrPanic(data.a == A.Three);
+ assertOrPanic(data.b == B.Four3);
+}
+
+fn getA(data: *const BitFieldOfEnums) A {
+ return data.a;
+}
+
+fn getB(data: *const BitFieldOfEnums) B {
+ return data.b;
+}
+
+fn getC(data: *const BitFieldOfEnums) C {
+ return data.c;
+}
+
+test "casting enum to its tag type" {
+ testCastEnumToTagType(Small2.Two);
+ comptime testCastEnumToTagType(Small2.Two);
+}
+
+fn testCastEnumToTagType(value: Small2) void {
+ assertOrPanic(@enumToInt(value) == 1);
+}
+
+const MultipleChoice = enum(u32) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+
+test "enum with specified tag values" {
+ testEnumWithSpecifiedTagValues(MultipleChoice.C);
+ comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
+}
+
+fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
+ assertOrPanic(@enumToInt(x) == 60);
+ assertOrPanic(1234 == switch (x) {
+ MultipleChoice.A => 1,
+ MultipleChoice.B => 2,
+ MultipleChoice.C => u32(1234),
+ MultipleChoice.D => 4,
+ });
+}
+
+const MultipleChoice2 = enum(u32) {
+ Unspecified1,
+ A = 20,
+ Unspecified2,
+ B = 40,
+ Unspecified3,
+ C = 60,
+ Unspecified4,
+ D = 1000,
+ Unspecified5,
+};
+
+test "enum with specified and unspecified tag values" {
+ testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+ comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
+ assertOrPanic(@enumToInt(x) == 1000);
+ assertOrPanic(1234 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => 3,
+ MultipleChoice2.D => u32(1234),
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
+
+test "cast integer literal to enum" {
+ assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
+ assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
+}
+
+const EnumWithOneMember = enum {
+ Eof,
+};
+
+fn doALoopThing(id: EnumWithOneMember) void {
+ while (true) {
+ if (id == EnumWithOneMember.Eof) {
+ break;
+ }
+ @compileError("above if condition should be comptime");
+ }
+}
+
+test "comparison operator on enum with one member is comptime known" {
+ doALoopThing(EnumWithOneMember.Eof);
+}
+
+const State = enum {
+ Start,
+};
+test "switch on enum with one member is comptime known" {
+ var state = State.Start;
+ switch (state) {
+ State.Start => return,
+ }
+ @compileError("analysis should not reach here");
+}
+
+const EnumWithTagValues = enum(u4) {
+ A = 1 << 0,
+ B = 1 << 1,
+ C = 1 << 2,
+ D = 1 << 3,
+};
+test "enum with tag values don't require parens" {
+ assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100);
+}
+
+test "enum with 1 field but explicit tag type should still have the tag type" {
+ const Enum = enum(u8) {
+ B = 2,
+ };
+ comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8));
+}
+
+test "empty extern enum with members" {
+ const E = extern enum {
+ A,
+ B,
+ C,
+ };
+ assertOrPanic(@sizeOf(E) == @sizeOf(c_int));
+}
+
+test "tag name with assigned enum values" {
+ const LocalFoo = enum {
+ A = 1,
+ B = 0,
+ };
+ var b = LocalFoo.B;
+ assertOrPanic(mem.eql(u8, @tagName(b), "B"));
+}
diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig
new file mode 100644
index 0000000000000000000000000000000000000000..49af1ceae78eef7a5566e589d9d39abd027d7d40
--- /dev/null
+++ b/test/stage1/behavior/enum_with_members.zig
@@ -0,0 +1,27 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const fmt = @import("std").fmt;
+
+const ET = union(enum) {
+ SINT: i32,
+ UINT: u32,
+
+ pub fn print(a: *const ET, buf: []u8) anyerror!usize {
+ return switch (a.*) {
+ ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
+ ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
+ };
+ }
+};
+
+test "enum with members" {
+ const a = ET{ .SINT = -42 };
+ const b = ET{ .UINT = 42 };
+ var buf: [20]u8 = undefined;
+
+ assertOrPanic((a.print(buf[0..]) catch unreachable) == 3);
+ assertOrPanic(mem.eql(u8, buf[0..3], "-42"));
+
+ assertOrPanic((b.print(buf[0..]) catch unreachable) == 2);
+ assertOrPanic(mem.eql(u8, buf[0..2], "42"));
+}
diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c7e38712bcdf5b8e7ff0a4eb8d8eba7692ec768c
--- /dev/null
+++ b/test/stage1/behavior/error.zig
@@ -0,0 +1,332 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const assertError = std.debug.assertError;
+const mem = std.mem;
+const builtin = @import("builtin");
+
+pub fn foo() anyerror!i32 {
+ const x = try bar();
+ return x + 1;
+}
+
+pub fn bar() anyerror!i32 {
+ return 13;
+}
+
+pub fn baz() anyerror!i32 {
+ const y = foo() catch 1234;
+ return y + 1;
+}
+
+test "error wrapping" {
+ assertOrPanic((baz() catch unreachable) == 15);
+}
+
+fn gimmeItBroke() []const u8 {
+ return @errorName(error.ItBroke);
+}
+
+test "@errorName" {
+ assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError"));
+ assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
+}
+
+test "error values" {
+ const a = @errorToInt(error.err1);
+ const b = @errorToInt(error.err2);
+ assertOrPanic(a != b);
+}
+
+test "redefinition of error values allowed" {
+ shouldBeNotEqual(error.AnError, error.SecondError);
+}
+fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
+ if (a == b) unreachable;
+}
+
+test "error binary operator" {
+ const a = errBinaryOperatorG(true) catch 3;
+ const b = errBinaryOperatorG(false) catch 3;
+ assertOrPanic(a == 3);
+ assertOrPanic(b == 10);
+}
+fn errBinaryOperatorG(x: bool) anyerror!isize {
+ return if (x) error.ItBroke else isize(10);
+}
+
+test "unwrap simple value from error" {
+ const i = unwrapSimpleValueFromErrorDo() catch unreachable;
+ assertOrPanic(i == 13);
+}
+fn unwrapSimpleValueFromErrorDo() anyerror!isize {
+ return 13;
+}
+
+test "error return in assignment" {
+ doErrReturnInAssignment() catch unreachable;
+}
+
+fn doErrReturnInAssignment() anyerror!void {
+ var x: i32 = undefined;
+ x = try makeANonErr();
+}
+
+fn makeANonErr() anyerror!i32 {
+ return 1;
+}
+
+test "error union type " {
+ testErrorUnionType();
+ comptime testErrorUnionType();
+}
+
+fn testErrorUnionType() void {
+ const x: anyerror!i32 = 1234;
+ if (x) |value| assertOrPanic(value == 1234) else |_| unreachable;
+ assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
+ assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
+ assertOrPanic(@typeOf(x).ErrorSet == anyerror);
+}
+
+test "error set type" {
+ testErrorSetType();
+ comptime testErrorSetType();
+}
+
+const MyErrSet = error{
+ OutOfMemory,
+ FileNotFound,
+};
+
+fn testErrorSetType() void {
+ assertOrPanic(@memberCount(MyErrSet) == 2);
+
+ const a: MyErrSet!i32 = 5678;
+ const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
+
+ if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) {
+ error.OutOfMemory => unreachable,
+ error.FileNotFound => unreachable,
+ }
+}
+
+test "explicit error set cast" {
+ testExplicitErrorSetCast(Set1.A);
+ comptime testExplicitErrorSetCast(Set1.A);
+}
+
+const Set1 = error{
+ A,
+ B,
+};
+const Set2 = error{
+ A,
+ C,
+};
+
+fn testExplicitErrorSetCast(set1: Set1) void {
+ var x = @errSetCast(Set2, set1);
+ var y = @errSetCast(Set1, x);
+ assertOrPanic(y == error.A);
+}
+
+test "comptime test error for empty error set" {
+ testComptimeTestErrorEmptySet(1234);
+ comptime testComptimeTestErrorEmptySet(1234);
+}
+
+const EmptyErrorSet = error{};
+
+fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
+ if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad");
+}
+
+test "syntax: optional operator in front of error union operator" {
+ comptime {
+ assertOrPanic(?(anyerror!i32) == ?(anyerror!i32));
+ }
+}
+
+test "comptime err to int of error set with only 1 possible value" {
+ testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
+ comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
+}
+fn testErrToIntWithOnePossibleValue(
+ x: error{A},
+ comptime value: u32,
+) void {
+ if (@errorToInt(x) != value) {
+ @compileError("bad");
+ }
+}
+
+test "error union peer type resolution" {
+ testErrorUnionPeerTypeResolution(1);
+}
+
+fn testErrorUnionPeerTypeResolution(x: i32) void {
+ const y = switch (x) {
+ 1 => bar_1(),
+ 2 => baz_1(),
+ else => quux_1(),
+ };
+ if (y) |_| {
+ @panic("expected error");
+ } else |e| {
+ assertOrPanic(e == error.A);
+ }
+}
+
+fn bar_1() anyerror {
+ return error.A;
+}
+
+fn baz_1() !i32 {
+ return error.B;
+}
+
+fn quux_1() !i32 {
+ return error.C;
+}
+
+test "error: fn returning empty error set can be passed as fn returning any error" {
+ entry();
+ comptime entry();
+}
+
+fn entry() void {
+ foo2(bar2);
+}
+
+fn foo2(f: fn () anyerror!void) void {
+ const x = f();
+}
+
+fn bar2() (error{}!void) {}
+
+test "error: Zero sized error set returned with value payload crash" {
+ _ = foo3(0);
+ _ = comptime foo3(0);
+}
+
+const Error = error{};
+fn foo3(b: usize) Error!usize {
+ return b;
+}
+
+test "error: Infer error set from literals" {
+ _ = nullLiteral("n") catch |err| handleErrors(err);
+ _ = floatLiteral("n") catch |err| handleErrors(err);
+ _ = intLiteral("n") catch |err| handleErrors(err);
+ _ = comptime nullLiteral("n") catch |err| handleErrors(err);
+ _ = comptime floatLiteral("n") catch |err| handleErrors(err);
+ _ = comptime intLiteral("n") catch |err| handleErrors(err);
+}
+
+fn handleErrors(err: var) noreturn {
+ switch (err) {
+ error.T => {},
+ }
+
+ unreachable;
+}
+
+fn nullLiteral(str: []const u8) !?i64 {
+ if (str[0] == 'n') return null;
+
+ return error.T;
+}
+
+fn floatLiteral(str: []const u8) !?f64 {
+ if (str[0] == 'n') return 1.0;
+
+ return error.T;
+}
+
+fn intLiteral(str: []const u8) !?i64 {
+ if (str[0] == 'n') return 1;
+
+ return error.T;
+}
+
+test "nested error union function call in optional unwrap" {
+ const S = struct {
+ const Foo = struct {
+ a: i32,
+ };
+
+ fn errorable() !i32 {
+ var x: Foo = (try getFoo()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable2() !i32 {
+ var x: Foo = (try getFoo2()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable3() !i32 {
+ var x: Foo = (try getFoo3()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn getFoo() anyerror!?Foo {
+ return Foo{ .a = 1234 };
+ }
+
+ fn getFoo2() anyerror!?Foo {
+ return error.Failure;
+ }
+
+ fn getFoo3() anyerror!?Foo {
+ return null;
+ }
+ };
+ assertOrPanic((try S.errorable()) == 1234);
+ assertError(S.errorable2(), error.Failure);
+ assertError(S.errorable3(), error.Other);
+ comptime {
+ assertOrPanic((try S.errorable()) == 1234);
+ assertError(S.errorable2(), error.Failure);
+ assertError(S.errorable3(), error.Other);
+ }
+}
+
+test "widen cast integer payload of error union function call" {
+ const S = struct {
+ fn errorable() !u64 {
+ var x = u64(try number());
+ return x;
+ }
+
+ fn number() anyerror!u32 {
+ return 1234;
+ }
+ };
+ assertOrPanic((try S.errorable()) == 1234);
+}
+
+test "return function call to error set from error union function" {
+ const S = struct {
+ fn errorable() anyerror!i32 {
+ return fail();
+ }
+
+ fn fail() anyerror {
+ return error.Failure;
+ }
+ };
+ assertError(S.errorable(), error.Failure);
+ comptime assertError(S.errorable(), error.Failure);
+}
+
+test "optional error set is the same size as error set" {
+ comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror));
+ const S = struct {
+ fn returnsOptErrSet() ?anyerror {
+ return null;
+ }
+ };
+ assertOrPanic(S.returnsOptErrSet() == null);
+ comptime assertOrPanic(S.returnsOptErrSet() == null);
+}
diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig
new file mode 100644
index 0000000000000000000000000000000000000000..3e8af0524fb24fef4f578203893fee18682430f0
--- /dev/null
+++ b/test/stage1/behavior/eval.zig
@@ -0,0 +1,784 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const builtin = @import("builtin");
+
+test "compile time recursion" {
+ assertOrPanic(some_data.len == 21);
+}
+var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
+fn fibonacci(x: i32) i32 {
+ if (x <= 1) return 1;
+ return fibonacci(x - 1) + fibonacci(x - 2);
+}
+
+fn unwrapAndAddOne(blah: ?i32) i32 {
+ return blah.? + 1;
+}
+const should_be_1235 = unwrapAndAddOne(1234);
+test "static add one" {
+ assertOrPanic(should_be_1235 == 1235);
+}
+
+test "inlined loop" {
+ comptime var i = 0;
+ comptime var sum = 0;
+ inline while (i <= 5) : (i += 1)
+ sum += i;
+ assertOrPanic(sum == 15);
+}
+
+fn gimme1or2(comptime a: bool) i32 {
+ const x: i32 = 1;
+ const y: i32 = 2;
+ comptime var z: i32 = if (a) x else y;
+ return z;
+}
+test "inline variable gets result of const if" {
+ assertOrPanic(gimme1or2(true) == 1);
+ assertOrPanic(gimme1or2(false) == 2);
+}
+
+test "static function evaluation" {
+ assertOrPanic(statically_added_number == 3);
+}
+const statically_added_number = staticAdd(1, 2);
+fn staticAdd(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "const expr eval on single expr blocks" {
+ assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
+ comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
+}
+
+fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
+ const literal = 3;
+
+ const result = if (b) b: {
+ break :b literal;
+ } else b: {
+ break :b x;
+ };
+
+ return result;
+}
+
+test "statically initialized list" {
+ assertOrPanic(static_point_list[0].x == 1);
+ assertOrPanic(static_point_list[0].y == 2);
+ assertOrPanic(static_point_list[1].x == 3);
+ assertOrPanic(static_point_list[1].y == 4);
+}
+const Point = struct {
+ x: i32,
+ y: i32,
+};
+const static_point_list = []Point{
+ makePoint(1, 2),
+ makePoint(3, 4),
+};
+fn makePoint(x: i32, y: i32) Point {
+ return Point{
+ .x = x,
+ .y = y,
+ };
+}
+
+test "static eval list init" {
+ assertOrPanic(static_vec3.data[2] == 1.0);
+ assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
+}
+const static_vec3 = vec3(0.0, 0.0, 1.0);
+pub const Vec3 = struct {
+ data: [3]f32,
+};
+pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
+ return Vec3{ .data = []f32{
+ x,
+ y,
+ z,
+ } };
+}
+
+test "constant expressions" {
+ var array: [array_size]u8 = undefined;
+ assertOrPanic(@sizeOf(@typeOf(array)) == 20);
+}
+const array_size: u8 = 20;
+
+test "constant struct with negation" {
+ assertOrPanic(vertices[0].x == -0.6);
+}
+const Vertex = struct {
+ x: f32,
+ y: f32,
+ r: f32,
+ g: f32,
+ b: f32,
+};
+const vertices = []Vertex{
+ Vertex{
+ .x = -0.6,
+ .y = -0.4,
+ .r = 1.0,
+ .g = 0.0,
+ .b = 0.0,
+ },
+ Vertex{
+ .x = 0.6,
+ .y = -0.4,
+ .r = 0.0,
+ .g = 1.0,
+ .b = 0.0,
+ },
+ Vertex{
+ .x = 0.0,
+ .y = 0.6,
+ .r = 0.0,
+ .g = 0.0,
+ .b = 1.0,
+ },
+};
+
+test "statically initialized struct" {
+ st_init_str_foo.x += 1;
+ assertOrPanic(st_init_str_foo.x == 14);
+}
+const StInitStrFoo = struct {
+ x: i32,
+ y: bool,
+};
+var st_init_str_foo = StInitStrFoo{
+ .x = 13,
+ .y = true,
+};
+
+test "statically initalized array literal" {
+ const y: [4]u8 = st_init_arr_lit_x;
+ assertOrPanic(y[3] == 4);
+}
+const st_init_arr_lit_x = []u8{
+ 1,
+ 2,
+ 3,
+ 4,
+};
+
+test "const slice" {
+ comptime {
+ const a = "1234567890";
+ assertOrPanic(a.len == 10);
+ const b = a[1..2];
+ assertOrPanic(b.len == 1);
+ assertOrPanic(b[0] == '2');
+ }
+}
+
+test "try to trick eval with runtime if" {
+ assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10);
+}
+
+fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
+ comptime var i: usize = 0;
+ inline while (i < 10) : (i += 1) {
+ const result = if (b) false else true;
+ }
+ comptime {
+ return i;
+ }
+}
+
+fn max(comptime T: type, a: T, b: T) T {
+ if (T == bool) {
+ return a or b;
+ } else if (a > b) {
+ return a;
+ } else {
+ return b;
+ }
+}
+fn letsTryToCompareBools(a: bool, b: bool) bool {
+ return max(bool, a, b);
+}
+test "inlined block and runtime block phi" {
+ assertOrPanic(letsTryToCompareBools(true, true));
+ assertOrPanic(letsTryToCompareBools(true, false));
+ assertOrPanic(letsTryToCompareBools(false, true));
+ assertOrPanic(!letsTryToCompareBools(false, false));
+
+ comptime {
+ assertOrPanic(letsTryToCompareBools(true, true));
+ assertOrPanic(letsTryToCompareBools(true, false));
+ assertOrPanic(letsTryToCompareBools(false, true));
+ assertOrPanic(!letsTryToCompareBools(false, false));
+ }
+}
+
+const CmdFn = struct {
+ name: []const u8,
+ func: fn (i32) i32,
+};
+
+const cmd_fns = []CmdFn{
+ CmdFn{
+ .name = "one",
+ .func = one,
+ },
+ CmdFn{
+ .name = "two",
+ .func = two,
+ },
+ CmdFn{
+ .name = "three",
+ .func = three,
+ },
+};
+fn one(value: i32) i32 {
+ return value + 1;
+}
+fn two(value: i32) i32 {
+ return value + 2;
+}
+fn three(value: i32) i32 {
+ return value + 3;
+}
+
+fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
+ var result: i32 = start_value;
+ comptime var i = 0;
+ inline while (i < cmd_fns.len) : (i += 1) {
+ if (cmd_fns[i].name[0] == prefix_char) {
+ result = cmd_fns[i].func(result);
+ }
+ }
+ return result;
+}
+
+test "comptime iterate over fn ptr list" {
+ assertOrPanic(performFn('t', 1) == 6);
+ assertOrPanic(performFn('o', 0) == 1);
+ assertOrPanic(performFn('w', 99) == 99);
+}
+
+test "eval @setRuntimeSafety at compile-time" {
+ const result = comptime fnWithSetRuntimeSafety();
+ assertOrPanic(result == 1234);
+}
+
+fn fnWithSetRuntimeSafety() i32 {
+ @setRuntimeSafety(true);
+ return 1234;
+}
+
+test "eval @setFloatMode at compile-time" {
+ const result = comptime fnWithFloatMode();
+ assertOrPanic(result == 1234.0);
+}
+
+fn fnWithFloatMode() f32 {
+ @setFloatMode(builtin.FloatMode.Strict);
+ return 1234.0;
+}
+
+const SimpleStruct = struct {
+ field: i32,
+
+ fn method(self: *const SimpleStruct) i32 {
+ return self.field + 3;
+ }
+};
+
+var simple_struct = SimpleStruct{ .field = 1234 };
+
+const bound_fn = simple_struct.method;
+
+test "call method on bound fn referring to var instance" {
+ assertOrPanic(bound_fn() == 1237);
+}
+
+test "ptr to local array argument at comptime" {
+ comptime {
+ var bytes: [10]u8 = undefined;
+ modifySomeBytes(bytes[0..]);
+ assertOrPanic(bytes[0] == 'a');
+ assertOrPanic(bytes[9] == 'b');
+ }
+}
+
+fn modifySomeBytes(bytes: []u8) void {
+ bytes[0] = 'a';
+ bytes[9] = 'b';
+}
+
+test "comparisons 0 <= uint and 0 > uint should be comptime" {
+ testCompTimeUIntComparisons(1234);
+}
+fn testCompTimeUIntComparisons(x: u32) void {
+ if (!(0 <= x)) {
+ @compileError("this condition should be comptime known");
+ }
+ if (0 > x) {
+ @compileError("this condition should be comptime known");
+ }
+ if (!(x >= 0)) {
+ @compileError("this condition should be comptime known");
+ }
+ if (x < 0) {
+ @compileError("this condition should be comptime known");
+ }
+}
+
+test "const ptr to variable data changes at runtime" {
+ assertOrPanic(foo_ref.name[0] == 'a');
+ foo_ref.name = "b";
+ assertOrPanic(foo_ref.name[0] == 'b');
+}
+
+const Foo = struct {
+ name: []const u8,
+};
+
+var foo_contents = Foo{ .name = "a" };
+const foo_ref = &foo_contents;
+
+test "create global array with for loop" {
+ assertOrPanic(global_array[5] == 5 * 5);
+ assertOrPanic(global_array[9] == 9 * 9);
+}
+
+const global_array = x: {
+ var result: [10]usize = undefined;
+ for (result) |*item, index| {
+ item.* = index * index;
+ }
+ break :x result;
+};
+
+test "compile-time downcast when the bits fit" {
+ comptime {
+ const spartan_count: u16 = 255;
+ const byte = @intCast(u8, spartan_count);
+ assertOrPanic(byte == 255);
+ }
+}
+
+const hi1 = "hi";
+const hi2 = hi1;
+test "const global shares pointer with other same one" {
+ assertEqualPtrs(&hi1[0], &hi2[0]);
+ comptime assertOrPanic(&hi1[0] == &hi2[0]);
+}
+fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void {
+ assertOrPanic(ptr1 == ptr2);
+}
+
+test "@setEvalBranchQuota" {
+ comptime {
+ // 1001 for the loop and then 1 more for the assertOrPanic fn call
+ @setEvalBranchQuota(1002);
+ var i = 0;
+ var sum = 0;
+ while (i < 1001) : (i += 1) {
+ sum += i;
+ }
+ assertOrPanic(sum == 500500);
+ }
+}
+
+// TODO test "float literal at compile time not lossy" {
+// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0);
+// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0);
+// TODO }
+
+test "f32 at compile time is lossy" {
+ assertOrPanic(f32(1 << 24) + 1 == 1 << 24);
+}
+
+test "f64 at compile time is lossy" {
+ assertOrPanic(f64(1 << 53) + 1 == 1 << 53);
+}
+
+test "f128 at compile time is lossy" {
+ assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
+}
+
+comptime {
+ assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192);
+}
+
+pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
+ return struct {
+ pub const Node = struct {};
+ };
+}
+
+test "string literal used as comptime slice is memoized" {
+ const a = "link";
+ const b = "link";
+ comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
+ comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
+}
+
+test "comptime slice of undefined pointer of length 0" {
+ const slice1 = ([*]i32)(undefined)[0..0];
+ assertOrPanic(slice1.len == 0);
+ const slice2 = ([*]i32)(undefined)[100..100];
+ assertOrPanic(slice2.len == 0);
+}
+
+fn copyWithPartialInline(s: []u32, b: []u8) void {
+ comptime var i: usize = 0;
+ inline while (i < 4) : (i += 1) {
+ s[i] = 0;
+ s[i] |= u32(b[i * 4 + 0]) << 24;
+ s[i] |= u32(b[i * 4 + 1]) << 16;
+ s[i] |= u32(b[i * 4 + 2]) << 8;
+ s[i] |= u32(b[i * 4 + 3]) << 0;
+ }
+}
+
+test "binary math operator in partially inlined function" {
+ var s: [4]u32 = undefined;
+ var b: [16]u8 = undefined;
+
+ for (b) |*r, i|
+ r.* = @intCast(u8, i + 1);
+
+ copyWithPartialInline(s[0..], b[0..]);
+ assertOrPanic(s[0] == 0x1020304);
+ assertOrPanic(s[1] == 0x5060708);
+ assertOrPanic(s[2] == 0x90a0b0c);
+ assertOrPanic(s[3] == 0xd0e0f10);
+}
+
+test "comptime function with the same args is memoized" {
+ comptime {
+ assertOrPanic(MakeType(i32) == MakeType(i32));
+ assertOrPanic(MakeType(i32) != MakeType(f64));
+ }
+}
+
+fn MakeType(comptime T: type) type {
+ return struct {
+ field: T,
+ };
+}
+
+test "comptime function with mutable pointer is not memoized" {
+ comptime {
+ var x: i32 = 1;
+ const ptr = &x;
+ increment(ptr);
+ increment(ptr);
+ assertOrPanic(x == 3);
+ }
+}
+
+fn increment(value: *i32) void {
+ value.* += 1;
+}
+
+fn generateTable(comptime T: type) [1010]T {
+ var res: [1010]T = undefined;
+ var i: usize = 0;
+ while (i < 1010) : (i += 1) {
+ res[i] = @intCast(T, i);
+ }
+ return res;
+}
+
+fn doesAlotT(comptime T: type, value: usize) T {
+ @setEvalBranchQuota(5000);
+ const table = comptime blk: {
+ break :blk generateTable(T);
+ };
+ return table[value];
+}
+
+test "@setEvalBranchQuota at same scope as generic function call" {
+ assertOrPanic(doesAlotT(u32, 2) == 2);
+}
+
+test "comptime slice of slice preserves comptime var" {
+ comptime {
+ var buff: [10]u8 = undefined;
+ buff[0..][0..][0] = 1;
+ assertOrPanic(buff[0..][0..][0] == 1);
+ }
+}
+
+test "comptime slice of pointer preserves comptime var" {
+ comptime {
+ var buff: [10]u8 = undefined;
+ var a = buff[0..].ptr;
+ a[0..1][0] = 1;
+ assertOrPanic(buff[0..][0..][0] == 1);
+ }
+}
+
+const SingleFieldStruct = struct {
+ x: i32,
+
+ fn read_x(self: *const SingleFieldStruct) i32 {
+ return self.x;
+ }
+};
+test "const ptr to comptime mutable data is not memoized" {
+ comptime {
+ var foo = SingleFieldStruct{ .x = 1 };
+ assertOrPanic(foo.read_x() == 1);
+ foo.x = 2;
+ assertOrPanic(foo.read_x() == 2);
+ }
+}
+
+test "array concat of slices gives slice" {
+ comptime {
+ var a: []const u8 = "aoeu";
+ var b: []const u8 = "asdf";
+ const c = a ++ b;
+ assertOrPanic(std.mem.eql(u8, c, "aoeuasdf"));
+ }
+}
+
+test "comptime shlWithOverflow" {
+ const ct_shifted: u64 = comptime amt: {
+ var amt = u64(0);
+ _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
+ break :amt amt;
+ };
+
+ const rt_shifted: u64 = amt: {
+ var amt = u64(0);
+ _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
+ break :amt amt;
+ };
+
+ assertOrPanic(ct_shifted == rt_shifted);
+}
+
+test "runtime 128 bit integer division" {
+ var a: u128 = 152313999999999991610955792383;
+ var b: u128 = 10000000000000000000;
+ var c = a / b;
+ assertOrPanic(c == 15231399999);
+}
+
+pub const Info = struct {
+ version: u8,
+};
+
+pub const diamond_info = Info{ .version = 0 };
+
+test "comptime modification of const struct field" {
+ comptime {
+ var res = diamond_info;
+ res.version = 1;
+ assertOrPanic(diamond_info.version == 0);
+ assertOrPanic(res.version == 1);
+ }
+}
+
+test "pointer to type" {
+ comptime {
+ var T: type = i32;
+ assertOrPanic(T == i32);
+ var ptr = &T;
+ assertOrPanic(@typeOf(ptr) == *type);
+ ptr.* = f32;
+ assertOrPanic(T == f32);
+ assertOrPanic(*T == *f32);
+ }
+}
+
+test "slice of type" {
+ comptime {
+ var types_array = []type{ i32, f64, type };
+ for (types_array) |T, i| {
+ switch (i) {
+ 0 => assertOrPanic(T == i32),
+ 1 => assertOrPanic(T == f64),
+ 2 => assertOrPanic(T == type),
+ else => unreachable,
+ }
+ }
+ for (types_array[0..]) |T, i| {
+ switch (i) {
+ 0 => assertOrPanic(T == i32),
+ 1 => assertOrPanic(T == f64),
+ 2 => assertOrPanic(T == type),
+ else => unreachable,
+ }
+ }
+ }
+}
+
+const Wrapper = struct {
+ T: type,
+};
+
+fn wrap(comptime T: type) Wrapper {
+ return Wrapper{ .T = T };
+}
+
+test "function which returns struct with type field causes implicit comptime" {
+ const ty = wrap(i32).T;
+ assertOrPanic(ty == i32);
+}
+
+test "call method with comptime pass-by-non-copying-value self parameter" {
+ const S = struct {
+ a: u8,
+
+ fn b(comptime s: @This()) u8 {
+ return s.a;
+ }
+ };
+
+ const s = S{ .a = 2 };
+ var b = s.b();
+ assertOrPanic(b == 2);
+}
+
+test "@tagName of @typeId" {
+ const str = @tagName(@typeId(u8));
+ assertOrPanic(std.mem.eql(u8, str, "Int"));
+}
+
+test "setting backward branch quota just before a generic fn call" {
+ @setEvalBranchQuota(1001);
+ loopNTimes(1001);
+}
+
+fn loopNTimes(comptime n: usize) void {
+ comptime var i = 0;
+ inline while (i < n) : (i += 1) {}
+}
+
+test "variable inside inline loop that has different types on different iterations" {
+ testVarInsideInlineLoop(true, u32(42));
+}
+
+fn testVarInsideInlineLoop(args: ...) void {
+ comptime var i = 0;
+ inline while (i < args.len) : (i += 1) {
+ const x = args[i];
+ if (i == 0) assertOrPanic(x);
+ if (i == 1) assertOrPanic(x == 42);
+ }
+}
+
+test "inline for with same type but different values" {
+ var res: usize = 0;
+ inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| {
+ var a: T = undefined;
+ res += a.len;
+ }
+ assertOrPanic(res == 5);
+}
+
+test "refer to the type of a generic function" {
+ const Func = fn (type) void;
+ const f: Func = doNothingWithType;
+ f(i32);
+}
+
+fn doNothingWithType(comptime T: type) void {}
+
+test "zero extend from u0 to u1" {
+ var zero_u0: u0 = 0;
+ var zero_u1: u1 = zero_u0;
+ assertOrPanic(zero_u1 == 0);
+}
+
+test "bit shift a u1" {
+ var x: u1 = 1;
+ var y = x << 0;
+ assertOrPanic(y == 1);
+}
+
+test "@intCast to a u0" {
+ var x: u8 = 0;
+ var y: u0 = @intCast(u0, x);
+ assertOrPanic(y == 0);
+}
+
+test "@bytesToslice on a packed struct" {
+ const F = packed struct {
+ a: u8,
+ };
+
+ var b = [1]u8{9};
+ var f = @bytesToSlice(F, b);
+ assertOrPanic(f[0].a == 9);
+}
+
+test "comptime pointer cast array and then slice" {
+ const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
+
+ const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
+ const sliceA: []const u8 = ptrA[0..2];
+
+ const ptrB: [*]const u8 = &array;
+ const sliceB: []const u8 = ptrB[0..2];
+
+ assertOrPanic(sliceA[1] == 2);
+ assertOrPanic(sliceB[1] == 2);
+}
+
+test "slice bounds in comptime concatenation" {
+ const bs = comptime blk: {
+ const b = c"........1........";
+ break :blk b[8..9];
+ };
+ const str = "" ++ bs;
+ assertOrPanic(str.len == 1);
+ assertOrPanic(std.mem.eql(u8, str, "1"));
+
+ const str2 = bs ++ "";
+ assertOrPanic(str2.len == 1);
+ assertOrPanic(std.mem.eql(u8, str2, "1"));
+}
+
+test "comptime bitwise operators" {
+ comptime {
+ assertOrPanic(3 & 1 == 1);
+ assertOrPanic(3 & -1 == 3);
+ assertOrPanic(-3 & -1 == -3);
+ assertOrPanic(3 | -1 == -1);
+ assertOrPanic(-3 | -1 == -1);
+ assertOrPanic(3 ^ -1 == -4);
+ assertOrPanic(-3 ^ -1 == 2);
+ assertOrPanic(~i8(-1) == 0);
+ assertOrPanic(~i128(-1) == 0);
+ assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
+ assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
+ assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff);
+ }
+}
+
+test "*align(1) u16 is the same as *align(1:0:2) u16" {
+ comptime {
+ assertOrPanic(*align(1:0:2) u16 == *align(1) u16);
+ // TODO add parsing support for this syntax
+ //assertOrPanic(*align(:0:2) u16 == *u16);
+ }
+}
+
+test "array concatenation forces comptime" {
+ var a = oneItem(3) ++ oneItem(4);
+ assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 }));
+}
+
+test "array multiplication forces comptime" {
+ var a = oneItem(3) ** scalar(2);
+ assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 }));
+}
+
+fn oneItem(x: i32) [1]i32 {
+ return []i32{x};
+}
+
+fn scalar(x: u32) u32 {
+ return x;
+}
diff --git a/test/stage1/behavior/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig
new file mode 100644
index 0000000000000000000000000000000000000000..ed2487c02081d059431989d21c31c5511a69bc54
--- /dev/null
+++ b/test/stage1/behavior/field_parent_ptr.zig
@@ -0,0 +1,41 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@fieldParentPtr non-first field" {
+ testParentFieldPtr(&foo.c);
+ comptime testParentFieldPtr(&foo.c);
+}
+
+test "@fieldParentPtr first field" {
+ testParentFieldPtrFirst(&foo.a);
+ comptime testParentFieldPtrFirst(&foo.a);
+}
+
+const Foo = struct {
+ a: bool,
+ b: f32,
+ c: i32,
+ d: i32,
+};
+
+const foo = Foo{
+ .a = true,
+ .b = 0.123,
+ .c = 1234,
+ .d = -10,
+};
+
+fn testParentFieldPtr(c: *const i32) void {
+ assertOrPanic(c == &foo.c);
+
+ const base = @fieldParentPtr(Foo, "c", c);
+ assertOrPanic(base == &foo);
+ assertOrPanic(&base.c == c);
+}
+
+fn testParentFieldPtrFirst(a: *const bool) void {
+ assertOrPanic(a == &foo.a);
+
+ const base = @fieldParentPtr(Foo, "a", a);
+ assertOrPanic(base == &foo);
+ assertOrPanic(&base.a == a);
+}
diff --git a/test/stage1/behavior/fn.zig b/test/stage1/behavior/fn.zig
new file mode 100644
index 0000000000000000000000000000000000000000..3011bc41d0746b316f816e94c3374bbc8b554a5f
--- /dev/null
+++ b/test/stage1/behavior/fn.zig
@@ -0,0 +1,208 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "params" {
+ assertOrPanic(testParamsAdd(22, 11) == 33);
+}
+fn testParamsAdd(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "local variables" {
+ testLocVars(2);
+}
+fn testLocVars(b: i32) void {
+ const a: i32 = 1;
+ if (a + b != 3) unreachable;
+}
+
+test "void parameters" {
+ voidFun(1, void{}, 2, {});
+}
+fn voidFun(a: i32, b: void, c: i32, d: void) void {
+ const v = b;
+ const vv: void = if (a == 1) v else {};
+ assertOrPanic(a + c == 3);
+ return vv;
+}
+
+test "mutable local variables" {
+ var zero: i32 = 0;
+ assertOrPanic(zero == 0);
+
+ var i = i32(0);
+ while (i != 3) {
+ i += 1;
+ }
+ assertOrPanic(i == 3);
+}
+
+test "separate block scopes" {
+ {
+ const no_conflict: i32 = 5;
+ assertOrPanic(no_conflict == 5);
+ }
+
+ const c = x: {
+ const no_conflict = i32(10);
+ break :x no_conflict;
+ };
+ assertOrPanic(c == 10);
+}
+
+test "call function with empty string" {
+ acceptsString("");
+}
+
+fn acceptsString(foo: []u8) void {}
+
+fn @"weird function name"() i32 {
+ return 1234;
+}
+test "weird function name" {
+ assertOrPanic(@"weird function name"() == 1234);
+}
+
+test "implicit cast function unreachable return" {
+ wantsFnWithVoid(fnWithUnreachable);
+}
+
+fn wantsFnWithVoid(f: fn () void) void {}
+
+fn fnWithUnreachable() noreturn {
+ unreachable;
+}
+
+test "function pointers" {
+ const fns = []@typeOf(fn1){
+ fn1,
+ fn2,
+ fn3,
+ fn4,
+ };
+ for (fns) |f, i| {
+ assertOrPanic(f() == @intCast(u32, i) + 5);
+ }
+}
+fn fn1() u32 {
+ return 5;
+}
+fn fn2() u32 {
+ return 6;
+}
+fn fn3() u32 {
+ return 7;
+}
+fn fn4() u32 {
+ return 8;
+}
+
+test "inline function call" {
+ assertOrPanic(@inlineCall(add, 3, 9) == 12);
+}
+
+fn add(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "number literal as an argument" {
+ numberLiteralArg(3);
+ comptime numberLiteralArg(3);
+}
+
+fn numberLiteralArg(a: var) void {
+ assertOrPanic(a == 3);
+}
+
+test "assign inline fn to const variable" {
+ const a = inlineFn;
+ a();
+}
+
+inline fn inlineFn() void {}
+
+test "pass by non-copying value" {
+ assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+const Point = struct {
+ x: i32,
+ y: i32,
+};
+
+fn addPointCoords(pt: Point) i32 {
+ return pt.x + pt.y;
+}
+
+test "pass by non-copying value through var arg" {
+ assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+fn addPointCoordsVar(pt: var) i32 {
+ comptime assertOrPanic(@typeOf(pt) == Point);
+ return pt.x + pt.y;
+}
+
+test "pass by non-copying value as method" {
+ var pt = Point2{ .x = 1, .y = 2 };
+ assertOrPanic(pt.addPointCoords() == 3);
+}
+
+const Point2 = struct {
+ x: i32,
+ y: i32,
+
+ fn addPointCoords(self: Point2) i32 {
+ return self.x + self.y;
+ }
+};
+
+test "pass by non-copying value as method, which is generic" {
+ var pt = Point3{ .x = 1, .y = 2 };
+ assertOrPanic(pt.addPointCoords(i32) == 3);
+}
+
+const Point3 = struct {
+ x: i32,
+ y: i32,
+
+ fn addPointCoords(self: Point3, comptime T: type) i32 {
+ return self.x + self.y;
+ }
+};
+
+test "pass by non-copying value as method, at comptime" {
+ comptime {
+ var pt = Point2{ .x = 1, .y = 2 };
+ assertOrPanic(pt.addPointCoords() == 3);
+ }
+}
+
+fn outer(y: u32) fn (u32) u32 {
+ const Y = @typeOf(y);
+ const st = struct {
+ fn get(z: u32) u32 {
+ return z + @sizeOf(Y);
+ }
+ };
+ return st.get;
+}
+
+test "return inner function which references comptime variable of outer function" {
+ var func = outer(10);
+ assertOrPanic(func(3) == 7);
+}
+
+test "extern struct with stdcallcc fn pointer" {
+ const S = extern struct {
+ ptr: stdcallcc fn () i32,
+
+ stdcallcc fn foo() i32 {
+ return 1234;
+ }
+ };
+
+ var s: S = undefined;
+ s.ptr = S.foo;
+ assertOrPanic(s.ptr() == 1234);
+}
+
diff --git a/test/stage1/behavior/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig
new file mode 100644
index 0000000000000000000000000000000000000000..0af076d40acfd848a05f6785243eeaecd2b56351
--- /dev/null
+++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig
@@ -0,0 +1,17 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+fn get_foo() fn (*u8) usize {
+ comptime {
+ return struct {
+ fn func(ptr: *u8) usize {
+ var u = @ptrToInt(ptr);
+ return u;
+ }
+ }.func;
+ }
+}
+
+test "define a function in an anonymous struct in comptime" {
+ const foo = get_foo();
+ assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345);
+}
diff --git a/test/stage1/behavior/for.zig b/test/stage1/behavior/for.zig
new file mode 100644
index 0000000000000000000000000000000000000000..b6d1ef24c42f58b3d349192267d494d64538d1ef
--- /dev/null
+++ b/test/stage1/behavior/for.zig
@@ -0,0 +1,106 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const mem = std.mem;
+
+test "continue in for loop" {
+ const array = []i32{
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ };
+ var sum: i32 = 0;
+ for (array) |x| {
+ sum += x;
+ if (x < 3) {
+ continue;
+ }
+ break;
+ }
+ if (sum != 6) unreachable;
+}
+
+test "for loop with pointer elem var" {
+ const source = "abcdefg";
+ var target: [source.len]u8 = undefined;
+ mem.copy(u8, target[0..], source);
+ mangleString(target[0..]);
+ assertOrPanic(mem.eql(u8, target, "bcdefgh"));
+}
+fn mangleString(s: []u8) void {
+ for (s) |*c| {
+ c.* += 1;
+ }
+}
+
+test "basic for loop" {
+ const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
+
+ var buffer: [expected_result.len]u8 = undefined;
+ var buf_index: usize = 0;
+
+ const array = []u8{ 9, 8, 7, 6 };
+ for (array) |item| {
+ buffer[buf_index] = item;
+ buf_index += 1;
+ }
+ for (array) |item, index| {
+ buffer[buf_index] = @intCast(u8, index);
+ buf_index += 1;
+ }
+ const array_ptr = &array;
+ for (array_ptr) |item| {
+ buffer[buf_index] = item;
+ buf_index += 1;
+ }
+ for (array_ptr) |item, index| {
+ buffer[buf_index] = @intCast(u8, index);
+ buf_index += 1;
+ }
+ const unknown_size: []const u8 = array;
+ for (unknown_size) |item| {
+ buffer[buf_index] = item;
+ buf_index += 1;
+ }
+ for (unknown_size) |item, index| {
+ buffer[buf_index] = @intCast(u8, index);
+ buf_index += 1;
+ }
+
+ assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result));
+}
+
+test "break from outer for loop" {
+ testBreakOuter();
+ comptime testBreakOuter();
+}
+
+fn testBreakOuter() void {
+ var array = "aoeu";
+ var count: usize = 0;
+ outer: for (array) |_| {
+ for (array) |_| {
+ count += 1;
+ break :outer;
+ }
+ }
+ assertOrPanic(count == 1);
+}
+
+test "continue outer for loop" {
+ testContinueOuter();
+ comptime testContinueOuter();
+}
+
+fn testContinueOuter() void {
+ var array = "aoeu";
+ var counter: usize = 0;
+ outer: for (array) |_| {
+ for (array) |_| {
+ counter += 1;
+ continue :outer;
+ }
+ }
+ assertOrPanic(counter == array.len);
+}
diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a0928634a7c3180411f22137ddffd2dffce30a13
--- /dev/null
+++ b/test/stage1/behavior/generics.zig
@@ -0,0 +1,151 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "simple generic fn" {
+ assertOrPanic(max(i32, 3, -1) == 3);
+ assertOrPanic(max(f32, 0.123, 0.456) == 0.456);
+ assertOrPanic(add(2, 3) == 5);
+}
+
+fn max(comptime T: type, a: T, b: T) T {
+ return if (a > b) a else b;
+}
+
+fn add(comptime a: i32, b: i32) i32 {
+ return (comptime a) + b;
+}
+
+const the_max = max(u32, 1234, 5678);
+test "compile time generic eval" {
+ assertOrPanic(the_max == 5678);
+}
+
+fn gimmeTheBigOne(a: u32, b: u32) u32 {
+ return max(u32, a, b);
+}
+
+fn shouldCallSameInstance(a: u32, b: u32) u32 {
+ return max(u32, a, b);
+}
+
+fn sameButWithFloats(a: f64, b: f64) f64 {
+ return max(f64, a, b);
+}
+
+test "fn with comptime args" {
+ assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678);
+ assertOrPanic(shouldCallSameInstance(34, 12) == 34);
+ assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49);
+}
+
+test "var params" {
+ assertOrPanic(max_i32(12, 34) == 34);
+ assertOrPanic(max_f64(1.2, 3.4) == 3.4);
+}
+
+comptime {
+ assertOrPanic(max_i32(12, 34) == 34);
+ assertOrPanic(max_f64(1.2, 3.4) == 3.4);
+}
+
+fn max_var(a: var, b: var) @typeOf(a + b) {
+ return if (a > b) a else b;
+}
+
+fn max_i32(a: i32, b: i32) i32 {
+ return max_var(a, b);
+}
+
+fn max_f64(a: f64, b: f64) f64 {
+ return max_var(a, b);
+}
+
+pub fn List(comptime T: type) type {
+ return SmallList(T, 8);
+}
+
+pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type {
+ return struct {
+ items: []T,
+ length: usize,
+ prealloc_items: [STATIC_SIZE]T,
+ };
+}
+
+test "function with return type type" {
+ var list: List(i32) = undefined;
+ var list2: List(i32) = undefined;
+ list.length = 10;
+ list2.length = 10;
+ assertOrPanic(list.prealloc_items.len == 8);
+ assertOrPanic(list2.prealloc_items.len == 8);
+}
+
+test "generic struct" {
+ var a1 = GenNode(i32){
+ .value = 13,
+ .next = null,
+ };
+ var b1 = GenNode(bool){
+ .value = true,
+ .next = null,
+ };
+ assertOrPanic(a1.value == 13);
+ assertOrPanic(a1.value == a1.getVal());
+ assertOrPanic(b1.getVal());
+}
+fn GenNode(comptime T: type) type {
+ return struct {
+ value: T,
+ next: ?*GenNode(T),
+ fn getVal(n: *const GenNode(T)) T {
+ return n.value;
+ }
+ };
+}
+
+test "const decls in struct" {
+ assertOrPanic(GenericDataThing(3).count_plus_one == 4);
+}
+fn GenericDataThing(comptime count: isize) type {
+ return struct {
+ const count_plus_one = count + 1;
+ };
+}
+
+test "use generic param in generic param" {
+ assertOrPanic(aGenericFn(i32, 3, 4) == 7);
+}
+fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
+ return a + b;
+}
+
+test "generic fn with implicit cast" {
+ assertOrPanic(getFirstByte(u8, []u8{13}) == 13);
+ assertOrPanic(getFirstByte(u16, []u16{
+ 0,
+ 13,
+ }) == 0);
+}
+fn getByte(ptr: ?*const u8) u8 {
+ return ptr.?.*;
+}
+fn getFirstByte(comptime T: type, mem: []const T) u8 {
+ return getByte(@ptrCast(*const u8, &mem[0]));
+}
+
+const foos = []fn (var) bool{
+ foo1,
+ foo2,
+};
+
+fn foo1(arg: var) bool {
+ return arg;
+}
+fn foo2(arg: var) bool {
+ return !arg;
+}
+
+test "array of generic fns" {
+ assertOrPanic(foos[0](true));
+ assertOrPanic(!foos[1](true));
+}
diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig
new file mode 100644
index 0000000000000000000000000000000000000000..58d1b8fd734f5e5d2047430cb80fb425f6a7e3af
--- /dev/null
+++ b/test/stage1/behavior/if.zig
@@ -0,0 +1,37 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "if statements" {
+ shouldBeEqual(1, 1);
+ firstEqlThird(2, 1, 2);
+}
+fn shouldBeEqual(a: i32, b: i32) void {
+ if (a != b) {
+ unreachable;
+ } else {
+ return;
+ }
+}
+fn firstEqlThird(a: i32, b: i32, c: i32) void {
+ if (a == b) {
+ unreachable;
+ } else if (b == c) {
+ unreachable;
+ } else if (a == c) {
+ return;
+ } else {
+ unreachable;
+ }
+}
+
+test "else if expression" {
+ assertOrPanic(elseIfExpressionF(1) == 1);
+}
+fn elseIfExpressionF(c: u8) u8 {
+ if (c == 0) {
+ return 0;
+ } else if (c == 1) {
+ return 1;
+ } else {
+ return u8(2);
+ }
+}
diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig
new file mode 100644
index 0000000000000000000000000000000000000000..736e4c219ddc6f4e9d5c286fbd93c9c48df6d2ee
--- /dev/null
+++ b/test/stage1/behavior/import.zig
@@ -0,0 +1,10 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const a_namespace = @import("import/a_namespace.zig");
+
+test "call fn via namespace lookup" {
+ assertOrPanic(a_namespace.foo() == 1234);
+}
+
+test "importing the same thing gives the same import" {
+ assertOrPanic(@import("std") == @import("std"));
+}
diff --git a/test/stage1/behavior/import/a_namespace.zig b/test/stage1/behavior/import/a_namespace.zig
new file mode 100644
index 0000000000000000000000000000000000000000..042f1867a5dd72fc0216b40f7f56962b7a8a8e9a
--- /dev/null
+++ b/test/stage1/behavior/import/a_namespace.zig
@@ -0,0 +1,3 @@
+pub fn foo() i32 {
+ return 1234;
+}
diff --git a/test/stage1/behavior/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig
new file mode 100644
index 0000000000000000000000000000000000000000..d062311b2e9fe2d44c9b243d00ad32ff6a0fb9ad
--- /dev/null
+++ b/test/stage1/behavior/incomplete_struct_param_tld.zig
@@ -0,0 +1,30 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const A = struct {
+ b: B,
+};
+
+const B = struct {
+ c: C,
+};
+
+const C = struct {
+ x: i32,
+
+ fn d(c: *const C) i32 {
+ return c.x;
+ }
+};
+
+fn foo(a: A) i32 {
+ return a.b.c.d();
+}
+
+test "incomplete struct param top level declaration" {
+ const a = A{
+ .b = B{
+ .c = C{ .x = 13 },
+ },
+ };
+ assertOrPanic(foo(a) == 13);
+}
diff --git a/test/stage1/behavior/inttoptr.zig b/test/stage1/behavior/inttoptr.zig
new file mode 100644
index 0000000000000000000000000000000000000000..bf657fc86a9c720d1be79b352aee94dc8031e150
--- /dev/null
+++ b/test/stage1/behavior/inttoptr.zig
@@ -0,0 +1,26 @@
+const builtin = @import("builtin");
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "casting random address to function pointer" {
+ randomAddressToFunction();
+ comptime randomAddressToFunction();
+}
+
+fn randomAddressToFunction() void {
+ var addr: usize = 0xdeadbeef;
+ var ptr = @intToPtr(fn () void, addr);
+}
+
+test "mutate through ptr initialized with constant intToPtr value" {
+ forceCompilerAnalyzeBranchHardCodedPtrDereference(false);
+}
+
+fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
+ const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef);
+ if (x) {
+ hardCodedP.* = hardCodedP.* | 10;
+ } else {
+ return;
+ }
+}
diff --git a/test/stage1/behavior/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig
new file mode 100644
index 0000000000000000000000000000000000000000..bc61e11df7a212a53315e05d910a879fb5553ff3
--- /dev/null
+++ b/test/stage1/behavior/ir_block_deps.zig
@@ -0,0 +1,21 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+fn foo(id: u64) !i32 {
+ return switch (id) {
+ 1 => getErrInt(),
+ 2 => {
+ const size = try getErrInt();
+ return try getErrInt();
+ },
+ else => error.ItBroke,
+ };
+}
+
+fn getErrInt() anyerror!i32 {
+ return 0;
+}
+
+test "ir block deps" {
+ assertOrPanic((foo(1) catch unreachable) == 0);
+ assertOrPanic((foo(2) catch unreachable) == 0);
+}
diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig
new file mode 100644
index 0000000000000000000000000000000000000000..9d6a5a499799273335bc8c5d1dd3142131d5b1ff
--- /dev/null
+++ b/test/stage1/behavior/math.zig
@@ -0,0 +1,500 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const maxInt = std.math.maxInt;
+const minInt = std.math.minInt;
+
+test "division" {
+ testDivision();
+ comptime testDivision();
+}
+fn testDivision() void {
+ assertOrPanic(div(u32, 13, 3) == 4);
+ assertOrPanic(div(f16, 1.0, 2.0) == 0.5);
+ assertOrPanic(div(f32, 1.0, 2.0) == 0.5);
+
+ assertOrPanic(divExact(u32, 55, 11) == 5);
+ assertOrPanic(divExact(i32, -55, 11) == -5);
+ assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0);
+ assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0);
+ assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0);
+ assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0);
+
+ assertOrPanic(divFloor(i32, 5, 3) == 1);
+ assertOrPanic(divFloor(i32, -5, 3) == -2);
+ assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0);
+ assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0);
+ assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0);
+ assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0);
+ assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000);
+ assertOrPanic(divFloor(i32, 0, -0x80000000) == 0);
+ assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2);
+ assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000);
+
+ assertOrPanic(divTrunc(i32, 5, 3) == 1);
+ assertOrPanic(divTrunc(i32, -5, 3) == -1);
+ assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0);
+ assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0);
+ assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0);
+
+ comptime {
+ assertOrPanic(
+ 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600,
+ );
+ assertOrPanic(
+ @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600,
+ );
+ assertOrPanic(
+ 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2,
+ );
+ assertOrPanic(
+ @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2,
+ );
+ assertOrPanic(
+ @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2,
+ );
+ assertOrPanic(
+ @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2,
+ );
+ assertOrPanic(
+ 4126227191251978491697987544882340798050766755606969681711 % 10 == 1,
+ );
+ }
+}
+fn div(comptime T: type, a: T, b: T) T {
+ return a / b;
+}
+fn divExact(comptime T: type, a: T, b: T) T {
+ return @divExact(a, b);
+}
+fn divFloor(comptime T: type, a: T, b: T) T {
+ return @divFloor(a, b);
+}
+fn divTrunc(comptime T: type, a: T, b: T) T {
+ return @divTrunc(a, b);
+}
+
+test "@addWithOverflow" {
+ var result: u8 = undefined;
+ assertOrPanic(@addWithOverflow(u8, 250, 100, &result));
+ assertOrPanic(!@addWithOverflow(u8, 100, 150, &result));
+ assertOrPanic(result == 250);
+}
+
+// TODO test mulWithOverflow
+// TODO test subWithOverflow
+
+test "@shlWithOverflow" {
+ var result: u16 = undefined;
+ assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
+ assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
+ assertOrPanic(result == 0b1011111111111100);
+}
+
+test "@clz" {
+ testClz();
+ comptime testClz();
+}
+
+fn testClz() void {
+ assertOrPanic(clz(u8(0b00001010)) == 4);
+ assertOrPanic(clz(u8(0b10001010)) == 0);
+ assertOrPanic(clz(u8(0b00000000)) == 8);
+ assertOrPanic(clz(u128(0xffffffffffffffff)) == 64);
+ assertOrPanic(clz(u128(0x10000000000000000)) == 63);
+}
+
+fn clz(x: var) usize {
+ return @clz(x);
+}
+
+test "@ctz" {
+ testCtz();
+ comptime testCtz();
+}
+
+fn testCtz() void {
+ assertOrPanic(ctz(u8(0b10100000)) == 5);
+ assertOrPanic(ctz(u8(0b10001010)) == 1);
+ assertOrPanic(ctz(u8(0b00000000)) == 8);
+}
+
+fn ctz(x: var) usize {
+ return @ctz(x);
+}
+
+test "assignment operators" {
+ var i: u32 = 0;
+ i += 5;
+ assertOrPanic(i == 5);
+ i -= 2;
+ assertOrPanic(i == 3);
+ i *= 20;
+ assertOrPanic(i == 60);
+ i /= 3;
+ assertOrPanic(i == 20);
+ i %= 11;
+ assertOrPanic(i == 9);
+ i <<= 1;
+ assertOrPanic(i == 18);
+ i >>= 2;
+ assertOrPanic(i == 4);
+ i = 6;
+ i &= 5;
+ assertOrPanic(i == 4);
+ i ^= 6;
+ assertOrPanic(i == 2);
+ i = 6;
+ i |= 3;
+ assertOrPanic(i == 7);
+}
+
+test "three expr in a row" {
+ testThreeExprInARow(false, true);
+ comptime testThreeExprInARow(false, true);
+}
+fn testThreeExprInARow(f: bool, t: bool) void {
+ assertFalse(f or f or f);
+ assertFalse(t and t and f);
+ assertFalse(1 | 2 | 4 != 7);
+ assertFalse(3 ^ 6 ^ 8 != 13);
+ assertFalse(7 & 14 & 28 != 4);
+ assertFalse(9 << 1 << 2 != 9 << 3);
+ assertFalse(90 >> 1 >> 2 != 90 >> 3);
+ assertFalse(100 - 1 + 1000 != 1099);
+ assertFalse(5 * 4 / 2 % 3 != 1);
+ assertFalse(i32(i32(5)) != 5);
+ assertFalse(!!false);
+ assertFalse(i32(7) != --(i32(7)));
+}
+fn assertFalse(b: bool) void {
+ assertOrPanic(!b);
+}
+
+test "const number literal" {
+ const one = 1;
+ const eleven = ten + one;
+
+ assertOrPanic(eleven == 11);
+}
+const ten = 10;
+
+test "unsigned wrapping" {
+ testUnsignedWrappingEval(maxInt(u32));
+ comptime testUnsignedWrappingEval(maxInt(u32));
+}
+fn testUnsignedWrappingEval(x: u32) void {
+ const zero = x +% 1;
+ assertOrPanic(zero == 0);
+ const orig = zero -% 1;
+ assertOrPanic(orig == maxInt(u32));
+}
+
+test "signed wrapping" {
+ testSignedWrappingEval(maxInt(i32));
+ comptime testSignedWrappingEval(maxInt(i32));
+}
+fn testSignedWrappingEval(x: i32) void {
+ const min_val = x +% 1;
+ assertOrPanic(min_val == minInt(i32));
+ const max_val = min_val -% 1;
+ assertOrPanic(max_val == maxInt(i32));
+}
+
+test "negation wrapping" {
+ testNegationWrappingEval(minInt(i16));
+ comptime testNegationWrappingEval(minInt(i16));
+}
+fn testNegationWrappingEval(x: i16) void {
+ assertOrPanic(x == -32768);
+ const neg = -%x;
+ assertOrPanic(neg == -32768);
+}
+
+test "unsigned 64-bit division" {
+ test_u64_div();
+ comptime test_u64_div();
+}
+fn test_u64_div() void {
+ const result = divWithResult(1152921504606846976, 34359738365);
+ assertOrPanic(result.quotient == 33554432);
+ assertOrPanic(result.remainder == 100663296);
+}
+fn divWithResult(a: u64, b: u64) DivResult {
+ return DivResult{
+ .quotient = a / b,
+ .remainder = a % b,
+ };
+}
+const DivResult = struct {
+ quotient: u64,
+ remainder: u64,
+};
+
+test "binary not" {
+ assertOrPanic(comptime x: {
+ break :x ~u16(0b1010101010101010) == 0b0101010101010101;
+ });
+ assertOrPanic(comptime x: {
+ break :x ~u64(2147483647) == 18446744071562067968;
+ });
+ testBinaryNot(0b1010101010101010);
+}
+
+fn testBinaryNot(x: u16) void {
+ assertOrPanic(~x == 0b0101010101010101);
+}
+
+test "small int addition" {
+ var x: @IntType(false, 2) = 0;
+ assertOrPanic(x == 0);
+
+ x += 1;
+ assertOrPanic(x == 1);
+
+ x += 1;
+ assertOrPanic(x == 2);
+
+ x += 1;
+ assertOrPanic(x == 3);
+
+ var result: @typeOf(x) = 3;
+ assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result));
+
+ assertOrPanic(result == 0);
+}
+
+test "float equality" {
+ const x: f64 = 0.012;
+ const y: f64 = x + 1.0;
+
+ testFloatEqualityImpl(x, y);
+ comptime testFloatEqualityImpl(x, y);
+}
+
+fn testFloatEqualityImpl(x: f64, y: f64) void {
+ const y2 = x + 1.0;
+ assertOrPanic(y == y2);
+}
+
+test "allow signed integer division/remainder when values are comptime known and positive or exact" {
+ assertOrPanic(5 / 3 == 1);
+ assertOrPanic(-5 / -3 == 1);
+ assertOrPanic(-6 / 3 == -2);
+
+ assertOrPanic(5 % 3 == 2);
+ assertOrPanic(-6 % 3 == 0);
+}
+
+test "hex float literal parsing" {
+ comptime assertOrPanic(0x1.0 == 1.0);
+}
+
+test "quad hex float literal parsing in range" {
+ const a = 0x1.af23456789bbaaab347645365cdep+5;
+ const b = 0x1.dedafcff354b6ae9758763545432p-9;
+ const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
+ const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
+}
+
+test "quad hex float literal parsing accurate" {
+ const a: f128 = 0x1.1111222233334444555566667777p+0;
+
+ // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
+ const expected: u128 = 0x3fff1111222233334444555566667777;
+ assertOrPanic(@bitCast(u128, a) == expected);
+}
+
+test "hex float literal within range" {
+ const a = 0x1.0p16383;
+ const b = 0x0.1p16387;
+ const c = 0x1.0p-16382;
+}
+
+test "truncating shift left" {
+ testShlTrunc(maxInt(u16));
+ comptime testShlTrunc(maxInt(u16));
+}
+fn testShlTrunc(x: u16) void {
+ const shifted = x << 1;
+ assertOrPanic(shifted == 65534);
+}
+
+test "truncating shift right" {
+ testShrTrunc(maxInt(u16));
+ comptime testShrTrunc(maxInt(u16));
+}
+fn testShrTrunc(x: u16) void {
+ const shifted = x >> 1;
+ assertOrPanic(shifted == 32767);
+}
+
+test "exact shift left" {
+ testShlExact(0b00110101);
+ comptime testShlExact(0b00110101);
+}
+fn testShlExact(x: u8) void {
+ const shifted = @shlExact(x, 2);
+ assertOrPanic(shifted == 0b11010100);
+}
+
+test "exact shift right" {
+ testShrExact(0b10110100);
+ comptime testShrExact(0b10110100);
+}
+fn testShrExact(x: u8) void {
+ const shifted = @shrExact(x, 2);
+ assertOrPanic(shifted == 0b00101101);
+}
+
+test "comptime_int addition" {
+ comptime {
+ assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
+ assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
+ }
+}
+
+test "comptime_int multiplication" {
+ comptime {
+ assertOrPanic(
+ 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
+ );
+ assertOrPanic(
+ 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
+ );
+ }
+}
+
+test "comptime_int shifting" {
+ comptime {
+ assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000);
+ }
+}
+
+test "comptime_int multi-limb shift and mask" {
+ comptime {
+ var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
+
+ assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab);
+ a >>= 32;
+ assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef);
+ a >>= 32;
+ assertOrPanic(u32(a & 0xffffffff) == 0xa0000001);
+ a >>= 32;
+ assertOrPanic(u32(a & 0xffffffff) == 0xefffffff);
+ a >>= 32;
+
+ assertOrPanic(a == 0);
+ }
+}
+
+test "comptime_int multi-limb partial shift right" {
+ comptime {
+ var a = 0x1ffffffffeeeeeeee;
+ a >>= 16;
+ assertOrPanic(a == 0x1ffffffffeeee);
+ }
+}
+
+test "xor" {
+ test_xor();
+ comptime test_xor();
+}
+
+fn test_xor() void {
+ assertOrPanic(0xFF ^ 0x00 == 0xFF);
+ assertOrPanic(0xF0 ^ 0x0F == 0xFF);
+ assertOrPanic(0xFF ^ 0xF0 == 0x0F);
+ assertOrPanic(0xFF ^ 0x0F == 0xF0);
+ assertOrPanic(0xFF ^ 0xFF == 0x00);
+}
+
+test "comptime_int xor" {
+ comptime {
+ assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
+ assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
+ assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
+ assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
+ assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
+ }
+}
+
+test "f128" {
+ test_f128();
+ comptime test_f128();
+}
+
+fn make_f128(x: f128) f128 {
+ return x;
+}
+
+fn test_f128() void {
+ assertOrPanic(@sizeOf(f128) == 16);
+ assertOrPanic(make_f128(1.0) == 1.0);
+ assertOrPanic(make_f128(1.0) != 1.1);
+ assertOrPanic(make_f128(1.0) > 0.9);
+ assertOrPanic(make_f128(1.0) >= 0.9);
+ assertOrPanic(make_f128(1.0) >= 1.0);
+ should_not_be_zero(1.0);
+}
+
+fn should_not_be_zero(x: f128) void {
+ assertOrPanic(x != 0.0);
+}
+
+test "comptime float rem int" {
+ comptime {
+ var x = f32(1) % 2;
+ assertOrPanic(x == 1.0);
+ }
+}
+
+test "remainder division" {
+ comptime remdiv(f16);
+ comptime remdiv(f32);
+ comptime remdiv(f64);
+ comptime remdiv(f128);
+ remdiv(f16);
+ remdiv(f64);
+ remdiv(f128);
+}
+
+fn remdiv(comptime T: type) void {
+ assertOrPanic(T(1) == T(1) % T(2));
+ assertOrPanic(T(1) == T(7) % T(3));
+}
+
+test "@sqrt" {
+ testSqrt(f64, 12.0);
+ comptime testSqrt(f64, 12.0);
+ testSqrt(f32, 13.0);
+ comptime testSqrt(f32, 13.0);
+ testSqrt(f16, 13.0);
+ comptime testSqrt(f16, 13.0);
+
+ const x = 14.0;
+ const y = x * x;
+ const z = @sqrt(@typeOf(y), y);
+ comptime assertOrPanic(z == x);
+}
+
+fn testSqrt(comptime T: type, x: T) void {
+ assertOrPanic(@sqrt(T, x * x) == x);
+}
+
+test "comptime_int param and return" {
+ const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
+ assertOrPanic(a == 137114567242441932203689521744947848950);
+
+ const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
+ assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380);
+}
+
+fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
+ return a + b;
+}
diff --git a/test/stage1/behavior/merge_error_sets.zig b/test/stage1/behavior/merge_error_sets.zig
new file mode 100644
index 0000000000000000000000000000000000000000..147b580232d10deaf9bc78715696c851aa92ae30
--- /dev/null
+++ b/test/stage1/behavior/merge_error_sets.zig
@@ -0,0 +1,21 @@
+const A = error{
+ FileNotFound,
+ NotDir,
+};
+const B = error{OutOfMemory};
+
+const C = A || B;
+
+fn foo() C!void {
+ return error.NotDir;
+}
+
+test "merge error sets" {
+ if (foo()) {
+ @panic("unexpected");
+ } else |err| switch (err) {
+ error.OutOfMemory => @panic("unexpected"),
+ error.FileNotFound => @panic("unexpected"),
+ error.NotDir => {},
+ }
+}
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
new file mode 100644
index 0000000000000000000000000000000000000000..8d2555ddddb390f928c6440024cfe008f58f6744
--- /dev/null
+++ b/test/stage1/behavior/misc.zig
@@ -0,0 +1,687 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const mem = std.mem;
+const cstr = std.cstr;
+const builtin = @import("builtin");
+const maxInt = std.math.maxInt;
+
+// normal comment
+
+/// this is a documentation comment
+/// doc comment line 2
+fn emptyFunctionWithComments() void {}
+
+test "empty function with comments" {
+ emptyFunctionWithComments();
+}
+
+comptime {
+ @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
+}
+
+extern fn disabledExternFn() void {}
+
+test "call disabled extern fn" {
+ disabledExternFn();
+}
+
+test "@IntType builtin" {
+ assertOrPanic(@IntType(true, 8) == i8);
+ assertOrPanic(@IntType(true, 16) == i16);
+ assertOrPanic(@IntType(true, 32) == i32);
+ assertOrPanic(@IntType(true, 64) == i64);
+
+ assertOrPanic(@IntType(false, 8) == u8);
+ assertOrPanic(@IntType(false, 16) == u16);
+ assertOrPanic(@IntType(false, 32) == u32);
+ assertOrPanic(@IntType(false, 64) == u64);
+
+ assertOrPanic(i8.bit_count == 8);
+ assertOrPanic(i16.bit_count == 16);
+ assertOrPanic(i32.bit_count == 32);
+ assertOrPanic(i64.bit_count == 64);
+
+ assertOrPanic(i8.is_signed);
+ assertOrPanic(i16.is_signed);
+ assertOrPanic(i32.is_signed);
+ assertOrPanic(i64.is_signed);
+ assertOrPanic(isize.is_signed);
+
+ assertOrPanic(!u8.is_signed);
+ assertOrPanic(!u16.is_signed);
+ assertOrPanic(!u32.is_signed);
+ assertOrPanic(!u64.is_signed);
+ assertOrPanic(!usize.is_signed);
+}
+
+test "floating point primitive bit counts" {
+ assertOrPanic(f16.bit_count == 16);
+ assertOrPanic(f32.bit_count == 32);
+ assertOrPanic(f64.bit_count == 64);
+}
+
+test "short circuit" {
+ testShortCircuit(false, true);
+ comptime testShortCircuit(false, true);
+}
+
+fn testShortCircuit(f: bool, t: bool) void {
+ var hit_1 = f;
+ var hit_2 = f;
+ var hit_3 = f;
+ var hit_4 = f;
+
+ if (t or x: {
+ assertOrPanic(f);
+ break :x f;
+ }) {
+ hit_1 = t;
+ }
+ if (f or x: {
+ hit_2 = t;
+ break :x f;
+ }) {
+ assertOrPanic(f);
+ }
+
+ if (t and x: {
+ hit_3 = t;
+ break :x f;
+ }) {
+ assertOrPanic(f);
+ }
+ if (f and x: {
+ assertOrPanic(f);
+ break :x f;
+ }) {
+ assertOrPanic(f);
+ } else {
+ hit_4 = t;
+ }
+ assertOrPanic(hit_1);
+ assertOrPanic(hit_2);
+ assertOrPanic(hit_3);
+ assertOrPanic(hit_4);
+}
+
+test "truncate" {
+ assertOrPanic(testTruncate(0x10fd) == 0xfd);
+}
+fn testTruncate(x: u32) u8 {
+ return @truncate(u8, x);
+}
+
+fn first4KeysOfHomeRow() []const u8 {
+ return "aoeu";
+}
+
+test "return string from function" {
+ assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
+}
+
+const g1: i32 = 1233 + 1;
+var g2: i32 = 0;
+
+test "global variables" {
+ assertOrPanic(g2 == 0);
+ g2 = g1;
+ assertOrPanic(g2 == 1234);
+}
+
+test "memcpy and memset intrinsics" {
+ var foo: [20]u8 = undefined;
+ var bar: [20]u8 = undefined;
+
+ @memset(foo[0..].ptr, 'A', foo.len);
+ @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);
+
+ if (bar[11] != 'A') unreachable;
+}
+
+test "builtin static eval" {
+ const x: i32 = comptime x: {
+ break :x 1 + 2 + 3;
+ };
+ assertOrPanic(x == comptime 6);
+}
+
+test "slicing" {
+ var array: [20]i32 = undefined;
+
+ array[5] = 1234;
+
+ var slice = array[5..10];
+
+ if (slice.len != 5) unreachable;
+
+ const ptr = &slice[0];
+ if (ptr.* != 1234) unreachable;
+
+ var slice_rest = array[10..];
+ if (slice_rest.len != 10) unreachable;
+}
+
+test "constant equal function pointers" {
+ const alias = emptyFn;
+ assertOrPanic(comptime x: {
+ break :x emptyFn == alias;
+ });
+}
+
+fn emptyFn() void {}
+
+test "hex escape" {
+ assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
+}
+
+test "string concatenation" {
+ assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
+}
+
+test "array mult operator" {
+ assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab"));
+}
+
+test "string escapes" {
+ assertOrPanic(mem.eql(u8, "\"", "\x22"));
+ assertOrPanic(mem.eql(u8, "\'", "\x27"));
+ assertOrPanic(mem.eql(u8, "\n", "\x0a"));
+ assertOrPanic(mem.eql(u8, "\r", "\x0d"));
+ assertOrPanic(mem.eql(u8, "\t", "\x09"));
+ assertOrPanic(mem.eql(u8, "\\", "\x5c"));
+ assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
+}
+
+test "multiline string" {
+ const s1 =
+ \\one
+ \\two)
+ \\three
+ ;
+ const s2 = "one\ntwo)\nthree";
+ assertOrPanic(mem.eql(u8, s1, s2));
+}
+
+test "multiline C string" {
+ const s1 =
+ c\\one
+ c\\two)
+ c\\three
+ ;
+ const s2 = c"one\ntwo)\nthree";
+ assertOrPanic(cstr.cmp(s1, s2) == 0);
+}
+
+test "type equality" {
+ assertOrPanic(*const u8 != *u8);
+}
+
+const global_a: i32 = 1234;
+const global_b: *const i32 = &global_a;
+const global_c: *const f32 = @ptrCast(*const f32, global_b);
+test "compile time global reinterpret" {
+ const d = @ptrCast(*const i32, global_c);
+ assertOrPanic(d.* == 1234);
+}
+
+test "explicit cast maybe pointers" {
+ const a: ?*i32 = undefined;
+ const b: ?*f32 = @ptrCast(?*f32, a);
+}
+
+test "generic malloc free" {
+ const a = memAlloc(u8, 10) catch unreachable;
+ memFree(u8, a);
+}
+var some_mem: [100]u8 = undefined;
+fn memAlloc(comptime T: type, n: usize) anyerror![]T {
+ return @ptrCast([*]T, &some_mem[0])[0..n];
+}
+fn memFree(comptime T: type, memory: []T) void {}
+
+test "cast undefined" {
+ const array: [100]u8 = undefined;
+ const slice = ([]const u8)(array);
+ testCastUndefined(slice);
+}
+fn testCastUndefined(x: []const u8) void {}
+
+test "cast small unsigned to larger signed" {
+ assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200));
+ assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
+}
+fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
+ return x;
+}
+fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
+ return x;
+}
+
+test "implicit cast after unreachable" {
+ assertOrPanic(outer() == 1234);
+}
+fn inner() i32 {
+ return 1234;
+}
+fn outer() i64 {
+ return inner();
+}
+
+test "pointer dereferencing" {
+ var x = i32(3);
+ const y = &x;
+
+ y.* += 1;
+
+ assertOrPanic(x == 4);
+ assertOrPanic(y.* == 4);
+}
+
+test "call result of if else expression" {
+ assertOrPanic(mem.eql(u8, f2(true), "a"));
+ assertOrPanic(mem.eql(u8, f2(false), "b"));
+}
+fn f2(x: bool) []const u8 {
+ return (if (x) fA else fB)();
+}
+fn fA() []const u8 {
+ return "a";
+}
+fn fB() []const u8 {
+ return "b";
+}
+
+test "const expression eval handling of variables" {
+ var x = true;
+ while (x) {
+ x = false;
+ }
+}
+
+test "constant enum initialization with differing sizes" {
+ test3_1(test3_foo);
+ test3_2(test3_bar);
+}
+const Test3Foo = union(enum) {
+ One: void,
+ Two: f32,
+ Three: Test3Point,
+};
+const Test3Point = struct {
+ x: i32,
+ y: i32,
+};
+const test3_foo = Test3Foo{
+ .Three = Test3Point{
+ .x = 3,
+ .y = 4,
+ },
+};
+const test3_bar = Test3Foo{ .Two = 13 };
+fn test3_1(f: Test3Foo) void {
+ switch (f) {
+ Test3Foo.Three => |pt| {
+ assertOrPanic(pt.x == 3);
+ assertOrPanic(pt.y == 4);
+ },
+ else => unreachable,
+ }
+}
+fn test3_2(f: Test3Foo) void {
+ switch (f) {
+ Test3Foo.Two => |x| {
+ assertOrPanic(x == 13);
+ },
+ else => unreachable,
+ }
+}
+
+test "character literals" {
+ assertOrPanic('\'' == single_quote);
+}
+const single_quote = '\'';
+
+test "take address of parameter" {
+ testTakeAddressOfParameter(12.34);
+}
+fn testTakeAddressOfParameter(f: f32) void {
+ const f_ptr = &f;
+ assertOrPanic(f_ptr.* == 12.34);
+}
+
+test "pointer comparison" {
+ const a = ([]const u8)("a");
+ const b = &a;
+ assertOrPanic(ptrEql(b, b));
+}
+fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
+ return a == b;
+}
+
+test "C string concatenation" {
+ const a = c"OK" ++ c" IT " ++ c"WORKED";
+ const b = c"OK IT WORKED";
+
+ const len = cstr.len(b);
+ const len_with_null = len + 1;
+ {
+ var i: u32 = 0;
+ while (i < len_with_null) : (i += 1) {
+ assertOrPanic(a[i] == b[i]);
+ }
+ }
+ assertOrPanic(a[len] == 0);
+ assertOrPanic(b[len] == 0);
+}
+
+test "cast slice to u8 slice" {
+ assertOrPanic(@sizeOf(i32) == 4);
+ var big_thing_array = []i32{ 1, 2, 3, 4 };
+ const big_thing_slice: []i32 = big_thing_array[0..];
+ const bytes = @sliceToBytes(big_thing_slice);
+ assertOrPanic(bytes.len == 4 * 4);
+ bytes[4] = 0;
+ bytes[5] = 0;
+ bytes[6] = 0;
+ bytes[7] = 0;
+ assertOrPanic(big_thing_slice[1] == 0);
+ const big_thing_again = @bytesToSlice(i32, bytes);
+ assertOrPanic(big_thing_again[2] == 3);
+ big_thing_again[2] = -1;
+ assertOrPanic(bytes[8] == maxInt(u8));
+ assertOrPanic(bytes[9] == maxInt(u8));
+ assertOrPanic(bytes[10] == maxInt(u8));
+ assertOrPanic(bytes[11] == maxInt(u8));
+}
+
+test "pointer to void return type" {
+ testPointerToVoidReturnType() catch unreachable;
+}
+fn testPointerToVoidReturnType() anyerror!void {
+ const a = testPointerToVoidReturnType2();
+ return a.*;
+}
+const test_pointer_to_void_return_type_x = void{};
+fn testPointerToVoidReturnType2() *const void {
+ return &test_pointer_to_void_return_type_x;
+}
+
+test "non const ptr to aliased type" {
+ const int = i32;
+ assertOrPanic(?*int == ?*i32);
+}
+
+test "array 2D const double ptr" {
+ const rect_2d_vertexes = [][1]f32{
+ []f32{1.0},
+ []f32{2.0},
+ };
+ testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
+}
+
+fn testArray2DConstDoublePtr(ptr: *const f32) void {
+ const ptr2 = @ptrCast([*]const f32, ptr);
+ assertOrPanic(ptr2[0] == 1.0);
+ assertOrPanic(ptr2[1] == 2.0);
+}
+
+const Tid = builtin.TypeId;
+const AStruct = struct {
+ x: i32,
+};
+const AnEnum = enum {
+ One,
+ Two,
+};
+const AUnionEnum = union(enum) {
+ One: i32,
+ Two: void,
+};
+const AUnion = union {
+ One: void,
+ Two: void,
+};
+
+test "@typeId" {
+ comptime {
+ assertOrPanic(@typeId(type) == Tid.Type);
+ assertOrPanic(@typeId(void) == Tid.Void);
+ assertOrPanic(@typeId(bool) == Tid.Bool);
+ assertOrPanic(@typeId(noreturn) == Tid.NoReturn);
+ assertOrPanic(@typeId(i8) == Tid.Int);
+ assertOrPanic(@typeId(u8) == Tid.Int);
+ assertOrPanic(@typeId(i64) == Tid.Int);
+ assertOrPanic(@typeId(u64) == Tid.Int);
+ assertOrPanic(@typeId(f32) == Tid.Float);
+ assertOrPanic(@typeId(f64) == Tid.Float);
+ assertOrPanic(@typeId(*f32) == Tid.Pointer);
+ assertOrPanic(@typeId([2]u8) == Tid.Array);
+ assertOrPanic(@typeId(AStruct) == Tid.Struct);
+ assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt);
+ assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
+ assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined);
+ assertOrPanic(@typeId(@typeOf(null)) == Tid.Null);
+ assertOrPanic(@typeId(?i32) == Tid.Optional);
+ assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion);
+ assertOrPanic(@typeId(anyerror) == Tid.ErrorSet);
+ assertOrPanic(@typeId(AnEnum) == Tid.Enum);
+ assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
+ assertOrPanic(@typeId(AUnionEnum) == Tid.Union);
+ assertOrPanic(@typeId(AUnion) == Tid.Union);
+ assertOrPanic(@typeId(fn () void) == Tid.Fn);
+ assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace);
+ // TODO bound fn
+ // TODO arg tuple
+ // TODO opaque
+ }
+}
+
+test "@typeName" {
+ const Struct = struct {};
+ const Union = union {
+ unused: u8,
+ };
+ const Enum = enum {
+ Unused,
+ };
+ comptime {
+ assertOrPanic(mem.eql(u8, @typeName(i64), "i64"));
+ assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize"));
+ // https://github.com/ziglang/zig/issues/675
+ assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
+ assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct"));
+ assertOrPanic(mem.eql(u8, @typeName(Union), "Union"));
+ assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum"));
+ }
+}
+
+fn TypeFromFn(comptime T: type) type {
+ return struct {};
+}
+
+test "double implicit cast in same expression" {
+ var x = i32(u16(nine()));
+ assertOrPanic(x == 9);
+}
+fn nine() u8 {
+ return 9;
+}
+
+test "global variable initialized to global variable array element" {
+ assertOrPanic(global_ptr == &gdt[0]);
+}
+const GDTEntry = struct {
+ field: i32,
+};
+var gdt = []GDTEntry{
+ GDTEntry{ .field = 1 },
+ GDTEntry{ .field = 2 },
+};
+var global_ptr = &gdt[0];
+
+// can't really run this test but we can make sure it has no compile error
+// and generates code
+const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000];
+export fn writeToVRam() void {
+ vram[0] = 'X';
+}
+
+const OpaqueA = @OpaqueType();
+const OpaqueB = @OpaqueType();
+test "@OpaqueType" {
+ assertOrPanic(*OpaqueA != *OpaqueB);
+ assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
+ assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
+}
+
+test "variable is allowed to be a pointer to an opaque type" {
+ var x: i32 = 1234;
+ _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
+}
+fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
+ var a = ptr;
+ return a;
+}
+
+test "comptime if inside runtime while which unconditionally breaks" {
+ testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
+ comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
+}
+fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
+ while (cond) {
+ if (false) {}
+ break;
+ }
+}
+
+test "implicit comptime while" {
+ while (false) {
+ @compileError("bad");
+ }
+}
+
+fn fnThatClosesOverLocalConst() type {
+ const c = 1;
+ return struct {
+ fn g() i32 {
+ return c;
+ }
+ };
+}
+
+test "function closes over local const" {
+ const x = fnThatClosesOverLocalConst().g();
+ assertOrPanic(x == 1);
+}
+
+test "cold function" {
+ thisIsAColdFn();
+ comptime thisIsAColdFn();
+}
+
+fn thisIsAColdFn() void {
+ @setCold(true);
+}
+
+const PackedStruct = packed struct {
+ a: u8,
+ b: u8,
+};
+const PackedUnion = packed union {
+ a: u8,
+ b: u32,
+};
+const PackedEnum = packed enum {
+ A,
+ B,
+};
+
+test "packed struct, enum, union parameters in extern function" {
+ testPackedStuff(&(PackedStruct{
+ .a = 1,
+ .b = 2,
+ }), &(PackedUnion{ .a = 1 }), PackedEnum.A);
+}
+
+export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {}
+
+test "slicing zero length array" {
+ const s1 = ""[0..];
+ const s2 = ([]u32{})[0..];
+ assertOrPanic(s1.len == 0);
+ assertOrPanic(s2.len == 0);
+ assertOrPanic(mem.eql(u8, s1, ""));
+ assertOrPanic(mem.eql(u32, s2, []u32{}));
+}
+
+const addr1 = @ptrCast(*const u8, emptyFn);
+test "comptime cast fn to ptr" {
+ const addr2 = @ptrCast(*const u8, emptyFn);
+ comptime assertOrPanic(addr1 == addr2);
+}
+
+test "equality compare fn ptrs" {
+ var a = emptyFn;
+ assertOrPanic(a == a);
+}
+
+test "self reference through fn ptr field" {
+ const S = struct {
+ const A = struct {
+ f: fn (A) u8,
+ };
+
+ fn foo(a: A) u8 {
+ return 12;
+ }
+ };
+ var a: S.A = undefined;
+ a.f = S.foo;
+ assertOrPanic(a.f(a) == 12);
+}
+
+test "volatile load and store" {
+ var number: i32 = 1234;
+ const ptr = (*volatile i32)(&number);
+ ptr.* += 1;
+ assertOrPanic(ptr.* == 1235);
+}
+
+test "slice string literal has type []const u8" {
+ comptime {
+ assertOrPanic(@typeOf("aoeu"[0..]) == []const u8);
+ const array = []i32{ 1, 2, 3, 4 };
+ assertOrPanic(@typeOf(array[0..]) == []const i32);
+ }
+}
+
+test "pointer child field" {
+ assertOrPanic((*u32).Child == u32);
+}
+
+test "struct inside function" {
+ testStructInFn();
+ comptime testStructInFn();
+}
+
+fn testStructInFn() void {
+ const BlockKind = u32;
+
+ const Block = struct {
+ kind: BlockKind,
+ };
+
+ var block = Block{ .kind = 1234 };
+
+ block.kind += 1;
+
+ assertOrPanic(block.kind == 1235);
+}
+
+test "fn call returning scalar optional in equality expression" {
+ assertOrPanic(getNull() == null);
+}
+
+fn getNull() ?*i32 {
+ return null;
+}
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/a.zig b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig
new file mode 100644
index 0000000000000000000000000000000000000000..5ce0e94f8bcf7a4c4c00d79fd1e526294ce68d28
--- /dev/null
+++ b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig
@@ -0,0 +1 @@
+pub const a_bool = true;
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/b.zig b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a12a54b5891baef53855a2c43f3ffef7b17a9d4d
--- /dev/null
+++ b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig
@@ -0,0 +1 @@
+pub const a_bool = false;
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fe3e0cc02093840810993eaacaeb9a1b6d5414f4
--- /dev/null
+++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
@@ -0,0 +1,14 @@
+const builtin = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "namespace depends on compile var" {
+ if (some_namespace.a_bool) {
+ assertOrPanic(some_namespace.a_bool);
+ } else {
+ assertOrPanic(!some_namespace.a_bool);
+ }
+}
+const some_namespace = switch (builtin.os) {
+ builtin.Os.linux => @import("a.zig"),
+ else => @import("b.zig"),
+};
diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig
new file mode 100644
index 0000000000000000000000000000000000000000..b9ae2d27cdb773017cd221a5badf73aea1fb10d3
--- /dev/null
+++ b/test/stage1/behavior/new_stack_call.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+var new_stack_bytes: [1024]u8 = undefined;
+
+test "calling a function with a new stack" {
+ const arg = 1234;
+
+ const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
+ const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
+ _ = targetFunction(arg);
+
+ assertOrPanic(arg == 1234);
+ assertOrPanic(a < b);
+}
+
+fn targetFunction(x: i32) usize {
+ assertOrPanic(x == 1234);
+
+ var local_variable: i32 = 42;
+ const ptr = &local_variable;
+ ptr.* += 1;
+
+ assertOrPanic(local_variable == 43);
+ return @ptrToInt(ptr);
+}
diff --git a/test/stage1/behavior/null.zig b/test/stage1/behavior/null.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e2f86a05ba442a2bf0469e47e49fb616282d9d4a
--- /dev/null
+++ b/test/stage1/behavior/null.zig
@@ -0,0 +1,162 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "optional type" {
+ const x: ?bool = true;
+
+ if (x) |y| {
+ if (y) {
+ // OK
+ } else {
+ unreachable;
+ }
+ } else {
+ unreachable;
+ }
+
+ const next_x: ?i32 = null;
+
+ const z = next_x orelse 1234;
+
+ assertOrPanic(z == 1234);
+
+ const final_x: ?i32 = 13;
+
+ const num = final_x orelse unreachable;
+
+ assertOrPanic(num == 13);
+}
+
+test "test maybe object and get a pointer to the inner value" {
+ var maybe_bool: ?bool = true;
+
+ if (maybe_bool) |*b| {
+ b.* = false;
+ }
+
+ assertOrPanic(maybe_bool.? == false);
+}
+
+test "rhs maybe unwrap return" {
+ const x: ?bool = true;
+ const y = x orelse return;
+}
+
+test "maybe return" {
+ maybeReturnImpl();
+ comptime maybeReturnImpl();
+}
+
+fn maybeReturnImpl() void {
+ assertOrPanic(foo(1235).?);
+ if (foo(null) != null) unreachable;
+ assertOrPanic(!foo(1234).?);
+}
+
+fn foo(x: ?i32) ?bool {
+ const value = x orelse return null;
+ return value > 1234;
+}
+
+test "if var maybe pointer" {
+ assertOrPanic(shouldBeAPlus1(Particle{
+ .a = 14,
+ .b = 1,
+ .c = 1,
+ .d = 1,
+ }) == 15);
+}
+fn shouldBeAPlus1(p: Particle) u64 {
+ var maybe_particle: ?Particle = p;
+ if (maybe_particle) |*particle| {
+ particle.a += 1;
+ }
+ if (maybe_particle) |particle| {
+ return particle.a;
+ }
+ return 0;
+}
+const Particle = struct {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+};
+
+test "null literal outside function" {
+ const is_null = here_is_a_null_literal.context == null;
+ assertOrPanic(is_null);
+
+ const is_non_null = here_is_a_null_literal.context != null;
+ assertOrPanic(!is_non_null);
+}
+const SillyStruct = struct {
+ context: ?i32,
+};
+const here_is_a_null_literal = SillyStruct{ .context = null };
+
+test "test null runtime" {
+ testTestNullRuntime(null);
+}
+fn testTestNullRuntime(x: ?i32) void {
+ assertOrPanic(x == null);
+ assertOrPanic(!(x != null));
+}
+
+test "optional void" {
+ optionalVoidImpl();
+ comptime optionalVoidImpl();
+}
+
+fn optionalVoidImpl() void {
+ assertOrPanic(bar(null) == null);
+ assertOrPanic(bar({}) != null);
+}
+
+fn bar(x: ?void) ?void {
+ if (x) |_| {
+ return {};
+ } else {
+ return null;
+ }
+}
+
+const StructWithOptional = struct {
+ field: ?i32,
+};
+
+var struct_with_optional: StructWithOptional = undefined;
+
+test "unwrap optional which is field of global var" {
+ struct_with_optional.field = null;
+ if (struct_with_optional.field) |payload| {
+ unreachable;
+ }
+ struct_with_optional.field = 1234;
+ if (struct_with_optional.field) |payload| {
+ assertOrPanic(payload == 1234);
+ } else {
+ unreachable;
+ }
+}
+
+test "null with default unwrap" {
+ const x: i32 = null orelse 1;
+ assertOrPanic(x == 1);
+}
+
+test "optional types" {
+ comptime {
+ const opt_type_struct = StructWithOptionalType{ .t = u8 };
+ assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8);
+ }
+}
+
+const StructWithOptionalType = struct {
+ t: ?type,
+};
+
+test "optional pointer to 0 bit type null value at runtime" {
+ const EmptyStruct = struct {};
+ var x: ?*EmptyStruct = null;
+ assertOrPanic(x == null);
+}
diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig
new file mode 100644
index 0000000000000000000000000000000000000000..14692cb1ea1b901922822b9c7f868c3ba2356345
--- /dev/null
+++ b/test/stage1/behavior/optional.zig
@@ -0,0 +1,81 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+pub const EmptyStruct = struct {};
+
+test "optional pointer to size zero struct" {
+ var e = EmptyStruct{};
+ var o: ?*EmptyStruct = &e;
+ assertOrPanic(o != null);
+}
+
+test "equality compare nullable pointers" {
+ testNullPtrsEql();
+ comptime testNullPtrsEql();
+}
+
+fn testNullPtrsEql() void {
+ var number: i32 = 1234;
+
+ var x: ?*i32 = null;
+ var y: ?*i32 = null;
+ assertOrPanic(x == y);
+ y = &number;
+ assertOrPanic(x != y);
+ assertOrPanic(x != &number);
+ assertOrPanic(&number != x);
+ x = &number;
+ assertOrPanic(x == y);
+ assertOrPanic(x == &number);
+ assertOrPanic(&number == x);
+}
+
+test "address of unwrap optional" {
+ const S = struct {
+ const Foo = struct {
+ a: i32,
+ };
+
+ var global: ?Foo = null;
+
+ pub fn getFoo() anyerror!*Foo {
+ return &global.?;
+ }
+ };
+ S.global = S.Foo{ .a = 1234 };
+ const foo = S.getFoo() catch unreachable;
+ assertOrPanic(foo.a == 1234);
+}
+
+test "passing an optional integer as a parameter" {
+ const S = struct {
+ fn entry() bool {
+ var x: i32 = 1234;
+ return foo(x);
+ }
+
+ fn foo(x: ?i32) bool {
+ return x.? == 1234;
+ }
+ };
+ assertOrPanic(S.entry());
+ comptime assertOrPanic(S.entry());
+}
+
+test "unwrap function call with optional pointer return value" {
+ const S = struct {
+ fn entry() void {
+ assertOrPanic(foo().?.* == 1234);
+ assertOrPanic(bar() == null);
+ }
+ const global: i32 = 1234;
+ fn foo() ?*const i32 {
+ return &global;
+ }
+ fn bar() ?*i32 {
+ return null;
+ }
+ };
+ S.entry();
+ // TODO https://github.com/ziglang/zig/issues/1901
+ //comptime S.entry();
+}
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
new file mode 100644
index 0000000000000000000000000000000000000000..1142d89ab5576746ef57667357de59931fcb97f9
--- /dev/null
+++ b/test/stage1/behavior/pointers.zig
@@ -0,0 +1,44 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "dereference pointer" {
+ comptime testDerefPtr();
+ testDerefPtr();
+}
+
+fn testDerefPtr() void {
+ var x: i32 = 1234;
+ var y = &x;
+ y.* += 1;
+ assertOrPanic(x == 1235);
+}
+
+test "pointer arithmetic" {
+ var ptr = c"abcd";
+
+ assertOrPanic(ptr[0] == 'a');
+ ptr += 1;
+ assertOrPanic(ptr[0] == 'b');
+ ptr += 1;
+ assertOrPanic(ptr[0] == 'c');
+ ptr += 1;
+ assertOrPanic(ptr[0] == 'd');
+ ptr += 1;
+ assertOrPanic(ptr[0] == 0);
+ ptr -= 1;
+ assertOrPanic(ptr[0] == 'd');
+ ptr -= 1;
+ assertOrPanic(ptr[0] == 'c');
+ ptr -= 1;
+ assertOrPanic(ptr[0] == 'b');
+ ptr -= 1;
+ assertOrPanic(ptr[0] == 'a');
+}
+
+test "double pointer parsing" {
+ comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32);
+}
+
+fn PtrOf(comptime T: type) type {
+ return *T;
+}
diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f7f8bb523bf4b218df8140b5220d443e97b91de1
--- /dev/null
+++ b/test/stage1/behavior/popcount.zig
@@ -0,0 +1,25 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@popCount" {
+ comptime testPopCount();
+ testPopCount();
+}
+
+fn testPopCount() void {
+ {
+ var x: u32 = 0xaa;
+ assertOrPanic(@popCount(x) == 4);
+ }
+ {
+ var x: u32 = 0xaaaaaaaa;
+ assertOrPanic(@popCount(x) == 16);
+ }
+ {
+ var x: i16 = -1;
+ assertOrPanic(@popCount(x) == 16);
+ }
+ comptime {
+ assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
+ }
+}
+
diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig
new file mode 100644
index 0000000000000000000000000000000000000000..54c3dda8493026f9547acf5570ee0fe64e4e87e3
--- /dev/null
+++ b/test/stage1/behavior/ptrcast.zig
@@ -0,0 +1,52 @@
+const builtin = @import("builtin");
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "reinterpret bytes as integer with nonzero offset" {
+ testReinterpretBytesAsInteger();
+ comptime testReinterpretBytesAsInteger();
+}
+
+fn testReinterpretBytesAsInteger() void {
+ const bytes = "\x12\x34\x56\x78\xab";
+ const expected = switch (builtin.endian) {
+ builtin.Endian.Little => 0xab785634,
+ builtin.Endian.Big => 0x345678ab,
+ };
+ assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);
+}
+
+test "reinterpret bytes of an array into an extern struct" {
+ testReinterpretBytesAsExternStruct();
+ comptime testReinterpretBytesAsExternStruct();
+}
+
+fn testReinterpretBytesAsExternStruct() void {
+ var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 };
+
+ const S = extern struct {
+ a: u8,
+ b: u16,
+ c: u8,
+ };
+
+ var ptr = @ptrCast(*const S, &bytes);
+ var val = ptr.c;
+ assertOrPanic(val == 5);
+}
+
+test "reinterpret struct field at comptime" {
+ const numLittle = comptime Bytes.init(0x12345678);
+ assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes));
+}
+
+const Bytes = struct {
+ bytes: [4]u8,
+
+ pub fn init(v: u32) Bytes {
+ var res: Bytes = undefined;
+ @ptrCast(*align(1) u32, &res.bytes).* = v;
+
+ return res;
+ }
+};
diff --git a/test/stage1/behavior/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig
new file mode 100644
index 0000000000000000000000000000000000000000..181113f6bf1922cf635a675b1d660efabf4ab358
--- /dev/null
+++ b/test/stage1/behavior/pub_enum/index.zig
@@ -0,0 +1,13 @@
+const other = @import("other.zig");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "pub enum" {
+ pubEnumTest(other.APubEnum.Two);
+}
+fn pubEnumTest(foo: other.APubEnum) void {
+ assertOrPanic(foo == other.APubEnum.Two);
+}
+
+test "cast with imported symbol" {
+ assertOrPanic(other.size_t(42) == 42);
+}
diff --git a/test/stage1/behavior/pub_enum/other.zig b/test/stage1/behavior/pub_enum/other.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c66395038397a4d91938ff3400613ae2d734bc14
--- /dev/null
+++ b/test/stage1/behavior/pub_enum/other.zig
@@ -0,0 +1,6 @@
+pub const APubEnum = enum {
+ One,
+ Two,
+ Three,
+};
+pub const size_t = u64;
diff --git a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
new file mode 100644
index 0000000000000000000000000000000000000000..acbe6b245978a018a846f77b9fdcb976b77cfee7
--- /dev/null
+++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
@@ -0,0 +1,37 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+var ok: bool = false;
+test "reference a variable in an if after an if in the 2nd switch prong" {
+ foo(true, Num.Two, false, "aoeu");
+ assertOrPanic(!ok);
+ foo(false, Num.One, false, "aoeu");
+ assertOrPanic(!ok);
+ foo(true, Num.One, false, "aoeu");
+ assertOrPanic(ok);
+}
+
+const Num = enum {
+ One,
+ Two,
+};
+
+fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
+ switch (k) {
+ Num.Two => {},
+ Num.One => {
+ if (c) {
+ const output_path = b;
+
+ if (c2) {}
+
+ a(output_path);
+ }
+ },
+ }
+}
+
+fn a(x: []const u8) void {
+ assertOrPanic(mem.eql(u8, x, "aoeu"));
+ ok = true;
+}
diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f4c142e0f75576884c6e259bd67c9fc640b9edd2
--- /dev/null
+++ b/test/stage1/behavior/reflection.zig
@@ -0,0 +1,96 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const reflection = @This();
+
+test "reflection: array, pointer, optional, error union type child" {
+ comptime {
+ assertOrPanic(([10]u8).Child == u8);
+ assertOrPanic((*u8).Child == u8);
+ assertOrPanic((anyerror!u8).Payload == u8);
+ assertOrPanic((?u8).Child == u8);
+ }
+}
+
+test "reflection: function return type, var args, and param types" {
+ comptime {
+ assertOrPanic(@typeOf(dummy).ReturnType == i32);
+ assertOrPanic(!@typeOf(dummy).is_var_args);
+ assertOrPanic(@typeOf(dummy_varargs).is_var_args);
+ assertOrPanic(@typeOf(dummy).arg_count == 3);
+ assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool);
+ assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32);
+ assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32);
+ }
+}
+
+fn dummy(a: bool, b: i32, c: f32) i32 {
+ return 1234;
+}
+fn dummy_varargs(args: ...) void {}
+
+test "reflection: struct member types and names" {
+ comptime {
+ assertOrPanic(@memberCount(Foo) == 3);
+
+ assertOrPanic(@memberType(Foo, 0) == i32);
+ assertOrPanic(@memberType(Foo, 1) == bool);
+ assertOrPanic(@memberType(Foo, 2) == void);
+
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one"));
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two"));
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three"));
+ }
+}
+
+test "reflection: enum member types and names" {
+ comptime {
+ assertOrPanic(@memberCount(Bar) == 4);
+
+ assertOrPanic(@memberType(Bar, 0) == void);
+ assertOrPanic(@memberType(Bar, 1) == i32);
+ assertOrPanic(@memberType(Bar, 2) == bool);
+ assertOrPanic(@memberType(Bar, 3) == f64);
+
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four"));
+ }
+}
+
+test "reflection: @field" {
+ var f = Foo{
+ .one = 42,
+ .two = true,
+ .three = void{},
+ };
+
+ assertOrPanic(f.one == f.one);
+ assertOrPanic(@field(f, "o" ++ "ne") == f.one);
+ assertOrPanic(@field(f, "t" ++ "wo") == f.two);
+ assertOrPanic(@field(f, "th" ++ "ree") == f.three);
+ assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant);
+ assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One);
+ assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two);
+ assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three);
+ assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four);
+ assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
+ @field(f, "o" ++ "ne") = 4;
+ assertOrPanic(f.one == 4);
+}
+
+const Foo = struct {
+ const constant = 52;
+
+ one: i32,
+ two: bool,
+ three: void,
+};
+
+const Bar = union(enum) {
+ One: void,
+ Two: i32,
+ Three: bool,
+ Four: f64,
+};
+
diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig
new file mode 100644
index 0000000000000000000000000000000000000000..ddaea4c24299dd75828a27861205e0a5568d55cb
--- /dev/null
+++ b/test/stage1/behavior/sizeof_and_typeof.zig
@@ -0,0 +1,69 @@
+const builtin = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@sizeOf and @typeOf" {
+ const y: @typeOf(x) = 120;
+ assertOrPanic(@sizeOf(@typeOf(y)) == 2);
+}
+const x: u16 = 13;
+const z: @typeOf(x) = 19;
+
+const A = struct {
+ a: u8,
+ b: u32,
+ c: u8,
+ d: u3,
+ e: u5,
+ f: u16,
+ g: u16,
+};
+
+const P = packed struct {
+ a: u8,
+ b: u32,
+ c: u8,
+ d: u3,
+ e: u5,
+ f: u16,
+ g: u16,
+};
+
+test "@byteOffsetOf" {
+ // Packed structs have fixed memory layout
+ assertOrPanic(@byteOffsetOf(P, "a") == 0);
+ assertOrPanic(@byteOffsetOf(P, "b") == 1);
+ assertOrPanic(@byteOffsetOf(P, "c") == 5);
+ assertOrPanic(@byteOffsetOf(P, "d") == 6);
+ assertOrPanic(@byteOffsetOf(P, "e") == 6);
+ assertOrPanic(@byteOffsetOf(P, "f") == 7);
+ assertOrPanic(@byteOffsetOf(P, "g") == 9);
+
+ // Normal struct fields can be moved/padded
+ var a: A = undefined;
+ assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
+ assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
+ assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
+ assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
+ assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
+ assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
+ assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
+}
+
+test "@bitOffsetOf" {
+ // Packed structs have fixed memory layout
+ assertOrPanic(@bitOffsetOf(P, "a") == 0);
+ assertOrPanic(@bitOffsetOf(P, "b") == 8);
+ assertOrPanic(@bitOffsetOf(P, "c") == 40);
+ assertOrPanic(@bitOffsetOf(P, "d") == 48);
+ assertOrPanic(@bitOffsetOf(P, "e") == 51);
+ assertOrPanic(@bitOffsetOf(P, "f") == 56);
+ assertOrPanic(@bitOffsetOf(P, "g") == 72);
+
+ assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
+ assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
+ assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
+ assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
+ assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
+ assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
+ assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
+}
diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig
new file mode 100644
index 0000000000000000000000000000000000000000..cc29e43485b2848c53e82d8963802b26aa04d719
--- /dev/null
+++ b/test/stage1/behavior/slice.zig
@@ -0,0 +1,40 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+const x = @intToPtr([*]i32, 0x1000)[0..0x500];
+const y = x[0x100..];
+test "compile time slice of pointer to hard coded address" {
+ assertOrPanic(@ptrToInt(x.ptr) == 0x1000);
+ assertOrPanic(x.len == 0x500);
+
+ assertOrPanic(@ptrToInt(y.ptr) == 0x1100);
+ assertOrPanic(y.len == 0x400);
+}
+
+test "slice child property" {
+ var array: [5]i32 = undefined;
+ var slice = array[0..];
+ assertOrPanic(@typeOf(slice).Child == i32);
+}
+
+test "runtime safety lets us slice from len..len" {
+ var an_array = []u8{
+ 1,
+ 2,
+ 3,
+ };
+ assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
+}
+
+fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
+ return a_slice[start..end];
+}
+
+test "implicitly cast array of size 0 to slice" {
+ var msg = []u8{};
+ assertLenIsZero(msg);
+}
+
+fn assertLenIsZero(msg: []const u8) void {
+ assertOrPanic(msg.len == 0);
+}
diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig
new file mode 100644
index 0000000000000000000000000000000000000000..92ae2baa152d5f9f4bffbf67d8402a6ea58899cf
--- /dev/null
+++ b/test/stage1/behavior/struct.zig
@@ -0,0 +1,470 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const builtin = @import("builtin");
+const maxInt = std.math.maxInt;
+
+const StructWithNoFields = struct {
+ fn add(a: i32, b: i32) i32 {
+ return a + b;
+ }
+};
+const empty_global_instance = StructWithNoFields{};
+
+test "call struct static method" {
+ const result = StructWithNoFields.add(3, 4);
+ assertOrPanic(result == 7);
+}
+
+test "return empty struct instance" {
+ _ = returnEmptyStructInstance();
+}
+fn returnEmptyStructInstance() StructWithNoFields {
+ return empty_global_instance;
+}
+
+const should_be_11 = StructWithNoFields.add(5, 6);
+
+test "invoke static method in global scope" {
+ assertOrPanic(should_be_11 == 11);
+}
+
+test "void struct fields" {
+ const foo = VoidStructFieldsFoo{
+ .a = void{},
+ .b = 1,
+ .c = void{},
+ };
+ assertOrPanic(foo.b == 1);
+ assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4);
+}
+const VoidStructFieldsFoo = struct {
+ a: void,
+ b: i32,
+ c: void,
+};
+
+test "structs" {
+ var foo: StructFoo = undefined;
+ @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
+ foo.a += 1;
+ foo.b = foo.a == 1;
+ testFoo(foo);
+ testMutation(&foo);
+ assertOrPanic(foo.c == 100);
+}
+const StructFoo = struct {
+ a: i32,
+ b: bool,
+ c: f32,
+};
+fn testFoo(foo: StructFoo) void {
+ assertOrPanic(foo.b);
+}
+fn testMutation(foo: *StructFoo) void {
+ foo.c = 100;
+}
+
+const Node = struct {
+ val: Val,
+ next: *Node,
+};
+
+const Val = struct {
+ x: i32,
+};
+
+test "struct point to self" {
+ var root: Node = undefined;
+ root.val.x = 1;
+
+ var node: Node = undefined;
+ node.next = &root;
+ node.val.x = 2;
+
+ root.next = &node;
+
+ assertOrPanic(node.next.next.next.val.x == 1);
+}
+
+test "struct byval assign" {
+ var foo1: StructFoo = undefined;
+ var foo2: StructFoo = undefined;
+
+ foo1.a = 1234;
+ foo2.a = 0;
+ assertOrPanic(foo2.a == 0);
+ foo2 = foo1;
+ assertOrPanic(foo2.a == 1234);
+}
+
+fn structInitializer() void {
+ const val = Val{ .x = 42 };
+ assertOrPanic(val.x == 42);
+}
+
+test "fn call of struct field" {
+ assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13);
+}
+
+const Foo = struct {
+ ptr: fn () i32,
+};
+
+fn aFunc() i32 {
+ return 13;
+}
+
+fn callStructField(foo: Foo) i32 {
+ return foo.ptr();
+}
+
+test "store member function in variable" {
+ const instance = MemberFnTestFoo{ .x = 1234 };
+ const memberFn = MemberFnTestFoo.member;
+ const result = memberFn(instance);
+ assertOrPanic(result == 1234);
+}
+const MemberFnTestFoo = struct {
+ x: i32,
+ fn member(foo: MemberFnTestFoo) i32 {
+ return foo.x;
+ }
+};
+
+test "call member function directly" {
+ const instance = MemberFnTestFoo{ .x = 1234 };
+ const result = MemberFnTestFoo.member(instance);
+ assertOrPanic(result == 1234);
+}
+
+test "member functions" {
+ const r = MemberFnRand{ .seed = 1234 };
+ assertOrPanic(r.getSeed() == 1234);
+}
+const MemberFnRand = struct {
+ seed: u32,
+ pub fn getSeed(r: *const MemberFnRand) u32 {
+ return r.seed;
+ }
+};
+
+test "return struct byval from function" {
+ const bar = makeBar(1234, 5678);
+ assertOrPanic(bar.y == 5678);
+}
+const Bar = struct {
+ x: i32,
+ y: i32,
+};
+fn makeBar(x: i32, y: i32) Bar {
+ return Bar{
+ .x = x,
+ .y = y,
+ };
+}
+
+test "empty struct method call" {
+ const es = EmptyStruct{};
+ assertOrPanic(es.method() == 1234);
+}
+const EmptyStruct = struct {
+ fn method(es: *const EmptyStruct) i32 {
+ return 1234;
+ }
+};
+
+test "return empty struct from fn" {
+ _ = testReturnEmptyStructFromFn();
+}
+const EmptyStruct2 = struct {};
+fn testReturnEmptyStructFromFn() EmptyStruct2 {
+ return EmptyStruct2{};
+}
+
+test "pass slice of empty struct to fn" {
+ assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
+}
+fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
+ return slice.len;
+}
+
+const APackedStruct = packed struct {
+ x: u8,
+ y: u8,
+};
+
+test "packed struct" {
+ var foo = APackedStruct{
+ .x = 1,
+ .y = 2,
+ };
+ foo.y += 1;
+ const four = foo.x + foo.y;
+ assertOrPanic(four == 4);
+}
+
+const BitField1 = packed struct {
+ a: u3,
+ b: u3,
+ c: u2,
+};
+
+const bit_field_1 = BitField1{
+ .a = 1,
+ .b = 2,
+ .c = 3,
+};
+
+test "bit field access" {
+ var data = bit_field_1;
+ assertOrPanic(getA(&data) == 1);
+ assertOrPanic(getB(&data) == 2);
+ assertOrPanic(getC(&data) == 3);
+ comptime assertOrPanic(@sizeOf(BitField1) == 1);
+
+ data.b += 1;
+ assertOrPanic(data.b == 3);
+
+ data.a += 1;
+ assertOrPanic(data.a == 2);
+ assertOrPanic(data.b == 3);
+}
+
+fn getA(data: *const BitField1) u3 {
+ return data.a;
+}
+
+fn getB(data: *const BitField1) u3 {
+ return data.b;
+}
+
+fn getC(data: *const BitField1) u2 {
+ return data.c;
+}
+
+const Foo24Bits = packed struct {
+ field: u24,
+};
+const Foo96Bits = packed struct {
+ a: u24,
+ b: u24,
+ c: u24,
+ d: u24,
+};
+
+test "packed struct 24bits" {
+ comptime {
+ assertOrPanic(@sizeOf(Foo24Bits) == 3);
+ assertOrPanic(@sizeOf(Foo96Bits) == 12);
+ }
+
+ var value = Foo96Bits{
+ .a = 0,
+ .b = 0,
+ .c = 0,
+ .d = 0,
+ };
+ value.a += 1;
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 0);
+ assertOrPanic(value.c == 0);
+ assertOrPanic(value.d == 0);
+
+ value.b += 1;
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 0);
+ assertOrPanic(value.d == 0);
+
+ value.c += 1;
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 1);
+ assertOrPanic(value.d == 0);
+
+ value.d += 1;
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 1);
+ assertOrPanic(value.d == 1);
+}
+
+const FooArray24Bits = packed struct {
+ a: u16,
+ b: [2]Foo24Bits,
+ c: u16,
+};
+
+test "packed array 24bits" {
+ comptime {
+ assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3);
+ assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
+ }
+
+ var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
+ bytes[bytes.len - 1] = 0xaa;
+ const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
+ assertOrPanic(ptr.a == 0);
+ assertOrPanic(ptr.b[0].field == 0);
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
+
+ ptr.a = maxInt(u16);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == 0);
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
+
+ ptr.b[0].field = maxInt(u24);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
+
+ ptr.b[1].field = maxInt(u24);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == maxInt(u24));
+ assertOrPanic(ptr.c == 0);
+
+ ptr.c = maxInt(u16);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == maxInt(u24));
+ assertOrPanic(ptr.c == maxInt(u16));
+
+ assertOrPanic(bytes[bytes.len - 1] == 0xaa);
+}
+
+const FooStructAligned = packed struct {
+ a: u8,
+ b: u8,
+};
+
+const FooArrayOfAligned = packed struct {
+ a: [2]FooStructAligned,
+};
+
+test "aligned array of packed struct" {
+ comptime {
+ assertOrPanic(@sizeOf(FooStructAligned) == 2);
+ assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2);
+ }
+
+ var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
+ const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
+
+ assertOrPanic(ptr.a[0].a == 0xbb);
+ assertOrPanic(ptr.a[0].b == 0xbb);
+ assertOrPanic(ptr.a[1].a == 0xbb);
+ assertOrPanic(ptr.a[1].b == 0xbb);
+}
+
+test "runtime struct initialization of bitfield" {
+ const s1 = Nibbles{
+ .x = x1,
+ .y = x1,
+ };
+ const s2 = Nibbles{
+ .x = @intCast(u4, x2),
+ .y = @intCast(u4, x2),
+ };
+
+ assertOrPanic(s1.x == x1);
+ assertOrPanic(s1.y == x1);
+ assertOrPanic(s2.x == @intCast(u4, x2));
+ assertOrPanic(s2.y == @intCast(u4, x2));
+}
+
+var x1 = u4(1);
+var x2 = u8(2);
+
+const Nibbles = packed struct {
+ x: u4,
+ y: u4,
+};
+
+const Bitfields = packed struct {
+ f1: u16,
+ f2: u16,
+ f3: u8,
+ f4: u8,
+ f5: u4,
+ f6: u4,
+ f7: u8,
+};
+
+test "native bit field understands endianness" {
+ var all: u64 = 0x7765443322221111;
+ var bytes: [8]u8 = undefined;
+ @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
+ var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
+
+ assertOrPanic(bitfields.f1 == 0x1111);
+ assertOrPanic(bitfields.f2 == 0x2222);
+ assertOrPanic(bitfields.f3 == 0x33);
+ assertOrPanic(bitfields.f4 == 0x44);
+ assertOrPanic(bitfields.f5 == 0x5);
+ assertOrPanic(bitfields.f6 == 0x6);
+ assertOrPanic(bitfields.f7 == 0x77);
+}
+
+test "align 1 field before self referential align 8 field as slice return type" {
+ const result = alloc(Expr);
+ assertOrPanic(result.len == 0);
+}
+
+const Expr = union(enum) {
+ Literal: u8,
+ Question: *Expr,
+};
+
+fn alloc(comptime T: type) []T {
+ return []T{};
+}
+
+test "call method with mutable reference to struct with no fields" {
+ const S = struct {
+ fn doC(s: *const @This()) bool {
+ return true;
+ }
+ fn do(s: *@This()) bool {
+ return true;
+ }
+ };
+
+ var s = S{};
+ assertOrPanic(S.doC(&s));
+ assertOrPanic(s.doC());
+ assertOrPanic(S.do(&s));
+ assertOrPanic(s.do());
+}
+
+test "implicit cast packed struct field to const ptr" {
+ const LevelUpMove = packed struct {
+ move_id: u9,
+ level: u7,
+
+ fn toInt(value: u7) u7 {
+ return value;
+ }
+ };
+
+ var lup: LevelUpMove = undefined;
+ lup.level = 12;
+ const res = LevelUpMove.toInt(lup.level);
+ assertOrPanic(res == 12);
+}
+
+test "pointer to packed struct member in a stack variable" {
+ const S = packed struct {
+ a: u2,
+ b: u2,
+ };
+
+ var s = S{ .a = 2, .b = 0 };
+ var b_ptr = &s.b;
+ assertOrPanic(s.b == 0);
+ b_ptr.* = 2;
+ assertOrPanic(s.b == 2);
+}
diff --git a/test/stage1/behavior/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4cc479f31c4aee69e6f88757f65d78e1388ed94e
--- /dev/null
+++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "struct contains null pointer which contains original struct" {
+ var x: ?*NodeLineComment = null;
+ assertOrPanic(x == null);
+}
+
+pub const Node = struct {
+ id: Id,
+ comment: ?*NodeLineComment,
+
+ pub const Id = enum {
+ Root,
+ LineComment,
+ };
+};
+
+pub const NodeLineComment = struct {
+ base: Node,
+};
diff --git a/test/stage1/behavior/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig
new file mode 100644
index 0000000000000000000000000000000000000000..15780a7c4456461fe28ff31bf3d098aef60f1dea
--- /dev/null
+++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig
@@ -0,0 +1,85 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const Node = struct {
+ payload: i32,
+ children: []Node,
+};
+
+const NodeAligned = struct {
+ payload: i32,
+ children: []align(@alignOf(NodeAligned)) NodeAligned,
+};
+
+test "struct contains slice of itself" {
+ var other_nodes = []Node{
+ Node{
+ .payload = 31,
+ .children = []Node{},
+ },
+ Node{
+ .payload = 32,
+ .children = []Node{},
+ },
+ };
+ var nodes = []Node{
+ Node{
+ .payload = 1,
+ .children = []Node{},
+ },
+ Node{
+ .payload = 2,
+ .children = []Node{},
+ },
+ Node{
+ .payload = 3,
+ .children = other_nodes[0..],
+ },
+ };
+ const root = Node{
+ .payload = 1234,
+ .children = nodes[0..],
+ };
+ assertOrPanic(root.payload == 1234);
+ assertOrPanic(root.children[0].payload == 1);
+ assertOrPanic(root.children[1].payload == 2);
+ assertOrPanic(root.children[2].payload == 3);
+ assertOrPanic(root.children[2].children[0].payload == 31);
+ assertOrPanic(root.children[2].children[1].payload == 32);
+}
+
+test "struct contains aligned slice of itself" {
+ var other_nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 31,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 32,
+ .children = []NodeAligned{},
+ },
+ };
+ var nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 1,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 2,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 3,
+ .children = other_nodes[0..],
+ },
+ };
+ const root = NodeAligned{
+ .payload = 1234,
+ .children = nodes[0..],
+ };
+ assertOrPanic(root.payload == 1234);
+ assertOrPanic(root.children[0].payload == 1);
+ assertOrPanic(root.children[1].payload == 2);
+ assertOrPanic(root.children[2].payload == 3);
+ assertOrPanic(root.children[2].children[0].payload == 31);
+ assertOrPanic(root.children[2].children[1].payload == 32);
+}
diff --git a/test/stage1/behavior/switch.zig b/test/stage1/behavior/switch.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4ac971397e0498888fd7c19aac2e773ed16d21f0
--- /dev/null
+++ b/test/stage1/behavior/switch.zig
@@ -0,0 +1,271 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "switch with numbers" {
+ testSwitchWithNumbers(13);
+}
+
+fn testSwitchWithNumbers(x: u32) void {
+ const result = switch (x) {
+ 1, 2, 3, 4...8 => false,
+ 13 => true,
+ else => false,
+ };
+ assertOrPanic(result);
+}
+
+test "switch with all ranges" {
+ assertOrPanic(testSwitchWithAllRanges(50, 3) == 1);
+ assertOrPanic(testSwitchWithAllRanges(101, 0) == 2);
+ assertOrPanic(testSwitchWithAllRanges(300, 5) == 3);
+ assertOrPanic(testSwitchWithAllRanges(301, 6) == 6);
+}
+
+fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
+ return switch (x) {
+ 0...100 => 1,
+ 101...200 => 2,
+ 201...300 => 3,
+ else => y,
+ };
+}
+
+test "implicit comptime switch" {
+ const x = 3 + 4;
+ const result = switch (x) {
+ 3 => 10,
+ 4 => 11,
+ 5, 6 => 12,
+ 7, 8 => 13,
+ else => 14,
+ };
+
+ comptime {
+ assertOrPanic(result + 1 == 14);
+ }
+}
+
+test "switch on enum" {
+ const fruit = Fruit.Orange;
+ nonConstSwitchOnEnum(fruit);
+}
+const Fruit = enum {
+ Apple,
+ Orange,
+ Banana,
+};
+fn nonConstSwitchOnEnum(fruit: Fruit) void {
+ switch (fruit) {
+ Fruit.Apple => unreachable,
+ Fruit.Orange => {},
+ Fruit.Banana => unreachable,
+ }
+}
+
+test "switch statement" {
+ nonConstSwitch(SwitchStatmentFoo.C);
+}
+fn nonConstSwitch(foo: SwitchStatmentFoo) void {
+ const val = switch (foo) {
+ SwitchStatmentFoo.A => i32(1),
+ SwitchStatmentFoo.B => 2,
+ SwitchStatmentFoo.C => 3,
+ SwitchStatmentFoo.D => 4,
+ };
+ assertOrPanic(val == 3);
+}
+const SwitchStatmentFoo = enum {
+ A,
+ B,
+ C,
+ D,
+};
+
+test "switch prong with variable" {
+ switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
+ switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
+ switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
+}
+const SwitchProngWithVarEnum = union(enum) {
+ One: i32,
+ Two: f32,
+ Meh: void,
+};
+fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void {
+ switch (a) {
+ SwitchProngWithVarEnum.One => |x| {
+ assertOrPanic(x == 13);
+ },
+ SwitchProngWithVarEnum.Two => |x| {
+ assertOrPanic(x == 13.0);
+ },
+ SwitchProngWithVarEnum.Meh => |x| {
+ const v: void = x;
+ },
+ }
+}
+
+test "switch on enum using pointer capture" {
+ testSwitchEnumPtrCapture();
+ comptime testSwitchEnumPtrCapture();
+}
+
+fn testSwitchEnumPtrCapture() void {
+ var value = SwitchProngWithVarEnum{ .One = 1234 };
+ switch (value) {
+ SwitchProngWithVarEnum.One => |*x| x.* += 1,
+ else => unreachable,
+ }
+ switch (value) {
+ SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235),
+ else => unreachable,
+ }
+}
+
+test "switch with multiple expressions" {
+ const x = switch (returnsFive()) {
+ 1, 2, 3 => 1,
+ 4, 5, 6 => 2,
+ else => i32(3),
+ };
+ assertOrPanic(x == 2);
+}
+fn returnsFive() i32 {
+ return 5;
+}
+
+const Number = union(enum) {
+ One: u64,
+ Two: u8,
+ Three: f32,
+};
+
+const number = Number{ .Three = 1.23 };
+
+fn returnsFalse() bool {
+ switch (number) {
+ Number.One => |x| return x > 1234,
+ Number.Two => |x| return x == 'a',
+ Number.Three => |x| return x > 12.34,
+ }
+}
+test "switch on const enum with var" {
+ assertOrPanic(!returnsFalse());
+}
+
+test "switch on type" {
+ assertOrPanic(trueIfBoolFalseOtherwise(bool));
+ assertOrPanic(!trueIfBoolFalseOtherwise(i32));
+}
+
+fn trueIfBoolFalseOtherwise(comptime T: type) bool {
+ return switch (T) {
+ bool => true,
+ else => false,
+ };
+}
+
+test "switch handles all cases of number" {
+ testSwitchHandleAllCases();
+ comptime testSwitchHandleAllCases();
+}
+
+fn testSwitchHandleAllCases() void {
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0);
+
+ assertOrPanic(testSwitchHandleAllCasesRange(100) == 0);
+ assertOrPanic(testSwitchHandleAllCasesRange(200) == 1);
+ assertOrPanic(testSwitchHandleAllCasesRange(201) == 2);
+ assertOrPanic(testSwitchHandleAllCasesRange(202) == 4);
+ assertOrPanic(testSwitchHandleAllCasesRange(230) == 3);
+}
+
+fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
+ return switch (x) {
+ 0 => u2(3),
+ 1 => 2,
+ 2 => 1,
+ 3 => 0,
+ };
+}
+
+fn testSwitchHandleAllCasesRange(x: u8) u8 {
+ return switch (x) {
+ 0...100 => u8(0),
+ 101...200 => 1,
+ 201, 203 => 2,
+ 202 => 4,
+ 204...255 => 3,
+ };
+}
+
+test "switch all prongs unreachable" {
+ testAllProngsUnreachable();
+ comptime testAllProngsUnreachable();
+}
+
+fn testAllProngsUnreachable() void {
+ assertOrPanic(switchWithUnreachable(1) == 2);
+ assertOrPanic(switchWithUnreachable(2) == 10);
+}
+
+fn switchWithUnreachable(x: i32) i32 {
+ while (true) {
+ switch (x) {
+ 1 => return 2,
+ 2 => break,
+ else => continue,
+ }
+ }
+ return 10;
+}
+
+fn return_a_number() anyerror!i32 {
+ return 1;
+}
+
+test "capture value of switch with all unreachable prongs" {
+ const x = return_a_number() catch |err| switch (err) {
+ else => unreachable,
+ };
+ assertOrPanic(x == 1);
+}
+
+test "switching on booleans" {
+ testSwitchOnBools();
+ comptime testSwitchOnBools();
+}
+
+fn testSwitchOnBools() void {
+ assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false);
+ assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true);
+
+ assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false);
+ assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true);
+
+ assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false);
+ assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true);
+}
+
+fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
+ return switch (x) {
+ true => false,
+ false => true,
+ };
+}
+
+fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
+ return switch (x) {
+ true => false,
+ else => true,
+ };
+}
+
+fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
+ return switch (x) {
+ false => true,
+ else => false,
+ };
+}
diff --git a/test/stage1/behavior/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6ac1919f0d5a17100ba3409c8523b43eadb8590c
--- /dev/null
+++ b/test/stage1/behavior/switch_prong_err_enum.zig
@@ -0,0 +1,30 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+var read_count: u64 = 0;
+
+fn readOnce() anyerror!u64 {
+ read_count += 1;
+ return read_count;
+}
+
+const FormValue = union(enum) {
+ Address: u64,
+ Other: bool,
+};
+
+fn doThing(form_id: u64) anyerror!FormValue {
+ return switch (form_id) {
+ 17 => FormValue{ .Address = try readOnce() },
+ else => error.InvalidDebugInfo,
+ };
+}
+
+test "switch prong returns error enum" {
+ switch (doThing(17) catch unreachable) {
+ FormValue.Address => |payload| {
+ assertOrPanic(payload == 1);
+ },
+ else => unreachable,
+ }
+ assertOrPanic(read_count == 1);
+}
diff --git a/test/stage1/behavior/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4ca031e2e11b9beeb27d3e2cb2171e0a744d989c
--- /dev/null
+++ b/test/stage1/behavior/switch_prong_implicit_cast.zig
@@ -0,0 +1,22 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const FormValue = union(enum) {
+ One: void,
+ Two: bool,
+};
+
+fn foo(id: u64) !FormValue {
+ return switch (id) {
+ 2 => FormValue{ .Two = true },
+ 1 => FormValue{ .One = {} },
+ else => return error.Whatever,
+ };
+}
+
+test "switch prong implicit cast" {
+ const result = switch (foo(2) catch unreachable) {
+ FormValue.One => false,
+ FormValue.Two => |x| x,
+ };
+ assertOrPanic(result);
+}
diff --git a/test/stage1/behavior/syntax.zig b/test/stage1/behavior/syntax.zig
new file mode 100644
index 0000000000000000000000000000000000000000..451e396142922fd102fc6ab8745e22e30b21b0eb
--- /dev/null
+++ b/test/stage1/behavior/syntax.zig
@@ -0,0 +1,60 @@
+// Test trailing comma syntax
+// zig fmt: off
+
+const struct_trailing_comma = struct { x: i32, y: i32, };
+const struct_no_comma = struct { x: i32, y: i32 };
+const struct_fn_no_comma = struct { fn m() void {} y: i32 };
+
+const enum_no_comma = enum { A, B };
+
+fn container_init() void {
+ const S = struct { x: i32, y: i32 };
+ _ = S { .x = 1, .y = 2 };
+ _ = S { .x = 1, .y = 2, };
+}
+
+fn type_expr_return1() if (true) A {}
+fn type_expr_return2() for (true) |_| A {}
+fn type_expr_return3() while (true) A {}
+fn type_expr_return4() comptime A {}
+
+fn switch_cases(x: i32) void {
+ switch (x) {
+ 1,2,3 => {},
+ 4,5, => {},
+ 6...8, => {},
+ else => {},
+ }
+}
+
+fn switch_prongs(x: i32) void {
+ switch (x) {
+ 0 => {},
+ else => {},
+ }
+ switch (x) {
+ 0 => {},
+ else => {}
+ }
+}
+
+const fn_no_comma = fn(i32, i32)void;
+const fn_trailing_comma = fn(i32, i32,)void;
+
+fn fn_calls() void {
+ fn add(x: i32, y: i32,) i32 { x + y };
+ _ = add(1, 2);
+ _ = add(1, 2,);
+}
+
+fn asm_lists() void {
+ if (false) { // Build AST but don't analyze
+ asm ("not real assembly"
+ :[a] "x" (x),);
+ asm ("not real assembly"
+ :[a] "x" (->i32),:[a] "x" (1),);
+ asm ("still not real assembly"
+ :::"a","b",);
+ }
+}
+
diff --git a/test/stage1/behavior/this.zig b/test/stage1/behavior/this.zig
new file mode 100644
index 0000000000000000000000000000000000000000..0e3a7a03ae078bf43dc7f8c2cb66fbfda66860eb
--- /dev/null
+++ b/test/stage1/behavior/this.zig
@@ -0,0 +1,35 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const module = @This();
+
+fn Point(comptime T: type) type {
+ return struct {
+ const Self = @This();
+ x: T,
+ y: T,
+
+ fn addOne(self: *Self) void {
+ self.x += 1;
+ self.y += 1;
+ }
+ };
+}
+
+fn add(x: i32, y: i32) i32 {
+ return x + y;
+}
+
+test "this refer to module call private fn" {
+ assertOrPanic(module.add(1, 2) == 3);
+}
+
+test "this refer to container" {
+ var pt = Point(i32){
+ .x = 12,
+ .y = 34,
+ };
+ pt.addOne();
+ assertOrPanic(pt.x == 13);
+ assertOrPanic(pt.y == 35);
+}
+
diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig
new file mode 100644
index 0000000000000000000000000000000000000000..b7904bc7fbca8f21ad3ba7800a0f5235a84b3fa5
--- /dev/null
+++ b/test/stage1/behavior/truncate.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "truncate u0 to larger integer allowed and has comptime known result" {
+ var x: u0 = 0;
+ const y = @truncate(u8, x);
+ comptime assertOrPanic(y == 0);
+}
diff --git a/test/stage1/behavior/try.zig b/test/stage1/behavior/try.zig
new file mode 100644
index 0000000000000000000000000000000000000000..ed48875eb46629628b6201aa1a3f4df7d7ca677a
--- /dev/null
+++ b/test/stage1/behavior/try.zig
@@ -0,0 +1,43 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "try on error union" {
+ tryOnErrorUnionImpl();
+ comptime tryOnErrorUnionImpl();
+}
+
+fn tryOnErrorUnionImpl() void {
+ const x = if (returnsTen()) |val| val + 1 else |err| switch (err) {
+ error.ItBroke, error.NoMem => 1,
+ error.CrappedOut => i32(2),
+ else => unreachable,
+ };
+ assertOrPanic(x == 11);
+}
+
+fn returnsTen() anyerror!i32 {
+ return 10;
+}
+
+test "try without vars" {
+ const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
+ assertOrPanic(result1 == 2);
+
+ const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
+ assertOrPanic(result2 == 1);
+}
+
+fn failIfTrue(ok: bool) anyerror!void {
+ if (ok) {
+ return error.ItBroke;
+ } else {
+ return;
+ }
+}
+
+test "try then not executed with assignment" {
+ if (failIfTrue(true)) {
+ unreachable;
+ } else |err| {
+ assertOrPanic(err == error.ItBroke);
+ }
+}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f3bb17b282a66e857379d4846c0f9098b39a9421
--- /dev/null
+++ b/test/stage1/behavior/type_info.zig
@@ -0,0 +1,276 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const TypeInfo = @import("builtin").TypeInfo;
+const TypeId = @import("builtin").TypeId;
+
+test "type info: tag type, void info" {
+ testBasic();
+ comptime testBasic();
+}
+
+fn testBasic() void {
+ assertOrPanic(@TagType(TypeInfo) == TypeId);
+ const void_info = @typeInfo(void);
+ assertOrPanic(TypeId(void_info) == TypeId.Void);
+ assertOrPanic(void_info.Void == {});
+}
+
+test "type info: integer, floating point type info" {
+ testIntFloat();
+ comptime testIntFloat();
+}
+
+fn testIntFloat() void {
+ const u8_info = @typeInfo(u8);
+ assertOrPanic(TypeId(u8_info) == TypeId.Int);
+ assertOrPanic(!u8_info.Int.is_signed);
+ assertOrPanic(u8_info.Int.bits == 8);
+
+ const f64_info = @typeInfo(f64);
+ assertOrPanic(TypeId(f64_info) == TypeId.Float);
+ assertOrPanic(f64_info.Float.bits == 64);
+}
+
+test "type info: pointer type info" {
+ testPointer();
+ comptime testPointer();
+}
+
+fn testPointer() void {
+ const u32_ptr_info = @typeInfo(*u32);
+ assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+ assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
+ assertOrPanic(u32_ptr_info.Pointer.is_const == false);
+ assertOrPanic(u32_ptr_info.Pointer.is_volatile == false);
+ assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32));
+ assertOrPanic(u32_ptr_info.Pointer.child == u32);
+}
+
+test "type info: unknown length pointer type info" {
+ testUnknownLenPtr();
+ comptime testUnknownLenPtr();
+}
+
+fn testUnknownLenPtr() void {
+ const u32_ptr_info = @typeInfo([*]const volatile f64);
+ assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+ assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+ assertOrPanic(u32_ptr_info.Pointer.is_const == true);
+ assertOrPanic(u32_ptr_info.Pointer.is_volatile == true);
+ assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64));
+ assertOrPanic(u32_ptr_info.Pointer.child == f64);
+}
+
+test "type info: slice type info" {
+ testSlice();
+ comptime testSlice();
+}
+
+fn testSlice() void {
+ const u32_slice_info = @typeInfo([]u32);
+ assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer);
+ assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
+ assertOrPanic(u32_slice_info.Pointer.is_const == false);
+ assertOrPanic(u32_slice_info.Pointer.is_volatile == false);
+ assertOrPanic(u32_slice_info.Pointer.alignment == 4);
+ assertOrPanic(u32_slice_info.Pointer.child == u32);
+}
+
+test "type info: array type info" {
+ testArray();
+ comptime testArray();
+}
+
+fn testArray() void {
+ const arr_info = @typeInfo([42]bool);
+ assertOrPanic(TypeId(arr_info) == TypeId.Array);
+ assertOrPanic(arr_info.Array.len == 42);
+ assertOrPanic(arr_info.Array.child == bool);
+}
+
+test "type info: optional type info" {
+ testOptional();
+ comptime testOptional();
+}
+
+fn testOptional() void {
+ const null_info = @typeInfo(?void);
+ assertOrPanic(TypeId(null_info) == TypeId.Optional);
+ assertOrPanic(null_info.Optional.child == void);
+}
+
+test "type info: promise info" {
+ testPromise();
+ comptime testPromise();
+}
+
+fn testPromise() void {
+ const null_promise_info = @typeInfo(promise);
+ assertOrPanic(TypeId(null_promise_info) == TypeId.Promise);
+ assertOrPanic(null_promise_info.Promise.child == null);
+
+ const promise_info = @typeInfo(promise->usize);
+ assertOrPanic(TypeId(promise_info) == TypeId.Promise);
+ assertOrPanic(promise_info.Promise.child.? == usize);
+}
+
+test "type info: error set, error union info" {
+ testErrorSet();
+ comptime testErrorSet();
+}
+
+fn testErrorSet() void {
+ const TestErrorSet = error{
+ First,
+ Second,
+ Third,
+ };
+
+ const error_set_info = @typeInfo(TestErrorSet);
+ assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet);
+ assertOrPanic(error_set_info.ErrorSet.errors.len == 3);
+ assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
+ assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
+
+ const error_union_info = @typeInfo(TestErrorSet!usize);
+ assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion);
+ assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet);
+ assertOrPanic(error_union_info.ErrorUnion.payload == usize);
+}
+
+test "type info: enum info" {
+ testEnum();
+ comptime testEnum();
+}
+
+fn testEnum() void {
+ const Os = enum {
+ Windows,
+ Macos,
+ Linux,
+ FreeBSD,
+ };
+
+ const os_info = @typeInfo(Os);
+ assertOrPanic(TypeId(os_info) == TypeId.Enum);
+ assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(os_info.Enum.fields.len == 4);
+ assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
+ assertOrPanic(os_info.Enum.fields[3].value == 3);
+ assertOrPanic(os_info.Enum.tag_type == u2);
+ assertOrPanic(os_info.Enum.defs.len == 0);
+}
+
+test "type info: union info" {
+ testUnion();
+ comptime testUnion();
+}
+
+fn testUnion() void {
+ const typeinfo_info = @typeInfo(TypeInfo);
+ assertOrPanic(TypeId(typeinfo_info) == TypeId.Union);
+ assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId);
+ assertOrPanic(typeinfo_info.Union.fields.len == 25);
+ assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null);
+ assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
+ assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
+ assertOrPanic(typeinfo_info.Union.defs.len == 21);
+
+ const TestNoTagUnion = union {
+ Foo: void,
+ Bar: u32,
+ };
+
+ const notag_union_info = @typeInfo(TestNoTagUnion);
+ assertOrPanic(TypeId(notag_union_info) == TypeId.Union);
+ assertOrPanic(notag_union_info.Union.tag_type == null);
+ assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(notag_union_info.Union.fields.len == 2);
+ assertOrPanic(notag_union_info.Union.fields[0].enum_field == null);
+ assertOrPanic(notag_union_info.Union.fields[1].field_type == u32);
+
+ const TestExternUnion = extern union {
+ foo: *c_void,
+ };
+
+ const extern_union_info = @typeInfo(TestExternUnion);
+ assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
+ assertOrPanic(extern_union_info.Union.tag_type == null);
+ assertOrPanic(extern_union_info.Union.fields[0].enum_field == null);
+ assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void);
+}
+
+test "type info: struct info" {
+ testStruct();
+ comptime testStruct();
+}
+
+fn testStruct() void {
+ const struct_info = @typeInfo(TestStruct);
+ assertOrPanic(TypeId(struct_info) == TypeId.Struct);
+ assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
+ assertOrPanic(struct_info.Struct.fields.len == 3);
+ assertOrPanic(struct_info.Struct.fields[1].offset == null);
+ assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct);
+ assertOrPanic(struct_info.Struct.defs.len == 2);
+ assertOrPanic(struct_info.Struct.defs[0].is_pub);
+ assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
+}
+
+const TestStruct = packed struct {
+ const Self = @This();
+
+ fieldA: usize,
+ fieldB: void,
+ fieldC: *Self,
+
+ pub fn foo(self: *const Self) void {}
+};
+
+test "type info: function type info" {
+ testFunction();
+ comptime testFunction();
+}
+
+fn testFunction() void {
+ const fn_info = @typeInfo(@typeOf(foo));
+ assertOrPanic(TypeId(fn_info) == TypeId.Fn);
+ assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
+ assertOrPanic(fn_info.Fn.is_generic);
+ assertOrPanic(fn_info.Fn.args.len == 2);
+ assertOrPanic(fn_info.Fn.is_var_args);
+ assertOrPanic(fn_info.Fn.return_type == null);
+ assertOrPanic(fn_info.Fn.async_allocator_type == null);
+
+ const test_instance: TestStruct = undefined;
+ const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
+ assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn);
+ assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
+}
+
+fn foo(comptime a: usize, b: bool, args: ...) usize {
+ return 0;
+}
+
+test "typeInfo with comptime parameter in struct fn def" {
+ const S = struct {
+ pub fn func(comptime x: f32) void {}
+ };
+ comptime var info = @typeInfo(S);
+}
+
+test "type info: vectors" {
+ testVector();
+ comptime testVector();
+}
+
+fn testVector() void {
+ const vec_info = @typeInfo(@Vector(4, i32));
+ assertOrPanic(TypeId(vec_info) == TypeId.Vector);
+ assertOrPanic(vec_info.Vector.len == 4);
+ assertOrPanic(vec_info.Vector.child == i32);
+}
diff --git a/test/stage1/behavior/undefined.zig b/test/stage1/behavior/undefined.zig
new file mode 100644
index 0000000000000000000000000000000000000000..333e217d493bdc3d13800861bc13533f13be8773
--- /dev/null
+++ b/test/stage1/behavior/undefined.zig
@@ -0,0 +1,69 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+fn initStaticArray() [10]i32 {
+ var array: [10]i32 = undefined;
+ array[0] = 1;
+ array[4] = 2;
+ array[7] = 3;
+ array[9] = 4;
+ return array;
+}
+const static_array = initStaticArray();
+test "init static array to undefined" {
+ assertOrPanic(static_array[0] == 1);
+ assertOrPanic(static_array[4] == 2);
+ assertOrPanic(static_array[7] == 3);
+ assertOrPanic(static_array[9] == 4);
+
+ comptime {
+ assertOrPanic(static_array[0] == 1);
+ assertOrPanic(static_array[4] == 2);
+ assertOrPanic(static_array[7] == 3);
+ assertOrPanic(static_array[9] == 4);
+ }
+}
+
+const Foo = struct {
+ x: i32,
+
+ fn setFooXMethod(foo: *Foo) void {
+ foo.x = 3;
+ }
+};
+
+fn setFooX(foo: *Foo) void {
+ foo.x = 2;
+}
+
+test "assign undefined to struct" {
+ comptime {
+ var foo: Foo = undefined;
+ setFooX(&foo);
+ assertOrPanic(foo.x == 2);
+ }
+ {
+ var foo: Foo = undefined;
+ setFooX(&foo);
+ assertOrPanic(foo.x == 2);
+ }
+}
+
+test "assign undefined to struct with method" {
+ comptime {
+ var foo: Foo = undefined;
+ foo.setFooXMethod();
+ assertOrPanic(foo.x == 3);
+ }
+ {
+ var foo: Foo = undefined;
+ foo.setFooXMethod();
+ assertOrPanic(foo.x == 3);
+ }
+}
+
+test "type name of undefined" {
+ const x = undefined;
+ assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
+}
+
diff --git a/test/stage1/behavior/underscore.zig b/test/stage1/behavior/underscore.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7443319336b0c66a63eb94bd4a287858f5e86118
--- /dev/null
+++ b/test/stage1/behavior/underscore.zig
@@ -0,0 +1,28 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "ignore lval with underscore" {
+ _ = false;
+}
+
+test "ignore lval with underscore (for loop)" {
+ for ([]void{}) |_, i| {
+ for ([]void{}) |_, j| {
+ break;
+ }
+ break;
+ }
+}
+
+test "ignore lval with underscore (while loop)" {
+ while (optionalReturnError()) |_| {
+ while (optionalReturnError()) |_| {
+ break;
+ } else |_| {}
+ break;
+ } else |_| {}
+}
+
+fn optionalReturnError() !?u32 {
+ return error.optionalReturnError;
+}
diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c8e8feb11ea661cb5711ebccd19ed0a599ce495f
--- /dev/null
+++ b/test/stage1/behavior/union.zig
@@ -0,0 +1,352 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const Value = union(enum) {
+ Int: u64,
+ Array: [9]u8,
+};
+
+const Agg = struct {
+ val1: Value,
+ val2: Value,
+};
+
+const v1 = Value{ .Int = 1234 };
+const v2 = Value{ .Array = []u8{3} ** 9 };
+
+const err = (anyerror!Agg)(Agg{
+ .val1 = v1,
+ .val2 = v2,
+});
+
+const array = []Value{
+ v1,
+ v2,
+ v1,
+ v2,
+};
+
+test "unions embedded in aggregate types" {
+ switch (array[1]) {
+ Value.Array => |arr| assertOrPanic(arr[4] == 3),
+ else => unreachable,
+ }
+ switch ((err catch unreachable).val1) {
+ Value.Int => |x| assertOrPanic(x == 1234),
+ else => unreachable,
+ }
+}
+
+const Foo = union {
+ float: f64,
+ int: i32,
+};
+
+test "basic unions" {
+ var foo = Foo{ .int = 1 };
+ assertOrPanic(foo.int == 1);
+ foo = Foo{ .float = 12.34 };
+ assertOrPanic(foo.float == 12.34);
+}
+
+test "comptime union field access" {
+ comptime {
+ var foo = Foo{ .int = 0 };
+ assertOrPanic(foo.int == 0);
+
+ foo = Foo{ .float = 42.42 };
+ assertOrPanic(foo.float == 42.42);
+ }
+}
+
+test "init union with runtime value" {
+ var foo: Foo = undefined;
+
+ setFloat(&foo, 12.34);
+ assertOrPanic(foo.float == 12.34);
+
+ setInt(&foo, 42);
+ assertOrPanic(foo.int == 42);
+}
+
+fn setFloat(foo: *Foo, x: f64) void {
+ foo.* = Foo{ .float = x };
+}
+
+fn setInt(foo: *Foo, x: i32) void {
+ foo.* = Foo{ .int = x };
+}
+
+const FooExtern = extern union {
+ float: f64,
+ int: i32,
+};
+
+test "basic extern unions" {
+ var foo = FooExtern{ .int = 1 };
+ assertOrPanic(foo.int == 1);
+ foo.float = 12.34;
+ assertOrPanic(foo.float == 12.34);
+}
+
+const Letter = enum {
+ A,
+ B,
+ C,
+};
+const Payload = union(Letter) {
+ A: i32,
+ B: f64,
+ C: bool,
+};
+
+test "union with specified enum tag" {
+ doTest();
+ comptime doTest();
+}
+
+fn doTest() void {
+ assertOrPanic(bar(Payload{ .A = 1234 }) == -10);
+}
+
+fn bar(value: Payload) i32 {
+ assertOrPanic(Letter(value) == Letter.A);
+ return switch (value) {
+ Payload.A => |x| return x - 1244,
+ Payload.B => |x| if (x == 12.34) i32(20) else 21,
+ Payload.C => |x| if (x) i32(30) else 31,
+ };
+}
+
+const MultipleChoice = union(enum(u32)) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+test "simple union(enum(u32))" {
+ var x = MultipleChoice.C;
+ assertOrPanic(x == MultipleChoice.C);
+ assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
+}
+
+const MultipleChoice2 = union(enum(u32)) {
+ Unspecified1: i32,
+ A: f32 = 20,
+ Unspecified2: void,
+ B: bool = 40,
+ Unspecified3: i32,
+ C: i8 = 60,
+ Unspecified4: void,
+ D: void = 1000,
+ Unspecified5: i32,
+};
+
+test "union(enum(u32)) with specified and unspecified tag values" {
+ comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32);
+ testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+ comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
+ assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
+ assertOrPanic(1123 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => |v| i32(1000) + v,
+ MultipleChoice2.D => 4,
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
+
+const ExternPtrOrInt = extern union {
+ ptr: *u8,
+ int: u64,
+};
+test "extern union size" {
+ comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8);
+}
+
+const PackedPtrOrInt = packed union {
+ ptr: *u8,
+ int: u64,
+};
+test "extern union size" {
+ comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8);
+}
+
+const ZeroBits = union {
+ OnlyField: void,
+};
+test "union with only 1 field which is void should be zero bits" {
+ comptime assertOrPanic(@sizeOf(ZeroBits) == 0);
+}
+
+const TheTag = enum {
+ A,
+ B,
+ C,
+};
+const TheUnion = union(TheTag) {
+ A: i32,
+ B: i32,
+ C: i32,
+};
+test "union field access gives the enum values" {
+ assertOrPanic(TheUnion.A == TheTag.A);
+ assertOrPanic(TheUnion.B == TheTag.B);
+ assertOrPanic(TheUnion.C == TheTag.C);
+}
+
+test "cast union to tag type of union" {
+ testCastUnionToTagType(TheUnion{ .B = 1234 });
+ comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
+}
+
+fn testCastUnionToTagType(x: TheUnion) void {
+ assertOrPanic(TheTag(x) == TheTag.B);
+}
+
+test "cast tag type of union to union" {
+ var x: Value2 = Letter2.B;
+ assertOrPanic(Letter2(x) == Letter2.B);
+}
+const Letter2 = enum {
+ A,
+ B,
+ C,
+};
+const Value2 = union(Letter2) {
+ A: i32,
+ B,
+ C,
+};
+
+test "implicit cast union to its tag type" {
+ var x: Value2 = Letter2.B;
+ assertOrPanic(x == Letter2.B);
+ giveMeLetterB(x);
+}
+fn giveMeLetterB(x: Letter2) void {
+ assertOrPanic(x == Value2.B);
+}
+
+pub const PackThis = union(enum) {
+ Invalid: bool,
+ StringLiteral: u2,
+};
+
+test "constant packed union" {
+ testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }});
+}
+
+fn testConstPackedUnion(expected_tokens: []const PackThis) void {
+ assertOrPanic(expected_tokens[0].StringLiteral == 1);
+}
+
+test "switch on union with only 1 field" {
+ var r: PartialInst = undefined;
+ r = PartialInst.Compiled;
+ switch (r) {
+ PartialInst.Compiled => {
+ var z: PartialInstWithPayload = undefined;
+ z = PartialInstWithPayload{ .Compiled = 1234 };
+ switch (z) {
+ PartialInstWithPayload.Compiled => |x| {
+ assertOrPanic(x == 1234);
+ return;
+ },
+ }
+ },
+ }
+ unreachable;
+}
+
+const PartialInst = union(enum) {
+ Compiled,
+};
+
+const PartialInstWithPayload = union(enum) {
+ Compiled: i32,
+};
+
+test "access a member of tagged union with conflicting enum tag name" {
+ const Bar = union(enum) {
+ A: A,
+ B: B,
+
+ const A = u8;
+ const B = void;
+ };
+
+ comptime assertOrPanic(Bar.A == u8);
+}
+
+test "tagged union initialization with runtime void" {
+ assertOrPanic(testTaggedUnionInit({}));
+}
+
+const TaggedUnionWithAVoid = union(enum) {
+ A,
+ B: i32,
+};
+
+fn testTaggedUnionInit(x: var) bool {
+ const y = TaggedUnionWithAVoid{ .A = x };
+ return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A;
+}
+
+pub const UnionEnumNoPayloads = union(enum) {
+ A,
+ B,
+};
+
+test "tagged union with no payloads" {
+ const a = UnionEnumNoPayloads{ .B = {} };
+ switch (a) {
+ @TagType(UnionEnumNoPayloads).A => @panic("wrong"),
+ @TagType(UnionEnumNoPayloads).B => {},
+ }
+}
+
+test "union with only 1 field casted to its enum type" {
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const Expr = union(enum) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ const Tag = @TagType(Expr);
+ comptime assertOrPanic(@TagType(Tag) == comptime_int);
+ var t = Tag(e);
+ assertOrPanic(t == Expr.Literal);
+}
+
+test "union with only 1 field casted to its enum type which has enum value specified" {
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const Tag = enum {
+ Literal = 33,
+ };
+
+ const Expr = union(Tag) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ comptime assertOrPanic(@TagType(Tag) == comptime_int);
+ var t = Tag(e);
+ assertOrPanic(t == Expr.Literal);
+ assertOrPanic(@enumToInt(t) == 33);
+ comptime assertOrPanic(@enumToInt(t) == 33);
+}
diff --git a/test/stage1/behavior/var_args.zig b/test/stage1/behavior/var_args.zig
new file mode 100644
index 0000000000000000000000000000000000000000..1f782a3bb3a3c9ba1e5b43c7a3fce0556b6f05e6
--- /dev/null
+++ b/test/stage1/behavior/var_args.zig
@@ -0,0 +1,84 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+fn add(args: ...) i32 {
+ var sum = i32(0);
+ {
+ comptime var i: usize = 0;
+ inline while (i < args.len) : (i += 1) {
+ sum += args[i];
+ }
+ }
+ return sum;
+}
+
+test "add arbitrary args" {
+ assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10);
+ assertOrPanic(add(i32(1234)) == 1234);
+ assertOrPanic(add() == 0);
+}
+
+fn readFirstVarArg(args: ...) void {
+ const value = args[0];
+}
+
+test "send void arg to var args" {
+ readFirstVarArg({});
+}
+
+test "pass args directly" {
+ assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
+ assertOrPanic(addSomeStuff(i32(1234)) == 1234);
+ assertOrPanic(addSomeStuff() == 0);
+}
+
+fn addSomeStuff(args: ...) i32 {
+ return add(args);
+}
+
+test "runtime parameter before var args" {
+ assertOrPanic(extraFn(10) == 0);
+ assertOrPanic(extraFn(10, false) == 1);
+ assertOrPanic(extraFn(10, false, true) == 2);
+
+ // TODO issue #313
+ //comptime {
+ // assertOrPanic(extraFn(10) == 0);
+ // assertOrPanic(extraFn(10, false) == 1);
+ // assertOrPanic(extraFn(10, false, true) == 2);
+ //}
+}
+
+fn extraFn(extra: u32, args: ...) usize {
+ if (args.len >= 1) {
+ assertOrPanic(args[0] == false);
+ }
+ if (args.len >= 2) {
+ assertOrPanic(args[1] == true);
+ }
+ return args.len;
+}
+
+const foos = []fn (...) bool{
+ foo1,
+ foo2,
+};
+
+fn foo1(args: ...) bool {
+ return true;
+}
+fn foo2(args: ...) bool {
+ return false;
+}
+
+test "array of var args functions" {
+ assertOrPanic(foos[0]());
+ assertOrPanic(!foos[1]());
+}
+
+test "pass zero length array to var args param" {
+ doNothingWithFirstArg("");
+}
+
+fn doNothingWithFirstArg(args: ...) void {
+ const a = args[0];
+}
diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig
new file mode 100644
index 0000000000000000000000000000000000000000..53c5d0138179bfb715034a90050c298e6a42d433
--- /dev/null
+++ b/test/stage1/behavior/vector.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "implicit array to vector and vector to array" {
+ const S = struct {
+ fn doTheTest() void {
+ var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40};
+ const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4};
+ v +%= x;
+ const result: [4]i32 = v;
+ assertOrPanic(result[0] == 11);
+ assertOrPanic(result[1] == 22);
+ assertOrPanic(result[2] == 33);
+ assertOrPanic(result[3] == 44);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
diff --git a/test/stage1/behavior/void.zig b/test/stage1/behavior/void.zig
new file mode 100644
index 0000000000000000000000000000000000000000..431d3f4eb1033606614c9abe35898951ea8a5f69
--- /dev/null
+++ b/test/stage1/behavior/void.zig
@@ -0,0 +1,35 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+const Foo = struct {
+ a: void,
+ b: i32,
+ c: void,
+};
+
+test "compare void with void compile time known" {
+ comptime {
+ const foo = Foo{
+ .a = {},
+ .b = 1,
+ .c = {},
+ };
+ assertOrPanic(foo.a == {});
+ }
+}
+
+test "iterate over a void slice" {
+ var j: usize = 0;
+ for (times(10)) |_, i| {
+ assertOrPanic(i == j);
+ j += 1;
+ }
+}
+
+fn times(n: usize) []const void {
+ return ([*]void)(undefined)[0..n];
+}
+
+test "void optional" {
+ var x: ?void = {};
+ assertOrPanic(x != null);
+}
diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig
new file mode 100644
index 0000000000000000000000000000000000000000..579b4e4db8529cdbf8819249228a7dfe876f9aec
--- /dev/null
+++ b/test/stage1/behavior/while.zig
@@ -0,0 +1,228 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "while loop" {
+ var i: i32 = 0;
+ while (i < 4) {
+ i += 1;
+ }
+ assertOrPanic(i == 4);
+ assertOrPanic(whileLoop1() == 1);
+}
+fn whileLoop1() i32 {
+ return whileLoop2();
+}
+fn whileLoop2() i32 {
+ while (true) {
+ return 1;
+ }
+}
+
+test "static eval while" {
+ assertOrPanic(static_eval_while_number == 1);
+}
+const static_eval_while_number = staticWhileLoop1();
+fn staticWhileLoop1() i32 {
+ return whileLoop2();
+}
+fn staticWhileLoop2() i32 {
+ while (true) {
+ return 1;
+ }
+}
+
+test "continue and break" {
+ runContinueAndBreakTest();
+ assertOrPanic(continue_and_break_counter == 8);
+}
+var continue_and_break_counter: i32 = 0;
+fn runContinueAndBreakTest() void {
+ var i: i32 = 0;
+ while (true) {
+ continue_and_break_counter += 2;
+ i += 1;
+ if (i < 4) {
+ continue;
+ }
+ break;
+ }
+ assertOrPanic(i == 4);
+}
+
+test "return with implicit cast from while loop" {
+ returnWithImplicitCastFromWhileLoopTest() catch unreachable;
+}
+fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
+ while (true) {
+ return;
+ }
+}
+
+test "while with continue expression" {
+ var sum: i32 = 0;
+ {
+ var i: i32 = 0;
+ while (i < 10) : (i += 1) {
+ if (i == 5) continue;
+ sum += i;
+ }
+ }
+ assertOrPanic(sum == 40);
+}
+
+test "while with else" {
+ var sum: i32 = 0;
+ var i: i32 = 0;
+ var got_else: i32 = 0;
+ while (i < 10) : (i += 1) {
+ sum += 1;
+ } else {
+ got_else += 1;
+ }
+ assertOrPanic(sum == 10);
+ assertOrPanic(got_else == 1);
+}
+
+test "while with optional as condition" {
+ numbers_left = 10;
+ var sum: i32 = 0;
+ while (getNumberOrNull()) |value| {
+ sum += value;
+ }
+ assertOrPanic(sum == 45);
+}
+
+test "while with optional as condition with else" {
+ numbers_left = 10;
+ var sum: i32 = 0;
+ var got_else: i32 = 0;
+ while (getNumberOrNull()) |value| {
+ sum += value;
+ assertOrPanic(got_else == 0);
+ } else {
+ got_else += 1;
+ }
+ assertOrPanic(sum == 45);
+ assertOrPanic(got_else == 1);
+}
+
+test "while with error union condition" {
+ numbers_left = 10;
+ var sum: i32 = 0;
+ var got_else: i32 = 0;
+ while (getNumberOrErr()) |value| {
+ sum += value;
+ } else |err| {
+ assertOrPanic(err == error.OutOfNumbers);
+ got_else += 1;
+ }
+ assertOrPanic(sum == 45);
+ assertOrPanic(got_else == 1);
+}
+
+var numbers_left: i32 = undefined;
+fn getNumberOrErr() anyerror!i32 {
+ return if (numbers_left == 0) error.OutOfNumbers else x: {
+ numbers_left -= 1;
+ break :x numbers_left;
+ };
+}
+fn getNumberOrNull() ?i32 {
+ return if (numbers_left == 0) null else x: {
+ numbers_left -= 1;
+ break :x numbers_left;
+ };
+}
+
+test "while on optional with else result follow else prong" {
+ const result = while (returnNull()) |value| {
+ break value;
+ } else
+ i32(2);
+ assertOrPanic(result == 2);
+}
+
+test "while on optional with else result follow break prong" {
+ const result = while (returnOptional(10)) |value| {
+ break value;
+ } else
+ i32(2);
+ assertOrPanic(result == 10);
+}
+
+test "while on error union with else result follow else prong" {
+ const result = while (returnError()) |value| {
+ break value;
+ } else |err|
+ i32(2);
+ assertOrPanic(result == 2);
+}
+
+test "while on error union with else result follow break prong" {
+ const result = while (returnSuccess(10)) |value| {
+ break value;
+ } else |err|
+ i32(2);
+ assertOrPanic(result == 10);
+}
+
+test "while on bool with else result follow else prong" {
+ const result = while (returnFalse()) {
+ break i32(10);
+ } else
+ i32(2);
+ assertOrPanic(result == 2);
+}
+
+test "while on bool with else result follow break prong" {
+ const result = while (returnTrue()) {
+ break i32(10);
+ } else
+ i32(2);
+ assertOrPanic(result == 10);
+}
+
+test "break from outer while loop" {
+ testBreakOuter();
+ comptime testBreakOuter();
+}
+
+fn testBreakOuter() void {
+ outer: while (true) {
+ while (true) {
+ break :outer;
+ }
+ }
+}
+
+test "continue outer while loop" {
+ testContinueOuter();
+ comptime testContinueOuter();
+}
+
+fn testContinueOuter() void {
+ var i: usize = 0;
+ outer: while (i < 10) : (i += 1) {
+ while (true) {
+ continue :outer;
+ }
+ }
+}
+
+fn returnNull() ?i32 {
+ return null;
+}
+fn returnOptional(x: i32) ?i32 {
+ return x;
+}
+fn returnError() anyerror!i32 {
+ return error.YouWantedAnError;
+}
+fn returnSuccess(x: i32) anyerror!i32 {
+ return x;
+}
+fn returnFalse() bool {
+ return false;
+}
+fn returnTrue() bool {
+ return true;
+}
diff --git a/test/stage1/behavior/widening.zig b/test/stage1/behavior/widening.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7577868aff5414a5d27e1983ff0137bb577dc038
--- /dev/null
+++ b/test/stage1/behavior/widening.zig
@@ -0,0 +1,28 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const mem = std.mem;
+
+test "integer widening" {
+ var a: u8 = 250;
+ var b: u16 = a;
+ var c: u32 = b;
+ var d: u64 = c;
+ var e: u64 = d;
+ var f: u128 = e;
+ assertOrPanic(f == a);
+}
+
+test "implicit unsigned integer to signed integer" {
+ var a: u8 = 250;
+ var b: i16 = a;
+ assertOrPanic(b == 250);
+}
+
+test "float widening" {
+ var a: f16 = 12.34;
+ var b: f32 = a;
+ var c: f64 = b;
+ var d: f128 = c;
+ assertOrPanic(d == a);
+}
+
diff --git a/test/tests.zig b/test/tests.zig
index 1ca06b4b3452f73f173ea05c999ee130785c5e1b..548496fa2f6dac4151b53d563ad1f2c3cd9436b8 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -48,13 +48,14 @@ const test_targets = []TestTarget{
const max_stdout_size = 1 * 1024 * 1024; // 1 MB
pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompareOutputContext{
+ const cases = b.allocator.create(CompareOutputContext) catch unreachable;
+ cases.* = CompareOutputContext{
.b = b,
.step = b.step("test-compare-output", "Run the compare output tests"),
.test_index = 0,
.test_filter = test_filter,
.modes = modes,
- }) catch unreachable;
+ };
compare_output.addCases(cases);
@@ -62,13 +63,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes:
}
pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompareOutputContext{
+ const cases = b.allocator.create(CompareOutputContext) catch unreachable;
+ cases.* = CompareOutputContext{
.b = b,
.step = b.step("test-runtime-safety", "Run the runtime safety tests"),
.test_index = 0,
.test_filter = test_filter,
.modes = modes,
- }) catch unreachable;
+ };
runtime_safety.addCases(cases);
@@ -76,13 +78,14 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes:
}
pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompileErrorContext{
+ const cases = b.allocator.create(CompileErrorContext) catch unreachable;
+ cases.* = CompileErrorContext{
.b = b,
.step = b.step("test-compile-errors", "Run the compile error tests"),
.test_index = 0,
.test_filter = test_filter,
.modes = modes,
- }) catch unreachable;
+ };
compile_errors.addCases(cases);
@@ -90,13 +93,14 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes:
}
pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(BuildExamplesContext{
+ const cases = b.allocator.create(BuildExamplesContext) catch unreachable;
+ cases.* = BuildExamplesContext{
.b = b,
.step = b.step("test-build-examples", "Build the examples"),
.test_index = 0,
.test_filter = test_filter,
.modes = modes,
- }) catch unreachable;
+ };
build_examples.addCases(cases);
@@ -119,13 +123,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M
}
pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompareOutputContext{
+ const cases = b.allocator.create(CompareOutputContext) catch unreachable;
+ cases.* = CompareOutputContext{
.b = b,
.step = b.step("test-asm-link", "Run the assemble and link tests"),
.test_index = 0,
.test_filter = test_filter,
.modes = modes,
- }) catch unreachable;
+ };
assemble_and_link.addCases(cases);
@@ -133,12 +138,13 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, mode
}
pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
- const cases = b.allocator.create(TranslateCContext{
+ const cases = b.allocator.create(TranslateCContext) catch unreachable;
+ cases.* = TranslateCContext{
.b = b,
.step = b.step("test-translate-c", "Run the C transation tests"),
.test_index = 0,
.test_filter = test_filter,
- }) catch unreachable;
+ };
translate_c.addCases(cases);
@@ -146,12 +152,13 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St
}
pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
- const cases = b.allocator.create(GenHContext{
+ const cases = b.allocator.create(GenHContext) catch unreachable;
+ cases.* = GenHContext{
.b = b,
.step = b.step("test-gen-h", "Run the C header file generation tests"),
.test_index = 0,
.test_filter = test_filter,
- }) catch unreachable;
+ };
gen_h.addCases(cases);
@@ -163,25 +170,32 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons
for (test_targets) |test_target| {
const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
for (modes) |mode| {
- for ([]bool{
- false,
- true,
- }) |link_libc| {
- if (link_libc and !is_native) {
- // don't assume we have a cross-compiling libc set up
- continue;
+ for ([]bool{ false, true }) |link_libc| {
+ for ([]bool{ false, true }) |single_threaded| {
+ if (link_libc and !is_native) {
+ // don't assume we have a cross-compiling libc set up
+ continue;
+ }
+ const these_tests = b.addTest(root_src);
+ these_tests.setNamePrefix(b.fmt(
+ "{}-{}-{}-{}-{}-{} ",
+ name,
+ @tagName(test_target.os),
+ @tagName(test_target.arch),
+ @tagName(mode),
+ if (link_libc) "c" else "bare",
+ if (single_threaded) "single" else "multi",
+ ));
+ these_tests.setFilter(test_filter);
+ these_tests.setBuildMode(mode);
+ if (!is_native) {
+ these_tests.setTarget(test_target.arch, test_target.os, test_target.environ);
+ }
+ if (link_libc) {
+ these_tests.linkSystemLibrary("c");
+ }
+ step.dependOn(&these_tests.step);
}
- const these_tests = b.addTest(root_src);
- these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
- these_tests.setFilter(test_filter);
- these_tests.setBuildMode(mode);
- if (!is_native) {
- these_tests.setTarget(test_target.arch, test_target.os, test_target.environ);
- }
- if (link_libc) {
- these_tests.linkSystemLibrary("c");
- }
- step.dependOn(&these_tests.step);
}
}
}
@@ -237,7 +251,8 @@ pub const CompareOutputContext = struct {
pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep {
const allocator = context.b.allocator;
- const ptr = allocator.create(RunCompareOutputStep{
+ const ptr = allocator.create(RunCompareOutputStep) catch unreachable;
+ ptr.* = RunCompareOutputStep{
.context = context,
.exe_path = exe_path,
.name = name,
@@ -245,7 +260,7 @@ pub const CompareOutputContext = struct {
.test_index = context.test_index,
.step = build.Step.init("RunCompareOutput", allocator, make),
.cli_args = cli_args,
- }) catch unreachable;
+ };
context.test_index += 1;
return ptr;
}
@@ -324,13 +339,14 @@ pub const CompareOutputContext = struct {
pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep {
const allocator = context.b.allocator;
- const ptr = allocator.create(RuntimeSafetyRunStep{
+ const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;
+ ptr.* = RuntimeSafetyRunStep{
.context = context,
.exe_path = exe_path,
.name = name,
.test_index = context.test_index,
.step = build.Step.init("RuntimeSafetyRun", allocator, make),
- }) catch unreachable;
+ };
context.test_index += 1;
return ptr;
@@ -535,14 +551,15 @@ pub const CompileErrorContext = struct {
pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {
const allocator = context.b.allocator;
- const ptr = allocator.create(CompileCmpOutputStep{
+ const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
+ ptr.* = CompileCmpOutputStep{
.step = build.Step.init("CompileCmpOutput", allocator, make),
.context = context,
.name = name,
.test_index = context.test_index,
.case = case,
.build_mode = build_mode,
- }) catch unreachable;
+ };
context.test_index += 1;
return ptr;
@@ -654,13 +671,14 @@ pub const CompileErrorContext = struct {
}
pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
- const tc = self.b.allocator.create(TestCase{
+ const tc = self.b.allocator.create(TestCase) catch unreachable;
+ tc.* = TestCase{
.name = name,
.sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
.expected_errors = ArrayList([]const u8).init(self.b.allocator),
.link_libc = false,
.is_exe = false,
- }) catch unreachable;
+ };
tc.addSourceFile(".tmp_source.zig", source);
comptime var arg_i = 0;
@@ -814,13 +832,14 @@ pub const TranslateCContext = struct {
pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep {
const allocator = context.b.allocator;
- const ptr = allocator.create(TranslateCCmpOutputStep{
+ const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;
+ ptr.* = TranslateCCmpOutputStep{
.step = build.Step.init("ParseCCmpOutput", allocator, make),
.context = context,
.name = name,
.test_index = context.test_index,
.case = case,
- }) catch unreachable;
+ };
context.test_index += 1;
return ptr;
@@ -921,12 +940,13 @@ pub const TranslateCContext = struct {
}
pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
- const tc = self.b.allocator.create(TestCase{
+ const tc = self.b.allocator.create(TestCase) catch unreachable;
+ tc.* = TestCase{
.name = name,
.sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
.expected_lines = ArrayList([]const u8).init(self.b.allocator),
.allow_warnings = allow_warnings,
- }) catch unreachable;
+ };
tc.addSourceFile(filename, source);
comptime var arg_i = 0;
@@ -1008,14 +1028,15 @@ pub const GenHContext = struct {
pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep {
const allocator = context.b.allocator;
- const ptr = allocator.create(GenHCmpOutputStep{
+ const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
+ ptr.* = GenHCmpOutputStep{
.step = build.Step.init("ParseCCmpOutput", allocator, make),
.context = context,
.h_path = h_path,
.name = name,
.test_index = context.test_index,
.case = case,
- }) catch unreachable;
+ };
context.test_index += 1;
return ptr;
@@ -1055,11 +1076,12 @@ pub const GenHContext = struct {
}
pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
- const tc = self.b.allocator.create(TestCase{
+ const tc = self.b.allocator.create(TestCase) catch unreachable;
+ tc.* = TestCase{
.name = name,
.sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
.expected_lines = ArrayList([]const u8).init(self.b.allocator),
- }) catch unreachable;
+ };
tc.addSourceFile(filename, source);
comptime var arg_i = 0;