mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 10:28:48 +00:00
Sema: implement array coercion
This commit is contained in:
parent
042b770d62
commit
85d4c8620f
27
src/Sema.zig
27
src/Sema.zig
@ -13014,7 +13014,25 @@ fn coerceInMemoryAllowed(
|
||||
return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
|
||||
}
|
||||
|
||||
// TODO: arrays
|
||||
// Arrays
|
||||
if (dest_tag == .Array and src_tag == .Array) arrays: {
|
||||
const dest_info = dest_ty.arrayInfo();
|
||||
const src_info = src_ty.arrayInfo();
|
||||
if (dest_info.len != src_info.len) break :arrays;
|
||||
|
||||
const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
|
||||
if (child == .no_match) {
|
||||
return child;
|
||||
}
|
||||
const ok_sent = dest_info.sentinel == null or
|
||||
(src_info.sentinel != null and
|
||||
dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type));
|
||||
if (!ok_sent) {
|
||||
return .no_match;
|
||||
}
|
||||
return .ok;
|
||||
}
|
||||
|
||||
// TODO: non-pointer-like optionals
|
||||
// TODO: vectors
|
||||
|
||||
@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation(
|
||||
defer parent.finishArena();
|
||||
|
||||
const bytes = parent.val.castTag(.bytes).?.data;
|
||||
assert(bytes.len == parent.ty.arrayLenIncludingSentinel());
|
||||
const elems = try arena.alloc(Value, bytes.len);
|
||||
const dest_len = parent.ty.arrayLenIncludingSentinel();
|
||||
// bytes.len may be one greater than dest_len because of the case when
|
||||
// assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
|
||||
assert(bytes.len >= dest_len);
|
||||
const elems = try arena.alloc(Value, dest_len);
|
||||
for (elems) |*elem, i| {
|
||||
elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
|
||||
}
|
||||
|
40
src/type.zig
40
src/type.zig
@ -2189,8 +2189,8 @@ pub const Type = extern union {
|
||||
}
|
||||
|
||||
/// Asserts the type has the bit size already resolved.
|
||||
pub fn bitSize(self: Type, target: Target) u64 {
|
||||
return switch (self.tag()) {
|
||||
pub fn bitSize(ty: Type, target: Target) u64 {
|
||||
return switch (ty.tag()) {
|
||||
.fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
|
||||
.fn_void_no_args => unreachable, // represents machine code; not a pointer
|
||||
.fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
|
||||
@ -2216,11 +2216,21 @@ pub const Type = extern union {
|
||||
.bound_fn => unreachable,
|
||||
|
||||
.@"struct" => {
|
||||
@panic("TODO bitSize struct");
|
||||
const field_count = ty.structFieldCount();
|
||||
if (field_count == 0) return 0;
|
||||
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
assert(struct_obj.status == .have_layout);
|
||||
|
||||
var total: u64 = 0;
|
||||
for (struct_obj.fields.values()) |field| {
|
||||
total += field.ty.bitSize(target);
|
||||
}
|
||||
return total;
|
||||
},
|
||||
.enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
|
||||
var buffer: Payload.Bits = undefined;
|
||||
const int_tag_ty = self.intTagType(&buffer);
|
||||
const int_tag_ty = ty.intTagType(&buffer);
|
||||
return int_tag_ty.bitSize(target);
|
||||
},
|
||||
.@"union", .union_tagged => {
|
||||
@ -2232,21 +2242,21 @@ pub const Type = extern union {
|
||||
.bool, .u1 => 1,
|
||||
|
||||
.vector => {
|
||||
const payload = self.castTag(.vector).?.data;
|
||||
const payload = ty.castTag(.vector).?.data;
|
||||
const elem_bit_size = payload.elem_type.bitSize(target);
|
||||
return elem_bit_size * payload.len;
|
||||
},
|
||||
.array_u8 => 8 * self.castTag(.array_u8).?.data,
|
||||
.array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
|
||||
.array_u8 => 8 * ty.castTag(.array_u8).?.data,
|
||||
.array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1),
|
||||
.array => {
|
||||
const payload = self.castTag(.array).?.data;
|
||||
const payload = ty.castTag(.array).?.data;
|
||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
if (elem_size == 0 or payload.len == 0)
|
||||
return 0;
|
||||
return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
|
||||
},
|
||||
.array_sentinel => {
|
||||
const payload = self.castTag(.array_sentinel).?.data;
|
||||
const payload = ty.castTag(.array_sentinel).?.data;
|
||||
const elem_size = std.math.max(
|
||||
payload.elem_type.abiAlignment(target),
|
||||
payload.elem_type.abiSize(target),
|
||||
@ -2267,7 +2277,7 @@ pub const Type = extern union {
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
if (ty.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth() * 2;
|
||||
} else {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
@ -2280,7 +2290,7 @@ pub const Type = extern union {
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
if (ty.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
} else {
|
||||
return 1;
|
||||
@ -2295,7 +2305,7 @@ pub const Type = extern union {
|
||||
.c_mut_pointer,
|
||||
.pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
if (ty.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
} else {
|
||||
return 0;
|
||||
@ -2325,11 +2335,11 @@ pub const Type = extern union {
|
||||
.error_set_merged,
|
||||
=> return 16, // TODO revisit this when we have the concept of the error tag type
|
||||
|
||||
.int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
|
||||
.int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data,
|
||||
|
||||
.optional => {
|
||||
var buf: Payload.ElemType = undefined;
|
||||
const child_type = self.optionalChild(&buf);
|
||||
const child_type = ty.optionalChild(&buf);
|
||||
if (!child_type.hasCodeGenBits()) return 8;
|
||||
|
||||
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
|
||||
@ -2343,7 +2353,7 @@ pub const Type = extern union {
|
||||
},
|
||||
|
||||
.error_union => {
|
||||
const payload = self.castTag(.error_union).?.data;
|
||||
const payload = ty.castTag(.error_union).?.data;
|
||||
if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
|
||||
return 0;
|
||||
} else if (!payload.error_set.hasCodeGenBits()) {
|
||||
|
@ -164,3 +164,53 @@ test "read/write through global variable array of struct fields initialized via
|
||||
};
|
||||
try S.doTheTest();
|
||||
}
|
||||
|
||||
test "single-item pointer to array indexing and slicing" {
|
||||
try testSingleItemPtrArrayIndexSlice();
|
||||
comptime try testSingleItemPtrArrayIndexSlice();
|
||||
}
|
||||
|
||||
fn testSingleItemPtrArrayIndexSlice() !void {
|
||||
{
|
||||
var array: [4]u8 = "aaaa".*;
|
||||
doSomeMangling(&array);
|
||||
try expect(mem.eql(u8, "azya", &array));
|
||||
}
|
||||
{
|
||||
var array = "aaaa".*;
|
||||
doSomeMangling(&array);
|
||||
try expect(mem.eql(u8, "azya", &array));
|
||||
}
|
||||
}
|
||||
|
||||
fn doSomeMangling(array: *[4]u8) void {
|
||||
array[1] = 'z';
|
||||
array[2..3][0] = 'y';
|
||||
}
|
||||
|
||||
test "implicit cast zero sized array ptr to slice" {
|
||||
{
|
||||
var b = "".*;
|
||||
const c: []const u8 = &b;
|
||||
try expect(c.len == 0);
|
||||
}
|
||||
{
|
||||
var b: [0]u8 = "".*;
|
||||
const c: []const u8 = &b;
|
||||
try expect(c.len == 0);
|
||||
}
|
||||
}
|
||||
|
||||
test "anonymous list literal syntax" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var array: [4]u8 = .{ 1, 2, 3, 4 };
|
||||
try expect(array[0] == 1);
|
||||
try expect(array[1] == 2);
|
||||
try expect(array[2] == 3);
|
||||
try expect(array[3] == 4);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
@ -4,29 +4,6 @@ const mem = std.mem;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "single-item pointer to array indexing and slicing" {
|
||||
try testSingleItemPtrArrayIndexSlice();
|
||||
comptime try testSingleItemPtrArrayIndexSlice();
|
||||
}
|
||||
|
||||
fn testSingleItemPtrArrayIndexSlice() !void {
|
||||
{
|
||||
var array: [4]u8 = "aaaa".*;
|
||||
doSomeMangling(&array);
|
||||
try expect(mem.eql(u8, "azya", &array));
|
||||
}
|
||||
{
|
||||
var array = "aaaa".*;
|
||||
doSomeMangling(&array);
|
||||
try expect(mem.eql(u8, "azya", &array));
|
||||
}
|
||||
}
|
||||
|
||||
fn doSomeMangling(array: *[4]u8) void {
|
||||
array[1] = 'z';
|
||||
array[2..3][0] = 'y';
|
||||
}
|
||||
|
||||
test "implicit cast single-item pointer" {
|
||||
try testImplicitCastSingleItemPtr();
|
||||
comptime try testImplicitCastSingleItemPtr();
|
||||
@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" {
|
||||
comptime try S.entry(2);
|
||||
}
|
||||
|
||||
test "implicit cast zero sized array ptr to slice" {
|
||||
{
|
||||
var b = "".*;
|
||||
const c: []const u8 = &b;
|
||||
try expect(c.len == 0);
|
||||
}
|
||||
{
|
||||
var b: [0]u8 = "".*;
|
||||
const c: []const u8 = &b;
|
||||
try expect(c.len == 0);
|
||||
}
|
||||
}
|
||||
|
||||
test "anonymous list literal syntax" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var array: [4]u8 = .{ 1, 2, 3, 4 };
|
||||
try expect(array[0] == 1);
|
||||
try expect(array[1] == 2);
|
||||
try expect(array[2] == 3);
|
||||
try expect(array[3] == 4);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "anonymous literal in array" {
|
||||
const S = struct {
|
||||
const Foo = struct {
|
||||
|
@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" {
|
||||
try expect(s.x == 1);
|
||||
try expect(s.y == 42);
|
||||
}
|
||||
|
||||
const BitField1 = packed struct {
|
||||
a: u3,
|
||||
b: u3,
|
||||
c: u2,
|
||||
};
|
||||
|
||||
const bit_field_1 = BitField1{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
};
|
||||
|
||||
test "bit field access" {
|
||||
var data = bit_field_1;
|
||||
try expect(getA(&data) == 1);
|
||||
try expect(getB(&data) == 2);
|
||||
try expect(getC(&data) == 3);
|
||||
comptime try expect(@sizeOf(BitField1) == 1);
|
||||
|
||||
data.b += 1;
|
||||
try expect(data.b == 3);
|
||||
|
||||
data.a += 1;
|
||||
try expect(data.a == 2);
|
||||
try expect(data.b == 3);
|
||||
}
|
||||
|
||||
fn getA(data: *const BitField1) u3 {
|
||||
return data.a;
|
||||
}
|
||||
|
||||
fn getB(data: *const BitField1) u3 {
|
||||
return data.b;
|
||||
}
|
||||
|
||||
fn getC(data: *const BitField1) u2 {
|
||||
return data.c;
|
||||
}
|
||||
|
@ -6,45 +6,6 @@ const expectEqual = std.testing.expectEqual;
|
||||
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
const BitField1 = packed struct {
|
||||
a: u3,
|
||||
b: u3,
|
||||
c: u2,
|
||||
};
|
||||
|
||||
const bit_field_1 = BitField1{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
};
|
||||
|
||||
test "bit field access" {
|
||||
var data = bit_field_1;
|
||||
try expect(getA(&data) == 1);
|
||||
try expect(getB(&data) == 2);
|
||||
try expect(getC(&data) == 3);
|
||||
comptime try expect(@sizeOf(BitField1) == 1);
|
||||
|
||||
data.b += 1;
|
||||
try expect(data.b == 3);
|
||||
|
||||
data.a += 1;
|
||||
try expect(data.a == 2);
|
||||
try expect(data.b == 3);
|
||||
}
|
||||
|
||||
fn getA(data: *const BitField1) u3 {
|
||||
return data.a;
|
||||
}
|
||||
|
||||
fn getB(data: *const BitField1) u3 {
|
||||
return data.b;
|
||||
}
|
||||
|
||||
fn getC(data: *const BitField1) u2 {
|
||||
return data.c;
|
||||
}
|
||||
|
||||
const Foo32Bits = packed struct {
|
||||
field: u24,
|
||||
pad: u8,
|
||||
|
Loading…
Reference in New Issue
Block a user