Commit 3af9731600
Changed files (9)
src/codegen/wasm.zig
@@ -809,6 +809,11 @@ pub const Context = struct {
try self.emitConstant(val, ty);
return Result.appended;
},
+ .Struct => {
+ // TODO write the fields for real
+ try self.code.writer().writeByteNTimes(0xaa, ty.abiSize(self.target));
+ return Result{ .appended = {} };
+ },
else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
}
}
src/codegen.zig
@@ -285,6 +285,13 @@ pub fn generateSymbol(
}
return Result{ .appended = {} };
},
+ .Struct => {
+ const field_vals = typed_value.val.castTag(.@"struct").?.data;
+ _ = field_vals; // TODO write the fields for real
+ const target = bin_file.options.target;
+ try code.writer().writeByteNTimes(0xaa, typed_value.ty.abiSize(target));
+ return Result{ .appended = {} };
+ },
else => |t| {
return Result{
.fail = try ErrorMsg.create(
src/Compilation.zig
@@ -46,6 +46,7 @@ stage1_cache_manifest: *Cache.Manifest = undefined,
link_error_flags: link.File.ErrorFlags = .{},
work_queue: std.fifo.LinearFifo(Job, .Dynamic),
+anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic),
/// These jobs are to invoke the Clang compiler to create an object file, which
/// gets linked with the Compilation.
@@ -1460,6 +1461,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.emit_analysis = options.emit_analysis,
.emit_docs = options.emit_docs,
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
+ .anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
.c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
.astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa),
.embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa),
@@ -1646,6 +1648,7 @@ pub fn destroy(self: *Compilation) void {
const gpa = self.gpa;
self.work_queue.deinit();
+ self.anon_work_queue.deinit();
self.c_object_work_queue.deinit();
self.astgen_work_queue.deinit();
self.embed_file_work_queue.deinit();
@@ -2072,7 +2075,6 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 {
}
pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {
- const gpa = self.gpa;
// If the terminal is dumb, we dont want to show the user all the
// output.
var progress: std.Progress = .{ .dont_print_on_dumb = true };
@@ -2146,7 +2148,24 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
}
}
- while (self.work_queue.readItem()) |work_item| switch (work_item) {
+ // In this main loop we give priority to non-anonymous Decls in the work queue, so
+ // that they can establish references to anonymous Decls, setting alive=true in the
+ // backend, preventing anonymous Decls from being prematurely destroyed.
+ while (true) {
+ if (self.work_queue.readItem()) |work_item| {
+ try processOneJob(self, work_item, main_progress_node);
+ continue;
+ }
+ if (self.anon_work_queue.readItem()) |work_item| {
+ try processOneJob(self, work_item, main_progress_node);
+ continue;
+ }
+ break;
+ }
+}
+
+fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress.Node) !void {
+ switch (job) {
.codegen_decl => |decl| switch (decl.analysis) {
.unreferenced => unreachable,
.in_progress => unreachable,
@@ -2157,24 +2176,25 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.codegen_failure,
.dependency_failure,
.sema_failure_retryable,
- => continue,
+ => return,
.complete, .codegen_failure_retryable => {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
+ const module = comp.bin_file.options.module.?;
assert(decl.has_tv);
assert(decl.ty.hasCodeGenBits());
if (decl.alive) {
try module.linkerUpdateDecl(decl);
- continue;
+ return;
}
// Instead of sending this decl to the linker, we actually will delete it
// because we found out that it in fact was never referenced.
module.deleteUnusedDecl(decl);
+ return;
},
},
.codegen_func => |func| switch (func.owner_decl.analysis) {
@@ -2187,20 +2207,21 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.codegen_failure,
.dependency_failure,
.sema_failure_retryable,
- => continue,
+ => return,
.complete, .codegen_failure_retryable => {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
switch (func.state) {
- .sema_failure, .dependency_failure => continue,
+ .sema_failure, .dependency_failure => return,
.queued => {},
.in_progress => unreachable,
.inline_only => unreachable, // don't queue work for this
.success => unreachable, // don't queue it twice
}
- const module = self.bin_file.options.module.?;
+ const gpa = comp.gpa;
+ const module = comp.bin_file.options.module.?;
const decl = func.owner_decl;
var tmp_arena = std.heap.ArenaAllocator.init(gpa);
@@ -2210,7 +2231,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
var air = module.analyzeFnBody(decl, func, sema_arena) catch |err| switch (err) {
error.AnalysisFail => {
assert(func.state != .in_progress);
- continue;
+ return;
},
error.OutOfMemory => return error.OutOfMemory,
};
@@ -2220,17 +2241,17 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
var liveness = try Liveness.analyze(gpa, air, decl.getFileScope().zir);
defer liveness.deinit(gpa);
- if (builtin.mode == .Debug and self.verbose_air) {
+ if (builtin.mode == .Debug and comp.verbose_air) {
std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
@import("print_air.zig").dump(gpa, air, decl.getFileScope().zir, liveness);
std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
}
- self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
+ comp.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
decl.analysis = .codegen_failure;
- continue;
+ return;
},
else => {
try module.failed_decls.ensureUnusedCapacity(gpa, 1);
@@ -2241,10 +2262,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.{@errorName(err)},
));
decl.analysis = .codegen_failure_retryable;
- continue;
+ return;
},
};
- continue;
+ return;
},
},
.emit_h_decl => |decl| switch (decl.analysis) {
@@ -2256,14 +2277,15 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.sema_failure,
.dependency_failure,
.sema_failure_retryable,
- => continue,
+ => return,
// emit-h only requires semantic analysis of the Decl to be complete,
// it does not depend on machine code generation to succeed.
.codegen_failure, .codegen_failure_retryable, .complete => {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
+ const gpa = comp.gpa;
+ const module = comp.bin_file.options.module.?;
const emit_h = module.emit_h.?;
_ = try emit_h.decl_table.getOrPut(gpa, decl);
const decl_emit_h = decl.getEmitH(module);
@@ -2287,7 +2309,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
c_codegen.genHeader(&dg) catch |err| switch (err) {
error.AnalysisFail => {
try emit_h.failed_decls.put(gpa, decl, dg.error_msg.?);
- continue;
+ return;
},
else => |e| return e,
};
@@ -2299,26 +2321,27 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.analyze_decl => |decl| {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
+ const module = comp.bin_file.options.module.?;
module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.AnalysisFail => continue,
+ error.AnalysisFail => return,
};
},
.update_embed_file => |embed_file| {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
+ const module = comp.bin_file.options.module.?;
module.updateEmbedFile(embed_file) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.AnalysisFail => continue,
+ error.AnalysisFail => return,
};
},
.update_line_number => |decl| {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
- self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
+ const gpa = comp.gpa;
+ const module = comp.bin_file.options.module.?;
+ comp.bin_file.updateDeclLineNumber(module, decl) catch |err| {
try module.failed_decls.ensureUnusedCapacity(gpa, 1);
module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
gpa,
@@ -2332,31 +2355,31 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.analyze_pkg => |pkg| {
if (build_options.omit_stage2)
@panic("sadly stage2 is omitted from this build to save memory on the CI server");
- const module = self.bin_file.options.module.?;
+ const module = comp.bin_file.options.module.?;
module.semaPkg(pkg) catch |err| switch (err) {
error.CurrentWorkingDirectoryUnlinked,
error.Unexpected,
- => try self.setMiscFailure(
+ => try comp.setMiscFailure(
.analyze_pkg,
"unexpected problem analyzing package '{s}'",
.{pkg.root_src_path},
),
error.OutOfMemory => return error.OutOfMemory,
- error.AnalysisFail => continue,
+ error.AnalysisFail => return,
};
},
.glibc_crt_file => |crt_file| {
- glibc.buildCRTFile(self, crt_file) catch |err| {
+ glibc.buildCRTFile(comp, crt_file) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
+ try comp.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
@errorName(err),
});
};
},
.glibc_shared_objects => {
- glibc.buildSharedObjects(self) catch |err| {
+ glibc.buildSharedObjects(comp) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.glibc_shared_objects,
"unable to build glibc shared objects: {s}",
.{@errorName(err)},
@@ -2364,9 +2387,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.musl_crt_file => |crt_file| {
- musl.buildCRTFile(self, crt_file) catch |err| {
+ musl.buildCRTFile(comp, crt_file) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.musl_crt_file,
"unable to build musl CRT file: {s}",
.{@errorName(err)},
@@ -2374,9 +2397,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.mingw_crt_file => |crt_file| {
- mingw.buildCRTFile(self, crt_file) catch |err| {
+ mingw.buildCRTFile(comp, crt_file) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.mingw_crt_file,
"unable to build mingw-w64 CRT file: {s}",
.{@errorName(err)},
@@ -2384,10 +2407,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.windows_import_lib => |index| {
- const link_lib = self.bin_file.options.system_libs.keys()[index];
- mingw.buildImportLib(self, link_lib) catch |err| {
+ const link_lib = comp.bin_file.options.system_libs.keys()[index];
+ mingw.buildImportLib(comp, link_lib) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.windows_import_lib,
"unable to generate DLL import .lib file: {s}",
.{@errorName(err)},
@@ -2395,9 +2418,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.libunwind => {
- libunwind.buildStaticLib(self) catch |err| {
+ libunwind.buildStaticLib(comp) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.libunwind,
"unable to build libunwind: {s}",
.{@errorName(err)},
@@ -2405,9 +2428,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.libcxx => {
- libcxx.buildLibCXX(self) catch |err| {
+ libcxx.buildLibCXX(comp) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.libcxx,
"unable to build libcxx: {s}",
.{@errorName(err)},
@@ -2415,9 +2438,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.libcxxabi => {
- libcxx.buildLibCXXABI(self) catch |err| {
+ libcxx.buildLibCXXABI(comp) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.libcxxabi,
"unable to build libcxxabi: {s}",
.{@errorName(err)},
@@ -2425,9 +2448,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.libtsan => {
- libtsan.buildTsan(self) catch |err| {
+ libtsan.buildTsan(comp) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.libtsan,
"unable to build TSAN library: {s}",
.{@errorName(err)},
@@ -2435,9 +2458,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.wasi_libc_crt_file => |crt_file| {
- wasi_libc.buildCRTFile(self, crt_file) catch |err| {
+ wasi_libc.buildCRTFile(comp, crt_file) catch |err| {
// TODO Surface more error details.
- try self.setMiscFailure(
+ try comp.setMiscFailure(
.wasi_libc_crt_file,
"unable to build WASI libc CRT file: {s}",
.{@errorName(err)},
@@ -2445,15 +2468,15 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.compiler_rt_lib => {
- self.buildOutputFromZig(
+ comp.buildOutputFromZig(
"compiler_rt.zig",
.Lib,
- &self.compiler_rt_static_lib,
+ &comp.compiler_rt_static_lib,
.compiler_rt,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.SubCompilationFailed => continue, // error reported already
- else => try self.setMiscFailure(
+ error.SubCompilationFailed => return, // error reported already
+ else => try comp.setMiscFailure(
.compiler_rt,
"unable to build compiler_rt: {s}",
.{@errorName(err)},
@@ -2461,15 +2484,15 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.compiler_rt_obj => {
- self.buildOutputFromZig(
+ comp.buildOutputFromZig(
"compiler_rt.zig",
.Obj,
- &self.compiler_rt_obj,
+ &comp.compiler_rt_obj,
.compiler_rt,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.SubCompilationFailed => continue, // error reported already
- else => try self.setMiscFailure(
+ error.SubCompilationFailed => return, // error reported already
+ else => try comp.setMiscFailure(
.compiler_rt,
"unable to build compiler_rt: {s}",
.{@errorName(err)},
@@ -2477,15 +2500,15 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.libssp => {
- self.buildOutputFromZig(
+ comp.buildOutputFromZig(
"ssp.zig",
.Lib,
- &self.libssp_static_lib,
+ &comp.libssp_static_lib,
.libssp,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.SubCompilationFailed => continue, // error reported already
- else => try self.setMiscFailure(
+ error.SubCompilationFailed => return, // error reported already
+ else => try comp.setMiscFailure(
.libssp,
"unable to build libssp: {s}",
.{@errorName(err)},
@@ -2493,15 +2516,15 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
},
.zig_libc => {
- self.buildOutputFromZig(
+ comp.buildOutputFromZig(
"c.zig",
.Lib,
- &self.libc_static_lib,
+ &comp.libc_static_lib,
.zig_libc,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.SubCompilationFailed => continue, // error reported already
- else => try self.setMiscFailure(
+ error.SubCompilationFailed => return, // error reported already
+ else => try comp.setMiscFailure(
.zig_libc,
"unable to build zig's multitarget libc: {s}",
.{@errorName(err)},
@@ -2512,11 +2535,11 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
if (!build_options.is_stage1)
unreachable;
- self.updateStage1Module(main_progress_node) catch |err| {
+ comp.updateStage1Module(main_progress_node) catch |err| {
fatal("unable to build stage1 zig object: {s}", .{@errorName(err)});
};
},
- };
+ }
}
const AstGenSrc = union(enum) {
src/Module.zig
@@ -3039,10 +3039,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
decl, decl.name, dep, dep.name,
});
- // We don't perform a deletion here, because this Decl or another one
- // may end up referencing it before the update is complete.
- dep.deletion_flag = true;
- try mod.deletion_set.put(mod.gpa, dep, {});
+ try mod.markDeclForDeletion(dep);
}
}
decl.dependencies.clearRetainingCapacity();
@@ -3433,21 +3430,29 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.owns_tv = false;
var queue_linker_work = false;
- if (decl_tv.val.castTag(.variable)) |payload| {
- const variable = payload.data;
- if (variable.owner_decl == decl) {
- decl.owns_tv = true;
- queue_linker_work = true;
-
- const copied_init = try variable.init.copy(&decl_arena.allocator);
- variable.init = copied_init;
- }
- } else if (decl_tv.val.castTag(.extern_fn)) |payload| {
- const owner_decl = payload.data;
- if (decl == owner_decl) {
- decl.owns_tv = true;
+ switch (decl_tv.val.tag()) {
+ .variable => {
+ const variable = decl_tv.val.castTag(.variable).?.data;
+ if (variable.owner_decl == decl) {
+ decl.owns_tv = true;
+ queue_linker_work = true;
+
+ const copied_init = try variable.init.copy(&decl_arena.allocator);
+ variable.init = copied_init;
+ }
+ },
+ .extern_fn => {
+ const owner_decl = decl_tv.val.castTag(.extern_fn).?.data;
+ if (decl == owner_decl) {
+ decl.owns_tv = true;
+ queue_linker_work = true;
+ }
+ },
+ .array, .@"struct", .@"union" => {
+ log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
queue_linker_work = true;
- }
+ },
+ else => {},
}
decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
@@ -3462,6 +3467,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.generation = mod.generation;
if (queue_linker_work and decl.ty.hasCodeGenBits()) {
+ log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
+
try mod.comp.bin_file.allocateDeclIndexes(decl);
try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
@@ -3985,6 +3992,7 @@ pub fn clearDecl(
decl.analysis = .unreferenced;
}
+/// This function is exclusively called for anonymous decls.
pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
log.debug("deleteUnusedDecl {*} ({s})", .{ decl, decl.name });
@@ -4019,6 +4027,13 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
decl.destroy(mod);
}
+/// We don't perform a deletion here, because this Decl or another one
+/// may end up referencing it before the update is complete.
+fn markDeclForDeletion(mod: *Module, decl: *Decl) !void {
+ decl.deletion_flag = true;
+ try mod.deletion_set.put(mod.gpa, decl, {});
+}
+
/// Cancel the creation of an anon decl and delete any references to it.
/// If other decls depend on this decl, they must be aborted first.
pub fn abortAnonDecl(mod: *Module, decl: *Decl) void {
@@ -4369,12 +4384,13 @@ pub fn createAnonymousDeclFromDeclNamed(
namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {});
- // TODO: This generates the Decl into the machine code file if it is of a
- // type that is non-zero size. We should be able to further improve the
- // compiler to omit Decls which are only referenced at compile-time and not runtime.
+ // The Decl starts off with alive=false and the codegen backend will set alive=true
+ // if the Decl is referenced by an instruction or another constant. Otherwise,
+ // the Decl will be garbage collected by the `codegen_decl` task instead of sent
+ // to the linker.
if (typed_value.ty.hasCodeGenBits()) {
try mod.comp.bin_file.allocateDeclIndexes(new_decl);
- try mod.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
+ try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
}
return new_decl;
test/behavior/basic.zig
@@ -459,3 +459,18 @@ var gdt = [_]GDTEntry{
GDTEntry{ .field = 2 },
};
var global_ptr = &gdt[0];
+
+test "global constant is loaded with a runtime-known index" {
+ const S = struct {
+ fn doTheTest() !void {
+ var index: usize = 1;
+ const ptr = &pieces[index].field;
+ try expect(ptr.* == 2);
+ }
+ const Piece = struct {
+ field: i32,
+ };
+ const pieces = [_]Piece{ Piece{ .field = 1 }, Piece{ .field = 2 }, Piece{ .field = 3 } };
+ };
+ try S.doTheTest();
+}
test/behavior/switch.zig
@@ -90,25 +90,6 @@ 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" {
- try expect(!returnsFalse());
-}
-
test "switch on type" {
try expect(trueIfBoolFalseOtherwise(bool));
try expect(!trueIfBoolFalseOtherwise(i32));
test/behavior/switch_stage1.zig
@@ -3,6 +3,24 @@ const expect = std.testing.expect;
const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
+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" {
+ try expect(!returnsFalse());
+}
test "switch all prongs unreachable" {
try testAllProngsUnreachable();
comptime try testAllProngsUnreachable();
test/behavior/union.zig
@@ -71,34 +71,3 @@ test "0-sized extern union definition" {
try expect(U.f == 1);
}
-
-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 = @as(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| try expect(arr[4] == 3),
- else => unreachable,
- }
- switch ((err catch unreachable).val1) {
- Value.Int => |x| try expect(x == 1234),
- else => unreachable,
- }
-}
test/behavior/union_stage1.zig
@@ -3,6 +3,37 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const Tag = std.meta.Tag;
+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 = @as(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| try expect(arr[4] == 3),
+ else => unreachable,
+ }
+ switch ((err catch unreachable).val1) {
+ Value.Int => |x| try expect(x == 1234),
+ else => unreachable,
+ }
+}
+
const Letter = enum { A, B, C };
const Payload = union(Letter) {
A: i32,