authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-29 08:54:59+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:08+00:00
log187fef209f73336163337474dc02f46c7c89ac3a
tree93e71de23bb4fed48ad868c7da5f0eddda323be9
parentb19074d252e7eb833b653263acd20e64a7fe26ff
signaturelock-open Commit is signed but in an unrecognized format.

compiler: rework OPV and noreturn-like types


19 files changed, 780 insertions(+), 912 deletions(-)

src/Air/Liveness.zig+1-1
......@@ -999,7 +999,7 @@ fn analyzeInstBlock(
999999
10001000 // If the block is noreturn, block deaths not only aren't useful, they're impossible to
10011001 // find: there could be more stuff alive after the block than before it!
1002 if (!a.intern_pool.isNoReturn(ty.toIntern())) {
1002 if (!ty.isNoReturn(a.zcu)) {
10031003 // The block kills the difference in the live sets
10041004 const block_scope = data.block_scopes.get(inst).?;
10051005 const num_deaths = data.live_set.count() - block_scope.live_set.count();
src/Air/Liveness/Verify.zig+1-1
......@@ -465,7 +465,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
465465
466466 for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);
467467
468 if (ip.isNoReturn(block_ty.toIntern())) {
468 if (block_ty.isNoReturn(self.zcu)) {
469469 assert(!self.blocks.contains(inst));
470470 } else {
471471 var live = if (self.blocks.fetchRemove(inst)) |kv| kv.value else {
src/InternPool.zig+44-127
......@@ -17,6 +17,7 @@ const Hash = std.hash.Wyhash;
1717const Zir = std.zig.Zir;
1818
1919const Zcu = @import("Zcu.zig");
20const TypeClass = @import("Type.zig").Class;
2021
2122/// One item per thread, indexed by `tid`, which is dense and unique per thread.
2223locals: []Local,
......@@ -2113,10 +2114,6 @@ pub const Key = union(enum) {
21132114 enum_literal: NullTerminatedString,
21142115 /// A specific enum tag, indicated by the integer tag value.
21152116 enum_tag: EnumTag,
2116 /// An empty enum or union. TODO: this value's existence is strange, because such a type in
2117 /// reality has no values. See #15909.
2118 /// Payload is the type for which we are an empty value.
2119 empty_enum_value: Index,
21202117 float: Float,
21212118 ptr: Ptr,
21222119 slice: Slice,
......@@ -2722,7 +2719,6 @@ pub const Key = union(enum) {
27222719 .err,
27232720 .enum_literal,
27242721 .enum_tag,
2725 .empty_enum_value,
27262722 .inferred_error_set_type,
27272723 .un,
27282724 => |x| Hash.hash(seed, asBytes(&x)),
......@@ -3005,10 +3001,6 @@ pub const Key = union(enum) {
30053001 const b_info = b.enum_tag;
30063002 return std.meta.eql(a_info, b_info);
30073003 },
3008 .empty_enum_value => |a_info| {
3009 const b_info = b.empty_enum_value;
3010 return a_info == b_info;
3011 },
30123004 .bitpack => |a_info| {
30133005 const b_info = b.bitpack;
30143006 return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val;
......@@ -3294,10 +3286,8 @@ pub const Key = union(enum) {
32943286 .enum_literal => .enum_literal_type,
32953287
32963288 .undef => |x| x,
3297 .empty_enum_value => |x| x,
32983289
32993290 .simple_value => |s| switch (s) {
3300 .undefined => .undefined_type,
33013291 .void => .void_type,
33023292 .null => .null_type,
33033293 .false, .true => .bool_type,
......@@ -3356,10 +3346,7 @@ pub const LoadedStructType = struct {
33563346 field_runtime_order: RuntimeOrder.Slice,
33573347 field_offsets: Offsets,
33583348 packed_backing_int_type: Index,
3359 has_no_possible_value: bool,
3360 has_one_possible_value: bool,
3361 comptime_only: bool,
3362 has_runtime_bits: bool,
3349 class: TypeClass,
33633350 size: u32,
33643351 alignment: Alignment,
33653352
......@@ -3535,19 +3522,21 @@ pub const LoadedUnionType = struct {
35353522 // The remaining fields are only valid once the union's layout is resolved.
35363523 field_types: Index.Slice,
35373524 field_aligns: Alignment.Slice,
3538 runtime_tag: RuntimeTag,
3539 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.
3525 tag_usage: TagUsage,
3526 /// While `tag_usage` indicates whether the union should logically contain a tag, it may be
3527 /// omitted if the union layout is resolved as OPV or NPV. This field is `true` iff there is an
3528 /// actual runtime tag in the union layout.
3529 has_runtime_tag: bool,
3530 /// Even if `tag_usage == .none` and `has_runtime_tag == false`, this is still populated with
3531 /// the union's "hypothetical" tag type.
35403532 enum_tag_type: Index,
35413533 packed_backing_int_type: Index,
3542 has_no_possible_value: bool,
3543 has_one_possible_value: bool,
3544 comptime_only: bool,
3545 has_runtime_bits: bool,
3534 class: TypeClass,
35463535 size: u32,
35473536 padding: u32,
35483537 alignment: Alignment,
35493538
3550 pub const RuntimeTag = enum(u2) {
3539 pub const TagUsage = enum(u2) {
35513540 none,
35523541 safety,
35533542 tagged,
......@@ -3733,10 +3722,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
37333722 .field_runtime_order = field_runtime_order,
37343723 .field_offsets = field_offsets,
37353724 .packed_backing_int_type = .none,
3736 .has_no_possible_value = extra.data.flags.has_no_possible_value,
3737 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3738 .comptime_only = extra.data.flags.comptime_only,
3739 .has_runtime_bits = extra.data.flags.has_runtime_bits,
3725 .class = extra.data.flags.class,
37403726 .size = extra.data.size,
37413727 .alignment = extra.data.flags.alignment,
37423728 };
......@@ -3797,10 +3783,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
37973783 .field_runtime_order = .empty,
37983784 .field_offsets = .empty,
37993785 .packed_backing_int_type = extra.data.backing_int_type,
3800 .has_no_possible_value = undefined,
3801 .has_one_possible_value = undefined,
3802 .comptime_only = undefined,
3803 .has_runtime_bits = undefined,
3786 .class = undefined,
38043787 .size = undefined,
38053788 .alignment = undefined,
38063789 };
......@@ -3865,7 +3848,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38653848 .auto => .auto,
38663849 .@"extern" => .@"extern",
38673850 },
3868 .runtime_tag = extra.data.flags.runtime_tag,
3851 .tag_usage = extra.data.flags.tag_usage,
38693852 .enum_tag_mode = extra.data.flags.enum_tag_mode,
38703853 .enum_tag_type = extra.data.enum_tag_type,
38713854 .packed_backing_mode = undefined,
......@@ -3874,10 +3857,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38743857 .want_layout = extra.data.flags.want_layout,
38753858 .field_types = field_types,
38763859 .field_aligns = field_aligns,
3877 .has_no_possible_value = extra.data.flags.has_no_possible_value,
3878 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3879 .comptime_only = extra.data.flags.comptime_only,
3880 .has_runtime_bits = extra.data.flags.has_runtime_bits,
3860 .has_runtime_tag = extra.data.flags.has_runtime_tag,
3861 .class = extra.data.flags.class,
38813862 .size = extra.data.size,
38823863 .padding = extra.data.padding,
38833864 .alignment = extra.data.flags.alignment,
......@@ -3919,7 +3900,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
39193900 .name_nav = extra.data.name_nav,
39203901 .namespace = extra.data.namespace,
39213902 .layout = .@"packed",
3922 .runtime_tag = .none,
3903 .tag_usage = .none,
39233904 .enum_tag_mode = .auto,
39243905 .enum_tag_type = extra.data.enum_tag_type,
39253906 .packed_backing_mode = backing_mode,
......@@ -3928,10 +3909,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
39283909 .want_layout = extra.data.bits.want_layout,
39293910 .field_types = field_types,
39303911 .field_aligns = .empty,
3931 .has_no_possible_value = undefined,
3932 .has_one_possible_value = undefined,
3933 .comptime_only = undefined,
3934 .has_runtime_bits = undefined,
3912 .has_runtime_tag = undefined,
3913 .class = undefined,
39353914 .size = undefined,
39363915 .padding = undefined,
39373916 .alignment = undefined,
......@@ -4818,7 +4797,7 @@ pub const static_keys: [static_len]Key = .{
48184797 .values = .empty,
48194798 } },
48204799
4821 .{ .simple_value = .undefined },
4800 .{ .undef = .undefined_type },
48224801 .{ .undef = .bool_type },
48234802 .{ .undef = .usize_type },
48244803 .{ .undef = .u1_type },
......@@ -5682,23 +5661,14 @@ pub const Tag = enum(u8) {
56825661 any_field_defaults: bool,
56835662 any_field_aligns: bool,
56845663
5685 /// Whether the struct is an OPV type. Always `false` until layout resolved.
5686 /// The actual OPV is not cached, but caching this bit of state means we avoid
5687 /// repeatedly doing redundant checks to find that the struct is not OPV!
5688 has_one_possible_value: bool,
5689 /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn).
5690 has_no_possible_value: bool,
5691 /// Whether the struct is comptime-only. Always `false` until layout resolved.
5692 comptime_only: bool,
5693 /// Whether the struct has runtime bits. Always `false` until layout resolved.
5694 has_runtime_bits: bool,
5664 class: TypeClass,
56955665 /// Alignment of the whole struct. Always `.none` until layout resolved.
56965666 alignment: Alignment,
56975667
56985668 want_layout: bool,
56995669 want_defaults: bool,
57005670
5701 _: u14 = 0,
5671 _: u15 = 0,
57025672 };
57035673 };
57045674
......@@ -5778,18 +5748,11 @@ pub const Tag = enum(u8) {
57785748 layout: enum(u1) { auto, @"extern" },
57795749
57805750 any_field_aligns: bool,
5781 runtime_tag: LoadedUnionType.RuntimeTag,
5782
5783 /// Whether the union is an OPV type. Always `false` until layout resolved.
5784 /// The actual OPV is not cached, but caching this bit of state means we avoid
5785 /// repeatedly doing redundant checks to find that the union is not OPV!
5786 has_one_possible_value: bool,
5787 /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn).
5788 has_no_possible_value: bool,
5789 /// Whether the union is comptime-only. Always `false` until layout resolved.
5790 comptime_only: bool,
5791 /// Whether the union has runtime bits. Always `false` until layout resolved.
5792 has_runtime_bits: bool,
5751 tag_usage: LoadedUnionType.TagUsage,
5752
5753 class: TypeClass,
5754 has_runtime_tag: bool,
5755
57935756 /// Alignment of the whole union. Always `.none` until layout resolved.
57945757 alignment: Alignment,
57955758
......@@ -5970,8 +5933,6 @@ pub const SimpleType = enum(u32) {
59705933};
59715934
59725935pub const SimpleValue = enum(u32) {
5973 /// This is untyped `undefined`.
5974 undefined = @intFromEnum(Index.undef),
59755936 void = @intFromEnum(Index.void_value),
59765937 /// This is untyped `null`.
59775938 null = @intFromEnum(Index.null_value),
......@@ -7016,11 +6977,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
70166977 } };
70176978 },
70186979
7019 .type_enum_auto,
7020 .type_enum_explicit,
7021 .type_union,
7022 => .{ .empty_enum_value = ty },
7023
70246980 else => unreachable,
70256981 };
70266982 },
......@@ -7914,11 +7870,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
79147870 });
79157871 },
79167872
7917 .empty_enum_value => |enum_or_union_ty| items.appendAssumeCapacity(.{
7918 .tag = .only_possible_value,
7919 .data = @intFromEnum(enum_or_union_ty),
7920 }),
7921
79227873 .float => |float| {
79237874 switch (float.ty) {
79247875 .f16_type => items.appendAssumeCapacity(.{
......@@ -8302,10 +8253,7 @@ pub fn getDeclaredStructType(
83028253 .any_comptime_fields = ini.any_comptime_fields,
83038254 .any_field_defaults = ini.any_field_defaults,
83048255 .any_field_aligns = ini.any_field_aligns,
8305 .has_one_possible_value = false,
8306 .has_no_possible_value = false,
8307 .comptime_only = false,
8308 .has_runtime_bits = false,
8256 .class = .no_possible_value,
83098257 .alignment = .none,
83108258 .want_layout = false,
83118259 .want_defaults = false,
......@@ -8456,10 +8404,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
84568404 .any_comptime_fields = ini.any_comptime_fields,
84578405 .any_field_defaults = ini.any_field_defaults,
84588406 .any_field_aligns = ini.any_field_aligns,
8459 .has_one_possible_value = false,
8460 .has_no_possible_value = false,
8461 .comptime_only = false,
8462 .has_runtime_bits = false,
8407 .class = .no_possible_value,
84638408 .alignment = .none,
84648409 .want_layout = false,
84658410 .want_defaults = false,
......@@ -8535,7 +8480,7 @@ pub fn getDeclaredUnionType(
85358480 fields_len: u32,
85368481 layout: std.builtin.Type.ContainerLayout,
85378482 any_field_aligns: bool,
8538 runtime_tag: LoadedUnionType.RuntimeTag,
8483 tag_usage: LoadedUnionType.TagUsage,
85398484 enum_tag_mode: BackingTypeMode,
85408485 packed_backing_mode: BackingTypeMode,
85418486 },
......@@ -8617,11 +8562,9 @@ pub fn getDeclaredUnionType(
86178562 .enum_tag_mode = ini.enum_tag_mode,
86188563 .layout = if (is_extern) .@"extern" else .auto,
86198564 .any_field_aligns = ini.any_field_aligns,
8620 .runtime_tag = ini.runtime_tag,
8621 .has_one_possible_value = false,
8622 .has_no_possible_value = false,
8623 .comptime_only = false,
8624 .has_runtime_bits = false,
8565 .tag_usage = ini.tag_usage,
8566 .class = .no_possible_value,
8567 .has_runtime_tag = false,
86258568 .alignment = .none,
86268569 .want_layout = false,
86278570 },
......@@ -8658,8 +8601,8 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
86588601 fields_len: u32,
86598602 layout: std.builtin.Type.ContainerLayout,
86608603 any_field_aligns: bool,
8661 runtime_tag: LoadedUnionType.RuntimeTag,
8662 /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`.
8604 tag_usage: LoadedUnionType.TagUsage,
8605 /// Explicitly specified enum tag type. `.none` if `tag_usage != .tagged`.
86638606 enum_tag_type: Index,
86648607 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
86658608 packed_backing_int_type: Index,
......@@ -8745,11 +8688,9 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
87458688 .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,
87468689 .layout = if (is_extern) .@"extern" else .auto,
87478690 .any_field_aligns = ini.any_field_aligns,
8748 .runtime_tag = ini.runtime_tag,
8749 .has_one_possible_value = false,
8750 .has_no_possible_value = false,
8751 .comptime_only = false,
8752 .has_runtime_bits = false,
8691 .tag_usage = ini.tag_usage,
8692 .class = .no_possible_value,
8693 .has_runtime_tag = false,
87538694 .alignment = .none,
87548695 .want_layout = false,
87558696 },
......@@ -12007,20 +11948,6 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
1200711948 ]);
1200811949}
1200911950
12010pub fn isNoReturn(ip: *const InternPool, ty: Index) bool {
12011 switch (ty) {
12012 .noreturn_type => return true,
12013 else => {
12014 const unwrapped_ty = ty.unwrap(ip);
12015 const ty_item = unwrapped_ty.getItem(ip);
12016 return switch (ty_item.tag) {
12017 .type_error_set => unwrapped_ty.getExtra(ip).view().items(.@"0")[ty_item.data + std.meta.fieldIndex(Tag.ErrorSet, "names_len").?] == 0,
12018 else => false,
12019 };
12020 },
12021 }
12022}
12023
1202411951pub fn isUndef(ip: *const InternPool, val: Index) bool {
1202511952 return val == .undef or val.unwrap(ip).getTag(ip) == .undef;
1202611953}
......@@ -12823,10 +12750,7 @@ pub fn resolveStructLayout(
1282312750 struct_type: Index,
1282412751 size: u32,
1282512752 alignment: Alignment,
12826 has_no_possible_value: bool,
12827 has_one_possible_value: bool,
12828 comptime_only: bool,
12829 has_runtime_bits: bool,
12753 class: TypeClass,
1283012754) void {
1283112755 const unwrapped_index = struct_type.unwrap(ip);
1283212756
......@@ -12840,10 +12764,7 @@ pub fn resolveStructLayout(
1284012764
1284112765 extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size;
1284212766 const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?]);
12843 flags.has_no_possible_value = has_no_possible_value;
12844 flags.has_one_possible_value = has_one_possible_value;
12845 flags.comptime_only = comptime_only;
12846 flags.has_runtime_bits = has_runtime_bits;
12767 flags.class = class;
1284712768 flags.alignment = alignment;
1284812769}
1284912770
......@@ -12856,13 +12777,11 @@ pub fn resolveUnionLayout(
1285612777 io: Io,
1285712778 union_type: Index,
1285812779 enum_tag_type: Index,
12780 class: TypeClass,
12781 has_runtime_tag: bool,
1285912782 size: u32,
1286012783 padding: u32,
1286112784 alignment: Alignment,
12862 has_no_possible_value: bool,
12863 has_one_possible_value: bool,
12864 comptime_only: bool,
12865 has_runtime_bits: bool,
1286612785) void {
1286712786 const unwrapped_index = union_type.unwrap(ip);
1286812787
......@@ -12878,10 +12797,8 @@ pub fn resolveUnionLayout(
1287812797 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
1287912798 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
1288012799 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);
12881 flags.has_no_possible_value = has_no_possible_value;
12882 flags.has_one_possible_value = has_one_possible_value;
12883 flags.comptime_only = comptime_only;
12884 flags.has_runtime_bits = has_runtime_bits;
12800 flags.class = class;
12801 flags.has_runtime_tag = has_runtime_tag;
1288512802 flags.alignment = alignment;
1288612803}
1288712804
src/Sema.zig+195-237
......@@ -178,8 +178,11 @@ const ComptimeAlloc = struct {
178178fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
179179 const pt = sema.pt;
180180
181 // Explicit guard because this call mutates the InternPool so cannot be optimized out.
182 if (std.debug.runtime_safety) assert(ty.onePossibleValue(pt) catch @panic("") == null);
181 switch (ty.classify(pt.zcu)) {
182 .no_possible_value => unreachable,
183 .one_possible_value => unreachable,
184 else => {},
185 }
183186
184187 const idx = sema.comptime_allocs.items.len;
185188 try sema.comptime_allocs.append(sema.gpa, .{
......@@ -1991,31 +1994,28 @@ fn analyzeBodyInner(
19911994 break :blk .void_value;
19921995 },
19931996 };
1994 if (sema.isNoReturn(air_ref)) {
1995 // We're going to assume that the body itself is noreturn, so let's ensure that now
1996 assert(block.instructions.items.len > 0);
1997 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));
1998 break;
1999 }
20001997
1998 const is_inferred_alloc = if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
1999 .inferred_alloc, .inferred_alloc_comptime => true,
2000 else => false,
2001 } else false;
20012002 // We must resolve the layout of a type before creating a value of that type. Therefore,
2002 // the layout of the type of `air_ref` must already be resolved.
2003 check_type: {
2004 if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
2005 .inferred_alloc, .inferred_alloc_comptime => break :check_type,
2006 else => {},
2007 };
2008 sema.typeOf(air_ref).assertHasLayout(zcu);
2009 // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value
2010 // it could be, and it would be a bug for the value to not be comptime-known when it has
2011 // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates
2012 // the InternPool so cannot be optimized out.
2013 if (std.debug.runtime_safety) {
2014 if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| {
2015 assert(air_ref == Air.Inst.Ref.fromValue(opv));
2016 }
2017 }
2018 }
2003 // the layout of the type of `air_ref` must already be resolved. The call to `classify`
2004 // doubles as an assertion of this.
2005 if (!is_inferred_alloc) switch (sema.typeOf(air_ref).classify(zcu)) {
2006 .no_possible_value => {
2007 // The instruction result was noreturn, which should mean that the body itself now
2008 // ends with a noreturn instruction. Let's confirm that.
2009 const last_inst = block.instructions.items[block.instructions.items.len - 1];
2010 const last_inst_ty = sema.typeOf(last_inst.toRef());
2011 assert(last_inst_ty.classify(zcu) == .no_possible_value);
2012 break;
2013 },
2014 .one_possible_value => assert(air_ref.toInterned() != null), // the value should be comptime-known
2015 .partially_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
2016 .fully_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
2017 .runtime => {},
2018 };
20192019
20202020 map.putAssumeCapacity(inst, air_ref);
20212021 i += 1;
......@@ -2287,11 +2287,12 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value {
22872287 .inferred_alloc_comptime => unreachable, // assertion failure
22882288 else => {},
22892289 }
2290 // Assert that the type is not OPV -- if it was, the value would have been comptime-known.
2291 // Explicit guard because this could add to the InternPool so cannot be optimized away.
2292 if (std.debug.runtime_safety) {
2293 const opv = sema.typeOf(inst).onePossibleValue(sema.pt) catch @panic("oom in assert");
2294 assert(opv == null);
2290 switch (sema.typeOf(inst).classify(zcu)) {
2291 .no_possible_value => unreachable, // values of this type do not exist
2292 .one_possible_value => unreachable, // the value should be comptime-known
2293 .partially_comptime => unreachable, // the value should be comptime-known
2294 .fully_comptime => unreachable, // the value should be comptime-known
2295 .runtime => {},
22952296 }
22962297 return null;
22972298 }
......@@ -4645,16 +4646,21 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
46454646 const elem_ty = operand_ty.childType(zcu);
46464647 try sema.ensureLayoutResolved(elem_ty, src);
46474648
4648 if (try elem_ty.onePossibleValue(pt) != null) {
4649 // No need to validate the actual pointer value, we don't need it!
4650 return;
4651 }
4649 const need_comptime = switch (elem_ty.classify(zcu)) {
4650 .no_possible_value => return sema.fail(block, src, "cannot load {s} type '{f}'", .{
4651 if (elem_ty.zigTypeTag(zcu) == .@"opaque") "opaque" else "uninstantiable",
4652 elem_ty.fmt(pt),
4653 }),
4654 .one_possible_value => return, // no need to validate the actual pointer value!
4655 .runtime => false,
4656 .partially_comptime, .fully_comptime => true,
4657 };
46524658
46534659 if (sema.resolveValue(operand)) |val| {
46544660 if (val.isUndef(zcu)) {
46554661 return sema.fail(block, src, "cannot dereference undefined value", .{});
46564662 }
4657 } else if (elem_ty.comptimeOnly(zcu)) {
4663 } else if (need_comptime) {
46584664 const msg = msg: {
46594665 const msg = try sema.errMsg(
46604666 src,
......@@ -4870,7 +4876,7 @@ fn storeToInferredAllocComptime(
48704876 .is_const = iac.is_const,
48714877 },
48724878 });
4873 if (try operand_ty.onePossibleValue(pt) != null or
4879 if (operand_ty.classify(zcu) == .one_possible_value or
48744880 (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)))
48754881 {
48764882 iac.ptr = try pt.intern(.{ .ptr = .{
......@@ -6672,7 +6678,7 @@ const CallArgsInfo = union(enum) {
66726678 return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);
66736679 }
66746680
6675 if (sema.typeOf(uncoerced_arg).zigTypeTag(zcu) == .noreturn) {
6681 if (sema.typeOf(uncoerced_arg).classify(zcu) == .no_possible_value) {
66766682 // This terminates resolution of arguments. The caller should
66776683 // propagate this.
66786684 return uncoerced_arg;
......@@ -6928,7 +6934,7 @@ fn analyzeCall(
69286934
69296935 arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst);
69306936 const arg_ty = sema.typeOf(arg.*);
6931 if (arg_ty.zigTypeTag(zcu) == .noreturn) {
6937 if (arg_ty.classify(zcu) == .no_possible_value) {
69326938 return arg.*; // terminate analysis here
69336939 }
69346940
......@@ -7183,7 +7189,7 @@ fn analyzeCall(
71837189 return sema.handleTailCall(block, call_src, runtime_func_ty, maybe_opv);
71847190 }
71857191
7186 if (ip.isNoReturn(resolved_ret_ty.toIntern())) {
7192 if (resolved_ret_ty.isNoReturn(zcu)) {
71877193 const want_check = c: {
71887194 if (!block.wantSafety()) break :c false;
71897195 if (func_val != null) break :c false;
......@@ -7989,16 +7995,16 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
79897995 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {
79907996 .@"enum" => operand,
79917997 .@"union" => blk: {
7992 const tag_ty = operand_ty.unionTagType(zcu) orelse {
7998 if (operand_ty.unionTagType(zcu) == null) {
79937999 return sema.fail(
79948000 block,
79958001 operand_src,
79968002 "untagged union '{f}' cannot be converted to integer",
79978003 .{operand_ty.fmt(pt)},
79988004 );
7999 };
8005 }
80008006
8001 break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
8007 break :blk try sema.unionToTag(block, operand);
80028008 },
80038009 else => {
80048010 return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{
......@@ -10151,9 +10157,8 @@ fn analyzeSwitchBlock(
1015110157 const maybe_operand_opv = try operand_ty.onePossibleValue(pt);
1015210158 const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
1015310159 .@"union" => tag: {
10154 const tag_ty = operand_ty.unionTagType(zcu).?;
10155 const tag_val = try sema.unionToTag(block, tag_ty, val, operand_src);
10156 break :tag .{ tag_val, tag_ty };
10160 const tag_val = try sema.unionToTag(block, val);
10161 break :tag .{ tag_val, sema.typeOf(tag_val) };
1015710162 },
1015810163 else => .{
1015910164 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,
......@@ -10245,7 +10250,7 @@ fn analyzeSwitchBlock(
1024510250 .{ new_operand, .none };
1024610251
1024710252 const new_cond_ref = if (union_originally)
10248 try sema.unionToTag(child_block, item_ty, new_val, src)
10253 try sema.unionToTag(child_block, new_val)
1024910254 else
1025010255 new_val;
1025110256
......@@ -12147,8 +12152,7 @@ fn analyzeSwitchTagCapture(
1214712152 .item_refs => |refs| if (refs.len == 1) return refs[0],
1214812153 .special => {},
1214912154 }
12150 const tag_ty = operand_ty.unionTagType(zcu).?;
12151 return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src);
12155 return sema.unionToTag(case_block, operand_val);
1215212156}
1215312157
1215412158fn analyzeSwitchPayloadCapture(
......@@ -15389,9 +15393,12 @@ fn analyzePtrArithmetic(
1538915393 const elem_ty: Type = .fromInterned(ptr_info.child);
1539015394 elem_ty.assertHasLayout(zcu);
1539115395
15392 if (elem_ty.abiSize(zcu) == 0) {
15393 // Offset will be multiplied by zero, so result is the same as the base pointer.
15394 return ptr;
15396 switch (elem_ty.classify(zcu)) {
15397 .no_possible_value, .one_possible_value => {
15398 // Offset will be multiplied by zero, so result is the same as the base pointer.
15399 return ptr;
15400 },
15401 else => {},
1539515402 }
1539615403
1539715404 const new_ptr_ty = t: {
......@@ -15757,7 +15764,7 @@ fn analyzeCmpUnionTag(
1575715764 if (sema.resolveValue(coerced_tag)) |enum_val| {
1575815765 if (enum_val.isUndef(zcu)) return .undef_bool;
1575915766 const field_ty = union_ty.unionFieldType(enum_val, zcu).?;
15760 if (field_ty.zigTypeTag(zcu) == .noreturn) {
15767 if (field_ty.classify(zcu) == .no_possible_value) {
1576115768 return .bool_false;
1576215769 }
1576315770 }
......@@ -15934,39 +15941,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1593415941 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1593515942 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
1593615943 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
15937 switch (ty.zigTypeTag(zcu)) {
15938 .@"fn",
15939 .noreturn,
15940 .undefined,
15941 .null,
15942 .@"opaque",
15943 => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}),
15944 try sema.ensureLayoutResolved(ty, operand_src);
15945 switch (ty.classify(zcu)) {
15946 .no_possible_value,
15947 => return sema.fail(block, operand_src, "no size available for uninstantiable type '{f}'", .{ty.fmt(pt)}),
1594415948
15945 .type,
15946 .enum_literal,
15947 .comptime_float,
15948 .comptime_int,
15949 .void,
15950 => return .zero,
15949 .partially_comptime,
15950 .fully_comptime,
15951 => return sema.fail(block, operand_src, "no size available for comptime-only type '{f}'", .{ty.fmt(pt)}),
1595115952
15952 .bool,
15953 .int,
15954 .float,
15955 .pointer,
15956 .array,
15957 .@"struct",
15958 .optional,
15959 .error_union,
15960 .error_set,
15961 .@"enum",
15962 .@"union",
15963 .vector,
15964 .frame,
15965 .@"anyframe",
15966 => {},
15953 .one_possible_value => {
15954 assert(ty.abiSize(zcu) == 0);
15955 return .zero;
15956 },
15957
15958 .runtime => return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu))),
1596715959 }
15968 try sema.ensureLayoutResolved(ty, operand_src);
15969 return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu)));
1597015960}
1597115961
1597215962fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -18631,9 +18621,9 @@ fn zirStructInit(
1863118621 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
1863218622 const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);
1863318623
18634 if (field_ty.zigTypeTag(zcu) == .noreturn) {
18624 if (field_ty.classify(zcu) == .no_possible_value) {
1863518625 return sema.failWithOwnedErrorMsg(block, msg: {
18636 const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
18626 const msg = try sema.errMsg(src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
1863718627 errdefer msg.destroy(sema.gpa);
1863818628
1863918629 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{
......@@ -18648,7 +18638,13 @@ fn zirStructInit(
1864818638 const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src);
1864918639
1865018640 if (resolved_ty.containerLayout(zcu) == .@"packed") {
18651 return sema.bitCast(block, resolved_ty, init_inst, src, field_src);
18641 const union_val = try sema.bitCast(block, resolved_ty, init_inst, src, field_src);
18642 const result_val = try sema.coerce(block, result_ty, union_val, src);
18643 if (is_ref) {
18644 return sema.analyzeRef(block, src, result_val);
18645 } else {
18646 return result_val;
18647 }
1865218648 }
1865318649
1865418650 if (sema.resolveValue(init_inst)) |val| {
......@@ -18681,9 +18677,6 @@ fn zirStructInit(
1868118677 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
1868218678 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);
1868318679 try sema.storePtr(block, src, field_ptr, init_inst);
18684 if (try tag_ty.onePossibleValue(pt) == null) {
18685 _ = try block.addBinOp(.set_union_tag, base_ptr, .fromValue(tag_val));
18686 }
1868718680 return sema.makePtrConst(block, alloc);
1868818681 }
1868918682
......@@ -19451,10 +19444,10 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1945119444 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1945219445 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
1945319446 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
19447 try sema.ensureLayoutResolved(ty, operand_src);
1945419448 if (ty.isNoReturn(zcu)) {
1945519449 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
1945619450 }
19457 try sema.ensureLayoutResolved(ty, operand_src);
1945819451 return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?));
1945919452}
1946019453
......@@ -20447,10 +20440,10 @@ fn zirReifyUnion(
2044720440 .fields_len = @intCast(fields_len),
2044820441 .layout = layout,
2044920442 .any_field_aligns = any_field_aligns,
20450 .runtime_tag = rt: {
20451 if (explicit_tag_ty != null) break :rt .tagged;
20452 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
20453 break :rt .none;
20443 .tag_usage = tag: {
20444 if (explicit_tag_ty != null) break :tag .tagged;
20445 if (layout == .auto and block.wantSafeTypes()) break :tag .safety;
20446 break :tag .none;
2045420447 },
2045520448 .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,
2045620449 .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,
......@@ -22608,7 +22601,7 @@ fn zirCmpxchg(
2260822601 const result_ty = try pt.optionalType(elem_ty.toIntern());
2260922602
2261022603 // special case zero bit types
22611 if (try elem_ty.onePossibleValue(pt) != null) {
22604 if (elem_ty.classify(zcu) == .one_possible_value) {
2261222605 return .fromValue(try pt.nullValue(result_ty));
2261322606 }
2261422607
......@@ -25514,8 +25507,9 @@ fn fieldPtrLoad(
2551425507 const pt = sema.pt;
2551525508 const zcu = pt.zcu;
2551625509 const object_ptr_ty = sema.typeOf(object_ptr);
25510 assert(object_ptr_ty.zigTypeTag(zcu) == .pointer);
2551725511 const pointee_ty = object_ptr_ty.childType(zcu);
25518 try sema.ensureLayoutResolved(pointee_ty, src); // MLUGG TODO
25512 try sema.ensureLayoutResolved(pointee_ty, src);
2551925513 if (try pointee_ty.onePossibleValue(pt)) |opv| {
2552025514 const object: Air.Inst.Ref = .fromValue(opv);
2552125515 return fieldVal(sema, block, src, object, field_name, field_name_src);
......@@ -26477,9 +26471,9 @@ fn unionFieldPtr(
2647726471 });
2647826472 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?);
2647926473
26480 if (initializing and field_ty.zigTypeTag(zcu) == .noreturn) {
26474 if (initializing and field_ty.classify(zcu) == .no_possible_value) {
2648126475 const msg = msg: {
26482 const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
26476 const msg = try sema.errMsg(src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
2648326477 errdefer msg.destroy(sema.gpa);
2648426478
2648526479 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
......@@ -26529,30 +26523,29 @@ fn unionFieldPtr(
2652926523 },
2653026524 .@"packed", .@"extern" => {},
2653126525 }
26532 const field_ptr_val = try union_ptr_val.ptrField(field_index, pt);
26533 return Air.internedToRef(field_ptr_val.toIntern());
26526 return .fromValue(try union_ptr_val.ptrField(field_index, pt));
2653426527 }
2653526528
2653626529 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
2653726530 tag: {
2653826531 if (union_ty.containerLayout(zcu) != .auto) break :tag;
2653926532 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
26540 if (try tag_ty.onePossibleValue(pt) != null) break :tag;
26533 if (tag_ty.classify(zcu) == .one_possible_value) break :tag;
2654126534 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
2654226535 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
2654326536 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
2654426537 if (initializing) {
2654526538 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
2654626539 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
26547 } else if (block.wantSafety() and union_obj.runtime_tag != .none) {
26548 // The tag exists at runtime (safety tag), so emit a safety check.
26540 } else if (block.wantSafety() and union_obj.has_runtime_tag) {
26541 // The tag exists at runtime (actual or safety tag), so emit a safety check.
2654926542 // TODO would it be better if get_union_tag supported pointers to unions?
2655026543 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
2655126544 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
2655226545 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
2655326546 }
2655426547 }
26555 if (field_ty.zigTypeTag(zcu) == .noreturn) {
26548 if (field_ty.classify(zcu) == .no_possible_value) {
2655626549 _ = try block.addNoOp(.unreach);
2655726550 return .unreachable_value;
2655826551 }
......@@ -26578,57 +26571,40 @@ fn unionFieldVal(
2657826571 const union_obj = zcu.typeToUnion(union_ty).?;
2657926572 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2658026573 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
26581 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?);
26574 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
2658226575
2658326576 if (sema.resolveValue(union_byval)) |union_val| {
2658426577 if (union_val.isUndef(zcu)) return pt.undefRef(field_ty);
26585
26586 const un = ip.indexToKey(union_val.toIntern()).un;
26587 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
26588 const tag_matches = un.tag == field_tag.toIntern();
2658926578 switch (union_obj.layout) {
2659026579 .auto => {
26591 if (tag_matches) {
26592 return Air.internedToRef(un.val);
26593 } else {
26594 const msg = msg: {
26595 const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
26596 const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu);
26597 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
26598 field_name.fmt(ip), active_field_name.fmt(ip),
26599 });
26600 errdefer msg.destroy(sema.gpa);
26601 try sema.addDeclaredHereNote(msg, union_ty);
26602 break :msg msg;
26603 };
26604 return sema.failWithOwnedErrorMsg(block, msg);
26605 }
26580 const active_tag_val = union_val.unionTag(zcu).?;
26581 const active_index = enum_tag_ty.enumTagFieldIndex(active_tag_val, zcu).?;
26582 if (active_index == field_index) return .fromValue(union_val.unionPayload(zcu));
26583 return sema.fail(block, src, "access of union field '{f}' while field '{f}' is active", .{
26584 field_name.fmt(ip), enum_tag_ty.enumFieldName(active_index, zcu).fmt(ip),
26585 });
2660626586 },
26607 .@"extern" => if (tag_matches) {
26608 // Fast path - no need to use bitcast logic.
26609 return Air.internedToRef(un.val);
26610 } else if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
26611 return Air.internedToRef(field_val.toIntern());
26587 .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
26588 return .fromValue(field_val);
26589 } else {
26590 // Runtime-known due to a pointer-to-integer conversion.
2661226591 },
26613 .@"packed" => if (tag_matches) {
26614 // Fast path - no need to use bitcast logic.
26615 return Air.internedToRef(un.val);
26616 } else if (try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0)) |field_val| {
26617 return Air.internedToRef(field_val.toIntern());
26592 .@"packed" => {
26593 const field_val = try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0) orelse {
26594 unreachable; // `null` is only possible if the input value contains a pointer, which a packed union cannot.
26595 };
26596 return .fromValue(field_val);
2661826597 },
2661926598 }
2662026599 }
2662126600
26622 if (union_obj.layout == .auto and block.wantSafety() and
26623 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
26624 {
26625 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
26626 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
26627 const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_type), union_byval);
26628 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);
26601 if (union_obj.layout == .auto and block.wantSafety() and union_obj.has_runtime_tag) {
26602 const wanted_tag_val = try pt.enumValueFieldIndex(enum_tag_ty, field_index);
26603 const active_tag = try block.addTyOp(.get_union_tag, enum_tag_ty, union_byval);
26604 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(wanted_tag_val));
2662926605 }
2663026606
26631 if (field_ty.zigTypeTag(zcu) == .noreturn) {
26607 if (field_ty.classify(zcu) == .no_possible_value) {
2663226608 _ = try block.addNoOp(.unreach);
2663326609 return .unreachable_value;
2663426610 }
......@@ -27767,11 +27743,10 @@ fn coerceExtra(
2776727743 };
2776827744 return Air.internedToRef((try pt.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());
2776927745 },
27770 .@"union" => blk: {
27746 .@"union" => if (inst_ty.unionTagType(zcu)) |enum_tag_ty| {
2777127747 // union to its own tag type
27772 const union_tag_ty = inst_ty.unionTagType(zcu) orelse break :blk;
27773 if (union_tag_ty.eql(dest_ty, zcu)) {
27774 return sema.unionToTag(block, dest_ty, inst, inst_src);
27748 if (enum_tag_ty.toIntern() == dest_ty.toIntern()) {
27749 return sema.unionToTag(block, inst);
2777527750 }
2777627751 },
2777727752 else => {},
......@@ -27857,18 +27832,16 @@ fn coerceExtra(
2785727832 else => {},
2785827833 }
2785927834
27860 const can_coerce_to = switch (dest_ty.zigTypeTag(zcu)) {
27861 .noreturn, .@"opaque" => false,
27862 else => true,
27835 const dest_is_npv = switch (dest_ty.classify(zcu)) {
27836 .no_possible_value => true,
27837 .one_possible_value => if (inst == .undef) {
27838 return .fromValue((try dest_ty.onePossibleValue(pt)).?);
27839 } else false,
27840 .runtime, .fully_comptime, .partially_comptime => if (inst == .undef) {
27841 return .fromValue(try pt.undefValue(dest_ty));
27842 } else false,
2786327843 };
2786427844
27865 if (can_coerce_to and inst == .undef) {
27866 // undefined to anything. We do this after the big switch above so that
27867 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
27868 // should initialize the length field of the slice.
27869 return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty));
27870 }
27871
2787227845 if (!opts.report_err) return error.NotCoercible;
2787327846
2787427847 if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .noreturn) {
......@@ -27890,8 +27863,8 @@ fn coerceExtra(
2789027863 const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty);
2789127864 errdefer msg.destroy(sema.gpa);
2789227865
27893 if (!can_coerce_to) {
27894 try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)});
27866 if (dest_is_npv) {
27867 try sema.errNote(inst_src, msg, "cannot coerce to uninstantiable type '{f}'", .{dest_ty.fmt(pt)});
2789527868 }
2789627869
2789727870 // E!T to T
......@@ -29099,6 +29072,13 @@ fn storePtr2(
2909929072 };
2910029073 const maybe_operand_val = sema.resolveValue(operand);
2910129074
29075 const comptime_only = switch (elem_ty.classify(zcu)) {
29076 .no_possible_value => unreachable, // the coercion should have failed
29077 .one_possible_value => return, // no actual store operation is necessary
29078 .runtime => false,
29079 .partially_comptime, .fully_comptime => true,
29080 };
29081
2910229082 const runtime_src = rs: {
2910329083 const ptr_val = try sema.resolveDefinedValue(block, ptr_src, ptr) orelse break :rs ptr_src;
2910429084 if (!sema.isComptimeMutablePtr(ptr_val)) break :rs ptr_src;
......@@ -29106,16 +29086,9 @@ fn storePtr2(
2910629086 return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
2910729087 };
2910829088
29109 // We do this after the possible comptime store above, for the case of field_ptr stores
29110 // to unions because we want the comptime tag to be set, even if the field type is void.
29111 // MLUGG TODO: that's insane, the runtime and comptime sematics should be the same. just set the tag at the same damn time
29112 if (try elem_ty.onePossibleValue(pt) != null) {
29113 return;
29114 }
29115
2911629089 // We're performing the store at runtime; as such, we need to make sure the pointee type
2911729090 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.
29118 if (elem_ty.comptimeOnly(zcu)) {
29091 if (comptime_only) {
2911929092 return sema.failWithOwnedErrorMsg(block, msg: {
2912029093 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
2912129094 errdefer msg.destroy(sema.gpa);
......@@ -29477,7 +29450,7 @@ fn coerceEnumToUnion(
2947729450 const enum_ty: Type = .fromInterned(union_obj.enum_tag_type);
2947829451 const enum_obj = ip.loadEnumType(enum_ty.toIntern());
2947929452
29480 if (union_obj.runtime_tag != .tagged) return sema.failWithOwnedErrorMsg(block, msg: {
29453 if (union_obj.tag_usage != .tagged) return sema.failWithOwnedErrorMsg(block, msg: {
2948129454 const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);
2948229455 errdefer msg.destroy(sema.gpa);
2948329456 try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});
......@@ -29495,31 +29468,35 @@ fn coerceEnumToUnion(
2949529468
2949629469 const field_name = enum_obj.field_names.get(ip)[field_index];
2949729470 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
29498 if (field_ty.zigTypeTag(zcu) == .noreturn) {
29499 const msg = msg: {
29500 const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});
29471 switch (field_ty.classify(zcu)) {
29472 .one_possible_value => return .fromValue(try pt.unionValue(
29473 union_ty,
29474 val,
29475 (try field_ty.onePossibleValue(pt)).?,
29476 )),
29477
29478 .no_possible_value => return sema.failWithOwnedErrorMsg(block, msg: {
29479 const msg = try sema.errMsg(inst_src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
2950129480 errdefer msg.destroy(sema.gpa);
2950229481 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
2950329482 field_name.fmt(ip),
2950429483 });
2950529484 try sema.addDeclaredHereNote(msg, union_ty);
2950629485 break :msg msg;
29507 };
29508 return sema.failWithOwnedErrorMsg(block, msg);
29509 }
29510 const opv = try field_ty.onePossibleValue(pt) orelse return sema.failWithOwnedErrorMsg(block, msg: {
29511 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
29512 inst_ty.fmt(pt), union_ty.fmt(pt),
29513 field_ty.fmt(pt), field_name.fmt(ip),
29514 });
29515 errdefer msg.destroy(sema.gpa);
29486 }),
2951629487
29517 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)});
29518 try sema.addDeclaredHereNote(msg, union_ty);
29519 break :msg msg;
29520 });
29488 else => return sema.failWithOwnedErrorMsg(block, msg: {
29489 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
29490 inst_ty.fmt(pt), union_ty.fmt(pt),
29491 field_ty.fmt(pt), field_name.fmt(ip),
29492 });
29493 errdefer msg.destroy(sema.gpa);
2952129494
29522 return Air.internedToRef((try pt.unionValue(union_ty, val, opv)).toIntern());
29495 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)});
29496 try sema.addDeclaredHereNote(msg, union_ty);
29497 break :msg msg;
29498 }),
29499 }
2952329500 }
2952429501
2952529502 try sema.requireRuntimeBlock(block, inst_src, null);
......@@ -29536,32 +29513,14 @@ fn coerceEnumToUnion(
2953629513 return sema.failWithOwnedErrorMsg(block, msg);
2953729514 }
2953829515
29539 {
29540 var msg: ?*Zcu.ErrorMsg = null;
29541 errdefer if (msg) |some| some.destroy(sema.gpa);
29542
29543 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
29544 if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .noreturn) {
29545 const err_msg = msg orelse try sema.errMsg(
29546 inst_src,
29547 "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field",
29548 .{ enum_ty.fmt(pt), union_ty.fmt(pt) },
29549 );
29550 msg = err_msg;
29551
29552 try sema.addFieldErrNote(union_ty, field_index, err_msg, "'noreturn' field here", .{});
29553 }
29554 }
29555 if (msg) |some| {
29556 msg = null;
29557 try sema.addDeclaredHereNote(some, union_ty);
29558 return sema.failWithOwnedErrorMsg(block, some);
29559 }
29560 }
29561
29562 // If the union has all fields 0 bits, the union value is just the enum value.
2956329516 if (union_ty.unionHasAllZeroBitFieldTypes(zcu)) {
29564 return block.addBitCast(union_ty, enum_tag);
29517 if (try union_ty.onePossibleValue(pt)) |opv| {
29518 // The tag had redundant bits, but we've omitted the tag from the union's runtime layout, so the union is OPV and hence runtime-known.
29519 return .fromValue(opv);
29520 } else {
29521 // The union layout is just the tag, so we can bitcast the enum straight to the union.
29522 return block.addBitCast(union_ty, enum_tag);
29523 }
2956529524 }
2956629525
2956729526 const msg = msg: {
......@@ -29575,9 +29534,15 @@ fn coerceEnumToUnion(
2957529534 for (0..union_obj.field_types.len) |field_index| {
2957629535 const field_name = enum_obj.field_names.get(ip)[field_index];
2957729536 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
29578 if (try field_ty.onePossibleValue(pt) != null) continue;
29579 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{
29537 const ty_description: []const u8 = switch (field_ty.classify(zcu)) {
29538 .one_possible_value => continue,
29539 .no_possible_value => "uninstantiable type",
29540 else => "type",
29541 };
29542 if (field_ty.classify(zcu) == .one_possible_value) continue;
29543 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has {s} '{f}'", .{
2958029544 field_name.fmt(ip),
29545 ty_description,
2958129546 field_ty.fmt(pt),
2958229547 });
2958329548 }
......@@ -30345,7 +30310,7 @@ fn resolveIsNonErrFromType(
3034530310 assert(ot == .error_union);
3034630311
3034730312 const payload_ty = operand_ty.errorUnionPayload(zcu);
30348 if (payload_ty.zigTypeTag(zcu) == .noreturn) {
30313 if (payload_ty.classify(zcu) == .no_possible_value) {
3034930314 return .false;
3035030315 }
3035130316
......@@ -31348,24 +31313,28 @@ fn wrapErrorUnionSet(
3134831313 }
3134931314}
3135031315
31351fn unionToTag(
31352 sema: *Sema,
31353 block: *Block,
31354 enum_ty: Type,
31355 un: Air.Inst.Ref,
31356 un_src: LazySrcLoc,
31357) !Air.Inst.Ref {
31316/// Returns the enum tag value for the active tag of a tagged union value.
31317///
31318/// Asserts that the type of `un` is a tagged union type.
31319fn unionToTag(sema: *Sema, block: *Block, un: Air.Inst.Ref) !Air.Inst.Ref {
3135831320 const pt = sema.pt;
3135931321 const zcu = pt.zcu;
31360 if (try enum_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
31322 const ip = &zcu.intern_pool;
31323 const union_obj = ip.loadUnionType(sema.typeOf(un).toIntern());
31324 assert(union_obj.tag_usage == .tagged);
3136131325 if (sema.resolveValue(un)) |un_val| {
31362 const tag_val = un_val.unionTag(zcu).?;
31363 if (tag_val.isUndef(zcu))
31364 return try pt.undefRef(enum_ty);
31365 return Air.internedToRef(tag_val.toIntern());
31326 return .fromValue(un_val.unionTag(zcu).?);
31327 }
31328 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
31329 if (!union_obj.has_runtime_tag) {
31330 // This means that only one field is possible.
31331 const field_index = for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
31332 const field_ty: Type = .fromInterned(field_ty_ip);
31333 if (field_ty.classify(zcu) != .no_possible_value) break field_index;
31334 } else unreachable;
31335 return .fromValue(try pt.enumValueFieldIndex(enum_tag_ty, @intCast(field_index)));
3136631336 }
31367 try sema.requireRuntimeBlock(block, un_src, null);
31368 return block.addTyOp(.get_union_tag, enum_ty, un);
31337 return block.addTyOp(.get_union_tag, enum_tag_ty, un);
3136931338}
3137031339
3137131340const PeerResolveStrategy = enum {
......@@ -33491,15 +33460,6 @@ fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
3349133460 return sema.typeOf(ref).isNoReturn(sema.pt.zcu);
3349233461}
3349333462
33494/// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type.
33495fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool {
33496 if (ref.toIndex()) |inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(inst)]) {
33497 .inferred_alloc, .inferred_alloc_comptime => return false,
33498 else => {},
33499 };
33500 return sema.typeOf(ref).zigTypeTag(sema.pt.zcu) == tag;
33501}
33502
3350333463pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3350433464 const pt = sema.pt;
3350533465 if (!pt.zcu.comp.config.incremental) return;
......@@ -33744,7 +33704,6 @@ fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
3374433704 const zcu = pt.zcu;
3374533705 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
3374633706 .undef => true,
33747 .simple_value => |v| v == .undefined,
3374833707 .slice => {
3374933708 // If the slice contents are runtime-known, reification will fail later on with a
3375033709 // specific error message.
......@@ -33898,7 +33857,6 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
3389833857const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
3389933858const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
3390033859
33901// MLUGG TODO: decide how to do the namespacing here
3390233860pub const type_resolution = @import("Sema/type_resolution.zig");
3390333861pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
3390433862pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;
......@@ -34313,7 +34271,7 @@ fn zirUnionDecl(
3431334271 .fields_len = @intCast(union_decl.field_names.len),
3431434272 .layout = union_decl.kind.layout(),
3431534273 .any_field_aligns = union_decl.field_align_body_lens != null,
34316 .runtime_tag = switch (union_decl.kind) {
34274 .tag_usage = switch (union_decl.kind) {
3431734275 .auto => if (block.wantSafeTypes()) .safety else .none,
3431834276
3431934277 .tagged_explicit,
src/Sema/bitcast.zig-2
......@@ -267,7 +267,6 @@ const UnpackValueBits = struct {
267267 .int,
268268 .enum_tag,
269269 .simple_value,
270 .empty_enum_value,
271270 .float,
272271 .ptr,
273272 .opt,
......@@ -453,7 +452,6 @@ const UnpackValueBits = struct {
453452 // The only values here with runtime bits are `true` and `false.
454453 // These are both 1 bit, so will never need truncating.
455454 .simple_value => unreachable,
456 .empty_enum_value => unreachable, // zero-bit
457455 else => unreachable, // zero-bit or not primitives
458456 }
459457 }
src/Sema/type_resolution.zig+79-43
......@@ -72,7 +72,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo
7272 .error_union,
7373 .enum_literal,
7474 .enum_tag,
75 .empty_enum_value,
7675 .float,
7776 .ptr,
7877 .slice,
......@@ -249,10 +248,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
249248 // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).
250249
251250 var any_comptime_fields = false;
252 var comptime_only = false;
253 var one_possible_value = true;
254 var has_runtime_bits = false;
255251 var struct_align: Alignment = .@"1";
252 var has_no_possible_value = false;
253 var has_runtime_state = false;
254 var has_comptime_state = false;
256255 // Unlike `struct_obj.field_aligns`, these are not `.none`.
257256 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
258257 for (resolved_field_aligns, 0..) |*align_out, field_idx| {
......@@ -264,22 +263,37 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
264263 }
265264 break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
266265 };
267 if (!struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
268 // Non-`comptime` fields contribute to the struct's layout.
269 struct_align = struct_align.maxStrict(field_align);
270 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
271 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
272 if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false;
273 if (struct_obj.layout == .auto) {
274 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
275 }
276 } else {
266 align_out.* = field_align;
267 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
277268 assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs
278269 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
279270 any_comptime_fields = true;
271 continue; // `comptime` fields do not contribute to the struct layout
272 }
273 struct_align = struct_align.maxStrict(field_align);
274 if (struct_obj.layout == .auto) {
275 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
276 }
277 switch (field_ty.classify(zcu)) {
278 .one_possible_value => {},
279 .no_possible_value => has_no_possible_value = true,
280 .runtime => has_runtime_state = true,
281 .fully_comptime => has_comptime_state = true,
282 .partially_comptime => {
283 has_runtime_state = true;
284 has_comptime_state = true;
285 },
280286 }
281 align_out.* = field_align;
282287 }
288 const class: Type.Class = class: {
289 if (has_no_possible_value) break :class .no_possible_value;
290 if (has_comptime_state) {
291 break :class if (has_runtime_state) .partially_comptime else .fully_comptime;
292 } else {
293 break :class if (has_runtime_state) .runtime else .one_possible_value;
294 }
295 };
296
283297 if (struct_obj.layout == .auto) {
284298 const runtime_order = struct_obj.field_runtime_order.get(ip);
285299 // This logic does not reorder fields; it only moves the omitted ones to the end so that logic
......@@ -327,21 +341,21 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
327341 struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below
328342 cur_offset = offset + field_ty.abiSize(zcu);
329343 }
330 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
331 &block,
332 struct_ty.srcLoc(zcu),
333 "struct layout requires size {d}, this compiler implementation supports up to {d}",
334 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
335 );
344 const struct_size: u32 = switch (class) {
345 .no_possible_value => 0,
346 else => std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
347 &block,
348 struct_ty.srcLoc(zcu),
349 "struct layout requires size {d}, this compiler implementation supports up to {d}",
350 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
351 ),
352 };
336353 ip.resolveStructLayout(
337354 io,
338355 struct_ty.toIntern(),
339356 struct_size,
340357 struct_align,
341 false, // MLUGG TODO XXX NPV
342 one_possible_value,
343 comptime_only,
344 has_runtime_bits,
358 class,
345359 );
346360
347361 if (any_comptime_fields and !struct_obj.is_reified) {
......@@ -758,9 +772,8 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
758772 // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).
759773 var payload_align: Alignment = .@"1";
760774 var payload_size: u64 = 0;
761 var comptime_only = false;
762 var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu);
763 var possible_values: enum { none, one, many } = .none;
775 var possible_tags: u32 = 0;
776 var payload_has_comptime_state = false;
764777 for (0..union_obj.field_types.len) |field_idx| {
765778 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
766779 const field_align: Alignment = a: {
......@@ -772,21 +785,41 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
772785 };
773786 payload_align = payload_align.maxStrict(field_align);
774787 payload_size = @max(payload_size, field_ty.abiSize(zcu));
775 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
776 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
777 if (!field_ty.isNoReturn(zcu)) {
778 if (try field_ty.onePossibleValue(pt) != null) {
779 possible_values = .many; // this field alone has many possible values
780 } else switch (possible_values) {
781 .none => possible_values = .one, // there were none, now there is this field's OPV
782 .one => possible_values = .many, // there was one, now there are two
783 .many => {},
784 }
788
789 switch (field_ty.classify(zcu)) {
790 .no_possible_value => {}, // uninstantiable field has no effect
791 .one_possible_value, .runtime => {
792 possible_tags += 1;
793 },
794 .partially_comptime, .fully_comptime => {
795 possible_tags += 1;
796 payload_has_comptime_state = true;
797 },
785798 }
786799 }
787800
801 // We only need a runtime tag if there are multiple possible active fields *and* the union is
802 // not going to be comptime-only. Even if there are still runtime bits in the payload, the tag
803 // does not require runtime bits in a comptime-only union, because it is impossible to get a
804 // pointer to a union's tag.
805 const has_runtime_tag = switch (possible_tags) {
806 0, 1 => false,
807 else => union_obj.tag_usage != .none and !payload_has_comptime_state,
808 };
809
810 const class: Type.Class = class: {
811 if (possible_tags == 0) {
812 break :class .no_possible_value;
813 }
814 if (payload_has_comptime_state) {
815 break :class if (payload_size > 0) .partially_comptime else .fully_comptime;
816 }
817 const have_runtime_bits = has_runtime_tag or payload_size > 0;
818 break :class if (have_runtime_bits) .runtime else .one_possible_value;
819 };
820
788821 const size: u64, const padding: u64, const alignment: Alignment = layout: {
789 if (union_obj.runtime_tag == .none) {
822 if (!has_runtime_tag) {
790823 break :layout .{ payload_align.forward(payload_size), 0, payload_align };
791824 }
792825 const tag_align = enum_tag_ty.abiAlignment(zcu);
......@@ -800,6 +833,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
800833 break :layout .{ size, size - unpadded_size, alignment };
801834 };
802835
836 if (class == .no_possible_value or class == .one_possible_value) {
837 assert(size == 0);
838 assert(padding == 0);
839 }
840
803841 const casted_size = std.math.cast(u32, size) orelse return sema.fail(
804842 &block,
805843 union_ty.srcLoc(zcu),
......@@ -810,13 +848,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
810848 io,
811849 union_ty.toIntern(),
812850 enum_tag_ty.toIntern(),
851 class,
852 has_runtime_tag,
813853 casted_size,
814854 @intCast(padding), // okay because padding is no greater than size
815855 alignment,
816 possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`!
817 possible_values == .one,
818 comptime_only,
819 has_runtime_bits,
820856 );
821857}
822858fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError {
src/Type.zig+412-415
......@@ -23,6 +23,240 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId {
2323 return zcu.intern_pool.zigTypeTag(ty.toIntern());
2424}
2525
26/// Every type is a member of exactly one "class" which determines:
27/// * whether values of the type can exist at all
28/// * whether values of the type can be runtime-knwon
29/// * whether the type is considered comptime-only
30/// * whether the type has runtime bits (nonzero ABI size)
31pub const Class = enum(u3) {
32 /// Values of this type cannot exist because the type semantically has no values. Attempting to
33 /// create a value of this type (such as by coercing `undefined`) always emits a compile error.
34 ///
35 /// Not comptime-only. No runtime bits, i.e. ABI size is 0.
36 ///
37 /// Exhaustive list of no-possible-value ("NPV") types:
38 /// * `noreturn`
39 /// * `anyopaque`, and any `opaque` type
40 /// * `[n]T` where `n` is non-zero and `T` is NPV
41 /// * Any tuple where at least one non-`comptime` field has an NPV type
42 /// * Any enum whose backing type is `noreturn`
43 /// * Any struct where at least one non-`comptime` field has an NPV type
44 /// * Any union where every field has an NPV type (including unions with no fields)
45 /// * If the union would typically have a runtime tag, even if that tag would have runtime
46 /// bits, the union type is still NPV; the runtime tag is effectively omitted.
47 no_possible_value,
48
49 /// Values of this type are always comptime-known because there is only one value inhabiting the
50 /// type. This matches the colloquial understanding of a "zero-bit type".
51 ///
52 /// Not comptime-only (although always comptime-known). No runtime bits, i.e. ABI size is 0.
53 ///
54 /// Exhaustive list of one-possible-value ("OPV") types:
55 /// * `void`
56 /// * `u0`, `i0`
57 /// * `[0]T` for any `T`
58 /// * `[n]T` where `T` is OPV
59 /// * `[n:s]T` where `T` is OPV
60 /// * `@Vector(0, T)` for any `T`
61 /// * `@Vector(n, T)` where `T` is OPV
62 /// * Any tuple where every non-`comptime` field has an OPV type (including tuples with no fields)
63 /// * Any enum whose backing type is OPV
64 /// * Any struct where every non-`comptime` field has an OPV type (including structs with no fields)
65 /// * Any union with no runtime tag where all fields have OPV
66 /// * Any union where one field has an OPV type, and either:
67 /// * All other fields have NPV types (in this case, if there would be a runtime tag, it is omitted)
68 /// * All other fields have NPV or OPV types, and the union has no runtime tag
69 one_possible_value,
70
71 /// The type holds state (so it is neither NPV nor OPV), but contains no comptime-only state, so
72 /// values may be runtime-known.
73 ///
74 /// Not comptime-only. Has runtime bits, i.e. ABI size is non-zero.
75 ///
76 /// Most types which are typically used in Zig inhabit this class. For instance, all pointer
77 /// types, all integer types other than `u0` and `i0`, and most user-defined aggregates fall
78 /// into this category.
79 runtime,
80
81 /// The type holds state (so it is neither NPV nor OPV). Some, but not all, of the contained
82 /// state is comptime-only.
83 ///
84 /// Comptime-only. Has runtime bits, i.e. ABI size is non-zero.
85 ///
86 /// Partially-comptime types arise from aggregates (`struct`s, `union`s, or tuples) which have
87 /// some fields with fully-comptime types (such as `comptime_int`) and some fields with runtime
88 /// types (such as `u8`). Because the user may acquire pointers to these fields, pointers to the
89 /// embedded runtime state must be valid, so backends are required to lower the runtime state
90 /// within the type.
91 ///
92 /// Note that logically-runtime state which cannot be directly referenced by the user (such as
93 /// the enum tag of a tagged union type, or the "populated" bit of an optional type) does not
94 /// cause a type to be partially-comptime.
95 partially_comptime,
96
97 /// The type contains exclusively comptime-only state.
98 ///
99 /// Comptime-only. No runtime bits, i.e. ABI size is 0.
100 ///
101 /// Fully-comptime types arise from a handful of primitive fully-comptime types:
102 /// * `type`
103 /// * `comptime_int`
104 /// * `comptime_float`
105 /// * `@EnumLiteral()`
106 /// * `@TypeOf(null)`
107 /// * `@TypeOf(undefined)`
108 ///
109 /// Then, aggregates containing fully-comptime types may themselves be either fully-comptime or
110 /// partially-comptime; see the doc comment on `.partially_comptime` for details.
111 fully_comptime,
112};
113
114/// Returns the `Class` for the type `ty`. Asserts that the layout of `ty` is resolved.
115pub fn classify(ty: Type, zcu: *const Zcu) Class {
116 ty.assertHasLayout(zcu);
117 const ip = &zcu.intern_pool;
118 return switch (ip.indexToKey(ty.toIntern())) {
119 .simple_type => |t| switch (t) {
120 .f16,
121 .f32,
122 .f64,
123 .f80,
124 .f128,
125 .usize,
126 .isize,
127 .c_char,
128 .c_short,
129 .c_ushort,
130 .c_int,
131 .c_uint,
132 .c_long,
133 .c_ulong,
134 .c_longlong,
135 .c_ulonglong,
136 .c_longdouble,
137 .bool,
138 .anyerror,
139 .adhoc_inferred_error_set,
140 => .runtime,
141
142 .anyopaque => .no_possible_value,
143
144 .type,
145 .comptime_int,
146 .comptime_float,
147 .enum_literal,
148 .null,
149 .undefined,
150 => .fully_comptime,
151
152 .void => .one_possible_value,
153 .noreturn => .no_possible_value,
154
155 .generic_poison => unreachable,
156 },
157
158 .error_set_type,
159 .inferred_error_set_type,
160 .ptr_type,
161 .anyframe_type,
162 => .runtime,
163
164 .func_type => .fully_comptime,
165
166 .opaque_type => .no_possible_value,
167
168 .error_union_type => |eu| switch (Type.fromInterned(eu.payload_type).classify(zcu)) {
169 .no_possible_value,
170 .one_possible_value,
171 .runtime,
172 => .runtime,
173
174 .partially_comptime => .partially_comptime,
175 // It may seem that this should be `.partially_comptime` due to the error set, however
176 // there is no way to take a pointer to the error set of an error union, so it does not
177 // actually necessitate runtime bits.
178 .fully_comptime => .fully_comptime,
179 },
180
181 .int_type => |int| switch (int.bits) {
182 0 => .one_possible_value,
183 else => .runtime,
184 },
185 .array_type => |arr| {
186 if (arr.len == 0 and arr.sentinel == .none) return .one_possible_value;
187 return Type.fromInterned(arr.child).classify(zcu);
188 },
189 .vector_type => |vec| {
190 if (vec.len == 0) return .one_possible_value;
191 return Type.fromInterned(vec.child).classify(zcu);
192 },
193 .opt_type => |child| switch (Type.fromInterned(child).classify(zcu)) {
194 .no_possible_value => .one_possible_value,
195 .one_possible_value => .runtime,
196 else => |class| class,
197 },
198 .tuple_type => |tuple| {
199 var has_runtime_state = false;
200 var has_comptime_state = false;
201 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_comptime_val| {
202 if (field_comptime_val != .none) continue;
203 switch (Type.fromInterned(field_ty).classify(zcu)) {
204 .no_possible_value => return .no_possible_value,
205 .one_possible_value => {},
206 .runtime => has_runtime_state = true,
207 .fully_comptime => has_comptime_state = true,
208 .partially_comptime => {
209 has_runtime_state = true;
210 has_comptime_state = true;
211 },
212 }
213 }
214 if (has_comptime_state) {
215 return if (has_runtime_state) .partially_comptime else .fully_comptime;
216 } else {
217 return if (has_runtime_state) .runtime else .one_possible_value;
218 }
219 },
220 .struct_type => {
221 const struct_obj = ip.loadStructType(ty.toIntern());
222 return switch (struct_obj.layout) {
223 .auto, .@"extern" => struct_obj.class,
224 .@"packed" => Type.fromInterned(struct_obj.packed_backing_int_type).classify(zcu),
225 };
226 },
227 .union_type => {
228 const union_obj = ip.loadUnionType(ty.toIntern());
229 return switch (union_obj.layout) {
230 .auto, .@"extern" => union_obj.class,
231 .@"packed" => Type.fromInterned(union_obj.packed_backing_int_type).classify(zcu),
232 };
233 },
234 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).classify(zcu),
235
236 // values, not types
237 .undef,
238 .simple_value,
239 .variable,
240 .@"extern",
241 .func,
242 .int,
243 .err,
244 .error_union,
245 .enum_literal,
246 .enum_tag,
247 .float,
248 .ptr,
249 .slice,
250 .opt,
251 .aggregate,
252 .un,
253 .bitpack,
254 // memoization, not types
255 .memoized_call,
256 => unreachable,
257 };
258}
259
26260/// Asserts the type is resolved.
27261pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
28262 return switch (ty.zigTypeTag(zcu)) {
......@@ -400,7 +634,6 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
400634 .error_union,
401635 .enum_literal,
402636 .enum_tag,
403 .empty_enum_value,
404637 .float,
405638 .ptr,
406639 .slice,
......@@ -438,116 +671,9 @@ pub fn toValue(self: Type) Value {
438671/// - an enum with an explicit tag type has the ABI size of the integer tag type,
439672/// making it one-possible-value only if the integer tag type has 0 bits.
440673pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
441 ty.assertHasLayout(zcu);
442 const ip = &zcu.intern_pool;
443 return switch (ip.indexToKey(ty.toIntern())) {
444 .int_type => |int_type| int_type.bits != 0,
445 .ptr_type => true,
446 .anyframe_type => true,
447 .array_type => |array_type| array_type.lenIncludingSentinel() > 0 and
448 Type.fromInterned(array_type.child).hasRuntimeBits(zcu),
449 .vector_type => |vector_type| vector_type.len > 0 and
450 Type.fromInterned(vector_type.child).hasRuntimeBits(zcu),
451 .opt_type => |child| !Type.fromInterned(child).isNoReturn(zcu),
452
453 .error_union_type,
454 .error_set_type,
455 .inferred_error_set_type,
456 => true,
457
458 // These are function *bodies*, not pointers.
459 // They return false here because they are comptime-only types.
460 // Special exceptions have to be made when emitting functions due to
461 // this returning false.
462 .func_type => false,
463
464 .simple_type => |t| switch (t) {
465 .f16,
466 .f32,
467 .f64,
468 .f80,
469 .f128,
470 .usize,
471 .isize,
472 .c_char,
473 .c_short,
474 .c_ushort,
475 .c_int,
476 .c_uint,
477 .c_long,
478 .c_ulong,
479 .c_longlong,
480 .c_ulonglong,
481 .c_longdouble,
482 .bool,
483 .anyerror,
484 .adhoc_inferred_error_set,
485 .anyopaque,
486 => true,
487
488 .void,
489 .noreturn,
490 => false,
491
492 // primitive comptime-only types
493 .type,
494 .comptime_int,
495 .comptime_float,
496 .null,
497 .undefined,
498 .enum_literal,
499 => false,
500
501 .generic_poison => unreachable,
502 },
503 .struct_type => {
504 const struct_obj = ip.loadStructType(ty.toIntern());
505 switch (struct_obj.layout) {
506 .auto, .@"extern" => return struct_obj.has_runtime_bits,
507 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).hasRuntimeBits(zcu),
508 }
509 },
510 .union_type => {
511 const union_obj = ip.loadUnionType(ty.toIntern());
512 switch (union_obj.layout) {
513 .auto, .@"extern" => return union_obj.has_runtime_bits,
514 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).hasRuntimeBits(zcu),
515 }
516 },
517 .tuple_type => |tuple| {
518 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
519 if (val != .none) continue; // comptime field
520 if (Type.fromInterned(field_ty).hasRuntimeBits(zcu)) return true;
521 }
522 return false;
523 },
524
525 // MLUGG TODO: this answer was already here but... does it actually make sense?
526 .opaque_type => true,
527 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu),
528
529 // values, not types
530 .undef,
531 .simple_value,
532 .variable,
533 .@"extern",
534 .func,
535 .int,
536 .err,
537 .error_union,
538 .enum_literal,
539 .enum_tag,
540 .empty_enum_value,
541 .float,
542 .ptr,
543 .slice,
544 .opt,
545 .aggregate,
546 .un,
547 .bitpack,
548 // memoization, not types
549 .memoized_call,
550 => unreachable,
674 return switch (ty.classify(zcu)) {
675 .no_possible_value, .one_possible_value, .fully_comptime => false,
676 .runtime, .partially_comptime => true,
551677 };
552678}
553679
......@@ -634,7 +760,6 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
634760 .error_union,
635761 .enum_literal,
636762 .enum_tag,
637 .empty_enum_value,
638763 .float,
639764 .ptr,
640765 .slice,
......@@ -681,8 +806,12 @@ pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
681806 }
682807}
683808
809/// Returns whether `ty` is NPV, meaning it is "like `noreturn`" in a sense. See doc comments on
810/// `Class` for more details.
811///
812/// Exactly equivalent to `ty.classify(zcu) == .no_possible_value`.
684813pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
685 return zcu.intern_pool.isNoReturn(ty.toIntern());
814 return ty.classify(zcu) == .no_possible_value;
686815}
687816
688817/// Never returns `none`. Asserts that all necessary type resolution is already done.
......@@ -705,7 +834,10 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
705834 };
706835}
707836
708/// Never returns `none`. Asserts that all necessary type resolution is already done.
837/// Never returns `.none`. Asserts that the layout of `ty` is resolved.
838///
839/// Unlike ABI size, a type's ABI alignment is not affected by its `Class`. In other words, any
840/// alignment is possible regardless of the result of `ty.classify(zcu)`.
709841pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
710842 const ip = &zcu.intern_pool;
711843 const target = zcu.getTarget();
......@@ -842,7 +974,6 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
842974 .error_union,
843975 .enum_literal,
844976 .enum_tag,
845 .empty_enum_value,
846977 .float,
847978 .ptr,
848979 .slice,
......@@ -856,7 +987,11 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
856987 };
857988}
858989
859/// Asserts that `ty` is not an opaque type.
990/// Asserts that `ty` is not an opaque type, and that the layout of `ty` is resolved.
991///
992/// If the type is NPV, OPV, or fully-comptime (see `Class`), the return value of this function is
993/// guaranteed to be zero. Otherwise (if the type is runtime or partially-comptime) the return value
994/// is guaranteed to be non-zero.
860995pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
861996 const ip = &zcu.intern_pool;
862997 const target = zcu.getTarget();
......@@ -883,29 +1018,26 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
8831018 },
8841019 .opt_type => |child_ty_ip| {
8851020 const child_ty: Type = .fromInterned(child_ty_ip);
886 if (child_ty.isNoReturn(zcu)) return 0;
887 const child_size = child_ty.abiSize(zcu);
888 if (ty.optionalReprIsPayload(zcu)) return child_size;
1021 if (child_ty.classify(zcu) == .no_possible_value) return 0;
1022 if (ty.optionalReprIsPayload(zcu)) return child_ty.abiSize(zcu);
8891023 // Optional types are represented as a struct with the child type as the first
8901024 // field and a boolean as the second. Since the child type's abi alignment is
8911025 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
8921026 // to the child type's ABI alignment.
893 return child_size + child_ty.abiAlignment(zcu).toByteUnits().?;
1027 return child_ty.abiSize(zcu) + child_ty.abiAlignment(zcu).toByteUnits().?;
8941028 },
8951029 .error_set_type, .inferred_error_set_type => errorAbiSize(zcu),
8961030 .error_union_type => |error_union| {
8971031 const payload_ty: Type = .fromInterned(error_union.payload_type);
898 // This code needs to be kept in sync with the equivalent switch prong
899 // in abiAlignmentInner.
900 const code_size = errorAbiSize(zcu);
901 const code_align = errorAbiAlignment(zcu);
902 const payload_size = payload_ty.abiSize(zcu);
903 const payload_align = payload_ty.abiAlignment(zcu);
1032 switch (payload_ty.classify(zcu)) {
1033 .fully_comptime => return 0, // error set does not require runtime bits, see comment in `classify`
1034 else => {},
1035 }
9041036 // The layout will either be (code, payload, padding) or (payload, code, padding)
9051037 // depending on which has larger alignment. So the overall size is just the code
9061038 // and payload sizes added and padded to the larger alignment.
907 const big_align = code_align.maxStrict(payload_align);
908 return big_align.forward(payload_size + code_size);
1039 const big_align: Alignment = .maxStrict(errorAbiAlignment(zcu), payload_ty.abiAlignment(zcu));
1040 return big_align.forward(errorAbiSize(zcu) + payload_ty.abiSize(zcu));
9091041 },
9101042 .func_type => 0,
9111043 .simple_type => |t| switch (t) {
......@@ -946,7 +1078,12 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
9461078 .anyopaque => unreachable,
9471079 .generic_poison => unreachable,
9481080 },
949 .tuple_type => |tuple| ty.structFieldOffset(tuple.types.len, zcu),
1081 .tuple_type => |tuple| switch (ty.classify(zcu)) {
1082 // `structFieldOffset` is bogus on NPV tuples, because there may be some fields with
1083 // non-zero size.
1084 .no_possible_value => 0,
1085 else => ty.structFieldOffset(tuple.types.len, zcu),
1086 },
9501087 .struct_type => {
9511088 const struct_obj = ip.loadStructType(ty.toIntern());
9521089 switch (struct_obj.layout) {
......@@ -975,7 +1112,6 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
9751112 .error_union,
9761113 .enum_literal,
9771114 .enum_tag,
978 .empty_enum_value,
9791115 .float,
9801116 .ptr,
9811117 .slice,
......@@ -1100,7 +1236,6 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
11001236 .error_union,
11011237 .enum_literal,
11021238 .enum_tag,
1103 .empty_enum_value,
11041239 .float,
11051240 .ptr,
11061241 .slice,
......@@ -1327,8 +1462,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
13271462 }
13281463}
13291464
1330/// Returns the tag type of a union, if the type is a union and it has a tag type.
1331/// Otherwise, returns `null`.
1465/// If `ty` is a tagged union, returns its tag type. Otherwise, returns `null`.
13321466pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
13331467 assertHasLayout(ty, zcu);
13341468 const ip = &zcu.intern_pool;
......@@ -1337,33 +1471,28 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
13371471 else => return null,
13381472 }
13391473 const union_obj = ip.loadUnionType(ty.toIntern());
1340 return switch (union_obj.runtime_tag) {
1474 return switch (union_obj.tag_usage) {
13411475 .tagged => .fromInterned(union_obj.enum_tag_type),
13421476 .none, .safety => null,
13431477 };
13441478}
13451479
1346/// Same as `unionTagType` but includes safety tag.
1347/// Codegen should use this version.
1348pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
1480/// If the given union type contains a tag (including a safety tag) in its runtime layout, returns
1481/// its enum tag type. Otherwise, returns null. Asserts that `ty` is a union type.
1482///
1483/// In general, codegen logic should call this function instead of `unionTagType`.
1484pub fn unionTagTypeRuntime(ty: Type, zcu: *const Zcu) ?Type {
13491485 assertHasLayout(ty, zcu);
1350 const ip = &zcu.intern_pool;
1351 return switch (ip.indexToKey(ty.toIntern())) {
1352 .union_type => {
1353 const union_type = ip.loadUnionType(ty.toIntern());
1354 if (union_type.runtime_tag == .none) return null;
1355 return Type.fromInterned(union_type.enum_tag_type);
1356 },
1357 else => null,
1358 };
1486 const union_type = zcu.intern_pool.loadUnionType(ty.toIntern());
1487 if (!union_type.has_runtime_tag) return null;
1488 return .fromInterned(union_type.enum_tag_type);
13591489}
13601490
1361/// Asserts the type is a union; returns the tag type, even if the tag will
1362/// not be stored at runtime.
1491/// Asserts that `ty` is a union type, and returns its tag type, even if the tag will not be stored at runtime.
13631492pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
13641493 assertHasLayout(ty, zcu);
1365 const union_obj = zcu.typeToUnion(ty).?;
1366 return Type.fromInterned(union_obj.enum_tag_type);
1494 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
1495 return .fromInterned(union_obj.enum_tag_type);
13671496}
13681497
13691498pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
......@@ -1573,12 +1702,12 @@ pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {
15731702 };
15741703}
15751704
1576/// Returns true for integers, enums, error sets, and packed structs.
1705/// Returns true for integers, enums, error sets, and packed structs/unions.
15771706/// If this function returns true, then intInfo() can be called on the type.
15781707pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool {
15791708 return switch (ty.zigTypeTag(zcu)) {
15801709 .int, .@"enum", .error_set => true,
1581 .@"struct" => ty.containerLayout(zcu) == .@"packed",
1710 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
15821711 else => false,
15831712 };
15841713}
......@@ -1611,6 +1740,11 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
16111740 assert(struct_obj.layout == .@"packed");
16121741 ty = .fromInterned(struct_obj.packed_backing_int_type);
16131742 },
1743 .union_type => {
1744 const union_obj = ip.loadUnionType(ty.toIntern());
1745 assert(union_obj.layout == .@"packed");
1746 ty = .fromInterned(union_obj.packed_backing_int_type);
1747 },
16141748 .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type),
16151749 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
16161750
......@@ -1629,7 +1763,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
16291763 .func_type => unreachable,
16301764 .simple_type => unreachable, // handled via Index enum tag above
16311765
1632 .union_type => unreachable,
16331766 .opaque_type => unreachable,
16341767
16351768 // values, not types
......@@ -1643,7 +1776,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
16431776 .error_union,
16441777 .enum_literal,
16451778 .enum_tag,
1646 .empty_enum_value,
16471779 .float,
16481780 .ptr,
16491781 .slice,
......@@ -1772,240 +1904,23 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {
17721904 };
17731905}
17741906
1775/// MLUGG TODO: deal with our friends structs and unions
1776pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
1907/// If the type's classification is `Class.one_possible_value` (see `classify`), returns the only
1908/// possible value for the type. Otherwise, returns `null`.
1909pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
17771910 const zcu = pt.zcu;
17781911 const comp = zcu.comp;
17791912 const gpa = comp.gpa;
17801913 const ip = &zcu.intern_pool;
1781 assertHasLayout(starting_type, zcu);
1782 var ty = starting_type;
1783 while (true) switch (ty.toIntern()) {
1784 .empty_tuple_type => return .empty_tuple,
1785
1786 else => switch (ip.indexToKey(ty.toIntern())) {
1787 .int_type => |int_type| {
1788 if (int_type.bits == 0) {
1789 return try pt.intValue(ty, 0);
1790 } else {
1791 return null;
1792 }
1793 },
1794
1795 .ptr_type,
1796 .error_union_type,
1797 .func_type,
1798 .anyframe_type,
1799 .error_set_type,
1800 .inferred_error_set_type,
1801 => return null,
1802
1803 inline .array_type, .vector_type => |seq_type, seq_tag| {
1804 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
1805 if (seq_type.len + @intFromBool(has_sentinel) == 0) {
1806 return try pt.aggregateValue(ty, &.{});
1807 }
1808 if (try Type.fromInterned(seq_type.child).onePossibleValue(pt)) |opv| {
1809 return try pt.aggregateSplatValue(ty, opv);
1810 }
1811 return null;
1812 },
1813 .opt_type => |child| {
1814 if (child == .noreturn_type) {
1815 return try pt.nullValue(ty);
1816 } else {
1817 return null;
1818 }
1819 },
1820
1821 .simple_type => |t| switch (t) {
1822 .f16,
1823 .f32,
1824 .f64,
1825 .f80,
1826 .f128,
1827 .usize,
1828 .isize,
1829 .c_char,
1830 .c_short,
1831 .c_ushort,
1832 .c_int,
1833 .c_uint,
1834 .c_long,
1835 .c_ulong,
1836 .c_longlong,
1837 .c_ulonglong,
1838 .c_longdouble,
1839 .anyopaque,
1840 .bool,
1841 .type,
1842 .anyerror,
1843 .comptime_int,
1844 .comptime_float,
1845 .enum_literal,
1846 .adhoc_inferred_error_set,
1847 => return null,
1848
1849 .void => return .void,
1850 .noreturn => return .@"unreachable",
1851 .null => return .null,
1852 .undefined => return .undef,
1853
1854 .generic_poison => unreachable,
1855 },
1856 .struct_type => {
1857 const struct_obj = ip.loadStructType(ty.toIntern());
1858 if (struct_obj.layout == .@"packed") {
1859 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
1860 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
1861 return try pt.bitpackValue(ty, backing_val);
1862 } else {
1863 if (!struct_obj.has_one_possible_value) return null;
1864 }
1865 // There is an OPV.
1866 const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len);
1867 defer gpa.free(field_vals);
1868 for (field_vals, 0..) |*field_val, i_usize| {
1869 const i: u32 = @intCast(i_usize);
1870 if (struct_obj.field_is_comptime_bits.get(ip, i)) {
1871 field_val.* = struct_obj.field_defaults.get(ip)[i];
1872 assert(field_val.* != .none);
1873 continue;
1874 }
1875 const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]);
1876 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
1877 }
1878
1879 // In this case the struct has no runtime-known fields and
1880 // therefore has one possible value.
1881 return try pt.aggregateValue(ty, field_vals);
1882 },
1883
1884 .tuple_type => |tuple| {
1885 if (tuple.types.len == 0) {
1886 return try pt.aggregateValue(ty, &.{});
1887 }
1888
1889 const field_vals = try zcu.gpa.alloc(
1890 InternPool.Index,
1891 tuple.types.len,
1892 );
1893 defer zcu.gpa.free(field_vals);
1894 for (
1895 field_vals,
1896 tuple.types.get(ip),
1897 tuple.values.get(ip),
1898 ) |*field_val, field_ty, field_comptime_val| {
1899 if (field_comptime_val != .none) {
1900 field_val.* = field_comptime_val;
1901 continue;
1902 }
1903 if (try Type.fromInterned(field_ty).onePossibleValue(pt)) |opv| {
1904 field_val.* = opv.toIntern();
1905 } else return null;
1906 }
1907
1908 return try pt.aggregateValue(ty, field_vals);
1909 },
1910
1911 .union_type => {
1912 const union_obj = ip.loadUnionType(ty.toIntern());
1913 if (union_obj.layout == .@"packed") {
1914 const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
1915 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
1916 return try pt.bitpackValue(ty, backing_val);
1917 }
1918 // MLUGG TODO: is this nonsensical or what!!!!!!
1919 const tag_val = (try Type.fromInterned(union_obj.enum_tag_type).onePossibleValue(pt)) orelse
1920 return null;
1921 if (union_obj.field_types.len == 0) {
1922 const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
1923 return .fromInterned(only);
1924 }
1925 const only_field_ty = union_obj.field_types.get(ip)[0];
1926 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse
1927 return null;
1928 const only = try pt.internUnion(.{
1929 .ty = ty.toIntern(),
1930 .tag = tag_val.toIntern(),
1931 .val = val_val.toIntern(),
1932 });
1933 return .fromInterned(only);
1934 },
1935 .opaque_type => return null,
1936 .enum_type => {
1937 const enum_obj = ip.loadEnumType(ty.toIntern());
1938 if (enum_obj.nonexhaustive) {
1939 const int_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null;
1940 return .fromInterned(try pt.intern(.{ .enum_tag = .{
1941 .ty = ty.toIntern(),
1942 .int = int_opv.toIntern(),
1943 } }));
1944 }
1945 // MLUGG TODO: this is to preserve existing semantics, i REALLY don't fuck with it...
1946 if (enum_obj.int_tag_type == .comptime_int_type) {
1947 return switch (enum_obj.field_names.len) {
1948 0 => .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() })),
1949 1 => try pt.enumValueFieldIndex(ty, 0),
1950 else => null,
1951 };
1952 }
1953 const int_tag_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null;
1954 if (enum_obj.field_names.len == 0) {
1955 return .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() }));
1956 }
1957 return .fromInterned(try pt.intern(.{ .enum_tag = .{
1958 .ty = ty.toIntern(),
1959 .int = int_tag_opv.toIntern(),
1960 } }));
1961 },
1962
1963 // values, not types
1964 .undef,
1965 .simple_value,
1966 .variable,
1967 .@"extern",
1968 .func,
1969 .int,
1970 .err,
1971 .error_union,
1972 .enum_literal,
1973 .enum_tag,
1974 .empty_enum_value,
1975 .float,
1976 .ptr,
1977 .slice,
1978 .opt,
1979 .aggregate,
1980 .un,
1981 .bitpack,
1982 // memoization, not types
1983 .memoized_call,
1984 => unreachable,
1985 },
1986 };
1987}
1988
1989/// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`.
1990pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
1991 const ip = &zcu.intern_pool;
1914 assertHasLayout(ty, zcu);
19921915 return switch (ip.indexToKey(ty.toIntern())) {
1993 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnly(zcu),
1994 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnly(zcu),
1995 .opt_type => |child| return Type.fromInterned(child).comptimeOnly(zcu),
1996 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnly(zcu),
1997 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).comptimeOnly(zcu),
1998
1999 .int_type,
20001916 .ptr_type,
1917 .error_union_type,
1918 .func_type,
20011919 .anyframe_type,
20021920 .error_set_type,
20031921 .inferred_error_set_type,
20041922 .opaque_type,
2005 => false,
2006
2007 // These are function bodies, not function pointers.
2008 .func_type => true,
1923 => null,
20091924
20101925 .simple_type => |t| switch (t) {
20111926 .f16,
......@@ -2027,43 +1942,111 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
20271942 .c_longdouble,
20281943 .anyopaque,
20291944 .bool,
2030 .void,
2031 .anyerror,
2032 .adhoc_inferred_error_set,
2033 .noreturn,
2034 .generic_poison,
2035 => false,
2036
20371945 .type,
1946 .anyerror,
20381947 .comptime_int,
20391948 .comptime_float,
1949 .enum_literal,
1950 .adhoc_inferred_error_set,
20401951 .null,
20411952 .undefined,
2042 .enum_literal,
2043 => true,
1953 .noreturn,
1954 => null,
1955
1956 .void => .void,
1957
1958 .generic_poison => unreachable,
1959 },
1960
1961 .int_type => |int_type| switch (int_type.bits) {
1962 0 => try pt.intValue(ty, 0),
1963 else => null,
1964 },
1965
1966 inline .array_type, .vector_type => |seq_type, seq_tag| {
1967 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
1968 if (seq_type.len + @intFromBool(has_sentinel) == 0) {
1969 return try pt.aggregateValue(ty, &.{});
1970 }
1971 if (try Type.fromInterned(seq_type.child).onePossibleValue(pt)) |opv| {
1972 return try pt.aggregateSplatValue(ty, opv);
1973 }
1974 return null;
1975 },
1976 .opt_type => |child| switch (Type.fromInterned(child).classify(zcu)) {
1977 .no_possible_value => try pt.nullValue(ty),
1978 else => null,
1979 },
1980 .tuple_type => |tuple| {
1981 // Check *whether* the OPV exists first, because constructing it is a little more expensive.
1982 if (ty.classify(zcu) != .one_possible_value) return null;
1983 const field_vals = try zcu.gpa.dupe(InternPool.Index, tuple.values.get(ip));
1984 defer zcu.gpa.free(field_vals);
1985 for (field_vals, tuple.types.get(ip)) |*field_val, field_ty_ip| {
1986 if (field_val.* != .none) continue; // comptime field value
1987 const field_ty: Type = .fromInterned(field_ty_ip);
1988 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
1989 }
1990 return try pt.aggregateValue(ty, field_vals);
20441991 },
20451992 .struct_type => {
20461993 const struct_obj = ip.loadStructType(ty.toIntern());
2047 return switch (struct_obj.layout) {
2048 .@"packed" => false,
2049 .auto, .@"extern" => struct_obj.comptime_only,
2050 };
1994 switch (struct_obj.layout) {
1995 .auto, .@"extern" => {},
1996 .@"packed" => {
1997 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
1998 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
1999 return try pt.bitpackValue(ty, backing_val);
2000 },
2001 }
2002 // Type resolution already figured out whether there is an OPV, but if there is, it's
2003 // our job to compute it.
2004 if (struct_obj.class != .one_possible_value) return null;
2005 const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len);
2006 defer gpa.free(field_vals);
2007 for (field_vals, 0..) |*field_val, i_usize| {
2008 const i: u32 = @intCast(i_usize);
2009 if (struct_obj.field_is_comptime_bits.get(ip, i)) {
2010 field_val.* = struct_obj.field_defaults.get(ip)[i];
2011 assert(field_val.* != .none);
2012 continue;
2013 }
2014 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[i]);
2015 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
2016 }
2017 return try pt.aggregateValue(ty, field_vals);
20512018 },
20522019 .union_type => {
20532020 const union_obj = ip.loadUnionType(ty.toIntern());
2054 return switch (union_obj.layout) {
2055 .@"packed" => false,
2056 .auto, .@"extern" => union_obj.comptime_only,
2057 };
2058 },
2059 .tuple_type => |tuple| {
2060 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2061 if (val != .none) continue;
2062 if (!Type.fromInterned(field_ty).comptimeOnly(zcu)) continue;
2063 return true;
2021 if (union_obj.layout == .@"packed") {
2022 const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
2023 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
2024 return try pt.bitpackValue(ty, backing_val);
20642025 }
2065 return false;
2066 },
2026 // Type resolution already figured out whether there is an OPV, but if there is, it's
2027 // our job to compute it.
2028 if (union_obj.class != .one_possible_value) return null;
2029 // The OPV comes from exactly one field whose type is OPV, while all others are NPV.
2030 for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
2031 const field_ty: Type = .fromInterned(field_ty_ip);
2032 switch (field_ty.classify(zcu)) {
2033 .no_possible_value => continue,
2034 .one_possible_value => {},
2035 else => unreachable,
2036 }
2037 // This field is the one!
2038 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
2039 const tag_val = try pt.enumValueFieldIndex(enum_tag_ty, @intCast(field_index));
2040 const payload_val = (try field_ty.onePossibleValue(pt)).?;
2041 return try pt.unionValue(ty, tag_val, payload_val);
2042 } else unreachable;
2043 },
2044 .enum_type => if (try ty.intTagType(zcu).onePossibleValue(pt)) |int_tag_opv| {
2045 return .fromInterned(try pt.intern(.{ .enum_tag = .{
2046 .ty = ty.toIntern(),
2047 .int = int_tag_opv.toIntern(),
2048 } }));
2049 } else null,
20672050
20682051 // values, not types
20692052 .undef,
......@@ -2076,7 +2059,6 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
20762059 .error_union,
20772060 .enum_literal,
20782061 .enum_tag,
2079 .empty_enum_value,
20802062 .float,
20812063 .ptr,
20822064 .slice,
......@@ -2090,6 +2072,16 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
20902072 };
20912073}
20922074
2075/// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`.
2076pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2077 if (ty.toIntern() == .generic_poison_type) return false;
2078 if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false;
2079 return switch (ty.classify(zcu)) {
2080 .no_possible_value, .one_possible_value, .runtime => false,
2081 .partially_comptime, .fully_comptime => true,
2082 };
2083}
2084
20932085pub fn isVector(ty: Type, zcu: *const Zcu) bool {
20942086 return ty.zigTypeTag(zcu) == .vector;
20952087}
......@@ -2286,8 +2278,8 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu
22862278 return enum_type.nameIndex(ip, field_name);
22872279}
22882280
2289/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
2290/// an integer which represents the enum value. Returns the field index in
2281/// Asserts `ty` is an enum. `enum_tag` can either be the actual enum tag value
2282/// or an integer which represents the enum value. Returns the field index in
22912283/// declaration order, or `null` if `enum_tag` does not match any field.
22922284pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
22932285 assertHasLayout(ty, zcu);
......@@ -2327,7 +2319,7 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
23272319 }
23282320}
23292321
2330/// Returns the field type. Supports structs and unions.
2322/// Returns the field type. Supports tuples, structs, and unions.
23312323pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
23322324 const ip = &zcu.intern_pool;
23332325 const types = switch (ip.indexToKey(ty.toIntern())) {
......@@ -2493,7 +2485,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
24932485 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
24942486 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {
24952487 // comptime field
2496 if (i == index) return offset;
2488 if (i == index) return 0;
24972489 continue;
24982490 }
24992491
......@@ -2509,8 +2501,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
25092501
25102502 .union_type => {
25112503 const union_type = ip.loadUnionType(ty.toIntern());
2512 if (union_type.runtime_tag == .none)
2513 return 0;
2504 if (!union_type.has_runtime_tag) return 0;
25142505 const layout = Type.getUnionLayout(union_type, zcu);
25152506 if (layout.tag_align.compare(.gte, layout.payload_align)) {
25162507 // {Tag, Payload}
......@@ -2746,7 +2737,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
27462737 }
27472738 payload_align = payload_align.max(field_align);
27482739 }
2749 if (loaded_union.runtime_tag == .none or
2740 if (!loaded_union.has_runtime_tag or
27502741 !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu))
27512742 {
27522743 return .{
......@@ -2872,11 +2863,19 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina
28722863}
28732864
28742865/// Returns `true` if a value of this type is always `null`.
2875/// Returns `false` if a value of this type is neve `null`.
2866/// Returns `false` if a value of this type is never `null`.
28762867/// Returns `null` otherwise.
28772868pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
28782869 if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;
2879 if (ty.optionalChild(zcu).isNoReturn(zcu)) return true; // `?noreturn` is always null
2870 const payload_ty = ty.optionalChild(zcu);
2871 if (payload_ty.classify(zcu) == .no_possible_value) return true; // `?noreturn` etc
2872
2873 // Although it has runtime bits, `?error{}` is always null. MLUGG TODO: think for a bit...
2874 switch (zcu.intern_pool.indexToKey(payload_ty.toIntern())) {
2875 .error_set_type => |error_set| if (error_set.names.len == 0) return true,
2876 else => {},
2877 }
2878
28802879 return null;
28812880}
28822881
......@@ -3096,7 +3095,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
30963095 .error_union,
30973096 .enum_literal,
30983097 .enum_tag,
3099 .empty_enum_value,
31003098 .float,
31013099 .ptr,
31023100 .slice,
......@@ -3175,7 +3173,6 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
31753173 .error_union,
31763174 .enum_literal,
31773175 .enum_tag,
3178 .empty_enum_value,
31793176 .float,
31803177 .ptr,
31813178 .slice,
src/Value.zig+3-4
......@@ -348,7 +348,7 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
348348 } else {
349349 const backing_ty = try ty.externUnionBackingType(pt);
350350 const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
351 return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
351 return writeToMemory(val.unionPayload(zcu), pt, buffer[0..byte_count]);
352352 }
353353 },
354354 .@"packed" => {
......@@ -746,7 +746,6 @@ pub fn compareScalar(
746746/// Returns `false` if the value or any vector element is undefined.
747747///
748748/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
749/// TODO MLUGG: lowkey wanna delete this
750749pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {
751750 return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
752751 .float => |float| switch (float.storage) {
......@@ -919,7 +918,7 @@ pub fn unionTag(val: Value, zcu: *Zcu) ?Value {
919918 };
920919}
921920
922pub fn unionValue(val: Value, zcu: *Zcu) Value {
921pub fn unionPayload(val: Value, zcu: *Zcu) Value {
923922 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
924923 .un => |un| Value.fromInterned(un.val),
925924 else => unreachable,
......@@ -2442,7 +2441,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
24422441 inline else => |tag_comptime| @unionInit(
24432442 T,
24442443 @tagName(tag_comptime),
2445 try val.unionValue(zcu).interpret(@FieldType(T, @tagName(tag_comptime)), pt),
2444 try val.unionPayload(zcu).interpret(@FieldType(T, @tagName(tag_comptime)), pt),
24462445 ),
24472446 };
24482447 },
src/Zcu/PerThread.zig+2-7
......@@ -3825,9 +3825,7 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca
38253825
38263826pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
38273827 if (std.debug.runtime_safety) {
3828 if (try ty.onePossibleValue(pt)) |opv| {
3829 assert(opv.isUndef(pt.zcu));
3830 }
3828 assert(ty.classify(pt.zcu) != .one_possible_value);
38313829 }
38323830 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
38333831}
......@@ -3909,10 +3907,7 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind
39093907 for (elems) |elem| {
39103908 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;
39113909 } else if (elems.len > 0) {
3912 // All undef, so return an undef struct. However, don't use `undefValue`, because its
3913 // non-OPV assertion can loop on `[1]@TypeOf(undefined)`: that type has an OPV of
3914 // `.{undefined}`, which here we normalize to `undefined`.
3915 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
3910 return pt.undefValue(ty);
39163911 }
39173912 return .fromInterned(try pt.intern(.{ .aggregate = .{
39183913 .ty = ty.toIntern(),
src/codegen.zig-2
......@@ -343,7 +343,6 @@ pub fn generateSymbol(
343343
344344 .undef => unreachable, // handled above
345345 .simple_value => |simple_value| switch (simple_value) {
346 .undefined => unreachable, // non-runtime value
347346 .void => unreachable, // non-runtime value
348347 .null => unreachable, // non-runtime value
349348 .@"unreachable" => unreachable, // non-runtime value
......@@ -357,7 +356,6 @@ pub fn generateSymbol(
357356 .@"extern",
358357 .func,
359358 .enum_literal,
360 .empty_enum_value,
361359 => unreachable, // non-runtime values
362360 .int => {
363361 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
src/codegen/aarch64/Select.zig+2-6
......@@ -10588,7 +10588,6 @@ pub const Value = struct {
1058810588 .error_union,
1058910589 .enum_literal,
1059010590 .enum_tag,
10591 .empty_enum_value,
1059210591 .float,
1059310592 .ptr,
1059410593 .slice,
......@@ -10711,7 +10710,6 @@ pub const Value = struct {
1071110710 .inferred_error_set_type,
1071210711
1071310712 .enum_literal,
10714 .empty_enum_value,
1071510713 .memoized_call,
1071610714 => unreachable, // not a runtime value
1071710715 .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {
......@@ -10732,7 +10730,7 @@ pub const Value = struct {
1073210730 } }),
1073310731 }),
1073410732 .simple_value => |simple_value| switch (simple_value) {
10735 .undefined, .void, .null, .@"unreachable" => unreachable,
10733 .void, .null, .@"unreachable" => unreachable,
1073610734 .true => continue :constant_key .{ .int = .{
1073710735 .ty = .bool_type,
1073810736 .storage = .{ .u64 = 1 },
......@@ -11408,7 +11406,6 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e
1140811406 .inferred_error_set_type,
1140911407
1141011408 .enum_literal,
11411 .empty_enum_value,
1141211409 .memoized_call,
1141311410 => unreachable, // not a runtime value
1141411411 .err => |err| {
......@@ -12085,7 +12082,7 @@ pub const CallAbiIterator = struct {
1208512082 const zcu = isel.pt.zcu;
1208612083 const ip = &zcu.intern_pool;
1208712084
12088 if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
12085 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
1208912086 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
1209012087 const wip_vi = isel.initValue(ty);
1209112088 type_key: switch (ip.indexToKey(ty.toIntern())) {
......@@ -12326,7 +12323,6 @@ pub const CallAbiIterator = struct {
1232612323 .error_union,
1232712324 .enum_literal,
1232812325 .enum_tag,
12329 .empty_enum_value,
1233012326 .float,
1233112327 .ptr,
1233212328 .slice,
src/codegen/c.zig+11-17
......@@ -1040,7 +1040,6 @@ pub const DeclGen = struct {
10401040 .undef => unreachable, // handled above
10411041 .simple_value => |simple_value| switch (simple_value) {
10421042 // non-runtime values
1043 .undefined => unreachable,
10441043 .void => unreachable,
10451044 .null => unreachable,
10461045 .@"unreachable" => unreachable,
......@@ -1052,7 +1051,6 @@ pub const DeclGen = struct {
10521051 .@"extern",
10531052 .func,
10541053 .enum_literal,
1055 .empty_enum_value,
10561054 => unreachable, // non-runtime values
10571055 .int => |int| switch (int.storage) {
10581056 .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),
......@@ -1756,7 +1754,6 @@ pub const DeclGen = struct {
17561754 .error_union,
17571755 .enum_literal,
17581756 .enum_tag,
1759 .empty_enum_value,
17601757 .float,
17611758 .ptr,
17621759 .slice,
......@@ -5848,7 +5845,7 @@ fn fieldLocation(
58485845 .auto, .@"extern" => {
58495846 const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
58505847 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))
5851 return if (loaded_union.hasTag(ip) and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
5848 return if (loaded_union.has_runtime_tag and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
58525849 .{ .field = .{ .identifier = "payload" } }
58535850 else
58545851 .begin;
......@@ -7022,7 +7019,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
70227019 const union_ty = f.typeOf(bin_op.lhs).childType(zcu);
70237020 const layout = union_ty.unionGetLayout(zcu);
70247021 if (layout.tag_size == 0) return .none;
7025 const tag_ty = union_ty.unionTagTypeSafety(zcu).?;
7022 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
70267023
70277024 const w = &f.object.code.writer;
70287025 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
......@@ -7462,18 +7459,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
74627459
74637460 const local = try f.allocLocal(inst, union_ty);
74647461
7465 const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {
7466 const layout = union_ty.unionGetLayout(zcu);
7467 if (layout.tag_size != 0) {
7468 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7469 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
7470
7471 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
7472 try f.writeCValueMember(w, local, .{ .identifier = "tag" });
7473 try a.assign(f, w);
7474 try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
7475 try a.end(f, w);
7476 }
7462 const field: CValue = if (union_ty.unionTagTypeRuntime(zcu)) |tag_ty| field: {
7463 assert(union_ty.unionGetLayout(zcu).tag_size != 0);
7464 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7465 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
7466 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
7467 try f.writeCValueMember(w, local, .{ .identifier = "tag" });
7468 try a.assign(f, w);
7469 try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
7470 try a.end(f, w);
74777471 break :field .{ .payload_identifier = field_name.toSlice(ip) };
74787472 } else .{ .identifier = field_name.toSlice(ip) };
74797473
src/codegen/c/Type.zig+6-8
......@@ -2479,7 +2479,7 @@ pub const Pool = struct {
24792479 return pool.fromFields(allocator, .@"struct", &fields, kind);
24802480 },
24812481 .opt_type => |payload_type| {
2482 if (ip.isNoReturn(payload_type)) return .void;
2482 if (Type.fromInterned(payload_type).isNoReturn(zcu)) return .void;
24832483 const payload_ctype = try pool.fromType(
24842484 allocator,
24852485 scratch,
......@@ -2521,7 +2521,7 @@ pub const Pool = struct {
25212521 .signedness = .unsigned,
25222522 .bits = error_set_bits,
25232523 }, mod, kind);
2524 if (ip.isNoReturn(error_union_info.payload_type)) return error_set_ctype;
2524 if (Type.fromInterned(error_union_info.payload_type).isNoReturn(zcu)) return error_set_ctype;
25252525 const payload_type = Type.fromInterned(error_union_info.payload_type);
25262526 const payload_ctype = try pool.fromType(
25272527 allocator,
......@@ -2684,9 +2684,8 @@ pub const Pool = struct {
26842684 const loaded_union = ip.loadUnionType(ip_index);
26852685 switch (loaded_union.flagsUnordered(ip).layout) {
26862686 .auto, .@"extern" => {
2687 const has_tag = loaded_union.hasTag(ip);
26882687 const fwd_decl = try pool.getFwdDecl(allocator, .{
2689 .tag = if (has_tag) .@"struct" else .@"union",
2688 .tag = if (loaded_union.has_runtime_tag) .@"struct" else .@"union",
26902689 .name = .{ .index = ip_index },
26912690 });
26922691 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
......@@ -2707,7 +2706,7 @@ pub const Pool = struct {
27072706 const field_type = Type.fromInterned(
27082707 loaded_union.field_types.get(ip)[field_index],
27092708 );
2710 if (ip.isNoReturn(field_type.toIntern())) continue;
2709 if (field_type.isNoReturn(zcu)) continue;
27112710 const field_ctype = try pool.fromType(
27122711 allocator,
27132712 scratch,
......@@ -2738,7 +2737,7 @@ pub const Pool = struct {
27382737 scratch.items.len - scratch_top,
27392738 @typeInfo(Field).@"struct".fields.len,
27402739 ));
2741 if (!has_tag) {
2740 if (!loaded_union.has_runtime_tag) {
27422741 if (fields_len == 0) return .void;
27432742 try pool.ensureUnusedCapacity(allocator, 1);
27442743 const extra_index = try pool.addHashedExtra(
......@@ -2836,7 +2835,7 @@ pub const Pool = struct {
28362835 var hasher = Hasher.init;
28372836 const return_type = Type.fromInterned(func_info.return_type);
28382837 const return_ctype: CType =
2839 if (!ip.isNoReturn(func_info.return_type)) try pool.fromType(
2838 if (!Type.fromInterned(func_info.return_type).isNoReturn(zcu)) try pool.fromType(
28402839 allocator,
28412840 scratch,
28422841 return_type,
......@@ -2889,7 +2888,6 @@ pub const Pool = struct {
28892888 .error_union,
28902889 .enum_literal,
28912890 .enum_tag,
2892 .empty_enum_value,
28932891 .float,
28942892 .ptr,
28952893 .slice,
src/codegen/llvm.zig-3
......@@ -3516,7 +3516,6 @@ pub const Object = struct {
35163516 .error_union,
35173517 .enum_literal,
35183518 .enum_tag,
3519 .empty_enum_value,
35203519 .float,
35213520 .ptr,
35223521 .slice,
......@@ -3722,7 +3721,6 @@ pub const Object = struct {
37223721
37233722 .undef => unreachable, // handled above
37243723 .simple_value => |simple_value| switch (simple_value) {
3725 .undefined => unreachable, // non-runtime value
37263724 .void => unreachable, // non-runtime value
37273725 .null => unreachable, // non-runtime value
37283726 .@"unreachable" => unreachable, // non-runtime value
......@@ -3732,7 +3730,6 @@ pub const Object = struct {
37323730 },
37333731 .variable,
37343732 .enum_literal,
3735 .empty_enum_value,
37363733 => unreachable, // non-runtime values
37373734 .@"extern" => |@"extern"| {
37383735 const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav);
src/codegen/spirv/CodeGen.zig+2-4
......@@ -814,11 +814,9 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
814814 .@"extern",
815815 .func,
816816 .enum_literal,
817 .empty_enum_value,
818817 => unreachable, // non-runtime values
819818
820819 .simple_value => |simple_value| switch (simple_value) {
821 .undefined,
822820 .void,
823821 .null,
824822 .@"unreachable",
......@@ -4482,7 +4480,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
44824480
44834481 if (layout.tag_size == 0) return;
44844482
4485 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
4483 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
44864484 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
44874485 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
44884486
......@@ -4508,7 +4506,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45084506 const union_handle = try cg.resolve(ty_op.operand);
45094507 if (!layout.has_payload) return union_handle;
45104508
4511 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
4509 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
45124510 return try cg.extractField(tag_ty, union_handle, layout.tag_index);
45134511}
45144512
src/codegen/wasm/CodeGen.zig+2-10
......@@ -1244,7 +1244,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {
12441244 if (any_returns and cg.air.instructions.len > 0) {
12451245 const inst: Air.Inst.Index = @enumFromInt(cg.air.instructions.len - 1);
12461246 const last_inst_ty = cg.typeOfIndex(inst);
1247 if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(zcu) or last_inst_ty.isNoReturn(zcu)) {
1247 if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
12481248 try cg.addTag(.@"unreachable");
12491249 }
12501250 }
......@@ -2201,9 +2201,6 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
22012201 const result_value = result_value: {
22022202 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
22032203 break :result_value .none;
2204 } else if (ret_ty.isNoReturn(zcu)) {
2205 try cg.addTag(.@"unreachable");
2206 break :result_value .none;
22072204 } else if (first_param_sret) {
22082205 break :result_value sret;
22092206 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_mvp) {
......@@ -3158,7 +3155,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
31583155
31593156 .undef => unreachable, // handled above
31603157 .simple_value => |simple_value| switch (simple_value) {
3161 .undefined,
31623158 .void,
31633159 .null,
31643160 .@"unreachable",
......@@ -3173,7 +3169,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
31733169 .@"extern",
31743170 .func,
31753171 .enum_literal,
3176 .empty_enum_value,
31773172 => unreachable, // non-runtime values
31783173 .int => {
31793174 const int_info = ty.intInfo(zcu);
......@@ -5340,7 +5335,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
53405335 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
53415336
53425337 const tag_int = blk: {
5343 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
5338 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
53445339 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
53455340 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
53465341 break :blk try cg.lowerConstant(tag_val, tag_ty);
......@@ -7109,9 +7104,6 @@ fn callIntrinsic(
71097104
71107105 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
71117106 return .none;
7112 } else if (return_type.isNoReturn(zcu)) {
7113 try cg.addTag(.@"unreachable");
7114 return .none;
71157107 } else if (want_sret_param) {
71167108 return sret;
71177109 } else {
src/codegen/x86_64/CodeGen.zig+1-1
......@@ -171467,7 +171467,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
171467171467 const union_layout = union_ty.unionGetLayout(zcu);
171468171468 if (union_layout.tag_size > 0) {
171469171469 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
171470 union_ty.unionTagTypeSafety(zcu).?,
171470 union_ty.unionTagTypeRuntime(zcu).?,
171471171471 union_init.field_index,
171472171472 ));
171473171473 try res.write(&tag_temp, .{
src/link/Dwarf.zig+19-22
......@@ -1603,7 +1603,7 @@ pub const WipNav = struct {
16031603 const zcu = pt.zcu;
16041604 const ty = val.typeOf(zcu);
16051605 const has_runtime_bits = ty.hasRuntimeBits(zcu);
1606 const has_comptime_state = ty.comptimeOnly(zcu) and try ty.onePossibleValue(pt) == null;
1606 const has_comptime_state = ty.comptimeOnly(zcu);
16071607 try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
16081608 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
16091609 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
......@@ -2108,7 +2108,7 @@ pub const WipNav = struct {
21082108 const zcu = wip_nav.pt.zcu;
21092109 const ip = &zcu.intern_pool;
21102110 const ty = value.typeOf(zcu);
2111 if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);
2111 if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu));
21122112 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
21132113 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
21142114 else => unreachable,
......@@ -2705,7 +2705,7 @@ fn initWipNavInner(
27052705 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
27062706 if (maybe_func_type) |func_type| {
27072707 try wip_nav.infoAddrSym(sym_index, 0);
2708 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2708 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
27092709 if (func_type.param_types.len > 0 or func_type.is_var_args) {
27102710 for (func_type.param_types.get(ip)) |param_type| {
27112711 try wip_nav.abbrevCode(.extern_param);
......@@ -2733,7 +2733,7 @@ fn initWipNavInner(
27332733 try wip_nav.strp(@"extern".name.toSlice(ip));
27342734 try wip_nav.refType(.fromInterned(func_type.return_type));
27352735 try wip_nav.infoAddrSym(sym_index, 0);
2736 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2736 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
27372737 if (func_type.param_types.len > 0 or func_type.is_var_args) {
27382738 for (func_type.param_types.get(ip)) |param_type| {
27392739 try wip_nav.abbrevCode(.extern_param);
......@@ -2818,7 +2818,7 @@ fn initWipNavInner(
28182818 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
28192819 }.toByteUnits().?);
28202820 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2821 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2821 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
28222822
28232823 const dlw = &wip_nav.debug_line.writer;
28242824 try dlw.writeByte(DW.LNS.extended_op);
......@@ -3172,7 +3172,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
31723172 .none => .{ false, false },
31733173 else => .{
31743174 field_type.hasRuntimeBits(zcu),
3175 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
3175 field_type.comptimeOnly(zcu),
31763176 },
31773177 };
31783178 try wip_nav.abbrevCode(if (is_comptime)
......@@ -3294,7 +3294,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
32943294 try diw.writeUleb128(union_layout.abi_size);
32953295 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
32963296 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
3297 if (loaded_union.runtime_tag != .none) {
3297 if (loaded_union.has_runtime_tag) {
32983298 try wip_nav.abbrevCode(.tagged_union);
32993299 try wip_nav.infoSectionOffset(
33003300 .debug_info,
......@@ -3371,7 +3371,6 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
33713371 .error_union,
33723372 .enum_literal,
33733373 .enum_tag,
3374 .empty_enum_value,
33753374 .float,
33763375 .ptr,
33773376 .slice,
......@@ -3465,7 +3464,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
34653464 const diw = &wip_nav.debug_info.writer;
34663465 const nav_ty = nav_val.typeOf(zcu);
34673466 const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
3468 const has_comptime_state = nav_ty.comptimeOnly(zcu) and try nav_ty.onePossibleValue(pt) == null;
3467 const has_comptime_state = nav_ty.comptimeOnly(zcu);
34693468 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
34703469 .decl = .decl_const_runtime_bits_comptime_state,
34713470 .generic_decl = .generic_decl_const,
......@@ -3845,7 +3844,7 @@ fn updateLazyType(
38453844 .none => .{ false, false },
38463845 else => .{
38473846 field_type.hasRuntimeBits(zcu),
3848 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
3847 field_type.comptimeOnly(zcu),
38493848 },
38503849 };
38513850 try wip_nav.abbrevCode(if (has_comptime_state)
......@@ -4008,7 +4007,6 @@ fn updateLazyType(
40084007 .error_union,
40094008 .enum_literal,
40104009 .enum_tag,
4011 .empty_enum_value,
40124010 .float,
40134011 .ptr,
40144012 .slice,
......@@ -4128,7 +4126,7 @@ fn updateLazyValue(
41284126 .payload => |payload_val| {
41294127 const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
41304128 const has_runtime_bits = payload_type.hasRuntimeBits(zcu);
4131 const has_comptime_state = payload_type.comptimeOnly(zcu) and try payload_type.onePossibleValue(pt) == null;
4129 const has_comptime_state = payload_type.comptimeOnly(zcu);
41324130 try wip_nav.abbrevCode(if (has_comptime_state)
41334131 .comptime_value_field_comptime_state
41344132 else if (has_runtime_bits)
......@@ -4164,7 +4162,6 @@ fn updateLazyValue(
41644162 }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
41654163 try wip_nav.refType(.fromInterned(enum_tag.ty));
41664164 },
4167 .empty_enum_value => unreachable,
41684165 .float => |float| {
41694166 switch (float.storage) {
41704167 .f16 => |f16_val| {
......@@ -4209,7 +4206,7 @@ fn updateLazyValue(
42094206 .comptime_alloc, .comptime_field => unreachable,
42104207 .uav => |uav| {
42114208 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
4212 if (try uav_ty.onePossibleValue(pt)) |_| {
4209 if (uav_ty.classify(zcu) == .one_possible_value) {
42134210 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
42144211 .aggregate_udata_comptime_value
42154212 else
......@@ -4337,7 +4334,7 @@ fn updateLazyValue(
43374334 }
43384335 if (opt.val != .none) child_field: {
43394336 const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
4340 const has_comptime_state = opt_child_type.comptimeOnly(zcu) and try opt_child_type.onePossibleValue(pt) == null;
4337 const has_comptime_state = opt_child_type.comptimeOnly(zcu);
43414338 try wip_nav.abbrevCode(if (has_comptime_state)
43424339 .comptime_value_field_comptime_state
43434340 else if (has_runtime_bits)
......@@ -4363,7 +4360,7 @@ fn updateLazyValue(
43634360 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;
43644361 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
43654362 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4366 const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
4363 const has_comptime_state = field_type.comptimeOnly(zcu);
43674364 try wip_nav.abbrevCode(if (has_comptime_state)
43684365 .comptime_value_field_comptime_state
43694366 else if (has_runtime_bits)
......@@ -4386,7 +4383,7 @@ fn updateLazyValue(
43864383 if (tuple_type.values.get(ip)[field_index] != .none) continue;
43874384 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
43884385 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4389 const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
4386 const has_comptime_state = field_type.comptimeOnly(zcu);
43904387 try wip_nav.abbrevCode(if (has_comptime_state)
43914388 .comptime_value_field_comptime_state
43924389 else if (has_runtime_bits)
......@@ -4411,7 +4408,7 @@ fn updateLazyValue(
44114408 inline .array_type, .vector_type => |sequence_type| {
44124409 const child_type: Type = .fromInterned(sequence_type.child);
44134410 const has_runtime_bits = child_type.hasRuntimeBits(zcu);
4414 const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null;
4411 const has_comptime_state = child_type.comptimeOnly(zcu);
44154412 for (switch (aggregate.storage) {
44164413 .bytes => unreachable,
44174414 .elems => |elems| elems,
......@@ -4443,7 +4440,7 @@ fn updateLazyValue(
44434440 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
44444441 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];
44454442 const has_runtime_bits = field_ty.hasRuntimeBits(zcu);
4446 const has_comptime_state = field_ty.comptimeOnly(zcu) and try field_ty.onePossibleValue(pt) == null;
4443 const has_comptime_state = field_ty.comptimeOnly(zcu);
44474444 try wip_nav.abbrevCode(if (has_comptime_state)
44484445 .comptime_value_field_comptime_state
44494446 else if (has_runtime_bits)
......@@ -4540,7 +4537,7 @@ fn updateContainerTypeWriterError(
45404537 .none => .{ false, false },
45414538 else => .{
45424539 field_type.hasRuntimeBits(zcu),
4543 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
4540 field_type.comptimeOnly(zcu),
45444541 },
45454542 };
45464543 try wip_nav.abbrevCode(if (is_comptime)
......@@ -4647,7 +4644,7 @@ fn updateContainerTypeWriterError(
46474644 .none => .{ false, false },
46484645 else => .{
46494646 field_type.hasRuntimeBits(zcu),
4650 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
4647 field_type.comptimeOnly(zcu),
46514648 },
46524649 };
46534650 try wip_nav.abbrevCode(if (is_comptime)
......@@ -4724,7 +4721,7 @@ fn updateContainerTypeWriterError(
47244721 try diw.writeUleb128(union_layout.abi_size);
47254722 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
47264723 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
4727 if (loaded_union.runtime_tag != .none) {
4724 if (loaded_union.has_runtime_tag) {
47284725 try wip_nav.abbrevCode(.tagged_union);
47294726 try wip_nav.infoSectionOffset(
47304727 .debug_info,
src/print_value.zig-2
......@@ -73,7 +73,6 @@ pub fn print(
7373 .simple_value => |simple_value| switch (simple_value) {
7474 .void => try writer.writeAll("{}"),
7575
76 .undefined,
7776 .null,
7877 .true,
7978 .false,
......@@ -111,7 +110,6 @@ pub fn print(
111110 try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema);
112111 try writer.writeAll(")");
113112 },
114 .empty_enum_value => try writer.writeAll("(empty enum value)"),
115113 .float => |float| switch (float.storage) {
116114 inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}),
117115 },