authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 19:22:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-02 19:22:31-07:00
logf5e2e301e98fe93f63b5b997e03fa73ed1798a26
treedb16a9ddb2e71bbb4f4123b4ea4dd95007b977f6
parent3ec74a1cd8b868b7cebfd584dec3f20a9aa2bda6

Sema: add coercion from anon structs to unions


2 files changed, 62 insertions(+), 6 deletions(-)

src/Sema.zig+57-5
...@@ -11481,6 +11481,19 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -11481,6 +11481,19 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
11481 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);11481 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
11482 const field_name = try sema.resolveConstString(block, field_src, extra.field_name);11482 const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
11483 const init = sema.resolveInst(extra.init);11483 const init = sema.resolveInst(extra.init);
11484 return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
11485}
11486
11487fn unionInit(
11488 sema: *Sema,
11489 block: *Block,
11490 init: Air.Inst.Ref,
11491 init_src: LazySrcLoc,
11492 union_ty: Type,
11493 union_ty_src: LazySrcLoc,
11494 field_name: []const u8,
11495 field_src: LazySrcLoc,
11496) CompileError!Air.Inst.Ref {
11484 const union_obj = union_ty.cast(Type.Payload.Union).?.data;11497 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
11485 const field_index_usize = union_obj.fields.getIndex(field_name) orelse11498 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
11486 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);11499 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
...@@ -11488,14 +11501,14 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -11488,14 +11501,14 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1148811501
11489 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {11502 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
11490 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);11503 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
11491 return sema.addConstant(11504 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
11492 union_ty,11505 .tag = tag_val,
11493 try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = init_val }),11506 .val = init_val,
11494 );11507 }));
11495 }11508 }
1149611509
11497 try sema.requireRuntimeBlock(block, init_src);11510 try sema.requireRuntimeBlock(block, init_src);
11498 try sema.resolveTypeLayout(block, ty_src, union_ty);11511 try sema.resolveTypeLayout(block, union_ty_src, union_ty);
11499 return block.addUnionInit(union_ty, field_index, init);11512 return block.addUnionInit(union_ty, field_index, init);
11500}11513}
1150111514
...@@ -15903,6 +15916,11 @@ fn coerce(...@@ -15903,6 +15916,11 @@ fn coerce(
15903 },15916 },
15904 .Union => switch (inst_ty.zigTypeTag()) {15917 .Union => switch (inst_ty.zigTypeTag()) {
15905 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),15918 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
15919 .Struct => {
15920 if (inst_ty.castTag(.anon_struct)) |anon_struct| {
15921 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src, anon_struct.data);
15922 }
15923 },
15906 else => {},15924 else => {},
15907 },15925 },
15908 .Array => switch (inst_ty.zigTypeTag()) {15926 .Array => switch (inst_ty.zigTypeTag()) {
...@@ -16983,6 +17001,40 @@ fn coerceEnumToUnion(...@@ -16983,6 +17001,40 @@ fn coerceEnumToUnion(
16983 return sema.failWithOwnedErrorMsg(msg);17001 return sema.failWithOwnedErrorMsg(msg);
16984}17002}
1698517003
17004fn coerceAnonStructToUnion(
17005 sema: *Sema,
17006 block: *Block,
17007 union_ty: Type,
17008 union_ty_src: LazySrcLoc,
17009 inst: Air.Inst.Ref,
17010 inst_src: LazySrcLoc,
17011 anon_struct: Type.Payload.AnonStruct.Data,
17012) !Air.Inst.Ref {
17013 if (anon_struct.types.len != 1) {
17014 const msg = msg: {
17015 const msg = try sema.errMsg(
17016 block,
17017 inst_src,
17018 "cannot initialize multiple union fields at once, unions can only have one active field",
17019 .{},
17020 );
17021 errdefer msg.destroy(sema.gpa);
17022
17023 // TODO add notes for where the anon struct was created to point out
17024 // the extra fields.
17025
17026 try sema.addDeclaredHereNote(msg, union_ty);
17027 break :msg msg;
17028 };
17029 return sema.failWithOwnedErrorMsg(msg);
17030 }
17031
17032 const field_name = anon_struct.names[0];
17033 const inst_ty = sema.typeOf(inst);
17034 const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
17035 return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
17036}
17037
16986/// If the lengths match, coerces element-wise.17038/// If the lengths match, coerces element-wise.
16987fn coerceArrayLike(17039fn coerceArrayLike(
16988 sema: *Sema,17040 sema: *Sema,
test/behavior/union.zig+5-1
...@@ -945,7 +945,11 @@ test "function call result coerces from tagged union to the tag" {...@@ -945,7 +945,11 @@ test "function call result coerces from tagged union to the tag" {
945}945}
946946
947test "cast from anonymous struct to union" {947test "cast from anonymous struct to union" {
948 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO948 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
949 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
951 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
952 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
949953
950 const S = struct {954 const S = struct {
951 const U = union(enum) {955 const U = union(enum) {