Commit cacd5366a6

Andrew Kelley <andrew@ziglang.org>
2021-10-15 07:16:26
stage2: LLVM backend: implement `wrap_optional` AIR
and move over some passing tests
1 parent 55eea3b
src/codegen/llvm.zig
@@ -2341,10 +2341,33 @@ pub const FuncGen = struct {
     }
 
     fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
-        if (self.liveness.isUnused(inst))
-            return null;
+        if (self.liveness.isUnused(inst)) return null;
 
-        return self.todo("implement llvm codegen for 'airWrapOptional'", .{});
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const operand_ty = self.air.typeOf(ty_op.operand);
+        const non_null_bit = self.context.intType(1).constAllOnes();
+        if (!operand_ty.hasCodeGenBits()) return non_null_bit;
+        const operand = try self.resolveInst(ty_op.operand);
+        const optional_ty = self.air.typeOfIndex(inst);
+        if (optional_ty.isPtrLikeOptional()) return operand;
+        const llvm_optional_ty = try self.dg.llvmType(optional_ty);
+        if (isByRef(optional_ty)) {
+            const optional_ptr = self.buildAlloca(llvm_optional_ty);
+            const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
+            var buf: Type.Payload.ElemType = undefined;
+            const payload_ty = operand_ty.optionalChild(&buf);
+            var ptr_ty_payload: Type.Payload.ElemType = .{
+                .base = .{ .tag = .single_mut_pointer },
+                .data = payload_ty,
+            };
+            const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
+            self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
+            const non_null_ptr = self.builder.buildStructGEP(optional_ptr, 1, "");
+            _ = self.builder.buildStore(non_null_bit, non_null_ptr);
+            return optional_ptr;
+        }
+        const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
+        return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
     }
 
     fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
test/behavior/basic.zig
@@ -411,3 +411,38 @@ test "use of declaration with same name as primitive" {
     const c: @"u8" = 300;
     try expect(c == 300);
 }
+
+fn emptyFn() void {}
+
+test "constant equal function pointers" {
+    const alias = emptyFn;
+    try expect(comptime x: {
+        break :x emptyFn == alias;
+    });
+}
+
+test "multiline string literal is null terminated" {
+    const s1 =
+        \\one
+        \\two)
+        \\three
+    ;
+    const s2 = "one\ntwo)\nthree";
+    try expect(std.cstr.cmp(s1, s2) == 0);
+}
+
+test "self reference through fn ptr field" {
+    const S = struct {
+        const A = struct {
+            f: fn (A) u8,
+        };
+
+        fn foo(a: A) u8 {
+            _ = a;
+            return 12;
+        }
+    };
+    var a: S.A = undefined;
+    a.f = S.foo;
+    try expect(a.f(a) == 12);
+}
test/behavior/eval.zig
@@ -217,3 +217,154 @@ const vertices = [_]Vertex{
         .b = 1.0,
     },
 };
+
+test "statically initialized list" {
+    try expect(static_point_list[0].x == 1);
+    try expect(static_point_list[0].y == 2);
+    try expect(static_point_list[1].x == 3);
+    try expect(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 "statically initialized array literal" {
+    const y: [4]u8 = st_init_arr_lit_x;
+    try expect(y[3] == 4);
+}
+const st_init_arr_lit_x = [_]u8{ 1, 2, 3, 4 };
+
+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" {
+    try expect(performFn('t', 1) == 6);
+    try expect(performFn('o', 0) == 1);
+    try expect(performFn('w', 99) == 99);
+}
+
+test "create global array with for loop" {
+    try expect(global_array[5] == 5 * 5);
+    try expect(global_array[9] == 9 * 9);
+}
+
+const global_array = x: {
+    var result: [10]usize = undefined;
+    for (result) |*item, index| {
+        item.* = index * index;
+    }
+    break :x result;
+};
+
+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" {
+    try expect(doesAlotT(u32, 2) == 2);
+}
+
+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;
+        try expect(diamond_info.version == 0);
+        try expect(res.version == 1);
+    }
+}
+
+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 {
+    _ = T;
+}
+
+test "zero extend from u0 to u1" {
+    var zero_u0: u0 = 0;
+    var zero_u1: u1 = zero_u0;
+    try expect(zero_u1 == 0);
+}
+
+test "return 0 from function that has u0 return type" {
+    const S = struct {
+        fn foo_zero() u0 {
+            return 0;
+        }
+    };
+    comptime {
+        if (S.foo_zero() != 0) {
+            @compileError("test failed");
+        }
+    }
+}
test/behavior/eval_stage1.zig
@@ -2,27 +2,6 @@ const std = @import("std");
 const expect = std.testing.expect;
 const expectEqual = std.testing.expectEqual;
 
