authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-02 20:15:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-02 20:15:03-07:00
logc4df9bf56f204f63f4e87255933ba453d69d0182
tree647cec61769d5723385f8ac9b1392b3c935a219b
parent61a53a587558ff1fe1b0ec98bb424022885edccf

AstGen: fix `while` and `for` with unreachable bodies

Companion commit to 61a53a587558ff1fe1b0ec98bb424022885edccf. This commit also moves over a bunch of behavior test cases to the passing-for-stage2 section.

23 files changed, 2335 insertions(+), 1705 deletions(-)

src/AstGen.zig+14-5
...@@ -5537,8 +5537,10 @@ fn whileExpr(...@@ -5537,8 +5537,10 @@ fn whileExpr(
5537 });5537 });
5538 }5538 }
55395539
5540 loop_scope.break_count += 1;
5541 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);5540 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
5541 if (!then_scope.endsWithNoReturn()) {
5542 loop_scope.break_count += 1;
5543 }
5542 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);5544 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
55435545
5544 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);5546 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
...@@ -5549,7 +5551,6 @@ fn whileExpr(...@@ -5549,7 +5551,6 @@ fn whileExpr(
5549 src: Ast.Node.Index,5551 src: Ast.Node.Index,
5550 result: Zir.Inst.Ref,5552 result: Zir.Inst.Ref,
5551 } = if (else_node != 0) blk: {5553 } = if (else_node != 0) blk: {
5552 loop_scope.break_count += 1;
5553 const sub_scope = s: {5554 const sub_scope = s: {
5554 if (while_full.error_token) |error_token| {5555 if (while_full.error_token) |error_token| {
5555 const tag: Zir.Inst.Tag = if (payload_is_ref)5556 const tag: Zir.Inst.Tag = if (payload_is_ref)
...@@ -5576,6 +5577,9 @@ fn whileExpr(...@@ -5576,6 +5577,9 @@ fn whileExpr(
5576 }5577 }
5577 };5578 };
5578 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);5579 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
5580 if (!else_scope.endsWithNoReturn()) {
5581 loop_scope.break_count += 1;
5582 }
5579 try checkUsed(parent_gz, &else_scope.base, sub_scope);5583 try checkUsed(parent_gz, &else_scope.base, sub_scope);
5580 break :blk .{5584 break :blk .{
5581 .src = else_node,5585 .src = else_node,
...@@ -5746,8 +5750,10 @@ fn forExpr(...@@ -5746,8 +5750,10 @@ fn forExpr(
5746 break :blk &index_scope.base;5750 break :blk &index_scope.base;
5747 };5751 };
57485752
5749 loop_scope.break_count += 1;
5750 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);5753 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
5754 if (!then_scope.endsWithNoReturn()) {
5755 loop_scope.break_count += 1;
5756 }
5751 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);5757 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
57525758
5753 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);5759 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
...@@ -5758,11 +5764,14 @@ fn forExpr(...@@ -5758,11 +5764,14 @@ fn forExpr(
5758 src: Ast.Node.Index,5764 src: Ast.Node.Index,
5759 result: Zir.Inst.Ref,5765 result: Zir.Inst.Ref,
5760 } = if (else_node != 0) blk: {5766 } = if (else_node != 0) blk: {
5761 loop_scope.break_count += 1;
5762 const sub_scope = &else_scope.base;5767 const sub_scope = &else_scope.base;
5768 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
5769 if (!else_scope.endsWithNoReturn()) {
5770 loop_scope.break_count += 1;
5771 }
5763 break :blk .{5772 break :blk .{
5764 .src = else_node,5773 .src = else_node,
5765 .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node),5774 .result = else_result,
5766 };5775 };
5767 } else .{5776 } else .{
5768 .src = for_full.ast.then_expr,5777 .src = for_full.ast.then_expr,
src/codegen/llvm.zig+9-1
...@@ -1605,7 +1605,15 @@ pub const FuncGen = struct {...@@ -1605,7 +1605,15 @@ pub const FuncGen = struct {
1605 self.builder.positionBuilderAtEnd(loop_block);1605 self.builder.positionBuilderAtEnd(loop_block);
1606 try self.genBody(body);1606 try self.genBody(body);
16071607
1608 _ = self.builder.buildBr(loop_block);1608 // TODO instead of this logic, change AIR to have the property that
1609 // every block is guaranteed to end with a noreturn instruction.
1610 // Then we can simply rely on the fact that a repeat or break instruction
1611 // would have been emitted already. Also the main loop in genBody can
1612 // be while(true) instead of for(body), which will eliminate 1 branch on
1613 // a hot path.
1614 if (body.len == 0 or !self.air.typeOfIndex(body[body.len - 1]).isNoReturn()) {
1615 _ = self.builder.buildBr(loop_block);
1616 }
1609 return null;1617 return null;
1610 }1618 }
16111619
test/behavior.zig+14-8
...@@ -15,8 +15,12 @@ test {...@@ -15,8 +15,12 @@ test {
15 _ = @import("behavior/bugs/4769_b.zig");15 _ = @import("behavior/bugs/4769_b.zig");
16 _ = @import("behavior/bugs/6850.zig");16 _ = @import("behavior/bugs/6850.zig");
17 _ = @import("behavior/bugs/9584.zig");17 _ = @import("behavior/bugs/9584.zig");
18 _ = @import("behavior/call.zig");
18 _ = @import("behavior/cast.zig");19 _ = @import("behavior/cast.zig");
20 _ = @import("behavior/defer.zig");
21 _ = @import("behavior/enum.zig");
19 _ = @import("behavior/eval.zig");22 _ = @import("behavior/eval.zig");
23 _ = @import("behavior/for.zig");
20 _ = @import("behavior/generics.zig");24 _ = @import("behavior/generics.zig");
21 _ = @import("behavior/if.zig");25 _ = @import("behavior/if.zig");
22 _ = @import("behavior/math.zig");26 _ = @import("behavior/math.zig");
...@@ -24,11 +28,14 @@ test {...@@ -24,11 +28,14 @@ test {
24 _ = @import("behavior/pointers.zig");28 _ = @import("behavior/pointers.zig");
25 _ = @import("behavior/sizeof_and_typeof.zig");29 _ = @import("behavior/sizeof_and_typeof.zig");
26 _ = @import("behavior/struct.zig");30 _ = @import("behavior/struct.zig");
31 _ = @import("behavior/switch.zig");
27 _ = @import("behavior/this.zig");32 _ = @import("behavior/this.zig");
28 _ = @import("behavior/translate_c_macros.zig");33 _ = @import("behavior/translate_c_macros.zig");
34 _ = @import("behavior/underscore.zig");
29 _ = @import("behavior/union.zig");35 _ = @import("behavior/union.zig");
30 _ = @import("behavior/usingnamespace.zig");36 _ = @import("behavior/usingnamespace.zig");
31 _ = @import("behavior/widening.zig");37 _ = @import("behavior/widening.zig");
38 _ = @import("behavior/while.zig");
3239
33 if (builtin.zig_is_stage2) {40 if (builtin.zig_is_stage2) {
34 // When all comptime_memory.zig tests pass, #9646 can be closed.41 // When all comptime_memory.zig tests pass, #9646 can be closed.
...@@ -98,12 +105,11 @@ test {...@@ -98,12 +105,11 @@ test {
98 _ = @import("behavior/bugs/7250.zig");105 _ = @import("behavior/bugs/7250.zig");
99 _ = @import("behavior/byteswap.zig");106 _ = @import("behavior/byteswap.zig");
100 _ = @import("behavior/byval_arg_var.zig");107 _ = @import("behavior/byval_arg_var.zig");
101 _ = @import("behavior/call.zig");108 _ = @import("behavior/call_stage1.zig");
102 _ = @import("behavior/cast_stage1.zig");109 _ = @import("behavior/cast_stage1.zig");
103 _ = @import("behavior/const_slice_child.zig");110 _ = @import("behavior/const_slice_child.zig");
104 _ = @import("behavior/defer.zig");111 _ = @import("behavior/defer_stage1.zig");
105 _ = @import("behavior/enum.zig");112 _ = @import("behavior/enum_stage1.zig");
106 _ = @import("behavior/enum_with_members.zig");
107 _ = @import("behavior/error.zig");113 _ = @import("behavior/error.zig");
108 _ = @import("behavior/eval_stage1.zig");114 _ = @import("behavior/eval_stage1.zig");
109 _ = @import("behavior/field_parent_ptr.zig");115 _ = @import("behavior/field_parent_ptr.zig");
...@@ -111,7 +117,7 @@ test {...@@ -111,7 +117,7 @@ test {
111 _ = @import("behavior/fn.zig");117 _ = @import("behavior/fn.zig");
112 _ = @import("behavior/fn_in_struct_in_comptime.zig");118 _ = @import("behavior/fn_in_struct_in_comptime.zig");
113 _ = @import("behavior/fn_delegation.zig");119 _ = @import("behavior/fn_delegation.zig");
114 _ = @import("behavior/for.zig");120 _ = @import("behavior/for_stage1.zig");
115 _ = @import("behavior/generics_stage1.zig");121 _ = @import("behavior/generics_stage1.zig");
116 _ = @import("behavior/hasdecl.zig");122 _ = @import("behavior/hasdecl.zig");
117 _ = @import("behavior/hasfield.zig");123 _ = @import("behavior/hasfield.zig");
...@@ -143,7 +149,7 @@ test {...@@ -143,7 +149,7 @@ test {
143 _ = @import("behavior/struct_stage1.zig");149 _ = @import("behavior/struct_stage1.zig");
144 _ = @import("behavior/struct_contains_null_ptr_itself.zig");150 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
145 _ = @import("behavior/struct_contains_slice_of_itself.zig");151 _ = @import("behavior/struct_contains_slice_of_itself.zig");
146 _ = @import("behavior/switch.zig");152 _ = @import("behavior/switch_stage1.zig");
147 _ = @import("behavior/switch_prong_err_enum.zig");153 _ = @import("behavior/switch_prong_err_enum.zig");
148 _ = @import("behavior/switch_prong_implicit_cast.zig");154 _ = @import("behavior/switch_prong_implicit_cast.zig");
149 _ = @import("behavior/truncate.zig");155 _ = @import("behavior/truncate.zig");
...@@ -153,8 +159,8 @@ test {...@@ -153,8 +159,8 @@ test {
153 _ = @import("behavior/type_info.zig");159 _ = @import("behavior/type_info.zig");
154 _ = @import("behavior/typename.zig");160 _ = @import("behavior/typename.zig");
155 _ = @import("behavior/undefined.zig");161 _ = @import("behavior/undefined.zig");
156 _ = @import("behavior/underscore.zig");
157 _ = @import("behavior/union_stage1.zig");162 _ = @import("behavior/union_stage1.zig");
163 _ = @import("behavior/union_with_members.zig");
158 _ = @import("behavior/usingnamespace_stage1.zig");164 _ = @import("behavior/usingnamespace_stage1.zig");
159 _ = @import("behavior/var_args.zig");165 _ = @import("behavior/var_args.zig");
160 _ = @import("behavior/vector.zig");166 _ = @import("behavior/vector.zig");
...@@ -162,7 +168,7 @@ test {...@@ -162,7 +168,7 @@ test {
162 if (builtin.target.cpu.arch == .wasm32) {168 if (builtin.target.cpu.arch == .wasm32) {
163 _ = @import("behavior/wasm.zig");169 _ = @import("behavior/wasm.zig");
164 }170 }
165 _ = @import("behavior/while.zig");171 _ = @import("behavior/while_stage1.zig");
166 _ = @import("behavior/src.zig");172 _ = @import("behavior/src.zig");
167 _ = @import("behavior/translate_c_macros_stage1.zig");173 _ = @import("behavior/translate_c_macros_stage1.zig");
168 }174 }
test/behavior/call.zig-71
...@@ -1,74 +1,3 @@...@@ -1,74 +1,3 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
4
5test "basic invocations" {
6 const foo = struct {
7 fn foo() i32 {
8 return 1234;
9 }
10 }.foo;
11 try expect(@call(.{}, foo, .{}) == 1234);
12 comptime {
13 // modifiers that allow comptime calls
14 try expect(@call(.{}, foo, .{}) == 1234);
15 try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234);
16 try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234);
17 try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
18 }
19 {
20 // comptime call without comptime keyword
21 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
22 comptime try expect(result);
23 }
24 {
25 // call of non comptime-known function
26 var alias_foo = foo;
27 try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
28 try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
29 try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
30 }
31}
32
33test "tuple parameters" {
34 const add = struct {
35 fn add(a: i32, b: i32) i32 {
36 return a + b;
37 }
38 }.add;
39 var a: i32 = 12;
40 var b: i32 = 34;
41 try expect(@call(.{}, add, .{ a, 34 }) == 46);
42 try expect(@call(.{}, add, .{ 12, b }) == 46);
43 try expect(@call(.{}, add, .{ a, b }) == 46);
44 try expect(@call(.{}, add, .{ 12, 34 }) == 46);
45 comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);
46 {
47 const separate_args0 = .{ a, b };
48 const separate_args1 = .{ a, 34 };
49 const separate_args2 = .{ 12, 34 };
50 const separate_args3 = .{ 12, b };
51 try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46);
52 try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46);
53 try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46);
54 try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46);
55 }
56}
57
58test "comptime call with bound function as parameter" {
59 const S = struct {
60 fn ReturnType(func: anytype) type {
61 return switch (@typeInfo(@TypeOf(func))) {
62 .BoundFn => |info| info,
63 else => unreachable,
64 }.return_type orelse void;
65 }
66
67 fn call_me_maybe() ?i32 {
68 return 123;
69 }
70 };
71
72 var inst: S = undefined;
73 try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
74}
test/behavior/call_stage1.zig created+74
...@@ -0,0 +1,74 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4
5test "basic invocations" {
6 const foo = struct {
7 fn foo() i32 {
8 return 1234;
9 }
10 }.foo;
11 try expect(@call(.{}, foo, .{}) == 1234);
12 comptime {
13 // modifiers that allow comptime calls
14 try expect(@call(.{}, foo, .{}) == 1234);
15 try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234);
16 try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234);
17 try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
18 }
19 {
20 // comptime call without comptime keyword
21 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
22 comptime try expect(result);
23 }
24 {
25 // call of non comptime-known function
26 var alias_foo = foo;
27 try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
28 try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
29 try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
30 }
31}
32
33test "tuple parameters" {
34 const add = struct {
35 fn add(a: i32, b: i32) i32 {
36 return a + b;
37 }
38 }.add;
39 var a: i32 = 12;
40 var b: i32 = 34;
41 try expect(@call(.{}, add, .{ a, 34 }) == 46);
42 try expect(@call(.{}, add, .{ 12, b }) == 46);
43 try expect(@call(.{}, add, .{ a, b }) == 46);
44 try expect(@call(.{}, add, .{ 12, 34 }) == 46);
45 comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);
46 {
47 const separate_args0 = .{ a, b };
48 const separate_args1 = .{ a, 34 };
49 const separate_args2 = .{ 12, 34 };
50 const separate_args3 = .{ 12, b };
51 try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46);
52 try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46);
53 try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46);
54 try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46);
55 }
56}
57
58test "comptime call with bound function as parameter" {
59 const S = struct {
60 fn ReturnType(func: anytype) type {
61 return switch (@typeInfo(@TypeOf(func))) {
62 .BoundFn => |info| info,
63 else => unreachable,
64 }.return_type orelse void;
65 }
66
67 fn call_me_maybe() ?i32 {
68 return 123;
69 }
70 };
71
72 var inst: S = undefined;
73 try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
74}
test/behavior/cast.zig+49
...@@ -16,3 +16,52 @@ test "integer literal to pointer cast" {...@@ -16,3 +16,52 @@ test "integer literal to pointer cast" {
16 const vga_mem = @intToPtr(*u16, 0xB8000);16 const vga_mem = @intToPtr(*u16, 0xB8000);
17 try expect(@ptrToInt(vga_mem) == 0xB8000);17 try expect(@ptrToInt(vga_mem) == 0xB8000);
18}18}
19
20test "peer type resolution: ?T and T" {
21 try expect(peerTypeTAndOptionalT(true, false).? == 0);
22 try expect(peerTypeTAndOptionalT(false, false).? == 3);
23 comptime {
24 try expect(peerTypeTAndOptionalT(true, false).? == 0);
25 try expect(peerTypeTAndOptionalT(false, false).? == 3);
26 }
27}
28fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
29 if (c) {
30 return if (b) null else @as(usize, 0);
31 }
32
33 return @as(usize, 3);
34}
35
36test "resolve undefined with integer" {
37 try testResolveUndefWithInt(true, 1234);
38 comptime try testResolveUndefWithInt(true, 1234);
39}
40fn testResolveUndefWithInt(b: bool, x: i32) !void {
41 const value = if (b) x else undefined;
42 if (b) {
43 try expect(value == x);
44 }
45}
46
47test "@intCast i32 to u7" {
48 var x: u128 = maxInt(u128);
49 var y: i32 = 120;
50 var z = x >> @intCast(u7, y);
51 try expect(z == 0xff);
52}
53
54test "@intCast to comptime_int" {
55 try expect(@intCast(comptime_int, 0) == 0);
56}
57
58test "implicit cast comptime numbers to any type when the value fits" {
59 const a: u64 = 255;
60 var b: u8 = a;
61 try expect(b == 255);
62}
63
64test "implicit cast comptime_int to comptime_float" {
65 comptime try expect(@as(comptime_float, 10) == @as(f32, 10));
66 try expect(2 == 2.0);
67}
test/behavior/cast_stage1.zig+2-58
...@@ -121,22 +121,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {...@@ -121,22 +121,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
121 return null;121 return null;
122}122}
123123
124test "peer type resolution: ?T and T" {
125 try expect(peerTypeTAndOptionalT(true, false).? == 0);
126 try expect(peerTypeTAndOptionalT(false, false).? == 3);
127 comptime {
128 try expect(peerTypeTAndOptionalT(true, false).? == 0);
129 try expect(peerTypeTAndOptionalT(false, false).? == 3);
130 }
131}
132fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
133 if (c) {
134 return if (b) null else @as(usize, 0);
135 }
136
137 return @as(usize, 3);
138}
139
140test "peer type resolution: [0]u8 and []const u8" {124test "peer type resolution: [0]u8 and []const u8" {
141 try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);125 try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
142 try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);126 try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
...@@ -203,17 +187,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {...@@ -203,17 +187,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
203 return slice[0..1];187 return slice[0..1];
204}188}
205189
206test "resolve undefined with integer" {
207 try testResolveUndefWithInt(true, 1234);
208 comptime try testResolveUndefWithInt(true, 1234);
209}
210fn testResolveUndefWithInt(b: bool, x: i32) !void {
211 const value = if (b) x else undefined;
212 if (b) {
213 try expect(value == x);
214 }
215}
216
217test "implicit cast from &const [N]T to []const T" {190test "implicit cast from &const [N]T to []const T" {
218 try testCastConstArrayRefToConstSlice();191 try testCastConstArrayRefToConstSlice();
219 comptime try testCastConstArrayRefToConstSlice();192 comptime try testCastConstArrayRefToConstSlice();
...@@ -424,13 +397,6 @@ test "comptime_int @intToFloat" {...@@ -424,13 +397,6 @@ test "comptime_int @intToFloat" {
424 }397 }
425}398}
426399
427test "@intCast i32 to u7" {
428 var x: u128 = maxInt(u128);
429 var y: i32 = 120;
430 var z = x >> @intCast(u7, y);
431 try expect(z == 0xff);
432}
433
434test "@floatCast cast down" {400test "@floatCast cast down" {
435 {401 {
436 var double: f64 = 0.001534;402 var double: f64 = 0.001534;
...@@ -533,20 +499,8 @@ test "implicit ptr to *c_void" {...@@ -533,20 +499,8 @@ test "implicit ptr to *c_void" {
533 try expect(c.* == 1);499 try expect(c.* == 1);
534}500}
535501
536test "@intCast to comptime_int" {
537 try expect(@intCast(comptime_int, 0) == 0);
538}
539
540test "implicit cast comptime numbers to any type when the value fits" {
541 const a: u64 = 255;
542 var b: u8 = a;
543 try expect(b == 255);
544}
545
546test "@intToEnum passed a comptime_int to an enum with one item" {502test "@intToEnum passed a comptime_int to an enum with one item" {
547 const E = enum {503 const E = enum { A };
548 A,
549 };
550 const x = @intToEnum(E, 0);504 const x = @intToEnum(E, 0);
551 try expect(x == E.A);505 try expect(x == E.A);
552}506}
...@@ -599,11 +553,6 @@ test "peer type resolution: unreachable, error set, unreachable" {...@@ -599,11 +553,6 @@ test "peer type resolution: unreachable, error set, unreachable" {
599 try expect(transformed_err == error.SystemResources);553 try expect(transformed_err == error.SystemResources);
600}554}
601555
602test "implicit cast comptime_int to comptime_float" {
603 comptime try expect(@as(comptime_float, 10) == @as(f32, 10));
604 try expect(2 == 2.0);
605}
606
607test "implicit cast *[0]T to E![]const u8" {556test "implicit cast *[0]T to E![]const u8" {
608 var x = @as(anyerror![]const u8, &[0]u8{});557 var x = @as(anyerror![]const u8, &[0]u8{});
609 try expect((x catch unreachable).len == 0);558 try expect((x catch unreachable).len == 0);
...@@ -645,12 +594,7 @@ test "*const [N]null u8 to ?[]const u8" {...@@ -645,12 +594,7 @@ test "*const [N]null u8 to ?[]const u8" {
645594
646test "peer resolution of string literals" {595test "peer resolution of string literals" {
647 const S = struct {596 const S = struct {
648 const E = enum {597 const E = enum { a, b, c, d };
649 a,
650 b,
651 c,
652 d,
653 };
654598
655 fn doTheTest(e: E) !void {599 fn doTheTest(e: E) !void {
656 const cmd = switch (e) {600 const cmd = switch (e) {
test/behavior/const_slice_child.zig+1-5
...@@ -6,11 +6,7 @@ const expect = testing.expect;...@@ -6,11 +6,7 @@ const expect = testing.expect;
6var argv: [*]const [*]const u8 = undefined;6var argv: [*]const [*]const u8 = undefined;
77
8test "const slice child" {8test "const slice child" {
9 const strs = [_][*]const u8{9 const strs = [_][*]const u8{ "one", "two", "three" };
10 "one",
11 "two",
12 "three",
13 };
14 argv = &strs;10 argv = &strs;
15 try bar(strs.len);11 try bar(strs.len);
16}12}
test/behavior/defer.zig-110
...@@ -2,113 +2,3 @@ const std = @import("std");...@@ -2,113 +2,3 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
4const expectError = std.testing.expectError;4const expectError = std.testing.expectError;
5
6var result: [3]u8 = undefined;
7var index: usize = undefined;
8
9fn runSomeErrorDefers(x: bool) !bool {
10 index = 0;
11 defer {
12 result[index] = 'a';
13 index += 1;
14 }
15 errdefer {
16 result[index] = 'b';
17 index += 1;
18 }
19 defer {
20 result[index] = 'c';
21 index += 1;
22 }
23 return if (x) x else error.FalseNotAllowed;
24}
25
26test "mixing normal and error defers" {
27 try expect(runSomeErrorDefers(true) catch unreachable);
28 try expect(result[0] == 'c');
29 try expect(result[1] == 'a');
30
31 const ok = runSomeErrorDefers(false) catch |err| x: {
32 try expect(err == error.FalseNotAllowed);
33 break :x true;
34 };
35 try expect(ok);
36 try expect(result[0] == 'c');
37 try expect(result[1] == 'b');
38 try expect(result[2] == 'a');
39}
40
41test "break and continue inside loop inside defer expression" {
42 testBreakContInDefer(10);
43 comptime testBreakContInDefer(10);
44}
45
46fn testBreakContInDefer(x: usize) void {
47 defer {
48 var i: usize = 0;
49 while (i < x) : (i += 1) {
50 if (i < 5) continue;
51 if (i == 5) break;
52 }
53 expect(i == 5) catch @panic("test failure");
54 }
55}
56
57test "defer and labeled break" {
58 var i = @as(usize, 0);
59
60 blk: {
61 defer i += 1;
62 break :blk;
63 }
64
65 try expect(i == 1);
66}
67
68test "errdefer does not apply to fn inside fn" {
69 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
70}
71
72fn testNestedFnErrDefer() anyerror!void {
73 var a: i32 = 0;
74 errdefer a += 1;
75 const S = struct {
76 fn baz() anyerror {
77 return error.Bad;
78 }
79 };
80 return S.baz();
81}
82
83test "return variable while defer expression in scope to modify it" {
84 const S = struct {
85 fn doTheTest() !void {
86 try expect(notNull().? == 1);
87 }
88
89 fn notNull() ?u8 {
90 var res: ?u8 = 1;
91 defer res = null;
92 return res;
93 }
94 };
95
96 try S.doTheTest();
97 comptime try S.doTheTest();
98}
99
100test "errdefer with payload" {
101 const S = struct {
102 fn foo() !i32 {
103 errdefer |a| {
104 expectEqual(error.One, a) catch @panic("test failure");
105 }
106 return error.One;
107 }
108 fn doTheTest() !void {
109 try expectError(error.One, foo());
110 }
111 };
112 try S.doTheTest();
113 comptime try S.doTheTest();
114}
test/behavior/defer_stage1.zig created+114
...@@ -0,0 +1,114 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4const expectError = std.testing.expectError;
5
6var result: [3]u8 = undefined;
7var index: usize = undefined;
8
9fn runSomeErrorDefers(x: bool) !bool {
10 index = 0;
11 defer {
12 result[index] = 'a';
13 index += 1;
14 }
15 errdefer {
16 result[index] = 'b';
17 index += 1;
18 }
19 defer {
20 result[index] = 'c';
21 index += 1;
22 }
23 return if (x) x else error.FalseNotAllowed;
24}
25
26test "mixing normal and error defers" {
27 try expect(runSomeErrorDefers(true) catch unreachable);
28 try expect(result[0] == 'c');
29 try expect(result[1] == 'a');
30
31 const ok = runSomeErrorDefers(false) catch |err| x: {
32 try expect(err == error.FalseNotAllowed);
33 break :x true;
34 };
35 try expect(ok);
36 try expect(result[0] == 'c');
37 try expect(result[1] == 'b');
38 try expect(result[2] == 'a');
39}
40
41test "break and continue inside loop inside defer expression" {
42 testBreakContInDefer(10);
43 comptime testBreakContInDefer(10);
44}
45
46fn testBreakContInDefer(x: usize) void {
47 defer {
48 var i: usize = 0;
49 while (i < x) : (i += 1) {
50 if (i < 5) continue;
51 if (i == 5) break;
52 }
53 expect(i == 5) catch @panic("test failure");
54 }
55}
56
57test "defer and labeled break" {
58 var i = @as(usize, 0);
59
60 blk: {
61 defer i += 1;
62 break :blk;
63 }
64
65 try expect(i == 1);
66}
67
68test "errdefer does not apply to fn inside fn" {
69 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
70}
71
72fn testNestedFnErrDefer() anyerror!void {
73 var a: i32 = 0;
74 errdefer a += 1;
75 const S = struct {
76 fn baz() anyerror {
77 return error.Bad;
78 }
79 };
80 return S.baz();
81}
82
83test "return variable while defer expression in scope to modify it" {
84 const S = struct {
85 fn doTheTest() !void {
86 try expect(notNull().? == 1);
87 }
88
89 fn notNull() ?u8 {
90 var res: ?u8 = 1;
91 defer res = null;
92 return res;
93 }
94 };
95
96 try S.doTheTest();
97 comptime try S.doTheTest();
98}
99
100test "errdefer with payload" {
101 const S = struct {
102 fn foo() !i32 {
103 errdefer |a| {
104 expectEqual(error.One, a) catch @panic("test failure");
105 }
106 return error.One;
107 }
108 fn doTheTest() !void {
109 try expectError(error.One, foo());
110 }
111 };
112 try S.doTheTest();
113 comptime try S.doTheTest();
114}
test/behavior/enum.zig+29-494
...@@ -1,133 +1,7 @@...@@ -1,133 +1,7 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const mem = @import("std").mem;2const expect = std.testing.expect;
3const Tag = @import("std").meta.Tag;3const mem = std.mem;
44const Tag = std.meta.Tag;
5test "non-exhaustive enum" {
6 const S = struct {
7 const E = enum(u8) {
8 a,
9 b,
10 _,
11 };
12 fn doTheTest(y: u8) !void {
13 var e: E = .b;
14 try expect(switch (e) {
15 .a => false,
16 .b => true,
17 _ => false,
18 });
19 e = @intToEnum(E, 12);
20 try expect(switch (e) {
21 .a => false,
22 .b => false,
23 _ => true,
24 });
25
26 try expect(switch (e) {
27 .a => false,
28 .b => false,
29 else => true,
30 });
31 e = .b;
32 try expect(switch (e) {
33 .a => false,
34 else => true,
35 });
36
37 try expect(@typeInfo(E).Enum.fields.len == 2);
38 e = @intToEnum(E, 12);
39 try expect(@enumToInt(e) == 12);
40 e = @intToEnum(E, y);
41 try expect(@enumToInt(e) == 52);
42 try expect(@typeInfo(E).Enum.is_exhaustive == false);
43 }
44 };
45 try S.doTheTest(52);
46 comptime try S.doTheTest(52);
47}
48
49test "empty non-exhaustive enum" {
50 const S = struct {
51 const E = enum(u8) {
52 _,
53 };
54 fn doTheTest(y: u8) !void {
55 var e = @intToEnum(E, y);
56 try expect(switch (e) {
57 _ => true,
58 });
59 try expect(@enumToInt(e) == y);
60
61 try expect(@typeInfo(E).Enum.fields.len == 0);
62 try expect(@typeInfo(E).Enum.is_exhaustive == false);
63 }
64 };
65 try S.doTheTest(42);
66 comptime try S.doTheTest(42);
67}
68
69test "single field non-exhaustive enum" {
70 const S = struct {
71 const E = enum(u8) {
72 a,
73 _,
74 };
75 fn doTheTest(y: u8) !void {
76 var e: E = .a;
77 try expect(switch (e) {
78 .a => true,
79 _ => false,
80 });
81 e = @intToEnum(E, 12);
82 try expect(switch (e) {
83 .a => false,
84 _ => true,
85 });
86
87 try expect(switch (e) {
88 .a => false,
89 else => true,
90 });
91 e = .a;
92 try expect(switch (e) {
93 .a => true,
94 else => false,
95 });
96
97 try expect(@enumToInt(@intToEnum(E, y)) == y);
98 try expect(@typeInfo(E).Enum.fields.len == 1);
99 try expect(@typeInfo(E).Enum.is_exhaustive == false);
100 }
101 };
102 try S.doTheTest(23);
103 comptime try S.doTheTest(23);
104}
105
106test "enum type" {
107 const foo1 = Foo{ .One = 13 };
108 const foo2 = Foo{
109 .Two = Point{
110 .x = 1234,
111 .y = 5678,
112 },
113 };
114 try expect(foo1.One == 13);
115 try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
116 const bar = Bar.B;
117
118 try expect(bar == Bar.B);
119 try expect(@typeInfo(Foo).Union.fields.len == 3);
120 try expect(@typeInfo(Bar).Enum.fields.len == 4);
121 try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid));
122 try expect(@sizeOf(Bar) == 1);
123}
124
125test "enum as return value" {
126 switch (returnAnInt(13)) {
127 Foo.One => |value| try expect(value == 13),
128 else => unreachable,
129 }
130}
1315
132const Point = struct {6const Point = struct {
133 x: u64,7 x: u64,
...@@ -153,13 +27,6 @@ fn returnAnInt(x: i32) Foo {...@@ -153,13 +27,6 @@ fn returnAnInt(x: i32) Foo {
153 return Foo{ .One = x };27 return Foo{ .One = x };
154}28}
15529
156test "constant enum with payload" {
157 var empty = AnEnumWithPayload{ .Empty = {} };
158 var full = AnEnumWithPayload{ .Full = 13 };
159 shouldBeEmpty(empty);
160 shouldBeNotEmpty(full);
161}
162
163fn shouldBeEmpty(x: AnEnumWithPayload) void {30fn shouldBeEmpty(x: AnEnumWithPayload) void {
164 switch (x) {31 switch (x) {
165 AnEnumWithPayload.Empty => {},32 AnEnumWithPayload.Empty => {},
...@@ -179,72 +46,19 @@ const AnEnumWithPayload = union(enum) {...@@ -179,72 +46,19 @@ const AnEnumWithPayload = union(enum) {
179 Full: i32,46 Full: i32,
180};47};
18148
182const Number = enum {49const Number = enum { Zero, One, Two, Three, Four };
183 Zero,
184 One,
185 Two,
186 Three,
187 Four,
188};
189
190test "enum to int" {
191 try shouldEqual(Number.Zero, 0);
192 try shouldEqual(Number.One, 1);
193 try shouldEqual(Number.Two, 2);
194 try shouldEqual(Number.Three, 3);
195 try shouldEqual(Number.Four, 4);
196}
19750
198fn shouldEqual(n: Number, expected: u3) !void {51fn shouldEqual(n: Number, expected: u3) !void {
199 try expect(@enumToInt(n) == expected);52 try expect(@enumToInt(n) == expected);
200}53}
20154
202test "int to enum" {
203 try testIntToEnumEval(3);
204}
205fn testIntToEnumEval(x: i32) !void {
206 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
207}
208const IntToEnumNumber = enum {
209 Zero,
210 One,
211 Two,
212 Three,
213 Four,
214};
215
216test "@tagName" {
217 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
218 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
219}
220
221test "@tagName non-exhaustive enum" {
222 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
223 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
224}
225
226fn testEnumTagNameBare(n: anytype) []const u8 {55fn testEnumTagNameBare(n: anytype) []const u8 {
227 return @tagName(n);56 return @tagName(n);
228}57}
22958
230const BareNumber = enum {59const BareNumber = enum { One, Two, Three };
231 One,
232 Two,
233 Three,
234};
235
236const NonExhaustive = enum(u8) {
237 A,
238 B,
239 _,
240};
24160
242test "enum alignment" {61const NonExhaustive = enum(u8) { A, B, _ };
243 comptime {
244 try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
245 try expect(@alignOf(AlignTestEnum) >= @alignOf(u64));
246 }
247}
24862
249const AlignTestEnum = union(enum) {63const AlignTestEnum = union(enum) {
250 A: [9]u8,64 A: [9]u8,
...@@ -776,67 +590,12 @@ const ValueCount257 = enum {...@@ -776,67 +590,12 @@ const ValueCount257 = enum {
776 I256,590 I256,
777};591};
778592
779test "enum sizes" {593const Small2 = enum(u2) { One, Two };
780 comptime {594const Small = enum(u2) { One, Two, Three, Four };
781 try expect(@sizeOf(ValueCount1) == 0);
782 try expect(@sizeOf(ValueCount2) == 1);
783 try expect(@sizeOf(ValueCount256) == 1);
784 try expect(@sizeOf(ValueCount257) == 2);
785 }
786}
787595
788const Small2 = enum(u2) {596const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
789 One,597const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
790 Two,598const C = enum(u2) { One4, Two4, Three4, Four4 };
791};
792const Small = enum(u2) {
793 One,
794 Two,
795 Three,
796 Four,
797};
798
799test "set enum tag type" {
800 {
801 var x = Small.One;
802 x = Small.Two;
803 comptime try expect(Tag(Small) == u2);
804 }
805 {
806 var x = Small2.One;
807 x = Small2.Two;
808 comptime try expect(Tag(Small2) == u2);
809 }
810}
811
812const A = enum(u3) {
813 One,
814 Two,
815 Three,
816 Four,
817 One2,
818 Two2,
819 Three2,
820 Four2,
821};
822
823const B = enum(u3) {
824 One3,
825 Two3,
826 Three3,
827 Four3,
828 One23,
829 Two23,
830 Three23,
831 Four23,
832};
833
834const C = enum(u2) {
835 One4,
836 Two4,
837 Three4,
838 Four4,
839};
840599
841const BitFieldOfEnums = packed struct {600const BitFieldOfEnums = packed struct {
842 a: A,601 a: A,
...@@ -850,21 +609,6 @@ const bit_field_1 = BitFieldOfEnums{...@@ -850,21 +609,6 @@ const bit_field_1 = BitFieldOfEnums{
850 .c = C.Four4,609 .c = C.Four4,
851};610};
852611
853test "bit field access with enum fields" {
854 var data = bit_field_1;
855 try expect(getA(&data) == A.Two);
856 try expect(getB(&data) == B.Three3);
857 try expect(getC(&data) == C.Four4);
858 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
859
860 data.b = B.Four3;
861 try expect(data.b == B.Four3);
862
863 data.a = A.Three;
864 try expect(data.a == A.Three);
865 try expect(data.b == B.Four3);
866}
867
868fn getA(data: *const BitFieldOfEnums) A {612fn getA(data: *const BitFieldOfEnums) A {
869 return data.a;613 return data.a;
870}614}
...@@ -877,15 +621,6 @@ fn getC(data: *const BitFieldOfEnums) C {...@@ -877,15 +621,6 @@ fn getC(data: *const BitFieldOfEnums) C {
877 return data.c;621 return data.c;
878}622}
879623
880test "casting enum to its tag type" {
881 try testCastEnumTag(Small2.Two);
882 comptime try testCastEnumTag(Small2.Two);
883}
884
885fn testCastEnumTag(value: Small2) !void {
886 try expect(@enumToInt(value) == 1);
887}
888
889const MultipleChoice = enum(u32) {624const MultipleChoice = enum(u32) {
890 A = 20,625 A = 20,
891 B = 40,626 B = 40,
...@@ -893,21 +628,6 @@ const MultipleChoice = enum(u32) {...@@ -893,21 +628,6 @@ const MultipleChoice = enum(u32) {
893 D = 1000,628 D = 1000,
894};629};
895630
896test "enum with specified tag values" {
897 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
898 comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
899}
900
901fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
902 try expect(@enumToInt(x) == 60);
903 try expect(1234 == switch (x) {
904 MultipleChoice.A => 1,
905 MultipleChoice.B => 2,
906 MultipleChoice.C => @as(u32, 1234),
907 MultipleChoice.D => 4,
908 });
909}
910
911const MultipleChoice2 = enum(u32) {631const MultipleChoice2 = enum(u32) {
912 Unspecified1,632 Unspecified1,
913 A = 20,633 A = 20,
...@@ -920,34 +640,7 @@ const MultipleChoice2 = enum(u32) {...@@ -920,34 +640,7 @@ const MultipleChoice2 = enum(u32) {
920 Unspecified5,640 Unspecified5,
921};641};
922642
923test "enum with specified and unspecified tag values" {643const EnumWithOneMember = enum { Eof };
924 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
925 comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
926}
927
928fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
929 try expect(@enumToInt(x) == 1000);
930 try expect(1234 == switch (x) {
931 MultipleChoice2.A => 1,
932 MultipleChoice2.B => 2,
933 MultipleChoice2.C => 3,
934 MultipleChoice2.D => @as(u32, 1234),
935 MultipleChoice2.Unspecified1 => 5,
936 MultipleChoice2.Unspecified2 => 6,
937 MultipleChoice2.Unspecified3 => 7,
938 MultipleChoice2.Unspecified4 => 8,
939 MultipleChoice2.Unspecified5 => 9,
940 });
941}
942
943test "cast integer literal to enum" {
944 try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
945 try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
946}
947
948const EnumWithOneMember = enum {
949 Eof,
950};
951644
952fn doALoopThing(id: EnumWithOneMember) void {645fn doALoopThing(id: EnumWithOneMember) void {
953 while (true) {646 while (true) {
...@@ -958,20 +651,7 @@ fn doALoopThing(id: EnumWithOneMember) void {...@@ -958,20 +651,7 @@ fn doALoopThing(id: EnumWithOneMember) void {
958 }651 }
959}652}
960653
961test "comparison operator on enum with one member is comptime known" {654const State = enum { Start };
962 doALoopThing(EnumWithOneMember.Eof);
963}
964
965const State = enum {
966 Start,
967};
968test "switch on enum with one member is comptime known" {
969 var state = State.Start;
970 switch (state) {
971 State.Start => return,
972 }
973 @compileError("analysis should not reach here");
974}
975655
976const EnumWithTagValues = enum(u4) {656const EnumWithTagValues = enum(u4) {
977 A = 1 << 0,657 A = 1 << 0,
...@@ -979,24 +659,22 @@ const EnumWithTagValues = enum(u4) {...@@ -979,24 +659,22 @@ const EnumWithTagValues = enum(u4) {
979 C = 1 << 2,659 C = 1 << 2,
980 D = 1 << 3,660 D = 1 << 3,
981};661};
982test "enum with tag values don't require parens" {
983 try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
984}
985662
986test "enum with 1 field but explicit tag type should still have the tag type" {663test "enum to int" {
987 const Enum = enum(u8) {664 try shouldEqual(Number.Zero, 0);
988 B = 2,665 try shouldEqual(Number.One, 1);
989 };666 try shouldEqual(Number.Two, 2);
990 comptime try expect(@sizeOf(Enum) == @sizeOf(u8));667 try shouldEqual(Number.Three, 3);
668 try shouldEqual(Number.Four, 4);
991}669}
992670
993test "tag name with assigned enum values" {671test "enum sizes" {
994 const LocalFoo = enum(u8) {672 comptime {
995 A = 1,673 try expect(@sizeOf(ValueCount1) == 0);
996 B = 0,674 try expect(@sizeOf(ValueCount2) == 1);
997 };675 try expect(@sizeOf(ValueCount256) == 1);
998 var b = LocalFoo.B;676 try expect(@sizeOf(ValueCount257) == 2);
999 try expect(mem.eql(u8, @tagName(b), "B"));677 }
1000}678}
1001679
1002test "enum literal equality" {680test "enum literal equality" {
...@@ -1009,11 +687,7 @@ test "enum literal equality" {...@@ -1009,11 +687,7 @@ test "enum literal equality" {
1009}687}
1010688
1011test "enum literal cast to enum" {689test "enum literal cast to enum" {
1012 const Color = enum {690 const Color = enum { Auto, Off, On };
1013 Auto,
1014 Off,
1015 On,
1016 };
1017691
1018 var color1: Color = .Auto;692 var color1: Color = .Auto;
1019 var color2 = Color.Auto;693 var color2 = Color.Auto;
...@@ -1021,147 +695,8 @@ test "enum literal cast to enum" {...@@ -1021,147 +695,8 @@ test "enum literal cast to enum" {
1021}695}
1022696
1023test "peer type resolution with enum literal" {697test "peer type resolution with enum literal" {
1024 const Items = enum {698 const Items = enum { one, two };
1025 one,
1026 two,
1027 };
1028699
1029 try expect(Items.two == .two);700 try expect(Items.two == .two);
1030 try expect(.two == Items.two);701 try expect(.two == Items.two);
1031}702}
1032
1033test "enum literal in array literal" {
1034 const Items = enum {
1035 one,
1036 two,
1037 };
1038
1039 const array = [_]Items{
1040 .one,
1041 .two,
1042 };
1043
1044 try expect(array[0] == .one);
1045 try expect(array[1] == .two);
1046}
1047
1048test "signed integer as enum tag" {
1049 const SignedEnum = enum(i2) {
1050 A0 = -1,
1051 A1 = 0,
1052 A2 = 1,
1053 };
1054
1055 try expect(@enumToInt(SignedEnum.A0) == -1);
1056 try expect(@enumToInt(SignedEnum.A1) == 0);
1057 try expect(@enumToInt(SignedEnum.A2) == 1);
1058}
1059
1060test "enum value allocation" {
1061 const LargeEnum = enum(u32) {
1062 A0 = 0x80000000,
1063 A1,
1064 A2,
1065 };
1066
1067 try expect(@enumToInt(LargeEnum.A0) == 0x80000000);
1068 try expect(@enumToInt(LargeEnum.A1) == 0x80000001);
1069 try expect(@enumToInt(LargeEnum.A2) == 0x80000002);
1070}
1071
1072test "enum literal casting to tagged union" {
1073 const Arch = union(enum) {
1074 x86_64,
1075 arm: Arm32,
1076
1077 const Arm32 = enum {
1078 v8_5a,
1079 v8_4a,
1080 };
1081 };
1082
1083 var t = true;
1084 var x: Arch = .x86_64;
1085 var y = if (t) x else .x86_64;
1086 switch (y) {
1087 .x86_64 => {},
1088 else => @panic("fail"),
1089 }
1090}
1091
1092test "enum with one member and custom tag type" {
1093 const E = enum(u2) {
1094 One,
1095 };
1096 try expect(@enumToInt(E.One) == 0);
1097 const E2 = enum(u2) {
1098 One = 2,
1099 };
1100 try expect(@enumToInt(E2.One) == 2);
1101}
1102
1103test "enum literal casting to optional" {
1104 var bar: ?Bar = undefined;
1105 bar = .B;
1106
1107 try expect(bar.? == Bar.B);
1108}
1109
1110test "enum literal casting to error union with payload enum" {
1111 var bar: error{B}!Bar = undefined;
1112 bar = .B; // should never cast to the error set
1113
1114 try expect((try bar) == Bar.B);
1115}
1116
1117test "enum with one member and u1 tag type @enumToInt" {
1118 const Enum = enum(u1) {
1119 Test,
1120 };
1121 try expect(@enumToInt(Enum.Test) == 0);
1122}
1123
1124test "enum with comptime_int tag type" {
1125 const Enum = enum(comptime_int) {
1126 One = 3,
1127 Two = 2,
1128 Three = 1,
1129 };
1130 comptime try expect(Tag(Enum) == comptime_int);
1131}
1132
1133test "enum with one member default to u0 tag type" {
1134 const E0 = enum {
1135 X,
1136 };
1137 comptime try expect(Tag(E0) == u0);
1138}
1139
1140test "tagName on enum literals" {
1141 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1142 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1143}
1144
1145test "method call on an enum" {
1146 const S = struct {
1147 const E = enum {
1148 one,
1149 two,
1150
1151 fn method(self: *E) bool {
1152 return self.* == .two;
1153 }
1154
1155 fn generic_method(self: *E, foo: anytype) bool {
1156 return self.* == .two and foo == bool;
1157 }
1158 };
1159 fn doTheTest() !void {
1160 var e = E.two;
1161 try expect(e.method());
1162 try expect(e.generic_method(bool));
1163 }
1164 };
1165 try S.doTheTest();
1166 comptime try S.doTheTest();
1167}
test/behavior/enum_stage1.zig created+1058
...@@ -0,0 +1,1058 @@
1const expect = @import("std").testing.expect;
2const mem = @import("std").mem;
3const Tag = @import("std").meta.Tag;
4
5test "non-exhaustive enum" {
6 const S = struct {
7 const E = enum(u8) {
8 a,
9 b,
10 _,
11 };
12 fn doTheTest(y: u8) !void {
13 var e: E = .b;
14 try expect(switch (e) {
15 .a => false,
16 .b => true,
17 _ => false,
18 });
19 e = @intToEnum(E, 12);
20 try expect(switch (e) {
21 .a => false,
22 .b => false,
23 _ => true,
24 });
25
26 try expect(switch (e) {
27 .a => false,
28 .b => false,
29 else => true,
30 });
31 e = .b;
32 try expect(switch (e) {
33 .a => false,
34 else => true,
35 });
36
37 try expect(@typeInfo(E).Enum.fields.len == 2);
38 e = @intToEnum(E, 12);
39 try expect(@enumToInt(e) == 12);
40 e = @intToEnum(E, y);
41 try expect(@enumToInt(e) == 52);
42 try expect(@typeInfo(E).Enum.is_exhaustive == false);
43 }
44 };
45 try S.doTheTest(52);
46 comptime try S.doTheTest(52);
47}
48
49test "empty non-exhaustive enum" {
50 const S = struct {
51 const E = enum(u8) {
52 _,
53 };
54 fn doTheTest(y: u8) !void {
55 var e = @intToEnum(E, y);
56 try expect(switch (e) {
57 _ => true,
58 });
59 try expect(@enumToInt(e) == y);
60
61 try expect(@typeInfo(E).Enum.fields.len == 0);
62 try expect(@typeInfo(E).Enum.is_exhaustive == false);
63 }
64 };
65 try S.doTheTest(42);
66 comptime try S.doTheTest(42);
67}
68
69test "single field non-exhaustive enum" {
70 const S = struct {
71 const E = enum(u8) { a, _ };
72 fn doTheTest(y: u8) !void {
73 var e: E = .a;
74 try expect(switch (e) {
75 .a => true,
76 _ => false,
77 });
78 e = @intToEnum(E, 12);
79 try expect(switch (e) {
80 .a => false,
81 _ => true,
82 });
83
84 try expect(switch (e) {
85 .a => false,
86 else => true,
87 });
88 e = .a;
89 try expect(switch (e) {
90 .a => true,
91 else => false,
92 });
93
94 try expect(@enumToInt(@intToEnum(E, y)) == y);
95 try expect(@typeInfo(E).Enum.fields.len == 1);
96 try expect(@typeInfo(E).Enum.is_exhaustive == false);
97 }
98 };
99 try S.doTheTest(23);
100 comptime try S.doTheTest(23);
101}
102
103test "enum type" {
104 const foo1 = Foo{ .One = 13 };
105 const foo2 = Foo{
106 .Two = Point{
107 .x = 1234,
108 .y = 5678,
109 },
110 };
111 try expect(foo1.One == 13);
112 try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
113 const bar = Bar.B;
114
115 try expect(bar == Bar.B);
116 try expect(@typeInfo(Foo).Union.fields.len == 3);
117 try expect(@typeInfo(Bar).Enum.fields.len == 4);
118 try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid));
119 try expect(@sizeOf(Bar) == 1);
120}
121
122test "enum as return value" {
123 switch (returnAnInt(13)) {
124 Foo.One => |value| try expect(value == 13),
125 else => unreachable,
126 }
127}
128
129const Point = struct {
130 x: u64,
131 y: u64,
132};
133const Foo = union(enum) {
134 One: i32,
135 Two: Point,
136 Three: void,
137};
138const FooNoVoid = union(enum) {
139 One: i32,
140 Two: Point,
141};
142const Bar = enum {
143 A,
144 B,
145 C,
146 D,
147};
148
149fn returnAnInt(x: i32) Foo {
150 return Foo{ .One = x };
151}
152
153test "constant enum with payload" {
154 var empty = AnEnumWithPayload{ .Empty = {} };
155 var full = AnEnumWithPayload{ .Full = 13 };
156 shouldBeEmpty(empty);
157 shouldBeNotEmpty(full);
158}
159
160fn shouldBeEmpty(x: AnEnumWithPayload) void {
161 switch (x) {
162 AnEnumWithPayload.Empty => {},
163 else => unreachable,
164 }
165}
166
167fn shouldBeNotEmpty(x: AnEnumWithPayload) void {
168 switch (x) {
169 AnEnumWithPayload.Empty => unreachable,
170 else => {},
171 }
172}
173
174const AnEnumWithPayload = union(enum) {
175 Empty: void,
176 Full: i32,
177};
178
179const Number = enum { Zero, One, Two, Three, Four };
180
181fn shouldEqual(n: Number, expected: u3) !void {
182 try expect(@enumToInt(n) == expected);
183}
184
185test "int to enum" {
186 try testIntToEnumEval(3);
187}
188fn testIntToEnumEval(x: i32) !void {
189 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
190}
191const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
192
193test "@tagName" {
194 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
195 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
196}
197
198test "@tagName non-exhaustive enum" {
199 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
200 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
201}
202
203fn testEnumTagNameBare(n: anytype) []const u8 {
204 return @tagName(n);
205}
206
207const BareNumber = enum { One, Two, Three };
208
209const NonExhaustive = enum(u8) { A, B, _ };
210
211test "enum alignment" {
212 comptime {
213 try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
214 try expect(@alignOf(AlignTestEnum) >= @alignOf(u64));
215 }
216}
217
218const AlignTestEnum = union(enum) {
219 A: [9]u8,
220 B: u64,
221};
222
223const ValueCount1 = enum {
224 I0,
225};
226const ValueCount2 = enum {
227 I0,
228 I1,
229};
230const ValueCount256 = enum {
231 I0,
232 I1,
233 I2,
234 I3,
235 I4,
236 I5,
237 I6,
238 I7,
239 I8,
240 I9,
241 I10,
242 I11,
243 I12,
244 I13,
245 I14,
246 I15,
247 I16,
248 I17,
249 I18,
250 I19,
251 I20,
252 I21,
253 I22,
254 I23,
255 I24,
256 I25,
257 I26,
258 I27,
259 I28,
260 I29,
261 I30,
262 I31,
263 I32,
264 I33,
265 I34,
266 I35,
267 I36,
268 I37,
269 I38,
270 I39,
271 I40,
272 I41,
273 I42,
274 I43,
275 I44,
276 I45,
277 I46,
278 I47,
279 I48,
280 I49,
281 I50,
282 I51,
283 I52,
284 I53,
285 I54,
286 I55,
287 I56,
288 I57,
289 I58,
290 I59,
291 I60,
292 I61,
293 I62,
294 I63,
295 I64,
296 I65,
297 I66,
298 I67,
299 I68,
300 I69,
301 I70,
302 I71,
303 I72,
304 I73,
305 I74,
306 I75,
307 I76,
308 I77,
309 I78,
310 I79,
311 I80,
312 I81,
313 I82,
314 I83,
315 I84,
316 I85,
317 I86,
318 I87,
319 I88,
320 I89,
321 I90,
322 I91,
323 I92,
324 I93,
325 I94,
326 I95,
327 I96,
328 I97,
329 I98,
330 I99,
331 I100,
332 I101,
333 I102,
334 I103,
335 I104,
336 I105,
337 I106,
338 I107,
339 I108,
340 I109,
341 I110,
342 I111,
343 I112,
344 I113,
345 I114,
346 I115,
347 I116,
348 I117,
349 I118,
350 I119,
351 I120,
352 I121,
353 I122,
354 I123,
355 I124,
356 I125,
357 I126,
358 I127,
359 I128,
360 I129,
361 I130,
362 I131,
363 I132,
364 I133,
365 I134,
366 I135,
367 I136,
368 I137,
369 I138,
370 I139,
371 I140,
372 I141,
373 I142,
374 I143,
375 I144,
376 I145,
377 I146,
378 I147,
379 I148,
380 I149,
381 I150,
382 I151,
383 I152,
384 I153,
385 I154,
386 I155,
387 I156,
388 I157,
389 I158,
390 I159,
391 I160,
392 I161,
393 I162,
394 I163,
395 I164,
396 I165,
397 I166,
398 I167,
399 I168,
400 I169,
401 I170,
402 I171,
403 I172,
404 I173,
405 I174,
406 I175,
407 I176,
408 I177,
409 I178,
410 I179,
411 I180,
412 I181,
413 I182,
414 I183,
415 I184,
416 I185,
417 I186,
418 I187,
419 I188,
420 I189,
421 I190,
422 I191,
423 I192,
424 I193,
425 I194,
426 I195,
427 I196,
428 I197,
429 I198,
430 I199,
431 I200,
432 I201,
433 I202,
434 I203,
435 I204,
436 I205,
437 I206,
438 I207,
439 I208,
440 I209,
441 I210,
442 I211,
443 I212,
444 I213,
445 I214,
446 I215,
447 I216,
448 I217,
449 I218,
450 I219,
451 I220,
452 I221,
453 I222,
454 I223,
455 I224,
456 I225,
457 I226,
458 I227,
459 I228,
460 I229,
461 I230,
462 I231,
463 I232,
464 I233,
465 I234,
466 I235,
467 I236,
468 I237,
469 I238,
470 I239,
471 I240,
472 I241,
473 I242,
474 I243,
475 I244,
476 I245,
477 I246,
478 I247,
479 I248,
480 I249,
481 I250,
482 I251,
483 I252,
484 I253,
485 I254,
486 I255,
487};
488const ValueCount257 = enum {
489 I0,
490 I1,
491 I2,
492 I3,
493 I4,
494 I5,
495 I6,
496 I7,
497 I8,
498 I9,
499 I10,
500 I11,
501 I12,
502 I13,
503 I14,
504 I15,
505 I16,
506 I17,
507 I18,
508 I19,
509 I20,
510 I21,
511 I22,
512 I23,
513 I24,
514 I25,
515 I26,
516 I27,
517 I28,
518 I29,
519 I30,
520 I31,
521 I32,
522 I33,
523 I34,
524 I35,
525 I36,
526 I37,
527 I38,
528 I39,
529 I40,
530 I41,
531 I42,
532 I43,
533 I44,
534 I45,
535 I46,
536 I47,
537 I48,
538 I49,
539 I50,
540 I51,
541 I52,
542 I53,
543 I54,
544 I55,
545 I56,
546 I57,
547 I58,
548 I59,
549 I60,
550 I61,
551 I62,
552 I63,
553 I64,
554 I65,
555 I66,
556 I67,
557 I68,
558 I69,
559 I70,
560 I71,
561 I72,
562 I73,
563 I74,
564 I75,
565 I76,
566 I77,
567 I78,
568 I79,
569 I80,
570 I81,
571 I82,
572 I83,
573 I84,
574 I85,
575 I86,
576 I87,
577 I88,
578 I89,
579 I90,
580 I91,
581 I92,
582 I93,
583 I94,
584 I95,
585 I96,
586 I97,
587 I98,
588 I99,
589 I100,
590 I101,
591 I102,
592 I103,
593 I104,
594 I105,
595 I106,
596 I107,
597 I108,
598 I109,
599 I110,
600 I111,
601 I112,
602 I113,
603 I114,
604 I115,
605 I116,
606 I117,
607 I118,
608 I119,
609 I120,
610 I121,
611 I122,
612 I123,
613 I124,
614 I125,
615 I126,
616 I127,
617 I128,
618 I129,
619 I130,
620 I131,
621 I132,
622 I133,
623 I134,
624 I135,
625 I136,
626 I137,
627 I138,
628 I139,
629 I140,
630 I141,
631 I142,
632 I143,
633 I144,
634 I145,
635 I146,
636 I147,
637 I148,
638 I149,
639 I150,
640 I151,
641 I152,
642 I153,
643 I154,
644 I155,
645 I156,
646 I157,
647 I158,
648 I159,
649 I160,
650 I161,
651 I162,
652 I163,
653 I164,
654 I165,
655 I166,
656 I167,
657 I168,
658 I169,
659 I170,
660 I171,
661 I172,
662 I173,
663 I174,
664 I175,
665 I176,
666 I177,
667 I178,
668 I179,
669 I180,
670 I181,
671 I182,
672 I183,
673 I184,
674 I185,
675 I186,
676 I187,
677 I188,
678 I189,
679 I190,
680 I191,
681 I192,
682 I193,
683 I194,
684 I195,
685 I196,
686 I197,
687 I198,
688 I199,
689 I200,
690 I201,
691 I202,
692 I203,
693 I204,
694 I205,
695 I206,
696 I207,
697 I208,
698 I209,
699 I210,
700 I211,
701 I212,
702 I213,
703 I214,
704 I215,
705 I216,
706 I217,
707 I218,
708 I219,
709 I220,
710 I221,
711 I222,
712 I223,
713 I224,
714 I225,
715 I226,
716 I227,
717 I228,
718 I229,
719 I230,
720 I231,
721 I232,
722 I233,
723 I234,
724 I235,
725 I236,
726 I237,
727 I238,
728 I239,
729 I240,
730 I241,
731 I242,
732 I243,
733 I244,
734 I245,
735 I246,
736 I247,
737 I248,
738 I249,
739 I250,
740 I251,
741 I252,
742 I253,
743 I254,
744 I255,
745 I256,
746};
747
748const Small2 = enum(u2) {
749 One,
750 Two,
751};
752const Small = enum(u2) {
753 One,
754 Two,
755 Three,
756 Four,
757};
758
759test "set enum tag type" {
760 {
761 var x = Small.One;
762 x = Small.Two;
763 comptime try expect(Tag(Small) == u2);
764 }
765 {
766 var x = Small2.One;
767 x = Small2.Two;
768 comptime try expect(Tag(Small2) == u2);
769 }
770}
771
772const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
773const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
774const C = enum(u2) { One4, Two4, Three4, Four4 };
775
776const BitFieldOfEnums = packed struct {
777 a: A,
778 b: B,
779 c: C,
780};
781
782const bit_field_1 = BitFieldOfEnums{
783 .a = A.Two,
784 .b = B.Three3,
785 .c = C.Four4,
786};
787
788test "bit field access with enum fields" {
789 var data = bit_field_1;
790 try expect(getA(&data) == A.Two);
791 try expect(getB(&data) == B.Three3);
792 try expect(getC(&data) == C.Four4);
793 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
794
795 data.b = B.Four3;
796 try expect(data.b == B.Four3);
797
798 data.a = A.Three;
799 try expect(data.a == A.Three);
800 try expect(data.b == B.Four3);
801}
802
803fn getA(data: *const BitFieldOfEnums) A {
804 return data.a;
805}
806
807fn getB(data: *const BitFieldOfEnums) B {
808 return data.b;
809}
810
811fn getC(data: *const BitFieldOfEnums) C {
812 return data.c;
813}
814
815test "casting enum to its tag type" {
816 try testCastEnumTag(Small2.Two);
817 comptime try testCastEnumTag(Small2.Two);
818}
819
820fn testCastEnumTag(value: Small2) !void {
821 try expect(@enumToInt(value) == 1);
822}
823
824const MultipleChoice = enum(u32) {
825 A = 20,
826 B = 40,
827 C = 60,
828 D = 1000,
829};
830
831test "enum with specified tag values" {
832 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
833 comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
834}
835
836fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
837 try expect(@enumToInt(x) == 60);
838 try expect(1234 == switch (x) {
839 MultipleChoice.A => 1,
840 MultipleChoice.B => 2,
841 MultipleChoice.C => @as(u32, 1234),
842 MultipleChoice.D => 4,
843 });
844}
845
846const MultipleChoice2 = enum(u32) {
847 Unspecified1,
848 A = 20,
849 Unspecified2,
850 B = 40,
851 Unspecified3,
852 C = 60,
853 Unspecified4,
854 D = 1000,
855 Unspecified5,
856};
857
858test "enum with specified and unspecified tag values" {
859 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
860 comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
861}
862
863fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
864 try expect(@enumToInt(x) == 1000);
865 try expect(1234 == switch (x) {
866 MultipleChoice2.A => 1,
867 MultipleChoice2.B => 2,
868 MultipleChoice2.C => 3,
869 MultipleChoice2.D => @as(u32, 1234),
870 MultipleChoice2.Unspecified1 => 5,
871 MultipleChoice2.Unspecified2 => 6,
872 MultipleChoice2.Unspecified3 => 7,
873 MultipleChoice2.Unspecified4 => 8,
874 MultipleChoice2.Unspecified5 => 9,
875 });
876}
877
878test "cast integer literal to enum" {
879 try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
880 try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
881}
882
883const EnumWithOneMember = enum { Eof };
884
885fn doALoopThing(id: EnumWithOneMember) void {
886 while (true) {
887 if (id == EnumWithOneMember.Eof) {
888 break;
889 }
890 @compileError("above if condition should be comptime");
891 }
892}
893
894test "comparison operator on enum with one member is comptime known" {
895 doALoopThing(EnumWithOneMember.Eof);
896}
897
898const State = enum { Start };
899test "switch on enum with one member is comptime known" {
900 var state = State.Start;
901 switch (state) {
902 State.Start => return,
903 }
904 @compileError("analysis should not reach here");
905}
906
907const EnumWithTagValues = enum(u4) {
908 A = 1 << 0,
909 B = 1 << 1,
910 C = 1 << 2,
911 D = 1 << 3,
912};
913test "enum with tag values don't require parens" {
914 try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
915}
916
917test "enum with 1 field but explicit tag type should still have the tag type" {
918 const Enum = enum(u8) {
919 B = 2,
920 };
921 comptime try expect(@sizeOf(Enum) == @sizeOf(u8));
922}
923
924test "tag name with assigned enum values" {
925 const LocalFoo = enum(u8) {
926 A = 1,
927 B = 0,
928 };
929 var b = LocalFoo.B;
930 try expect(mem.eql(u8, @tagName(b), "B"));
931}
932
933test "enum literal in array literal" {
934 const Items = enum { one, two };
935 const array = [_]Items{ .one, .two };
936
937 try expect(array[0] == .one);
938 try expect(array[1] == .two);
939}
940
941test "signed integer as enum tag" {
942 const SignedEnum = enum(i2) {
943 A0 = -1,
944 A1 = 0,
945 A2 = 1,
946 };
947
948 try expect(@enumToInt(SignedEnum.A0) == -1);
949 try expect(@enumToInt(SignedEnum.A1) == 0);
950 try expect(@enumToInt(SignedEnum.A2) == 1);
951}
952
953test "enum value allocation" {
954 const LargeEnum = enum(u32) {
955 A0 = 0x80000000,
956 A1,
957 A2,
958 };
959
960 try expect(@enumToInt(LargeEnum.A0) == 0x80000000);
961 try expect(@enumToInt(LargeEnum.A1) == 0x80000001);
962 try expect(@enumToInt(LargeEnum.A2) == 0x80000002);
963}
964
965test "enum literal casting to tagged union" {
966 const Arch = union(enum) {
967 x86_64,
968 arm: Arm32,
969
970 const Arm32 = enum {
971 v8_5a,
972 v8_4a,
973 };
974 };
975
976 var t = true;
977 var x: Arch = .x86_64;
978 var y = if (t) x else .x86_64;
979 switch (y) {
980 .x86_64 => {},
981 else => @panic("fail"),
982 }
983}
984
985test "enum with one member and custom tag type" {
986 const E = enum(u2) {
987 One,
988 };
989 try expect(@enumToInt(E.One) == 0);
990 const E2 = enum(u2) {
991 One = 2,
992 };
993 try expect(@enumToInt(E2.One) == 2);
994}
995
996test "enum literal casting to optional" {
997 var bar: ?Bar = undefined;
998 bar = .B;
999
1000 try expect(bar.? == Bar.B);
1001}
1002
1003test "enum literal casting to error union with payload enum" {
1004 var bar: error{B}!Bar = undefined;
1005 bar = .B; // should never cast to the error set
1006
1007 try expect((try bar) == Bar.B);
1008}
1009
1010test "enum with one member and u1 tag type @enumToInt" {
1011 const Enum = enum(u1) {
1012 Test,
1013 };
1014 try expect(@enumToInt(Enum.Test) == 0);
1015}
1016
1017test "enum with comptime_int tag type" {
1018 const Enum = enum(comptime_int) {
1019 One = 3,
1020 Two = 2,
1021 Three = 1,
1022 };
1023 comptime try expect(Tag(Enum) == comptime_int);
1024}
1025
1026test "enum with one member default to u0 tag type" {
1027 const E0 = enum { X };
1028 comptime try expect(Tag(E0) == u0);
1029}
1030
1031test "tagName on enum literals" {
1032 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1033 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1034}
1035
1036test "method call on an enum" {
1037 const S = struct {
1038 const E = enum {
1039 one,
1040 two,
1041
1042 fn method(self: *E) bool {
1043 return self.* == .two;
1044 }
1045
1046 fn generic_method(self: *E, foo: anytype) bool {
1047 return self.* == .two and foo == bool;
1048 }
1049 };
1050 fn doTheTest() !void {
1051 var e = E.two;
1052 try expect(e.method());
1053 try expect(e.generic_method(bool));
1054 }
1055 };
1056 try S.doTheTest();
1057 comptime try S.doTheTest();
1058}
test/behavior/enum_with_members.zig deleted-27
...@@ -1,27 +0,0 @@
1const expect = @import("std").testing.expect;
2const mem = @import("std").mem;
3const fmt = @import("std").fmt;
4
5const ET = union(enum) {
6 SINT: i32,
7 UINT: u32,
8
9 pub fn print(a: *const ET, buf: []u8) anyerror!usize {
10 return switch (a.*) {
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
13 };
14 }
15};
16
17test "enum with members" {
18 const a = ET{ .SINT = -42 };
19 const b = ET{ .UINT = 42 };
20 var buf: [20]u8 = undefined;
21
22 try expect((a.print(buf[0..]) catch unreachable) == 3);
23 try expect(mem.eql(u8, buf[0..3], "-42"));
24
25 try expect((b.print(buf[0..]) catch unreachable) == 2);
26 try expect(mem.eql(u8, buf[0..2], "42"));
27}
test/behavior/for.zig-176
...@@ -2,179 +2,3 @@ const std = @import("std");...@@ -2,179 +2,3 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
4const mem = std.mem;4const mem = std.mem;
5
6test "continue in for loop" {
7 const array = [_]i32{
8 1,
9 2,
10 3,
11 4,
12 5,
13 };
14 var sum: i32 = 0;
15 for (array) |x| {
16 sum += x;
17 if (x < 3) {
18 continue;
19 }
20 break;
21 }
22 if (sum != 6) unreachable;
23}
24
25test "for loop with pointer elem var" {
26 const source = "abcdefg";
27 var target: [source.len]u8 = undefined;
28 mem.copy(u8, target[0..], source);
29 mangleString(target[0..]);
30 try expect(mem.eql(u8, &target, "bcdefgh"));
31
32 for (source) |*c, i| {
33 _ = i;
34 try expect(@TypeOf(c) == *const u8);
35 }
36 for (target) |*c, i| {
37 _ = i;
38 try expect(@TypeOf(c) == *u8);
39 }
40}
41
42fn mangleString(s: []u8) void {
43 for (s) |*c| {
44 c.* += 1;
45 }
46}
47
48test "basic for loop" {
49 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
50
51 var buffer: [expected_result.len]u8 = undefined;
52 var buf_index: usize = 0;
53
54 const array = [_]u8{ 9, 8, 7, 6 };
55 for (array) |item| {
56 buffer[buf_index] = item;
57 buf_index += 1;
58 }
59 for (array) |item, index| {
60 _ = item;
61 buffer[buf_index] = @intCast(u8, index);
62 buf_index += 1;
63 }
64 const array_ptr = &array;
65 for (array_ptr) |item| {
66 buffer[buf_index] = item;
67 buf_index += 1;
68 }
69 for (array_ptr) |item, index| {
70 _ = item;
71 buffer[buf_index] = @intCast(u8, index);
72 buf_index += 1;
73 }
74 const unknown_size: []const u8 = &array;
75 for (unknown_size) |item| {
76 buffer[buf_index] = item;
77 buf_index += 1;
78 }
79 for (unknown_size) |_, index| {
80 buffer[buf_index] = @intCast(u8, index);
81 buf_index += 1;
82 }
83
84 try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
85}
86
87test "break from outer for loop" {
88 try testBreakOuter();
89 comptime try testBreakOuter();
90}
91
92fn testBreakOuter() !void {
93 var array = "aoeu";
94 var count: usize = 0;
95 outer: for (array) |_| {
96 for (array) |_| {
97 count += 1;
98 break :outer;
99 }
100 }
101 try expect(count == 1);
102}
103
104test "continue outer for loop" {
105 try testContinueOuter();
106 comptime try testContinueOuter();
107}
108
109fn testContinueOuter() !void {
110 var array = "aoeu";
111 var counter: usize = 0;
112 outer: for (array) |_| {
113 for (array) |_| {
114 counter += 1;
115 continue :outer;
116 }
117 }
118 try expect(counter == array.len);
119}
120
121test "2 break statements and an else" {
122 const S = struct {
123 fn entry(t: bool, f: bool) !void {
124 var buf: [10]u8 = undefined;
125 var ok = false;
126 ok = for (buf) |item| {
127 _ = item;
128 if (f) break false;
129 if (t) break true;
130 } else false;
131 try expect(ok);
132 }
133 };
134 try S.entry(true, false);
135 comptime try S.entry(true, false);
136}
137
138test "for with null and T peer types and inferred result location type" {
139 const S = struct {
140 fn doTheTest(slice: []const u8) !void {
141 if (for (slice) |item| {
142 if (item == 10) {
143 break item;
144 }
145 } else null) |v| {
146 _ = v;
147 @panic("fail");
148 }
149 }
150 };
151 try S.doTheTest(&[_]u8{ 1, 2 });
152 comptime try S.doTheTest(&[_]u8{ 1, 2 });
153}
154
155test "for copies its payload" {
156 const S = struct {
157 fn doTheTest() !void {
158 var x = [_]usize{ 1, 2, 3 };
159 for (x) |value, i| {
160 // Modify the original array
161 x[i] += 99;
162 try expectEqual(value, i + 1);
163 }
164 }
165 };
166 try S.doTheTest();
167 comptime try S.doTheTest();
168}
169
170test "for on slice with allowzero ptr" {
171 const S = struct {
172 fn doTheTest(slice: []const u8) !void {
173 var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len];
174 for (ptr) |x, i| try expect(x == i + 1);
175 for (ptr) |*x, i| try expect(x.* == i + 1);
176 }
177 };
178 try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
179 comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
180}
test/behavior/for_stage1.zig created+185
...@@ -0,0 +1,185 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4const mem = std.mem;
5
6test "continue in for loop" {
7 const array = [_]i32{ 1, 2, 3, 4, 5 };
8 var sum: i32 = 0;
9 for (array) |x| {
10 sum += x;
11 if (x < 3) {
12 continue;
13 }
14 break;
15 }
16 if (sum != 6) unreachable;
17}
18
19test "for loop with pointer elem var" {
20 const source = "abcdefg";
21 var target: [source.len]u8 = undefined;
22 mem.copy(u8, target[0..], source);
23 mangleString(target[0..]);
24 try expect(mem.eql(u8, &target, "bcdefgh"));
25
26 for (source) |*c, i| {
27 _ = i;
28 try expect(@TypeOf(c) == *const u8);
29 }
30 for (target) |*c, i| {
31 _ = i;
32 try expect(@TypeOf(c) == *u8);
33 }
34}
35
36fn mangleString(s: []u8) void {
37 for (s) |*c| {
38 c.* += 1;
39 }
40}
41
42test "basic for loop" {
43 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
44
45 var buffer: [expected_result.len]u8 = undefined;
46 var buf_index: usize = 0;
47
48 const array = [_]u8{ 9, 8, 7, 6 };
49 for (array) |item| {
50 buffer[buf_index] = item;
51 buf_index += 1;
52 }
53 for (array) |item, index| {
54 _ = item;
55 buffer[buf_index] = @intCast(u8, index);
56 buf_index += 1;
57 }
58 const array_ptr = &array;
59 for (array_ptr) |item| {
60 buffer[buf_index] = item;
61 buf_index += 1;
62 }
63 for (array_ptr) |item, index| {
64 _ = item;
65 buffer[buf_index] = @intCast(u8, index);
66 buf_index += 1;
67 }
68 const unknown_size: []const u8 = &array;
69 for (unknown_size) |item| {
70 buffer[buf_index] = item;
71 buf_index += 1;
72 }
73 for (unknown_size) |_, index| {
74 buffer[buf_index] = @intCast(u8, index);
75 buf_index += 1;
76 }
77
78 try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
79}
80
81test "break from outer for loop" {
82 try testBreakOuter();
83 comptime try testBreakOuter();
84}
85
86fn testBreakOuter() !void {
87 var array = "aoeu";
88 var count: usize = 0;
89 outer: for (array) |_| {
90 for (array) |_| {
91 count += 1;
92 break :outer;
93 }
94 }
95 try expect(count == 1);
96}
97
98test "continue outer for loop" {
99 try testContinueOuter();
100 comptime try testContinueOuter();
101}
102
103fn testContinueOuter() !void {
104 var array = "aoeu";
105 var counter: usize = 0;
106 outer: for (array) |_| {
107 for (array) |_| {
108 counter += 1;
109 continue :outer;
110 }
111 }
112 try expect(counter == array.len);
113}
114
115test "2 break statements and an else" {
116 const S = struct {
117 fn entry(t: bool, f: bool) !void {
118 var buf: [10]u8 = undefined;
119 var ok = false;
120 ok = for (buf) |item| {
121 _ = item;
122 if (f) break false;
123 if (t) break true;
124 } else false;
125 try expect(ok);
126 }
127 };
128 try S.entry(true, false);
129 comptime try S.entry(true, false);
130}
131
132test "for with null and T peer types and inferred result location type" {
133 const S = struct {
134 fn doTheTest(slice: []const u8) !void {
135 if (for (slice) |item| {
136 if (item == 10) {
137 break item;
138 }
139 } else null) |v| {
140 _ = v;
141 @panic("fail");
142 }
143 }
144 };
145 try S.doTheTest(&[_]u8{ 1, 2 });
146 comptime try S.doTheTest(&[_]u8{ 1, 2 });
147}
148
149test "for copies its payload" {
150 const S = struct {
151 fn doTheTest() !void {
152 var x = [_]usize{ 1, 2, 3 };
153 for (x) |value, i| {
154 // Modify the original array
155 x[i] += 99;
156 try expectEqual(value, i + 1);
157 }
158 }
159 };
160 try S.doTheTest();
161 comptime try S.doTheTest();
162}
163
164test "for on slice with allowzero ptr" {
165 const S = struct {
166 fn doTheTest(slice: []const u8) !void {
167 var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len];
168 for (ptr) |x, i| try expect(x == i + 1);
169 for (ptr) |*x, i| try expect(x.* == i + 1);
170 }
171 };
172 try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
173 comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
174}
175
176test "ignore lval with underscore (for loop)" {
177 for ([_]void{}) |_, i| {
178 _ = i;
179 for ([_]void{}) |_, j| {
180 _ = j;
181 break;
182 }
183 break;
184 }
185}
test/behavior/if.zig+15
...@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {...@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {
73 const x = if (t) Num.Two else unreachable;73 const x = if (t) Num.Two else unreachable;
74 try expect(x == .Two);74 try expect(x == .Two);
75}75}
76
77test "if copies its payload" {
78 const S = struct {
79 fn doTheTest() !void {
80 var tmp: ?i32 = 10;
81 if (tmp) |value| {
82 // Modify the original variable
83 tmp = null;
84 try expect(value == 10);
85 } else unreachable;
86 }
87 };
88 try S.doTheTest();
89 comptime try S.doTheTest();
90}
test/behavior/if_stage1.zig-15
...@@ -17,18 +17,3 @@ test "if prongs cast to expected type instead of peer type resolution" {...@@ -17,18 +17,3 @@ test "if prongs cast to expected type instead of peer type resolution" {
17 try S.doTheTest(false);17 try S.doTheTest(false);
18 comptime try S.doTheTest(false);18 comptime try S.doTheTest(false);
19}19}
20
21test "while copies its payload" {
22 const S = struct {
23 fn doTheTest() !void {
24 var tmp: ?i32 = 10;
25 if (tmp) |value| {
26 // Modify the original variable
27 tmp = null;
28 try expectEqual(@as(i32, 10), value);
29 } else unreachable;
30 }
31 };
32 try S.doTheTest();
33 comptime try S.doTheTest();
34}
test/behavior/switch.zig-545
...@@ -2,548 +2,3 @@ const std = @import("std");...@@ -2,548 +2,3 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectError = std.testing.expectError;3const expectError = std.testing.expectError;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
5
6test "switch with numbers" {
7 try testSwitchWithNumbers(13);
8}
9
10fn testSwitchWithNumbers(x: u32) !void {
11 const result = switch (x) {
12 1, 2, 3, 4...8 => false,
13 13 => true,
14 else => false,
15 };
16 try expect(result);
17}
18
19test "switch with all ranges" {
20 try expect(testSwitchWithAllRanges(50, 3) == 1);
21 try expect(testSwitchWithAllRanges(101, 0) == 2);
22 try expect(testSwitchWithAllRanges(300, 5) == 3);
23 try expect(testSwitchWithAllRanges(301, 6) == 6);
24}
25
26fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
27 return switch (x) {
28 0...100 => 1,
29 101...200 => 2,
30 201...300 => 3,
31 else => y,
32 };
33}
34
35test "implicit comptime switch" {
36 const x = 3 + 4;
37 const result = switch (x) {
38 3 => 10,
39 4 => 11,
40 5, 6 => 12,
41 7, 8 => 13,
42 else => 14,
43 };
44
45 comptime {
46 try expect(result + 1 == 14);
47 }
48}
49
50test "switch on enum" {
51 const fruit = Fruit.Orange;
52 nonConstSwitchOnEnum(fruit);
53}
54const Fruit = enum {
55 Apple,
56 Orange,
57 Banana,
58};
59fn nonConstSwitchOnEnum(fruit: Fruit) void {
60 switch (fruit) {
61 Fruit.Apple => unreachable,
62 Fruit.Orange => {},
63 Fruit.Banana => unreachable,
64 }
65}
66
67test "switch statement" {
68 try nonConstSwitch(SwitchStatementFoo.C);
69}
70fn nonConstSwitch(foo: SwitchStatementFoo) !void {
71 const val = switch (foo) {
72 SwitchStatementFoo.A => @as(i32, 1),
73 SwitchStatementFoo.B => 2,
74 SwitchStatementFoo.C => 3,
75 SwitchStatementFoo.D => 4,
76 };
77 try expect(val == 3);
78}
79const SwitchStatementFoo = enum {
80 A,
81 B,
82 C,
83 D,
84};
85
86test "switch prong with variable" {
87 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
88 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
89 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
90}
91const SwitchProngWithVarEnum = union(enum) {
92 One: i32,
93 Two: f32,
94 Meh: void,
95};
96fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
97 switch (a) {
98 SwitchProngWithVarEnum.One => |x| {
99 try expect(x == 13);
100 },
101 SwitchProngWithVarEnum.Two => |x| {
102 try expect(x == 13.0);
103 },
104 SwitchProngWithVarEnum.Meh => |x| {
105 const v: void = x;
106 _ = v;
107 },
108 }
109}
110
111test "switch on enum using pointer capture" {
112 try testSwitchEnumPtrCapture();
113 comptime try testSwitchEnumPtrCapture();
114}
115
116fn testSwitchEnumPtrCapture() !void {
117 var value = SwitchProngWithVarEnum{ .One = 1234 };
118 switch (value) {
119 SwitchProngWithVarEnum.One => |*x| x.* += 1,
120 else => unreachable,
121 }
122 switch (value) {
123 SwitchProngWithVarEnum.One => |x| try expect(x == 1235),
124 else => unreachable,
125 }
126}
127
128test "switch with multiple expressions" {
129 const x = switch (returnsFive()) {
130 1, 2, 3 => 1,
131 4, 5, 6 => 2,
132 else => @as(i32, 3),
133 };
134 try expect(x == 2);
135}
136fn returnsFive() i32 {
137 return 5;
138}
139
140const Number = union(enum) {
141 One: u64,
142 Two: u8,
143 Three: f32,
144};
145
146const number = Number{ .Three = 1.23 };
147
148fn returnsFalse() bool {
149 switch (number) {
150 Number.One => |x| return x > 1234,
151 Number.Two => |x| return x == 'a',
152 Number.Three => |x| return x > 12.34,
153 }
154}
155test "switch on const enum with var" {
156 try expect(!returnsFalse());
157}
158
159test "switch on type" {
160 try expect(trueIfBoolFalseOtherwise(bool));
161 try expect(!trueIfBoolFalseOtherwise(i32));
162}
163
164fn trueIfBoolFalseOtherwise(comptime T: type) bool {
165 return switch (T) {
166 bool => true,
167 else => false,
168 };
169}
170
171test "switch handles all cases of number" {
172 try testSwitchHandleAllCases();
173 comptime try testSwitchHandleAllCases();
174}
175
176fn testSwitchHandleAllCases() !void {
177 try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
178 try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
179 try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
180 try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
181
182 try expect(testSwitchHandleAllCasesRange(100) == 0);
183 try expect(testSwitchHandleAllCasesRange(200) == 1);
184 try expect(testSwitchHandleAllCasesRange(201) == 2);
185 try expect(testSwitchHandleAllCasesRange(202) == 4);
186 try expect(testSwitchHandleAllCasesRange(230) == 3);
187}
188
189fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
190 return switch (x) {
191 0 => @as(u2, 3),
192 1 => 2,
193 2 => 1,
194 3 => 0,
195 };
196}
197
198fn testSwitchHandleAllCasesRange(x: u8) u8 {
199 return switch (x) {
200 0...100 => @as(u8, 0),
201 101...200 => 1,
202 201, 203 => 2,
203 202 => 4,
204 204...255 => 3,
205 };
206}
207
208test "switch all prongs unreachable" {
209 try testAllProngsUnreachable();
210 comptime try testAllProngsUnreachable();
211}
212
213fn testAllProngsUnreachable() !void {
214 try expect(switchWithUnreachable(1) == 2);
215 try expect(switchWithUnreachable(2) == 10);
216}
217
218fn switchWithUnreachable(x: i32) i32 {
219 while (true) {
220 switch (x) {
221 1 => return 2,
222 2 => break,
223 else => continue,
224 }
225 }
226 return 10;
227}
228
229fn return_a_number() anyerror!i32 {
230 return 1;
231}
232
233test "capture value of switch with all unreachable prongs" {
234 const x = return_a_number() catch |err| switch (err) {
235 else => unreachable,
236 };
237 try expect(x == 1);
238}
239
240test "switching on booleans" {
241 try testSwitchOnBools();
242 comptime try testSwitchOnBools();
243}
244
245fn testSwitchOnBools() !void {
246 try expect(testSwitchOnBoolsTrueAndFalse(true) == false);
247 try expect(testSwitchOnBoolsTrueAndFalse(false) == true);
248
249 try expect(testSwitchOnBoolsTrueWithElse(true) == false);
250 try expect(testSwitchOnBoolsTrueWithElse(false) == true);
251
252 try expect(testSwitchOnBoolsFalseWithElse(true) == false);
253 try expect(testSwitchOnBoolsFalseWithElse(false) == true);
254}
255
256fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
257 return switch (x) {
258 true => false,
259 false => true,
260 };
261}
262
263fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
264 return switch (x) {
265 true => false,
266 else => true,
267 };
268}
269
270fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
271 return switch (x) {
272 false => true,
273 else => false,
274 };
275}
276
277test "u0" {
278 var val: u0 = 0;
279 switch (val) {
280 0 => try expect(val == 0),
281 }
282}
283
284test "undefined.u0" {
285 var val: u0 = undefined;
286 switch (val) {
287 0 => try expect(val == 0),
288 }
289}
290
291test "anon enum literal used in switch on union enum" {
292 const Foo = union(enum) {
293 a: i32,
294 };
295
296 var foo = Foo{ .a = 1234 };
297 switch (foo) {
298 .a => |x| {
299 try expect(x == 1234);
300 },
301 }
302}
303
304test "else prong of switch on error set excludes other cases" {
305 const S = struct {
306 fn doTheTest() !void {
307 try expectError(error.C, bar());
308 }
309 const E = error{
310 A,
311 B,
312 } || E2;
313
314 const E2 = error{
315 C,
316 D,
317 };
318
319 fn foo() E!void {
320 return error.C;
321 }
322
323 fn bar() E2!void {
324 foo() catch |err| switch (err) {
325 error.A, error.B => {},
326 else => |e| return e,
327 };
328 }
329 };
330 try S.doTheTest();
331 comptime try S.doTheTest();
332}
333
334test "switch prongs with error set cases make a new error set type for capture value" {
335 const S = struct {
336 fn doTheTest() !void {
337 try expectError(error.B, bar());
338 }
339 const E = E1 || E2;
340
341 const E1 = error{
342 A,
343 B,
344 };
345
346 const E2 = error{
347 C,
348 D,
349 };
350
351 fn foo() E!void {
352 return error.B;
353 }
354
355 fn bar() E1!void {
356 foo() catch |err| switch (err) {
357 error.A, error.B => |e| return e,
358 else => {},
359 };
360 }
361 };
362 try S.doTheTest();
363 comptime try S.doTheTest();
364}
365
366test "return result loc and then switch with range implicit casted to error union" {
367 const S = struct {
368 fn doTheTest() !void {
369 try expect((func(0xb) catch unreachable) == 0xb);
370 }
371 fn func(d: u8) anyerror!u8 {
372 return switch (d) {
373 0xa...0xf => d,
374 else => unreachable,
375 };
376 }
377 };
378 try S.doTheTest();
379 comptime try S.doTheTest();
380}
381
382test "switch with null and T peer types and inferred result location type" {
383 const S = struct {
384 fn doTheTest(c: u8) !void {
385 if (switch (c) {
386 0 => true,
387 else => null,
388 }) |v| {
389 _ = v;
390 @panic("fail");
391 }
392 }
393 };
394 try S.doTheTest(1);
395 comptime try S.doTheTest(1);
396}
397
398test "switch prongs with cases with identical payload types" {
399 const Union = union(enum) {
400 A: usize,
401 B: isize,
402 C: usize,
403 };
404 const S = struct {
405 fn doTheTest() !void {
406 try doTheSwitch1(Union{ .A = 8 });
407 try doTheSwitch2(Union{ .B = -8 });
408 }
409 fn doTheSwitch1(u: Union) !void {
410 switch (u) {
411 .A, .C => |e| {
412 try expect(@TypeOf(e) == usize);
413 try expect(e == 8);
414 },
415 .B => |e| {
416 _ = e;
417 @panic("fail");
418 },
419 }
420 }
421 fn doTheSwitch2(u: Union) !void {
422 switch (u) {
423 .A, .C => |e| {
424 _ = e;
425 @panic("fail");
426 },
427 .B => |e| {
428 try expect(@TypeOf(e) == isize);
429 try expect(e == -8);
430 },
431 }
432 }
433 };
434 try S.doTheTest();
435 comptime try S.doTheTest();
436}
437
438test "switch with disjoint range" {
439 var q: u8 = 0;
440 switch (q) {
441 0...125 => {},
442 127...255 => {},
443 126...126 => {},
444 }
445}
446
447test "switch variable for range and multiple prongs" {
448 const S = struct {
449 fn doTheTest() !void {
450 var u: u8 = 16;
451 try doTheSwitch(u);
452 comptime try doTheSwitch(u);
453 var v: u8 = 42;
454 try doTheSwitch(v);
455 comptime try doTheSwitch(v);
456 }
457 fn doTheSwitch(q: u8) !void {
458 switch (q) {
459 0...40 => |x| try expect(x == 16),
460 41, 42, 43 => |x| try expect(x == 42),
461 else => try expect(false),
462 }
463 }
464 };
465 _ = S;
466}
467
468var state: u32 = 0;
469fn poll() void {
470 switch (state) {
471 0 => {
472 state = 1;
473 },
474 else => {
475 state += 1;
476 },
477 }
478}
479
480test "switch on global mutable var isn't constant-folded" {
481 while (state < 2) {
482 poll();
483 }
484}
485
486test "switch on pointer type" {
487 const S = struct {
488 const X = struct {
489 field: u32,
490 };
491
492 const P1 = @intToPtr(*X, 0x400);
493 const P2 = @intToPtr(*X, 0x800);
494 const P3 = @intToPtr(*X, 0xC00);
495
496 fn doTheTest(arg: *X) i32 {
497 switch (arg) {
498 P1 => return 1,
499 P2 => return 2,
500 else => return 3,
501 }
502 }
503 };
504
505 try expect(1 == S.doTheTest(S.P1));
506 try expect(2 == S.doTheTest(S.P2));
507 try expect(3 == S.doTheTest(S.P3));
508 comptime try expect(1 == S.doTheTest(S.P1));
509 comptime try expect(2 == S.doTheTest(S.P2));
510 comptime try expect(3 == S.doTheTest(S.P3));
511}
512
513test "switch on error set with single else" {
514 const S = struct {
515 fn doTheTest() !void {
516 var some: error{Foo} = error.Foo;
517 try expect(switch (some) {
518 else => |a| blk: {
519 a catch {};
520 break :blk true;
521 },
522 });
523 }
524 };
525
526 try S.doTheTest();
527 comptime try S.doTheTest();
528}
529
530test "while copies its payload" {
531 const S = struct {
532 fn doTheTest() !void {
533 var tmp: union(enum) {
534 A: u8,
535 B: u32,
536 } = .{ .A = 42 };
537 switch (tmp) {
538 .A => |value| {
539 // Modify the original union
540 tmp = .{ .B = 0x10101010 };
541 try expectEqual(@as(u8, 42), value);
542 },
543 else => unreachable,
544 }
545 }
546 };
547 try S.doTheTest();
548 comptime try S.doTheTest();
549}
test/behavior/switch_stage1.zig created+549
...@@ -0,0 +1,549 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectError = std.testing.expectError;
4const expectEqual = std.testing.expectEqual;
5
6test "switch with numbers" {
7 try testSwitchWithNumbers(13);
8}
9
10fn testSwitchWithNumbers(x: u32) !void {
11 const result = switch (x) {
12 1, 2, 3, 4...8 => false,
13 13 => true,
14 else => false,
15 };
16 try expect(result);
17}
18
19test "switch with all ranges" {
20 try expect(testSwitchWithAllRanges(50, 3) == 1);
21 try expect(testSwitchWithAllRanges(101, 0) == 2);
22 try expect(testSwitchWithAllRanges(300, 5) == 3);
23 try expect(testSwitchWithAllRanges(301, 6) == 6);
24}
25
26fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
27 return switch (x) {
28 0...100 => 1,
29 101...200 => 2,
30 201...300 => 3,
31 else => y,
32 };
33}
34
35test "implicit comptime switch" {
36 const x = 3 + 4;
37 const result = switch (x) {
38 3 => 10,
39 4 => 11,
40 5, 6 => 12,
41 7, 8 => 13,
42 else => 14,
43 };
44
45 comptime {
46 try expect(result + 1 == 14);
47 }
48}
49
50test "switch on enum" {
51 const fruit = Fruit.Orange;
52 nonConstSwitchOnEnum(fruit);
53}
54const Fruit = enum {
55 Apple,
56 Orange,
57 Banana,
58};
59fn nonConstSwitchOnEnum(fruit: Fruit) void {
60 switch (fruit) {
61 Fruit.Apple => unreachable,
62 Fruit.Orange => {},
63 Fruit.Banana => unreachable,
64 }
65}
66
67test "switch statement" {
68 try nonConstSwitch(SwitchStatementFoo.C);
69}
70fn nonConstSwitch(foo: SwitchStatementFoo) !void {
71 const val = switch (foo) {
72 SwitchStatementFoo.A => @as(i32, 1),
73 SwitchStatementFoo.B => 2,
74 SwitchStatementFoo.C => 3,
75 SwitchStatementFoo.D => 4,
76 };
77 try expect(val == 3);
78}
79const SwitchStatementFoo = enum {
80 A,
81 B,
82 C,
83 D,
84};
85
86test "switch prong with variable" {
87 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
88 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
89 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
90}
91const SwitchProngWithVarEnum = union(enum) {
92 One: i32,
93 Two: f32,
94 Meh: void,
95};
96fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
97 switch (a) {
98 SwitchProngWithVarEnum.One => |x| {
99 try expect(x == 13);
100 },
101 SwitchProngWithVarEnum.Two => |x| {
102 try expect(x == 13.0);
103 },
104 SwitchProngWithVarEnum.Meh => |x| {
105 const v: void = x;
106 _ = v;
107 },
108 }
109}
110
111test "switch on enum using pointer capture" {
112 try testSwitchEnumPtrCapture();
113 comptime try testSwitchEnumPtrCapture();
114}
115
116fn testSwitchEnumPtrCapture() !void {
117 var value = SwitchProngWithVarEnum{ .One = 1234 };
118 switch (value) {
119 SwitchProngWithVarEnum.One => |*x| x.* += 1,
120 else => unreachable,
121 }
122 switch (value) {
123 SwitchProngWithVarEnum.One => |x| try expect(x == 1235),
124 else => unreachable,
125 }
126}
127
128test "switch with multiple expressions" {
129 const x = switch (returnsFive()) {
130 1, 2, 3 => 1,
131 4, 5, 6 => 2,
132 else => @as(i32, 3),
133 };
134 try expect(x == 2);
135}
136fn returnsFive() i32 {
137 return 5;
138}
139
140const Number = union(enum) {
141 One: u64,
142 Two: u8,
143 Three: f32,
144};
145
146const number = Number{ .Three = 1.23 };
147
148fn returnsFalse() bool {
149 switch (number) {
150 Number.One => |x| return x > 1234,
151 Number.Two => |x| return x == 'a',
152 Number.Three => |x| return x > 12.34,
153 }
154}
155test "switch on const enum with var" {
156 try expect(!returnsFalse());
157}
158
159test "switch on type" {
160 try expect(trueIfBoolFalseOtherwise(bool));
161 try expect(!trueIfBoolFalseOtherwise(i32));
162}
163
164fn trueIfBoolFalseOtherwise(comptime T: type) bool {
165 return switch (T) {
166 bool => true,
167 else => false,
168 };
169}
170
171test "switch handles all cases of number" {
172 try testSwitchHandleAllCases();
173 comptime try testSwitchHandleAllCases();
174}
175
176fn testSwitchHandleAllCases() !void {
177 try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
178 try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
179 try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
180 try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
181
182 try expect(testSwitchHandleAllCasesRange(100) == 0);
183 try expect(testSwitchHandleAllCasesRange(200) == 1);
184 try expect(testSwitchHandleAllCasesRange(201) == 2);
185 try expect(testSwitchHandleAllCasesRange(202) == 4);
186 try expect(testSwitchHandleAllCasesRange(230) == 3);
187}
188
189fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
190 return switch (x) {
191 0 => @as(u2, 3),
192 1 => 2,
193 2 => 1,
194 3 => 0,
195 };
196}
197
198fn testSwitchHandleAllCasesRange(x: u8) u8 {
199 return switch (x) {
200 0...100 => @as(u8, 0),
201 101...200 => 1,
202 201, 203 => 2,
203 202 => 4,
204 204...255 => 3,
205 };
206}
207
208test "switch all prongs unreachable" {
209 try testAllProngsUnreachable();
210 comptime try testAllProngsUnreachable();
211}
212
213fn testAllProngsUnreachable() !void {
214 try expect(switchWithUnreachable(1) == 2);
215 try expect(switchWithUnreachable(2) == 10);
216}
217
218fn switchWithUnreachable(x: i32) i32 {
219 while (true) {
220 switch (x) {
221 1 => return 2,
222 2 => break,
223 else => continue,
224 }
225 }
226 return 10;
227}
228
229fn return_a_number() anyerror!i32 {
230 return 1;
231}
232
233test "capture value of switch with all unreachable prongs" {
234 const x = return_a_number() catch |err| switch (err) {
235 else => unreachable,
236 };
237 try expect(x == 1);
238}
239
240test "switching on booleans" {
241 try testSwitchOnBools();
242 comptime try testSwitchOnBools();
243}
244
245fn testSwitchOnBools() !void {
246 try expect(testSwitchOnBoolsTrueAndFalse(true) == false);
247 try expect(testSwitchOnBoolsTrueAndFalse(false) == true);
248
249 try expect(testSwitchOnBoolsTrueWithElse(true) == false);
250 try expect(testSwitchOnBoolsTrueWithElse(false) == true);
251
252 try expect(testSwitchOnBoolsFalseWithElse(true) == false);
253 try expect(testSwitchOnBoolsFalseWithElse(false) == true);
254}
255
256fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
257 return switch (x) {
258 true => false,
259 false => true,
260 };
261}
262
263fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
264 return switch (x) {
265 true => false,
266 else => true,
267 };
268}
269
270fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
271 return switch (x) {
272 false => true,
273 else => false,
274 };
275}
276
277test "u0" {
278 var val: u0 = 0;
279 switch (val) {
280 0 => try expect(val == 0),
281 }
282}
283
284test "undefined.u0" {
285 var val: u0 = undefined;
286 switch (val) {
287 0 => try expect(val == 0),
288 }
289}
290
291test "anon enum literal used in switch on union enum" {
292 const Foo = union(enum) {
293 a: i32,
294 };
295
296 var foo = Foo{ .a = 1234 };
297 switch (foo) {
298 .a => |x| {
299 try expect(x == 1234);
300 },
301 }
302}
303
304test "else prong of switch on error set excludes other cases" {
305 const S = struct {
306 fn doTheTest() !void {
307 try expectError(error.C, bar());
308 }
309 const E = error{
310 A,
311 B,
312 } || E2;
313
314 const E2 = error{
315 C,
316 D,
317 };
318
319 fn foo() E!void {
320 return error.C;
321 }
322
323 fn bar() E2!void {
324 foo() catch |err| switch (err) {
325 error.A, error.B => {},
326 else => |e| return e,
327 };
328 }
329 };
330 try S.doTheTest();
331 comptime try S.doTheTest();
332}
333
334test "switch prongs with error set cases make a new error set type for capture value" {
335 const S = struct {
336 fn doTheTest() !void {
337 try expectError(error.B, bar());
338 }
339 const E = E1 || E2;
340
341 const E1 = error{
342 A,
343 B,
344 };
345
346 const E2 = error{
347 C,
348 D,
349 };
350
351 fn foo() E!void {
352 return error.B;
353 }
354
355 fn bar() E1!void {
356 foo() catch |err| switch (err) {
357 error.A, error.B => |e| return e,
358 else => {},
359 };
360 }
361 };
362 try S.doTheTest();
363 comptime try S.doTheTest();
364}
365
366test "return result loc and then switch with range implicit casted to error union" {
367 const S = struct {
368 fn doTheTest() !void {
369 try expect((func(0xb) catch unreachable) == 0xb);
370 }
371 fn func(d: u8) anyerror!u8 {
372 return switch (d) {
373 0xa...0xf => d,
374 else => unreachable,
375 };
376 }
377 };
378 try S.doTheTest();
379 comptime try S.doTheTest();
380}
381
382test "switch with null and T peer types and inferred result location type" {
383 const S = struct {
384 fn doTheTest(c: u8) !void {
385 if (switch (c) {
386 0 => true,
387 else => null,
388 }) |v| {
389 _ = v;
390 @panic("fail");
391 }
392 }
393 };
394 try S.doTheTest(1);
395 comptime try S.doTheTest(1);
396}
397
398test "switch prongs with cases with identical payload types" {
399 const Union = union(enum) {
400 A: usize,
401 B: isize,
402 C: usize,
403 };
404 const S = struct {
405 fn doTheTest() !void {
406 try doTheSwitch1(Union{ .A = 8 });
407 try doTheSwitch2(Union{ .B = -8 });
408 }
409 fn doTheSwitch1(u: Union) !void {
410 switch (u) {
411 .A, .C => |e| {
412 try expect(@TypeOf(e) == usize);
413 try expect(e == 8);
414 },
415 .B => |e| {
416 _ = e;
417 @panic("fail");
418 },
419 }
420 }
421 fn doTheSwitch2(u: Union) !void {
422 switch (u) {
423 .A, .C => |e| {
424 _ = e;
425 @panic("fail");
426 },
427 .B => |e| {
428 try expect(@TypeOf(e) == isize);
429 try expect(e == -8);
430 },
431 }
432 }
433 };
434 try S.doTheTest();
435 comptime try S.doTheTest();
436}
437
438test "switch with disjoint range" {
439 var q: u8 = 0;
440 switch (q) {
441 0...125 => {},
442 127...255 => {},
443 126...126 => {},
444 }
445}
446
447test "switch variable for range and multiple prongs" {
448 const S = struct {
449 fn doTheTest() !void {
450 var u: u8 = 16;
451 try doTheSwitch(u);
452 comptime try doTheSwitch(u);
453 var v: u8 = 42;
454 try doTheSwitch(v);
455 comptime try doTheSwitch(v);
456 }
457 fn doTheSwitch(q: u8) !void {
458 switch (q) {
459 0...40 => |x| try expect(x == 16),
460 41, 42, 43 => |x| try expect(x == 42),
461 else => try expect(false),
462 }
463 }
464 };
465 _ = S;
466}
467
468var state: u32 = 0;
469fn poll() void {
470 switch (state) {
471 0 => {
472 state = 1;
473 },
474 else => {
475 state += 1;
476 },
477 }
478}
479
480test "switch on global mutable var isn't constant-folded" {
481 while (state < 2) {
482 poll();
483 }
484}
485
486test "switch on pointer type" {
487 const S = struct {
488 const X = struct {
489 field: u32,
490 };
491
492 const P1 = @intToPtr(*X, 0x400);
493 const P2 = @intToPtr(*X, 0x800);
494 const P3 = @intToPtr(*X, 0xC00);
495
496 fn doTheTest(arg: *X) i32 {
497 switch (arg) {
498 P1 => return 1,
499 P2 => return 2,
500 else => return 3,
501 }
502 }
503 };
504
505 try expect(1 == S.doTheTest(S.P1));
506 try expect(2 == S.doTheTest(S.P2));
507 try expect(3 == S.doTheTest(S.P3));
508 comptime try expect(1 == S.doTheTest(S.P1));
509 comptime try expect(2 == S.doTheTest(S.P2));
510 comptime try expect(3 == S.doTheTest(S.P3));
511}
512
513test "switch on error set with single else" {
514 const S = struct {
515 fn doTheTest() !void {
516 var some: error{Foo} = error.Foo;
517 try expect(switch (some) {
518 else => |a| blk: {
519 a catch {};
520 break :blk true;
521 },
522 });
523 }
524 };
525
526 try S.doTheTest();
527 comptime try S.doTheTest();
528}
529
530test "while copies its payload" {
531 const S = struct {
532 fn doTheTest() !void {
533 var tmp: union(enum) {
534 A: u8,
535 B: u32,
536 } = .{ .A = 42 };
537 switch (tmp) {
538 .A => |value| {
539 // Modify the original union
540 tmp = .{ .B = 0x10101010 };
541 try expectEqual(@as(u8, 42), value);
542 },
543 else => unreachable,
544 }
545 }
546 };
547 try S.doTheTest();
548 comptime try S.doTheTest();
549}
test/behavior/underscore.zig-11
...@@ -5,17 +5,6 @@ test "ignore lval with underscore" {...@@ -5,17 +5,6 @@ test "ignore lval with underscore" {
5 _ = false;5 _ = false;
6}6}
77
8test "ignore lval with underscore (for loop)" {
9 for ([_]void{}) |_, i| {
10 _ = i;
11 for ([_]void{}) |_, j| {
12 _ = j;
13 break;
14 }
15 break;
16 }
17}
18
19test "ignore lval with underscore (while loop)" {8test "ignore lval with underscore (while loop)" {
20 while (optionalReturnError()) |_| {9 while (optionalReturnError()) |_| {
21 while (optionalReturnError()) |_| {10 while (optionalReturnError()) |_| {
test/behavior/union_with_members.zig created+27
...@@ -0,0 +1,27 @@
1const expect = @import("std").testing.expect;
2const mem = @import("std").mem;
3const fmt = @import("std").fmt;
4
5const ET = union(enum) {
6 SINT: i32,
7 UINT: u32,
8
9 pub fn print(a: *const ET, buf: []u8) anyerror!usize {
10 return switch (a.*) {
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
13 };
14 }
15};
16
17test "enum with members" {
18 const a = ET{ .SINT = -42 };
19 const b = ET{ .UINT = 42 };
20 var buf: [20]u8 = undefined;
21
22 try expect((a.print(buf[0..]) catch unreachable) == 3);
23 try expect(mem.eql(u8, buf[0..3], "-42"));
24
25 try expect((b.print(buf[0..]) catch unreachable) == 2);
26 try expect(mem.eql(u8, buf[0..2], "42"));
27}
test/behavior/while.zig+9-179
...@@ -23,7 +23,7 @@ test "static eval while" {...@@ -23,7 +23,7 @@ test "static eval while" {
23}23}
24const static_eval_while_number = staticWhileLoop1();24const static_eval_while_number = staticWhileLoop1();
25fn staticWhileLoop1() i32 {25fn staticWhileLoop1() i32 {
26 return whileLoop2();26 return staticWhileLoop2();
27}27}
28fn staticWhileLoop2() i32 {28fn staticWhileLoop2() i32 {
29 while (true) {29 while (true) {
...@@ -31,33 +31,6 @@ fn staticWhileLoop2() i32 {...@@ -31,33 +31,6 @@ fn staticWhileLoop2() i32 {
31 }31 }
32}32}
3333
34test "continue and break" {
35 try runContinueAndBreakTest();
36 try expect(continue_and_break_counter == 8);
37}
38var continue_and_break_counter: i32 = 0;
39fn runContinueAndBreakTest() !void {
40 var i: i32 = 0;
41 while (true) {
42 continue_and_break_counter += 2;
43 i += 1;
44 if (i < 4) {
45 continue;
46 }
47 break;
48 }
49 try expect(i == 4);
50}
51
52test "return with implicit cast from while loop" {
53 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
54}
55fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
56 while (true) {
57 return;
58 }
59}
60
61test "while with continue expression" {34test "while with continue expression" {
62 var sum: i32 = 0;35 var sum: i32 = 0;
63 {36 {
...@@ -83,43 +56,6 @@ test "while with else" {...@@ -83,43 +56,6 @@ test "while with else" {
83 try expect(got_else == 1);56 try expect(got_else == 1);
84}57}
8558
86test "while with optional as condition" {
87 numbers_left = 10;
88 var sum: i32 = 0;
89 while (getNumberOrNull()) |value| {
90 sum += value;
91 }
92 try expect(sum == 45);
93}
94
95test "while with optional as condition with else" {
96 numbers_left = 10;
97 var sum: i32 = 0;
98 var got_else: i32 = 0;
99 while (getNumberOrNull()) |value| {
100 sum += value;
101 try expect(got_else == 0);
102 } else {
103 got_else += 1;
104 }
105 try expect(sum == 45);
106 try expect(got_else == 1);
107}
108
109test "while with error union condition" {
110 numbers_left = 10;
111 var sum: i32 = 0;
112 var got_else: i32 = 0;
113 while (getNumberOrErr()) |value| {
114 sum += value;
115 } else |err| {
116 try expect(err == error.OutOfNumbers);
117 got_else += 1;
118 }
119 try expect(sum == 45);
120 try expect(got_else == 1);
121}
122
123var numbers_left: i32 = undefined;59var numbers_left: i32 = undefined;
124fn getNumberOrErr() anyerror!i32 {60fn getNumberOrErr() anyerror!i32 {
125 return if (numbers_left == 0) error.OutOfNumbers else x: {61 return if (numbers_left == 0) error.OutOfNumbers else x: {
...@@ -134,61 +70,6 @@ fn getNumberOrNull() ?i32 {...@@ -134,61 +70,6 @@ fn getNumberOrNull() ?i32 {
134 };70 };
135}71}
13672
137test "while on optional with else result follow else prong" {
138 const result = while (returnNull()) |value| {
139 break value;
140 } else @as(i32, 2);
141 try expect(result == 2);
142}
143
144test "while on optional with else result follow break prong" {
145 const result = while (returnOptional(10)) |value| {
146 break value;
147 } else @as(i32, 2);
148 try expect(result == 10);
149}
150
151test "while on error union with else result follow else prong" {
152 const result = while (returnError()) |value| {
153 break value;
154 } else |_| @as(i32, 2);
155 try expect(result == 2);
156}
157
158test "while on error union with else result follow break prong" {
159 const result = while (returnSuccess(10)) |value| {
160 break value;
161 } else |_| @as(i32, 2);
162 try expect(result == 10);
163}
164
165test "while on bool with else result follow else prong" {
166 const result = while (returnFalse()) {
167 break @as(i32, 10);
168 } else @as(i32, 2);
169 try expect(result == 2);
170}
171
172test "while on bool with else result follow break prong" {
173 const result = while (returnTrue()) {
174 break @as(i32, 10);
175 } else @as(i32, 2);
176 try expect(result == 10);
177}
178
179test "break from outer while loop" {
180 testBreakOuter();
181 comptime testBreakOuter();
182}
183
184fn testBreakOuter() void {
185 outer: while (true) {
186 while (true) {
187 break :outer;
188 }
189 }
190}
191
192test "continue outer while loop" {73test "continue outer while loop" {
193 testContinueOuter();74 testContinueOuter();
194 comptime testContinueOuter();75 comptime testContinueOuter();
...@@ -203,68 +84,17 @@ fn testContinueOuter() void {...@@ -203,68 +84,17 @@ fn testContinueOuter() void {
203 }84 }
204}85}
20586
206fn returnNull() ?i32 {87test "break from outer while loop" {
207 return null;88 testBreakOuter();
208}89 comptime testBreakOuter();
209fn returnOptional(x: i32) ?i32 {
210 return x;
211}
212fn returnError() anyerror!i32 {
213 return error.YouWantedAnError;
214}
215fn returnSuccess(x: i32) anyerror!i32 {
216 return x;
217}
218fn returnFalse() bool {
219 return false;
220}
221fn returnTrue() bool {
222 return true;
223}
224
225test "while bool 2 break statements and an else" {
226 const S = struct {
227 fn entry(t: bool, f: bool) !void {
228 var ok = false;
229 ok = while (t) {
230 if (f) break false;
231 if (t) break true;
232 } else false;
233 try expect(ok);
234 }
235 };
236 try S.entry(true, false);
237 comptime try S.entry(true, false);
238}
239
240test "while optional 2 break statements and an else" {
241 const S = struct {
242 fn entry(opt_t: ?bool, f: bool) !void {
243 var ok = false;
244 ok = while (opt_t) |t| {
245 if (f) break false;
246 if (t) break true;
247 } else false;
248 try expect(ok);
249 }
250 };
251 try S.entry(true, false);
252 comptime try S.entry(true, false);
253}90}
25491
255test "while error 2 break statements and an else" {92fn testBreakOuter() void {
256 const S = struct {93 outer: while (true) {
257 fn entry(opt_t: anyerror!bool, f: bool) !void {94 while (true) {
258 var ok = false;95 break :outer;
259 ok = while (opt_t) |t| {
260 if (f) break false;
261 if (t) break true;
262 } else |_| false;
263 try expect(ok);
264 }96 }
265 };97 }
266 try S.entry(true, false);
267 comptime try S.entry(true, false);
268}98}
26999
270test "while copies its payload" {100test "while copies its payload" {
test/behavior/while_stage1.zig created+186
...@@ -0,0 +1,186 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "continue and break" {
5 try runContinueAndBreakTest();
6 try expect(continue_and_break_counter == 8);
7}
8var continue_and_break_counter: i32 = 0;
9fn runContinueAndBreakTest() !void {
10 var i: i32 = 0;
11 while (true) {
12 continue_and_break_counter += 2;
13 i += 1;
14 if (i < 4) {
15 continue;
16 }
17 break;
18 }
19 try expect(i == 4);
20}
21
22test "return with implicit cast from while loop" {
23 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
24}
25fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
26 while (true) {
27 return;
28 }
29}
30
31test "while with optional as condition" {
32 numbers_left = 10;
33 var sum: i32 = 0;
34 while (getNumberOrNull()) |value| {
35 sum += value;
36 }
37 try expect(sum == 45);
38}
39
40test "while with optional as condition with else" {
41 numbers_left = 10;
42 var sum: i32 = 0;
43 var got_else: i32 = 0;
44 while (getNumberOrNull()) |value| {
45 sum += value;
46 try expect(got_else == 0);
47 } else {
48 got_else += 1;
49 }
50 try expect(sum == 45);
51 try expect(got_else == 1);
52}
53
54test "while with error union condition" {
55 numbers_left = 10;
56 var sum: i32 = 0;
57 var got_else: i32 = 0;
58 while (getNumberOrErr()) |value| {
59 sum += value;
60 } else |err| {
61 try expect(err == error.OutOfNumbers);
62 got_else += 1;
63 }
64 try expect(sum == 45);
65 try expect(got_else == 1);
66}
67
68var numbers_left: i32 = undefined;
69fn getNumberOrErr() anyerror!i32 {
70 return if (numbers_left == 0) error.OutOfNumbers else x: {
71 numbers_left -= 1;
72 break :x numbers_left;
73 };
74}
75fn getNumberOrNull() ?i32 {
76 return if (numbers_left == 0) null else x: {
77 numbers_left -= 1;
78 break :x numbers_left;
79 };
80}
81
82test "while on optional with else result follow else prong" {
83 const result = while (returnNull()) |value| {
84 break value;
85 } else @as(i32, 2);
86 try expect(result == 2);
87}
88
89test "while on optional with else result follow break prong" {
90 const result = while (returnOptional(10)) |value| {
91 break value;
92 } else @as(i32, 2);
93 try expect(result == 10);
94}
95
96test "while on error union with else result follow else prong" {
97 const result = while (returnError()) |value| {
98 break value;
99 } else |_| @as(i32, 2);
100 try expect(result == 2);
101}
102
103test "while on error union with else result follow break prong" {
104 const result = while (returnSuccess(10)) |value| {
105 break value;
106 } else |_| @as(i32, 2);
107 try expect(result == 10);
108}
109
110test "while on bool with else result follow else prong" {
111 const result = while (returnFalse()) {
112 break @as(i32, 10);
113 } else @as(i32, 2);
114 try expect(result == 2);
115}
116
117test "while on bool with else result follow break prong" {
118 const result = while (returnTrue()) {
119 break @as(i32, 10);
120 } else @as(i32, 2);
121 try expect(result == 10);
122}
123
124fn returnNull() ?i32 {
125 return null;
126}
127fn returnOptional(x: i32) ?i32 {
128 return x;
129}
130fn returnError() anyerror!i32 {
131 return error.YouWantedAnError;
132}
133fn returnSuccess(x: i32) anyerror!i32 {
134 return x;
135}
136fn returnFalse() bool {
137 return false;
138}
139fn returnTrue() bool {
140 return true;
141}
142
143test "while bool 2 break statements and an else" {
144 const S = struct {
145 fn entry(t: bool, f: bool) !void {
146 var ok = false;
147 ok = while (t) {
148 if (f) break false;
149 if (t) break true;
150 } else false;
151 try expect(ok);
152 }
153 };
154 try S.entry(true, false);
155 comptime try S.entry(true, false);
156}
157
158test "while optional 2 break statements and an else" {
159 const S = struct {
160 fn entry(opt_t: ?bool, f: bool) !void {
161 var ok = false;
162 ok = while (opt_t) |t| {
163 if (f) break false;
164 if (t) break true;
165 } else false;
166 try expect(ok);
167 }
168 };
169 try S.entry(true, false);
170 comptime try S.entry(true, false);
171}
172
173test "while error 2 break statements and an else" {
174 const S = struct {
175 fn entry(opt_t: anyerror!bool, f: bool) !void {
176 var ok = false;
177 ok = while (opt_t) |t| {
178 if (f) break false;
179 if (t) break true;
180 } else |_| false;
181 try expect(ok);
182 }
183 };
184 try S.entry(true, false);
185 comptime try S.entry(true, false);
186}