diff options
| -rw-r--r-- | src/InternPool.zig | 24 | ||||
| -rw-r--r-- | src/Sema.zig | 29 | ||||
| -rw-r--r-- | src/TypedValue.zig | 1 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 1 | ||||
| -rw-r--r-- | src/codegen.zig | 1 | ||||
| -rw-r--r-- | src/codegen/c.zig | 1 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 1 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 1 | ||||
| -rw-r--r-- | src/type.zig | 19 | ||||
| -rw-r--r-- | src/value.zig | 1 |
10 files changed, 66 insertions, 13 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index 0b98dfcae5..9047041db8 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -206,6 +206,10 @@ pub const Key = union(enum) { enum_literal: NullTerminatedString, /// A specific enum tag, indicated by the integer tag value. enum_tag: Key.EnumTag, + /// An empty enum or union. TODO: this value's existence is strange, because such a type in + /// reality has no values. See #15909. + /// Payload is the type for which we are an empty value. + empty_enum_value: Index, float: Key.Float, ptr: Ptr, opt: Opt, @@ -670,6 +674,7 @@ pub const Key = union(enum) { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .inferred_error_set_type, => |info| { var hasher = std.hash.Wyhash.init(seed); @@ -957,6 +962,10 @@ pub const Key = union(enum) { const b_info = b.enum_tag; return std.meta.eql(a_info, b_info); }, + .empty_enum_value => |a_info| { + const b_info = b.empty_enum_value; + return a_info == b_info; + }, .variable => |a_info| { const b_info = b.variable; @@ -1192,6 +1201,7 @@ pub const Key = union(enum) { .enum_literal => .enum_literal_type, .undef => |x| x, + .empty_enum_value => |x| x, .simple_value => |s| switch (s) { .undefined => .undefined_type, @@ -1980,6 +1990,7 @@ pub const Tag = enum(u8) { /// The set of values that are encoded this way is: /// * An array or vector which has length 0. /// * A struct which has all fields comptime-known. + /// * An empty enum or union. TODO: this value's existence is strange, because such a type in reality has no values. See #15909 /// data is Index of the type, which is known to be zero bits at runtime. only_possible_value, /// data is extra index to Key.Union. @@ -2952,6 +2963,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { } }; }, + .type_enum_auto, + .type_enum_explicit, + .type_union_tagged, + .type_union_untagged, + .type_union_safety, + => .{ .empty_enum_value = ty }, + else => unreachable, }; }, @@ -3755,6 +3773,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { }); }, + .empty_enum_value => |enum_or_union_ty| ip.items.appendAssumeCapacity(.{ + .tag = .only_possible_value, + .data = @enumToInt(enum_or_union_ty), + }), + .float => |float| { switch (float.ty) { .f16_type => ip.items.appendAssumeCapacity(.{ @@ -5416,7 +5439,6 @@ pub fn isNoReturn(ip: *const InternPool, ty: Index) bool { .noreturn_type => true, else => switch (ip.indexToKey(ty)) { .error_set_type => |error_set_type| error_set_type.names.len == 0, - .enum_type => |enum_type| enum_type.names.len == 0, else => false, }, }; diff --git a/src/Sema.zig b/src/Sema.zig index 23a54da5ca..c2535eb4e9 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1725,8 +1725,12 @@ fn analyzeBodyInner( break :blk Air.Inst.Ref.void_value; }, }; - if (sema.isNoReturn(air_inst)) + if (sema.isNoReturn(air_inst)) { + // We're going to assume that the body itself is noreturn, so let's ensure that now + assert(block.instructions.items.len > 0); + assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1]))); break always_noreturn; + } map.putAssumeCapacity(inst, air_inst); i += 1; }; @@ -32150,6 +32154,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -33015,10 +33020,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); } - if (fields_len == 0) { - return; - } - const bits_per_field = 4; const fields_per_u32 = 32 / bits_per_field; const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; @@ -33301,7 +33302,7 @@ fn generateUnionTagTypeNumbered( .decl = new_decl_index, .namespace = .none, .tag_ty = if (enum_field_vals.len == 0) - .noreturn_type + (try mod.intType(.unsigned, 0)).toIntern() else mod.intern_pool.typeOf(enum_field_vals[0]), .names = enum_field_names, @@ -33351,7 +33352,7 @@ fn generateUnionTagTypeSimple( .decl = new_decl_index, .namespace = .none, .tag_ty = if (enum_field_names.len == 0) - .noreturn_type + (try mod.intType(.unsigned, 0)).toIntern() else (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(), .names = enum_field_names, @@ -33590,7 +33591,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse return null; const fields = union_obj.fields.values(); - if (fields.len == 0) return Value.@"unreachable"; + if (fields.len == 0) { + const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); + return only.toValue(); + } const only_field = fields[0]; if (only_field.ty.eql(resolved_ty, sema.mod)) { const msg = try Module.ErrorMsg.create( @@ -33630,7 +33634,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; switch (enum_type.names.len) { - 0 => return Value.@"unreachable", + 0 => { + const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); + return only.toValue(); + }, 1 => return try mod.getCoerced((if (enum_type.values.len == 0) try mod.intern(.{ .int = .{ .ty = enum_type.tag_ty, @@ -33655,6 +33662,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -34143,6 +34151,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -34848,7 +34857,7 @@ fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type { /// Avoids crashing the compiler when asking if inferred allocations are noreturn. fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool { - if (ref == .noreturn_type) return true; + if (ref == .unreachable_value) return true; if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { .inferred_alloc, .inferred_alloc_comptime => return false, else => {}, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 0128a3cbfb..81d25ed98a 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -248,6 +248,7 @@ pub fn print( try writer.writeAll(")"); return; }, + .empty_enum_value => return writer.writeAll("(empty enum value)"), .float => |float| switch (float.storage) { inline else => |x| return writer.print("{}", .{x}), }, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index e397cf29f8..e92bd8f676 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3156,6 +3156,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { .extern_func, .func, .enum_literal, + .empty_enum_value, => unreachable, // non-runtime values .int => { const int_info = ty.intInfo(mod); diff --git a/src/codegen.zig b/src/codegen.zig index 7fd432dceb..1470b94f1b 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -242,6 +242,7 @@ pub fn generateSymbol( .extern_func, .func, .enum_literal, + .empty_enum_value, => unreachable, // non-runtime values .int => { const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 56f6c669df..eea6e14896 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -946,6 +946,7 @@ pub const DeclGen = struct { .extern_func, .func, .enum_literal, + .empty_enum_value, => unreachable, // non-runtime values .int => |int| switch (int.storage) { .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8b78c4067a..91dcbe11a5 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3246,6 +3246,7 @@ pub const DeclGen = struct { }, .variable, .enum_literal, + .empty_enum_value, => unreachable, // non-runtime values .extern_func, .func => { const fn_decl_index = switch (val_key) { diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ddd7f36435..c7bea80eb6 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -660,6 +660,7 @@ pub const DeclGen = struct { .extern_func, .func, .enum_literal, + .empty_enum_value, => unreachable, // non-runtime values .int => try self.addInt(ty, val), .err => |err| { diff --git a/src/type.zig b/src/type.zig index 049ca1ebd8..0c4dfb7e7e 100644 --- a/src/type.zig +++ b/src/type.zig @@ -439,6 +439,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -655,6 +656,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -764,6 +766,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -1098,6 +1101,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -1515,6 +1519,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -1749,6 +1754,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -2302,6 +2308,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -2584,7 +2591,10 @@ pub const Type = struct { .union_type => |union_type| { const union_obj = mod.unionPtr(union_type.index); const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null; - if (union_obj.fields.count() == 0) return Value.@"unreachable"; + if (union_obj.fields.count() == 0) { + const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); + return only.toValue(); + } const only_field = union_obj.fields.values()[0]; const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null; const only = try mod.intern(.{ .un = .{ @@ -2613,7 +2623,10 @@ pub const Type = struct { if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; switch (enum_type.names.len) { - 0 => return Value.@"unreachable", + 0 => { + const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); + return only.toValue(); + }, 1 => { if (enum_type.values.len == 0) { const only = try mod.intern(.{ .enum_tag = .{ @@ -2645,6 +2658,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, @@ -2790,6 +2804,7 @@ pub const Type = struct { .error_union, .enum_literal, .enum_tag, + .empty_enum_value, .float, .ptr, .opt, diff --git a/src/value.zig b/src/value.zig index fe6a15154c..89ba1fba67 100644 --- a/src/value.zig +++ b/src/value.zig @@ -441,6 +441,7 @@ pub const Value = struct { .err, .enum_literal, .enum_tag, + .empty_enum_value, .float, => val, |
