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(...@@ -2733,7 +2733,7 @@ fn zirValidateStructInit(
2733 ),2733 ),
2734 .Union => return sema.validateUnionInit(2734 .Union => return sema.validateUnionInit(
2735 block,2735 block,
2736 agg_ty.cast(Type.Payload.Union).?.data,2736 agg_ty,
2737 init_src,2737 init_src,
2738 instrs,2738 instrs,
2739 object_ptr,2739 object_ptr,
...@@ -2746,12 +2746,14 @@ fn zirValidateStructInit(...@@ -2746,12 +2746,14 @@ fn zirValidateStructInit(
2746fn validateUnionInit(2746fn validateUnionInit(
2747 sema: *Sema,2747 sema: *Sema,
2748 block: *Block,2748 block: *Block,
2749 union_obj: *Module.Union,2749 union_ty: Type,
2750 init_src: LazySrcLoc,2750 init_src: LazySrcLoc,
2751 instrs: []const Zir.Inst.Index,2751 instrs: []const Zir.Inst.Index,
2752 union_ptr: Air.Inst.Ref,2752 union_ptr: Air.Inst.Ref,
2753 is_comptime: bool,2753 is_comptime: bool,
2754) CompileError!void {2754) CompileError!void {
2755 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2756
2755 if (instrs.len != 1) {2757 if (instrs.len != 1) {
2756 const msg = msg: {2758 const msg = msg: {
2757 const msg = try sema.errMsg(2759 const msg = try sema.errMsg(
...@@ -2767,7 +2769,7 @@ fn validateUnionInit(...@@ -2767,7 +2769,7 @@ fn validateUnionInit(
2767 const inst_src: LazySrcLoc = .{ .node_offset_back2tok = inst_data.src_node };2769 const inst_src: LazySrcLoc = .{ .node_offset_back2tok = inst_data.src_node };
2768 try sema.errNote(block, inst_src, msg, "additional initializer here", .{});2770 try sema.errNote(block, inst_src, msg, "additional initializer here", .{});
2769 }2771 }
2770 try sema.mod.errNoteNonLazy(union_obj.srcLoc(), msg, "union declared here", .{});2772 try sema.addDeclaredHereNote(msg, union_ty);
2771 break :msg msg;2773 break :msg msg;
2772 };2774 };
2773 return sema.failWithOwnedErrorMsg(msg);2775 return sema.failWithOwnedErrorMsg(msg);
...@@ -2783,9 +2785,7 @@ fn validateUnionInit(...@@ -2783,9 +2785,7 @@ fn validateUnionInit(
2783 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };2785 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
2784 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;2786 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
2785 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);2787 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
2786 const field_index_big = union_obj.fields.getIndex(field_name) orelse2788 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
2787 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
2788 const field_index = @intCast(u32, field_index_big);
2789 const air_tags = sema.air_instructions.items(.tag);2789 const air_tags = sema.air_instructions.items(.tag);
2790 const air_datas = sema.air_instructions.items(.data);2790 const air_datas = sema.air_instructions.items(.data);
2791 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;2791 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
...@@ -2844,7 +2844,6 @@ fn validateUnionInit(...@@ -2844,7 +2844,6 @@ fn validateUnionInit(
2844 .tag = tag_val,2844 .tag = tag_val,
2845 .val = val,2845 .val = val,
2846 });2846 });
2847 const union_ty = sema.typeOf(union_ptr).childType();
2848 const union_init = try sema.addConstant(union_ty, union_val);2847 const union_init = try sema.addConstant(union_ty, union_val);
2849 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);2848 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
2850 return;2849 return;
...@@ -11494,10 +11493,7 @@ fn unionInit(...@@ -11494,10 +11493,7 @@ fn unionInit(
11494 field_name: []const u8,11493 field_name: []const u8,
11495 field_src: LazySrcLoc,11494 field_src: LazySrcLoc,
11496) CompileError!Air.Inst.Ref {11495) CompileError!Air.Inst.Ref {
11497 const union_obj = union_ty.cast(Type.Payload.Union).?.data;11496 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
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);
1150111497
11502 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {11498 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
11503 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);11499 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
...@@ -11594,9 +11590,7 @@ fn zirStructInit(...@@ -11594,9 +11590,7 @@ fn zirStructInit(
11594 }11590 }
11595 }11591 }
11596 return sema.finishStructInit(block, src, field_inits, root_msg, struct_obj, resolved_ty, is_ref);11592 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| {11593 } else if (resolved_ty.zigTypeTag() == .Union) {
11598 const union_obj = union_payload.data;
11599
11600 if (extra.data.fields_len != 1) {11594 if (extra.data.fields_len != 1) {
11601 return sema.fail(block, src, "union initialization expects exactly one field", .{});11595 return sema.fail(block, src, "union initialization expects exactly one field", .{});
11602 }11596 }
...@@ -11607,9 +11601,7 @@ fn zirStructInit(...@@ -11607,9 +11601,7 @@ fn zirStructInit(
11607 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };11601 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
11608 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;11602 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
11609 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);11603 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
11610 const field_index_usize = union_obj.fields.getIndex(field_name) orelse11604 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
11611 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
11612 const field_index = @intCast(u32, field_index_usize);
1161311605
11614 if (is_ref) {11606 if (is_ref) {
11615 return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{});11607 return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{});
...@@ -11732,7 +11724,11 @@ fn zirStructInitAnon(...@@ -11732,7 +11724,11 @@ fn zirStructInitAnon(
1173211724
11733 if (is_ref) {11725 if (is_ref) {
11734 const target = sema.mod.getTarget();11726 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);
11736 var extra_index = extra.end;11732 var extra_index = extra.end;
11737 for (types) |field_ty, i_usize| {11733 for (types) |field_ty, i_usize| {
11738 const i = @intCast(u32, i_usize);11734 const i = @intCast(u32, i_usize);
...@@ -11882,7 +11878,11 @@ fn zirArrayInitAnon(...@@ -11882,7 +11878,11 @@ fn zirArrayInitAnon(
1188211878
11883 if (is_ref) {11879 if (is_ref) {
11884 const target = sema.mod.getTarget();11880 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);
11886 for (operands) |operand, i_usize| {11886 for (operands) |operand, i_usize| {
11887 const i = @intCast(u32, i_usize);11887 const i = @intCast(u32, i_usize);
11888 const field_ptr_ty = try Type.ptr(sema.arena, target, .{11888 const field_ptr_ty = try Type.ptr(sema.arena, target, .{
...@@ -15220,11 +15220,7 @@ fn unionFieldPtr(...@@ -15220,11 +15220,7 @@ fn unionFieldPtr(
15220 const union_ptr_ty = sema.typeOf(union_ptr);15220 const union_ptr_ty = sema.typeOf(union_ptr);
15221 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);15221 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
15222 const union_obj = union_ty.cast(Type.Payload.Union).?.data;15222 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
1522315223 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
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
15228 const field = union_obj.fields.values()[field_index];15224 const field = union_obj.fields.values()[field_index];
15229 const target = sema.mod.getTarget();15225 const target = sema.mod.getTarget();
15230 const ptr_field_ty = try Type.ptr(arena, target, .{15226 const ptr_field_ty = try Type.ptr(arena, target, .{
...@@ -15286,10 +15282,7 @@ fn unionFieldVal(...@@ -15286,10 +15282,7 @@ fn unionFieldVal(
1528615282
15287 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);15283 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
15288 const union_obj = union_ty.cast(Type.Payload.Union).?.data;15284 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
1528915285 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
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);
15293 const field = union_obj.fields.values()[field_index];15286 const field = union_obj.fields.values()[field_index];
1529415287
15295 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {15288 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
...@@ -15799,6 +15792,15 @@ fn coerce(...@@ -15799,6 +15792,15 @@ fn coerce(
15799 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);15792 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
15800 }15793 }
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
15802 // This will give an extra hint on top of what the bottom of this func would provide.15804 // This will give an extra hint on top of what the bottom of this func would provide.
15803 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);15805 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
15804 },15806 },
...@@ -15956,8 +15958,8 @@ fn coerce(...@@ -15956,8 +15958,8 @@ fn coerce(
15956 .Union => switch (inst_ty.zigTypeTag()) {15958 .Union => switch (inst_ty.zigTypeTag()) {
15957 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),15959 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
15958 .Struct => {15960 .Struct => {
15959 if (inst_ty.castTag(.anon_struct)) |anon_struct| {15961 if (inst_ty.isAnonStruct()) {
15960 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src, anon_struct.data);15962 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
15961 }15963 }
15962 },15964 },
15963 else => {},15965 else => {},
...@@ -17047,8 +17049,9 @@ fn coerceAnonStructToUnion(...@@ -17047,8 +17049,9 @@ fn coerceAnonStructToUnion(
17047 union_ty_src: LazySrcLoc,17049 union_ty_src: LazySrcLoc,
17048 inst: Air.Inst.Ref,17050 inst: Air.Inst.Ref,
17049 inst_src: LazySrcLoc,17051 inst_src: LazySrcLoc,
17050 anon_struct: Type.Payload.AnonStruct.Data,
17051) !Air.Inst.Ref {17052) !Air.Inst.Ref {
17053 const inst_ty = sema.typeOf(inst);
17054 const anon_struct = inst_ty.castTag(.anon_struct).?.data;
17052 if (anon_struct.types.len != 1) {17055 if (anon_struct.types.len != 1) {
17053 const msg = msg: {17056 const msg = msg: {
17054 const msg = try sema.errMsg(17057 const msg = try sema.errMsg(
...@@ -17069,11 +17072,24 @@ fn coerceAnonStructToUnion(...@@ -17069,11 +17072,24 @@ fn coerceAnonStructToUnion(
17069 }17072 }
1707017073
17071 const field_name = anon_struct.names[0];17074 const field_name = anon_struct.names[0];
17072 const inst_ty = sema.typeOf(inst);
17073 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);17075 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
17074 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);17076 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
17075}17077}
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
17077/// If the lengths match, coerces element-wise.17093/// If the lengths match, coerces element-wise.
17078fn coerceArrayLike(17094fn coerceArrayLike(
17079 sema: *Sema,17095 sema: *Sema,
...@@ -20080,3 +20096,17 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C...@@ -20080,3 +20096,17 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
20080 }20096 }
20081 return true;20097 return true;
20082}20098}
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 {...@@ -5036,6 +5036,13 @@ pub const Type = extern union {
5036 };5036 };
5037 }5037 }
50385038
5039 pub fn isAnonStruct(ty: Type) bool {
5040 return switch (ty.tag()) {
5041 .anon_struct => true,
5042 else => false,
5043 };
5044 }
5045
5039 pub fn isTupleOrAnonStruct(ty: Type) bool {5046 pub fn isTupleOrAnonStruct(ty: Type) bool {
5040 return switch (ty.tag()) {5047 return switch (ty.tag()) {
5041 .tuple, .empty_struct_literal, .anon_struct => true,5048 .tuple, .empty_struct_literal, .anon_struct => true,
test/behavior/union.zig+5-1
...@@ -978,7 +978,11 @@ test "cast from anonymous struct to union" {...@@ -978,7 +978,11 @@ test "cast from anonymous struct to union" {
978}978}
979979
980test "cast from pointer to anonymous struct to pointer to union" {980test "cast from pointer to anonymous struct to pointer to union" {
981 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO981 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
983 const S = struct {987 const S = struct {
984 const U = union(enum) {988 const U = union(enum) {