authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-15 00:21:11-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-15 00:21:11-04:00
logf36bf8506c9c1fa48dadd699b3122acd15890cf6
treea33f67ffb59f9b43fe003ea6decadd185ebfdeaf
parent84f96779c381dbd885ee321042b8cb8f88e439e3
parent53de31d62c91b96cbf082169d76d02f6900f6273
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11164 from mitchellh/reify-union

stage2: reify unions

2 files changed, 117 insertions(+), 11 deletions(-)

src/Sema.zig+102-8
...@@ -12607,18 +12607,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -12607,18 +12607,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
12607 enum_obj.tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator);12607 enum_obj.tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator);
1260812608
12609 // Fields12609 // Fields
12610 const slice_val = fields_val.castTag(.slice).?.data;12610 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen());
12611 const decl = slice_val.ptr.pointerDecl().?;
12612 try sema.ensureDeclAnalyzed(decl);
12613 const fields_len = try sema.usizeCast(block, src, decl.ty.arrayLen());
12614 if (fields_len > 0) {12611 if (fields_len > 0) {
12615 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);12612 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
12616 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{12613 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
12617 .ty = enum_obj.tag_ty,12614 .ty = enum_obj.tag_ty,
12618 });12615 });
1261912616
12620 const array_vals = decl.val.castTag(.aggregate).?.data;12617 var i: usize = 0;
12621 for (array_vals) |elem_val| {12618 while (i < fields_len) : (i += 1) {
12619 const elem_val = try fields_val.elemValue(sema.arena, i);
12622 const field_struct_val = elem_val.castTag(.aggregate).?.data;12620 const field_struct_val = elem_val.castTag(.aggregate).?.data;
12623 // TODO use reflection instead of magic numbers here12621 // TODO use reflection instead of magic numbers here
12624 // name: []const u812622 // name: []const u8
...@@ -12691,7 +12689,103 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -12691,7 +12689,103 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
12691 try new_decl.finalizeNewArena(&new_decl_arena);12689 try new_decl.finalizeNewArena(&new_decl_arena);
12692 return sema.analyzeDeclVal(block, src, new_decl);12690 return sema.analyzeDeclVal(block, src, new_decl);
12693 },12691 },
12694 .Union => return sema.fail(block, src, "TODO: Sema.zirReify for Union", .{}),12692 .Union => {
12693 // TODO use reflection instead of magic numbers here
12694 const struct_val = union_val.val.castTag(.aggregate).?.data;
12695 // layout: containerlayout,
12696 const layout_val = struct_val[0];
12697 // tag_type: ?type,
12698 const tag_type_val = struct_val[1];
12699 // fields: []const enumfield,
12700 const fields_val = struct_val[2];
12701 // decls: []const declaration,
12702 const decls_val = struct_val[3];
12703
12704 // Decls
12705 if (decls_val.sliceLen() > 0) {
12706 return sema.fail(block, src, "reified unions must have no decls", .{});
12707 }
12708
12709 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
12710 errdefer new_decl_arena.deinit();
12711 const new_decl_arena_allocator = new_decl_arena.allocator();
12712
12713 const union_obj = try new_decl_arena_allocator.create(Module.Union);
12714 const type_tag: Type.Tag = if (!tag_type_val.isNull()) .union_tagged else .@"union";
12715 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
12716 union_payload.* = .{
12717 .base = .{ .tag = type_tag },
12718 .data = union_obj,
12719 };
12720 const union_ty = Type.initPayload(&union_payload.base);
12721 const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
12722 const type_name = try sema.createTypeName(block, .anon);
12723 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
12724 .ty = Type.type,
12725 .val = new_union_val,
12726 }, type_name);
12727 new_decl.owns_tv = true;
12728 errdefer sema.mod.abortAnonDecl(new_decl);
12729 union_obj.* = .{
12730 .owner_decl = new_decl,
12731 .tag_ty = Type.initTag(.@"null"),
12732 .fields = .{},
12733 .node_offset = src.node_offset,
12734 .zir_index = inst,
12735 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),
12736 .status = .have_field_types,
12737 .namespace = .{
12738 .parent = block.namespace,
12739 .ty = union_ty,
12740 .file_scope = block.getFileScope(),
12741 },
12742 };
12743
12744 // Tag type
12745 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen());
12746 union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: {
12747 var buffer: Value.ToTypeBuffer = undefined;
12748 break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
12749 } else try sema.generateUnionTagTypeSimple(block, fields_len);
12750
12751 // Fields
12752 if (fields_len > 0) {
12753 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
12754
12755 var i: usize = 0;
12756 while (i < fields_len) : (i += 1) {
12757 const elem_val = try fields_val.elemValue(sema.arena, i);
12758 const field_struct_val = elem_val.castTag(.aggregate).?.data;
12759 // TODO use reflection instead of magic numbers here
12760 // name: []const u8
12761 const name_val = field_struct_val[0];
12762 // field_type: type,
12763 const field_type_val = field_struct_val[1];
12764 // alignment: comptime_int,
12765 const alignment_val = field_struct_val[2];
12766
12767 const field_name = try name_val.toAllocatedBytes(
12768 Type.initTag(.const_slice_u8),
12769 new_decl_arena_allocator,
12770 );
12771
12772 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
12773 if (gop.found_existing) {
12774 // TODO: better source location
12775 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
12776 }
12777
12778 var buffer: Value.ToTypeBuffer = undefined;
12779 gop.value_ptr.* = .{
12780 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
12781 .abi_align = try alignment_val.copy(new_decl_arena_allocator),
12782 };
12783 }
12784 }
12785
12786 try new_decl.finalizeNewArena(&new_decl_arena);
12787 return sema.analyzeDeclVal(block, src, new_decl);
12788 },
12695 .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}),12789 .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}),
12696 .BoundFn => @panic("TODO delete BoundFn from the language"),12790 .BoundFn => @panic("TODO delete BoundFn from the language"),
12697 .Frame => @panic("TODO implement https://github.com/ziglang/zig/issues/10710"),12791 .Frame => @panic("TODO implement https://github.com/ziglang/zig/issues/10710"),
...@@ -20417,7 +20511,7 @@ fn generateUnionTagTypeNumbered(...@@ -20417,7 +20511,7 @@ fn generateUnionTagTypeNumbered(
20417 return enum_ty;20511 return enum_ty;
20418}20512}
2041920513
20420fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: u32) !Type {20514fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize) !Type {
20421 const mod = sema.mod;20515 const mod = sema.mod;
2042220516
20423 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);20517 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
test/behavior/type.zig+15-3
...@@ -395,7 +395,11 @@ test "Type.Enum" {...@@ -395,7 +395,11 @@ test "Type.Enum" {
395}395}
396396
397test "Type.Union" {397test "Type.Union" {
398 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO398 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
400 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
399403
400 const Untagged = @Type(.{404 const Untagged = @Type(.{
401 .Union = .{405 .Union = .{
...@@ -458,7 +462,11 @@ test "Type.Union" {...@@ -458,7 +462,11 @@ test "Type.Union" {
458}462}
459463
460test "Type.Union from Type.Enum" {464test "Type.Union from Type.Enum" {
461 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO465 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
462470
463 const Tag = @Type(.{471 const Tag = @Type(.{
464 .Enum = .{472 .Enum = .{
...@@ -486,7 +494,11 @@ test "Type.Union from Type.Enum" {...@@ -486,7 +494,11 @@ test "Type.Union from Type.Enum" {
486}494}
487495
488test "Type.Union from regular enum" {496test "Type.Union from regular enum" {
489 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
490502
491 const E = enum { working_as_expected };503 const E = enum { working_as_expected };
492 const T = @Type(.{504 const T = @Type(.{