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(...@@ -999,7 +999,7 @@ fn analyzeInstBlock(
999999
1000 // If the block is noreturn, block deaths not only aren't useful, they're impossible to1000 // If the block is noreturn, block deaths not only aren't useful, they're impossible to
1001 // find: there could be more stuff alive after the block than before it!1001 // 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)) {
1003 // The block kills the difference in the live sets1003 // The block kills the difference in the live sets
1004 const block_scope = data.block_scopes.get(inst).?;1004 const block_scope = data.block_scopes.get(inst).?;
1005 const num_deaths = data.live_set.count() - block_scope.live_set.count();1005 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 {...@@ -465,7 +465,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
465465
466 for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);466 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)) {
469 assert(!self.blocks.contains(inst));469 assert(!self.blocks.contains(inst));
470 } else {470 } else {
471 var live = if (self.blocks.fetchRemove(inst)) |kv| kv.value else {471 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;...@@ -17,6 +17,7 @@ const Hash = std.hash.Wyhash;
17const Zir = std.zig.Zir;17const Zir = std.zig.Zir;
1818
19const Zcu = @import("Zcu.zig");19const Zcu = @import("Zcu.zig");
20const TypeClass = @import("Type.zig").Class;
2021
21/// One item per thread, indexed by `tid`, which is dense and unique per thread.22/// One item per thread, indexed by `tid`, which is dense and unique per thread.
22locals: []Local,23locals: []Local,
...@@ -2113,10 +2114,6 @@ pub const Key = union(enum) {...@@ -2113,10 +2114,6 @@ pub const Key = union(enum) {
2113 enum_literal: NullTerminatedString,2114 enum_literal: NullTerminatedString,
2114 /// A specific enum tag, indicated by the integer tag value.2115 /// A specific enum tag, indicated by the integer tag value.
2115 enum_tag: EnumTag,2116 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,
2120 float: Float,2117 float: Float,
2121 ptr: Ptr,2118 ptr: Ptr,
2122 slice: Slice,2119 slice: Slice,
...@@ -2722,7 +2719,6 @@ pub const Key = union(enum) {...@@ -2722,7 +2719,6 @@ pub const Key = union(enum) {
2722 .err,2719 .err,
2723 .enum_literal,2720 .enum_literal,
2724 .enum_tag,2721 .enum_tag,
2725 .empty_enum_value,
2726 .inferred_error_set_type,2722 .inferred_error_set_type,
2727 .un,2723 .un,
2728 => |x| Hash.hash(seed, asBytes(&x)),2724 => |x| Hash.hash(seed, asBytes(&x)),
...@@ -3005,10 +3001,6 @@ pub const Key = union(enum) {...@@ -3005,10 +3001,6 @@ pub const Key = union(enum) {
3005 const b_info = b.enum_tag;3001 const b_info = b.enum_tag;
3006 return std.meta.eql(a_info, b_info);3002 return std.meta.eql(a_info, b_info);
3007 },3003 },
3008 .empty_enum_value => |a_info| {
3009 const b_info = b.empty_enum_value;
3010 return a_info == b_info;
3011 },
3012 .bitpack => |a_info| {3004 .bitpack => |a_info| {
3013 const b_info = b.bitpack;3005 const b_info = b.bitpack;
3014 return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val;3006 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) {...@@ -3294,10 +3286,8 @@ pub const Key = union(enum) {
3294 .enum_literal => .enum_literal_type,3286 .enum_literal => .enum_literal_type,
32953287
3296 .undef => |x| x,3288 .undef => |x| x,
3297 .empty_enum_value => |x| x,
32983289
3299 .simple_value => |s| switch (s) {3290 .simple_value => |s| switch (s) {
3300 .undefined => .undefined_type,
3301 .void => .void_type,3291 .void => .void_type,
3302 .null => .null_type,3292 .null => .null_type,
3303 .false, .true => .bool_type,3293 .false, .true => .bool_type,
...@@ -3356,10 +3346,7 @@ pub const LoadedStructType = struct {...@@ -3356,10 +3346,7 @@ pub const LoadedStructType = struct {
3356 field_runtime_order: RuntimeOrder.Slice,3346 field_runtime_order: RuntimeOrder.Slice,
3357 field_offsets: Offsets,3347 field_offsets: Offsets,
3358 packed_backing_int_type: Index,3348 packed_backing_int_type: Index,
3359 has_no_possible_value: bool,3349 class: TypeClass,
3360 has_one_possible_value: bool,
3361 comptime_only: bool,
3362 has_runtime_bits: bool,
3363 size: u32,3350 size: u32,
3364 alignment: Alignment,3351 alignment: Alignment,
33653352
...@@ -3535,19 +3522,21 @@ pub const LoadedUnionType = struct {...@@ -3535,19 +3522,21 @@ pub const LoadedUnionType = struct {
3535 // The remaining fields are only valid once the union's layout is resolved.3522 // The remaining fields are only valid once the union's layout is resolved.
3536 field_types: Index.Slice,3523 field_types: Index.Slice,
3537 field_aligns: Alignment.Slice,3524 field_aligns: Alignment.Slice,
3538 runtime_tag: RuntimeTag,3525 tag_usage: TagUsage,
3539 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.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.
3540 enum_tag_type: Index,3532 enum_tag_type: Index,
3541 packed_backing_int_type: Index,3533 packed_backing_int_type: Index,
3542 has_no_possible_value: bool,3534 class: TypeClass,
3543 has_one_possible_value: bool,
3544 comptime_only: bool,
3545 has_runtime_bits: bool,
3546 size: u32,3535 size: u32,
3547 padding: u32,3536 padding: u32,
3548 alignment: Alignment,3537 alignment: Alignment,
35493538
3550 pub const RuntimeTag = enum(u2) {3539 pub const TagUsage = enum(u2) {
3551 none,3540 none,
3552 safety,3541 safety,
3553 tagged,3542 tagged,
...@@ -3733,10 +3722,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3733,10 +3722,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3733 .field_runtime_order = field_runtime_order,3722 .field_runtime_order = field_runtime_order,
3734 .field_offsets = field_offsets,3723 .field_offsets = field_offsets,
3735 .packed_backing_int_type = .none,3724 .packed_backing_int_type = .none,
3736 .has_no_possible_value = extra.data.flags.has_no_possible_value,3725 .class = extra.data.flags.class,
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,
3740 .size = extra.data.size,3726 .size = extra.data.size,
3741 .alignment = extra.data.flags.alignment,3727 .alignment = extra.data.flags.alignment,
3742 };3728 };
...@@ -3797,10 +3783,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3797,10 +3783,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3797 .field_runtime_order = .empty,3783 .field_runtime_order = .empty,
3798 .field_offsets = .empty,3784 .field_offsets = .empty,
3799 .packed_backing_int_type = extra.data.backing_int_type,3785 .packed_backing_int_type = extra.data.backing_int_type,
3800 .has_no_possible_value = undefined,3786 .class = undefined,
3801 .has_one_possible_value = undefined,
3802 .comptime_only = undefined,
3803 .has_runtime_bits = undefined,
3804 .size = undefined,3787 .size = undefined,
3805 .alignment = undefined,3788 .alignment = undefined,
3806 };3789 };
...@@ -3865,7 +3848,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3865,7 +3848,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3865 .auto => .auto,3848 .auto => .auto,
3866 .@"extern" => .@"extern",3849 .@"extern" => .@"extern",
3867 },3850 },
3868 .runtime_tag = extra.data.flags.runtime_tag,3851 .tag_usage = extra.data.flags.tag_usage,
3869 .enum_tag_mode = extra.data.flags.enum_tag_mode,3852 .enum_tag_mode = extra.data.flags.enum_tag_mode,
3870 .enum_tag_type = extra.data.enum_tag_type,3853 .enum_tag_type = extra.data.enum_tag_type,
3871 .packed_backing_mode = undefined,3854 .packed_backing_mode = undefined,
...@@ -3874,10 +3857,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3874,10 +3857,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3874 .want_layout = extra.data.flags.want_layout,3857 .want_layout = extra.data.flags.want_layout,
3875 .field_types = field_types,3858 .field_types = field_types,
3876 .field_aligns = field_aligns,3859 .field_aligns = field_aligns,
3877 .has_no_possible_value = extra.data.flags.has_no_possible_value,3860 .has_runtime_tag = extra.data.flags.has_runtime_tag,
3878 .has_one_possible_value = extra.data.flags.has_one_possible_value,3861 .class = extra.data.flags.class,
3879 .comptime_only = extra.data.flags.comptime_only,
3880 .has_runtime_bits = extra.data.flags.has_runtime_bits,
3881 .size = extra.data.size,3862 .size = extra.data.size,
3882 .padding = extra.data.padding,3863 .padding = extra.data.padding,
3883 .alignment = extra.data.flags.alignment,3864 .alignment = extra.data.flags.alignment,
...@@ -3919,7 +3900,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3919,7 +3900,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3919 .name_nav = extra.data.name_nav,3900 .name_nav = extra.data.name_nav,
3920 .namespace = extra.data.namespace,3901 .namespace = extra.data.namespace,
3921 .layout = .@"packed",3902 .layout = .@"packed",
3922 .runtime_tag = .none,3903 .tag_usage = .none,
3923 .enum_tag_mode = .auto,3904 .enum_tag_mode = .auto,
3924 .enum_tag_type = extra.data.enum_tag_type,3905 .enum_tag_type = extra.data.enum_tag_type,
3925 .packed_backing_mode = backing_mode,3906 .packed_backing_mode = backing_mode,
...@@ -3928,10 +3909,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3928,10 +3909,8 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3928 .want_layout = extra.data.bits.want_layout,3909 .want_layout = extra.data.bits.want_layout,
3929 .field_types = field_types,3910 .field_types = field_types,
3930 .field_aligns = .empty,3911 .field_aligns = .empty,
3931 .has_no_possible_value = undefined,3912 .has_runtime_tag = undefined,
3932 .has_one_possible_value = undefined,3913 .class = undefined,
3933 .comptime_only = undefined,
3934 .has_runtime_bits = undefined,
3935 .size = undefined,3914 .size = undefined,
3936 .padding = undefined,3915 .padding = undefined,
3937 .alignment = undefined,3916 .alignment = undefined,
...@@ -4818,7 +4797,7 @@ pub const static_keys: [static_len]Key = .{...@@ -4818,7 +4797,7 @@ pub const static_keys: [static_len]Key = .{
4818 .values = .empty,4797 .values = .empty,
4819 } },4798 } },
48204799
4821 .{ .simple_value = .undefined },4800 .{ .undef = .undefined_type },
4822 .{ .undef = .bool_type },4801 .{ .undef = .bool_type },
4823 .{ .undef = .usize_type },4802 .{ .undef = .usize_type },
4824 .{ .undef = .u1_type },4803 .{ .undef = .u1_type },
...@@ -5682,23 +5661,14 @@ pub const Tag = enum(u8) {...@@ -5682,23 +5661,14 @@ pub const Tag = enum(u8) {
5682 any_field_defaults: bool,5661 any_field_defaults: bool,
5683 any_field_aligns: bool,5662 any_field_aligns: bool,
56845663
5685 /// Whether the struct is an OPV type. Always `false` until layout resolved.5664 class: TypeClass,
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,
5695 /// Alignment of the whole struct. Always `.none` until layout resolved.5665 /// Alignment of the whole struct. Always `.none` until layout resolved.
5696 alignment: Alignment,5666 alignment: Alignment,
56975667
5698 want_layout: bool,5668 want_layout: bool,
5699 want_defaults: bool,5669 want_defaults: bool,
57005670
5701 _: u14 = 0,5671 _: u15 = 0,
5702 };5672 };
5703 };5673 };
57045674
...@@ -5778,18 +5748,11 @@ pub const Tag = enum(u8) {...@@ -5778,18 +5748,11 @@ pub const Tag = enum(u8) {
5778 layout: enum(u1) { auto, @"extern" },5748 layout: enum(u1) { auto, @"extern" },
57795749
5780 any_field_aligns: bool,5750 any_field_aligns: bool,
5781 runtime_tag: LoadedUnionType.RuntimeTag,5751 tag_usage: LoadedUnionType.TagUsage,
57825752
5783 /// Whether the union is an OPV type. Always `false` until layout resolved.5753 class: TypeClass,
5784 /// The actual OPV is not cached, but caching this bit of state means we avoid5754 has_runtime_tag: bool,
5785 /// repeatedly doing redundant checks to find that the union is not OPV!5755
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,
5793 /// Alignment of the whole union. Always `.none` until layout resolved.5756 /// Alignment of the whole union. Always `.none` until layout resolved.
5794 alignment: Alignment,5757 alignment: Alignment,
57955758
...@@ -5970,8 +5933,6 @@ pub const SimpleType = enum(u32) {...@@ -5970,8 +5933,6 @@ pub const SimpleType = enum(u32) {
5970};5933};
59715934
5972pub const SimpleValue = enum(u32) {5935pub const SimpleValue = enum(u32) {
5973 /// This is untyped `undefined`.
5974 undefined = @intFromEnum(Index.undef),
5975 void = @intFromEnum(Index.void_value),5936 void = @intFromEnum(Index.void_value),
5976 /// This is untyped `null`.5937 /// This is untyped `null`.
5977 null = @intFromEnum(Index.null_value),5938 null = @intFromEnum(Index.null_value),
...@@ -7016,11 +6977,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7016,11 +6977,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7016 } };6977 } };
7017 },6978 },
70186979
7019 .type_enum_auto,
7020 .type_enum_explicit,
7021 .type_union,
7022 => .{ .empty_enum_value = ty },
7023
7024 else => unreachable,6980 else => unreachable,
7025 };6981 };
7026 },6982 },
...@@ -7914,11 +7870,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -7914,11 +7870,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7914 });7870 });
7915 },7871 },
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
7922 .float => |float| {7873 .float => |float| {
7923 switch (float.ty) {7874 switch (float.ty) {
7924 .f16_type => items.appendAssumeCapacity(.{7875 .f16_type => items.appendAssumeCapacity(.{
...@@ -8302,10 +8253,7 @@ pub fn getDeclaredStructType(...@@ -8302,10 +8253,7 @@ pub fn getDeclaredStructType(
8302 .any_comptime_fields = ini.any_comptime_fields,8253 .any_comptime_fields = ini.any_comptime_fields,
8303 .any_field_defaults = ini.any_field_defaults,8254 .any_field_defaults = ini.any_field_defaults,
8304 .any_field_aligns = ini.any_field_aligns,8255 .any_field_aligns = ini.any_field_aligns,
8305 .has_one_possible_value = false,8256 .class = .no_possible_value,
8306 .has_no_possible_value = false,
8307 .comptime_only = false,
8308 .has_runtime_bits = false,
8309 .alignment = .none,8257 .alignment = .none,
8310 .want_layout = false,8258 .want_layout = false,
8311 .want_defaults = false,8259 .want_defaults = false,
...@@ -8456,10 +8404,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe...@@ -8456,10 +8404,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
8456 .any_comptime_fields = ini.any_comptime_fields,8404 .any_comptime_fields = ini.any_comptime_fields,
8457 .any_field_defaults = ini.any_field_defaults,8405 .any_field_defaults = ini.any_field_defaults,
8458 .any_field_aligns = ini.any_field_aligns,8406 .any_field_aligns = ini.any_field_aligns,
8459 .has_one_possible_value = false,8407 .class = .no_possible_value,
8460 .has_no_possible_value = false,
8461 .comptime_only = false,
8462 .has_runtime_bits = false,
8463 .alignment = .none,8408 .alignment = .none,
8464 .want_layout = false,8409 .want_layout = false,
8465 .want_defaults = false,8410 .want_defaults = false,
...@@ -8535,7 +8480,7 @@ pub fn getDeclaredUnionType(...@@ -8535,7 +8480,7 @@ pub fn getDeclaredUnionType(
8535 fields_len: u32,8480 fields_len: u32,
8536 layout: std.builtin.Type.ContainerLayout,8481 layout: std.builtin.Type.ContainerLayout,
8537 any_field_aligns: bool,8482 any_field_aligns: bool,
8538 runtime_tag: LoadedUnionType.RuntimeTag,8483 tag_usage: LoadedUnionType.TagUsage,
8539 enum_tag_mode: BackingTypeMode,8484 enum_tag_mode: BackingTypeMode,
8540 packed_backing_mode: BackingTypeMode,8485 packed_backing_mode: BackingTypeMode,
8541 },8486 },
...@@ -8617,11 +8562,9 @@ pub fn getDeclaredUnionType(...@@ -8617,11 +8562,9 @@ pub fn getDeclaredUnionType(
8617 .enum_tag_mode = ini.enum_tag_mode,8562 .enum_tag_mode = ini.enum_tag_mode,
8618 .layout = if (is_extern) .@"extern" else .auto,8563 .layout = if (is_extern) .@"extern" else .auto,
8619 .any_field_aligns = ini.any_field_aligns,8564 .any_field_aligns = ini.any_field_aligns,
8620 .runtime_tag = ini.runtime_tag,8565 .tag_usage = ini.tag_usage,
8621 .has_one_possible_value = false,8566 .class = .no_possible_value,
8622 .has_no_possible_value = false,8567 .has_runtime_tag = false,
8623 .comptime_only = false,
8624 .has_runtime_bits = false,
8625 .alignment = .none,8568 .alignment = .none,
8626 .want_layout = false,8569 .want_layout = false,
8627 },8570 },
...@@ -8658,8 +8601,8 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8658,8 +8601,8 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8658 fields_len: u32,8601 fields_len: u32,
8659 layout: std.builtin.Type.ContainerLayout,8602 layout: std.builtin.Type.ContainerLayout,
8660 any_field_aligns: bool,8603 any_field_aligns: bool,
8661 runtime_tag: LoadedUnionType.RuntimeTag,8604 tag_usage: LoadedUnionType.TagUsage,
8662 /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`.8605 /// Explicitly specified enum tag type. `.none` if `tag_usage != .tagged`.
8663 enum_tag_type: Index,8606 enum_tag_type: Index,
8664 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.8607 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
8665 packed_backing_int_type: Index,8608 packed_backing_int_type: Index,
...@@ -8745,11 +8688,9 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8745,11 +8688,9 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8745 .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,8688 .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,
8746 .layout = if (is_extern) .@"extern" else .auto,8689 .layout = if (is_extern) .@"extern" else .auto,
8747 .any_field_aligns = ini.any_field_aligns,8690 .any_field_aligns = ini.any_field_aligns,
8748 .runtime_tag = ini.runtime_tag,8691 .tag_usage = ini.tag_usage,
8749 .has_one_possible_value = false,8692 .class = .no_possible_value,
8750 .has_no_possible_value = false,8693 .has_runtime_tag = false,
8751 .comptime_only = false,
8752 .has_runtime_bits = false,
8753 .alignment = .none,8694 .alignment = .none,
8754 .want_layout = false,8695 .want_layout = false,
8755 },8696 },
...@@ -12007,20 +11948,6 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {...@@ -12007,20 +11948,6 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
12007 ]);11948 ]);
12008}11949}
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
12024pub fn isUndef(ip: *const InternPool, val: Index) bool {11951pub fn isUndef(ip: *const InternPool, val: Index) bool {
12025 return val == .undef or val.unwrap(ip).getTag(ip) == .undef;11952 return val == .undef or val.unwrap(ip).getTag(ip) == .undef;
12026}11953}
...@@ -12823,10 +12750,7 @@ pub fn resolveStructLayout(...@@ -12823,10 +12750,7 @@ pub fn resolveStructLayout(
12823 struct_type: Index,12750 struct_type: Index,
12824 size: u32,12751 size: u32,
12825 alignment: Alignment,12752 alignment: Alignment,
12826 has_no_possible_value: bool,12753 class: TypeClass,
12827 has_one_possible_value: bool,
12828 comptime_only: bool,
12829 has_runtime_bits: bool,
12830) void {12754) void {
12831 const unwrapped_index = struct_type.unwrap(ip);12755 const unwrapped_index = struct_type.unwrap(ip);
1283212756
...@@ -12840,10 +12764,7 @@ pub fn resolveStructLayout(...@@ -12840,10 +12764,7 @@ pub fn resolveStructLayout(
1284012764
12841 extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size;12765 extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size;
12842 const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?]);12766 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;12767 flags.class = class;
12844 flags.has_one_possible_value = has_one_possible_value;
12845 flags.comptime_only = comptime_only;
12846 flags.has_runtime_bits = has_runtime_bits;
12847 flags.alignment = alignment;12768 flags.alignment = alignment;
12848}12769}
1284912770
...@@ -12856,13 +12777,11 @@ pub fn resolveUnionLayout(...@@ -12856,13 +12777,11 @@ pub fn resolveUnionLayout(
12856 io: Io,12777 io: Io,
12857 union_type: Index,12778 union_type: Index,
12858 enum_tag_type: Index,12779 enum_tag_type: Index,
12780 class: TypeClass,
12781 has_runtime_tag: bool,
12859 size: u32,12782 size: u32,
12860 padding: u32,12783 padding: u32,
12861 alignment: Alignment,12784 alignment: Alignment,
12862 has_no_possible_value: bool,
12863 has_one_possible_value: bool,
12864 comptime_only: bool,
12865 has_runtime_bits: bool,
12866) void {12785) void {
12867 const unwrapped_index = union_type.unwrap(ip);12786 const unwrapped_index = union_type.unwrap(ip);
1286812787
...@@ -12878,10 +12797,8 @@ pub fn resolveUnionLayout(...@@ -12878,10 +12797,8 @@ pub fn resolveUnionLayout(
12878 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;12797 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
12879 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;12798 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
12880 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);12799 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;12800 flags.class = class;
12882 flags.has_one_possible_value = has_one_possible_value;12801 flags.has_runtime_tag = has_runtime_tag;
12883 flags.comptime_only = comptime_only;
12884 flags.has_runtime_bits = has_runtime_bits;
12885 flags.alignment = alignment;12802 flags.alignment = alignment;
12886}12803}
1288712804
src/Sema.zig+195-237
...@@ -178,8 +178,11 @@ const ComptimeAlloc = struct {...@@ -178,8 +178,11 @@ const ComptimeAlloc = struct {
178fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {178fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
179 const pt = sema.pt;179 const pt = sema.pt;
180180
181 // Explicit guard because this call mutates the InternPool so cannot be optimized out.181 switch (ty.classify(pt.zcu)) {
182 if (std.debug.runtime_safety) assert(ty.onePossibleValue(pt) catch @panic("") == null);182 .no_possible_value => unreachable,
183 .one_possible_value => unreachable,
184 else => {},
185 }
183186
184 const idx = sema.comptime_allocs.items.len;187 const idx = sema.comptime_allocs.items.len;
185 try sema.comptime_allocs.append(sema.gpa, .{188 try sema.comptime_allocs.append(sema.gpa, .{
...@@ -1991,31 +1994,28 @@ fn analyzeBodyInner(...@@ -1991,31 +1994,28 @@ fn analyzeBodyInner(
1991 break :blk .void_value;1994 break :blk .void_value;
1992 },1995 },
1993 };1996 };
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;
2001 // We must resolve the layout of a type before creating a value of that type. Therefore,2002 // 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 // the layout of the type of `air_ref` must already be resolved. The call to `classify`
2003 check_type: {2004 // doubles as an assertion of this.
2004 if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {2005 if (!is_inferred_alloc) switch (sema.typeOf(air_ref).classify(zcu)) {
2005 .inferred_alloc, .inferred_alloc_comptime => break :check_type,2006 .no_possible_value => {
2006 else => {},2007 // The instruction result was noreturn, which should mean that the body itself now
2007 };2008 // ends with a noreturn instruction. Let's confirm that.
2008 sema.typeOf(air_ref).assertHasLayout(zcu);2009 const last_inst = block.instructions.items[block.instructions.items.len - 1];
2009 // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value2010 const last_inst_ty = sema.typeOf(last_inst.toRef());
2010 // it could be, and it would be a bug for the value to not be comptime-known when it has2011 assert(last_inst_ty.classify(zcu) == .no_possible_value);
2011 // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates2012 break;
2012 // the InternPool so cannot be optimized out.2013 },
2013 if (std.debug.runtime_safety) {2014 .one_possible_value => assert(air_ref.toInterned() != null), // the value should be comptime-known
2014 if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| {2015 .partially_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
2015 assert(air_ref == Air.Inst.Ref.fromValue(opv));2016 .fully_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
2016 }2017 .runtime => {},
2017 }2018 };
2018 }
20192019
2020 map.putAssumeCapacity(inst, air_ref);2020 map.putAssumeCapacity(inst, air_ref);
2021 i += 1;2021 i += 1;
...@@ -2287,11 +2287,12 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value {...@@ -2287,11 +2287,12 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value {
2287 .inferred_alloc_comptime => unreachable, // assertion failure2287 .inferred_alloc_comptime => unreachable, // assertion failure
2288 else => {},2288 else => {},
2289 }2289 }
2290 // Assert that the type is not OPV -- if it was, the value would have been comptime-known.2290 switch (sema.typeOf(inst).classify(zcu)) {
2291 // Explicit guard because this could add to the InternPool so cannot be optimized away.2291 .no_possible_value => unreachable, // values of this type do not exist
2292 if (std.debug.runtime_safety) {2292 .one_possible_value => unreachable, // the value should be comptime-known
2293 const opv = sema.typeOf(inst).onePossibleValue(sema.pt) catch @panic("oom in assert");2293 .partially_comptime => unreachable, // the value should be comptime-known
2294 assert(opv == null);2294 .fully_comptime => unreachable, // the value should be comptime-known
2295 .runtime => {},
2295 }2296 }
2296 return null;2297 return null;
2297 }2298 }
...@@ -4645,16 +4646,21 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -4645,16 +4646,21 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
4645 const elem_ty = operand_ty.childType(zcu);4646 const elem_ty = operand_ty.childType(zcu);
4646 try sema.ensureLayoutResolved(elem_ty, src);4647 try sema.ensureLayoutResolved(elem_ty, src);
46474648
4648 if (try elem_ty.onePossibleValue(pt) != null) {4649 const need_comptime = switch (elem_ty.classify(zcu)) {
4649 // No need to validate the actual pointer value, we don't need it!4650 .no_possible_value => return sema.fail(block, src, "cannot load {s} type '{f}'", .{
4650 return;4651 if (elem_ty.zigTypeTag(zcu) == .@"opaque") "opaque" else "uninstantiable",
4651 }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
4653 if (sema.resolveValue(operand)) |val| {4659 if (sema.resolveValue(operand)) |val| {
4654 if (val.isUndef(zcu)) {4660 if (val.isUndef(zcu)) {
4655 return sema.fail(block, src, "cannot dereference undefined value", .{});4661 return sema.fail(block, src, "cannot dereference undefined value", .{});
4656 }4662 }
4657 } else if (elem_ty.comptimeOnly(zcu)) {4663 } else if (need_comptime) {
4658 const msg = msg: {4664 const msg = msg: {
4659 const msg = try sema.errMsg(4665 const msg = try sema.errMsg(
4660 src,4666 src,
...@@ -4870,7 +4876,7 @@ fn storeToInferredAllocComptime(...@@ -4870,7 +4876,7 @@ fn storeToInferredAllocComptime(
4870 .is_const = iac.is_const,4876 .is_const = iac.is_const,
4871 },4877 },
4872 });4878 });
4873 if (try operand_ty.onePossibleValue(pt) != null or4879 if (operand_ty.classify(zcu) == .one_possible_value or
4874 (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)))4880 (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)))
4875 {4881 {
4876 iac.ptr = try pt.intern(.{ .ptr = .{4882 iac.ptr = try pt.intern(.{ .ptr = .{
...@@ -6672,7 +6678,7 @@ const CallArgsInfo = union(enum) {...@@ -6672,7 +6678,7 @@ const CallArgsInfo = union(enum) {
6672 return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);6678 return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);
6673 }6679 }
66746680
6675 if (sema.typeOf(uncoerced_arg).zigTypeTag(zcu) == .noreturn) {6681 if (sema.typeOf(uncoerced_arg).classify(zcu) == .no_possible_value) {
6676 // This terminates resolution of arguments. The caller should6682 // This terminates resolution of arguments. The caller should
6677 // propagate this.6683 // propagate this.
6678 return uncoerced_arg;6684 return uncoerced_arg;
...@@ -6928,7 +6934,7 @@ fn analyzeCall(...@@ -6928,7 +6934,7 @@ fn analyzeCall(
69286934
6929 arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst);6935 arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst);
6930 const arg_ty = sema.typeOf(arg.*);6936 const arg_ty = sema.typeOf(arg.*);
6931 if (arg_ty.zigTypeTag(zcu) == .noreturn) {6937 if (arg_ty.classify(zcu) == .no_possible_value) {
6932 return arg.*; // terminate analysis here6938 return arg.*; // terminate analysis here
6933 }6939 }
69346940
...@@ -7183,7 +7189,7 @@ fn analyzeCall(...@@ -7183,7 +7189,7 @@ fn analyzeCall(
7183 return sema.handleTailCall(block, call_src, runtime_func_ty, maybe_opv);7189 return sema.handleTailCall(block, call_src, runtime_func_ty, maybe_opv);
7184 }7190 }
71857191
7186 if (ip.isNoReturn(resolved_ret_ty.toIntern())) {7192 if (resolved_ret_ty.isNoReturn(zcu)) {
7187 const want_check = c: {7193 const want_check = c: {
7188 if (!block.wantSafety()) break :c false;7194 if (!block.wantSafety()) break :c false;
7189 if (func_val != null) break :c false;7195 if (func_val != null) break :c false;
...@@ -7989,16 +7995,16 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7989,16 +7995,16 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
7989 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {7995 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {
7990 .@"enum" => operand,7996 .@"enum" => operand,
7991 .@"union" => blk: {7997 .@"union" => blk: {
7992 const tag_ty = operand_ty.unionTagType(zcu) orelse {7998 if (operand_ty.unionTagType(zcu) == null) {
7993 return sema.fail(7999 return sema.fail(
7994 block,8000 block,
7995 operand_src,8001 operand_src,
7996 "untagged union '{f}' cannot be converted to integer",8002 "untagged union '{f}' cannot be converted to integer",
7997 .{operand_ty.fmt(pt)},8003 .{operand_ty.fmt(pt)},
7998 );8004 );
7999 };8005 }
80008006
8001 break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);8007 break :blk try sema.unionToTag(block, operand);
8002 },8008 },
8003 else => {8009 else => {
8004 return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{8010 return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{
...@@ -10151,9 +10157,8 @@ fn analyzeSwitchBlock(...@@ -10151,9 +10157,8 @@ fn analyzeSwitchBlock(
10151 const maybe_operand_opv = try operand_ty.onePossibleValue(pt);10157 const maybe_operand_opv = try operand_ty.onePossibleValue(pt);
10152 const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {10158 const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
10153 .@"union" => tag: {10159 .@"union" => tag: {
10154 const tag_ty = operand_ty.unionTagType(zcu).?;10160 const tag_val = try sema.unionToTag(block, val);
10155 const tag_val = try sema.unionToTag(block, tag_ty, val, operand_src);10161 break :tag .{ tag_val, sema.typeOf(tag_val) };
10156 break :tag .{ tag_val, tag_ty };
10157 },10162 },
10158 else => .{10163 else => .{
10159 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,10164 if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,
...@@ -10245,7 +10250,7 @@ fn analyzeSwitchBlock(...@@ -10245,7 +10250,7 @@ fn analyzeSwitchBlock(
10245 .{ new_operand, .none };10250 .{ new_operand, .none };
1024610251
10247 const new_cond_ref = if (union_originally)10252 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)
10249 else10254 else
10250 new_val;10255 new_val;
1025110256
...@@ -12147,8 +12152,7 @@ fn analyzeSwitchTagCapture(...@@ -12147,8 +12152,7 @@ fn analyzeSwitchTagCapture(
12147 .item_refs => |refs| if (refs.len == 1) return refs[0],12152 .item_refs => |refs| if (refs.len == 1) return refs[0],
12148 .special => {},12153 .special => {},
12149 }12154 }
12150 const tag_ty = operand_ty.unionTagType(zcu).?;12155 return sema.unionToTag(case_block, operand_val);
12151 return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src);
12152}12156}
1215312157
12154fn analyzeSwitchPayloadCapture(12158fn analyzeSwitchPayloadCapture(
...@@ -15389,9 +15393,12 @@ fn analyzePtrArithmetic(...@@ -15389,9 +15393,12 @@ fn analyzePtrArithmetic(
15389 const elem_ty: Type = .fromInterned(ptr_info.child);15393 const elem_ty: Type = .fromInterned(ptr_info.child);
15390 elem_ty.assertHasLayout(zcu);15394 elem_ty.assertHasLayout(zcu);
1539115395
15392 if (elem_ty.abiSize(zcu) == 0) {15396 switch (elem_ty.classify(zcu)) {
15393 // Offset will be multiplied by zero, so result is the same as the base pointer.15397 .no_possible_value, .one_possible_value => {
15394 return ptr;15398 // Offset will be multiplied by zero, so result is the same as the base pointer.
15399 return ptr;
15400 },
15401 else => {},
15395 }15402 }
1539615403
15397 const new_ptr_ty = t: {15404 const new_ptr_ty = t: {
...@@ -15757,7 +15764,7 @@ fn analyzeCmpUnionTag(...@@ -15757,7 +15764,7 @@ fn analyzeCmpUnionTag(
15757 if (sema.resolveValue(coerced_tag)) |enum_val| {15764 if (sema.resolveValue(coerced_tag)) |enum_val| {
15758 if (enum_val.isUndef(zcu)) return .undef_bool;15765 if (enum_val.isUndef(zcu)) return .undef_bool;
15759 const field_ty = union_ty.unionFieldType(enum_val, zcu).?;15766 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) {
15761 return .bool_false;15768 return .bool_false;
15762 }15769 }
15763 }15770 }
...@@ -15934,39 +15941,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -15934,39 +15941,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
15934 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;15941 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
15935 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);15942 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
15936 const ty = try sema.resolveType(block, operand_src, inst_data.operand);15943 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
15937 switch (ty.zigTypeTag(zcu)) {15944 try sema.ensureLayoutResolved(ty, operand_src);
15938 .@"fn",15945 switch (ty.classify(zcu)) {
15939 .noreturn,15946 .no_possible_value,
15940 .undefined,15947 => return sema.fail(block, operand_src, "no size available for uninstantiable type '{f}'", .{ty.fmt(pt)}),
15941 .null,
15942 .@"opaque",
15943 => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}),
1594415948
15945 .type,15949 .partially_comptime,
15946 .enum_literal,15950 .fully_comptime,
15947 .comptime_float,15951 => return sema.fail(block, operand_src, "no size available for comptime-only type '{f}'", .{ty.fmt(pt)}),
15948 .comptime_int,
15949 .void,
15950 => return .zero,
1595115952
15952 .bool,15953 .one_possible_value => {
15953 .int,15954 assert(ty.abiSize(zcu) == 0);
15954 .float,15955 return .zero;
15955 .pointer,15956 },
15956 .array,15957
15957 .@"struct",15958 .runtime => return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu))),
15958 .optional,
15959 .error_union,
15960 .error_set,
15961 .@"enum",
15962 .@"union",
15963 .vector,
15964 .frame,
15965 .@"anyframe",
15966 => {},
15967 }15959 }
15968 try sema.ensureLayoutResolved(ty, operand_src);
15969 return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu)));
15970}15960}
1597115961
15972fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {15962fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -18631,9 +18621,9 @@ fn zirStructInit(...@@ -18631,9 +18621,9 @@ fn zirStructInit(
18631 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);18621 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
18632 const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);18622 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) {
18635 return sema.failWithOwnedErrorMsg(block, msg: {18625 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)});
18637 errdefer msg.destroy(sema.gpa);18627 errdefer msg.destroy(sema.gpa);
1863818628
18639 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{18629 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{
...@@ -18648,7 +18638,13 @@ fn zirStructInit(...@@ -18648,7 +18638,13 @@ fn zirStructInit(
18648 const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src);18638 const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src);
1864918639
18650 if (resolved_ty.containerLayout(zcu) == .@"packed") {18640 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 }
18652 }18648 }
1865318649
18654 if (sema.resolveValue(init_inst)) |val| {18650 if (sema.resolveValue(init_inst)) |val| {
...@@ -18681,9 +18677,6 @@ fn zirStructInit(...@@ -18681,9 +18677,6 @@ fn zirStructInit(
18681 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);18677 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
18682 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);18678 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);
18683 try sema.storePtr(block, src, field_ptr, init_inst);18679 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 }
18687 return sema.makePtrConst(block, alloc);18680 return sema.makePtrConst(block, alloc);
18688 }18681 }
1868918682
...@@ -19451,10 +19444,10 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -19451,10 +19444,10 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
19451 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;19444 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
19452 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);19445 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
19453 const ty = try sema.resolveType(block, operand_src, inst_data.operand);19446 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
19447 try sema.ensureLayoutResolved(ty, operand_src);
19454 if (ty.isNoReturn(zcu)) {19448 if (ty.isNoReturn(zcu)) {
19455 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});19449 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
19456 }19450 }
19457 try sema.ensureLayoutResolved(ty, operand_src);
19458 return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?));19451 return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?));
19459}19452}
1946019453
...@@ -20447,10 +20440,10 @@ fn zirReifyUnion(...@@ -20447,10 +20440,10 @@ fn zirReifyUnion(
20447 .fields_len = @intCast(fields_len),20440 .fields_len = @intCast(fields_len),
20448 .layout = layout,20441 .layout = layout,
20449 .any_field_aligns = any_field_aligns,20442 .any_field_aligns = any_field_aligns,
20450 .runtime_tag = rt: {20443 .tag_usage = tag: {
20451 if (explicit_tag_ty != null) break :rt .tagged;20444 if (explicit_tag_ty != null) break :tag .tagged;
20452 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;20445 if (layout == .auto and block.wantSafeTypes()) break :tag .safety;
20453 break :rt .none;20446 break :tag .none;
20454 },20447 },
20455 .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,20448 .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,
20456 .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,20449 .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,
...@@ -22608,7 +22601,7 @@ fn zirCmpxchg(...@@ -22608,7 +22601,7 @@ fn zirCmpxchg(
22608 const result_ty = try pt.optionalType(elem_ty.toIntern());22601 const result_ty = try pt.optionalType(elem_ty.toIntern());
2260922602
22610 // special case zero bit types22603 // special case zero bit types
22611 if (try elem_ty.onePossibleValue(pt) != null) {22604 if (elem_ty.classify(zcu) == .one_possible_value) {
22612 return .fromValue(try pt.nullValue(result_ty));22605 return .fromValue(try pt.nullValue(result_ty));
22613 }22606 }
2261422607
...@@ -25514,8 +25507,9 @@ fn fieldPtrLoad(...@@ -25514,8 +25507,9 @@ fn fieldPtrLoad(
25514 const pt = sema.pt;25507 const pt = sema.pt;
25515 const zcu = pt.zcu;25508 const zcu = pt.zcu;
25516 const object_ptr_ty = sema.typeOf(object_ptr);25509 const object_ptr_ty = sema.typeOf(object_ptr);
25510 assert(object_ptr_ty.zigTypeTag(zcu) == .pointer);
25517 const pointee_ty = object_ptr_ty.childType(zcu);25511 const pointee_ty = object_ptr_ty.childType(zcu);
25518 try sema.ensureLayoutResolved(pointee_ty, src); // MLUGG TODO25512 try sema.ensureLayoutResolved(pointee_ty, src);
25519 if (try pointee_ty.onePossibleValue(pt)) |opv| {25513 if (try pointee_ty.onePossibleValue(pt)) |opv| {
25520 const object: Air.Inst.Ref = .fromValue(opv);25514 const object: Air.Inst.Ref = .fromValue(opv);
25521 return fieldVal(sema, block, src, object, field_name, field_name_src);25515 return fieldVal(sema, block, src, object, field_name, field_name_src);
...@@ -26477,9 +26471,9 @@ fn unionFieldPtr(...@@ -26477,9 +26471,9 @@ fn unionFieldPtr(
26477 });26471 });
26478 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?);26472 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) {
26481 const msg = msg: {26475 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)});
26483 errdefer msg.destroy(sema.gpa);26477 errdefer msg.destroy(sema.gpa);
2648426478
26485 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{26479 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
...@@ -26529,30 +26523,29 @@ fn unionFieldPtr(...@@ -26529,30 +26523,29 @@ fn unionFieldPtr(
26529 },26523 },
26530 .@"packed", .@"extern" => {},26524 .@"packed", .@"extern" => {},
26531 }26525 }
26532 const field_ptr_val = try union_ptr_val.ptrField(field_index, pt);26526 return .fromValue(try union_ptr_val.ptrField(field_index, pt));
26533 return Air.internedToRef(field_ptr_val.toIntern());
26534 }26527 }
2653526528
26536 // If the union has a tag, we must either set or or safety check it depending on `initializing`.26529 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
26537 tag: {26530 tag: {
26538 if (union_ty.containerLayout(zcu) != .auto) break :tag;26531 if (union_ty.containerLayout(zcu) != .auto) break :tag;
26539 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);26532 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;
26541 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but26534 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
26542 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).26535 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
26543 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);26536 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
26544 if (initializing) {26537 if (initializing) {
26545 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));26538 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
26546 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store26539 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) {26540 } else if (block.wantSafety() and union_obj.has_runtime_tag) {
26548 // The tag exists at runtime (safety tag), so emit a safety check.26541 // The tag exists at runtime (actual or safety tag), so emit a safety check.
26549 // TODO would it be better if get_union_tag supported pointers to unions?26542 // TODO would it be better if get_union_tag supported pointers to unions?
26550 const union_val = try block.addTyOp(.load, union_ty, union_ptr);26543 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
26551 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);26544 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
26552 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));26545 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
26553 }26546 }
26554 }26547 }
26555 if (field_ty.zigTypeTag(zcu) == .noreturn) {26548 if (field_ty.classify(zcu) == .no_possible_value) {
26556 _ = try block.addNoOp(.unreach);26549 _ = try block.addNoOp(.unreach);
26557 return .unreachable_value;26550 return .unreachable_value;
26558 }26551 }
...@@ -26578,57 +26571,40 @@ fn unionFieldVal(...@@ -26578,57 +26571,40 @@ fn unionFieldVal(
26578 const union_obj = zcu.typeToUnion(union_ty).?;26571 const union_obj = zcu.typeToUnion(union_ty).?;
26579 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26572 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
26580 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);26573 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
26583 if (sema.resolveValue(union_byval)) |union_val| {26576 if (sema.resolveValue(union_byval)) |union_val| {
26584 if (union_val.isUndef(zcu)) return pt.undefRef(field_ty);26577 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();
26589 switch (union_obj.layout) {26578 switch (union_obj.layout) {
26590 .auto => {26579 .auto => {
26591 if (tag_matches) {26580 const active_tag_val = union_val.unionTag(zcu).?;
26592 return Air.internedToRef(un.val);26581 const active_index = enum_tag_ty.enumTagFieldIndex(active_tag_val, zcu).?;
26593 } else {26582 if (active_index == field_index) return .fromValue(union_val.unionPayload(zcu));
26594 const msg = msg: {26583 return sema.fail(block, src, "access of union field '{f}' while field '{f}' is active", .{
26595 const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;26584 field_name.fmt(ip), enum_tag_ty.enumFieldName(active_index, zcu).fmt(ip),
26596 const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu);26585 });
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 }
26606 },26586 },
26607 .@"extern" => if (tag_matches) {26587 .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
26608 // Fast path - no need to use bitcast logic.26588 return .fromValue(field_val);
26609 return Air.internedToRef(un.val);26589 } else {
26610 } else if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {26590 // Runtime-known due to a pointer-to-integer conversion.
26611 return Air.internedToRef(field_val.toIntern());
26612 },26591 },
26613 .@"packed" => if (tag_matches) {26592 .@"packed" => {
26614 // Fast path - no need to use bitcast logic.26593 const field_val = try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0) orelse {
26615 return Air.internedToRef(un.val);26594 unreachable; // `null` is only possible if the input value contains a pointer, which a packed union cannot.
26616 } else if (try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0)) |field_val| {26595 };
26617 return Air.internedToRef(field_val.toIntern());26596 return .fromValue(field_val);
26618 },26597 },
26619 }26598 }
26620 }26599 }
2662126600
26622 if (union_obj.layout == .auto and block.wantSafety() and26601 if (union_obj.layout == .auto and block.wantSafety() and union_obj.has_runtime_tag) {
26623 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)26602 const wanted_tag_val = try pt.enumValueFieldIndex(enum_tag_ty, field_index);
26624 {26603 const active_tag = try block.addTyOp(.get_union_tag, enum_tag_ty, union_byval);
26625 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);26604 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(wanted_tag_val));
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);
26629 }26605 }
2663026606
26631 if (field_ty.zigTypeTag(zcu) == .noreturn) {26607 if (field_ty.classify(zcu) == .no_possible_value) {
26632 _ = try block.addNoOp(.unreach);26608 _ = try block.addNoOp(.unreach);
26633 return .unreachable_value;26609 return .unreachable_value;
26634 }26610 }
...@@ -27767,11 +27743,10 @@ fn coerceExtra(...@@ -27767,11 +27743,10 @@ fn coerceExtra(
27767 };27743 };
27768 return Air.internedToRef((try pt.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());27744 return Air.internedToRef((try pt.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());
27769 },27745 },
27770 .@"union" => blk: {27746 .@"union" => if (inst_ty.unionTagType(zcu)) |enum_tag_ty| {
27771 // union to its own tag type27747 // union to its own tag type
27772 const union_tag_ty = inst_ty.unionTagType(zcu) orelse break :blk;27748 if (enum_tag_ty.toIntern() == dest_ty.toIntern()) {
27773 if (union_tag_ty.eql(dest_ty, zcu)) {27749 return sema.unionToTag(block, inst);
27774 return sema.unionToTag(block, dest_ty, inst, inst_src);
27775 }27750 }
27776 },27751 },
27777 else => {},27752 else => {},
...@@ -27857,18 +27832,16 @@ fn coerceExtra(...@@ -27857,18 +27832,16 @@ fn coerceExtra(
27857 else => {},27832 else => {},
27858 }27833 }
2785927834
27860 const can_coerce_to = switch (dest_ty.zigTypeTag(zcu)) {27835 const dest_is_npv = switch (dest_ty.classify(zcu)) {
27861 .noreturn, .@"opaque" => false,27836 .no_possible_value => true,
27862 else => 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,
27863 };27843 };
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
27872 if (!opts.report_err) return error.NotCoercible;27845 if (!opts.report_err) return error.NotCoercible;
2787327846
27874 if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .noreturn) {27847 if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .noreturn) {
...@@ -27890,8 +27863,8 @@ fn coerceExtra(...@@ -27890,8 +27863,8 @@ fn coerceExtra(
27890 const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty);27863 const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty);
27891 errdefer msg.destroy(sema.gpa);27864 errdefer msg.destroy(sema.gpa);
2789227865
27893 if (!can_coerce_to) {27866 if (dest_is_npv) {
27894 try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)});27867 try sema.errNote(inst_src, msg, "cannot coerce to uninstantiable type '{f}'", .{dest_ty.fmt(pt)});
27895 }27868 }
2789627869
27897 // E!T to T27870 // E!T to T
...@@ -29099,6 +29072,13 @@ fn storePtr2(...@@ -29099,6 +29072,13 @@ fn storePtr2(
29099 };29072 };
29100 const maybe_operand_val = sema.resolveValue(operand);29073 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
29102 const runtime_src = rs: {29082 const runtime_src = rs: {
29103 const ptr_val = try sema.resolveDefinedValue(block, ptr_src, ptr) orelse break :rs ptr_src;29083 const ptr_val = try sema.resolveDefinedValue(block, ptr_src, ptr) orelse break :rs ptr_src;
29104 if (!sema.isComptimeMutablePtr(ptr_val)) break :rs ptr_src;29084 if (!sema.isComptimeMutablePtr(ptr_val)) break :rs ptr_src;
...@@ -29106,16 +29086,9 @@ fn storePtr2(...@@ -29106,16 +29086,9 @@ fn storePtr2(
29106 return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);29086 return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
29107 };29087 };
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
29116 // We're performing the store at runtime; as such, we need to make sure the pointee type29089 // We're performing the store at runtime; as such, we need to make sure the pointee type
29117 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.29090 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.
29118 if (elem_ty.comptimeOnly(zcu)) {29091 if (comptime_only) {
29119 return sema.failWithOwnedErrorMsg(block, msg: {29092 return sema.failWithOwnedErrorMsg(block, msg: {
29120 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});29093 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
29121 errdefer msg.destroy(sema.gpa);29094 errdefer msg.destroy(sema.gpa);
...@@ -29477,7 +29450,7 @@ fn coerceEnumToUnion(...@@ -29477,7 +29450,7 @@ fn coerceEnumToUnion(
29477 const enum_ty: Type = .fromInterned(union_obj.enum_tag_type);29450 const enum_ty: Type = .fromInterned(union_obj.enum_tag_type);
29478 const enum_obj = ip.loadEnumType(enum_ty.toIntern());29451 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: {
29481 const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);29454 const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);
29482 errdefer msg.destroy(sema.gpa);29455 errdefer msg.destroy(sema.gpa);
29483 try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});29456 try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});
...@@ -29495,31 +29468,35 @@ fn coerceEnumToUnion(...@@ -29495,31 +29468,35 @@ fn coerceEnumToUnion(
2949529468
29496 const field_name = enum_obj.field_names.get(ip)[field_index];29469 const field_name = enum_obj.field_names.get(ip)[field_index];
29497 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);29470 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
29498 if (field_ty.zigTypeTag(zcu) == .noreturn) {29471 switch (field_ty.classify(zcu)) {
29499 const msg = msg: {29472 .one_possible_value => return .fromValue(try pt.unionValue(
29500 const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});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)});
29501 errdefer msg.destroy(sema.gpa);29480 errdefer msg.destroy(sema.gpa);
29502 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{29481 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
29503 field_name.fmt(ip),29482 field_name.fmt(ip),
29504 });29483 });
29505 try sema.addDeclaredHereNote(msg, union_ty);29484 try sema.addDeclaredHereNote(msg, union_ty);
29506 break :msg msg;29485 break :msg msg;
29507 };29486 }),
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);
2951629487
29517 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)});29488 else => return sema.failWithOwnedErrorMsg(block, msg: {
29518 try sema.addDeclaredHereNote(msg, union_ty);29489 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
29519 break :msg msg;29490 inst_ty.fmt(pt), union_ty.fmt(pt),
29520 });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 }
29523 }29500 }
2952429501
29525 try sema.requireRuntimeBlock(block, inst_src, null);29502 try sema.requireRuntimeBlock(block, inst_src, null);
...@@ -29536,32 +29513,14 @@ fn coerceEnumToUnion(...@@ -29536,32 +29513,14 @@ fn coerceEnumToUnion(
29536 return sema.failWithOwnedErrorMsg(block, msg);29513 return sema.failWithOwnedErrorMsg(block, msg);
29537 }29514 }
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.
29563 if (union_ty.unionHasAllZeroBitFieldTypes(zcu)) {29516 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 }
29565 }29524 }
2956629525
29567 const msg = msg: {29526 const msg = msg: {
...@@ -29575,9 +29534,15 @@ fn coerceEnumToUnion(...@@ -29575,9 +29534,15 @@ fn coerceEnumToUnion(
29575 for (0..union_obj.field_types.len) |field_index| {29534 for (0..union_obj.field_types.len) |field_index| {
29576 const field_name = enum_obj.field_names.get(ip)[field_index];29535 const field_name = enum_obj.field_names.get(ip)[field_index];
29577 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);29536 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
29578 if (try field_ty.onePossibleValue(pt) != null) continue;29537 const ty_description: []const u8 = switch (field_ty.classify(zcu)) {
29579 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{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}'", .{
29580 field_name.fmt(ip),29544 field_name.fmt(ip),
29545 ty_description,
29581 field_ty.fmt(pt),29546 field_ty.fmt(pt),
29582 });29547 });
29583 }29548 }
...@@ -30345,7 +30310,7 @@ fn resolveIsNonErrFromType(...@@ -30345,7 +30310,7 @@ fn resolveIsNonErrFromType(
30345 assert(ot == .error_union);30310 assert(ot == .error_union);
3034630311
30347 const payload_ty = operand_ty.errorUnionPayload(zcu);30312 const payload_ty = operand_ty.errorUnionPayload(zcu);
30348 if (payload_ty.zigTypeTag(zcu) == .noreturn) {30313 if (payload_ty.classify(zcu) == .no_possible_value) {
30349 return .false;30314 return .false;
30350 }30315 }
3035130316
...@@ -31348,24 +31313,28 @@ fn wrapErrorUnionSet(...@@ -31348,24 +31313,28 @@ fn wrapErrorUnionSet(
31348 }31313 }
31349}31314}
3135031315
31351fn unionToTag(31316/// Returns the enum tag value for the active tag of a tagged union value.
31352 sema: *Sema,31317///
31353 block: *Block,31318/// Asserts that the type of `un` is a tagged union type.
31354 enum_ty: Type,31319fn unionToTag(sema: *Sema, block: *Block, un: Air.Inst.Ref) !Air.Inst.Ref {
31355 un: Air.Inst.Ref,
31356 un_src: LazySrcLoc,
31357) !Air.Inst.Ref {
31358 const pt = sema.pt;31320 const pt = sema.pt;
31359 const zcu = pt.zcu;31321 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);
31361 if (sema.resolveValue(un)) |un_val| {31325 if (sema.resolveValue(un)) |un_val| {
31362 const tag_val = un_val.unionTag(zcu).?;31326 return .fromValue(un_val.unionTag(zcu).?);
31363 if (tag_val.isUndef(zcu))31327 }
31364 return try pt.undefRef(enum_ty);31328 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
31365 return Air.internedToRef(tag_val.toIntern());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)));
31366 }31336 }
31367 try sema.requireRuntimeBlock(block, un_src, null);31337 return block.addTyOp(.get_union_tag, enum_tag_ty, un);
31368 return block.addTyOp(.get_union_tag, enum_ty, un);
31369}31338}
3137031339
31371const PeerResolveStrategy = enum {31340const PeerResolveStrategy = enum {
...@@ -33491,15 +33460,6 @@ fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {...@@ -33491,15 +33460,6 @@ fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
33491 return sema.typeOf(ref).isNoReturn(sema.pt.zcu);33460 return sema.typeOf(ref).isNoReturn(sema.pt.zcu);
33492}33461}
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
33503pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {33463pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
33504 const pt = sema.pt;33464 const pt = sema.pt;
33505 if (!pt.zcu.comp.config.incremental) return;33465 if (!pt.zcu.comp.config.incremental) return;
...@@ -33744,7 +33704,6 @@ fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {...@@ -33744,7 +33704,6 @@ fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
33744 const zcu = pt.zcu;33704 const zcu = pt.zcu;
33745 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {33705 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
33746 .undef => true,33706 .undef => true,
33747 .simple_value => |v| v == .undefined,
33748 .slice => {33707 .slice => {
33749 // If the slice contents are runtime-known, reification will fail later on with a33708 // If the slice contents are runtime-known, reification will fail later on with a
33750 // specific error message.33709 // specific error message.
...@@ -33898,7 +33857,6 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR...@@ -33898,7 +33857,6 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
33898const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;33857const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
33899const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;33858const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
3390033859
33901// MLUGG TODO: decide how to do the namespacing here
33902pub const type_resolution = @import("Sema/type_resolution.zig");33860pub const type_resolution = @import("Sema/type_resolution.zig");
33903pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;33861pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
33904pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;33862pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;
...@@ -34313,7 +34271,7 @@ fn zirUnionDecl(...@@ -34313,7 +34271,7 @@ fn zirUnionDecl(
34313 .fields_len = @intCast(union_decl.field_names.len),34271 .fields_len = @intCast(union_decl.field_names.len),
34314 .layout = union_decl.kind.layout(),34272 .layout = union_decl.kind.layout(),
34315 .any_field_aligns = union_decl.field_align_body_lens != null,34273 .any_field_aligns = union_decl.field_align_body_lens != null,
34316 .runtime_tag = switch (union_decl.kind) {34274 .tag_usage = switch (union_decl.kind) {
34317 .auto => if (block.wantSafeTypes()) .safety else .none,34275 .auto => if (block.wantSafeTypes()) .safety else .none,
3431834276
34319 .tagged_explicit,34277 .tagged_explicit,
src/Sema/bitcast.zig-2
...@@ -267,7 +267,6 @@ const UnpackValueBits = struct {...@@ -267,7 +267,6 @@ const UnpackValueBits = struct {
267 .int,267 .int,
268 .enum_tag,268 .enum_tag,
269 .simple_value,269 .simple_value,
270 .empty_enum_value,
271 .float,270 .float,
272 .ptr,271 .ptr,
273 .opt,272 .opt,
...@@ -453,7 +452,6 @@ const UnpackValueBits = struct {...@@ -453,7 +452,6 @@ const UnpackValueBits = struct {
453 // The only values here with runtime bits are `true` and `false.452 // The only values here with runtime bits are `true` and `false.
454 // These are both 1 bit, so will never need truncating.453 // These are both 1 bit, so will never need truncating.
455 .simple_value => unreachable,454 .simple_value => unreachable,
456 .empty_enum_value => unreachable, // zero-bit
457 else => unreachable, // zero-bit or not primitives455 else => unreachable, // zero-bit or not primitives
458 }456 }
459 }457 }
src/Sema/type_resolution.zig+79-43
...@@ -72,7 +72,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo...@@ -72,7 +72,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo
72 .error_union,72 .error_union,
73 .enum_literal,73 .enum_literal,
74 .enum_tag,74 .enum_tag,
75 .empty_enum_value,
76 .float,75 .float,
77 .ptr,76 .ptr,
78 .slice,77 .slice,
...@@ -249,10 +248,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -249,10 +248,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
249 // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).248 // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).
250249
251 var any_comptime_fields = false;250 var any_comptime_fields = false;
252 var comptime_only = false;
253 var one_possible_value = true;
254 var has_runtime_bits = false;
255 var struct_align: Alignment = .@"1";251 var struct_align: Alignment = .@"1";
252 var has_no_possible_value = false;
253 var has_runtime_state = false;
254 var has_comptime_state = false;
256 // Unlike `struct_obj.field_aligns`, these are not `.none`.255 // Unlike `struct_obj.field_aligns`, these are not `.none`.
257 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);256 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
258 for (resolved_field_aligns, 0..) |*align_out, field_idx| {257 for (resolved_field_aligns, 0..) |*align_out, field_idx| {
...@@ -264,22 +263,37 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -264,22 +263,37 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
264 }263 }
265 break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);264 break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
266 };265 };
267 if (!struct_obj.field_is_comptime_bits.get(ip, field_idx)) {266 align_out.* = field_align;
268 // Non-`comptime` fields contribute to the struct's layout.267 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
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 {
277 assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs268 assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs
278 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order269 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
279 any_comptime_fields = true;270 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 },
280 }286 }
281 align_out.* = field_align;
282 }287 }
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
283 if (struct_obj.layout == .auto) {297 if (struct_obj.layout == .auto) {
284 const runtime_order = struct_obj.field_runtime_order.get(ip);298 const runtime_order = struct_obj.field_runtime_order.get(ip);
285 // This logic does not reorder fields; it only moves the omitted ones to the end so that logic299 // 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 {...@@ -327,21 +341,21 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
327 struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below341 struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below
328 cur_offset = offset + field_ty.abiSize(zcu);342 cur_offset = offset + field_ty.abiSize(zcu);
329 }343 }
330 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(344 const struct_size: u32 = switch (class) {
331 &block,345 .no_possible_value => 0,
332 struct_ty.srcLoc(zcu),346 else => std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
333 "struct layout requires size {d}, this compiler implementation supports up to {d}",347 &block,
334 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },348 struct_ty.srcLoc(zcu),
335 );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 };
336 ip.resolveStructLayout(353 ip.resolveStructLayout(
337 io,354 io,
338 struct_ty.toIntern(),355 struct_ty.toIntern(),
339 struct_size,356 struct_size,
340 struct_align,357 struct_align,
341 false, // MLUGG TODO XXX NPV358 class,
342 one_possible_value,
343 comptime_only,
344 has_runtime_bits,
345 );359 );
346360
347 if (any_comptime_fields and !struct_obj.is_reified) {361 if (any_comptime_fields and !struct_obj.is_reified) {
...@@ -758,9 +772,8 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -758,9 +772,8 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
758 // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).772 // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).
759 var payload_align: Alignment = .@"1";773 var payload_align: Alignment = .@"1";
760 var payload_size: u64 = 0;774 var payload_size: u64 = 0;
761 var comptime_only = false;775 var possible_tags: u32 = 0;
762 var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu);776 var payload_has_comptime_state = false;
763 var possible_values: enum { none, one, many } = .none;
764 for (0..union_obj.field_types.len) |field_idx| {777 for (0..union_obj.field_types.len) |field_idx| {
765 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);778 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
766 const field_align: Alignment = a: {779 const field_align: Alignment = a: {
...@@ -772,21 +785,41 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -772,21 +785,41 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
772 };785 };
773 payload_align = payload_align.maxStrict(field_align);786 payload_align = payload_align.maxStrict(field_align);
774 payload_size = @max(payload_size, field_ty.abiSize(zcu));787 payload_size = @max(payload_size, field_ty.abiSize(zcu));
775 if (field_ty.comptimeOnly(zcu)) comptime_only = true;788
776 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;789 switch (field_ty.classify(zcu)) {
777 if (!field_ty.isNoReturn(zcu)) {790 .no_possible_value => {}, // uninstantiable field has no effect
778 if (try field_ty.onePossibleValue(pt) != null) {791 .one_possible_value, .runtime => {
779 possible_values = .many; // this field alone has many possible values792 possible_tags += 1;
780 } else switch (possible_values) {793 },
781 .none => possible_values = .one, // there were none, now there is this field's OPV794 .partially_comptime, .fully_comptime => {
782 .one => possible_values = .many, // there was one, now there are two795 possible_tags += 1;
783 .many => {},796 payload_has_comptime_state = true;
784 }797 },
785 }798 }
786 }799 }
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
788 const size: u64, const padding: u64, const alignment: Alignment = layout: {821 const size: u64, const padding: u64, const alignment: Alignment = layout: {
789 if (union_obj.runtime_tag == .none) {822 if (!has_runtime_tag) {
790 break :layout .{ payload_align.forward(payload_size), 0, payload_align };823 break :layout .{ payload_align.forward(payload_size), 0, payload_align };
791 }824 }
792 const tag_align = enum_tag_ty.abiAlignment(zcu);825 const tag_align = enum_tag_ty.abiAlignment(zcu);
...@@ -800,6 +833,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -800,6 +833,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
800 break :layout .{ size, size - unpadded_size, alignment };833 break :layout .{ size, size - unpadded_size, alignment };
801 };834 };
802835
836 if (class == .no_possible_value or class == .one_possible_value) {
837 assert(size == 0);
838 assert(padding == 0);
839 }
840
803 const casted_size = std.math.cast(u32, size) orelse return sema.fail(841 const casted_size = std.math.cast(u32, size) orelse return sema.fail(
804 &block,842 &block,
805 union_ty.srcLoc(zcu),843 union_ty.srcLoc(zcu),
...@@ -810,13 +848,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -810,13 +848,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
810 io,848 io,
811 union_ty.toIntern(),849 union_ty.toIntern(),
812 enum_tag_ty.toIntern(),850 enum_tag_ty.toIntern(),
851 class,
852 has_runtime_tag,
813 casted_size,853 casted_size,
814 @intCast(padding), // okay because padding is no greater than size854 @intCast(padding), // okay because padding is no greater than size
815 alignment,855 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,
820 );856 );
821}857}
822fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError {858fn 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 {...@@ -23,6 +23,240 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId {
23 return zcu.intern_pool.zigTypeTag(ty.toIntern());23 return zcu.intern_pool.zigTypeTag(ty.toIntern());
24}24}
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
26/// Asserts the type is resolved.260/// Asserts the type is resolved.
27pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {261pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
28 return switch (ty.zigTypeTag(zcu)) {262 return switch (ty.zigTypeTag(zcu)) {
...@@ -400,7 +634,6 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari...@@ -400,7 +634,6 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
400 .error_union,634 .error_union,
401 .enum_literal,635 .enum_literal,
402 .enum_tag,636 .enum_tag,
403 .empty_enum_value,
404 .float,637 .float,
405 .ptr,638 .ptr,
406 .slice,639 .slice,
...@@ -438,116 +671,9 @@ pub fn toValue(self: Type) Value {...@@ -438,116 +671,9 @@ pub fn toValue(self: Type) Value {
438/// - an enum with an explicit tag type has the ABI size of the integer tag type,671/// - an enum with an explicit tag type has the ABI size of the integer tag type,
439/// making it one-possible-value only if the integer tag type has 0 bits.672/// making it one-possible-value only if the integer tag type has 0 bits.
440pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {673pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
441 ty.assertHasLayout(zcu);674 return switch (ty.classify(zcu)) {
442 const ip = &zcu.intern_pool;675 .no_possible_value, .one_possible_value, .fully_comptime => false,
443 return switch (ip.indexToKey(ty.toIntern())) {676 .runtime, .partially_comptime => true,
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,
551 };677 };
552}678}
553679
...@@ -634,7 +760,6 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {...@@ -634,7 +760,6 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
634 .error_union,760 .error_union,
635 .enum_literal,761 .enum_literal,
636 .enum_tag,762 .enum_tag,
637 .empty_enum_value,
638 .float,763 .float,
639 .ptr,764 .ptr,
640 .slice,765 .slice,
...@@ -681,8 +806,12 @@ pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {...@@ -681,8 +806,12 @@ pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
681 }806 }
682}807}
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`.
684pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {813pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
685 return zcu.intern_pool.isNoReturn(ty.toIntern());814 return ty.classify(zcu) == .no_possible_value;
686}815}
687816
688/// Never returns `none`. Asserts that all necessary type resolution is already done.817/// 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 {...@@ -705,7 +834,10 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
705 };834 };
706}835}
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)`.
709pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {841pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
710 const ip = &zcu.intern_pool;842 const ip = &zcu.intern_pool;
711 const target = zcu.getTarget();843 const target = zcu.getTarget();
...@@ -842,7 +974,6 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -842,7 +974,6 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
842 .error_union,974 .error_union,
843 .enum_literal,975 .enum_literal,
844 .enum_tag,976 .enum_tag,
845 .empty_enum_value,
846 .float,977 .float,
847 .ptr,978 .ptr,
848 .slice,979 .slice,
...@@ -856,7 +987,11 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -856,7 +987,11 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
856 };987 };
857}988}
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.
860pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {995pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
861 const ip = &zcu.intern_pool;996 const ip = &zcu.intern_pool;
862 const target = zcu.getTarget();997 const target = zcu.getTarget();
...@@ -883,29 +1018,26 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -883,29 +1018,26 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
883 },1018 },
884 .opt_type => |child_ty_ip| {1019 .opt_type => |child_ty_ip| {
885 const child_ty: Type = .fromInterned(child_ty_ip);1020 const child_ty: Type = .fromInterned(child_ty_ip);
886 if (child_ty.isNoReturn(zcu)) return 0;1021 if (child_ty.classify(zcu) == .no_possible_value) return 0;
887 const child_size = child_ty.abiSize(zcu);1022 if (ty.optionalReprIsPayload(zcu)) return child_ty.abiSize(zcu);
888 if (ty.optionalReprIsPayload(zcu)) return child_size;
889 // Optional types are represented as a struct with the child type as the first1023 // Optional types are represented as a struct with the child type as the first
890 // field and a boolean as the second. Since the child type's abi alignment is1024 // field and a boolean as the second. Since the child type's abi alignment is
891 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal1025 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
892 // to the child type's ABI alignment.1026 // 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().?;
894 },1028 },
895 .error_set_type, .inferred_error_set_type => errorAbiSize(zcu),1029 .error_set_type, .inferred_error_set_type => errorAbiSize(zcu),
896 .error_union_type => |error_union| {1030 .error_union_type => |error_union| {
897 const payload_ty: Type = .fromInterned(error_union.payload_type);1031 const payload_ty: Type = .fromInterned(error_union.payload_type);
898 // This code needs to be kept in sync with the equivalent switch prong1032 switch (payload_ty.classify(zcu)) {
899 // in abiAlignmentInner.1033 .fully_comptime => return 0, // error set does not require runtime bits, see comment in `classify`
900 const code_size = errorAbiSize(zcu);1034 else => {},
901 const code_align = errorAbiAlignment(zcu);1035 }
902 const payload_size = payload_ty.abiSize(zcu);
903 const payload_align = payload_ty.abiAlignment(zcu);
904 // The layout will either be (code, payload, padding) or (payload, code, padding)1036 // The layout will either be (code, payload, padding) or (payload, code, padding)
905 // depending on which has larger alignment. So the overall size is just the code1037 // depending on which has larger alignment. So the overall size is just the code
906 // and payload sizes added and padded to the larger alignment.1038 // and payload sizes added and padded to the larger alignment.
907 const big_align = code_align.maxStrict(payload_align);1039 const big_align: Alignment = .maxStrict(errorAbiAlignment(zcu), payload_ty.abiAlignment(zcu));
908 return big_align.forward(payload_size + code_size);1040 return big_align.forward(errorAbiSize(zcu) + payload_ty.abiSize(zcu));
909 },1041 },
910 .func_type => 0,1042 .func_type => 0,
911 .simple_type => |t| switch (t) {1043 .simple_type => |t| switch (t) {
...@@ -946,7 +1078,12 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -946,7 +1078,12 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
946 .anyopaque => unreachable,1078 .anyopaque => unreachable,
947 .generic_poison => unreachable,1079 .generic_poison => unreachable,
948 },1080 },
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 },
950 .struct_type => {1087 .struct_type => {
951 const struct_obj = ip.loadStructType(ty.toIntern());1088 const struct_obj = ip.loadStructType(ty.toIntern());
952 switch (struct_obj.layout) {1089 switch (struct_obj.layout) {
...@@ -975,7 +1112,6 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -975,7 +1112,6 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
975 .error_union,1112 .error_union,
976 .enum_literal,1113 .enum_literal,
977 .enum_tag,1114 .enum_tag,
978 .empty_enum_value,
979 .float,1115 .float,
980 .ptr,1116 .ptr,
981 .slice,1117 .slice,
...@@ -1100,7 +1236,6 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1100,7 +1236,6 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
1100 .error_union,1236 .error_union,
1101 .enum_literal,1237 .enum_literal,
1102 .enum_tag,1238 .enum_tag,
1103 .empty_enum_value,
1104 .float,1239 .float,
1105 .ptr,1240 .ptr,
1106 .slice,1241 .slice,
...@@ -1327,8 +1462,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {...@@ -1327,8 +1462,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
1327 }1462 }
1328}1463}
13291464
1330/// Returns the tag type of a union, if the type is a union and it has a tag type.1465/// If `ty` is a tagged union, returns its tag type. Otherwise, returns `null`.
1331/// Otherwise, returns `null`.
1332pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {1466pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
1333 assertHasLayout(ty, zcu);1467 assertHasLayout(ty, zcu);
1334 const ip = &zcu.intern_pool;1468 const ip = &zcu.intern_pool;
...@@ -1337,33 +1471,28 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {...@@ -1337,33 +1471,28 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
1337 else => return null,1471 else => return null,
1338 }1472 }
1339 const union_obj = ip.loadUnionType(ty.toIntern());1473 const union_obj = ip.loadUnionType(ty.toIntern());
1340 return switch (union_obj.runtime_tag) {1474 return switch (union_obj.tag_usage) {
1341 .tagged => .fromInterned(union_obj.enum_tag_type),1475 .tagged => .fromInterned(union_obj.enum_tag_type),
1342 .none, .safety => null,1476 .none, .safety => null,
1343 };1477 };
1344}1478}
13451479
1346/// Same as `unionTagType` but includes safety tag.1480/// If the given union type contains a tag (including a safety tag) in its runtime layout, returns
1347/// Codegen should use this version.1481/// its enum tag type. Otherwise, returns null. Asserts that `ty` is a union type.
1348pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {1482///
1483/// In general, codegen logic should call this function instead of `unionTagType`.
1484pub fn unionTagTypeRuntime(ty: Type, zcu: *const Zcu) ?Type {
1349 assertHasLayout(ty, zcu);1485 assertHasLayout(ty, zcu);
1350 const ip = &zcu.intern_pool;1486 const union_type = zcu.intern_pool.loadUnionType(ty.toIntern());
1351 return switch (ip.indexToKey(ty.toIntern())) {1487 if (!union_type.has_runtime_tag) return null;
1352 .union_type => {1488 return .fromInterned(union_type.enum_tag_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 };
1359}1489}
13601490
1361/// Asserts the type is a union; returns the tag type, even if the tag will1491/// Asserts that `ty` is a union type, and returns its tag type, even if the tag will not be stored at runtime.
1362/// not be stored at runtime.
1363pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {1492pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
1364 assertHasLayout(ty, zcu);1493 assertHasLayout(ty, zcu);
1365 const union_obj = zcu.typeToUnion(ty).?;1494 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
1366 return Type.fromInterned(union_obj.enum_tag_type);1495 return .fromInterned(union_obj.enum_tag_type);
1367}1496}
13681497
1369pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {1498pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
...@@ -1573,12 +1702,12 @@ pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {...@@ -1573,12 +1702,12 @@ pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {
1573 };1702 };
1574}1703}
15751704
1576/// Returns true for integers, enums, error sets, and packed structs.1705/// Returns true for integers, enums, error sets, and packed structs/unions.
1577/// If this function returns true, then intInfo() can be called on the type.1706/// If this function returns true, then intInfo() can be called on the type.
1578pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool {1707pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool {
1579 return switch (ty.zigTypeTag(zcu)) {1708 return switch (ty.zigTypeTag(zcu)) {
1580 .int, .@"enum", .error_set => true,1709 .int, .@"enum", .error_set => true,
1581 .@"struct" => ty.containerLayout(zcu) == .@"packed",1710 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
1582 else => false,1711 else => false,
1583 };1712 };
1584}1713}
...@@ -1611,6 +1740,11 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -1611,6 +1740,11 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
1611 assert(struct_obj.layout == .@"packed");1740 assert(struct_obj.layout == .@"packed");
1612 ty = .fromInterned(struct_obj.packed_backing_int_type);1741 ty = .fromInterned(struct_obj.packed_backing_int_type);
1613 },1742 },
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 },
1614 .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type),1748 .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type),
1615 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),1749 .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 {...@@ -1629,7 +1763,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
1629 .func_type => unreachable,1763 .func_type => unreachable,
1630 .simple_type => unreachable, // handled via Index enum tag above1764 .simple_type => unreachable, // handled via Index enum tag above
16311765
1632 .union_type => unreachable,
1633 .opaque_type => unreachable,1766 .opaque_type => unreachable,
16341767
1635 // values, not types1768 // values, not types
...@@ -1643,7 +1776,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -1643,7 +1776,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
1643 .error_union,1776 .error_union,
1644 .enum_literal,1777 .enum_literal,
1645 .enum_tag,1778 .enum_tag,
1646 .empty_enum_value,
1647 .float,1779 .float,
1648 .ptr,1780 .ptr,
1649 .slice,1781 .slice,
...@@ -1772,240 +1904,23 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {...@@ -1772,240 +1904,23 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {
1772 };1904 };
1773}1905}
17741906
1775/// MLUGG TODO: deal with our friends structs and unions1907/// If the type's classification is `Class.one_possible_value` (see `classify`), returns the only
1776pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {1908/// possible value for the type. Otherwise, returns `null`.
1909pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
1777 const zcu = pt.zcu;1910 const zcu = pt.zcu;
1778 const comp = zcu.comp;1911 const comp = zcu.comp;
1779 const gpa = comp.gpa;1912 const gpa = comp.gpa;
1780 const ip = &zcu.intern_pool;1913 const ip = &zcu.intern_pool;
1781 assertHasLayout(starting_type, zcu);1914 assertHasLayout(ty, 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;
1992 return switch (ip.indexToKey(ty.toIntern())) {1915 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,
2000 .ptr_type,1916 .ptr_type,
1917 .error_union_type,
1918 .func_type,
2001 .anyframe_type,1919 .anyframe_type,
2002 .error_set_type,1920 .error_set_type,
2003 .inferred_error_set_type,1921 .inferred_error_set_type,
2004 .opaque_type,1922 .opaque_type,
2005 => false,1923 => null,
2006
2007 // These are function bodies, not function pointers.
2008 .func_type => true,
20091924
2010 .simple_type => |t| switch (t) {1925 .simple_type => |t| switch (t) {
2011 .f16,1926 .f16,
...@@ -2027,43 +1942,111 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {...@@ -2027,43 +1942,111 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2027 .c_longdouble,1942 .c_longdouble,
2028 .anyopaque,1943 .anyopaque,
2029 .bool,1944 .bool,
2030 .void,
2031 .anyerror,
2032 .adhoc_inferred_error_set,
2033 .noreturn,
2034 .generic_poison,
2035 => false,
2036
2037 .type,1945 .type,
1946 .anyerror,
2038 .comptime_int,1947 .comptime_int,
2039 .comptime_float,1948 .comptime_float,
1949 .enum_literal,
1950 .adhoc_inferred_error_set,
2040 .null,1951 .null,
2041 .undefined,1952 .undefined,
2042 .enum_literal,1953 .noreturn,
2043 => true,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);
2044 },1991 },
2045 .struct_type => {1992 .struct_type => {
2046 const struct_obj = ip.loadStructType(ty.toIntern());1993 const struct_obj = ip.loadStructType(ty.toIntern());
2047 return switch (struct_obj.layout) {1994 switch (struct_obj.layout) {
2048 .@"packed" => false,1995 .auto, .@"extern" => {},
2049 .auto, .@"extern" => struct_obj.comptime_only,1996 .@"packed" => {
2050 };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);
2051 },2018 },
2052 .union_type => {2019 .union_type => {
2053 const union_obj = ip.loadUnionType(ty.toIntern());2020 const union_obj = ip.loadUnionType(ty.toIntern());
2054 return switch (union_obj.layout) {2021 if (union_obj.layout == .@"packed") {
2055 .@"packed" => false,2022 const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
2056 .auto, .@"extern" => union_obj.comptime_only,2023 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
2057 };2024 return try pt.bitpackValue(ty, backing_val);
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;
2064 }2025 }
2065 return false;2026 // Type resolution already figured out whether there is an OPV, but if there is, it's
2066 },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
2068 // values, not types2051 // values, not types
2069 .undef,2052 .undef,
...@@ -2076,7 +2059,6 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {...@@ -2076,7 +2059,6 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2076 .error_union,2059 .error_union,
2077 .enum_literal,2060 .enum_literal,
2078 .enum_tag,2061 .enum_tag,
2079 .empty_enum_value,
2080 .float,2062 .float,
2081 .ptr,2063 .ptr,
2082 .slice,2064 .slice,
...@@ -2090,6 +2072,16 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {...@@ -2090,6 +2072,16 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2090 };2072 };
2091}2073}
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
2093pub fn isVector(ty: Type, zcu: *const Zcu) bool {2085pub fn isVector(ty: Type, zcu: *const Zcu) bool {
2094 return ty.zigTypeTag(zcu) == .vector;2086 return ty.zigTypeTag(zcu) == .vector;
2095}2087}
...@@ -2286,8 +2278,8 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu...@@ -2286,8 +2278,8 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu
2286 return enum_type.nameIndex(ip, field_name);2278 return enum_type.nameIndex(ip, field_name);
2287}2279}
22882280
2289/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or2281/// Asserts `ty` is an enum. `enum_tag` can either be the actual enum tag value
2290/// an integer which represents the enum value. Returns the field index in2282/// or an integer which represents the enum value. Returns the field index in
2291/// declaration order, or `null` if `enum_tag` does not match any field.2283/// declaration order, or `null` if `enum_tag` does not match any field.
2292pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {2284pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
2293 assertHasLayout(ty, zcu);2285 assertHasLayout(ty, zcu);
...@@ -2327,7 +2319,7 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {...@@ -2327,7 +2319,7 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
2327 }2319 }
2328}2320}
23292321
2330/// Returns the field type. Supports structs and unions.2322/// Returns the field type. Supports tuples, structs, and unions.
2331pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {2323pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
2332 const ip = &zcu.intern_pool;2324 const ip = &zcu.intern_pool;
2333 const types = switch (ip.indexToKey(ty.toIntern())) {2325 const types = switch (ip.indexToKey(ty.toIntern())) {
...@@ -2493,7 +2485,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {...@@ -2493,7 +2485,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
2493 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {2485 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
2494 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {2486 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {
2495 // comptime field2487 // comptime field
2496 if (i == index) return offset;2488 if (i == index) return 0;
2497 continue;2489 continue;
2498 }2490 }
24992491
...@@ -2509,8 +2501,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {...@@ -2509,8 +2501,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
25092501
2510 .union_type => {2502 .union_type => {
2511 const union_type = ip.loadUnionType(ty.toIntern());2503 const union_type = ip.loadUnionType(ty.toIntern());
2512 if (union_type.runtime_tag == .none)2504 if (!union_type.has_runtime_tag) return 0;
2513 return 0;
2514 const layout = Type.getUnionLayout(union_type, zcu);2505 const layout = Type.getUnionLayout(union_type, zcu);
2515 if (layout.tag_align.compare(.gte, layout.payload_align)) {2506 if (layout.tag_align.compare(.gte, layout.payload_align)) {
2516 // {Tag, Payload}2507 // {Tag, Payload}
...@@ -2746,7 +2737,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -2746,7 +2737,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
2746 }2737 }
2747 payload_align = payload_align.max(field_align);2738 payload_align = payload_align.max(field_align);
2748 }2739 }
2749 if (loaded_union.runtime_tag == .none or2740 if (!loaded_union.has_runtime_tag or
2750 !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu))2741 !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu))
2751 {2742 {
2752 return .{2743 return .{
...@@ -2872,11 +2863,19 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina...@@ -2872,11 +2863,19 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina
2872}2863}
28732864
2874/// Returns `true` if a value of this type is always `null`.2865/// 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`.
2876/// Returns `null` otherwise.2867/// Returns `null` otherwise.
2877pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {2868pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
2878 if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;2869 if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;
2879 if (ty.optionalChild(zcu).isNoReturn(zcu)) return true; // `?noreturn` is always null2870 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
2880 return null;2879 return null;
2881}2880}
28822881
...@@ -3096,7 +3095,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {...@@ -3096,7 +3095,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
3096 .error_union,3095 .error_union,
3097 .enum_literal,3096 .enum_literal,
3098 .enum_tag,3097 .enum_tag,
3099 .empty_enum_value,
3100 .float,3098 .float,
3101 .ptr,3099 .ptr,
3102 .slice,3100 .slice,
...@@ -3175,7 +3173,6 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn...@@ -3175,7 +3173,6 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
3175 .error_union,3173 .error_union,
3176 .enum_literal,3174 .enum_literal,
3177 .enum_tag,3175 .enum_tag,
3178 .empty_enum_value,
3179 .float,3176 .float,
3180 .ptr,3177 .ptr,
3181 .slice,3178 .slice,
src/Value.zig+3-4
...@@ -348,7 +348,7 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{...@@ -348,7 +348,7 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
348 } else {348 } else {
349 const backing_ty = try ty.externUnionBackingType(pt);349 const backing_ty = try ty.externUnionBackingType(pt);
350 const byte_count: usize = @intCast(backing_ty.abiSize(zcu));350 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]);
352 }352 }
353 },353 },
354 .@"packed" => {354 .@"packed" => {
...@@ -746,7 +746,6 @@ pub fn compareScalar(...@@ -746,7 +746,6 @@ pub fn compareScalar(
746/// Returns `false` if the value or any vector element is undefined.746/// Returns `false` if the value or any vector element is undefined.
747///747///
748/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`748/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
749/// TODO MLUGG: lowkey wanna delete this
750pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {749pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {
751 return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {750 return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
752 .float => |float| switch (float.storage) {751 .float => |float| switch (float.storage) {
...@@ -919,7 +918,7 @@ pub fn unionTag(val: Value, zcu: *Zcu) ?Value {...@@ -919,7 +918,7 @@ pub fn unionTag(val: Value, zcu: *Zcu) ?Value {
919 };918 };
920}919}
921920
922pub fn unionValue(val: Value, zcu: *Zcu) Value {921pub fn unionPayload(val: Value, zcu: *Zcu) Value {
923 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {922 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
924 .un => |un| Value.fromInterned(un.val),923 .un => |un| Value.fromInterned(un.val),
925 else => unreachable,924 else => unreachable,
...@@ -2442,7 +2441,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe...@@ -2442,7 +2441,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
2442 inline else => |tag_comptime| @unionInit(2441 inline else => |tag_comptime| @unionInit(
2443 T,2442 T,
2444 @tagName(tag_comptime),2443 @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),
2446 ),2445 ),
2447 };2446 };
2448 },2447 },
src/Zcu/PerThread.zig+2-7
...@@ -3825,9 +3825,7 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca...@@ -3825,9 +3825,7 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca
38253825
3826pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {3826pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
3827 if (std.debug.runtime_safety) {3827 if (std.debug.runtime_safety) {
3828 if (try ty.onePossibleValue(pt)) |opv| {3828 assert(ty.classify(pt.zcu) != .one_possible_value);
3829 assert(opv.isUndef(pt.zcu));
3830 }
3831 }3829 }
3832 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));3830 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
3833}3831}
...@@ -3909,10 +3907,7 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind...@@ -3909,10 +3907,7 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind
3909 for (elems) |elem| {3907 for (elems) |elem| {
3910 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;3908 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;
3911 } else if (elems.len > 0) {3909 } else if (elems.len > 0) {
3912 // All undef, so return an undef struct. However, don't use `undefValue`, because its3910 return pt.undefValue(ty);
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() }));
3916 }3911 }
3917 return .fromInterned(try pt.intern(.{ .aggregate = .{3912 return .fromInterned(try pt.intern(.{ .aggregate = .{
3918 .ty = ty.toIntern(),3913 .ty = ty.toIntern(),
src/codegen.zig-2
...@@ -343,7 +343,6 @@ pub fn generateSymbol(...@@ -343,7 +343,6 @@ pub fn generateSymbol(
343343
344 .undef => unreachable, // handled above344 .undef => unreachable, // handled above
345 .simple_value => |simple_value| switch (simple_value) {345 .simple_value => |simple_value| switch (simple_value) {
346 .undefined => unreachable, // non-runtime value
347 .void => unreachable, // non-runtime value346 .void => unreachable, // non-runtime value
348 .null => unreachable, // non-runtime value347 .null => unreachable, // non-runtime value
349 .@"unreachable" => unreachable, // non-runtime value348 .@"unreachable" => unreachable, // non-runtime value
...@@ -357,7 +356,6 @@ pub fn generateSymbol(...@@ -357,7 +356,6 @@ pub fn generateSymbol(
357 .@"extern",356 .@"extern",
358 .func,357 .func,
359 .enum_literal,358 .enum_literal,
360 .empty_enum_value,
361 => unreachable, // non-runtime values359 => unreachable, // non-runtime values
362 .int => {360 .int => {
363 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;361 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 {...@@ -10588,7 +10588,6 @@ pub const Value = struct {
10588 .error_union,10588 .error_union,
10589 .enum_literal,10589 .enum_literal,
10590 .enum_tag,10590 .enum_tag,
10591 .empty_enum_value,
10592 .float,10591 .float,
10593 .ptr,10592 .ptr,
10594 .slice,10593 .slice,
...@@ -10711,7 +10710,6 @@ pub const Value = struct {...@@ -10711,7 +10710,6 @@ pub const Value = struct {
10711 .inferred_error_set_type,10710 .inferred_error_set_type,
1071210711
10713 .enum_literal,10712 .enum_literal,
10714 .empty_enum_value,
10715 .memoized_call,10713 .memoized_call,
10716 => unreachable, // not a runtime value10714 => unreachable, // not a runtime value
10717 .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {10715 .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {
...@@ -10732,7 +10730,7 @@ pub const Value = struct {...@@ -10732,7 +10730,7 @@ pub const Value = struct {
10732 } }),10730 } }),
10733 }),10731 }),
10734 .simple_value => |simple_value| switch (simple_value) {10732 .simple_value => |simple_value| switch (simple_value) {
10735 .undefined, .void, .null, .@"unreachable" => unreachable,10733 .void, .null, .@"unreachable" => unreachable,
10736 .true => continue :constant_key .{ .int = .{10734 .true => continue :constant_key .{ .int = .{
10737 .ty = .bool_type,10735 .ty = .bool_type,
10738 .storage = .{ .u64 = 1 },10736 .storage = .{ .u64 = 1 },
...@@ -11408,7 +11406,6 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e...@@ -11408,7 +11406,6 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e
11408 .inferred_error_set_type,11406 .inferred_error_set_type,
1140911407
11410 .enum_literal,11408 .enum_literal,
11411 .empty_enum_value,
11412 .memoized_call,11409 .memoized_call,
11413 => unreachable, // not a runtime value11410 => unreachable, // not a runtime value
11414 .err => |err| {11411 .err => |err| {
...@@ -12085,7 +12082,7 @@ pub const CallAbiIterator = struct {...@@ -12085,7 +12082,7 @@ pub const CallAbiIterator = struct {
12085 const zcu = isel.pt.zcu;12082 const zcu = isel.pt.zcu;
12086 const ip = &zcu.intern_pool;12083 const ip = &zcu.intern_pool;
1208712084
12088 if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;12085 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
12089 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);12086 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
12090 const wip_vi = isel.initValue(ty);12087 const wip_vi = isel.initValue(ty);
12091 type_key: switch (ip.indexToKey(ty.toIntern())) {12088 type_key: switch (ip.indexToKey(ty.toIntern())) {
...@@ -12326,7 +12323,6 @@ pub const CallAbiIterator = struct {...@@ -12326,7 +12323,6 @@ pub const CallAbiIterator = struct {
12326 .error_union,12323 .error_union,
12327 .enum_literal,12324 .enum_literal,
12328 .enum_tag,12325 .enum_tag,
12329 .empty_enum_value,
12330 .float,12326 .float,
12331 .ptr,12327 .ptr,
12332 .slice,12328 .slice,
src/codegen/c.zig+11-17
...@@ -1040,7 +1040,6 @@ pub const DeclGen = struct {...@@ -1040,7 +1040,6 @@ pub const DeclGen = struct {
1040 .undef => unreachable, // handled above1040 .undef => unreachable, // handled above
1041 .simple_value => |simple_value| switch (simple_value) {1041 .simple_value => |simple_value| switch (simple_value) {
1042 // non-runtime values1042 // non-runtime values
1043 .undefined => unreachable,
1044 .void => unreachable,1043 .void => unreachable,
1045 .null => unreachable,1044 .null => unreachable,
1046 .@"unreachable" => unreachable,1045 .@"unreachable" => unreachable,
...@@ -1052,7 +1051,6 @@ pub const DeclGen = struct {...@@ -1052,7 +1051,6 @@ pub const DeclGen = struct {
1052 .@"extern",1051 .@"extern",
1053 .func,1052 .func,
1054 .enum_literal,1053 .enum_literal,
1055 .empty_enum_value,
1056 => unreachable, // non-runtime values1054 => unreachable, // non-runtime values
1057 .int => |int| switch (int.storage) {1055 .int => |int| switch (int.storage) {
1058 .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),1056 .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),
...@@ -1756,7 +1754,6 @@ pub const DeclGen = struct {...@@ -1756,7 +1754,6 @@ pub const DeclGen = struct {
1756 .error_union,1754 .error_union,
1757 .enum_literal,1755 .enum_literal,
1758 .enum_tag,1756 .enum_tag,
1759 .empty_enum_value,
1760 .float,1757 .float,
1761 .ptr,1758 .ptr,
1762 .slice,1759 .slice,
...@@ -5848,7 +5845,7 @@ fn fieldLocation(...@@ -5848,7 +5845,7 @@ fn fieldLocation(
5848 .auto, .@"extern" => {5845 .auto, .@"extern" => {
5849 const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);5846 const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
5850 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))5847 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))
5852 .{ .field = .{ .identifier = "payload" } }5849 .{ .field = .{ .identifier = "payload" } }
5853 else5850 else
5854 .begin;5851 .begin;
...@@ -7022,7 +7019,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7022,7 +7019,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
7022 const union_ty = f.typeOf(bin_op.lhs).childType(zcu);7019 const union_ty = f.typeOf(bin_op.lhs).childType(zcu);
7023 const layout = union_ty.unionGetLayout(zcu);7020 const layout = union_ty.unionGetLayout(zcu);
7024 if (layout.tag_size == 0) return .none;7021 if (layout.tag_size == 0) return .none;
7025 const tag_ty = union_ty.unionTagTypeSafety(zcu).?;7022 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
70267023
7027 const w = &f.object.code.writer;7024 const w = &f.object.code.writer;
7028 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));7025 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 {...@@ -7462,18 +7459,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
74627459
7463 const local = try f.allocLocal(inst, union_ty);7460 const local = try f.allocLocal(inst, union_ty);
74647461
7465 const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {7462 const field: CValue = if (union_ty.unionTagTypeRuntime(zcu)) |tag_ty| field: {
7466 const layout = union_ty.unionGetLayout(zcu);7463 assert(union_ty.unionGetLayout(zcu).tag_size != 0);
7467 if (layout.tag_size != 0) {7464 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7468 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;7465 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
7469 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);7466 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
74707467 try f.writeCValueMember(w, local, .{ .identifier = "tag" });
7471 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));7468 try a.assign(f, w);
7472 try f.writeCValueMember(w, local, .{ .identifier = "tag" });7469 try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
7473 try a.assign(f, w);7470 try a.end(f, w);
7474 try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
7475 try a.end(f, w);
7476 }
7477 break :field .{ .payload_identifier = field_name.toSlice(ip) };7471 break :field .{ .payload_identifier = field_name.toSlice(ip) };
7478 } else .{ .identifier = field_name.toSlice(ip) };7472 } else .{ .identifier = field_name.toSlice(ip) };
74797473
src/codegen/c/Type.zig+6-8
...@@ -2479,7 +2479,7 @@ pub const Pool = struct {...@@ -2479,7 +2479,7 @@ pub const Pool = struct {
2479 return pool.fromFields(allocator, .@"struct", &fields, kind);2479 return pool.fromFields(allocator, .@"struct", &fields, kind);
2480 },2480 },
2481 .opt_type => |payload_type| {2481 .opt_type => |payload_type| {
2482 if (ip.isNoReturn(payload_type)) return .void;2482 if (Type.fromInterned(payload_type).isNoReturn(zcu)) return .void;
2483 const payload_ctype = try pool.fromType(2483 const payload_ctype = try pool.fromType(
2484 allocator,2484 allocator,
2485 scratch,2485 scratch,
...@@ -2521,7 +2521,7 @@ pub const Pool = struct {...@@ -2521,7 +2521,7 @@ pub const Pool = struct {
2521 .signedness = .unsigned,2521 .signedness = .unsigned,
2522 .bits = error_set_bits,2522 .bits = error_set_bits,
2523 }, mod, kind);2523 }, 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;
2525 const payload_type = Type.fromInterned(error_union_info.payload_type);2525 const payload_type = Type.fromInterned(error_union_info.payload_type);
2526 const payload_ctype = try pool.fromType(2526 const payload_ctype = try pool.fromType(
2527 allocator,2527 allocator,
...@@ -2684,9 +2684,8 @@ pub const Pool = struct {...@@ -2684,9 +2684,8 @@ pub const Pool = struct {
2684 const loaded_union = ip.loadUnionType(ip_index);2684 const loaded_union = ip.loadUnionType(ip_index);
2685 switch (loaded_union.flagsUnordered(ip).layout) {2685 switch (loaded_union.flagsUnordered(ip).layout) {
2686 .auto, .@"extern" => {2686 .auto, .@"extern" => {
2687 const has_tag = loaded_union.hasTag(ip);
2688 const fwd_decl = try pool.getFwdDecl(allocator, .{2687 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",
2690 .name = .{ .index = ip_index },2689 .name = .{ .index = ip_index },
2691 });2690 });
2692 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))2691 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
...@@ -2707,7 +2706,7 @@ pub const Pool = struct {...@@ -2707,7 +2706,7 @@ pub const Pool = struct {
2707 const field_type = Type.fromInterned(2706 const field_type = Type.fromInterned(
2708 loaded_union.field_types.get(ip)[field_index],2707 loaded_union.field_types.get(ip)[field_index],
2709 );2708 );
2710 if (ip.isNoReturn(field_type.toIntern())) continue;2709 if (field_type.isNoReturn(zcu)) continue;
2711 const field_ctype = try pool.fromType(2710 const field_ctype = try pool.fromType(
2712 allocator,2711 allocator,
2713 scratch,2712 scratch,
...@@ -2738,7 +2737,7 @@ pub const Pool = struct {...@@ -2738,7 +2737,7 @@ pub const Pool = struct {
2738 scratch.items.len - scratch_top,2737 scratch.items.len - scratch_top,
2739 @typeInfo(Field).@"struct".fields.len,2738 @typeInfo(Field).@"struct".fields.len,
2740 ));2739 ));
2741 if (!has_tag) {2740 if (!loaded_union.has_runtime_tag) {
2742 if (fields_len == 0) return .void;2741 if (fields_len == 0) return .void;
2743 try pool.ensureUnusedCapacity(allocator, 1);2742 try pool.ensureUnusedCapacity(allocator, 1);
2744 const extra_index = try pool.addHashedExtra(2743 const extra_index = try pool.addHashedExtra(
...@@ -2836,7 +2835,7 @@ pub const Pool = struct {...@@ -2836,7 +2835,7 @@ pub const Pool = struct {
2836 var hasher = Hasher.init;2835 var hasher = Hasher.init;
2837 const return_type = Type.fromInterned(func_info.return_type);2836 const return_type = Type.fromInterned(func_info.return_type);
2838 const return_ctype: CType =2837 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(
2840 allocator,2839 allocator,
2841 scratch,2840 scratch,
2842 return_type,2841 return_type,
...@@ -2889,7 +2888,6 @@ pub const Pool = struct {...@@ -2889,7 +2888,6 @@ pub const Pool = struct {
2889 .error_union,2888 .error_union,
2890 .enum_literal,2889 .enum_literal,
2891 .enum_tag,2890 .enum_tag,
2892 .empty_enum_value,
2893 .float,2891 .float,
2894 .ptr,2892 .ptr,
2895 .slice,2893 .slice,
src/codegen/llvm.zig-3
...@@ -3516,7 +3516,6 @@ pub const Object = struct {...@@ -3516,7 +3516,6 @@ pub const Object = struct {
3516 .error_union,3516 .error_union,
3517 .enum_literal,3517 .enum_literal,
3518 .enum_tag,3518 .enum_tag,
3519 .empty_enum_value,
3520 .float,3519 .float,
3521 .ptr,3520 .ptr,
3522 .slice,3521 .slice,
...@@ -3722,7 +3721,6 @@ pub const Object = struct {...@@ -3722,7 +3721,6 @@ pub const Object = struct {
37223721
3723 .undef => unreachable, // handled above3722 .undef => unreachable, // handled above
3724 .simple_value => |simple_value| switch (simple_value) {3723 .simple_value => |simple_value| switch (simple_value) {
3725 .undefined => unreachable, // non-runtime value
3726 .void => unreachable, // non-runtime value3724 .void => unreachable, // non-runtime value
3727 .null => unreachable, // non-runtime value3725 .null => unreachable, // non-runtime value
3728 .@"unreachable" => unreachable, // non-runtime value3726 .@"unreachable" => unreachable, // non-runtime value
...@@ -3732,7 +3730,6 @@ pub const Object = struct {...@@ -3732,7 +3730,6 @@ pub const Object = struct {
3732 },3730 },
3733 .variable,3731 .variable,
3734 .enum_literal,3732 .enum_literal,
3735 .empty_enum_value,
3736 => unreachable, // non-runtime values3733 => unreachable, // non-runtime values
3737 .@"extern" => |@"extern"| {3734 .@"extern" => |@"extern"| {
3738 const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav);3735 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 {...@@ -814,11 +814,9 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
814 .@"extern",814 .@"extern",
815 .func,815 .func,
816 .enum_literal,816 .enum_literal,
817 .empty_enum_value,
818 => unreachable, // non-runtime values817 => unreachable, // non-runtime values
819818
820 .simple_value => |simple_value| switch (simple_value) {819 .simple_value => |simple_value| switch (simple_value) {
821 .undefined,
822 .void,820 .void,
823 .null,821 .null,
824 .@"unreachable",822 .@"unreachable",
...@@ -4482,7 +4480,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4482,7 +4480,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
44824480
4483 if (layout.tag_size == 0) return;4481 if (layout.tag_size == 0) return;
44844482
4485 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;4483 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
4486 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);4484 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
4487 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));4485 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 {...@@ -4508,7 +4506,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4508 const union_handle = try cg.resolve(ty_op.operand);4506 const union_handle = try cg.resolve(ty_op.operand);
4509 if (!layout.has_payload) return union_handle;4507 if (!layout.has_payload) return union_handle;
45104508
4511 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;4509 const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
4512 return try cg.extractField(tag_ty, union_handle, layout.tag_index);4510 return try cg.extractField(tag_ty, union_handle, layout.tag_index);
4513}4511}
45144512
src/codegen/wasm/CodeGen.zig+2-10
...@@ -1244,7 +1244,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {...@@ -1244,7 +1244,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {
1244 if (any_returns and cg.air.instructions.len > 0) {1244 if (any_returns and cg.air.instructions.len > 0) {
1245 const inst: Air.Inst.Index = @enumFromInt(cg.air.instructions.len - 1);1245 const inst: Air.Inst.Index = @enumFromInt(cg.air.instructions.len - 1);
1246 const last_inst_ty = cg.typeOfIndex(inst);1246 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)) {
1248 try cg.addTag(.@"unreachable");1248 try cg.addTag(.@"unreachable");
1249 }1249 }
1250 }1250 }
...@@ -2201,9 +2201,6 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2201,9 +2201,6 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2201 const result_value = result_value: {2201 const result_value = result_value: {
2202 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {2202 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
2203 break :result_value .none;2203 break :result_value .none;
2204 } else if (ret_ty.isNoReturn(zcu)) {
2205 try cg.addTag(.@"unreachable");
2206 break :result_value .none;
2207 } else if (first_param_sret) {2204 } else if (first_param_sret) {
2208 break :result_value sret;2205 break :result_value sret;
2209 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_mvp) {2206 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_mvp) {
...@@ -3158,7 +3155,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3158,7 +3155,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
31583155
3159 .undef => unreachable, // handled above3156 .undef => unreachable, // handled above
3160 .simple_value => |simple_value| switch (simple_value) {3157 .simple_value => |simple_value| switch (simple_value) {
3161 .undefined,
3162 .void,3158 .void,
3163 .null,3159 .null,
3164 .@"unreachable",3160 .@"unreachable",
...@@ -3173,7 +3169,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3173,7 +3169,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3173 .@"extern",3169 .@"extern",
3174 .func,3170 .func,
3175 .enum_literal,3171 .enum_literal,
3176 .empty_enum_value,
3177 => unreachable, // non-runtime values3172 => unreachable, // non-runtime values
3178 .int => {3173 .int => {
3179 const int_info = ty.intInfo(zcu);3174 const int_info = ty.intInfo(zcu);
...@@ -5340,7 +5335,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5340,7 +5335,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5340 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];5335 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
53415336
5342 const tag_int = blk: {5337 const tag_int = blk: {
5343 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);5338 const tag_ty = union_ty.unionTagTypeRuntime(zcu).?;
5344 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;5339 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
5345 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);5340 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
5346 break :blk try cg.lowerConstant(tag_val, tag_ty);5341 break :blk try cg.lowerConstant(tag_val, tag_ty);
...@@ -7109,9 +7104,6 @@ fn callIntrinsic(...@@ -7109,9 +7104,6 @@ fn callIntrinsic(
71097104
7110 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {7105 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
7111 return .none;7106 return .none;
7112 } else if (return_type.isNoReturn(zcu)) {
7113 try cg.addTag(.@"unreachable");
7114 return .none;
7115 } else if (want_sret_param) {7107 } else if (want_sret_param) {
7116 return sret;7108 return sret;
7117 } else {7109 } else {
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -171467,7 +171467,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -171467,7 +171467,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
171467 const union_layout = union_ty.unionGetLayout(zcu);171467 const union_layout = union_ty.unionGetLayout(zcu);
171468 if (union_layout.tag_size > 0) {171468 if (union_layout.tag_size > 0) {
171469 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(171469 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
171470 union_ty.unionTagTypeSafety(zcu).?,171470 union_ty.unionTagTypeRuntime(zcu).?,
171471 union_init.field_index,171471 union_init.field_index,
171472 ));171472 ));
171473 try res.write(&tag_temp, .{171473 try res.write(&tag_temp, .{
src/link/Dwarf.zig+19-22
...@@ -1603,7 +1603,7 @@ pub const WipNav = struct {...@@ -1603,7 +1603,7 @@ pub const WipNav = struct {
1603 const zcu = pt.zcu;1603 const zcu = pt.zcu;
1604 const ty = val.typeOf(zcu);1604 const ty = val.typeOf(zcu);
1605 const has_runtime_bits = ty.hasRuntimeBits(zcu);1605 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);
1607 try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {1607 try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
1608 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,1608 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
1609 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,1609 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
...@@ -2108,7 +2108,7 @@ pub const WipNav = struct {...@@ -2108,7 +2108,7 @@ pub const WipNav = struct {
2108 const zcu = wip_nav.pt.zcu;2108 const zcu = wip_nav.pt.zcu;
2109 const ip = &zcu.intern_pool;2109 const ip = &zcu.intern_pool;
2110 const ty = value.typeOf(zcu);2110 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));
2112 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());2112 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
2113 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {2113 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
2114 else => unreachable,2114 else => unreachable,
...@@ -2705,7 +2705,7 @@ fn initWipNavInner(...@@ -2705,7 +2705,7 @@ fn initWipNavInner(
2705 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));2705 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2706 if (maybe_func_type) |func_type| {2706 if (maybe_func_type) |func_type| {
2707 try wip_nav.infoAddrSym(sym_index, 0);2707 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)));
2709 if (func_type.param_types.len > 0 or func_type.is_var_args) {2709 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2710 for (func_type.param_types.get(ip)) |param_type| {2710 for (func_type.param_types.get(ip)) |param_type| {
2711 try wip_nav.abbrevCode(.extern_param);2711 try wip_nav.abbrevCode(.extern_param);
...@@ -2733,7 +2733,7 @@ fn initWipNavInner(...@@ -2733,7 +2733,7 @@ fn initWipNavInner(
2733 try wip_nav.strp(@"extern".name.toSlice(ip));2733 try wip_nav.strp(@"extern".name.toSlice(ip));
2734 try wip_nav.refType(.fromInterned(func_type.return_type));2734 try wip_nav.refType(.fromInterned(func_type.return_type));
2735 try wip_nav.infoAddrSym(sym_index, 0);2735 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)));
2737 if (func_type.param_types.len > 0 or func_type.is_var_args) {2737 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2738 for (func_type.param_types.get(ip)) |param_type| {2738 for (func_type.param_types.get(ip)) |param_type| {
2739 try wip_nav.abbrevCode(.extern_param);2739 try wip_nav.abbrevCode(.extern_param);
...@@ -2818,7 +2818,7 @@ fn initWipNavInner(...@@ -2818,7 +2818,7 @@ fn initWipNavInner(
2818 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),2818 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2819 }.toByteUnits().?);2819 }.toByteUnits().?);
2820 try diw.writeByte(@intFromBool(decl.linkage != .normal));2820 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
2823 const dlw = &wip_nav.debug_line.writer;2823 const dlw = &wip_nav.debug_line.writer;
2824 try dlw.writeByte(DW.LNS.extended_op);2824 try dlw.writeByte(DW.LNS.extended_op);
...@@ -3172,7 +3172,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3172,7 +3172,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3172 .none => .{ false, false },3172 .none => .{ false, false },
3173 else => .{3173 else => .{
3174 field_type.hasRuntimeBits(zcu),3174 field_type.hasRuntimeBits(zcu),
3175 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,3175 field_type.comptimeOnly(zcu),
3176 },3176 },
3177 };3177 };
3178 try wip_nav.abbrevCode(if (is_comptime)3178 try wip_nav.abbrevCode(if (is_comptime)
...@@ -3294,7 +3294,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3294,7 +3294,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3294 try diw.writeUleb128(union_layout.abi_size);3294 try diw.writeUleb128(union_layout.abi_size);
3295 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);3295 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
3296 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);3296 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
3297 if (loaded_union.runtime_tag != .none) {3297 if (loaded_union.has_runtime_tag) {
3298 try wip_nav.abbrevCode(.tagged_union);3298 try wip_nav.abbrevCode(.tagged_union);
3299 try wip_nav.infoSectionOffset(3299 try wip_nav.infoSectionOffset(
3300 .debug_info,3300 .debug_info,
...@@ -3371,7 +3371,6 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3371,7 +3371,6 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3371 .error_union,3371 .error_union,
3372 .enum_literal,3372 .enum_literal,
3373 .enum_tag,3373 .enum_tag,
3374 .empty_enum_value,
3375 .float,3374 .float,
3376 .ptr,3375 .ptr,
3377 .slice,3376 .slice,
...@@ -3465,7 +3464,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3465,7 +3464,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3465 const diw = &wip_nav.debug_info.writer;3464 const diw = &wip_nav.debug_info.writer;
3466 const nav_ty = nav_val.typeOf(zcu);3465 const nav_ty = nav_val.typeOf(zcu);
3467 const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);3466 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);
3469 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{3468 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
3470 .decl = .decl_const_runtime_bits_comptime_state,3469 .decl = .decl_const_runtime_bits_comptime_state,
3471 .generic_decl = .generic_decl_const,3470 .generic_decl = .generic_decl_const,
...@@ -3845,7 +3844,7 @@ fn updateLazyType(...@@ -3845,7 +3844,7 @@ fn updateLazyType(
3845 .none => .{ false, false },3844 .none => .{ false, false },
3846 else => .{3845 else => .{
3847 field_type.hasRuntimeBits(zcu),3846 field_type.hasRuntimeBits(zcu),
3848 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,3847 field_type.comptimeOnly(zcu),
3849 },3848 },
3850 };3849 };
3851 try wip_nav.abbrevCode(if (has_comptime_state)3850 try wip_nav.abbrevCode(if (has_comptime_state)
...@@ -4008,7 +4007,6 @@ fn updateLazyType(...@@ -4008,7 +4007,6 @@ fn updateLazyType(
4008 .error_union,4007 .error_union,
4009 .enum_literal,4008 .enum_literal,
4010 .enum_tag,4009 .enum_tag,
4011 .empty_enum_value,
4012 .float,4010 .float,
4013 .ptr,4011 .ptr,
4014 .slice,4012 .slice,
...@@ -4128,7 +4126,7 @@ fn updateLazyValue(...@@ -4128,7 +4126,7 @@ fn updateLazyValue(
4128 .payload => |payload_val| {4126 .payload => |payload_val| {
4129 const payload_type: Type = .fromInterned(ip.typeOf(payload_val));4127 const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
4130 const has_runtime_bits = payload_type.hasRuntimeBits(zcu);4128 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);
4132 try wip_nav.abbrevCode(if (has_comptime_state)4130 try wip_nav.abbrevCode(if (has_comptime_state)
4133 .comptime_value_field_comptime_state4131 .comptime_value_field_comptime_state
4134 else if (has_runtime_bits)4132 else if (has_runtime_bits)
...@@ -4164,7 +4162,6 @@ fn updateLazyValue(...@@ -4164,7 +4162,6 @@ fn updateLazyValue(
4164 }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));4162 }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4165 try wip_nav.refType(.fromInterned(enum_tag.ty));4163 try wip_nav.refType(.fromInterned(enum_tag.ty));
4166 },4164 },
4167 .empty_enum_value => unreachable,
4168 .float => |float| {4165 .float => |float| {
4169 switch (float.storage) {4166 switch (float.storage) {
4170 .f16 => |f16_val| {4167 .f16 => |f16_val| {
...@@ -4209,7 +4206,7 @@ fn updateLazyValue(...@@ -4209,7 +4206,7 @@ fn updateLazyValue(
4209 .comptime_alloc, .comptime_field => unreachable,4206 .comptime_alloc, .comptime_field => unreachable,
4210 .uav => |uav| {4207 .uav => |uav| {
4211 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));4208 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) {
4213 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)4210 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4214 .aggregate_udata_comptime_value4211 .aggregate_udata_comptime_value
4215 else4212 else
...@@ -4337,7 +4334,7 @@ fn updateLazyValue(...@@ -4337,7 +4334,7 @@ fn updateLazyValue(
4337 }4334 }
4338 if (opt.val != .none) child_field: {4335 if (opt.val != .none) child_field: {
4339 const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);4336 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);
4341 try wip_nav.abbrevCode(if (has_comptime_state)4338 try wip_nav.abbrevCode(if (has_comptime_state)
4342 .comptime_value_field_comptime_state4339 .comptime_value_field_comptime_state
4343 else if (has_runtime_bits)4340 else if (has_runtime_bits)
...@@ -4363,7 +4360,7 @@ fn updateLazyValue(...@@ -4363,7 +4360,7 @@ fn updateLazyValue(
4363 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;4360 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;
4364 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);4361 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
4365 const has_runtime_bits = field_type.hasRuntimeBits(zcu);4362 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);
4367 try wip_nav.abbrevCode(if (has_comptime_state)4364 try wip_nav.abbrevCode(if (has_comptime_state)
4368 .comptime_value_field_comptime_state4365 .comptime_value_field_comptime_state
4369 else if (has_runtime_bits)4366 else if (has_runtime_bits)
...@@ -4386,7 +4383,7 @@ fn updateLazyValue(...@@ -4386,7 +4383,7 @@ fn updateLazyValue(
4386 if (tuple_type.values.get(ip)[field_index] != .none) continue;4383 if (tuple_type.values.get(ip)[field_index] != .none) continue;
4387 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);4384 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
4388 const has_runtime_bits = field_type.hasRuntimeBits(zcu);4385 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);
4390 try wip_nav.abbrevCode(if (has_comptime_state)4387 try wip_nav.abbrevCode(if (has_comptime_state)
4391 .comptime_value_field_comptime_state4388 .comptime_value_field_comptime_state
4392 else if (has_runtime_bits)4389 else if (has_runtime_bits)
...@@ -4411,7 +4408,7 @@ fn updateLazyValue(...@@ -4411,7 +4408,7 @@ fn updateLazyValue(
4411 inline .array_type, .vector_type => |sequence_type| {4408 inline .array_type, .vector_type => |sequence_type| {
4412 const child_type: Type = .fromInterned(sequence_type.child);4409 const child_type: Type = .fromInterned(sequence_type.child);
4413 const has_runtime_bits = child_type.hasRuntimeBits(zcu);4410 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);
4415 for (switch (aggregate.storage) {4412 for (switch (aggregate.storage) {
4416 .bytes => unreachable,4413 .bytes => unreachable,
4417 .elems => |elems| elems,4414 .elems => |elems| elems,
...@@ -4443,7 +4440,7 @@ fn updateLazyValue(...@@ -4443,7 +4440,7 @@ fn updateLazyValue(
4443 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);4440 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
4444 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];4441 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];
4445 const has_runtime_bits = field_ty.hasRuntimeBits(zcu);4442 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);
4447 try wip_nav.abbrevCode(if (has_comptime_state)4444 try wip_nav.abbrevCode(if (has_comptime_state)
4448 .comptime_value_field_comptime_state4445 .comptime_value_field_comptime_state
4449 else if (has_runtime_bits)4446 else if (has_runtime_bits)
...@@ -4540,7 +4537,7 @@ fn updateContainerTypeWriterError(...@@ -4540,7 +4537,7 @@ fn updateContainerTypeWriterError(
4540 .none => .{ false, false },4537 .none => .{ false, false },
4541 else => .{4538 else => .{
4542 field_type.hasRuntimeBits(zcu),4539 field_type.hasRuntimeBits(zcu),
4543 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,4540 field_type.comptimeOnly(zcu),
4544 },4541 },
4545 };4542 };
4546 try wip_nav.abbrevCode(if (is_comptime)4543 try wip_nav.abbrevCode(if (is_comptime)
...@@ -4647,7 +4644,7 @@ fn updateContainerTypeWriterError(...@@ -4647,7 +4644,7 @@ fn updateContainerTypeWriterError(
4647 .none => .{ false, false },4644 .none => .{ false, false },
4648 else => .{4645 else => .{
4649 field_type.hasRuntimeBits(zcu),4646 field_type.hasRuntimeBits(zcu),
4650 field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,4647 field_type.comptimeOnly(zcu),
4651 },4648 },
4652 };4649 };
4653 try wip_nav.abbrevCode(if (is_comptime)4650 try wip_nav.abbrevCode(if (is_comptime)
...@@ -4724,7 +4721,7 @@ fn updateContainerTypeWriterError(...@@ -4724,7 +4721,7 @@ fn updateContainerTypeWriterError(
4724 try diw.writeUleb128(union_layout.abi_size);4721 try diw.writeUleb128(union_layout.abi_size);
4725 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);4722 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4726 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);4723 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
4727 if (loaded_union.runtime_tag != .none) {4724 if (loaded_union.has_runtime_tag) {
4728 try wip_nav.abbrevCode(.tagged_union);4725 try wip_nav.abbrevCode(.tagged_union);
4729 try wip_nav.infoSectionOffset(4726 try wip_nav.infoSectionOffset(
4730 .debug_info,4727 .debug_info,
src/print_value.zig-2
...@@ -73,7 +73,6 @@ pub fn print(...@@ -73,7 +73,6 @@ pub fn print(
73 .simple_value => |simple_value| switch (simple_value) {73 .simple_value => |simple_value| switch (simple_value) {
74 .void => try writer.writeAll("{}"),74 .void => try writer.writeAll("{}"),
7575
76 .undefined,
77 .null,76 .null,
78 .true,77 .true,
79 .false,78 .false,
...@@ -111,7 +110,6 @@ pub fn print(...@@ -111,7 +110,6 @@ pub fn print(
111 try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema);110 try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema);
112 try writer.writeAll(")");111 try writer.writeAll(")");
113 },112 },
114 .empty_enum_value => try writer.writeAll("(empty enum value)"),
115 .float => |float| switch (float.storage) {113 .float => |float| switch (float.storage) {
116 inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}),114 inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}),
117 },115 },