authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-27 00:23:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-27 00:27:52-07:00
log17f057c5568bda6b011a213c95aa9538f6fb6a78
treed988df1935461c2b28f88cea5f6f50effb240128
parentf0deef1d79db272fa80ef0323b4382ee1936a3e4

stage2: implement `@typeName`

* stage1: change the `@typeName` of `@TypeOf(undefined)`, `@TypeOf(null)`, and `@TypeOf(.foo)` to match stage2. * move passing behavior tests to the passing-for-stage2 section.

16 files changed, 369 insertions(+), 263 deletions(-)

src/Sema.zig+21-13
......@@ -2771,20 +2771,16 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
27712771 // expression of a variable declaration. We need the memory to be in the new
27722772 // anonymous Decl's arena.
27732773
2774 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
2775 errdefer new_decl_arena.deinit();
2774 var anon_decl = try block.startAnonDecl();
2775 defer anon_decl.deinit();
27762776
2777 const bytes = try new_decl_arena.allocator.dupeZ(u8, zir_bytes);
2777 const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
27782778
2779 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
2780 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes[0 .. bytes.len + 1]);
2779 const new_decl = try anon_decl.finish(
2780 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
2781 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
2782 );
27812783
2782 const new_decl = try sema.mod.createAnonymousDecl(block, .{
2783 .ty = decl_ty,
2784 .val = decl_val,
2785 });
2786 errdefer sema.mod.abortAnonDecl(new_decl);
2787 try new_decl.finalizeNewArena(&new_decl_arena);
27882784 return sema.analyzeDeclRef(new_decl);
27892785}
27902786
......@@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
97419737
97429738fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
97439739 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
9744 const src = inst_data.src();
9745 return sema.fail(block, src, "TODO: Sema.zirTypeName", .{});
9740 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9741 const ty = try sema.resolveType(block, ty_src, inst_data.operand);
9742
9743 var anon_decl = try block.startAnonDecl();
9744 defer anon_decl.deinit();
9745
9746 const bytes = try ty.nameAlloc(anon_decl.arena());
9747
9748 const new_decl = try anon_decl.finish(
9749 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
9750 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
9751 );
9752
9753 return sema.analyzeDeclRef(new_decl);
97469754}
97479755
97489756fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/stage1/codegen.cpp+3-3
......@@ -8755,17 +8755,17 @@ static void define_builtin_types(CodeGen *g) {
87558755 }
87568756 {
87578757 ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral);
8758 buf_init_from_str(&entry->name, "(enum literal)");
8758 buf_init_from_str(&entry->name, "@Type(.EnumLiteral)");
87598759 g->builtin_types.entry_enum_literal = entry;
87608760 }
87618761 {
87628762 ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);
8763 buf_init_from_str(&entry->name, "(undefined)");
8763 buf_init_from_str(&entry->name, "@Type(.Undefined)");
87648764 g->builtin_types.entry_undef = entry;
87658765 }
87668766 {
87678767 ZigType *entry = new_type_table_entry(ZigTypeIdNull);
8768 buf_init_from_str(&entry->name, "(null)");
8768 buf_init_from_str(&entry->name, "@Type(.Null)");
87698769 g->builtin_types.entry_null = entry;
87708770 }
87718771 {
src/type.zig+107
......@@ -1197,6 +1197,113 @@ pub const Type = extern union {
11971197 }
11981198 }
11991199
1200 /// Returns a name suitable for `@typeName`.
1201 pub fn nameAlloc(ty: Type, arena: *Allocator) Allocator.Error![:0]const u8 {
1202 const t = ty.tag();
1203 switch (t) {
1204 .inferred_alloc_const => unreachable,
1205 .inferred_alloc_mut => unreachable,
1206 .generic_poison => unreachable,
1207
1208 .u1,
1209 .u8,
1210 .i8,
1211 .u16,
1212 .i16,
1213 .u32,
1214 .i32,
1215 .u64,
1216 .i64,
1217 .u128,
1218 .i128,
1219 .usize,
1220 .isize,
1221 .c_short,
1222 .c_ushort,
1223 .c_int,
1224 .c_uint,
1225 .c_long,
1226 .c_ulong,
1227 .c_longlong,
1228 .c_ulonglong,
1229 .c_longdouble,
1230 .c_void,
1231 .f16,
1232 .f32,
1233 .f64,
1234 .f128,
1235 .bool,
1236 .void,
1237 .type,
1238 .anyerror,
1239 .@"anyframe",
1240 .comptime_int,
1241 .comptime_float,
1242 .noreturn,
1243 .var_args_param,
1244 .bound_fn,
1245 => return @tagName(t),
1246
1247 .enum_literal => return "@Type(.EnumLiteral)",
1248 .@"null" => return "@Type(.Null)",
1249 .@"undefined" => return "@Type(.Undefined)",
1250
1251 .empty_struct, .empty_struct_literal => return "struct {}",
1252
1253 .@"struct" => {
1254 const struct_obj = ty.castTag(.@"struct").?.data;
1255 return try arena.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));
1256 },
1257 .@"union", .union_tagged => {
1258 const union_obj = ty.cast(Payload.Union).?.data;
1259 return try arena.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));
1260 },
1261 .enum_full, .enum_nonexhaustive => {
1262 const enum_full = ty.cast(Payload.EnumFull).?.data;
1263 return try arena.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));
1264 },
1265 .enum_simple => {
1266 const enum_simple = ty.castTag(.enum_simple).?.data;
1267 return try arena.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));
1268 },
1269 .enum_numbered => {
1270 const enum_numbered = ty.castTag(.enum_numbered).?.data;
1271 return try arena.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));
1272 },
1273 .@"opaque" => {
1274 // TODO use declaration name
1275 return "opaque {}";
1276 },
1277
1278 .anyerror_void_error_union => return "anyerror!void",
1279 .const_slice_u8 => return "[]const u8",
1280 .fn_noreturn_no_args => return "fn() noreturn",
1281 .fn_void_no_args => return "fn() void",
1282 .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
1283 .fn_ccc_void_no_args => return "fn() callconv(.C) void",
1284 .single_const_pointer_to_comptime_int => return "*const comptime_int",
1285 .manyptr_u8 => return "[*]u8",
1286 .manyptr_const_u8 => return "[*]const u8",
1287 .atomic_order => return "AtomicOrder",
1288 .atomic_rmw_op => return "AtomicRmwOp",
1289 .calling_convention => return "CallingConvention",
1290 .address_space => return "AddressSpace",
1291 .float_mode => return "FloatMode",
1292 .reduce_op => return "ReduceOp",
1293 .call_options => return "CallOptions",
1294 .export_options => return "ExportOptions",
1295 .extern_options => return "ExternOptions",
1296 .type_info => return "TypeInfo",
1297
1298 else => {
1299 // TODO this is wasteful and also an incorrect implementation of `@typeName`
1300 var buf = std.ArrayList(u8).init(arena);
1301 try buf.writer().print("{}", .{ty});
1302 return try buf.toOwnedSliceSentinel(0);
1303 },
1304 }
1305 }
1306
12001307 /// Anything that reports hasCodeGenBits() false returns false here as well.
12011308 /// `generic_poison` will return false.
12021309 pub fn requiresComptime(ty: Type) bool {
test/behavior.zig+3-4
......@@ -24,11 +24,11 @@ test {
2424 _ = @import("behavior/defer.zig");
2525 _ = @import("behavior/enum.zig");
2626 _ = @import("behavior/error.zig");
27 _ = @import("behavior/error.zig");
2827 _ = @import("behavior/generics.zig");
2928 _ = @import("behavior/hasdecl.zig");
3029 _ = @import("behavior/hasfield.zig");
3130 _ = @import("behavior/if.zig");
31 _ = @import("behavior/import.zig");
3232 _ = @import("behavior/int128.zig");
3333 _ = @import("behavior/member_func.zig");
3434 _ = @import("behavior/null.zig");
......@@ -73,7 +73,9 @@ test {
7373 _ = @import("behavior/slice.zig");
7474 _ = @import("behavior/struct_llvm.zig");
7575 _ = @import("behavior/switch.zig");
76 _ = @import("behavior/undefined.zig");
7677 _ = @import("behavior/union.zig");
78 _ = @import("behavior/void.zig");
7779 _ = @import("behavior/widening.zig");
7880
7981 if (builtin.zig_is_stage2) {
......@@ -151,7 +153,6 @@ test {
151153 _ = @import("behavior/fn_in_struct_in_comptime.zig");
152154 _ = @import("behavior/for_stage1.zig");
153155 _ = @import("behavior/if_stage1.zig");
154 _ = @import("behavior/import.zig");
155156 _ = @import("behavior/incomplete_struct_param_tld.zig");
156157 _ = @import("behavior/inttoptr.zig");
157158 _ = @import("behavior/ir_block_deps.zig");
......@@ -183,13 +184,11 @@ test {
183184 _ = @import("behavior/type.zig");
184185 _ = @import("behavior/type_info.zig");
185186 _ = @import("behavior/typename.zig");
186 _ = @import("behavior/undefined.zig");
187187 _ = @import("behavior/union_stage1.zig");
188188 _ = @import("behavior/union_with_members.zig");
189189 _ = @import("behavior/usingnamespace_stage1.zig");
190190 _ = @import("behavior/var_args.zig");
191191 _ = @import("behavior/vector.zig");
192 _ = @import("behavior/void.zig");
193192 if (builtin.target.cpu.arch == .wasm32) {
194193 _ = @import("behavior/wasm.zig");
195194 }
test/behavior/enum.zig+22
......@@ -583,3 +583,25 @@ test "peer type resolution with enum literal" {
583583 try expect(Items.two == .two);
584584 try expect(.two == Items.two);
585585}
586
587const MultipleChoice = enum(u32) {
588 A = 20,
589 B = 40,
590 C = 60,
591 D = 1000,
592};
593
594fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
595 try expect(@enumToInt(x) == 60);
596 try expect(1234 == switch (x) {
597 MultipleChoice.A => 1,
598 MultipleChoice.B => 2,
599 MultipleChoice.C => @as(u32, 1234),
600 MultipleChoice.D => 4,
601 });
602}
603
604test "enum with specified tag values" {
605 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
606 comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
607}
test/behavior/enum_stage1.zig-22
......@@ -2,28 +2,6 @@ const expect = @import("std").testing.expect;
22const mem = @import("std").mem;
33const Tag = @import("std").meta.Tag;
44
5const MultipleChoice = enum(u32) {
6 A = 20,
7 B = 40,
8 C = 60,
9 D = 1000,
10};
11
12fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
13 try expect(@enumToInt(x) == 60);
14 try expect(1234 == switch (x) {
15 MultipleChoice.A => 1,
16 MultipleChoice.B => 2,
17 MultipleChoice.C => @as(u32, 1234),
18 MultipleChoice.D => 4,
19 });
20}
21
22test "enum with specified tag values" {
23 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
24 comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
25}
26
275test "non-exhaustive enum" {
286 const S = struct {
297 const E = enum(u8) {
test/behavior/fn.zig+81
......@@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
163163test "function with complex callconv and return type expressions" {
164164 try expect(fComplexCallconvRet(3).x == 9);
165165}
166
167test "pass by non-copying value" {
168 try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
169}
170
171const Point = struct {
172 x: i32,
173 y: i32,
174};
175
176fn addPointCoords(pt: Point) i32 {
177 return pt.x + pt.y;
178}
179
180test "pass by non-copying value through var arg" {
181 try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
182}
183
184fn addPointCoordsVar(pt: anytype) !i32 {
185 comptime try expect(@TypeOf(pt) == Point);
186 return pt.x + pt.y;
187}
188
189test "pass by non-copying value as method" {
190 var pt = Point2{ .x = 1, .y = 2 };
191 try expect(pt.addPointCoords() == 3);
192}
193
194const Point2 = struct {
195 x: i32,
196 y: i32,
197
198 fn addPointCoords(self: Point2) i32 {
199 return self.x + self.y;
200 }
201};
202
203test "pass by non-copying value as method, which is generic" {
204 var pt = Point3{ .x = 1, .y = 2 };
205 try expect(pt.addPointCoords(i32) == 3);
206}
207
208const Point3 = struct {
209 x: i32,
210 y: i32,
211
212 fn addPointCoords(self: Point3, comptime T: type) i32 {
213 _ = T;
214 return self.x + self.y;
215 }
216};
217
218test "pass by non-copying value as method, at comptime" {
219 comptime {
220 var pt = Point2{ .x = 1, .y = 2 };
221 try expect(pt.addPointCoords() == 3);
222 }
223}
224
225test "implicit cast fn call result to optional in field result" {
226 const S = struct {
227 fn entry() !void {
228 var x = Foo{
229 .field = optionalPtr(),
230 };
231 try expect(x.field.?.* == 999);
232 }
233
234 const glob: i32 = 999;
235
236 fn optionalPtr() *const i32 {
237 return &glob;
238 }
239
240 const Foo = struct {
241 field: ?*const i32,
242 };
243 };
244 try S.entry();
245 comptime try S.entry();
246}
test/behavior/fn_stage1.zig-81
......@@ -56,87 +56,6 @@ fn numberLiteralArg(a: anytype) !void {
5656 try expect(a == 3);
5757}
5858
59test "pass by non-copying value" {
60 try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
61}
62
63const Point = struct {
64 x: i32,
65 y: i32,
66};
67
68fn addPointCoords(pt: Point) i32 {
69 return pt.x + pt.y;
70}
71
72test "pass by non-copying value through var arg" {
73 try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
74}
75
76fn addPointCoordsVar(pt: anytype) !i32 {
77 comptime try expect(@TypeOf(pt) == Point);
78 return pt.x + pt.y;
79}
80
81test "pass by non-copying value as method" {
82 var pt = Point2{ .x = 1, .y = 2 };
83 try expect(pt.addPointCoords() == 3);
84}
85
86const Point2 = struct {
87 x: i32,
88 y: i32,
89
90 fn addPointCoords(self: Point2) i32 {
91 return self.x + self.y;
92 }
93};
94
95test "pass by non-copying value as method, which is generic" {
96 var pt = Point3{ .x = 1, .y = 2 };
97 try expect(pt.addPointCoords(i32) == 3);
98}
99
100const Point3 = struct {
101 x: i32,
102 y: i32,
103
104 fn addPointCoords(self: Point3, comptime T: type) i32 {
105 _ = T;
106 return self.x + self.y;
107 }
108};
109
110test "pass by non-copying value as method, at comptime" {
111 comptime {
112 var pt = Point2{ .x = 1, .y = 2 };
113 try expect(pt.addPointCoords() == 3);
114 }
115}
116
117test "implicit cast fn call result to optional in field result" {
118 const S = struct {
119 fn entry() !void {
120 var x = Foo{
121 .field = optionalPtr(),
122 };
123 try expect(x.field.?.* == 999);
124 }
125
126 const glob: i32 = 999;
127
128 fn optionalPtr() *const i32 {
129 return &glob;
130 }
131
132 const Foo = struct {
133 field: ?*const i32,
134 };
135 };
136 try S.entry();
137 comptime try S.entry();
138}
139
14059test "function call with anon list literal" {
14160 const S = struct {
14261 fn doTheTest() !void {
test/behavior/for.zig+56
......@@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" {
6060 break;
6161 }
6262}
63
64test "basic for loop" {
65 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
66
67 var buffer: [expected_result.len]u8 = undefined;
68 var buf_index: usize = 0;
69
70 const array = [_]u8{ 9, 8, 7, 6 };
71 for (array) |item| {
72 buffer[buf_index] = item;
73 buf_index += 1;
74 }
75 for (array) |item, index| {
76 _ = item;
77 buffer[buf_index] = @intCast(u8, index);
78 buf_index += 1;
79 }
80 const array_ptr = &array;
81 for (array_ptr) |item| {
82 buffer[buf_index] = item;
83 buf_index += 1;
84 }
85 for (array_ptr) |item, index| {
86 _ = item;
87 buffer[buf_index] = @intCast(u8, index);
88 buf_index += 1;
89 }
90 const unknown_size: []const u8 = &array;
91 for (unknown_size) |item| {
92 buffer[buf_index] = item;
93 buf_index += 1;
94 }
95 for (unknown_size) |_, index| {
96 buffer[buf_index] = @intCast(u8, index);
97 buf_index += 1;
98 }
99
100 try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
101}
102
103test "for with null and T peer types and inferred result location type" {
104 const S = struct {
105 fn doTheTest(slice: []const u8) !void {
106 if (for (slice) |item| {
107 if (item == 10) {
108 break item;
109 }
110 } else null) |v| {
111 _ = v;
112 @panic("fail");
113 }
114 }
115 };
116 try S.doTheTest(&[_]u8{ 1, 2 });
117 comptime try S.doTheTest(&[_]u8{ 1, 2 });
118}
test/behavior/for_stage1.zig-56
......@@ -26,45 +26,6 @@ fn mangleString(s: []u8) void {
2626 }
2727}
2828
29test "basic for loop" {
30 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
31
32 var buffer: [expected_result.len]u8 = undefined;
33 var buf_index: usize = 0;
34
35 const array = [_]u8{ 9, 8, 7, 6 };
36 for (array) |item| {
37 buffer[buf_index] = item;
38 buf_index += 1;
39 }
40 for (array) |item, index| {
41 _ = item;
42 buffer[buf_index] = @intCast(u8, index);
43 buf_index += 1;
44 }
45 const array_ptr = &array;
46 for (array_ptr) |item| {
47 buffer[buf_index] = item;
48 buf_index += 1;
49 }
50 for (array_ptr) |item, index| {
51 _ = item;
52 buffer[buf_index] = @intCast(u8, index);
53 buf_index += 1;
54 }
55 const unknown_size: []const u8 = &array;
56 for (unknown_size) |item| {
57 buffer[buf_index] = item;
58 buf_index += 1;
59 }
60 for (unknown_size) |_, index| {
61 buffer[buf_index] = @intCast(u8, index);
62 buf_index += 1;
63 }
64
65 try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
66}
67
6829test "2 break statements and an else" {
6930 const S = struct {
7031 fn entry(t: bool, f: bool) !void {
......@@ -82,23 +43,6 @@ test "2 break statements and an else" {
8243 comptime try S.entry(true, false);
8344}
8445
85test "for with null and T peer types and inferred result location type" {
86 const S = struct {
87 fn doTheTest(slice: []const u8) !void {
88 if (for (slice) |item| {
89 if (item == 10) {
90 break item;
91 }
92 } else null) |v| {
93 _ = v;
94 @panic("fail");
95 }
96 }
97 };
98 try S.doTheTest(&[_]u8{ 1, 2 });
99 comptime try S.doTheTest(&[_]u8{ 1, 2 });
100}
101
10246test "for copies its payload" {
10347 const S = struct {
10448 fn doTheTest() !void {
test/behavior/import.zig+2-2
......@@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual;
33const a_namespace = @import("import/a_namespace.zig");
44
55test "call fn via namespace lookup" {
6 try expectEqual(@as(i32, 1234), a_namespace.foo());
6 try expect(@as(i32, 1234) == a_namespace.foo());
77}
88
99test "importing the same thing gives the same import" {
......@@ -14,7 +14,7 @@ test "import in non-toplevel scope" {
1414 const S = struct {
1515 usingnamespace @import("import/a_namespace.zig");
1616 };
17 try expectEqual(@as(i32, 1234), S.foo());
17 try expect(@as(i32, 1234) == S.foo());
1818}
1919
2020test "import empty file" {
test/behavior/null.zig+25
......@@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" {
115115 var x: ?*EmptyStruct = null;
116116 try expect(x == null);
117117}
118
119test "if var maybe pointer" {
120 try expect(shouldBeAPlus1(Particle{
121 .a = 14,
122 .b = 1,
123 .c = 1,
124 .d = 1,
125 }) == 15);
126}
127fn shouldBeAPlus1(p: Particle) u64 {
128 var maybe_particle: ?Particle = p;
129 if (maybe_particle) |*particle| {
130 particle.a += 1;
131 }
132 if (maybe_particle) |particle| {
133 return particle.a;
134 }
135 return 0;
136}
137const Particle = struct {
138 a: u64,
139 b: u64,
140 c: u64,
141 d: u64,
142};
test/behavior/undefined.zig+1-1
......@@ -65,5 +65,5 @@ test "assign undefined to struct with method" {
6565
6666test "type name of undefined" {
6767 const x = undefined;
68 try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)"));
68 try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)"));
6969}
test/behavior/while.zig+37
......@@ -153,6 +153,20 @@ test "while with optional as condition with else" {
153153 try expect(got_else == 1);
154154}
155155
156test "while with error union condition" {
157 numbers_left = 10;
158 var sum: i32 = 0;
159 var got_else: i32 = 0;
160 while (getNumberOrErr()) |value| {
161 sum += value;
162 } else |err| {
163 try expect(err == error.OutOfNumbers);
164 got_else += 1;
165 }
166 try expect(sum == 45);
167 try expect(got_else == 1);
168}
169
156170test "while on bool with else result follow else prong" {
157171 const result = while (returnFalse()) {
158172 break @as(i32, 10);
......@@ -199,3 +213,26 @@ fn returnFalse() bool {
199213fn returnTrue() bool {
200214 return true;
201215}
216
217test "return with implicit cast from while loop" {
218 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
219}
220fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
221 while (true) {
222 return;
223 }
224}
225
226test "while on error union with else result follow else prong" {
227 const result = while (returnError()) |value| {
228 break value;
229 } else |_| @as(i32, 2);
230 try expect(result == 2);
231}
232
233test "while on error union with else result follow break prong" {
234 const result = while (returnSuccess(10)) |value| {
235 break value;
236 } else |_| @as(i32, 2);
237 try expect(result == 10);
238}
test/behavior/while_stage1.zig-70
......@@ -1,76 +1,6 @@
11const std = @import("std");
22const expect = std.testing.expect;
33
4test "return with implicit cast from while loop" {
5 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
6}
7fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
8 while (true) {
9 return;
10 }
11}
12
13test "while with error union condition" {
14 numbers_left = 10;
15 var sum: i32 = 0;
16 var got_else: i32 = 0;
17 while (getNumberOrErr()) |value| {
18 sum += value;
19 } else |err| {
20 try expect(err == error.OutOfNumbers);
21 got_else += 1;
22 }
23 try expect(sum == 45);
24 try expect(got_else == 1);
25}
26
27var numbers_left: i32 = undefined;
28fn getNumberOrErr() anyerror!i32 {
29 return if (numbers_left == 0) error.OutOfNumbers else x: {
30 numbers_left -= 1;
31 break :x numbers_left;
32 };
33}
34fn getNumberOrNull() ?i32 {
35 return if (numbers_left == 0) null else x: {
36 numbers_left -= 1;
37 break :x numbers_left;
38 };
39}
40
41test "while on error union with else result follow else prong" {
42 const result = while (returnError()) |value| {
43 break value;
44 } else |_| @as(i32, 2);
45 try expect(result == 2);
46}
47
48test "while on error union with else result follow break prong" {
49 const result = while (returnSuccess(10)) |value| {
50 break value;
51 } else |_| @as(i32, 2);
52 try expect(result == 10);
53}
54
55fn returnNull() ?i32 {
56 return null;
57}
58fn returnOptional(x: i32) ?i32 {
59 return x;
60}
61fn returnError() anyerror!i32 {
62 return error.YouWantedAnError;
63}
64fn returnSuccess(x: i32) anyerror!i32 {
65 return x;
66}
67fn returnFalse() bool {
68 return false;
69}
70fn returnTrue() bool {
71 return true;
72}
73
744test "while bool 2 break statements and an else" {
755 const S = struct {
766 fn entry(t: bool, f: bool) !void {
test/compile_errors.zig+11-11
......@@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void {
26742674 \\ }
26752675 \\}
26762676 , &[_][]const u8{
2677 "tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'",
2677 "tmp.zig:3:9: error: expected type 'error{Hi}', found '@Type(.EnumLiteral)'",
26782678 });
26792679
26802680 ctx.objErrStage1("@sizeOf bad type",
......@@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void {
26822682 \\ return @sizeOf(@TypeOf(null));
26832683 \\}
26842684 , &[_][]const u8{
2685 "tmp.zig:2:20: error: no size available for type '(null)'",
2685 "tmp.zig:2:20: error: no size available for type '@Type(.Null)'",
26862686 });
26872687
26882688 ctx.objErrStage1("generic function where return type is self-referenced",
......@@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void {
57835783 \\
57845784 \\export fn entry() usize { return @sizeOf(@TypeOf(a)); }
57855785 , &[_][]const u8{
5786 "tmp.zig:1:16: error: expected type '*u8', found '(null)'",
5786 "tmp.zig:1:16: error: expected type '*u8', found '@Type(.Null)'",
57875787 });
57885788
57895789 ctx.objErrStage1("indexing an array of size zero",
......@@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void {
75067506 \\};
75077507 , &[_][]const u8{
75087508 "tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime",
7509 "tmp.zig:6:4: error: variable of type '(undefined)' must be const or comptime",
7509 "tmp.zig:6:4: error: variable of type '@Type(.Undefined)' must be const or comptime",
75107510 "tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",
75117511 "tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
75127512 "tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",
75137513 "tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
7514 "tmp.zig:18:4: error: variable of type '(null)' must be const or comptime",
7514 "tmp.zig:18:4: error: variable of type '@Type(.Null)' must be const or comptime",
75157515 "tmp.zig:22:4: error: variable of type 'Opaque' not allowed",
75167516 "tmp.zig:26:4: error: variable of type 'type' must be const or comptime",
75177517 "tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
......@@ -8278,8 +8278,8 @@ pub fn addCases(ctx: *TestContext) !void {
82788278 , &[_][]const u8{
82798279 "tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",
82808280 "tmp.zig:1:1: note: type declared here",
8281 "tmp.zig:5:18: error: Null return type '(null)' not allowed",
8282 "tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",
8281 "tmp.zig:5:18: error: Null return type '@Type(.Null)' not allowed",
8282 "tmp.zig:8:18: error: Undefined return type '@Type(.Undefined)' not allowed",
82838283 });
82848284
82858285 ctx.objErrStage1("generic function returning opaque type",
......@@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void {
83008300 "tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",
83018301 "tmp.zig:2:1: note: function declared here",
83028302 "tmp.zig:1:1: note: type declared here",
8303 "tmp.zig:9:16: error: call to generic function with Null return type '(null)' not allowed",
8303 "tmp.zig:9:16: error: call to generic function with Null return type '@Type(.Null)' not allowed",
83048304 "tmp.zig:2:1: note: function declared here",
8305 "tmp.zig:12:16: error: call to generic function with Undefined return type '(undefined)' not allowed",
8305 "tmp.zig:12:16: error: call to generic function with Undefined return type '@Type(.Undefined)' not allowed",
83068306 "tmp.zig:2:1: note: function declared here",
83078307 });
83088308
......@@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void {
83298329 \\}
83308330 , &[_][]const u8{
83318331 "tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed",
8332 "tmp.zig:8:28: error: parameter of type '(null)' not allowed",
8332 "tmp.zig:8:28: error: parameter of type '@Type(.Null)' not allowed",
83338333 "tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed",
8334 "tmp.zig:17:11: error: parameter of type '(null)' not allowed",
8334 "tmp.zig:17:11: error: parameter of type '@Type(.Null)' not allowed",
83358335 });
83368336
83378337 ctx.objErrStage1( // fixed bug #2032