authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 17:33:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 17:33:01-07:00
logf32a77b30df48552897a5c9023c39d8ba6610821
tree0a12927beef0a93bbfeb6ab02989b48b94b30eb9
parent3b6e8fa59e6fb933e8279ba676ef986739665247

Sema: implement pointer-to-tuple coercion to slice and struct


5 files changed, 86 insertions(+), 23 deletions(-)

src/Sema.zig+75-13
......@@ -16052,13 +16052,38 @@ fn coerce(
1605216052 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1605316053 }
1605416054
16055 // cast from pointer to anonymous struct to pointer to union
16056 if (dest_info.pointee_type.zigTypeTag() == .Union and
16057 inst_ty.zigTypeTag() == .Pointer and
16058 inst_ty.childType().tag() == .anon_struct and
16059 !dest_info.mutable)
16060 {
16061 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
16055 switch (dest_info.size) {
16056 .C, .Many => {},
16057 .One => switch (dest_info.pointee_type.zigTypeTag()) {
16058 .Union => {
16059 // cast from pointer to anonymous struct to pointer to union
16060 if (inst_ty.isSinglePointer() and
16061 inst_ty.childType().isAnonStruct() and
16062 !dest_info.mutable)
16063 {
16064 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
16065 }
16066 },
16067 .Struct => {
16068 // cast from pointer to anonymous struct to pointer to struct
16069 if (inst_ty.isSinglePointer() and
16070 inst_ty.childType().isAnonStruct() and
16071 !dest_info.mutable)
16072 {
16073 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
16074 }
16075 },
16076 else => {},
16077 },
16078 .Slice => {
16079 // pointer to tuple to slice
16080 if (inst_ty.isSinglePointer() and
16081 inst_ty.childType().isTuple() and
16082 !dest_info.mutable and dest_info.size == .Slice)
16083 {
16084 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
16085 }
16086 },
1606216087 }
1606316088
1606416089 // This will give an extra hint on top of what the bottom of this func would provide.
......@@ -17365,6 +17390,20 @@ fn coerceAnonStructToUnionPtrs(
1736517390 return sema.analyzeRef(block, union_ty_src, union_inst);
1736617391}
1736717392
17393fn coerceAnonStructToStructPtrs(
17394 sema: *Sema,
17395 block: *Block,
17396 ptr_struct_ty: Type,
17397 struct_ty_src: LazySrcLoc,
17398 ptr_anon_struct: Air.Inst.Ref,
17399 anon_struct_src: LazySrcLoc,
17400) !Air.Inst.Ref {
17401 const struct_ty = ptr_struct_ty.childType();
17402 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
17403 const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, struct_ty_src, anon_struct, anon_struct_src);
17404 return sema.analyzeRef(block, struct_ty_src, struct_inst);
17405}
17406
1736817407/// If the lengths match, coerces element-wise.
1736917408fn coerceArrayLike(
1737017409 sema: *Sema,
......@@ -17494,6 +17533,27 @@ fn coerceTupleToArray(
1749417533 );
1749517534}
1749617535
17536/// If the lengths match, coerces element-wise.
17537fn coerceTupleToSlicePtrs(
17538 sema: *Sema,
17539 block: *Block,
17540 slice_ty: Type,
17541 slice_ty_src: LazySrcLoc,
17542 ptr_tuple: Air.Inst.Ref,
17543 tuple_src: LazySrcLoc,
17544) !Air.Inst.Ref {
17545 const tuple_ty = sema.typeOf(ptr_tuple).childType();
17546 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
17547 const slice_info = slice_ty.ptrInfo().data;
17548 const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type);
17549 const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
17550 if (slice_info.@"align" != 0) {
17551 return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
17552 }
17553 const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst);
17554 return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
17555}
17556
1749717557/// Handles both tuples and anon struct literals. Coerces field-wise. Reports
1749817558/// errors for both extra fields and missing fields.
1749917559fn coerceTupleToStruct(
......@@ -17504,11 +17564,13 @@ fn coerceTupleToStruct(
1750417564 inst: Air.Inst.Ref,
1750517565 inst_src: LazySrcLoc,
1750617566) !Air.Inst.Ref {
17507 if (dest_ty.isTupleOrAnonStruct()) {
17567 const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);
17568
17569 if (struct_ty.isTupleOrAnonStruct()) {
1750817570 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{});
1750917571 }
1751017572
17511 const fields = dest_ty.structFields();
17573 const fields = struct_ty.structFields();
1751217574 const field_vals = try sema.arena.alloc(Value, fields.count());
1751317575 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
1751417576 mem.set(Air.Inst.Ref, field_refs, .none);
......@@ -17523,7 +17585,7 @@ fn coerceTupleToStruct(
1752317585 payload.data.names[i]
1752417586 else
1752517587 try std.fmt.allocPrint(sema.arena, "{d}", .{i});
17526 const field_index = try sema.structFieldIndex(block, dest_ty, field_name, field_src);
17588 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
1752717589 const field = fields.values()[field_index];
1752817590 if (field.is_comptime) {
1752917591 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{});
......@@ -17567,17 +17629,17 @@ fn coerceTupleToStruct(
1756717629 }
1756817630
1756917631 if (root_msg) |msg| {
17570 try sema.addDeclaredHereNote(msg, dest_ty);
17632 try sema.addDeclaredHereNote(msg, struct_ty);
1757117633 return sema.failWithOwnedErrorMsg(block, msg);
1757217634 }
1757317635
1757417636 if (runtime_src) |rs| {
1757517637 try sema.requireRuntimeBlock(block, rs);
17576 return block.addAggregateInit(dest_ty, field_refs);
17638 return block.addAggregateInit(struct_ty, field_refs);
1757717639 }
1757817640
1757917641 return sema.addConstant(
17580 dest_ty,
17642 struct_ty,
1758117643 try Value.Tag.@"struct".create(sema.arena, field_vals),
1758217644 );
1758317645}
src/type.zig+2-1
......@@ -3502,6 +3502,7 @@ pub const Type = extern union {
35023502 .tuple => ty.castTag(.tuple).?.data.types.len,
35033503 .anon_struct => ty.castTag(.anon_struct).?.data.types.len,
35043504 .@"struct" => ty.castTag(.@"struct").?.data.fields.count(),
3505 .empty_struct, .empty_struct_literal => 0,
35053506
35063507 else => unreachable,
35073508 };
......@@ -5070,7 +5071,7 @@ pub const Type = extern union {
50705071
50715072 pub fn isAnonStruct(ty: Type) bool {
50725073 return switch (ty.tag()) {
5073 .anon_struct => true,
5074 .anon_struct, .empty_struct_literal => true,
50745075 else => false,
50755076 };
50765077 }
test/behavior/align.zig+2-6
......@@ -6,17 +6,15 @@ const native_arch = builtin.target.cpu.arch;
66var foo: u8 align(4) = 100;
77
88test "global variable alignment" {
9 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
10
119 comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
1210 comptime try expect(@TypeOf(&foo) == *align(4) u8);
1311 {
14 const slice = @as(*[1]u8, &foo)[0..];
12 const slice = @as(*align(4) [1]u8, &foo)[0..];
1513 comptime try expect(@TypeOf(slice) == *align(4) [1]u8);
1614 }
1715 {
1816 var runtime_zero: usize = 0;
19 const slice = @as(*[1]u8, &foo)[runtime_zero..];
17 const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];
2018 comptime try expect(@TypeOf(slice) == []align(4) u8);
2119 }
2220}
......@@ -86,8 +84,6 @@ test "size of extern struct with 128-bit field" {
8684}
8785
8886test "@ptrCast preserves alignment of bigger source" {
89 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
90
9187 var x: u32 align(16) = 1234;
9288 const ptr = @ptrCast(*u8, &x);
9389 try expect(@TypeOf(ptr) == *align(16) u8);
test/behavior/struct.zig+5-1
......@@ -1072,7 +1072,11 @@ test "type coercion of anon struct literal to struct" {
10721072}
10731073
10741074test "type coercion of pointer to anon struct literal to pointer to struct" {
1075 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1075 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1076 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1077 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1078 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1079 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10761080
10771081 const S = struct {
10781082 const S2 = struct {
test/behavior/tuple.zig+2-2
......@@ -159,8 +159,8 @@ test "array-like initializer for tuple types" {
159159 const S = struct {
160160 fn doTheTest() !void {
161161 var obj: T = .{ -1234, 128 };
162 try testing.expectEqual(@as(i32, -1234), obj[0]);
163 try testing.expectEqual(@as(u8, 128), obj[1]);
162 try expect(@as(i32, -1234) == obj[0]);
163 try expect(@as(u8, 128) == obj[1]);
164164 }
165165 };
166166