authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-31 04:42:18+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:57-07:00
loga0d4ef0acf50db06fdde8ff229d20d15afc7d402
tree92b320040e5a979d569a5284e71c6fcdf7ee893f
parent99531b0d52392668fe9f86b5109fff74cd37aff3

InternPool: add representation for value of empty enums and unions

This is a bit odd, because this value doesn't actually exist: see #15909. This gets all the empty enum/union behavior tests passing. Also adds an assertion to `Sema.analyzeBodyInner` which would have helped figure out the issue here much more quickly.

10 files changed, 66 insertions(+), 13 deletions(-)

src/InternPool.zig+23-1
......@@ -206,6 +206,10 @@ pub const Key = union(enum) {
206206 enum_literal: NullTerminatedString,
207207 /// A specific enum tag, indicated by the integer tag value.
208208 enum_tag: Key.EnumTag,
209 /// An empty enum or union. TODO: this value's existence is strange, because such a type in
210 /// reality has no values. See #15909.
211 /// Payload is the type for which we are an empty value.
212 empty_enum_value: Index,
209213 float: Key.Float,
210214 ptr: Ptr,
211215 opt: Opt,
......@@ -670,6 +674,7 @@ pub const Key = union(enum) {
670674 .error_union,
671675 .enum_literal,
672676 .enum_tag,
677 .empty_enum_value,
673678 .inferred_error_set_type,
674679 => |info| {
675680 var hasher = std.hash.Wyhash.init(seed);
......@@ -957,6 +962,10 @@ pub const Key = union(enum) {
957962 const b_info = b.enum_tag;
958963 return std.meta.eql(a_info, b_info);
959964 },
965 .empty_enum_value => |a_info| {
966 const b_info = b.empty_enum_value;
967 return a_info == b_info;
968 },
960969
961970 .variable => |a_info| {
962971 const b_info = b.variable;
......@@ -1192,6 +1201,7 @@ pub const Key = union(enum) {
11921201 .enum_literal => .enum_literal_type,
11931202
11941203 .undef => |x| x,
1204 .empty_enum_value => |x| x,
11951205
11961206 .simple_value => |s| switch (s) {
11971207 .undefined => .undefined_type,
......@@ -1980,6 +1990,7 @@ pub const Tag = enum(u8) {
19801990 /// The set of values that are encoded this way is:
19811991 /// * An array or vector which has length 0.
19821992 /// * A struct which has all fields comptime-known.
1993 /// * An empty enum or union. TODO: this value's existence is strange, because such a type in reality has no values. See #15909
19831994 /// data is Index of the type, which is known to be zero bits at runtime.
19841995 only_possible_value,
19851996 /// data is extra index to Key.Union.
......@@ -2952,6 +2963,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
29522963 } };
29532964 },
29542965
2966 .type_enum_auto,
2967 .type_enum_explicit,
2968 .type_union_tagged,
2969 .type_union_untagged,
2970 .type_union_safety,
2971 => .{ .empty_enum_value = ty },
2972
29552973 else => unreachable,
29562974 };
29572975 },
......@@ -3755,6 +3773,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
37553773 });
37563774 },
37573775
3776 .empty_enum_value => |enum_or_union_ty| ip.items.appendAssumeCapacity(.{
3777 .tag = .only_possible_value,
3778 .data = @enumToInt(enum_or_union_ty),
3779 }),
3780
37583781 .float => |float| {
37593782 switch (float.ty) {
37603783 .f16_type => ip.items.appendAssumeCapacity(.{
......@@ -5416,7 +5439,6 @@ pub fn isNoReturn(ip: *const InternPool, ty: Index) bool {
54165439 .noreturn_type => true,
54175440 else => switch (ip.indexToKey(ty)) {
54185441 .error_set_type => |error_set_type| error_set_type.names.len == 0,
5419 .enum_type => |enum_type| enum_type.names.len == 0,
54205442 else => false,
54215443 },
54225444 };
src/Sema.zig+19-10
......@@ -1725,8 +1725,12 @@ fn analyzeBodyInner(
17251725 break :blk Air.Inst.Ref.void_value;
17261726 },
17271727 };
1728 if (sema.isNoReturn(air_inst))
1728 if (sema.isNoReturn(air_inst)) {
1729 // We're going to assume that the body itself is noreturn, so let's ensure that now
1730 assert(block.instructions.items.len > 0);
1731 assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])));
17291732 break always_noreturn;
1733 }
17301734 map.putAssumeCapacity(inst, air_inst);
17311735 i += 1;
17321736 };
......@@ -32150,6 +32154,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3215032154 .error_union,
3215132155 .enum_literal,
3215232156 .enum_tag,
32157 .empty_enum_value,
3215332158 .float,
3215432159 .ptr,
3215532160 .opt,
......@@ -33015,10 +33020,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3301533020 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
3301633021 }
3301733022
33018 if (fields_len == 0) {
33019 return;
33020 }
33021
3302233023 const bits_per_field = 4;
3302333024 const fields_per_u32 = 32 / bits_per_field;
3302433025 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
......@@ -33301,7 +33302,7 @@ fn generateUnionTagTypeNumbered(
3330133302 .decl = new_decl_index,
3330233303 .namespace = .none,
3330333304 .tag_ty = if (enum_field_vals.len == 0)
33304 .noreturn_type
33305 (try mod.intType(.unsigned, 0)).toIntern()
3330533306 else
3330633307 mod.intern_pool.typeOf(enum_field_vals[0]),
3330733308 .names = enum_field_names,
......@@ -33351,7 +33352,7 @@ fn generateUnionTagTypeSimple(
3335133352 .decl = new_decl_index,
3335233353 .namespace = .none,
3335333354 .tag_ty = if (enum_field_names.len == 0)
33354 .noreturn_type
33355 (try mod.intType(.unsigned, 0)).toIntern()
3335533356 else
3335633357 (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(),
3335733358 .names = enum_field_names,
......@@ -33590,7 +33591,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3359033591 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
3359133592 return null;
3359233593 const fields = union_obj.fields.values();
33593 if (fields.len == 0) return Value.@"unreachable";
33594 if (fields.len == 0) {
33595 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
33596 return only.toValue();
33597 }
3359433598 const only_field = fields[0];
3359533599 if (only_field.ty.eql(resolved_ty, sema.mod)) {
3359633600 const msg = try Module.ErrorMsg.create(
......@@ -33630,7 +33634,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3363033634 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
3363133635
3363233636 switch (enum_type.names.len) {
33633 0 => return Value.@"unreachable",
33637 0 => {
33638 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
33639 return only.toValue();
33640 },
3363433641 1 => return try mod.getCoerced((if (enum_type.values.len == 0)
3363533642 try mod.intern(.{ .int = .{
3363633643 .ty = enum_type.tag_ty,
......@@ -33655,6 +33662,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3365533662 .error_union,
3365633663 .enum_literal,
3365733664 .enum_tag,
33665 .empty_enum_value,
3365833666 .float,
3365933667 .ptr,
3366033668 .opt,
......@@ -34143,6 +34151,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3414334151 .error_union,
3414434152 .enum_literal,
3414534153 .enum_tag,
34154 .empty_enum_value,
3414634155 .float,
3414734156 .ptr,
3414834157 .opt,
......@@ -34848,7 +34857,7 @@ fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
3484834857
3484934858/// Avoids crashing the compiler when asking if inferred allocations are noreturn.
3485034859fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
34851 if (ref == .noreturn_type) return true;
34860 if (ref == .unreachable_value) return true;
3485234861 if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) {
3485334862 .inferred_alloc, .inferred_alloc_comptime => return false,
3485434863 else => {},
src/TypedValue.zig+1
......@@ -248,6 +248,7 @@ pub fn print(
248248 try writer.writeAll(")");
249249 return;
250250 },
251 .empty_enum_value => return writer.writeAll("(empty enum value)"),
251252 .float => |float| switch (float.storage) {
252253 inline else => |x| return writer.print("{}", .{x}),
253254 },
src/arch/wasm/CodeGen.zig+1
......@@ -3156,6 +3156,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
31563156 .extern_func,
31573157 .func,
31583158 .enum_literal,
3159 .empty_enum_value,
31593160 => unreachable, // non-runtime values
31603161 .int => {
31613162 const int_info = ty.intInfo(mod);
src/codegen.zig+1
......@@ -242,6 +242,7 @@ pub fn generateSymbol(
242242 .extern_func,
243243 .func,
244244 .enum_literal,
245 .empty_enum_value,
245246 => unreachable, // non-runtime values
246247 .int => {
247248 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
src/codegen/c.zig+1
......@@ -946,6 +946,7 @@ pub const DeclGen = struct {
946946 .extern_func,
947947 .func,
948948 .enum_literal,
949 .empty_enum_value,
949950 => unreachable, // non-runtime values
950951 .int => |int| switch (int.storage) {
951952 .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}),
src/codegen/llvm.zig+1
......@@ -3246,6 +3246,7 @@ pub const DeclGen = struct {
32463246 },
32473247 .variable,
32483248 .enum_literal,
3249 .empty_enum_value,
32493250 => unreachable, // non-runtime values
32503251 .extern_func, .func => {
32513252 const fn_decl_index = switch (val_key) {
src/codegen/spirv.zig+1
......@@ -660,6 +660,7 @@ pub const DeclGen = struct {
660660 .extern_func,
661661 .func,
662662 .enum_literal,
663 .empty_enum_value,
663664 => unreachable, // non-runtime values
664665 .int => try self.addInt(ty, val),
665666 .err => |err| {
src/type.zig+17-2
......@@ -439,6 +439,7 @@ pub const Type = struct {
439439 .error_union,
440440 .enum_literal,
441441 .enum_tag,
442 .empty_enum_value,
442443 .float,
443444 .ptr,
444445 .opt,
......@@ -655,6 +656,7 @@ pub const Type = struct {
655656 .error_union,
656657 .enum_literal,
657658 .enum_tag,
659 .empty_enum_value,
658660 .float,
659661 .ptr,
660662 .opt,
......@@ -764,6 +766,7 @@ pub const Type = struct {
764766 .error_union,
765767 .enum_literal,
766768 .enum_tag,
769 .empty_enum_value,
767770 .float,
768771 .ptr,
769772 .opt,
......@@ -1098,6 +1101,7 @@ pub const Type = struct {
10981101 .error_union,
10991102 .enum_literal,
11001103 .enum_tag,
1104 .empty_enum_value,
11011105 .float,
11021106 .ptr,
11031107 .opt,
......@@ -1515,6 +1519,7 @@ pub const Type = struct {
15151519 .error_union,
15161520 .enum_literal,
15171521 .enum_tag,
1522 .empty_enum_value,
15181523 .float,
15191524 .ptr,
15201525 .opt,
......@@ -1749,6 +1754,7 @@ pub const Type = struct {
17491754 .error_union,
17501755 .enum_literal,
17511756 .enum_tag,
1757 .empty_enum_value,
17521758 .float,
17531759 .ptr,
17541760 .opt,
......@@ -2302,6 +2308,7 @@ pub const Type = struct {
23022308 .error_union,
23032309 .enum_literal,
23042310 .enum_tag,
2311 .empty_enum_value,
23052312 .float,
23062313 .ptr,
23072314 .opt,
......@@ -2584,7 +2591,10 @@ pub const Type = struct {
25842591 .union_type => |union_type| {
25852592 const union_obj = mod.unionPtr(union_type.index);
25862593 const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;
2587 if (union_obj.fields.count() == 0) return Value.@"unreachable";
2594 if (union_obj.fields.count() == 0) {
2595 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2596 return only.toValue();
2597 }
25882598 const only_field = union_obj.fields.values()[0];
25892599 const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;
25902600 const only = try mod.intern(.{ .un = .{
......@@ -2613,7 +2623,10 @@ pub const Type = struct {
26132623 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
26142624
26152625 switch (enum_type.names.len) {
2616 0 => return Value.@"unreachable",
2626 0 => {
2627 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2628 return only.toValue();
2629 },
26172630 1 => {
26182631 if (enum_type.values.len == 0) {
26192632 const only = try mod.intern(.{ .enum_tag = .{
......@@ -2645,6 +2658,7 @@ pub const Type = struct {
26452658 .error_union,
26462659 .enum_literal,
26472660 .enum_tag,
2661 .empty_enum_value,
26482662 .float,
26492663 .ptr,
26502664 .opt,
......@@ -2790,6 +2804,7 @@ pub const Type = struct {
27902804 .error_union,
27912805 .enum_literal,
27922806 .enum_tag,
2807 .empty_enum_value,
27932808 .float,
27942809 .ptr,
27952810 .opt,
src/value.zig+1
......@@ -441,6 +441,7 @@ pub const Value = struct {
441441 .err,
442442 .enum_literal,
443443 .enum_tag,
444 .empty_enum_value,
444445 .float,
445446 => val,
446447