From 71aa5084edd1d3fba5bf8db87c4cf0d03667a566 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Sun, 27 Feb 2022 09:50:53 -0700 Subject: [PATCH] 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 --- src/Sema.zig | 31 ++++++++++++++++++++----------- src/type.zig | 18 ++++++++++++------ test/behavior/type_info.zig | 6 ------ 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 5b97305010..4a8cd38dd4 100644 --- a/src/Sema.zig +++ b/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: { diff --git a/src/type.zig b/src/type.zig index a84a0f4520..30f06a6296 100644 --- a/src/type.zig +++ b/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, } }, diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index c4517ac277..4a4e7f62ac 100644 --- a/test/behavior/type_info.zig +++ b/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); }