authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 22:04:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 22:06:23-07:00
log85d4c8620f602726b159efe1fe2ea0e07e3c5b59
tree73399f38f3a9782a9ecf067eec3cc612d79a4591
parent042b770d6272391a9c25f3444991b439ae07a1b5

Sema: implement array coercion


6 files changed, 138 insertions(+), 107 deletions(-)

src/Sema.zig+24-3
......@@ -13014,7 +13014,25 @@ fn coerceInMemoryAllowed(
1301413014 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
1301513015 }
1301613016
13017 // TODO: arrays
13017 // Arrays
13018 if (dest_tag == .Array and src_tag == .Array) arrays: {
13019 const dest_info = dest_ty.arrayInfo();
13020 const src_info = src_ty.arrayInfo();
13021 if (dest_info.len != src_info.len) break :arrays;
13022
13023 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
13024 if (child == .no_match) {
13025 return child;
13026 }
13027 const ok_sent = dest_info.sentinel == null or
13028 (src_info.sentinel != null and
13029 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type));
13030 if (!ok_sent) {
13031 return .no_match;
13032 }
13033 return .ok;
13034 }
13035
1301813036 // TODO: non-pointer-like optionals
1301913037 // TODO: vectors
1302013038
......@@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation(
1339913417 defer parent.finishArena();
1340013418
1340113419 const bytes = parent.val.castTag(.bytes).?.data;
13402 assert(bytes.len == parent.ty.arrayLenIncludingSentinel());
13403 const elems = try arena.alloc(Value, bytes.len);
13420 const dest_len = parent.ty.arrayLenIncludingSentinel();
13421 // bytes.len may be one greater than dest_len because of the case when
13422 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
13423 assert(bytes.len >= dest_len);
13424 const elems = try arena.alloc(Value, dest_len);
1340413425 for (elems) |*elem, i| {
1340513426 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
1340613427 }
src/type.zig+25-15
......@@ -2189,8 +2189,8 @@ pub const Type = extern union {
21892189 }
21902190
21912191 /// Asserts the type has the bit size already resolved.
2192 pub fn bitSize(self: Type, target: Target) u64 {
2193 return switch (self.tag()) {
2192 pub fn bitSize(ty: Type, target: Target) u64 {
2193 return switch (ty.tag()) {
21942194 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
21952195 .fn_void_no_args => unreachable, // represents machine code; not a pointer
21962196 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
......@@ -2216,11 +2216,21 @@ pub const Type = extern union {
22162216 .bound_fn => unreachable,
22172217
22182218 .@"struct" => {
2219 @panic("TODO bitSize struct");
2219 const field_count = ty.structFieldCount();
2220 if (field_count == 0) return 0;
2221
2222 const struct_obj = ty.castTag(.@"struct").?.data;
2223 assert(struct_obj.status == .have_layout);
2224
2225 var total: u64 = 0;
2226 for (struct_obj.fields.values()) |field| {
2227 total += field.ty.bitSize(target);
2228 }
2229 return total;
22202230 },
22212231 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
22222232 var buffer: Payload.Bits = undefined;
2223 const int_tag_ty = self.intTagType(&buffer);
2233 const int_tag_ty = ty.intTagType(&buffer);
22242234 return int_tag_ty.bitSize(target);
22252235 },
22262236 .@"union", .union_tagged => {
......@@ -2232,21 +2242,21 @@ pub const Type = extern union {
22322242 .bool, .u1 => 1,
22332243
22342244 .vector => {
2235 const payload = self.castTag(.vector).?.data;
2245 const payload = ty.castTag(.vector).?.data;
22362246 const elem_bit_size = payload.elem_type.bitSize(target);
22372247 return elem_bit_size * payload.len;
22382248 },
2239 .array_u8 => 8 * self.castTag(.array_u8).?.data,
2240 .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
2249 .array_u8 => 8 * ty.castTag(.array_u8).?.data,
2250 .array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1),
22412251 .array => {
2242 const payload = self.castTag(.array).?.data;
2252 const payload = ty.castTag(.array).?.data;
22432253 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
22442254 if (elem_size == 0 or payload.len == 0)
22452255 return 0;
22462256 return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
22472257 },
22482258 .array_sentinel => {
2249 const payload = self.castTag(.array_sentinel).?.data;
2259 const payload = ty.castTag(.array_sentinel).?.data;
22502260 const elem_size = std.math.max(
22512261 payload.elem_type.abiAlignment(target),
22522262 payload.elem_type.abiSize(target),
......@@ -2267,7 +2277,7 @@ pub const Type = extern union {
22672277 .const_slice,
22682278 .mut_slice,
22692279 => {
2270 if (self.elemType().hasCodeGenBits()) {
2280 if (ty.elemType().hasCodeGenBits()) {
22712281 return target.cpu.arch.ptrBitWidth() * 2;
22722282 } else {
22732283 return target.cpu.arch.ptrBitWidth();
......@@ -2280,7 +2290,7 @@ pub const Type = extern union {
22802290 .optional_single_const_pointer,
22812291 .optional_single_mut_pointer,
22822292 => {
2283 if (self.elemType().hasCodeGenBits()) {
2293 if (ty.elemType().hasCodeGenBits()) {
22842294 return target.cpu.arch.ptrBitWidth();
22852295 } else {
22862296 return 1;
......@@ -2295,7 +2305,7 @@ pub const Type = extern union {
22952305 .c_mut_pointer,
22962306 .pointer,
22972307 => {
2298 if (self.elemType().hasCodeGenBits()) {
2308 if (ty.elemType().hasCodeGenBits()) {
22992309 return target.cpu.arch.ptrBitWidth();
23002310 } else {
23012311 return 0;
......@@ -2325,11 +2335,11 @@ pub const Type = extern union {
23252335 .error_set_merged,
23262336 => return 16, // TODO revisit this when we have the concept of the error tag type
23272337
2328 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
2338 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data,
23292339
23302340 .optional => {
23312341 var buf: Payload.ElemType = undefined;
2332 const child_type = self.optionalChild(&buf);
2342 const child_type = ty.optionalChild(&buf);
23332343 if (!child_type.hasCodeGenBits()) return 8;
23342344
23352345 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
......@@ -2343,7 +2353,7 @@ pub const Type = extern union {
23432353 },
23442354
23452355 .error_union => {
2346 const payload = self.castTag(.error_union).?.data;
2356 const payload = ty.castTag(.error_union).?.data;
23472357 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
23482358 return 0;
23492359 } else if (!payload.error_set.hasCodeGenBits()) {
test/behavior/array.zig+50
......@@ -164,3 +164,53 @@ test "read/write through global variable array of struct fields initialized via
164164 };
165165 try S.doTheTest();
166166}
167
168test "single-item pointer to array indexing and slicing" {
169 try testSingleItemPtrArrayIndexSlice();
170 comptime try testSingleItemPtrArrayIndexSlice();
171}
172
173fn testSingleItemPtrArrayIndexSlice() !void {
174 {
175 var array: [4]u8 = "aaaa".*;
176 doSomeMangling(&array);
177 try expect(mem.eql(u8, "azya", &array));
178 }
179 {
180 var array = "aaaa".*;
181 doSomeMangling(&array);
182 try expect(mem.eql(u8, "azya", &array));
183 }
184}
185
186fn doSomeMangling(array: *[4]u8) void {
187 array[1] = 'z';
188 array[2..3][0] = 'y';
189}
190
191test "implicit cast zero sized array ptr to slice" {
192 {
193 var b = "".*;
194 const c: []const u8 = &b;
195 try expect(c.len == 0);
196 }
197 {
198 var b: [0]u8 = "".*;
199 const c: []const u8 = &b;
200 try expect(c.len == 0);
201 }
202}
203
204test "anonymous list literal syntax" {
205 const S = struct {
206 fn doTheTest() !void {
207 var array: [4]u8 = .{ 1, 2, 3, 4 };
208 try expect(array[0] == 1);
209 try expect(array[1] == 2);
210 try expect(array[2] == 3);
211 try expect(array[3] == 4);
212 }
213 };
214 try S.doTheTest();
215 comptime try S.doTheTest();
216}
test/behavior/array_stage1.zig-50
......@@ -4,29 +4,6 @@ const mem = std.mem;
44const expect = testing.expect;
55const expectEqual = testing.expectEqual;
66
7test "single-item pointer to array indexing and slicing" {
8 try testSingleItemPtrArrayIndexSlice();
9 comptime try testSingleItemPtrArrayIndexSlice();
10}
11
12fn testSingleItemPtrArrayIndexSlice() !void {
13 {
14 var array: [4]u8 = "aaaa".*;
15 doSomeMangling(&array);
16 try expect(mem.eql(u8, "azya", &array));
17 }
18 {
19 var array = "aaaa".*;
20 doSomeMangling(&array);
21 try expect(mem.eql(u8, "azya", &array));
22 }
23}
24
25fn doSomeMangling(array: *[4]u8) void {
26 array[1] = 'z';
27 array[2..3][0] = 'y';
28}
29
307test "implicit cast single-item pointer" {
318 try testImplicitCastSingleItemPtr();
329 comptime try testImplicitCastSingleItemPtr();
......@@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" {
136113 comptime try S.entry(2);
137114}
138115
139test "implicit cast zero sized array ptr to slice" {
140 {
141 var b = "".*;
142 const c: []const u8 = &b;
143 try expect(c.len == 0);
144 }
145 {
146 var b: [0]u8 = "".*;
147 const c: []const u8 = &b;
148 try expect(c.len == 0);
149 }
150}
151
152test "anonymous list literal syntax" {
153 const S = struct {
154 fn doTheTest() !void {
155 var array: [4]u8 = .{ 1, 2, 3, 4 };
156 try expect(array[0] == 1);
157 try expect(array[1] == 2);
158 try expect(array[2] == 3);
159 try expect(array[3] == 4);
160 }
161 };
162 try S.doTheTest();
163 comptime try S.doTheTest();
164}
165
166116test "anonymous literal in array" {
167117 const S = struct {
168118 const Foo = struct {
test/behavior/struct_llvm.zig+39
......@@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" {
246246 try expect(s.x == 1);
247247 try expect(s.y == 42);
248248}
249
250const BitField1 = packed struct {
251 a: u3,
252 b: u3,
253 c: u2,
254};
255
256const bit_field_1 = BitField1{
257 .a = 1,
258 .b = 2,
259 .c = 3,
260};
261
262test "bit field access" {
263 var data = bit_field_1;
264 try expect(getA(&data) == 1);
265 try expect(getB(&data) == 2);
266 try expect(getC(&data) == 3);
267 comptime try expect(@sizeOf(BitField1) == 1);
268
269 data.b += 1;
270 try expect(data.b == 3);
271
272 data.a += 1;
273 try expect(data.a == 2);
274 try expect(data.b == 3);
275}
276
277fn getA(data: *const BitField1) u3 {
278 return data.a;
279}
280
281fn getB(data: *const BitField1) u3 {
282 return data.b;
283}
284
285fn getC(data: *const BitField1) u2 {
286 return data.c;
287}
test/behavior/struct_stage1.zig-39
......@@ -6,45 +6,6 @@ const expectEqual = std.testing.expectEqual;
66const expectEqualSlices = std.testing.expectEqualSlices;
77const maxInt = std.math.maxInt;
88
9const BitField1 = packed struct {
10 a: u3,
11 b: u3,
12 c: u2,
13};
14
15const bit_field_1 = BitField1{
16 .a = 1,
17 .b = 2,
18 .c = 3,
19};
20
21test "bit field access" {
22 var data = bit_field_1;
23 try expect(getA(&data) == 1);
24 try expect(getB(&data) == 2);
25 try expect(getC(&data) == 3);
26 comptime try expect(@sizeOf(BitField1) == 1);
27
28 data.b += 1;
29 try expect(data.b == 3);
30
31 data.a += 1;
32 try expect(data.a == 2);
33 try expect(data.b == 3);
34}
35
36fn getA(data: *const BitField1) u3 {
37 return data.a;
38}
39
40fn getB(data: *const BitField1) u3 {
41 return data.b;
42}
43
44fn getC(data: *const BitField1) u2 {
45 return data.c;
46}
47
489const Foo32Bits = packed struct {
4910 field: u24,
5011 pad: u8,