Commit c4df9bf56f
Changed files (22)
src/codegen/llvm.zig
@@ -1605,7 +1605,15 @@ pub const FuncGen = struct {
self.builder.positionBuilderAtEnd(loop_block);
try self.genBody(body);
- _ = self.builder.buildBr(loop_block);
+ // TODO instead of this logic, change AIR to have the property that
+ // every block is guaranteed to end with a noreturn instruction.
+ // Then we can simply rely on the fact that a repeat or break instruction
+ // would have been emitted already. Also the main loop in genBody can
+ // be while(true) instead of for(body), which will eliminate 1 branch on
+ // a hot path.
+ if (body.len == 0 or !self.air.typeOfIndex(body[body.len - 1]).isNoReturn()) {
+ _ = self.builder.buildBr(loop_block);
+ }
return null;
}
src/AstGen.zig
@@ -5537,8 +5537,10 @@ fn whileExpr(
});
}
- loop_scope.break_count += 1;
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
+ if (!then_scope.endsWithNoReturn()) {
+ loop_scope.break_count += 1;
+ }
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
@@ -5549,7 +5551,6 @@ fn whileExpr(
src: Ast.Node.Index,
result: Zir.Inst.Ref,
} = if (else_node != 0) blk: {
- loop_scope.break_count += 1;
const sub_scope = s: {
if (while_full.error_token) |error_token| {
const tag: Zir.Inst.Tag = if (payload_is_ref)
@@ -5576,6 +5577,9 @@ fn whileExpr(
}
};
const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
+ if (!else_scope.endsWithNoReturn()) {
+ loop_scope.break_count += 1;
+ }
try checkUsed(parent_gz, &else_scope.base, sub_scope);
break :blk .{
.src = else_node,
@@ -5746,8 +5750,10 @@ fn forExpr(
break :blk &index_scope.base;
};
- loop_scope.break_count += 1;
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
+ if (!then_scope.endsWithNoReturn()) {
+ loop_scope.break_count += 1;
+ }
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
@@ -5758,11 +5764,14 @@ fn forExpr(
src: Ast.Node.Index,
result: Zir.Inst.Ref,
} = if (else_node != 0) blk: {
- loop_scope.break_count += 1;
const sub_scope = &else_scope.base;
+ const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
+ if (!else_scope.endsWithNoReturn()) {
+ loop_scope.break_count += 1;
+ }
break :blk .{
.src = else_node,
- .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node),
+ .result = else_result,
};
} else .{
.src = for_full.ast.then_expr,
test/behavior/call.zig
@@ -1,74 +1,3 @@
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
-
-test "basic invocations" {
- const foo = struct {
- fn foo() i32 {
- return 1234;
- }
- }.foo;
- try expect(@call(.{}, foo, .{}) == 1234);
- comptime {
- // modifiers that allow comptime calls
- try expect(@call(.{}, foo, .{}) == 1234);
- try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234);
- try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234);
- try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
- }
- {
- // comptime call without comptime keyword
- const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
- comptime try expect(result);
- }
- {
- // call of non comptime-known function
- var alias_foo = foo;
- try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
- try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
- try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
- }
-}
-
-test "tuple parameters" {
- const add = struct {
- fn add(a: i32, b: i32) i32 {
- return a + b;
- }
- }.add;
- var a: i32 = 12;
- var b: i32 = 34;
- try expect(@call(.{}, add, .{ a, 34 }) == 46);
- try expect(@call(.{}, add, .{ 12, b }) == 46);
- try expect(@call(.{}, add, .{ a, b }) == 46);
- try expect(@call(.{}, add, .{ 12, 34 }) == 46);
- comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);
- {
- const separate_args0 = .{ a, b };
- const separate_args1 = .{ a, 34 };
- const separate_args2 = .{ 12, 34 };
- const separate_args3 = .{ 12, b };
- try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46);
- try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46);
- try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46);
- try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46);
- }
-}
-
-test "comptime call with bound function as parameter" {
- const S = struct {
- fn ReturnType(func: anytype) type {
- return switch (@typeInfo(@TypeOf(func))) {
- .BoundFn => |info| info,
- else => unreachable,
- }.return_type orelse void;
- }
-
- fn call_me_maybe() ?i32 {
- return 123;
- }
- };
-
- var inst: S = undefined;
- try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
-}
test/behavior/call_stage1.zig
@@ -0,0 +1,74 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
+
+test "basic invocations" {
+ const foo = struct {
+ fn foo() i32 {
+ return 1234;
+ }
+ }.foo;
+ try expect(@call(.{}, foo, .{}) == 1234);
+ comptime {
+ // modifiers that allow comptime calls
+ try expect(@call(.{}, foo, .{}) == 1234);
+ try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234);
+ try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234);
+ try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
+ }
+ {
+ // comptime call without comptime keyword
+ const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
+ comptime try expect(result);
+ }
+ {
+ // call of non comptime-known function
+ var alias_foo = foo;
+ try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
+ try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
+ try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
+ }
+}
+
+test "tuple parameters" {
+ const add = struct {
+ fn add(a: i32, b: i32) i32 {
+ return a + b;
+ }
+ }.add;
+ var a: i32 = 12;
+ var b: i32 = 34;
+ try expect(@call(.{}, add, .{ a, 34 }) == 46);
+ try expect(@call(.{}, add, .{ 12, b }) == 46);
+ try expect(@call(.{}, add, .{ a, b }) == 46);
+ try expect(@call(.{}, add, .{ 12, 34 }) == 46);
+ comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);
+ {
+ const separate_args0 = .{ a, b };
+ const separate_args1 = .{ a, 34 };
+ const separate_args2 = .{ 12, 34 };
+ const separate_args3 = .{ 12, b };
+ try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46);
+ try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46);
+ try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46);
+ try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46);
+ }
+}
+
+test "comptime call with bound function as parameter" {
+ const S = struct {
+ fn ReturnType(func: anytype) type {
+ return switch (@typeInfo(@TypeOf(func))) {
+ .BoundFn => |info| info,
+ else => unreachable,
+ }.return_type orelse void;
+ }
+
+ fn call_me_maybe() ?i32 {
+ return 123;
+ }
+ };
+
+ var inst: S = undefined;
+ try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
+}
test/behavior/cast.zig
@@ -16,3 +16,52 @@ test "integer literal to pointer cast" {
const vga_mem = @intToPtr(*u16, 0xB8000);
try expect(@ptrToInt(vga_mem) == 0xB8000);
}
+
+test "peer type resolution: ?T and T" {
+ try expect(peerTypeTAndOptionalT(true, false).? == 0);
+ try expect(peerTypeTAndOptionalT(false, false).? == 3);
+ comptime {
+ try expect(peerTypeTAndOptionalT(true, false).? == 0);
+ try expect(peerTypeTAndOptionalT(false, false).? == 3);
+ }
+}
+fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
+ if (c) {
+ return if (b) null else @as(usize, 0);
+ }
+
+ return @as(usize, 3);
+}
+
+test "resolve undefined with integer" {
+ try testResolveUndefWithInt(true, 1234);
+ comptime try testResolveUndefWithInt(true, 1234);
+}
+fn testResolveUndefWithInt(b: bool, x: i32) !void {
+ const value = if (b) x else undefined;
+ if (b) {
+ try expect(value == x);
+ }
+}
+
+test "@intCast i32 to u7" {
+ var x: u128 = maxInt(u128);
+ var y: i32 = 120;
+ var z = x >> @intCast(u7, y);
+ try expect(z == 0xff);
+}
+
+test "@intCast to comptime_int" {
+ try expect(@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;
+ try expect(b == 255);
+}
+
+test "implicit cast comptime_int to comptime_float" {
+ comptime try expect(@as(comptime_float, 10) == @as(f32, 10));
+ try expect(2 == 2.0);
+}
test/behavior/cast_stage1.zig
@@ -121,22 +121,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
return null;
}
-test "peer type resolution: ?T and T" {
- try expect(peerTypeTAndOptionalT(true, false).? == 0);
- try expect(peerTypeTAndOptionalT(false, false).? == 3);
- comptime {
- try expect(peerTypeTAndOptionalT(true, false).? == 0);
- try expect(peerTypeTAndOptionalT(false, false).? == 3);
- }
-}
-fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
- if (c) {
- return if (b) null else @as(usize, 0);
- }
-
- return @as(usize, 3);
-}
-
test "peer type resolution: [0]u8 and []const u8" {
try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
@@ -203,17 +187,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
return slice[0..1];
}
-test "resolve undefined with integer" {
- try testResolveUndefWithInt(true, 1234);
- comptime try testResolveUndefWithInt(true, 1234);
-}
-fn testResolveUndefWithInt(b: bool, x: i32) !void {
- const value = if (b) x else undefined;
- if (b) {
- try expect(value == x);
- }
-}
-
test "implicit cast from &const [N]T to []const T" {
try testCastConstArrayRefToConstSlice();
comptime try testCastConstArrayRefToConstSlice();
@@ -424,13 +397,6 @@ test "comptime_int @intToFloat" {
}
}
-test "@intCast i32 to u7" {
- var x: u128 = maxInt(u128);
- var y: i32 = 120;
- var z = x >> @intCast(u7, y);
- try expect(z == 0xff);
-}
-
test "@floatCast cast down" {
{
var double: f64 = 0.001534;
@@ -533,20 +499,8 @@ test "implicit ptr to *c_void" {
try expect(c.* == 1);
}
-test "@intCast to comptime_int" {
- try expect(@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;
- try expect(b == 255);
-}
-
test "@intToEnum passed a comptime_int to an enum with one item" {
- const E = enum {
- A,
- };
+ const E = enum { A };
const x = @intToEnum(E, 0);
try expect(x == E.A);
}
@@ -599,11 +553,6 @@ test "peer type resolution: unreachable, error set, unreachable" {
try expect(transformed_err == error.SystemResources);
}
-test "implicit cast comptime_int to comptime_float" {
- comptime try expect(@as(comptime_float, 10) == @as(f32, 10));
- try expect(2 == 2.0);
-}
-
test "implicit cast *[0]T to E![]const u8" {
var x = @as(anyerror![]const u8, &[0]u8{});
try expect((x catch unreachable).len == 0);
@@ -645,12 +594,7 @@ test "*const [N]null u8 to ?[]const u8" {
test "peer resolution of string literals" {
const S = struct {
- const E = enum {
- a,
- b,
- c,
- d,
- };
+ const E = enum { a, b, c, d };
fn doTheTest(e: E) !void {
const cmd = switch (e) {
test/behavior/const_slice_child.zig
@@ -6,11 +6,7 @@ const expect = testing.expect;
var argv: [*]const [*]const u8 = undefined;
test "const slice child" {
- const strs = [_][*]const u8{
- "one",
- "two",
- "three",
- };
+ const strs = [_][*]const u8{ "one", "two", "three" };
argv = &strs;
try bar(strs.len);
}
test/behavior/defer.zig
@@ -2,113 +2,3 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError;
-
-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" {
- try expect(runSomeErrorDefers(true) catch unreachable);
- try expect(result[0] == 'c');
- try expect(result[1] == 'a');
-
- const ok = runSomeErrorDefers(false) catch |err| x: {
- try expect(err == error.FalseNotAllowed);
- break :x true;
- };
- try expect(ok);
- try expect(result[0] == 'c');
- try expect(result[1] == 'b');
- try expect(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;
- }
- expect(i == 5) catch @panic("test failure");
- }
-}
-
-test "defer and labeled break" {
- var i = @as(usize, 0);
-
- blk: {
- defer i += 1;
- break :blk;
- }
-
- try expect(i == 1);
-}
-
-test "errdefer does not apply to fn inside fn" {
- if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(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();
-}
-
-test "return variable while defer expression in scope to modify it" {
- const S = struct {
- fn doTheTest() !void {
- try expect(notNull().? == 1);
- }
-
- fn notNull() ?u8 {
- var res: ?u8 = 1;
- defer res = null;
- return res;
- }
- };
-
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "errdefer with payload" {
- const S = struct {
- fn foo() !i32 {
- errdefer |a| {
- expectEqual(error.One, a) catch @panic("test failure");
- }
- return error.One;
- }
- fn doTheTest() !void {
- try expectError(error.One, foo());
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
test/behavior/defer_stage1.zig
@@ -0,0 +1,114 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
+const expectError = std.testing.expectError;
+
+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" {
+ try expect(runSomeErrorDefers(true) catch unreachable);
+ try expect(result[0] == 'c');
+ try expect(result[1] == 'a');
+
+ const ok = runSomeErrorDefers(false) catch |err| x: {
+ try expect(err == error.FalseNotAllowed);
+ break :x true;
+ };
+ try expect(ok);
+ try expect(result[0] == 'c');
+ try expect(result[1] == 'b');
+ try expect(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;
+ }
+ expect(i == 5) catch @panic("test failure");
+ }
+}
+
+test "defer and labeled break" {
+ var i = @as(usize, 0);
+
+ blk: {
+ defer i += 1;
+ break :blk;
+ }
+
+ try expect(i == 1);
+}
+
+test "errdefer does not apply to fn inside fn" {
+ if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(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();
+}
+
+test "return variable while defer expression in scope to modify it" {
+ const S = struct {
+ fn doTheTest() !void {
+ try expect(notNull().? == 1);
+ }
+
+ fn notNull() ?u8 {
+ var res: ?u8 = 1;
+ defer res = null;
+ return res;
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "errdefer with payload" {
+ const S = struct {
+ fn foo() !i32 {
+ errdefer |a| {
+ expectEqual(error.One, a) catch @panic("test failure");
+ }
+ return error.One;
+ }
+ fn doTheTest() !void {
+ try expectError(error.One, foo());
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
test/behavior/enum.zig
@@ -1,133 +1,7 @@
-const expect = @import("std").testing.expect;
-const mem = @import("std").mem;
-const Tag = @import("std").meta.Tag;
-
-test "non-exhaustive enum" {
- const S = struct {
- const E = enum(u8) {
- a,
- b,
- _,
- };
- fn doTheTest(y: u8) !void {
- var e: E = .b;
- try expect(switch (e) {
- .a => false,
- .b => true,
- _ => false,
- });
- e = @intToEnum(E, 12);
- try expect(switch (e) {
- .a => false,
- .b => false,
- _ => true,
- });
-
- try expect(switch (e) {
- .a => false,
- .b => false,
- else => true,
- });
- e = .b;
- try expect(switch (e) {
- .a => false,
- else => true,
- });
-
- try expect(@typeInfo(E).Enum.fields.len == 2);
- e = @intToEnum(E, 12);
- try expect(@enumToInt(e) == 12);
- e = @intToEnum(E, y);
- try expect(@enumToInt(e) == 52);
- try expect(@typeInfo(E).Enum.is_exhaustive == false);
- }
- };
- try S.doTheTest(52);
- comptime try S.doTheTest(52);
-}
-
-test "empty non-exhaustive enum" {
- const S = struct {
- const E = enum(u8) {
- _,
- };
- fn doTheTest(y: u8) !void {
- var e = @intToEnum(E, y);
- try expect(switch (e) {
- _ => true,
- });
- try expect(@enumToInt(e) == y);
-
- try expect(@typeInfo(E).Enum.fields.len == 0);
- try expect(@typeInfo(E).Enum.is_exhaustive == false);
- }
- };
- try S.doTheTest(42);
- comptime try S.doTheTest(42);
-}
-
-test "single field non-exhaustive enum" {
- const S = struct {
- const E = enum(u8) {
- a,
- _,
- };
- fn doTheTest(y: u8) !void {
- var e: E = .a;
- try expect(switch (e) {
- .a => true,
- _ => false,
- });
- e = @intToEnum(E, 12);
- try expect(switch (e) {
- .a => false,
- _ => true,
- });
-
- try expect(switch (e) {
- .a => false,
- else => true,
- });
- e = .a;
- try expect(switch (e) {
- .a => true,
- else => false,
- });
-
- try expect(@enumToInt(@intToEnum(E, y)) == y);
- try expect(@typeInfo(E).Enum.fields.len == 1);
- try expect(@typeInfo(E).Enum.is_exhaustive == false);
- }
- };
- try S.doTheTest(23);
- comptime try S.doTheTest(23);
-}
-
-test "enum type" {
- const foo1 = Foo{ .One = 13 };
- const foo2 = Foo{
- .Two = Point{
- .x = 1234,
- .y = 5678,
- },
- };
- try expect(foo1.One == 13);
- try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
- const bar = Bar.B;
-
- try expect(bar == Bar.B);
- try expect(@typeInfo(Foo).Union.fields.len == 3);
- try expect(@typeInfo(Bar).Enum.fields.len == 4);
- try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid));
- try expect(@sizeOf(Bar) == 1);
-}
-
-test "enum as return value" {
- switch (returnAnInt(13)) {
- Foo.One => |value| try expect(value == 13),
- else => unreachable,
- }
-}
+const std = @import("std");
+const expect = std.testing.expect;
+const mem = std.mem;
+const Tag = std.meta.Tag;
const Point = struct {
x: u64,
@@ -153,13 +27,6 @@ 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 => {},
@@ -179,72 +46,19 @@ const AnEnumWithPayload = union(enum) {
Full: i32,
};
-const Number = enum {
- Zero,
- One,
- Two,
- Three,
- Four,
-};
-
-test "enum to int" {
- try shouldEqual(Number.Zero, 0);
- try shouldEqual(Number.One, 1);
- try shouldEqual(Number.Two, 2);
- try shouldEqual(Number.Three, 3);
- try shouldEqual(Number.Four, 4);
-}
+const Number = enum { Zero, One, Two, Three, Four };
fn shouldEqual(n: Number, expected: u3) !void {
try expect(@enumToInt(n) == expected);
}
-test "int to enum" {
- try testIntToEnumEval(3);
-}
-fn testIntToEnumEval(x: i32) !void {
- try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
-}
-const IntToEnumNumber = enum {
- Zero,
- One,
- Two,
- Three,
- Four,
-};
-
-test "@tagName" {
- try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
- comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
-}
-
-test "@tagName non-exhaustive enum" {
- try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
- comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
-}
-
fn testEnumTagNameBare(n: anytype) []const u8 {
return @tagName(n);
}
-const BareNumber = enum {
- One,
- Two,
- Three,
-};
-
-const NonExhaustive = enum(u8) {
- A,
- B,
- _,
-};
+const BareNumber = enum { One, Two, Three };
-test "enum alignment" {
- comptime {
- try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
- try expect(@alignOf(AlignTestEnum) >= @alignOf(u64));
- }
-}
+const NonExhaustive = enum(u8) { A, B, _ };
const AlignTestEnum = union(enum) {
A: [9]u8,
@@ -776,67 +590,12 @@ const ValueCount257 = enum {
I256,
};
-test "enum sizes" {
- comptime {
- try expect(@sizeOf(ValueCount1) == 0);
- try expect(@sizeOf(ValueCount2) == 1);
- try expect(@sizeOf(ValueCount256) == 1);
- try expect(@sizeOf(ValueCount257) == 2);
- }
-}
+const Small2 = enum(u2) { One, Two };
+const Small = enum(u2) { One, Two, Three, Four };
-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 try expect(Tag(Small) == u2);
- }
- {
- var x = Small2.One;
- x = Small2.Two;
- comptime try expect(Tag(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 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,
@@ -850,21 +609,6 @@ const bit_field_1 = BitFieldOfEnums{
.c = C.Four4,
};
-test "bit field access with enum fields" {
- var data = bit_field_1;
- try expect(getA(&data) == A.Two);
- try expect(getB(&data) == B.Three3);
- try expect(getC(&data) == C.Four4);
- comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
-
- data.b = B.Four3;
- try expect(data.b == B.Four3);
-
- data.a = A.Three;
- try expect(data.a == A.Three);
- try expect(data.b == B.Four3);
-}
-
fn getA(data: *const BitFieldOfEnums) A {
return data.a;
}
@@ -877,15 +621,6 @@ fn getC(data: *const BitFieldOfEnums) C {
return data.c;
}
-test "casting enum to its tag type" {
- try testCastEnumTag(Small2.Two);
- comptime try testCastEnumTag(Small2.Two);
-}
-
-fn testCastEnumTag(value: Small2) !void {
- try expect(@enumToInt(value) == 1);
-}
-
const MultipleChoice = enum(u32) {
A = 20,
B = 40,
@@ -893,21 +628,6 @@ const MultipleChoice = enum(u32) {
D = 1000,
};
-test "enum with specified tag values" {
- try testEnumWithSpecifiedTagValues(MultipleChoice.C);
- comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
-}
-
-fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
- try expect(@enumToInt(x) == 60);
- try expect(1234 == switch (x) {
- MultipleChoice.A => 1,
- MultipleChoice.B => 2,
- MultipleChoice.C => @as(u32, 1234),
- MultipleChoice.D => 4,
- });
-}
-
const MultipleChoice2 = enum(u32) {
Unspecified1,
A = 20,
@@ -920,34 +640,7 @@ const MultipleChoice2 = enum(u32) {
Unspecified5,
};
-test "enum with specified and unspecified tag values" {
- try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
- comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
- try expect(@enumToInt(x) == 1000);
- try expect(1234 == switch (x) {
- MultipleChoice2.A => 1,
- MultipleChoice2.B => 2,
- MultipleChoice2.C => 3,
- MultipleChoice2.D => @as(u32, 1234),
- MultipleChoice2.Unspecified1 => 5,
- MultipleChoice2.Unspecified2 => 6,
- MultipleChoice2.Unspecified3 => 7,
- MultipleChoice2.Unspecified4 => 8,
- MultipleChoice2.Unspecified5 => 9,
- });
-}
-
-test "cast integer literal to enum" {
- try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
- try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
-}
-
-const EnumWithOneMember = enum {
- Eof,
-};
+const EnumWithOneMember = enum { Eof };
fn doALoopThing(id: EnumWithOneMember) void {
while (true) {
@@ -958,20 +651,7 @@ fn doALoopThing(id: EnumWithOneMember) void {
}
}
-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 State = enum { Start };
const EnumWithTagValues = enum(u4) {
A = 1 << 0,
@@ -979,24 +659,22 @@ const EnumWithTagValues = enum(u4) {
C = 1 << 2,
D = 1 << 3,
};
-test "enum with tag values don't require parens" {
- try expect(@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 try expect(@sizeOf(Enum) == @sizeOf(u8));
+test "enum to int" {
+ try shouldEqual(Number.Zero, 0);
+ try shouldEqual(Number.One, 1);
+ try shouldEqual(Number.Two, 2);
+ try shouldEqual(Number.Three, 3);
+ try shouldEqual(Number.Four, 4);
}
-test "tag name with assigned enum values" {
- const LocalFoo = enum(u8) {
- A = 1,
- B = 0,
- };
- var b = LocalFoo.B;
- try expect(mem.eql(u8, @tagName(b), "B"));
+test "enum sizes" {
+ comptime {
+ try expect(@sizeOf(ValueCount1) == 0);
+ try expect(@sizeOf(ValueCount2) == 1);
+ try expect(@sizeOf(ValueCount256) == 1);
+ try expect(@sizeOf(ValueCount257) == 2);
+ }
}
test "enum literal equality" {
@@ -1009,11 +687,7 @@ test "enum literal equality" {
}
test "enum literal cast to enum" {
- const Color = enum {
- Auto,
- Off,
- On,
- };
+ const Color = enum { Auto, Off, On };
var color1: Color = .Auto;
var color2 = Color.Auto;
@@ -1021,147 +695,8 @@ test "enum literal cast to enum" {
}
test "peer type resolution with enum literal" {
- const Items = enum {
- one,
- two,
- };
+ const Items = enum { one, two };
try expect(Items.two == .two);
try expect(.two == Items.two);
}
-
-test "enum literal in array literal" {
- const Items = enum {
- one,
- two,
- };
-
- const array = [_]Items{
- .one,
- .two,
- };
-
- try expect(array[0] == .one);
- try expect(array[1] == .two);
-}
-
-test "signed integer as enum tag" {
- const SignedEnum = enum(i2) {
- A0 = -1,
- A1 = 0,
- A2 = 1,
- };
-
- try expect(@enumToInt(SignedEnum.A0) == -1);
- try expect(@enumToInt(SignedEnum.A1) == 0);
- try expect(@enumToInt(SignedEnum.A2) == 1);
-}
-
-test "enum value allocation" {
- const LargeEnum = enum(u32) {
- A0 = 0x80000000,
- A1,
- A2,
- };
-
- try expect(@enumToInt(LargeEnum.A0) == 0x80000000);
- try expect(@enumToInt(LargeEnum.A1) == 0x80000001);
- try expect(@enumToInt(LargeEnum.A2) == 0x80000002);
-}
-
-test "enum literal casting to tagged union" {
- const Arch = union(enum) {
- x86_64,
- arm: Arm32,
-
- const Arm32 = enum {
- v8_5a,
- v8_4a,
- };
- };
-
- var t = true;
- var x: Arch = .x86_64;
- var y = if (t) x else .x86_64;
- switch (y) {
- .x86_64 => {},
- else => @panic("fail"),
- }
-}
-
-test "enum with one member and custom tag type" {
- const E = enum(u2) {
- One,
- };
- try expect(@enumToInt(E.One) == 0);
- const E2 = enum(u2) {
- One = 2,
- };
- try expect(@enumToInt(E2.One) == 2);
-}
-
-test "enum literal casting to optional" {
- var bar: ?Bar = undefined;
- bar = .B;
-
- try expect(bar.? == Bar.B);
-}
-
-test "enum literal casting to error union with payload enum" {
- var bar: error{B}!Bar = undefined;
- bar = .B; // should never cast to the error set
-
- try expect((try bar) == Bar.B);
-}
-
-test "enum with one member and u1 tag type @enumToInt" {
- const Enum = enum(u1) {
- Test,
- };
- try expect(@enumToInt(Enum.Test) == 0);
-}
-
-test "enum with comptime_int tag type" {
- const Enum = enum(comptime_int) {
- One = 3,
- Two = 2,
- Three = 1,
- };
- comptime try expect(Tag(Enum) == comptime_int);
-}
-
-test "enum with one member default to u0 tag type" {
- const E0 = enum {
- X,
- };
- comptime try expect(Tag(E0) == u0);
-}
-
-test "tagName on enum literals" {
- try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
- comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
-}
-
-test "method call on an enum" {
- const S = struct {
- const E = enum {
- one,
- two,
-
- fn method(self: *E) bool {
- return self.* == .two;
- }
-
- fn generic_method(self: *E, foo: anytype) bool {
- return self.* == .two and foo == bool;
- }
- };
- fn doTheTest() !void {
- var e = E.two;
- try expect(e.method());
- try expect(e.generic_method(bool));
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
test/behavior/enum_stage1.zig
@@ -0,0 +1,1058 @@
+const expect = @import("std").testing.expect;
+const mem = @import("std").mem;
+const Tag = @import("std").meta.Tag;
+
+test "non-exhaustive enum" {
+ const S = struct {
+ const E = enum(u8) {
+ a,
+ b,
+ _,
+ };
+ fn doTheTest(y: u8) !void {
+ var e: E = .b;
+ try expect(switch (e) {
+ .a => false,
+ .b => true,
+ _ => false,
+ });
+ e = @intToEnum(E, 12);
+ try expect(switch (e) {
+ .a => false,
+ .b => false,
+ _ => true,
+ });
+
+ try expect(switch (e) {
+ .a => false,
+ .b => false,
+ else => true,
+ });
+ e = .b;
+ try expect(switch (e) {
+ .a => false,
+ else => true,
+ });
+
+ try expect(@typeInfo(E).Enum.fields.len == 2);
+ e = @intToEnum(E, 12);
+ try expect(@enumToInt(e) == 12);
+ e = @intToEnum(E, y);
+ try expect(@enumToInt(e) == 52);
+ try expect(@typeInfo(E).Enum.is_exhaustive == false);
+ }
+ };
+ try S.doTheTest(52);
+ comptime try S.doTheTest(52);
+}
+
+test "empty non-exhaustive enum" {
+ const S = struct {
+ const E = enum(u8) {
+ _,
+ };
+ fn doTheTest(y: u8) !void {
+ var e = @intToEnum(E, y);
+ try expect(switch (e) {
+ _ => true,
+ });
+ try expect(@enumToInt(e) == y);
+
+ try expect(@typeInfo(E).Enum.fields.len == 0);
+ try expect(@typeInfo(E).Enum.is_exhaustive == false);
+ }
+ };
+ try S.doTheTest(42);
+ comptime try S.doTheTest(42);
+}
+
+test "single field non-exhaustive enum" {
+ const S = struct {
+ const E = enum(u8) { a, _ };
+ fn doTheTest(y: u8) !void {
+ var e: E = .a;
+ try expect(switch (e) {
+ .a => true,
+ _ => false,
+ });
+ e = @intToEnum(E, 12);
+ try expect(switch (e) {
+ .a => false,
+ _ => true,
+ });
+
+ try expect(switch (e) {
+ .a => false,
+ else => true,
+ });
+ e = .a;
+ try expect(switch (e) {
+ .a => true,
+ else => false,
+ });
+
+ try expect(@enumToInt(@intToEnum(E, y)) == y);
+ try expect(@typeInfo(E).Enum.fields.len == 1);
+ try expect(@typeInfo(E).Enum.is_exhaustive == false);
+ }
+ };
+ try S.doTheTest(23);
+ comptime try S.doTheTest(23);
+}
+
+test "enum type" {
+ const foo1 = Foo{ .One = 13 };
+ const foo2 = Foo{
+ .Two = Point{
+ .x = 1234,
+ .y = 5678,
+ },
+ };
+ try expect(foo1.One == 13);
+ try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
+ const bar = Bar.B;
+
+ try expect(bar == Bar.B);
+ try expect(@typeInfo(Foo).Union.fields.len == 3);
+ try expect(@typeInfo(Bar).Enum.fields.len == 4);
+ try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid));
+ try expect(@sizeOf(Bar) == 1);
+}
+
+test "enum as return value" {
+ switch (returnAnInt(13)) {
+ Foo.One => |value| try expect(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 };
+
+fn shouldEqual(n: Number, expected: u3) !void {
+ try expect(@enumToInt(n) == expected);
+}
+
+test "int to enum" {
+ try testIntToEnumEval(3);
+}
+fn testIntToEnumEval(x: i32) !void {
+ try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
+}
+const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
+
+test "@tagName" {
+ try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+ comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+}
+
+test "@tagName non-exhaustive enum" {
+ try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
+ comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
+}
+
+fn testEnumTagNameBare(n: anytype) []const u8 {
+ return @tagName(n);
+}
+
+const BareNumber = enum { One, Two, Three };
+
+const NonExhaustive = enum(u8) { A, B, _ };
+
+test "enum alignment" {
+ comptime {
+ try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
+ try expect(@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,
+};
+
+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 try expect(Tag(Small) == u2);
+ }
+ {
+ var x = Small2.One;
+ x = Small2.Two;
+ comptime try expect(Tag(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;
+ try expect(getA(&data) == A.Two);
+ try expect(getB(&data) == B.Three3);
+ try expect(getC(&data) == C.Four4);
+ comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
+
+ data.b = B.Four3;
+ try expect(data.b == B.Four3);
+
+ data.a = A.Three;
+ try expect(data.a == A.Three);
+ try expect(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" {
+ try testCastEnumTag(Small2.Two);
+ comptime try testCastEnumTag(Small2.Two);
+}
+
+fn testCastEnumTag(value: Small2) !void {
+ try expect(@enumToInt(value) == 1);
+}
+
+const MultipleChoice = enum(u32) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+
+test "enum with specified tag values" {
+ try testEnumWithSpecifiedTagValues(MultipleChoice.C);
+ comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
+}
+
+fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
+ try expect(@enumToInt(x) == 60);
+ try expect(1234 == switch (x) {
+ MultipleChoice.A => 1,
+ MultipleChoice.B => 2,
+ MultipleChoice.C => @as(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" {
+ try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+ comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
+ try expect(@enumToInt(x) == 1000);
+ try expect(1234 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => 3,
+ MultipleChoice2.D => @as(u32, 1234),
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
+
+test "cast integer literal to enum" {
+ try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
+ try expect(@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" {
+ try expect(@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 try expect(@sizeOf(Enum) == @sizeOf(u8));
+}
+
+test "tag name with assigned enum values" {
+ const LocalFoo = enum(u8) {
+ A = 1,
+ B = 0,
+ };
+ var b = LocalFoo.B;
+ try expect(mem.eql(u8, @tagName(b), "B"));
+}
+
+test "enum literal in array literal" {
+ const Items = enum { one, two };
+ const array = [_]Items{ .one, .two };
+
+ try expect(array[0] == .one);
+ try expect(array[1] == .two);
+}
+
+test "signed integer as enum tag" {
+ const SignedEnum = enum(i2) {
+ A0 = -1,
+ A1 = 0,
+ A2 = 1,
+ };
+
+ try expect(@enumToInt(SignedEnum.A0) == -1);
+ try expect(@enumToInt(SignedEnum.A1) == 0);
+ try expect(@enumToInt(SignedEnum.A2) == 1);
+}
+
+test "enum value allocation" {
+ const LargeEnum = enum(u32) {
+ A0 = 0x80000000,
+ A1,
+ A2,
+ };
+
+ try expect(@enumToInt(LargeEnum.A0) == 0x80000000);
+ try expect(@enumToInt(LargeEnum.A1) == 0x80000001);
+ try expect(@enumToInt(LargeEnum.A2) == 0x80000002);
+}
+
+test "enum literal casting to tagged union" {
+ const Arch = union(enum) {
+ x86_64,
+ arm: Arm32,
+
+ const Arm32 = enum {
+ v8_5a,
+ v8_4a,
+ };
+ };
+
+ var t = true;
+ var x: Arch = .x86_64;
+ var y = if (t) x else .x86_64;
+ switch (y) {
+ .x86_64 => {},
+ else => @panic("fail"),
+ }
+}
+
+test "enum with one member and custom tag type" {
+ const E = enum(u2) {
+ One,
+ };
+ try expect(@enumToInt(E.One) == 0);
+ const E2 = enum(u2) {
+ One = 2,
+ };
+ try expect(@enumToInt(E2.One) == 2);
+}
+
+test "enum literal casting to optional" {
+ var bar: ?Bar = undefined;
+ bar = .B;
+
+ try expect(bar.? == Bar.B);
+}
+
+test "enum literal casting to error union with payload enum" {
+ var bar: error{B}!Bar = undefined;
+ bar = .B; // should never cast to the error set
+
+ try expect((try bar) == Bar.B);
+}
+
+test "enum with one member and u1 tag type @enumToInt" {
+ const Enum = enum(u1) {
+ Test,
+ };
+ try expect(@enumToInt(Enum.Test) == 0);
+}
+
+test "enum with comptime_int tag type" {
+ const Enum = enum(comptime_int) {
+ One = 3,
+ Two = 2,
+ Three = 1,
+ };
+ comptime try expect(Tag(Enum) == comptime_int);
+}
+
+test "enum with one member default to u0 tag type" {
+ const E0 = enum { X };
+ comptime try expect(Tag(E0) == u0);
+}
+
+test "tagName on enum literals" {
+ try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
+ comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
+}
+
+test "method call on an enum" {
+ const S = struct {
+ const E = enum {
+ one,
+ two,
+
+ fn method(self: *E) bool {
+ return self.* == .two;
+ }
+
+ fn generic_method(self: *E, foo: anytype) bool {
+ return self.* == .two and foo == bool;
+ }
+ };
+ fn doTheTest() !void {
+ var e = E.two;
+ try expect(e.method());
+ try expect(e.generic_method(bool));
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
test/behavior/for.zig
@@ -2,179 +2,3 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
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..]);
- try expect(mem.eql(u8, &target, "bcdefgh"));
-
- for (source) |*c, i| {
- _ = i;
- try expect(@TypeOf(c) == *const u8);
- }
- for (target) |*c, i| {
- _ = i;
- try expect(@TypeOf(c) == *u8);
- }
-}
-
-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| {
- _ = item;
- 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| {
- _ = item;
- 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) |_, index| {
- buffer[buf_index] = @intCast(u8, index);
- buf_index += 1;
- }
-
- try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
-}
-
-test "break from outer for loop" {
- try testBreakOuter();
- comptime try testBreakOuter();
-}
-
-fn testBreakOuter() !void {
- var array = "aoeu";
- var count: usize = 0;
- outer: for (array) |_| {
- for (array) |_| {
- count += 1;
- break :outer;
- }
- }
- try expect(count == 1);
-}
-
-test "continue outer for loop" {
- try testContinueOuter();
- comptime try testContinueOuter();
-}
-
-fn testContinueOuter() !void {
- var array = "aoeu";
- var counter: usize = 0;
- outer: for (array) |_| {
- for (array) |_| {
- counter += 1;
- continue :outer;
- }
- }
- try expect(counter == array.len);
-}
-
-test "2 break statements and an else" {
- const S = struct {
- fn entry(t: bool, f: bool) !void {
- var buf: [10]u8 = undefined;
- var ok = false;
- ok = for (buf) |item| {
- _ = item;
- if (f) break false;
- if (t) break true;
- } else false;
- try expect(ok);
- }
- };
- try S.entry(true, false);
- comptime try S.entry(true, false);
-}
-
-test "for with null and T peer types and inferred result location type" {
- const S = struct {
- fn doTheTest(slice: []const u8) !void {
- if (for (slice) |item| {
- if (item == 10) {
- break item;
- }
- } else null) |v| {
- _ = v;
- @panic("fail");
- }
- }
- };
- try S.doTheTest(&[_]u8{ 1, 2 });
- comptime try S.doTheTest(&[_]u8{ 1, 2 });
-}
-
-test "for copies its payload" {
- const S = struct {
- fn doTheTest() !void {
- var x = [_]usize{ 1, 2, 3 };
- for (x) |value, i| {
- // Modify the original array
- x[i] += 99;
- try expectEqual(value, i + 1);
- }
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "for on slice with allowzero ptr" {
- const S = struct {
- fn doTheTest(slice: []const u8) !void {
- var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len];
- for (ptr) |x, i| try expect(x == i + 1);
- for (ptr) |*x, i| try expect(x.* == i + 1);
- }
- };
- try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
- comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
-}
test/behavior/for_stage1.zig
@@ -0,0 +1,185 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
+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..]);
+ try expect(mem.eql(u8, &target, "bcdefgh"));
+
+ for (source) |*c, i| {
+ _ = i;
+ try expect(@TypeOf(c) == *const u8);
+ }
+ for (target) |*c, i| {
+ _ = i;
+ try expect(@TypeOf(c) == *u8);
+ }
+}
+
+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| {
+ _ = item;
+ 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| {
+ _ = item;
+ 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) |_, index| {
+ buffer[buf_index] = @intCast(u8, index);
+ buf_index += 1;
+ }
+
+ try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
+}
+
+test "break from outer for loop" {
+ try testBreakOuter();
+ comptime try testBreakOuter();
+}
+
+fn testBreakOuter() !void {
+ var array = "aoeu";
+ var count: usize = 0;
+ outer: for (array) |_| {
+ for (array) |_| {
+ count += 1;
+ break :outer;
+ }
+ }
+ try expect(count == 1);
+}
+
+test "continue outer for loop" {
+ try testContinueOuter();
+ comptime try testContinueOuter();
+}
+
+fn testContinueOuter() !void {
+ var array = "aoeu";
+ var counter: usize = 0;
+ outer: for (array) |_| {
+ for (array) |_| {
+ counter += 1;
+ continue :outer;
+ }
+ }
+ try expect(counter == array.len);
+}
+
+test "2 break statements and an else" {
+ const S = struct {
+ fn entry(t: bool, f: bool) !void {
+ var buf: [10]u8 = undefined;
+ var ok = false;
+ ok = for (buf) |item| {
+ _ = item;
+ if (f) break false;
+ if (t) break true;
+ } else false;
+ try expect(ok);
+ }
+ };
+ try S.entry(true, false);
+ comptime try S.entry(true, false);
+}
+
+test "for with null and T peer types and inferred result location type" {
+ const S = struct {
+ fn doTheTest(slice: []const u8) !void {
+ if (for (slice) |item| {
+ if (item == 10) {
+ break item;
+ }
+ } else null) |v| {
+ _ = v;
+ @panic("fail");
+ }
+ }
+ };
+ try S.doTheTest(&[_]u8{ 1, 2 });
+ comptime try S.doTheTest(&[_]u8{ 1, 2 });
+}
+
+test "for copies its payload" {
+ const S = struct {
+ fn doTheTest() !void {
+ var x = [_]usize{ 1, 2, 3 };
+ for (x) |value, i| {
+ // Modify the original array
+ x[i] += 99;
+ try expectEqual(value, i + 1);
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "for on slice with allowzero ptr" {
+ const S = struct {
+ fn doTheTest(slice: []const u8) !void {
+ var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len];
+ for (ptr) |x, i| try expect(x == i + 1);
+ for (ptr) |*x, i| try expect(x.* == i + 1);
+ }
+ };
+ try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
+ comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
+}
+
+test "ignore lval with underscore (for loop)" {
+ for ([_]void{}) |_, i| {
+ _ = i;
+ for ([_]void{}) |_, j| {
+ _ = j;
+ break;
+ }
+ break;
+ }
+}
test/behavior/if.zig
@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {
const x = if (t) Num.Two else unreachable;
try expect(x == .Two);
}
+
+test "if copies its payload" {
+ const S = struct {
+ fn doTheTest() !void {
+ var tmp: ?i32 = 10;
+ if (tmp) |value| {
+ // Modify the original variable
+ tmp = null;
+ try expect(value == 10);
+ } else unreachable;
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
test/behavior/if_stage1.zig
@@ -17,18 +17,3 @@ test "if prongs cast to expected type instead of peer type resolution" {
try S.doTheTest(false);
comptime try S.doTheTest(false);
}
-
-test "while copies its payload" {
- const S = struct {
- fn doTheTest() !void {
- var tmp: ?i32 = 10;
- if (tmp) |value| {
- // Modify the original variable
- tmp = null;
- try expectEqual(@as(i32, 10), value);
- } else unreachable;
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
test/behavior/switch.zig
@@ -2,548 +2,3 @@ const std = @import("std");
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
-
-test "switch with numbers" {
- try testSwitchWithNumbers(13);
-}
-
-fn testSwitchWithNumbers(x: u32) !void {
- const result = switch (x) {
- 1, 2, 3, 4...8 => false,
- 13 => true,
- else => false,
- };
- try expect(result);
-}
-
-test "switch with all ranges" {
- try expect(testSwitchWithAllRanges(50, 3) == 1);
- try expect(testSwitchWithAllRanges(101, 0) == 2);
- try expect(testSwitchWithAllRanges(300, 5) == 3);
- try expect(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 {
- try expect(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" {
- try nonConstSwitch(SwitchStatementFoo.C);
-}
-fn nonConstSwitch(foo: SwitchStatementFoo) !void {
- const val = switch (foo) {
- SwitchStatementFoo.A => @as(i32, 1),
- SwitchStatementFoo.B => 2,
- SwitchStatementFoo.C => 3,
- SwitchStatementFoo.D => 4,
- };
- try expect(val == 3);
-}
-const SwitchStatementFoo = enum {
- A,
- B,
- C,
- D,
-};
-
-test "switch prong with variable" {
- try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
- try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
- try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
-}
-const SwitchProngWithVarEnum = union(enum) {
- One: i32,
- Two: f32,
- Meh: void,
-};
-fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
- switch (a) {
- SwitchProngWithVarEnum.One => |x| {
- try expect(x == 13);
- },
- SwitchProngWithVarEnum.Two => |x| {
- try expect(x == 13.0);
- },
- SwitchProngWithVarEnum.Meh => |x| {
- const v: void = x;
- _ = v;
- },
- }
-}
-
-test "switch on enum using pointer capture" {
- try testSwitchEnumPtrCapture();
- comptime try testSwitchEnumPtrCapture();
-}
-
-fn testSwitchEnumPtrCapture() !void {
- var value = SwitchProngWithVarEnum{ .One = 1234 };
- switch (value) {
- SwitchProngWithVarEnum.One => |*x| x.* += 1,
- else => unreachable,
- }
- switch (value) {
- SwitchProngWithVarEnum.One => |x| try expect(x == 1235),
- else => unreachable,
- }
-}
-
-test "switch with multiple expressions" {
- const x = switch (returnsFive()) {
- 1, 2, 3 => 1,
- 4, 5, 6 => 2,
- else => @as(i32, 3),
- };
- try expect(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" {
- try expect(!returnsFalse());
-}
-
-test "switch on type" {
- try expect(trueIfBoolFalseOtherwise(bool));
- try expect(!trueIfBoolFalseOtherwise(i32));
-}
-
-fn trueIfBoolFalseOtherwise(comptime T: type) bool {
- return switch (T) {
- bool => true,
- else => false,
- };
-}
-
-test "switch handles all cases of number" {
- try testSwitchHandleAllCases();
- comptime try testSwitchHandleAllCases();
-}
-
-fn testSwitchHandleAllCases() !void {
- try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
- try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
- try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
- try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
-
- try expect(testSwitchHandleAllCasesRange(100) == 0);
- try expect(testSwitchHandleAllCasesRange(200) == 1);
- try expect(testSwitchHandleAllCasesRange(201) == 2);
- try expect(testSwitchHandleAllCasesRange(202) == 4);
- try expect(testSwitchHandleAllCasesRange(230) == 3);
-}
-
-fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
- return switch (x) {
- 0 => @as(u2, 3),
- 1 => 2,
- 2 => 1,
- 3 => 0,
- };
-}
-
-fn testSwitchHandleAllCasesRange(x: u8) u8 {
- return switch (x) {
- 0...100 => @as(u8, 0),
- 101...200 => 1,
- 201, 203 => 2,
- 202 => 4,
- 204...255 => 3,
- };
-}
-
-test "switch all prongs unreachable" {
- try testAllProngsUnreachable();
- comptime try testAllProngsUnreachable();
-}
-
-fn testAllProngsUnreachable() !void {
- try expect(switchWithUnreachable(1) == 2);
- try expect(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,
- };
- try expect(x == 1);
-}
-
-test "switching on booleans" {
- try testSwitchOnBools();
- comptime try testSwitchOnBools();
-}
-
-fn testSwitchOnBools() !void {
- try expect(testSwitchOnBoolsTrueAndFalse(true) == false);
- try expect(testSwitchOnBoolsTrueAndFalse(false) == true);
-
- try expect(testSwitchOnBoolsTrueWithElse(true) == false);
- try expect(testSwitchOnBoolsTrueWithElse(false) == true);
-
- try expect(testSwitchOnBoolsFalseWithElse(true) == false);
- try expect(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,
- };
-}
-
-test "u0" {
- var val: u0 = 0;
- switch (val) {
- 0 => try expect(val == 0),
- }
-}
-
-test "undefined.u0" {
- var val: u0 = undefined;
- switch (val) {
- 0 => try expect(val == 0),
- }
-}
-
-test "anon enum literal used in switch on union enum" {
- const Foo = union(enum) {
- a: i32,
- };
-
- var foo = Foo{ .a = 1234 };
- switch (foo) {
- .a => |x| {
- try expect(x == 1234);
- },
- }
-}
-
-test "else prong of switch on error set excludes other cases" {
- const S = struct {
- fn doTheTest() !void {
- try expectError(error.C, bar());
- }
- const E = error{
- A,
- B,
- } || E2;
-
- const E2 = error{
- C,
- D,
- };
-
- fn foo() E!void {
- return error.C;
- }
-
- fn bar() E2!void {
- foo() catch |err| switch (err) {
- error.A, error.B => {},
- else => |e| return e,
- };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "switch prongs with error set cases make a new error set type for capture value" {
- const S = struct {
- fn doTheTest() !void {
- try expectError(error.B, bar());
- }
- const E = E1 || E2;
-
- const E1 = error{
- A,
- B,
- };
-
- const E2 = error{
- C,
- D,
- };
-
- fn foo() E!void {
- return error.B;
- }
-
- fn bar() E1!void {
- foo() catch |err| switch (err) {
- error.A, error.B => |e| return e,
- else => {},
- };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "return result loc and then switch with range implicit casted to error union" {
- const S = struct {
- fn doTheTest() !void {
- try expect((func(0xb) catch unreachable) == 0xb);
- }
- fn func(d: u8) anyerror!u8 {
- return switch (d) {
- 0xa...0xf => d,
- else => unreachable,
- };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "switch with null and T peer types and inferred result location type" {
- const S = struct {
- fn doTheTest(c: u8) !void {
- if (switch (c) {
- 0 => true,
- else => null,
- }) |v| {
- _ = v;
- @panic("fail");
- }
- }
- };
- try S.doTheTest(1);
- comptime try S.doTheTest(1);
-}
-
-test "switch prongs with cases with identical payload types" {
- const Union = union(enum) {
- A: usize,
- B: isize,
- C: usize,
- };
- const S = struct {
- fn doTheTest() !void {
- try doTheSwitch1(Union{ .A = 8 });
- try doTheSwitch2(Union{ .B = -8 });
- }
- fn doTheSwitch1(u: Union) !void {
- switch (u) {
- .A, .C => |e| {
- try expect(@TypeOf(e) == usize);
- try expect(e == 8);
- },
- .B => |e| {
- _ = e;
- @panic("fail");
- },
- }
- }
- fn doTheSwitch2(u: Union) !void {
- switch (u) {
- .A, .C => |e| {
- _ = e;
- @panic("fail");
- },
- .B => |e| {
- try expect(@TypeOf(e) == isize);
- try expect(e == -8);
- },
- }
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "switch with disjoint range" {
- var q: u8 = 0;
- switch (q) {
- 0...125 => {},
- 127...255 => {},
- 126...126 => {},
- }
-}
-
-test "switch variable for range and multiple prongs" {
- const S = struct {
- fn doTheTest() !void {
- var u: u8 = 16;
- try doTheSwitch(u);
- comptime try doTheSwitch(u);
- var v: u8 = 42;
- try doTheSwitch(v);
- comptime try doTheSwitch(v);
- }
- fn doTheSwitch(q: u8) !void {
- switch (q) {
- 0...40 => |x| try expect(x == 16),
- 41, 42, 43 => |x| try expect(x == 42),
- else => try expect(false),
- }
- }
- };
- _ = S;
-}
-
-var state: u32 = 0;
-fn poll() void {
- switch (state) {
- 0 => {
- state = 1;
- },
- else => {
- state += 1;
- },
- }
-}
-
-test "switch on global mutable var isn't constant-folded" {
- while (state < 2) {
- poll();
- }
-}
-
-test "switch on pointer type" {
- const S = struct {
- const X = struct {
- field: u32,
- };
-
- const P1 = @intToPtr(*X, 0x400);
- const P2 = @intToPtr(*X, 0x800);
- const P3 = @intToPtr(*X, 0xC00);
-
- fn doTheTest(arg: *X) i32 {
- switch (arg) {
- P1 => return 1,
- P2 => return 2,
- else => return 3,
- }
- }
- };
-
- try expect(1 == S.doTheTest(S.P1));
- try expect(2 == S.doTheTest(S.P2));
- try expect(3 == S.doTheTest(S.P3));
- comptime try expect(1 == S.doTheTest(S.P1));
- comptime try expect(2 == S.doTheTest(S.P2));
- comptime try expect(3 == S.doTheTest(S.P3));
-}
-
-test "switch on error set with single else" {
- const S = struct {
- fn doTheTest() !void {
- var some: error{Foo} = error.Foo;
- try expect(switch (some) {
- else => |a| blk: {
- a catch {};
- break :blk true;
- },
- });
- }
- };
-
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "while copies its payload" {
- const S = struct {
- fn doTheTest() !void {
- var tmp: union(enum) {
- A: u8,
- B: u32,
- } = .{ .A = 42 };
- switch (tmp) {
- .A => |value| {
- // Modify the original union
- tmp = .{ .B = 0x10101010 };
- try expectEqual(@as(u8, 42), value);
- },
- else => unreachable,
- }
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
test/behavior/switch_stage1.zig
@@ -0,0 +1,549 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectError = std.testing.expectError;
+const expectEqual = std.testing.expectEqual;
+
+test "switch with numbers" {
+ try testSwitchWithNumbers(13);
+}
+
+fn testSwitchWithNumbers(x: u32) !void {
+ const result = switch (x) {
+ 1, 2, 3, 4...8 => false,
+ 13 => true,
+ else => false,
+ };
+ try expect(result);
+}
+
+test "switch with all ranges" {
+ try expect(testSwitchWithAllRanges(50, 3) == 1);
+ try expect(testSwitchWithAllRanges(101, 0) == 2);
+ try expect(testSwitchWithAllRanges(300, 5) == 3);
+ try expect(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 {
+ try expect(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" {
+ try nonConstSwitch(SwitchStatementFoo.C);
+}
+fn nonConstSwitch(foo: SwitchStatementFoo) !void {
+ const val = switch (foo) {
+ SwitchStatementFoo.A => @as(i32, 1),
+ SwitchStatementFoo.B => 2,
+ SwitchStatementFoo.C => 3,
+ SwitchStatementFoo.D => 4,
+ };
+ try expect(val == 3);
+}
+const SwitchStatementFoo = enum {
+ A,
+ B,
+ C,
+ D,
+};
+
+test "switch prong with variable" {
+ try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
+ try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
+ try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
+}
+const SwitchProngWithVarEnum = union(enum) {
+ One: i32,
+ Two: f32,
+ Meh: void,
+};
+fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
+ switch (a) {
+ SwitchProngWithVarEnum.One => |x| {
+ try expect(x == 13);
+ },
+ SwitchProngWithVarEnum.Two => |x| {
+ try expect(x == 13.0);
+ },
+ SwitchProngWithVarEnum.Meh => |x| {
+ const v: void = x;
+ _ = v;
+ },
+ }
+}
+
+test "switch on enum using pointer capture" {
+ try testSwitchEnumPtrCapture();
+ comptime try testSwitchEnumPtrCapture();
+}
+
+fn testSwitchEnumPtrCapture() !void {
+ var value = SwitchProngWithVarEnum{ .One = 1234 };
+ switch (value) {
+ SwitchProngWithVarEnum.One => |*x| x.* += 1,
+ else => unreachable,
+ }
+ switch (value) {
+ SwitchProngWithVarEnum.One => |x| try expect(x == 1235),
+ else => unreachable,
+ }
+}
+
+test "switch with multiple expressions" {
+ const x = switch (returnsFive()) {
+ 1, 2, 3 => 1,
+ 4, 5, 6 => 2,
+ else => @as(i32, 3),
+ };
+ try expect(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" {
+ try expect(!returnsFalse());
+}
+
+test "switch on type" {
+ try expect(trueIfBoolFalseOtherwise(bool));
+ try expect(!trueIfBoolFalseOtherwise(i32));
+}
+
+fn trueIfBoolFalseOtherwise(comptime T: type) bool {
+ return switch (T) {
+ bool => true,
+ else => false,
+ };
+}
+
+test "switch handles all cases of number" {
+ try testSwitchHandleAllCases();
+ comptime try testSwitchHandleAllCases();
+}
+
+fn testSwitchHandleAllCases() !void {
+ try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
+ try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
+ try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
+ try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
+
+ try expect(testSwitchHandleAllCasesRange(100) == 0);
+ try expect(testSwitchHandleAllCasesRange(200) == 1);
+ try expect(testSwitchHandleAllCasesRange(201) == 2);
+ try expect(testSwitchHandleAllCasesRange(202) == 4);
+ try expect(testSwitchHandleAllCasesRange(230) == 3);
+}
+
+fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
+ return switch (x) {
+ 0 => @as(u2, 3),
+ 1 => 2,
+ 2 => 1,
+ 3 => 0,
+ };
+}
+
+fn testSwitchHandleAllCasesRange(x: u8) u8 {
+ return switch (x) {
+ 0...100 => @as(u8, 0),
+ 101...200 => 1,
+ 201, 203 => 2,
+ 202 => 4,
+ 204...255 => 3,
+ };
+}
+
+test "switch all prongs unreachable" {
+ try testAllProngsUnreachable();
+ comptime try testAllProngsUnreachable();
+}
+
+fn testAllProngsUnreachable() !void {
+ try expect(switchWithUnreachable(1) == 2);
+ try expect(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,
+ };
+ try expect(x == 1);
+}
+
+test "switching on booleans" {
+ try testSwitchOnBools();
+ comptime try testSwitchOnBools();
+}
+
+fn testSwitchOnBools() !void {
+ try expect(testSwitchOnBoolsTrueAndFalse(true) == false);
+ try expect(testSwitchOnBoolsTrueAndFalse(false) == true);
+
+ try expect(testSwitchOnBoolsTrueWithElse(true) == false);
+ try expect(testSwitchOnBoolsTrueWithElse(false) == true);
+
+ try expect(testSwitchOnBoolsFalseWithElse(true) == false);
+ try expect(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,
+ };
+}
+
+test "u0" {
+ var val: u0 = 0;
+ switch (val) {
+ 0 => try expect(val == 0),
+ }
+}
+
+test "undefined.u0" {
+ var val: u0 = undefined;
+ switch (val) {
+ 0 => try expect(val == 0),
+ }
+}
+
+test "anon enum literal used in switch on union enum" {
+ const Foo = union(enum) {
+ a: i32,
+ };
+
+ var foo = Foo{ .a = 1234 };
+ switch (foo) {
+ .a => |x| {
+ try expect(x == 1234);
+ },
+ }
+}
+
+test "else prong of switch on error set excludes other cases" {
+ const S = struct {
+ fn doTheTest() !void {
+ try expectError(error.C, bar());
+ }
+ const E = error{
+ A,
+ B,
+ } || E2;
+
+ const E2 = error{
+ C,
+ D,
+ };
+
+ fn foo() E!void {
+ return error.C;
+ }
+
+ fn bar() E2!void {
+ foo() catch |err| switch (err) {
+ error.A, error.B => {},
+ else => |e| return e,
+ };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "switch prongs with error set cases make a new error set type for capture value" {
+ const S = struct {
+ fn doTheTest() !void {
+ try expectError(error.B, bar());
+ }
+ const E = E1 || E2;
+
+ const E1 = error{
+ A,
+ B,
+ };
+
+ const E2 = error{
+ C,
+ D,
+ };
+
+ fn foo() E!void {
+ return error.B;
+ }
+
+ fn bar() E1!void {
+ foo() catch |err| switch (err) {
+ error.A, error.B => |e| return e,
+ else => {},
+ };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "return result loc and then switch with range implicit casted to error union" {
+ const S = struct {
+ fn doTheTest() !void {
+ try expect((func(0xb) catch unreachable) == 0xb);
+ }
+ fn func(d: u8) anyerror!u8 {
+ return switch (d) {
+ 0xa...0xf => d,
+ else => unreachable,
+ };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "switch with null and T peer types and inferred result location type" {
+ const S = struct {
+ fn doTheTest(c: u8) !void {
+ if (switch (c) {
+ 0 => true,
+ else => null,
+ }) |v| {
+ _ = v;
+ @panic("fail");
+ }
+ }
+ };
+ try S.doTheTest(1);
+ comptime try S.doTheTest(1);
+}
+
+test "switch prongs with cases with identical payload types" {
+ const Union = union(enum) {
+ A: usize,
+ B: isize,
+ C: usize,
+ };
+ const S = struct {
+ fn doTheTest() !void {
+ try doTheSwitch1(Union{ .A = 8 });
+ try doTheSwitch2(Union{ .B = -8 });
+ }
+ fn doTheSwitch1(u: Union) !void {
+ switch (u) {
+ .A, .C => |e| {
+ try expect(@TypeOf(e) == usize);
+ try expect(e == 8);
+ },
+ .B => |e| {
+ _ = e;
+ @panic("fail");
+ },
+ }
+ }
+ fn doTheSwitch2(u: Union) !void {
+ switch (u) {
+ .A, .C => |e| {
+ _ = e;
+ @panic("fail");
+ },
+ .B => |e| {
+ try expect(@TypeOf(e) == isize);
+ try expect(e == -8);
+ },
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "switch with disjoint range" {
+ var q: u8 = 0;
+ switch (q) {
+ 0...125 => {},
+ 127...255 => {},
+ 126...126 => {},
+ }
+}
+
+test "switch variable for range and multiple prongs" {
+ const S = struct {
+ fn doTheTest() !void {
+ var u: u8 = 16;
+ try doTheSwitch(u);
+ comptime try doTheSwitch(u);
+ var v: u8 = 42;
+ try doTheSwitch(v);
+ comptime try doTheSwitch(v);
+ }
+ fn doTheSwitch(q: u8) !void {
+ switch (q) {
+ 0...40 => |x| try expect(x == 16),
+ 41, 42, 43 => |x| try expect(x == 42),
+ else => try expect(false),
+ }
+ }
+ };
+ _ = S;
+}
+
+var state: u32 = 0;
+fn poll() void {
+ switch (state) {
+ 0 => {
+ state = 1;
+ },
+ else => {
+ state += 1;
+ },
+ }
+}
+
+test "switch on global mutable var isn't constant-folded" {
+ while (state < 2) {
+ poll();
+ }
+}
+
+test "switch on pointer type" {
+ const S = struct {
+ const X = struct {
+ field: u32,
+ };
+
+ const P1 = @intToPtr(*X, 0x400);
+ const P2 = @intToPtr(*X, 0x800);
+ const P3 = @intToPtr(*X, 0xC00);
+
+ fn doTheTest(arg: *X) i32 {
+ switch (arg) {
+ P1 => return 1,
+ P2 => return 2,
+ else => return 3,
+ }
+ }
+ };
+
+ try expect(1 == S.doTheTest(S.P1));
+ try expect(2 == S.doTheTest(S.P2));
+ try expect(3 == S.doTheTest(S.P3));
+ comptime try expect(1 == S.doTheTest(S.P1));
+ comptime try expect(2 == S.doTheTest(S.P2));
+ comptime try expect(3 == S.doTheTest(S.P3));
+}
+
+test "switch on error set with single else" {
+ const S = struct {
+ fn doTheTest() !void {
+ var some: error{Foo} = error.Foo;
+ try expect(switch (some) {
+ else => |a| blk: {
+ a catch {};
+ break :blk true;
+ },
+ });
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "while copies its payload" {
+ const S = struct {
+ fn doTheTest() !void {
+ var tmp: union(enum) {
+ A: u8,
+ B: u32,
+ } = .{ .A = 42 };
+ switch (tmp) {
+ .A => |value| {
+ // Modify the original union
+ tmp = .{ .B = 0x10101010 };
+ try expectEqual(@as(u8, 42), value);
+ },
+ else => unreachable,
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
test/behavior/underscore.zig
@@ -5,17 +5,6 @@ test "ignore lval with underscore" {
_ = false;
}
-test "ignore lval with underscore (for loop)" {
- for ([_]void{}) |_, i| {
- _ = i;
- for ([_]void{}) |_, j| {
- _ = j;
- break;
- }
- break;
- }
-}
-
test "ignore lval with underscore (while loop)" {
while (optionalReturnError()) |_| {
while (optionalReturnError()) |_| {
test/behavior/enum_with_members.zig → test/behavior/union_with_members.zig
File renamed without changes
test/behavior/while.zig
@@ -23,7 +23,7 @@ test "static eval while" {
}
const static_eval_while_number = staticWhileLoop1();
fn staticWhileLoop1() i32 {
- return whileLoop2();
+ return staticWhileLoop2();
}
fn staticWhileLoop2() i32 {
while (true) {
@@ -31,33 +31,6 @@ fn staticWhileLoop2() i32 {
}
}
-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;
-}
-fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
- while (true) {
- return;
- }
-}
-
test "while with continue expression" {
var sum: i32 = 0;
{
@@ -83,43 +56,6 @@ test "while with else" {
try expect(got_else == 1);
}
-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;
- var got_else: i32 = 0;
- while (getNumberOrErr()) |value| {
- sum += value;
- } else |err| {
- try expect(err == error.OutOfNumbers);
- got_else += 1;
- }
- try expect(sum == 45);
- try expect(got_else == 1);
-}
-
var numbers_left: i32 = undefined;
fn getNumberOrErr() anyerror!i32 {
return if (numbers_left == 0) error.OutOfNumbers else x: {
@@ -134,61 +70,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;
- } else |_| @as(i32, 2);
- try expect(result == 2);
-}
-
-test "while on error union with else result follow break prong" {
- const result = while (returnSuccess(10)) |value| {
- break value;
- } else |_| @as(i32, 2);
- 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);
-}
-
-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();
@@ -203,68 +84,17 @@ fn testContinueOuter() void {
}
}
-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 "while bool 2 break statements and an else" {
- const S = struct {
- fn entry(t: bool, f: bool) !void {
- var ok = false;
- ok = while (t) {
- if (f) break false;
- if (t) break true;
- } else false;
- try expect(ok);
- }
- };
- try S.entry(true, false);
- comptime try S.entry(true, false);
-}
-
-test "while optional 2 break statements and an else" {
- const S = struct {
- fn entry(opt_t: ?bool, f: bool) !void {
- var ok = false;
- ok = while (opt_t) |t| {
- if (f) break false;
- if (t) break true;
- } else false;
- try expect(ok);
- }
- };
- try S.entry(true, false);
- comptime try S.entry(true, false);
+test "break from outer while loop" {
+ testBreakOuter();
+ comptime testBreakOuter();
}
-test "while error 2 break statements and an else" {
- const S = struct {
- fn entry(opt_t: anyerror!bool, f: bool) !void {
- var ok = false;
- ok = while (opt_t) |t| {
- if (f) break false;
- if (t) break true;
- } else |_| false;
- try expect(ok);
+fn testBreakOuter() void {
+ outer: while (true) {
+ while (true) {
+ break :outer;
}
- };
- try S.entry(true, false);
- comptime try S.entry(true, false);
+ }
}
test "while copies its payload" {
test/behavior/while_stage1.zig
@@ -0,0 +1,186 @@
+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;
+}
+fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
+ while (true) {
+ return;
+ }
+}
+
+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;
+ var got_else: i32 = 0;
+ while (getNumberOrErr()) |value| {
+ sum += value;
+ } else |err| {
+ try expect(err == error.OutOfNumbers);
+ got_else += 1;
+ }
+ try expect(sum == 45);
+ try expect(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 @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;
+ } else |_| @as(i32, 2);
+ try expect(result == 2);
+}
+
+test "while on error union with else result follow break prong" {
+ const result = while (returnSuccess(10)) |value| {
+ break value;
+ } else |_| @as(i32, 2);
+ 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;
+}
+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 "while bool 2 break statements and an else" {
+ const S = struct {
+ fn entry(t: bool, f: bool) !void {
+ var ok = false;
+ ok = while (t) {
+ if (f) break false;
+ if (t) break true;
+ } else false;
+ try expect(ok);
+ }
+ };
+ try S.entry(true, false);
+ comptime try S.entry(true, false);
+}
+
+test "while optional 2 break statements and an else" {
+ const S = struct {
+ fn entry(opt_t: ?bool, f: bool) !void {
+ var ok = false;
+ ok = while (opt_t) |t| {
+ if (f) break false;
+ if (t) break true;
+ } else false;
+ try expect(ok);
+ }
+ };
+ try S.entry(true, false);
+ comptime try S.entry(true, false);
+}
+
+test "while error 2 break statements and an else" {
+ const S = struct {
+ fn entry(opt_t: anyerror!bool, f: bool) !void {
+ var ok = false;
+ ok = while (opt_t) |t| {
+ if (f) break false;
+ if (t) break true;
+ } else |_| false;
+ try expect(ok);
+ }
+ };
+ try S.entry(true, false);
+ comptime try S.entry(true, false);
+}
test/behavior.zig
@@ -15,8 +15,12 @@ test {
_ = @import("behavior/bugs/4769_b.zig");
_ = @import("behavior/bugs/6850.zig");
_ = @import("behavior/bugs/9584.zig");
+ _ = @import("behavior/call.zig");
_ = @import("behavior/cast.zig");
+ _ = @import("behavior/defer.zig");
+ _ = @import("behavior/enum.zig");
_ = @import("behavior/eval.zig");
+ _ = @import("behavior/for.zig");
_ = @import("behavior/generics.zig");
_ = @import("behavior/if.zig");
_ = @import("behavior/math.zig");
@@ -24,11 +28,14 @@ test {
_ = @import("behavior/pointers.zig");
_ = @import("behavior/sizeof_and_typeof.zig");
_ = @import("behavior/struct.zig");
+ _ = @import("behavior/switch.zig");
_ = @import("behavior/this.zig");
_ = @import("behavior/translate_c_macros.zig");
+ _ = @import("behavior/underscore.zig");
_ = @import("behavior/union.zig");
_ = @import("behavior/usingnamespace.zig");
_ = @import("behavior/widening.zig");
+ _ = @import("behavior/while.zig");
if (builtin.zig_is_stage2) {
// When all comptime_memory.zig tests pass, #9646 can be closed.
@@ -98,12 +105,11 @@ test {
_ = @import("behavior/bugs/7250.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/byval_arg_var.zig");
- _ = @import("behavior/call.zig");
+ _ = @import("behavior/call_stage1.zig");
_ = @import("behavior/cast_stage1.zig");
_ = @import("behavior/const_slice_child.zig");
- _ = @import("behavior/defer.zig");
- _ = @import("behavior/enum.zig");
- _ = @import("behavior/enum_with_members.zig");
+ _ = @import("behavior/defer_stage1.zig");
+ _ = @import("behavior/enum_stage1.zig");
_ = @import("behavior/error.zig");
_ = @import("behavior/eval_stage1.zig");
_ = @import("behavior/field_parent_ptr.zig");
@@ -111,7 +117,7 @@ test {
_ = @import("behavior/fn.zig");
_ = @import("behavior/fn_in_struct_in_comptime.zig");
_ = @import("behavior/fn_delegation.zig");
- _ = @import("behavior/for.zig");
+ _ = @import("behavior/for_stage1.zig");
_ = @import("behavior/generics_stage1.zig");
_ = @import("behavior/hasdecl.zig");
_ = @import("behavior/hasfield.zig");
@@ -143,7 +149,7 @@ test {
_ = @import("behavior/struct_stage1.zig");
_ = @import("behavior/struct_contains_null_ptr_itself.zig");
_ = @import("behavior/struct_contains_slice_of_itself.zig");
- _ = @import("behavior/switch.zig");
+ _ = @import("behavior/switch_stage1.zig");
_ = @import("behavior/switch_prong_err_enum.zig");
_ = @import("behavior/switch_prong_implicit_cast.zig");
_ = @import("behavior/truncate.zig");
@@ -153,8 +159,8 @@ test {
_ = @import("behavior/type_info.zig");
_ = @import("behavior/typename.zig");
_ = @import("behavior/undefined.zig");
- _ = @import("behavior/underscore.zig");
_ = @import("behavior/union_stage1.zig");
+ _ = @import("behavior/union_with_members.zig");
_ = @import("behavior/usingnamespace_stage1.zig");
_ = @import("behavior/var_args.zig");
_ = @import("behavior/vector.zig");
@@ -162,7 +168,7 @@ test {
if (builtin.target.cpu.arch == .wasm32) {
_ = @import("behavior/wasm.zig");
}
- _ = @import("behavior/while.zig");
+ _ = @import("behavior/while_stage1.zig");
_ = @import("behavior/src.zig");
_ = @import("behavior/translate_c_macros_stage1.zig");
}