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(...@@ -13014,7 +13014,25 @@ fn coerceInMemoryAllowed(
13014 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);13014 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
13015 }13015 }
1301613016
13017 // TODO: arrays13017 // 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
13018 // TODO: non-pointer-like optionals13036 // TODO: non-pointer-like optionals
13019 // TODO: vectors13037 // TODO: vectors
1302013038
...@@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation(...@@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation(
13399 defer parent.finishArena();13417 defer parent.finishArena();
1340013418
13401 const bytes = parent.val.castTag(.bytes).?.data;13419 const bytes = parent.val.castTag(.bytes).?.data;
13402 assert(bytes.len == parent.ty.arrayLenIncludingSentinel());13420 const dest_len = parent.ty.arrayLenIncludingSentinel();
13403 const elems = try arena.alloc(Value, bytes.len);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);
13404 for (elems) |*elem, i| {13425 for (elems) |*elem, i| {
13405 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);13426 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
13406 }13427 }
src/type.zig+25-15
...@@ -2189,8 +2189,8 @@ pub const Type = extern union {...@@ -2189,8 +2189,8 @@ pub const Type = extern union {
2189 }2189 }
21902190
2191 /// Asserts the type has the bit size already resolved.2191 /// Asserts the type has the bit size already resolved.
2192 pub fn bitSize(self: Type, target: Target) u64 {2192 pub fn bitSize(ty: Type, target: Target) u64 {
2193 return switch (self.tag()) {2193 return switch (ty.tag()) {
2194 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer2194 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
2195 .fn_void_no_args => unreachable, // represents machine code; not a pointer2195 .fn_void_no_args => unreachable, // represents machine code; not a pointer
2196 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer2196 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
...@@ -2216,11 +2216,21 @@ pub const Type = extern union {...@@ -2216,11 +2216,21 @@ pub const Type = extern union {
2216 .bound_fn => unreachable,2216 .bound_fn => unreachable,
22172217
2218 .@"struct" => {2218 .@"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;
2220 },2230 },
2221 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {2231 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
2222 var buffer: Payload.Bits = undefined;2232 var buffer: Payload.Bits = undefined;
2223 const int_tag_ty = self.intTagType(&buffer);2233 const int_tag_ty = ty.intTagType(&buffer);
2224 return int_tag_ty.bitSize(target);2234 return int_tag_ty.bitSize(target);
2225 },2235 },
2226 .@"union", .union_tagged => {2236 .@"union", .union_tagged => {
...@@ -2232,21 +2242,21 @@ pub const Type = extern union {...@@ -2232,21 +2242,21 @@ pub const Type = extern union {
2232 .bool, .u1 => 1,2242 .bool, .u1 => 1,
22332243
2234 .vector => {2244 .vector => {
2235 const payload = self.castTag(.vector).?.data;2245 const payload = ty.castTag(.vector).?.data;
2236 const elem_bit_size = payload.elem_type.bitSize(target);2246 const elem_bit_size = payload.elem_type.bitSize(target);
2237 return elem_bit_size * payload.len;2247 return elem_bit_size * payload.len;
2238 },2248 },
2239 .array_u8 => 8 * self.castTag(.array_u8).?.data,2249 .array_u8 => 8 * ty.castTag(.array_u8).?.data,
2240 .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),2250 .array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1),
2241 .array => {2251 .array => {
2242 const payload = self.castTag(.array).?.data;2252 const payload = ty.castTag(.array).?.data;
2243 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));2253 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
2244 if (elem_size == 0 or payload.len == 0)2254 if (elem_size == 0 or payload.len == 0)
2245 return 0;2255 return 0;
2246 return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);2256 return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
2247 },2257 },
2248 .array_sentinel => {2258 .array_sentinel => {
2249 const payload = self.castTag(.array_sentinel).?.data;2259 const payload = ty.castTag(.array_sentinel).?.data;
2250 const elem_size = std.math.max(2260 const elem_size = std.math.max(
2251 payload.elem_type.abiAlignment(target),2261 payload.elem_type.abiAlignment(target),
2252 payload.elem_type.abiSize(target),2262 payload.elem_type.abiSize(target),
...@@ -2267,7 +2277,7 @@ pub const Type = extern union {...@@ -2267,7 +2277,7 @@ pub const Type = extern union {
2267 .const_slice,2277 .const_slice,
2268 .mut_slice,2278 .mut_slice,
2269 => {2279 => {
2270 if (self.elemType().hasCodeGenBits()) {2280 if (ty.elemType().hasCodeGenBits()) {
2271 return target.cpu.arch.ptrBitWidth() * 2;2281 return target.cpu.arch.ptrBitWidth() * 2;
2272 } else {2282 } else {
2273 return target.cpu.arch.ptrBitWidth();2283 return target.cpu.arch.ptrBitWidth();
...@@ -2280,7 +2290,7 @@ pub const Type = extern union {...@@ -2280,7 +2290,7 @@ pub const Type = extern union {
2280 .optional_single_const_pointer,2290 .optional_single_const_pointer,
2281 .optional_single_mut_pointer,2291 .optional_single_mut_pointer,
2282 => {2292 => {
2283 if (self.elemType().hasCodeGenBits()) {2293 if (ty.elemType().hasCodeGenBits()) {
2284 return target.cpu.arch.ptrBitWidth();2294 return target.cpu.arch.ptrBitWidth();
2285 } else {2295 } else {
2286 return 1;2296 return 1;
...@@ -2295,7 +2305,7 @@ pub const Type = extern union {...@@ -2295,7 +2305,7 @@ pub const Type = extern union {
2295 .c_mut_pointer,2305 .c_mut_pointer,
2296 .pointer,2306 .pointer,
2297 => {2307 => {
2298 if (self.elemType().hasCodeGenBits()) {2308 if (ty.elemType().hasCodeGenBits()) {
2299 return target.cpu.arch.ptrBitWidth();2309 return target.cpu.arch.ptrBitWidth();
2300 } else {2310 } else {
2301 return 0;2311 return 0;
...@@ -2325,11 +2335,11 @@ pub const Type = extern union {...@@ -2325,11 +2335,11 @@ pub const Type = extern union {
2325 .error_set_merged,2335 .error_set_merged,
2326 => return 16, // TODO revisit this when we have the concept of the error tag type2336 => 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
2330 .optional => {2340 .optional => {
2331 var buf: Payload.ElemType = undefined;2341 var buf: Payload.ElemType = undefined;
2332 const child_type = self.optionalChild(&buf);2342 const child_type = ty.optionalChild(&buf);
2333 if (!child_type.hasCodeGenBits()) return 8;2343 if (!child_type.hasCodeGenBits()) return 8;
23342344
2335 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())2345 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
...@@ -2343,7 +2353,7 @@ pub const Type = extern union {...@@ -2343,7 +2353,7 @@ pub const Type = extern union {
2343 },2353 },
23442354
2345 .error_union => {2355 .error_union => {
2346 const payload = self.castTag(.error_union).?.data;2356 const payload = ty.castTag(.error_union).?.data;
2347 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {2357 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
2348 return 0;2358 return 0;
2349 } else if (!payload.error_set.hasCodeGenBits()) {2359 } 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...@@ -164,3 +164,53 @@ test "read/write through global variable array of struct fields initialized via
164 };164 };
165 try S.doTheTest();165 try S.doTheTest();
166}166}
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;...@@ -4,29 +4,6 @@ const mem = std.mem;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const 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
30test "implicit cast single-item pointer" {7test "implicit cast single-item pointer" {
31 try testImplicitCastSingleItemPtr();8 try testImplicitCastSingleItemPtr();
32 comptime try testImplicitCastSingleItemPtr();9 comptime try testImplicitCastSingleItemPtr();
...@@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" {...@@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" {
136 comptime try S.entry(2);113 comptime try S.entry(2);
137}114}
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
166test "anonymous literal in array" {116test "anonymous literal in array" {
167 const S = struct {117 const S = struct {
168 const Foo = struct {118 const Foo = struct {
test/behavior/struct_llvm.zig+39
...@@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" {...@@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" {
246 try expect(s.x == 1);246 try expect(s.x == 1);
247 try expect(s.y == 42);247 try expect(s.y == 42);
248}248}
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;...@@ -6,45 +6,6 @@ const expectEqual = std.testing.expectEqual;
6const expectEqualSlices = std.testing.expectEqualSlices;6const expectEqualSlices = std.testing.expectEqualSlices;
7const maxInt = std.math.maxInt;7const 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
48const Foo32Bits = packed struct {9const Foo32Bits = packed struct {
49 field: u24,10 field: u24,
50 pad: u8,11 pad: u8,