authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 20:17:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 20:18:22-07:00
log06b1a88a157dde8fdb9653aabda600cdeee2dd13
treed9c577ec040e73bd659a65abfb5b17b80e954dc4
parentac7028f559d888f61f19589c1ead1f6cdeace736

Sema: implement cast from anon struct ptr to union ptr


3 files changed, 74 insertions(+), 33 deletions(-)

src/Sema.zig+62-32
......@@ -2733,7 +2733,7 @@ fn zirValidateStructInit(
27332733 ),
27342734 .Union => return sema.validateUnionInit(
27352735 block,
2736 agg_ty.cast(Type.Payload.Union).?.data,
2736 agg_ty,
27372737 init_src,
27382738 instrs,
27392739 object_ptr,
......@@ -2746,12 +2746,14 @@ fn zirValidateStructInit(
27462746fn validateUnionInit(
27472747 sema: *Sema,
27482748 block: *Block,
2749 union_obj: *Module.Union,
2749 union_ty: Type,
27502750 init_src: LazySrcLoc,
27512751 instrs: []const Zir.Inst.Index,
27522752 union_ptr: Air.Inst.Ref,
27532753 is_comptime: bool,
27542754) CompileError!void {
2755 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2756
27552757 if (instrs.len != 1) {
27562758 const msg = msg: {
27572759 const msg = try sema.errMsg(
......@@ -2767,7 +2769,7 @@ fn validateUnionInit(
27672769 const inst_src: LazySrcLoc = .{ .node_offset_back2tok = inst_data.src_node };
27682770 try sema.errNote(block, inst_src, msg, "additional initializer here", .{});
27692771 }
2770 try sema.mod.errNoteNonLazy(union_obj.srcLoc(), msg, "union declared here", .{});
2772 try sema.addDeclaredHereNote(msg, union_ty);
27712773 break :msg msg;
27722774 };
27732775 return sema.failWithOwnedErrorMsg(msg);
......@@ -2783,9 +2785,7 @@ fn validateUnionInit(
27832785 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
27842786 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
27852787 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
2786 const field_index_big = union_obj.fields.getIndex(field_name) orelse
2787 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
2788 const field_index = @intCast(u32, field_index_big);
2788 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
27892789 const air_tags = sema.air_instructions.items(.tag);
27902790 const air_datas = sema.air_instructions.items(.data);
27912791 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
......@@ -2844,7 +2844,6 @@ fn validateUnionInit(
28442844 .tag = tag_val,
28452845 .val = val,
28462846 });
2847 const union_ty = sema.typeOf(union_ptr).childType();
28482847 const union_init = try sema.addConstant(union_ty, union_val);
28492848 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
28502849 return;
......@@ -11494,10 +11493,7 @@ fn unionInit(
1149411493 field_name: []const u8,
1149511494 field_src: LazySrcLoc,
1149611495) CompileError!Air.Inst.Ref {
11497 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
11498 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
11499 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
11500 const field_index = @intCast(u32, field_index_usize);
11496 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
1150111497
1150211498 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
1150311499 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
......@@ -11594,9 +11590,7 @@ fn zirStructInit(
1159411590 }
1159511591 }
1159611592 return sema.finishStructInit(block, src, field_inits, root_msg, struct_obj, resolved_ty, is_ref);
11597 } else if (resolved_ty.cast(Type.Payload.Union)) |union_payload| {
11598 const union_obj = union_payload.data;
11599
11593 } else if (resolved_ty.zigTypeTag() == .Union) {
1160011594 if (extra.data.fields_len != 1) {
1160111595 return sema.fail(block, src, "union initialization expects exactly one field", .{});
1160211596 }
......@@ -11607,9 +11601,7 @@ fn zirStructInit(
1160711601 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
1160811602 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1160911603 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
11610 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
11611 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
11612 const field_index = @intCast(u32, field_index_usize);
11604 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
1161311605
1161411606 if (is_ref) {
1161511607 return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{});
......@@ -11732,7 +11724,11 @@ fn zirStructInitAnon(
1173211724
1173311725 if (is_ref) {
1173411726 const target = sema.mod.getTarget();
11735 const alloc = try block.addTy(.alloc, tuple_ty);
11727 const alloc_ty = try Type.ptr(sema.arena, target, .{
11728 .pointee_type = tuple_ty,
11729 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
11730 });
11731 const alloc = try block.addTy(.alloc, alloc_ty);
1173611732 var extra_index = extra.end;
1173711733 for (types) |field_ty, i_usize| {
1173811734 const i = @intCast(u32, i_usize);
......@@ -11882,7 +11878,11 @@ fn zirArrayInitAnon(
1188211878
1188311879 if (is_ref) {
1188411880 const target = sema.mod.getTarget();
11885 const alloc = try block.addTy(.alloc, tuple_ty);
11881 const alloc_ty = try Type.ptr(sema.arena, target, .{
11882 .pointee_type = tuple_ty,
11883 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
11884 });
11885 const alloc = try block.addTy(.alloc, alloc_ty);
1188611886 for (operands) |operand, i_usize| {
1188711887 const i = @intCast(u32, i_usize);
1188811888 const field_ptr_ty = try Type.ptr(sema.arena, target, .{
......@@ -15220,11 +15220,7 @@ fn unionFieldPtr(
1522015220 const union_ptr_ty = sema.typeOf(union_ptr);
1522115221 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
1522215222 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
15223
15224 const field_index_big = union_obj.fields.getIndex(field_name) orelse
15225 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
15226 const field_index = @intCast(u32, field_index_big);
15227
15223 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
1522815224 const field = union_obj.fields.values()[field_index];
1522915225 const target = sema.mod.getTarget();
1523015226 const ptr_field_ty = try Type.ptr(arena, target, .{
......@@ -15286,10 +15282,7 @@ fn unionFieldVal(
1528615282
1528715283 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
1528815284 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
15289
15290 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
15291 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
15292 const field_index = @intCast(u32, field_index_usize);
15285 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
1529315286 const field = union_obj.fields.values()[field_index];
1529415287
1529515288 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
......@@ -15799,6 +15792,15 @@ fn coerce(
1579915792 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1580015793 }
1580115794
15795 // cast from pointer to anonymous struct to pointer to union
15796 if (dest_info.pointee_type.zigTypeTag() == .Union and
15797 inst_ty.zigTypeTag() == .Pointer and
15798 inst_ty.childType().tag() == .anon_struct and
15799 !dest_info.mutable)
15800 {
15801 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
15802 }
15803
1580215804 // This will give an extra hint on top of what the bottom of this func would provide.
1580315805 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
1580415806 },
......@@ -15956,8 +15958,8 @@ fn coerce(
1595615958 .Union => switch (inst_ty.zigTypeTag()) {
1595715959 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
1595815960 .Struct => {
15959 if (inst_ty.castTag(.anon_struct)) |anon_struct| {
15960 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src, anon_struct.data);
15961 if (inst_ty.isAnonStruct()) {
15962 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
1596115963 }
1596215964 },
1596315965 else => {},
......@@ -17047,8 +17049,9 @@ fn coerceAnonStructToUnion(
1704717049 union_ty_src: LazySrcLoc,
1704817050 inst: Air.Inst.Ref,
1704917051 inst_src: LazySrcLoc,
17050 anon_struct: Type.Payload.AnonStruct.Data,
1705117052) !Air.Inst.Ref {
17053 const inst_ty = sema.typeOf(inst);
17054 const anon_struct = inst_ty.castTag(.anon_struct).?.data;
1705217055 if (anon_struct.types.len != 1) {
1705317056 const msg = msg: {
1705417057 const msg = try sema.errMsg(
......@@ -17069,11 +17072,24 @@ fn coerceAnonStructToUnion(
1706917072 }
1707017073
1707117074 const field_name = anon_struct.names[0];
17072 const inst_ty = sema.typeOf(inst);
1707317075 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
1707417076 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
1707517077}
1707617078
17079fn coerceAnonStructToUnionPtrs(
17080 sema: *Sema,
17081 block: *Block,
17082 ptr_union_ty: Type,
17083 union_ty_src: LazySrcLoc,
17084 ptr_anon_struct: Air.Inst.Ref,
17085 anon_struct_src: LazySrcLoc,
17086) !Air.Inst.Ref {
17087 const union_ty = ptr_union_ty.childType();
17088 const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
17089 const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src);
17090 return sema.analyzeRef(block, union_ty_src, union_inst);
17091}
17092
1707717093/// If the lengths match, coerces element-wise.
1707817094fn coerceArrayLike(
1707917095 sema: *Sema,
......@@ -20080,3 +20096,17 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
2008020096 }
2008120097 return true;
2008220098}
20099
20100fn unionFieldIndex(
20101 sema: *Sema,
20102 block: *Block,
20103 unresolved_union_ty: Type,
20104 field_name: []const u8,
20105 field_src: LazySrcLoc,
20106) !u32 {
20107 const union_ty = try sema.resolveTypeFields(block, field_src, unresolved_union_ty);
20108 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
20109 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
20110 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
20111 return @intCast(u32, field_index_usize);
20112}
src/type.zig+7
......@@ -5036,6 +5036,13 @@ pub const Type = extern union {
50365036 };
50375037 }
50385038
5039 pub fn isAnonStruct(ty: Type) bool {
5040 return switch (ty.tag()) {
5041 .anon_struct => true,
5042 else => false,
5043 };
5044 }
5045
50395046 pub fn isTupleOrAnonStruct(ty: Type) bool {
50405047 return switch (ty.tag()) {
50415048 .tuple, .empty_struct_literal, .anon_struct => true,
test/behavior/union.zig+5-1
......@@ -978,7 +978,11 @@ test "cast from anonymous struct to union" {
978978}
979979
980980test "cast from pointer to anonymous struct to pointer to union" {
981 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
981 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
982 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
983 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
982986
983987 const S = struct {
984988 const U = union(enum) {