authorgravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-11 17:44:52-08:00
committergravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-11 17:44:52-08:00
log015cc41e505ec640c84b91b6fca4fa353593df66
treea3278caf3ab4308d559c410e056e24626c8ef276
parent6f986298c6cc58d2d86e9790b11bad5ce36085ad
signaturelock-open Commit is signed but in an unrecognized format.

stage2: zirReify for enums


2 files changed, 126 insertions(+), 3 deletions(-)

src/Sema.zig+115-1
......@@ -12470,7 +12470,121 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1247012470 const ty = try Type.Tag.error_set_merged.create(sema.arena, names);
1247112471 return sema.addType(ty);
1247212472 },
12473 .Enum => return sema.fail(block, src, "TODO: Sema.zirReify for Enum", .{}),
12473 .Enum => {
12474 const struct_val = union_val.val.castTag(.@"struct").?.data;
12475 // TODO use reflection instead of magic numbers here
12476 // error_set: type,
12477 // layout: ContainerLayout,
12478 const layout_val = struct_val[0];
12479 // tag_type: type,
12480 const tag_type_val = struct_val[1];
12481 // fields: []const EnumField,
12482 const fields_val = struct_val[2];
12483 // decls: []const Declaration,
12484 const decls_val = struct_val[3];
12485 // is_exhaustive: bool,
12486 const is_exhaustive_val = struct_val[4];
12487
12488 // enum layout is always auto
12489 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
12490 if (layout != .Auto) {
12491 return sema.fail(block, src, "reified enums must have a layout .Auto", .{});
12492 }
12493
12494 // Decls
12495 const decls_slice_val = decls_val.castTag(.slice).?.data;
12496 const decls_decl = decls_slice_val.ptr.castTag(.decl_ref).?.data;
12497 try sema.ensureDeclAnalyzed(decls_decl);
12498 if (decls_decl.ty.arrayLen() > 0) {
12499 return sema.fail(block, src, "reified enums must have no decls", .{});
12500 }
12501
12502 const mod = sema.mod;
12503 const gpa = sema.gpa;
12504 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
12505 errdefer new_decl_arena.deinit();
12506 const new_decl_arena_allocator = new_decl_arena.allocator();
12507
12508 // Define our empty enum decl
12509 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
12510 const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
12511 enum_ty_payload.* = .{
12512 .base = .{
12513 .tag = if (!is_exhaustive_val.toBool())
12514 .enum_nonexhaustive
12515 else
12516 .enum_full,
12517 },
12518 .data = enum_obj,
12519 };
12520 const enum_ty = Type.initPayload(&enum_ty_payload.base);
12521 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
12522 const type_name = try sema.createTypeName(block, .anon);
12523 const new_decl = try mod.createAnonymousDeclNamed(block, .{
12524 .ty = Type.type,
12525 .val = enum_val,
12526 }, type_name);
12527 new_decl.owns_tv = true;
12528 errdefer mod.abortAnonDecl(new_decl);
12529
12530 enum_obj.* = .{
12531 .owner_decl = new_decl,
12532 .tag_ty = Type.initTag(.@"null"),
12533 .fields = .{},
12534 .values = .{},
12535 .node_offset = src.node_offset,
12536 .namespace = .{
12537 .parent = block.namespace,
12538 .ty = enum_ty,
12539 .file_scope = block.getFileScope(),
12540 },
12541 };
12542
12543 // Enum tag type
12544 var buffer: Value.ToTypeBuffer = undefined;
12545 enum_obj.tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator);
12546
12547 // Fields
12548 const slice_val = fields_val.castTag(.slice).?.data;
12549 const decl = slice_val.ptr.castTag(.decl_ref).?.data;
12550 try sema.ensureDeclAnalyzed(decl);
12551 const fields_len = decl.ty.arrayLen();
12552 if (fields_len > 0) {
12553 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
12554 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
12555 .ty = enum_obj.tag_ty,
12556 });
12557
12558 const array_vals = decl.val.castTag(.array).?.data;
12559 for (array_vals) |elem_val| {
12560 const field_struct_val = elem_val.castTag(.@"struct").?.data;
12561 // TODO use reflection instead of magic numbers here
12562 // name: []const u8
12563 const name_val = field_struct_val[0];
12564 // value: comptime_int
12565 const value_val = field_struct_val[1];
12566
12567 const field_name = try name_val.toAllocatedBytes(
12568 Type.initTag(.const_slice_u8),
12569 new_decl_arena_allocator,
12570 );
12571
12572 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
12573 if (gop.found_existing) {
12574 // TODO: better source location
12575 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
12576 }
12577
12578 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
12579 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
12580 .ty = enum_obj.tag_ty,
12581 });
12582 }
12583 }
12584
12585 try new_decl.finalizeNewArena(&new_decl_arena);
12586 return sema.analyzeDeclVal(block, src, new_decl);
12587 },
1247412588 .Union => return sema.fail(block, src, "TODO: Sema.zirReify for Union", .{}),
1247512589 .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}),
1247612590 .BoundFn => @panic("TODO delete BoundFn from the language"),
test/behavior/type.zig+11-2
......@@ -302,7 +302,11 @@ test "Type.Struct" {
302302}
303303
304304test "Type.Enum" {
305 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
306 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
306310
307311 const Foo = @Type(.{
308312 .Enum = .{
......@@ -321,7 +325,12 @@ test "Type.Enum" {
321325 try testing.expectEqual(@as(u8, 5), @enumToInt(Foo.b));
322326 const Bar = @Type(.{
323327 .Enum = .{
324 .layout = .Extern,
328 // stage2 only has auto layouts
329 .layout = if (builtin.zig_backend == .stage1)
330 .Extern
331 else
332 .Auto,
333
325334 .tag_type = u32,
326335 .fields = &.{
327336 .{ .name = "a", .value = 1 },