Commit 71aa5084ed

Cody Tapscott <topolarity@tapscott.me>
2022-02-27 17:50:53
stage2: Resolve alignment for union field in `@TypeInfo`
This also includes two other small fixes: - Instantiate void TypeInfo fields as void - Return error in `type.comptimeOnly` on unresolved comptime requirements
1 parent 139b731
Changed files (3)
src/Sema.zig
@@ -9903,63 +9903,63 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .Void => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .Bool => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .NoReturn => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .ComptimeFloat => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .ComptimeInt => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .Undefined => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .Null => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .EnumLiteral => return sema.addConstant(
             type_info_ty,
             try Value.Tag.@"union".create(sema.arena, .{
                 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)),
-                .val = Value.initTag(.unreachable_value),
+                .val = Value.@"void",
             }),
         ),
         .Fn => {
@@ -10380,6 +10380,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
             };
 
             const union_ty = try sema.resolveTypeFields(block, src, ty);
+            try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout
+            const layout = union_ty.containerLayout();
+
             const union_fields = union_ty.unionFields();
             const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
 
@@ -10398,13 +10401,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 };
 
                 const union_field_fields = try fields_anon_decl.arena().create([3]Value);
+                const alignment = switch (layout) {
+                    .Auto, .Extern => field.normalAlignment(target),
+                    .Packed => 0,
+                };
+
                 union_field_fields.* = .{
                     // name: []const u8,
                     name_val,
                     // field_type: type,
                     try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
                     // alignment: comptime_int,
-                    try field.abi_align.copy(fields_anon_decl.arena()),
+                    try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
                 };
                 field_val.* = try Value.Tag.@"struct".create(fields_anon_decl.arena(), union_field_fields);
             }
@@ -10435,7 +10443,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 // layout: ContainerLayout,
                 try Value.Tag.enum_field_index.create(
                     sema.arena,
-                    @enumToInt(union_ty.containerLayout()),
+                    @enumToInt(layout),
                 ),
 
                 // tag_type: ?type,
@@ -10473,6 +10481,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
             };
             const struct_ty = try sema.resolveTypeFields(block, src, ty);
+            try sema.resolveTypeLayout(block, src, ty); // Getting alignment requires type layout
             const layout = struct_ty.containerLayout();
 
             const struct_field_vals = fv: {
src/type.zig
@@ -1619,6 +1619,10 @@ pub const Type = extern union {
 
             // These types have more than one possible value, so the result is the same as
             // asking whether they are comptime-only types.
+            //
+            // If we get an error that the comptimeOnly status hasn't been
+            // resolved yet, then we assume that there are runtime bits,
+            // just like we do for structs below
             .anyframe_T,
             .optional,
             .optional_single_mut_pointer,
@@ -1632,7 +1636,7 @@ pub const Type = extern union {
             .const_slice,
             .mut_slice,
             .pointer,
-            => !ty.comptimeOnly(),
+            => !(ty.comptimeOnly() catch return true),
 
             .@"struct" => {
                 const struct_obj = ty.castTag(.@"struct").?.data;
@@ -1728,7 +1732,7 @@ pub const Type = extern union {
                     .Inline => return false,
                     else => {},
                 }
-                if (fn_info.return_type.comptimeOnly()) return false;
+                if (fn_info.return_type.comptimeOnly() catch unreachable) return false;
                 return true;
             },
             else => return ty.hasRuntimeBits(),
@@ -3610,7 +3614,7 @@ pub const Type = extern union {
 
     /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
     /// resolves field types rather than asserting they are already resolved.
-    pub fn comptimeOnly(ty: Type) bool {
+    pub fn comptimeOnly(ty: Type) error{StatusNotResolved}!bool {
         return switch (ty.tag()) {
             .u1,
             .u8,
@@ -3731,7 +3735,7 @@ pub const Type = extern union {
             .tuple => {
                 const tuple = ty.castTag(.tuple).?.data;
                 for (tuple.types) |field_ty| {
-                    if (field_ty.comptimeOnly()) return true;
+                    if (try field_ty.comptimeOnly()) return true;
                 }
                 return false;
             },
@@ -3739,18 +3743,20 @@ pub const Type = extern union {
             .@"struct" => {
                 const struct_obj = ty.castTag(.@"struct").?.data;
                 switch (struct_obj.requires_comptime) {
-                    .wip, .unknown => unreachable, // This function asserts types already resolved.
+                    .wip => unreachable,
                     .no => return false,
                     .yes => return true,
+                    .unknown => return error.StatusNotResolved,
                 }
             },
 
             .@"union", .union_tagged => {
                 const union_obj = ty.cast(Type.Payload.Union).?.data;
                 switch (union_obj.requires_comptime) {
-                    .wip, .unknown => unreachable, // This function asserts types already resolved.
+                    .wip => unreachable,
                     .no => return false,
                     .yes => return true,
+                    .unknown => return error.StatusNotResolved,
                 }
             },
 
test/behavior/type_info.zig
@@ -249,8 +249,6 @@ fn testEnum() !void {
 }
 
 test "type info: union info" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     try testUnion();
     comptime try testUnion();
 }
@@ -436,8 +434,6 @@ fn testAnyFrame() !void {
 }
 
 test "type info: pass to function" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     _ = passTypeInfo(@typeInfo(void));
     _ = comptime passTypeInfo(@typeInfo(void));
 }
@@ -448,8 +444,6 @@ fn passTypeInfo(comptime info: TypeInfo) type {
 }
 
 test "type info: TypeId -> TypeInfo impl cast" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     _ = passTypeInfo(TypeId.Void);
     _ = comptime passTypeInfo(TypeId.Void);
 }