| author | |
| committer | |
| log | 187fef209f73336163337474dc02f46c7c89ac3a |
| tree | 93e71de23bb4fed48ad868c7da5f0eddda323be9 |
| parent | b19074d252e7eb833b653263acd20e64a7fe26ff |
| signature |
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( |
| 999 | 999 | ||
| 1000 | // If the block is noreturn, block deaths not only aren't useful, they're impossible to | 1000 | // 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 sets | 1003 | // 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 { |
| 465 | 465 | ||
| 466 | for (block_liveness.deaths) |death| try self.verifyDeath(inst, death); | 466 | for (block_liveness.deaths) |death| try self.verifyDeath(inst, death); |
| 467 | 467 | ||
| 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; |
| 17 | const Zir = std.zig.Zir; | 17 | const Zir = std.zig.Zir; |
| 18 | 18 | ||
| 19 | const Zcu = @import("Zcu.zig"); | 19 | const Zcu = @import("Zcu.zig"); |
| 20 | const TypeClass = @import("Type.zig").Class; | ||
| 20 | 21 | ||
| 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. |
| 22 | locals: []Local, | 23 | locals: []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, |
| 3295 | 3287 | ||
| 3296 | .undef => |x| x, | 3288 | .undef => |x| x, |
| 3297 | .empty_enum_value => |x| x, | ||
| 3298 | 3289 | ||
| 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, |
| 3365 | 3352 | ||
| ... | @@ -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, |
| 3549 | 3538 | ||
| 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 | } }, |
| 4820 | 4799 | ||
| 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, |
| 5684 | 5663 | ||
| 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, |
| 5697 | 5667 | ||
| 5698 | want_layout: bool, | 5668 | want_layout: bool, |
| 5699 | want_defaults: bool, | 5669 | want_defaults: bool, |
| 5700 | 5670 | ||
| 5701 | _: u14 = 0, | 5671 | _: u15 = 0, |
| 5702 | }; | 5672 | }; |
| 5703 | }; | 5673 | }; |
| 5704 | 5674 | ||
| ... | @@ -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" }, |
| 5779 | 5749 | ||
| 5780 | any_field_aligns: bool, | 5750 | any_field_aligns: bool, |
| 5781 | runtime_tag: LoadedUnionType.RuntimeTag, | 5751 | tag_usage: LoadedUnionType.TagUsage, |
| 5782 | 5752 | ||
| 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 avoid | 5754 | 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, |
| 5795 | 5758 | ||
| ... | @@ -5970,8 +5933,6 @@ pub const SimpleType = enum(u32) { | ... | @@ -5970,8 +5933,6 @@ pub const SimpleType = enum(u32) { |
| 5970 | }; | 5933 | }; |
| 5971 | 5934 | ||
| 5972 | pub const SimpleValue = enum(u32) { | 5935 | pub 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 | }, |
| 7018 | 6979 | ||
| 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 | }, |
| 7916 | 7872 | ||
| 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 | } |
| 12009 | 11950 | ||
| 12010 | pub 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 | |||
| 12024 | pub fn isUndef(ip: *const InternPool, val: Index) bool { | 11951 | pub 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); |
| 12832 | 12756 | ||
| ... | @@ -12840,10 +12764,7 @@ pub fn resolveStructLayout( | ... | @@ -12840,10 +12764,7 @@ pub fn resolveStructLayout( |
| 12840 | 12764 | ||
| 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 | } |
| 12849 | 12770 | ||
| ... | @@ -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); |
| 12868 | 12787 | ||
| ... | @@ -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 | } |
| 12887 | 12804 |
src/Sema.zig+195-237| ... | @@ -178,8 +178,11 @@ const ComptimeAlloc = struct { | ... | @@ -178,8 +178,11 @@ const ComptimeAlloc = struct { |
| 178 | fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex { | 178 | fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex { |
| 179 | const pt = sema.pt; | 179 | const pt = sema.pt; |
| 180 | 180 | ||
| 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 | } | ||
| 183 | 186 | ||
| 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 | } | ||
| 2000 | 1997 | ||
| 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 value | 2010 | 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 has | 2011 | assert(last_inst_ty.classify(zcu) == .no_possible_value); |
| 2011 | // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates | 2012 | 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 | } | ||
| 2019 | 2019 | ||
| 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 failure | 2287 | .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); |
| 4647 | 4648 | ||
| 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 | }; | ||
| 4652 | 4658 | ||
| 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 or | 4879 | 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 | } |
| 6674 | 6680 | ||
| 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 should | 6682 | // 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( |
| 6928 | 6934 | ||
| 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 here | 6938 | return arg.*; // terminate analysis here |
| 6933 | } | 6939 | } |
| 6934 | 6940 | ||
| ... | @@ -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 | } |
| 7185 | 7191 | ||
| 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 | } |
| 8000 | 8006 | ||
| 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 }; |
| 10246 | 10251 | ||
| 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 | else | 10254 | else |
| 10250 | new_val; | 10255 | new_val; |
| 10251 | 10256 | ||
| ... | @@ -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 | } |
| 12153 | 12157 | ||
| 12154 | fn analyzeSwitchPayloadCapture( | 12158 | fn 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); |
| 15391 | 15395 | ||
| 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 | } |
| 15396 | 15403 | ||
| 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)}), | ||
| 15944 | 15948 | ||
| 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, | ||
| 15951 | 15952 | ||
| 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 | } |
| 15971 | 15961 | ||
| 15972 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 15962 | fn 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]); |
| 18633 | 18623 | ||
| 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); |
| 18638 | 18628 | ||
| 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); |
| 18649 | 18639 | ||
| 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 | } |
| 18653 | 18649 | ||
| 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 | } |
| 18689 | 18682 | ||
| ... | @@ -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 | } |
| 19460 | 19453 | ||
| ... | @@ -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()); |
| 22609 | 22602 | ||
| 22610 | // special case zero bit types | 22603 | // 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 | } |
| 22614 | 22607 | ||
| ... | @@ -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 TODO | 25512 | 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).?); |
| 26479 | 26473 | ||
| 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); |
| 26484 | 26478 | ||
| 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 | } |
| 26535 | 26528 | ||
| 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, but | 26534 | // 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" store | 26539 | 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); |
| 26582 | 26575 | ||
| 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 | } |
| 26621 | 26600 | ||
| 26622 | if (union_obj.layout == .auto and block.wantSafety() and | 26601 | 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 | } |
| 26630 | 26606 | ||
| 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 type | 27747 | // 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 | } |
| 27859 | 27834 | ||
| 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 | }; |
| 27864 | 27844 | ||
| 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; |
| 27873 | 27846 | ||
| 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); |
| 27892 | 27865 | ||
| 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 | } |
| 27896 | 27869 | ||
| 27897 | // E!T to T | 27870 | // 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); |
| 29101 | 29074 | ||
| 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 | }; |
| 29108 | 29088 | ||
| 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 type | 29089 | // 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()); |
| 29479 | 29452 | ||
| 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( |
| 29495 | 29468 | ||
| 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); | ||
| 29516 | 29487 | ||
| 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); | ||
| 29521 | 29494 | ||
| 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 | } |
| 29524 | 29501 | ||
| 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 | } |
| 29538 | 29515 | ||
| 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 | } |
| 29566 | 29525 | ||
| 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); |
| 30346 | 30311 | ||
| 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 | } |
| 30351 | 30316 | ||
| ... | @@ -31348,24 +31313,28 @@ fn wrapErrorUnionSet( | ... | @@ -31348,24 +31313,28 @@ fn wrapErrorUnionSet( |
| 31348 | } | 31313 | } |
| 31349 | } | 31314 | } |
| 31350 | 31315 | ||
| 31351 | fn 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, | 31319 | fn 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 | } |
| 31370 | 31339 | ||
| 31371 | const PeerResolveStrategy = enum { | 31340 | const 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 | } |
| 33493 | 33462 | ||
| 33494 | /// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type. | ||
| 33495 | fn 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 | |||
| 33503 | pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { | 33463 | pub 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 a | 33708 | // 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 |
| 33898 | const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr; | 33857 | const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr; |
| 33899 | const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult; | 33858 | const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult; |
| 33900 | 33859 | ||
| 33901 | // MLUGG TODO: decide how to do the namespacing here | ||
| 33902 | pub const type_resolution = @import("Sema/type_resolution.zig"); | 33860 | pub const type_resolution = @import("Sema/type_resolution.zig"); |
| 33903 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; | 33861 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; |
| 33904 | pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved; | 33862 | pub 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, |
| 34318 | 34276 | ||
| 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 primitives | 455 | 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). |
| 250 | 249 | ||
| 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 structs | 268 | 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 order | 269 | 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 logic | 299 | // 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 below | 341 | 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 NPV | 358 | class, |
| 342 | one_possible_value, | ||
| 343 | comptime_only, | ||
| 344 | has_runtime_bits, | ||
| 345 | ); | 359 | ); |
| 346 | 360 | ||
| 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 values | 792 | possible_tags += 1; |
| 780 | } else switch (possible_values) { | 793 | }, |
| 781 | .none => possible_values = .one, // there were none, now there is this field's OPV | 794 | .partially_comptime, .fully_comptime => { |
| 782 | .one => possible_values = .many, // there was one, now there are two | 795 | possible_tags += 1; |
| 783 | .many => {}, | 796 | payload_has_comptime_state = true; |
| 784 | } | 797 | }, |
| 785 | } | 798 | } |
| 786 | } | 799 | } |
| 787 | 800 | ||
| 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 | }; |
| 802 | 835 | ||
| 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 size | 854 | @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 | } |
| 822 | fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError { | 858 | fn 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 | } |
| 25 | 25 | ||
| 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) | ||
| 31 | pub 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. | ||
| 115 | pub 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. |
| 27 | pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { | 261 | pub 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. |
| 440 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | 673 | pub 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 | } |
| 553 | 679 | ||
| ... | @@ -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 | } |
| 683 | 808 | ||
| 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`. | ||
| 684 | pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool { | 813 | pub 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 | } |
| 687 | 816 | ||
| 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 | } |
| 707 | 836 | ||
| 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)`. | ||
| 709 | pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | 841 | pub 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 | } |
| 858 | 989 | ||
| 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. | ||
| 860 | pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { | 995 | pub 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 first | 1023 | // 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 is | 1024 | // 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 equal | 1025 | // 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 prong | 1032 | 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 code | 1037 | // 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 | } |
| 1329 | 1464 | ||
| 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`. | ||
| 1332 | pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { | 1466 | pub 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 | } |
| 1345 | 1479 | ||
| 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. |
| 1348 | pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { | 1482 | /// |
| 1483 | /// In general, codegen logic should call this function instead of `unionTagType`. | ||
| 1484 | pub 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 | } |
| 1360 | 1490 | ||
| 1361 | /// Asserts the type is a union; returns the tag type, even if the tag will | 1491 | /// 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. | ||
| 1363 | pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type { | 1492 | pub 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 | } |
| 1368 | 1497 | ||
| 1369 | pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { | 1498 | pub 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 | } |
| 1575 | 1704 | ||
| 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. |
| 1578 | pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool { | 1707 | pub 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), |
| 1616 | 1750 | ||
| ... | @@ -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 above | 1764 | .simple_type => unreachable, // handled via Index enum tag above |
| 1631 | 1765 | ||
| 1632 | .union_type => unreachable, | ||
| 1633 | .opaque_type => unreachable, | 1766 | .opaque_type => unreachable, |
| 1634 | 1767 | ||
| 1635 | // values, not types | 1768 | // 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 | } |
| 1774 | 1906 | ||
| 1775 | /// MLUGG TODO: deal with our friends structs and unions | 1907 | /// If the type's classification is `Class.one_possible_value` (see `classify`), returns the only |
| 1776 | pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { | 1908 | /// possible value for the type. Otherwise, returns `null`. |
| 1909 | pub 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`. | ||
| 1990 | pub 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, | ||
| 2009 | 1924 | ||
| 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, | ||
| 2067 | 2050 | ||
| 2068 | // values, not types | 2051 | // 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 | } |
| 2092 | 2074 | ||
| 2075 | /// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`. | ||
| 2076 | pub 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 | |||
| 2093 | pub fn isVector(ty: Type, zcu: *const Zcu) bool { | 2085 | pub 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 | } |
| 2288 | 2280 | ||
| 2289 | /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or | 2281 | /// 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 in | 2282 | /// 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. |
| 2292 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { | 2284 | pub 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 | } |
| 2329 | 2321 | ||
| 2330 | /// Returns the field type. Supports structs and unions. | 2322 | /// Returns the field type. Supports tuples, structs, and unions. |
| 2331 | pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { | 2323 | pub 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 field | 2487 | // comptime field |
| 2496 | if (i == index) return offset; | 2488 | if (i == index) return 0; |
| 2497 | continue; | 2489 | continue; |
| 2498 | } | 2490 | } |
| 2499 | 2491 | ||
| ... | @@ -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 { |
| 2509 | 2501 | ||
| 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 or | 2740 | 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 | } |
| 2873 | 2864 | ||
| 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. |
| 2877 | pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { | 2868 | pub 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 null | 2870 | const payload_ty = ty.optionalChild(zcu); |
| 2871 | if (payload_ty.classify(zcu) == .no_possible_value) return true; // `?noreturn` etc | ||
| 2872 | |||
| 2873 | // Although it has runtime bits, `?error{}` is always null. MLUGG TODO: think for a bit... | ||
| 2874 | switch (zcu.intern_pool.indexToKey(payload_ty.toIntern())) { | ||
| 2875 | .error_set_type => |error_set| if (error_set.names.len == 0) return true, | ||
| 2876 | else => {}, | ||
| 2877 | } | ||
| 2878 | |||
| 2880 | return null; | 2879 | return null; |
| 2881 | } | 2880 | } |
| 2882 | 2881 | ||
| ... | @@ -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 | ||
| 750 | pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool { | 749 | pub 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 | } |
| 921 | 920 | ||
| 922 | pub fn unionValue(val: Value, zcu: *Zcu) Value { | 921 | pub 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 |
| 3825 | 3825 | ||
| 3826 | pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value { | 3826 | pub 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 its | 3910 | 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( |
| 343 | 343 | ||
| 344 | .undef => unreachable, // handled above | 344 | .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 value | 346 | .void => unreachable, // non-runtime value |
| 348 | .null => unreachable, // non-runtime value | 347 | .null => unreachable, // non-runtime value |
| 349 | .@"unreachable" => unreachable, // non-runtime value | 348 | .@"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 values | 359 | => 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, |
| 10712 | 10711 | ||
| 10713 | .enum_literal, | 10712 | .enum_literal, |
| 10714 | .empty_enum_value, | ||
| 10715 | .memoized_call, | 10713 | .memoized_call, |
| 10716 | => unreachable, // not a runtime value | 10714 | => 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, |
| 11409 | 11407 | ||
| 11410 | .enum_literal, | 11408 | .enum_literal, |
| 11411 | .empty_enum_value, | ||
| 11412 | .memoized_call, | 11409 | .memoized_call, |
| 11413 | => unreachable, // not a runtime value | 11410 | => 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; |
| 12087 | 12084 | ||
| 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 above | 1040 | .undef => unreachable, // handled above |
| 1041 | .simple_value => |simple_value| switch (simple_value) { | 1041 | .simple_value => |simple_value| switch (simple_value) { |
| 1042 | // non-runtime values | 1042 | // 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 values | 1054 | => 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 | else | 5850 | 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).?; |
| 7026 | 7023 | ||
| 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 { |
| 7462 | 7459 | ||
| 7463 | const local = try f.allocLocal(inst, union_ty); | 7460 | const local = try f.allocLocal(inst, union_ty); |
| 7464 | 7461 | ||
| 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)); |
| 7470 | 7467 | 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) }; |
| 7479 | 7473 |
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 { |
| 3722 | 3721 | ||
| 3723 | .undef => unreachable, // handled above | 3722 | .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 value | 3724 | .void => unreachable, // non-runtime value |
| 3727 | .null => unreachable, // non-runtime value | 3725 | .null => unreachable, // non-runtime value |
| 3728 | .@"unreachable" => unreachable, // non-runtime value | 3726 | .@"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 values | 3733 | => 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 values | 817 | => unreachable, // non-runtime values |
| 819 | 818 | ||
| 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 { |
| 4482 | 4480 | ||
| 4483 | if (layout.tag_size == 0) return; | 4481 | if (layout.tag_size == 0) return; |
| 4484 | 4482 | ||
| 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))); |
| 4488 | 4486 | ||
| ... | @@ -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; |
| 4510 | 4508 | ||
| 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 | } |
| 4514 | 4512 |
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 { |
| 3158 | 3155 | ||
| 3159 | .undef => unreachable, // handled above | 3156 | .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 values | 3172 | => 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]; |
| 5341 | 5336 | ||
| 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( |
| 7109 | 7104 | ||
| 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))); |
| 2822 | 2822 | ||
| 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_state | 4131 | .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_value | 4211 | .aggregate_udata_comptime_value |
| 4215 | else | 4212 | 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_state | 4339 | .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_state | 4365 | .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_state | 4388 | .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_state | 4445 | .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("{}"), |
| 75 | 75 | ||
| 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 | }, |