-test "statically initialized list" {
-    try expect(static_point_list[0].x == 1);
-    try expect(static_point_list[0].y == 2);
-    try expect(static_point_list[1].x == 3);
-    try expect(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" {
     try expect(static_vec3.data[2] == 1.0);
     try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
@@ -54,27 +33,6 @@ var st_init_str_foo = StInitStrFoo{
     .y = true,
 };
 
-test "statically initialized array literal" {
-    const y: [4]u8 = st_init_arr_lit_x;
-    try expect(y[3] == 4);
-}
-const st_init_arr_lit_x = [_]u8{
-    1,
-    2,
-    3,
-    4,
-};
-
-test "const slice" {
-    comptime {
-        const a = "1234567890";
-        try expect(a.len == 10);
-        const b = a[1..2];
-        try expect(b.len == 1);
-        try expect(b[0] == '2');
-    }
-}
-
 test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
     var runtime = [1]i32{3};
     comptime var i: usize = 0;
@@ -87,52 +45,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
     }
 }
 
-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" {
-    try expect(performFn('t', 1) == 6);
-    try expect(performFn('o', 0) == 1);
-    try expect(performFn('w', 99) == 99);
-}
-
 test "eval @setFloatMode at compile-time" {
     const result = comptime fnWithFloatMode();
     try expect(result == 1234.0);
@@ -204,19 +116,6 @@ const Foo = struct {
 var foo_contents = Foo{ .name = "a" };
 const foo_ref = &foo_contents;
 
-test "create global array with for loop" {
-    try expect(global_array[5] == 5 * 5);
-    try expect(global_array[9] == 9 * 9);
-}
-
-const global_array = x: {
-    var result: [10]usize = undefined;
-    for (result) |*item, index| {
-        item.* = index * index;
-    }
-    break :x result;
-};
-
 const hi1 = "hi";
 const hi2 = hi1;
 test "const global shares pointer with other same one" {
@@ -262,13 +161,6 @@ test "string literal used as comptime slice is memoized" {
     comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
 }
 
-test "comptime slice of undefined pointer of length 0" {
-    const slice1 = @as([*]i32, undefined)[0..0];
-    try expect(slice1.len == 0);
-    const slice2 = @as([*]i32, undefined)[100..100];
-    try expect(slice2.len == 0);
-}
-
 fn copyWithPartialInline(s: []u32, b: []u8) void {
     comptime var i: usize = 0;
     inline while (i < 4) : (i += 1) {
@@ -308,44 +200,6 @@ 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" {
-    try expect(doesAlotT(u32, 2) == 2);
-}
-
-test "comptime slice of slice preserves comptime var" {
-    comptime {
-        var buff: [10]u8 = undefined;
-        buff[0..][0..][0] = 1;
-        try expect(buff[0..][0..][0] == 1);
-    }
-}
-
-test "comptime slice of pointer preserves comptime var" {
-    comptime {
-        var buff: [10]u8 = undefined;
-        var a = @ptrCast([*]u8, &buff);
-        a[0..1][0] = 1;
-        try expect(buff[0..][0..][0] == 1);
-    }
-}
-
 const SingleFieldStruct = struct {
     x: i32,
 
@@ -362,15 +216,6 @@ test "const ptr to comptime mutable data is not memoized" {
     }
 }
 
-test "array concat of slices gives slice" {
-    comptime {
-        var a: []const u8 = "aoeu";
-        var b: []const u8 = "asdf";
-        const c = a ++ b;
-        try expect(std.mem.eql(u8, c, "aoeuasdf"));
-    }
-}
-
 test "comptime shlWithOverflow" {
     const ct_shifted: u64 = comptime amt: {
         var amt = @as(u64, 0);
@@ -401,43 +246,6 @@ test "runtime 128 bit integer division" {
     try expect(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;
-        try expect(diamond_info.version == 0);
-        try expect(res.version == 1);
-    }
-}
-
-test "slice of type" {
-    comptime {
-        var types_array = [_]type{ i32, f64, type };
-        for (types_array) |T, i| {
-            switch (i) {
-                0 => try expect(T == i32),
-                1 => try expect(T == f64),
-                2 => try expect(T == type),
-                else => unreachable,
-            }
-        }
-        for (types_array[0..]) |T, i| {
-            switch (i) {
-                0 => try expect(T == i32),
-                1 => try expect(T == f64),
-                2 => try expect(T == type),
-                else => unreachable,
-            }
-        }
-    }
-}
-
 const Wrapper = struct {
     T: type,
 };
@@ -502,55 +310,12 @@ test "inline for with same type but different values" {
     try expect(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 {
-    _ = T;
-}
-
-test "zero extend from u0 to u1" {
-    var zero_u0: u0 = 0;
-    var zero_u1: u1 = zero_u0;
-    try expect(zero_u1 == 0);
-}
-
 test "bit shift a u1" {
     var x: u1 = 1;
     var y = x << 0;
     try expect(y == 1);
 }
 
-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];
-
-    try expect(sliceA[1] == 2);
-    try expect(sliceB[1] == 2);
-}
-
-test "slice bounds in comptime concatenation" {
-    const bs = comptime blk: {
-        const b = "........1........";
-        break :blk b[8..9];
-    };
-    const str = "" ++ bs;
-    try expect(str.len == 1);
-    try expect(std.mem.eql(u8, str, "1"));
-
-    const str2 = bs ++ "";
-    try expect(str2.len == 1);
-    try expect(std.mem.eql(u8, str2, "1"));
-}
-
 test "comptime bitwise operators" {
     comptime {
         try expect(3 & 1 == 1);
@@ -602,19 +367,6 @@ test "comptime assign int to optional int" {
     }
 }
 
-test "return 0 from function that has u0 return type" {
-    const S = struct {
-        fn foo_zero() u0 {
-            return 0;
-        }
-    };
-    comptime {
-        if (S.foo_zero() != 0) {
-            @compileError("test failed");
-        }
-    }
-}
-
 test "two comptime calls with array default initialized to undefined" {
     const S = struct {
         const CrossTarget = struct {
test/behavior/misc.zig
@@ -7,13 +7,6 @@ const builtin = @import("builtin");
 
 fn emptyFn() void {}
 
-test "constant equal function pointers" {
-    const alias = emptyFn;
-    try expect(comptime x: {
-        break :x emptyFn == alias;
-    });
-}
-
 const addr1 = @ptrCast(*const u8, emptyFn);
 test "comptime cast fn to ptr" {
     const addr2 = @ptrCast(*const u8, emptyFn);
@@ -35,17 +28,7 @@ test "string escapes" {
     try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");
 }
 
-test "multiline string literal is null terminated" {
-    const s1 =
-        \\one
-        \\two)
-        \\three
-    ;
-    const s2 = "one\ntwo)\nthree";
-    try expect(std.cstr.cmp(s1, s2) == 0);
-}
-
-test "explicit cast maybe pointers" {
+test "explicit cast optional pointers" {
     const a: ?*i32 = undefined;
     const b: ?*f32 = @ptrCast(?*f32, a);
     _ = b;
@@ -159,22 +142,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
     }
 }
 
-test "self reference through fn ptr field" {
-    const S = struct {
-        const A = struct {
-            f: fn (A) u8,
-        };
-
-        fn foo(a: A) u8 {
-            _ = a;
-            return 12;
-        }
-    };
-    var a: S.A = undefined;
-    a.f = S.foo;
-    try expect(a.f(a) == 12);
-}
-
 test "thread local variable" {
     const S = struct {
         threadlocal var t: i32 = 1234;
@@ -183,19 +150,6 @@ test "thread local variable" {
     try expect(S.t == 1235);
 }
 
-test "nested optional field in struct" {
-    const S2 = struct {
-        y: u8,
-    };
-    const S1 = struct {
-        x: ?S2,
-    };
-    var s = S1{
-        .x = S2{ .y = 127 },
-    };
-    try expect(s.x.?.y == 127);
-}
-
 fn maybe(x: bool) anyerror!?u32 {
     return switch (x) {
         true => @as(u32, 42),
test/behavior/optional.zig
@@ -2,3 +2,37 @@ const std = @import("std");
 const testing = std.testing;
 const expect = testing.expect;
 const expectEqual = testing.expectEqual;
+
+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;
+        }
+    };
+    try expect(S.entry());
+    comptime try expect(S.entry());
+}
+
+test "self-referential struct through a slice of optional" {
+    const S = struct {
+        const Node = struct {
+            children: []?Node,
+            data: ?u8,
+
+            fn new() Node {
+                return Node{
+                    .children = undefined,
+                    .data = null,
+                };
+            }
+        };
+    };
+
+    var n = S.Node.new();
+    try expect(n.data == null);
+}
test/behavior/optional_stage1.zig
@@ -83,21 +83,6 @@ fn test_cmp_optional_non_optional() !void {
     };
 }
 
-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;
-        }
-    };
-    try expect(S.entry());
-    comptime try expect(S.entry());
-}
-
 test "unwrap function call with optional pointer return value" {
     const S = struct {
         fn entry() !void {
@@ -139,25 +124,6 @@ test "nested orelse" {
     comptime try S.entry();
 }
 
-test "self-referential struct through a slice of optional" {
-    const S = struct {
-        const Node = struct {
-            children: []?Node,
-            data: ?u8,
-
-            fn new() Node {
-                return Node{
-                    .children = undefined,
-                    .data = null,
-                };
-            }
-        };
-    };
-
-    var n = S.Node.new();
-    try expect(n.data == null);
-}
-
 test "assigning to an unwrapped optional field in an inline loop" {
     comptime var maybe_pos_arg: ?comptime_int = null;
     inline for ("ab") |x| {
test/behavior/slice_stage1.zig
@@ -20,6 +20,23 @@ test "slicing" {
     if (slice_rest.len != 10) unreachable;
 }
 
+test "const slice" {
+    comptime {
+        const a = "1234567890";
+        try expect(a.len == 10);
+        const b = a[1..2];
+        try expect(b.len == 1);
+        try expect(b[0] == '2');
+    }
+}
+
+test "comptime slice of undefined pointer of length 0" {
+    const slice1 = @as([*]i32, undefined)[0..0];
+    try expect(slice1.len == 0);
+    const slice2 = @as([*]i32, undefined)[100..100];
+    try expect(slice2.len == 0);
+}
+
 test "slicing zero length array" {
     const s1 = ""[0..];
     const s2 = ([_]u32{})[0..];
@@ -389,3 +406,78 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
     // try S.doTheTest();
     comptime try S.doTheTest();
 }
+
+test "comptime slice of slice preserves comptime var" {
+    comptime {
+        var buff: [10]u8 = undefined;
+        buff[0..][0..][0] = 1;
+        try expect(buff[0..][0..][0] == 1);
+    }
+}
+
+test "comptime slice of pointer preserves comptime var" {
+    comptime {
+        var buff: [10]u8 = undefined;
+        var a = @ptrCast([*]u8, &buff);
+        a[0..1][0] = 1;
+        try expect(buff[0..][0..][0] == 1);
+    }
+}
+
+test "array concat of slices gives slice" {
+    comptime {
+        var a: []const u8 = "aoeu";
+        var b: []const u8 = "asdf";
+        const c = a ++ b;
+        try expect(std.mem.eql(u8, c, "aoeuasdf"));
+    }
+}
+
+test "slice of type" {
+    comptime {
+        var types_array = [_]type{ i32, f64, type };
+        for (types_array) |T, i| {
+            switch (i) {
+                0 => try expect(T == i32),
+                1 => try expect(T == f64),
+                2 => try expect(T == type),
+                else => unreachable,
+            }
+        }
+        for (types_array[0..]) |T, i| {
+            switch (i) {
+                0 => try expect(T == i32),
+                1 => try expect(T == f64),
+                2 => try expect(T == type),
+                else => unreachable,
+            }
+        }
+    }
+}
+
+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];
+
+    try expect(sliceA[1] == 2);
+    try expect(sliceB[1] == 2);
+}
+
+test "slice bounds in comptime concatenation" {
+    const bs = comptime blk: {
+        const b = "........1........";
+        break :blk b[8..9];
+    };
+    const str = "" ++ bs;
+    try expect(str.len == 1);
+    try expect(std.mem.eql(u8, str, "1"));
+
+    const str2 = bs ++ "";
+    try expect(str2.len == 1);
+    try expect(std.mem.eql(u8, str2, "1"));
+}
test/behavior/while.zig
@@ -111,3 +111,91 @@ test "while copies its payload" {
     try S.doTheTest();
     comptime try S.doTheTest();
 }
+
+test "continue and break" {
+    try runContinueAndBreakTest();
+    try expect(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;
+    }
+    try expect(i == 4);
+}
+
+test "while with optional as condition" {
+    numbers_left = 10;
+    var sum: i32 = 0;
+    while (getNumberOrNull()) |value| {
+        sum += value;
+    }
+    try expect(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;
+        try expect(got_else == 0);
+    } else {
+        got_else += 1;
+    }
+    try expect(sum == 45);
+    try expect(got_else == 1);
+}
+
+test "while on bool with else result follow else prong" {
+    const result = while (returnFalse()) {
+        break @as(i32, 10);
+    } else @as(i32, 2);
+    try expect(result == 2);
+}
+
+test "while on bool with else result follow break prong" {
+    const result = while (returnTrue()) {
+        break @as(i32, 10);
+    } else @as(i32, 2);
+    try expect(result == 10);
+}
+
+test "while on optional with else result follow else prong" {
+    const result = while (returnNull()) |value| {
+        break value;
+    } else @as(i32, 2);
+    try expect(result == 2);
+}
+
+test "while on optional with else result follow break prong" {
+    const result = while (returnOptional(10)) |value| {
+        break value;
+    } else @as(i32, 2);
+    try expect(result == 10);
+}
+
+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;
+}
test/behavior/while_stage1.zig
@@ -1,24 +1,6 @@
 const std = @import("std");
 const expect = std.testing.expect;
 
-test "continue and break" {
-    try runContinueAndBreakTest();
-    try expect(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;
-    }
-    try expect(i == 4);
-}
-
 test "return with implicit cast from while loop" {
     returnWithImplicitCastFromWhileLoopTest() catch unreachable;
 }
@@ -28,29 +10,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
     }
 }
 
-test "while with optional as condition" {
-    numbers_left = 10;
-    var sum: i32 = 0;
-    while (getNumberOrNull()) |value| {
-        sum += value;
-    }
-    try expect(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;
-        try expect(got_else == 0);
-    } else {
-        got_else += 1;
-    }
-    try expect(sum == 45);
-    try expect(got_else == 1);
-}
-
 test "while with error union condition" {
     numbers_left = 10;
     var sum: i32 = 0;
@@ -79,20 +38,6 @@ fn getNumberOrNull() ?i32 {
     };
 }
 
-test "while on optional with else result follow else prong" {
-    const result = while (returnNull()) |value| {
-        break value;
-    } else @as(i32, 2);
-    try expect(result == 2);
-}
-
-test "while on optional with else result follow break prong" {
-    const result = while (returnOptional(10)) |value| {
-        break value;
-    } else @as(i32, 2);
-    try expect(result == 10);
-}
-
 test "while on error union with else result follow else prong" {
     const result = while (returnError()) |value| {
         break value;
@@ -107,20 +52,6 @@ test "while on error union with else result follow break prong" {
     try expect(result == 10);
 }
 
-test "while on bool with else result follow else prong" {
-    const result = while (returnFalse()) {
-        break @as(i32, 10);
-    } else @as(i32, 2);
-    try expect(result == 2);
-}
-
-test "while on bool with else result follow break prong" {
-    const result = while (returnTrue()) {
-        break @as(i32, 10);
-    } else @as(i32, 2);
-    try expect(result == 10);
-}
-
 fn returnNull() ?i32 {
     return null;
 }
test/behavior.zig
@@ -28,6 +28,7 @@ test {
     _ = @import("behavior/member_func.zig");
     _ = @import("behavior/optional.zig");
     _ = @import("behavior/pointers.zig");
+    _ = @import("behavior/pub_enum.zig");
     _ = @import("behavior/slice.zig");
     _ = @import("behavior/sizeof_and_typeof.zig");
     _ = @import("behavior/struct.zig");
@@ -140,7 +141,6 @@ test {
         _ = @import("behavior/pointers_stage1.zig");
         _ = @import("behavior/popcount.zig");
         _ = @import("behavior/ptrcast.zig");
-        _ = @import("behavior/pub_enum.zig");
         _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
         _ = @import("behavior/reflection.zig");
         {