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...@@ -2771,20 +2771,16 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
2771 // expression of a variable declaration. We need the memory to be in the new2771 // expression of a variable declaration. We need the memory to be in the new
2772 // anonymous Decl's arena.2772 // anonymous Decl's arena.
27732773
2774 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);2774 var anon_decl = try block.startAnonDecl();
2775 errdefer new_decl_arena.deinit();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);2779 const new_decl = try anon_decl.finish(
2780 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes[0 .. bytes.len + 1]);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);
2788 return sema.analyzeDeclRef(new_decl);2784 return sema.analyzeDeclRef(new_decl);
2789}2785}
27902786
...@@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
97419737
9742fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9738fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9743 const inst_data = sema.code.instructions.items(.data)[inst].un_node;9739 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
9744 const src = inst_data.src();9740 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9745 return sema.fail(block, src, "TODO: Sema.zirTypeName", .{});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);
9746}9754}
97479755
9748fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9756fn 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) {...@@ -8755,17 +8755,17 @@ static void define_builtin_types(CodeGen *g) {
8755 }8755 }
8756 {8756 {
8757 ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral);8757 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)");
8759 g->builtin_types.entry_enum_literal = entry;8759 g->builtin_types.entry_enum_literal = entry;
8760 }8760 }
8761 {8761 {
8762 ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);8762 ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);
8763 buf_init_from_str(&entry->name, "(undefined)");8763 buf_init_from_str(&entry->name, "@Type(.Undefined)");
8764 g->builtin_types.entry_undef = entry;8764 g->builtin_types.entry_undef = entry;
8765 }8765 }
8766 {8766 {
8767 ZigType *entry = new_type_table_entry(ZigTypeIdNull);8767 ZigType *entry = new_type_table_entry(ZigTypeIdNull);
8768 buf_init_from_str(&entry->name, "(null)");8768 buf_init_from_str(&entry->name, "@Type(.Null)");
8769 g->builtin_types.entry_null = entry;8769 g->builtin_types.entry_null = entry;
8770 }8770 }
8771 {8771 {
src/type.zig+107
...@@ -1197,6 +1197,113 @@ pub const Type = extern union {...@@ -1197,6 +1197,113 @@ pub const Type = extern union {
1197 }1197 }
1198 }1198 }
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
1200 /// Anything that reports hasCodeGenBits() false returns false here as well.1307 /// Anything that reports hasCodeGenBits() false returns false here as well.
1201 /// `generic_poison` will return false.1308 /// `generic_poison` will return false.
1202 pub fn requiresComptime(ty: Type) bool {1309 pub fn requiresComptime(ty: Type) bool {
test/behavior.zig+3-4
...@@ -24,11 +24,11 @@ test {...@@ -24,11 +24,11 @@ test {
24 _ = @import("behavior/defer.zig");24 _ = @import("behavior/defer.zig");
25 _ = @import("behavior/enum.zig");25 _ = @import("behavior/enum.zig");
26 _ = @import("behavior/error.zig");26 _ = @import("behavior/error.zig");
27 _ = @import("behavior/error.zig");
28 _ = @import("behavior/generics.zig");27 _ = @import("behavior/generics.zig");
29 _ = @import("behavior/hasdecl.zig");28 _ = @import("behavior/hasdecl.zig");
30 _ = @import("behavior/hasfield.zig");29 _ = @import("behavior/hasfield.zig");
31 _ = @import("behavior/if.zig");30 _ = @import("behavior/if.zig");
31 _ = @import("behavior/import.zig");
32 _ = @import("behavior/int128.zig");32 _ = @import("behavior/int128.zig");
33 _ = @import("behavior/member_func.zig");33 _ = @import("behavior/member_func.zig");
34 _ = @import("behavior/null.zig");34 _ = @import("behavior/null.zig");
...@@ -73,7 +73,9 @@ test {...@@ -73,7 +73,9 @@ test {
73 _ = @import("behavior/slice.zig");73 _ = @import("behavior/slice.zig");
74 _ = @import("behavior/struct_llvm.zig");74 _ = @import("behavior/struct_llvm.zig");
75 _ = @import("behavior/switch.zig");75 _ = @import("behavior/switch.zig");
76 _ = @import("behavior/undefined.zig");
76 _ = @import("behavior/union.zig");77 _ = @import("behavior/union.zig");
78 _ = @import("behavior/void.zig");
77 _ = @import("behavior/widening.zig");79 _ = @import("behavior/widening.zig");
7880
79 if (builtin.zig_is_stage2) {81 if (builtin.zig_is_stage2) {
...@@ -151,7 +153,6 @@ test {...@@ -151,7 +153,6 @@ test {
151 _ = @import("behavior/fn_in_struct_in_comptime.zig");153 _ = @import("behavior/fn_in_struct_in_comptime.zig");
152 _ = @import("behavior/for_stage1.zig");154 _ = @import("behavior/for_stage1.zig");
153 _ = @import("behavior/if_stage1.zig");155 _ = @import("behavior/if_stage1.zig");
154 _ = @import("behavior/import.zig");
155 _ = @import("behavior/incomplete_struct_param_tld.zig");156 _ = @import("behavior/incomplete_struct_param_tld.zig");
156 _ = @import("behavior/inttoptr.zig");157 _ = @import("behavior/inttoptr.zig");
157 _ = @import("behavior/ir_block_deps.zig");158 _ = @import("behavior/ir_block_deps.zig");
...@@ -183,13 +184,11 @@ test {...@@ -183,13 +184,11 @@ test {
183 _ = @import("behavior/type.zig");184 _ = @import("behavior/type.zig");
184 _ = @import("behavior/type_info.zig");185 _ = @import("behavior/type_info.zig");
185 _ = @import("behavior/typename.zig");186 _ = @import("behavior/typename.zig");
186 _ = @import("behavior/undefined.zig");
187 _ = @import("behavior/union_stage1.zig");187 _ = @import("behavior/union_stage1.zig");
188 _ = @import("behavior/union_with_members.zig");188 _ = @import("behavior/union_with_members.zig");
189 _ = @import("behavior/usingnamespace_stage1.zig");189 _ = @import("behavior/usingnamespace_stage1.zig");
190 _ = @import("behavior/var_args.zig");190 _ = @import("behavior/var_args.zig");
191 _ = @import("behavior/vector.zig");191 _ = @import("behavior/vector.zig");
192 _ = @import("behavior/void.zig");
193 if (builtin.target.cpu.arch == .wasm32) {192 if (builtin.target.cpu.arch == .wasm32) {
194 _ = @import("behavior/wasm.zig");193 _ = @import("behavior/wasm.zig");
195 }194 }
test/behavior/enum.zig+22
...@@ -583,3 +583,25 @@ test "peer type resolution with enum literal" {...@@ -583,3 +583,25 @@ test "peer type resolution with enum literal" {
583 try expect(Items.two == .two);583 try expect(Items.two == .two);
584 try expect(.two == Items.two);584 try expect(.two == Items.two);
585}585}
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;...@@ -2,28 +2,6 @@ const expect = @import("std").testing.expect;
2const mem = @import("std").mem;2const mem = @import("std").mem;
3const Tag = @import("std").meta.Tag;3const 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
27test "non-exhaustive enum" {5test "non-exhaustive enum" {
28 const S = struct {6 const S = struct {
29 const E = enum(u8) {7 const E = enum(u8) {
test/behavior/fn.zig+81
...@@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {...@@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
163test "function with complex callconv and return type expressions" {163test "function with complex callconv and return type expressions" {
164 try expect(fComplexCallconvRet(3).x == 9);164 try expect(fComplexCallconvRet(3).x == 9);
165}165}
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 {...@@ -56,87 +56,6 @@ fn numberLiteralArg(a: anytype) !void {
56 try expect(a == 3);56 try expect(a == 3);
57}57}
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
140test "function call with anon list literal" {59test "function call with anon list literal" {
141 const S = struct {60 const S = struct {
142 fn doTheTest() !void {61 fn doTheTest() !void {
test/behavior/for.zig+56
...@@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" {...@@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" {
60 break;60 break;
61 }61 }
62}62}
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 {...@@ -26,45 +26,6 @@ fn mangleString(s: []u8) void {
26 }26 }
27}27}
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
68test "2 break statements and an else" {29test "2 break statements and an else" {
69 const S = struct {30 const S = struct {
70 fn entry(t: bool, f: bool) !void {31 fn entry(t: bool, f: bool) !void {
...@@ -82,23 +43,6 @@ test "2 break statements and an else" {...@@ -82,23 +43,6 @@ test "2 break statements and an else" {
82 comptime try S.entry(true, false);43 comptime try S.entry(true, false);
83}44}
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
102test "for copies its payload" {46test "for copies its payload" {
103 const S = struct {47 const S = struct {
104 fn doTheTest() !void {48 fn doTheTest() !void {
test/behavior/import.zig+2-2
...@@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual;...@@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual;
3const a_namespace = @import("import/a_namespace.zig");3const a_namespace = @import("import/a_namespace.zig");
44
5test "call fn via namespace lookup" {5test "call fn via namespace lookup" {
6 try expectEqual(@as(i32, 1234), a_namespace.foo());6 try expect(@as(i32, 1234) == a_namespace.foo());
7}7}
88
9test "importing the same thing gives the same import" {9test "importing the same thing gives the same import" {
...@@ -14,7 +14,7 @@ test "import in non-toplevel scope" {...@@ -14,7 +14,7 @@ test "import in non-toplevel scope" {
14 const S = struct {14 const S = struct {
15 usingnamespace @import("import/a_namespace.zig");15 usingnamespace @import("import/a_namespace.zig");
16 };16 };
17 try expectEqual(@as(i32, 1234), S.foo());17 try expect(@as(i32, 1234) == S.foo());
18}18}
1919
20test "import empty file" {20test "import empty file" {
test/behavior/null.zig+25
...@@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" {...@@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" {
115 var x: ?*EmptyStruct = null;115 var x: ?*EmptyStruct = null;
116 try expect(x == null);116 try expect(x == null);
117}117}
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" {...@@ -65,5 +65,5 @@ test "assign undefined to struct with method" {
6565
66test "type name of undefined" {66test "type name of undefined" {
67 const x = undefined;67 const x = undefined;
68 try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)"));68 try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)"));
69}69}
test/behavior/while.zig+37
...@@ -153,6 +153,20 @@ test "while with optional as condition with else" {...@@ -153,6 +153,20 @@ test "while with optional as condition with else" {
153 try expect(got_else == 1);153 try expect(got_else == 1);
154}154}
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
156test "while on bool with else result follow else prong" {170test "while on bool with else result follow else prong" {
157 const result = while (returnFalse()) {171 const result = while (returnFalse()) {
158 break @as(i32, 10);172 break @as(i32, 10);
...@@ -199,3 +213,26 @@ fn returnFalse() bool {...@@ -199,3 +213,26 @@ fn returnFalse() bool {
199fn returnTrue() bool {213fn returnTrue() bool {
200 return true;214 return true;
201}215}
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 @@...@@ -1,76 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const 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
74test "while bool 2 break statements and an else" {4test "while bool 2 break statements and an else" {
75 const S = struct {5 const S = struct {
76 fn entry(t: bool, f: bool) !void {6 fn entry(t: bool, f: bool) !void {
test/compile_errors.zig+11-11
...@@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void {
2674 \\ }2674 \\ }
2675 \\}2675 \\}
2676 , &[_][]const u8{2676 , &[_][]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)'",
2678 });2678 });
26792679
2680 ctx.objErrStage1("@sizeOf bad type",2680 ctx.objErrStage1("@sizeOf bad type",
...@@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void {
2682 \\ return @sizeOf(@TypeOf(null));2682 \\ return @sizeOf(@TypeOf(null));
2683 \\}2683 \\}
2684 , &[_][]const u8{2684 , &[_][]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)'",
2686 });2686 });
26872687
2688 ctx.objErrStage1("generic function where return type is self-referenced",2688 ctx.objErrStage1("generic function where return type is self-referenced",
...@@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void {
5783 \\5783 \\
5784 \\export fn entry() usize { return @sizeOf(@TypeOf(a)); }5784 \\export fn entry() usize { return @sizeOf(@TypeOf(a)); }
5785 , &[_][]const u8{5785 , &[_][]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)'",
5787 });5787 });
57885788
5789 ctx.objErrStage1("indexing an array of size zero",5789 ctx.objErrStage1("indexing an array of size zero",
...@@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void {
7506 \\};7506 \\};
7507 , &[_][]const u8{7507 , &[_][]const u8{
7508 "tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime",7508 "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",
7510 "tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",7510 "tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",
7511 "tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",7511 "tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
7512 "tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",7512 "tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",
7513 "tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",7513 "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",
7515 "tmp.zig:22:4: error: variable of type 'Opaque' not allowed",7515 "tmp.zig:22:4: error: variable of type 'Opaque' not allowed",
7516 "tmp.zig:26:4: error: variable of type 'type' must be const or comptime",7516 "tmp.zig:26:4: error: variable of type 'type' must be const or comptime",
7517 "tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",7517 "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 {...@@ -8278,8 +8278,8 @@ pub fn addCases(ctx: *TestContext) !void {
8278 , &[_][]const u8{8278 , &[_][]const u8{
8279 "tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",8279 "tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",
8280 "tmp.zig:1:1: note: type declared here",8280 "tmp.zig:1:1: note: type declared here",
8281 "tmp.zig:5:18: error: Null return type '(null)' not allowed",8281 "tmp.zig:5:18: error: Null return type '@Type(.Null)' not allowed",
8282 "tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",8282 "tmp.zig:8:18: error: Undefined return type '@Type(.Undefined)' not allowed",
8283 });8283 });
82848284
8285 ctx.objErrStage1("generic function returning opaque type",8285 ctx.objErrStage1("generic function returning opaque type",
...@@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void {
8300 "tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",8300 "tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",
8301 "tmp.zig:2:1: note: function declared here",8301 "tmp.zig:2:1: note: function declared here",
8302 "tmp.zig:1:1: note: type declared here",8302 "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",
8304 "tmp.zig:2:1: note: function declared here",8304 "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",
8306 "tmp.zig:2:1: note: function declared here",8306 "tmp.zig:2:1: note: function declared here",
8307 });8307 });
83088308
...@@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void {
8329 \\}8329 \\}
8330 , &[_][]const u8{8330 , &[_][]const u8{
8331 "tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed",8331 "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",
8333 "tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed",8333 "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",
8335 });8335 });
83368336
8337 ctx.objErrStage1( // fixed bug #20328337 ctx.objErrStage1( // fixed bug #2032