authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-10 17:21:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:30-07:00
log3ba099bfba9d3c38fe188010aa82fc589b1cabf6
treeef96b24aa9e6417e4cfa8c421c0a77ef9b75e22c
parent8297f28546b44afe49bec074733f05e03a3c0e62

stage2: move union types and values to InternPool


18 files changed, 688 insertions(+), 546 deletions(-)

src/InternPool.zig+148-25
...@@ -21,6 +21,13 @@ allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},...@@ -21,6 +21,13 @@ allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},
21/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.21/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
22structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},22structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
2323
24/// Union objects are stored in this data structure because:
25/// * They contain pointers such as the field maps.
26/// * They need to be mutated after creation.
27allocated_unions: std.SegmentedList(Module.Union, 0) = .{},
28/// When a Union object is freed from `allocated_unions`, it is pushed into this stack.
29unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
30
24const std = @import("std");31const std = @import("std");
25const Allocator = std.mem.Allocator;32const Allocator = std.mem.Allocator;
26const assert = std.debug.assert;33const assert = std.debug.assert;
...@@ -59,10 +66,7 @@ pub const Key = union(enum) {...@@ -59,10 +66,7 @@ pub const Key = union(enum) {
59 /// If `empty_struct_type` is handled separately, then this value may be66 /// If `empty_struct_type` is handled separately, then this value may be
60 /// safely assumed to never be `none`.67 /// safely assumed to never be `none`.
61 struct_type: StructType,68 struct_type: StructType,
62 union_type: struct {69 union_type: UnionType,
63 fields_len: u32,
64 // TODO move Module.Union data to InternPool
65 },
66 opaque_type: OpaqueType,70 opaque_type: OpaqueType,
6771
68 simple_value: SimpleValue,72 simple_value: SimpleValue,
...@@ -87,6 +91,8 @@ pub const Key = union(enum) {...@@ -87,6 +91,8 @@ pub const Key = union(enum) {
87 /// In the case of sentinel-terminated arrays, the sentinel value *is* stored,91 /// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
88 /// so the slice length will be one more than the type's array length.92 /// so the slice length will be one more than the type's array length.
89 aggregate: Aggregate,93 aggregate: Aggregate,
94 /// An instance of a union.
95 un: Union,
9096
91 pub const IntType = std.builtin.Type.Int;97 pub const IntType = std.builtin.Type.Int;
9298
...@@ -145,13 +151,27 @@ pub const Key = union(enum) {...@@ -145,13 +151,27 @@ pub const Key = union(enum) {
145 /// - index == .none151 /// - index == .none
146 /// * A struct which has fields as well as a namepace.152 /// * A struct which has fields as well as a namepace.
147 pub const StructType = struct {153 pub const StructType = struct {
148 /// This will be `none` only in the case of `@TypeOf(.{})`
149 /// (`Index.empty_struct_type`).
150 namespace: Module.Namespace.OptionalIndex,
151 /// The `none` tag is used to represent two cases:154 /// The `none` tag is used to represent two cases:
152 /// * `@TypeOf(.{})`, in which case `namespace` will also be `none`.155 /// * `@TypeOf(.{})`, in which case `namespace` will also be `none`.
153 /// * A struct with no fields, in which case `namespace` will be populated.156 /// * A struct with no fields, in which case `namespace` will be populated.
154 index: Module.Struct.OptionalIndex,157 index: Module.Struct.OptionalIndex,
158 /// This will be `none` only in the case of `@TypeOf(.{})`
159 /// (`Index.empty_struct_type`).
160 namespace: Module.Namespace.OptionalIndex,
161 };
162
163 pub const UnionType = struct {
164 index: Module.Union.Index,
165 runtime_tag: RuntimeTag,
166
167 pub const RuntimeTag = enum { none, safety, tagged };
168
169 pub fn hasTag(self: UnionType) bool {
170 return switch (self.runtime_tag) {
171 .none => false,
172 .tagged, .safety => true,
173 };
174 }
155 };175 };
156176
157 pub const Int = struct {177 pub const Int = struct {
...@@ -198,6 +218,15 @@ pub const Key = union(enum) {...@@ -198,6 +218,15 @@ pub const Key = union(enum) {
198 val: Index,218 val: Index,
199 };219 };
200220
221 pub const Union = struct {
222 /// This is the union type; not the field type.
223 ty: Index,
224 /// Indicates the active field.
225 tag: Index,
226 /// The value of the active field.
227 val: Index,
228 };
229
201 pub const Aggregate = struct {230 pub const Aggregate = struct {
202 ty: Index,231 ty: Index,
203 fields: []const Index,232 fields: []const Index,
...@@ -229,12 +258,10 @@ pub const Key = union(enum) {...@@ -229,12 +258,10 @@ pub const Key = union(enum) {
229 .extern_func,258 .extern_func,
230 .opt,259 .opt,
231 .struct_type,260 .struct_type,
261 .union_type,
262 .un,
232 => |info| std.hash.autoHash(hasher, info),263 => |info| std.hash.autoHash(hasher, info),
233264
234 .union_type => |union_type| {
235 _ = union_type;
236 @panic("TODO");
237 },
238 .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),265 .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),
239266
240 .int => |int| {267 .int => |int| {
...@@ -320,6 +347,14 @@ pub const Key = union(enum) {...@@ -320,6 +347,14 @@ pub const Key = union(enum) {
320 const b_info = b.struct_type;347 const b_info = b.struct_type;
321 return std.meta.eql(a_info, b_info);348 return std.meta.eql(a_info, b_info);
322 },349 },
350 .union_type => |a_info| {
351 const b_info = b.union_type;
352 return std.meta.eql(a_info, b_info);
353 },
354 .un => |a_info| {
355 const b_info = b.un;
356 return std.meta.eql(a_info, b_info);
357 },
323358
324 .ptr => |a_info| {359 .ptr => |a_info| {
325 const b_info = b.ptr;360 const b_info = b.ptr;
...@@ -371,14 +406,6 @@ pub const Key = union(enum) {...@@ -371,14 +406,6 @@ pub const Key = union(enum) {
371 @panic("TODO");406 @panic("TODO");
372 },407 },
373408
374 .union_type => |a_info| {
375 const b_info = b.union_type;
376
377 _ = a_info;
378 _ = b_info;
379 @panic("TODO");
380 },
381
382 .opaque_type => |a_info| {409 .opaque_type => |a_info| {
383 const b_info = b.opaque_type;410 const b_info = b.opaque_type;
384 return a_info.decl == b_info.decl;411 return a_info.decl == b_info.decl;
...@@ -411,6 +438,7 @@ pub const Key = union(enum) {...@@ -411,6 +438,7 @@ pub const Key = union(enum) {
411 .extern_func,438 .extern_func,
412 .enum_tag,439 .enum_tag,
413 .aggregate,440 .aggregate,
441 .un,
414 => |x| return x.ty,442 => |x| return x.ty,
415443
416 .simple_value => |s| switch (s) {444 .simple_value => |s| switch (s) {
...@@ -838,6 +866,15 @@ pub const Tag = enum(u8) {...@@ -838,6 +866,15 @@ pub const Tag = enum(u8) {
838 /// Module.Struct object allocated for it.866 /// Module.Struct object allocated for it.
839 /// data is Module.Namespace.Index.867 /// data is Module.Namespace.Index.
840 type_struct_ns,868 type_struct_ns,
869 /// A tagged union type.
870 /// `data` is `Module.Union.Index`.
871 type_union_tagged,
872 /// An untagged union type. It also has no safety tag.
873 /// `data` is `Module.Union.Index`.
874 type_union_untagged,
875 /// An untagged union type which has a safety tag.
876 /// `data` is `Module.Union.Index`.
877 type_union_safety,
841878
842 /// A value that can be represented with only an enum tag.879 /// A value that can be represented with only an enum tag.
843 /// data is SimpleValue enum value.880 /// data is SimpleValue enum value.
...@@ -908,6 +945,8 @@ pub const Tag = enum(u8) {...@@ -908,6 +945,8 @@ pub const Tag = enum(u8) {
908 /// * A struct which has 0 fields.945 /// * A struct which has 0 fields.
909 /// data is Index of the type, which is known to be zero bits at runtime.946 /// data is Index of the type, which is known to be zero bits at runtime.
910 only_possible_value,947 only_possible_value,
948 /// data is extra index to Key.Union.
949 union_value,
911};950};
912951
913/// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to952/// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to
...@@ -1141,6 +1180,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -1141,6 +1180,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
1141 ip.structs_free_list.deinit(gpa);1180 ip.structs_free_list.deinit(gpa);
1142 ip.allocated_structs.deinit(gpa);1181 ip.allocated_structs.deinit(gpa);
11431182
1183 ip.unions_free_list.deinit(gpa);
1184 ip.allocated_unions.deinit(gpa);
1185
1144 ip.* = undefined;1186 ip.* = undefined;
1145}1187}
11461188
...@@ -1233,6 +1275,19 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1233,6 +1275,19 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1233 .namespace = @intToEnum(Module.Namespace.Index, data).toOptional(),1275 .namespace = @intToEnum(Module.Namespace.Index, data).toOptional(),
1234 } },1276 } },
12351277
1278 .type_union_untagged => .{ .union_type = .{
1279 .index = @intToEnum(Module.Union.Index, data),
1280 .runtime_tag = .none,
1281 } },
1282 .type_union_tagged => .{ .union_type = .{
1283 .index = @intToEnum(Module.Union.Index, data),
1284 .runtime_tag = .tagged,
1285 } },
1286 .type_union_safety => .{ .union_type = .{
1287 .index = @intToEnum(Module.Union.Index, data),
1288 .runtime_tag = .safety,
1289 } },
1290
1236 .opt_null => .{ .opt = .{1291 .opt_null => .{ .opt = .{
1237 .ty = @intToEnum(Index, data),1292 .ty = @intToEnum(Index, data),
1238 .val = .none,1293 .val = .none,
...@@ -1303,6 +1358,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1303,6 +1358,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1303 else => unreachable,1358 else => unreachable,
1304 };1359 };
1305 },1360 },
1361 .union_value => .{ .un = ip.extraData(Key.Union, data) },
1306 };1362 };
1307}1363}
13081364
...@@ -1350,7 +1406,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1350,7 +1406,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1350 return @intToEnum(Index, ip.items.len - 1);1406 return @intToEnum(Index, ip.items.len - 1);
1351 }1407 }
13521408
1353 // TODO introduce more pointer encodings
1354 ip.items.appendAssumeCapacity(.{1409 ip.items.appendAssumeCapacity(.{
1355 .tag = .type_pointer,1410 .tag = .type_pointer,
1356 .data = try ip.addExtra(gpa, Pointer{1411 .data = try ip.addExtra(gpa, Pointer{
...@@ -1450,8 +1505,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1450,8 +1505,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1450 },1505 },
14511506
1452 .union_type => |union_type| {1507 .union_type => |union_type| {
1453 _ = union_type;1508 ip.items.appendAssumeCapacity(.{
1454 @panic("TODO");1509 .tag = switch (union_type.runtime_tag) {
1510 .none => .type_union_untagged,
1511 .safety => .type_union_safety,
1512 .tagged => .type_union_tagged,
1513 },
1514 .data = @enumToInt(union_type.index),
1515 });
1455 },1516 },
14561517
1457 .opaque_type => |opaque_type| {1518 .opaque_type => |opaque_type| {
...@@ -1642,6 +1703,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1642,6 +1703,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1642 }1703 }
1643 @panic("TODO");1704 @panic("TODO");
1644 },1705 },
1706
1707 .un => |un| {
1708 assert(un.ty != .none);
1709 assert(un.tag != .none);
1710 assert(un.val != .none);
1711 ip.items.appendAssumeCapacity(.{
1712 .tag = .union_value,
1713 .data = try ip.addExtra(gpa, un),
1714 });
1715 },
1645 }1716 }
1646 return @intToEnum(Index, ip.items.len - 1);1717 return @intToEnum(Index, ip.items.len - 1);
1647}1718}
...@@ -1923,6 +1994,17 @@ pub fn indexToStruct(ip: *InternPool, val: Index) Module.Struct.OptionalIndex {...@@ -1923,6 +1994,17 @@ pub fn indexToStruct(ip: *InternPool, val: Index) Module.Struct.OptionalIndex {
1923 return @intToEnum(Module.Struct.Index, datas[@enumToInt(val)]).toOptional();1994 return @intToEnum(Module.Struct.Index, datas[@enumToInt(val)]).toOptional();
1924}1995}
19251996
1997pub fn indexToUnion(ip: *InternPool, val: Index) Module.Union.OptionalIndex {
1998 const tags = ip.items.items(.tag);
1999 if (val == .none) return .none;
2000 switch (tags[@enumToInt(val)]) {
2001 .type_union_tagged, .type_union_untagged, .type_union_safety => {},
2002 else => return .none,
2003 }
2004 const datas = ip.items.items(.data);
2005 return @intToEnum(Module.Union.Index, datas[@enumToInt(val)]).toOptional();
2006}
2007
1926pub fn isOptionalType(ip: InternPool, ty: Index) bool {2008pub fn isOptionalType(ip: InternPool, ty: Index) bool {
1927 const tags = ip.items.items(.tag);2009 const tags = ip.items.items(.tag);
1928 if (ty == .none) return false;2010 if (ty == .none) return false;
...@@ -1937,15 +2019,22 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -1937,15 +2019,22 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
1937 const items_size = (1 + 4) * ip.items.len;2019 const items_size = (1 + 4) * ip.items.len;
1938 const extra_size = 4 * ip.extra.items.len;2020 const extra_size = 4 * ip.extra.items.len;
1939 const limbs_size = 8 * ip.limbs.items.len;2021 const limbs_size = 8 * ip.limbs.items.len;
2022 const structs_size = ip.allocated_structs.len *
2023 (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));
2024 const unions_size = ip.allocated_unions.len *
2025 (@sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));
19402026
1941 // TODO: map overhead size is not taken into account2027 // TODO: map overhead size is not taken into account
1942 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size;2028 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size +
2029 structs_size + unions_size;
19432030
1944 std.debug.print(2031 std.debug.print(
1945 \\InternPool size: {d} bytes2032 \\InternPool size: {d} bytes
1946 \\ {d} items: {d} bytes2033 \\ {d} items: {d} bytes
1947 \\ {d} extra: {d} bytes2034 \\ {d} extra: {d} bytes
1948 \\ {d} limbs: {d} bytes2035 \\ {d} limbs: {d} bytes
2036 \\ {d} structs: {d} bytes
2037 \\ {d} unions: {d} bytes
1949 \\2038 \\
1950 , .{2039 , .{
1951 total_size,2040 total_size,
...@@ -1955,6 +2044,10 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -1955,6 +2044,10 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
1955 extra_size,2044 extra_size,
1956 ip.limbs.items.len,2045 ip.limbs.items.len,
1957 limbs_size,2046 limbs_size,
2047 ip.allocated_structs.len,
2048 structs_size,
2049 ip.allocated_unions.len,
2050 unions_size,
1958 });2051 });
19592052
1960 const tags = ip.items.items(.tag);2053 const tags = ip.items.items(.tag);
...@@ -1980,8 +2073,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -1980,8 +2073,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
1980 .type_error_union => @sizeOf(ErrorUnion),2073 .type_error_union => @sizeOf(ErrorUnion),
1981 .type_enum_simple => @sizeOf(EnumSimple),2074 .type_enum_simple => @sizeOf(EnumSimple),
1982 .type_opaque => @sizeOf(Key.OpaqueType),2075 .type_opaque => @sizeOf(Key.OpaqueType),
1983 .type_struct => 0,2076 .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
1984 .type_struct_ns => 0,2077 .type_struct_ns => @sizeOf(Module.Namespace),
2078
2079 .type_union_tagged,
2080 .type_union_untagged,
2081 .type_union_safety,
2082 => @sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
2083
1985 .simple_type => 0,2084 .simple_type => 0,
1986 .simple_value => 0,2085 .simple_value => 0,
1987 .ptr_int => @sizeOf(PtrInt),2086 .ptr_int => @sizeOf(PtrInt),
...@@ -2010,6 +2109,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -2010,6 +2109,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
2010 .extern_func => @panic("TODO"),2109 .extern_func => @panic("TODO"),
2011 .func => @panic("TODO"),2110 .func => @panic("TODO"),
2012 .only_possible_value => 0,2111 .only_possible_value => 0,
2112 .union_value => @sizeOf(Key.Union),
2013 });2113 });
2014 }2114 }
2015 const SortContext = struct {2115 const SortContext = struct {
...@@ -2041,6 +2141,10 @@ pub fn structPtrUnwrapConst(ip: InternPool, index: Module.Struct.OptionalIndex)...@@ -2041,6 +2141,10 @@ pub fn structPtrUnwrapConst(ip: InternPool, index: Module.Struct.OptionalIndex)
2041 return structPtrConst(ip, index.unwrap() orelse return null);2141 return structPtrConst(ip, index.unwrap() orelse return null);
2042}2142}
20432143
2144pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union {
2145 return ip.allocated_unions.at(@enumToInt(index));
2146}
2147
2044pub fn createStruct(2148pub fn createStruct(
2045 ip: *InternPool,2149 ip: *InternPool,
2046 gpa: Allocator,2150 gpa: Allocator,
...@@ -2059,3 +2163,22 @@ pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index...@@ -2059,3 +2163,22 @@ pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index
2059 // allocation failures here, instead leaking the Struct until garbage collection.2163 // allocation failures here, instead leaking the Struct until garbage collection.
2060 };2164 };
2061}2165}
2166
2167pub fn createUnion(
2168 ip: *InternPool,
2169 gpa: Allocator,
2170 initialization: Module.Union,
2171) Allocator.Error!Module.Union.Index {
2172 if (ip.unions_free_list.popOrNull()) |index| return index;
2173 const ptr = try ip.allocated_unions.addOne(gpa);
2174 ptr.* = initialization;
2175 return @intToEnum(Module.Union.Index, ip.allocated_unions.len - 1);
2176}
2177
2178pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) void {
2179 ip.unionPtr(index).* = undefined;
2180 ip.unions_free_list.append(gpa, index) catch {
2181 // In order to keep `destroyUnion` a non-fallible function, we ignore memory
2182 // allocation failures here, instead leaking the Union until garbage collection.
2183 };
2184}
src/Module.zig+57-20
...@@ -851,11 +851,10 @@ pub const Decl = struct {...@@ -851,11 +851,10 @@ pub const Decl = struct {
851851
852 /// If the Decl has a value and it is a union, return it,852 /// If the Decl has a value and it is a union, return it,
853 /// otherwise null.853 /// otherwise null.
854 pub fn getUnion(decl: *Decl) ?*Union {854 pub fn getUnion(decl: *Decl, mod: *Module) ?*Union {
855 if (!decl.owns_tv) return null;855 if (!decl.owns_tv) return null;
856 const ty = (decl.val.castTag(.ty) orelse return null).data;856 const ty = (decl.val.castTag(.ty) orelse return null).data;
857 const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data;857 return mod.typeToUnion(ty);
858 return union_obj;
859 }858 }
860859
861 /// If the Decl has a value and it is a function, return it,860 /// If the Decl has a value and it is a function, return it,
...@@ -896,10 +895,6 @@ pub const Decl = struct {...@@ -896,10 +895,6 @@ pub const Decl = struct {
896 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;895 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
897 return enum_obj.namespace.toOptional();896 return enum_obj.namespace.toOptional();
898 },897 },
899 .@"union", .union_safety_tagged, .union_tagged => {
900 const union_obj = ty.cast(Type.Payload.Union).?.data;
901 return union_obj.namespace.toOptional();
902 },
903898
904 else => return .none,899 else => return .none,
905 }900 }
...@@ -907,6 +902,10 @@ pub const Decl = struct {...@@ -907,6 +902,10 @@ pub const Decl = struct {
907 else => return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {902 else => return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
908 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),903 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
909 .struct_type => |struct_type| struct_type.namespace,904 .struct_type => |struct_type| struct_type.namespace,
905 .union_type => |union_type| {
906 const union_obj = mod.unionPtr(union_type.index);
907 return union_obj.namespace.toOptional();
908 },
910 else => .none,909 else => .none,
911 },910 },
912 }911 }
...@@ -1373,6 +1372,28 @@ pub const Union = struct {...@@ -1373,6 +1372,28 @@ pub const Union = struct {
1373 requires_comptime: PropertyBoolean = .unknown,1372 requires_comptime: PropertyBoolean = .unknown,
1374 assumed_runtime_bits: bool = false,1373 assumed_runtime_bits: bool = false,
13751374
1375 pub const Index = enum(u32) {
1376 _,
1377
1378 pub fn toOptional(i: Index) OptionalIndex {
1379 return @intToEnum(OptionalIndex, @enumToInt(i));
1380 }
1381 };
1382
1383 pub const OptionalIndex = enum(u32) {
1384 none = std.math.maxInt(u32),
1385 _,
1386
1387 pub fn init(oi: ?Index) OptionalIndex {
1388 return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none));
1389 }
1390
1391 pub fn unwrap(oi: OptionalIndex) ?Index {
1392 if (oi == .none) return null;
1393 return @intToEnum(Index, @enumToInt(oi));
1394 }
1395 };
1396
1376 pub const Field = struct {1397 pub const Field = struct {
1377 /// undefined until `status` is `have_field_types` or `have_layout`.1398 /// undefined until `status` is `have_field_types` or `have_layout`.
1378 ty: Type,1399 ty: Type,
...@@ -3639,6 +3660,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {...@@ -3639,6 +3660,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
3639 return mod.allocated_namespaces.at(@enumToInt(index));3660 return mod.allocated_namespaces.at(@enumToInt(index));
3640}3661}
36413662
3663pub fn unionPtr(mod: *Module, index: Union.Index) *Union {
3664 return mod.intern_pool.unionPtr(index);
3665}
3666
3642pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {3667pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
3643 return mod.intern_pool.structPtr(index);3668 return mod.intern_pool.structPtr(index);
3644}3669}
...@@ -4112,7 +4137,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {...@@ -4112,7 +4137,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
4112 };4137 };
4113 }4138 }
41144139
4115 if (decl.getUnion()) |union_obj| {4140 if (decl.getUnion(mod)) |union_obj| {
4116 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {4141 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {
4117 try file.deleted_decls.append(gpa, decl_index);4142 try file.deleted_decls.append(gpa, decl_index);
4118 continue;4143 continue;
...@@ -5988,20 +6013,10 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void {...@@ -5988,20 +6013,10 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void {
5988 decl.analysis = .outdated;6013 decl.analysis = .outdated;
5989}6014}
59906015
5991pub const CreateNamespaceOptions = struct {6016pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index {
5992 parent: Namespace.OptionalIndex,
5993 file_scope: *File,
5994 ty: Type,
5995};
5996
5997pub fn createNamespace(mod: *Module, options: CreateNamespaceOptions) !Namespace.Index {
5998 if (mod.namespaces_free_list.popOrNull()) |index| return index;6017 if (mod.namespaces_free_list.popOrNull()) |index| return index;
5999 const ptr = try mod.allocated_namespaces.addOne(mod.gpa);6018 const ptr = try mod.allocated_namespaces.addOne(mod.gpa);
6000 ptr.* = .{6019 ptr.* = initialization;
6001 .parent = options.parent,
6002 .file_scope = options.file_scope,
6003 .ty = options.ty,
6004 };
6005 return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1);6020 return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1);
6006}6021}
60076022
...@@ -6021,6 +6036,14 @@ pub fn destroyStruct(mod: *Module, index: Struct.Index) void {...@@ -6021,6 +6036,14 @@ pub fn destroyStruct(mod: *Module, index: Struct.Index) void {
6021 return mod.intern_pool.destroyStruct(mod.gpa, index);6036 return mod.intern_pool.destroyStruct(mod.gpa, index);
6022}6037}
60236038
6039pub fn createUnion(mod: *Module, initialization: Union) Allocator.Error!Union.Index {
6040 return mod.intern_pool.createUnion(mod.gpa, initialization);
6041}
6042
6043pub fn destroyUnion(mod: *Module, index: Union.Index) void {
6044 return mod.intern_pool.destroyUnion(mod.gpa, index);
6045}
6046
6024pub fn allocateNewDecl(6047pub fn allocateNewDecl(
6025 mod: *Module,6048 mod: *Module,
6026 namespace: Namespace.Index,6049 namespace: Namespace.Index,
...@@ -7068,6 +7091,15 @@ pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value {...@@ -7068,6 +7091,15 @@ pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value {
7068 return i.toValue();7091 return i.toValue();
7069}7092}
70707093
7094pub fn unionValue(mod: *Module, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value {
7095 const i = try intern(mod, .{ .un = .{
7096 .ty = union_ty.ip_index,
7097 .tag = tag.ip_index,
7098 .val = val.ip_index,
7099 } });
7100 return i.toValue();
7101}
7102
7071pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {7103pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {
7072 return intType(mod, .unsigned, Type.smallestUnsignedBits(max));7104 return intType(mod, .unsigned, Type.smallestUnsignedBits(max));
7073}7105}
...@@ -7276,3 +7308,8 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {...@@ -7276,3 +7308,8 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {
7276 const struct_index = mod.intern_pool.indexToStruct(ty.ip_index).unwrap() orelse return null;7308 const struct_index = mod.intern_pool.indexToStruct(ty.ip_index).unwrap() orelse return null;
7277 return mod.structPtr(struct_index);7309 return mod.structPtr(struct_index);
7278}7310}
7311
7312pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {
7313 const union_index = mod.intern_pool.indexToUnion(ty.ip_index).unwrap() orelse return null;
7314 return mod.unionPtr(union_index);
7315}
src/Sema.zig+203-178
...@@ -3123,6 +3123,8 @@ fn zirUnionDecl(...@@ -3123,6 +3123,8 @@ fn zirUnionDecl(
3123 const tracy = trace(@src());3123 const tracy = trace(@src());
3124 defer tracy.end();3124 defer tracy.end();
31253125
3126 const mod = sema.mod;
3127 const gpa = sema.gpa;
3126 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);3128 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
3127 var extra_index: usize = extended.operand;3129 var extra_index: usize = extended.operand;
31283130
...@@ -3142,49 +3144,57 @@ fn zirUnionDecl(...@@ -3142,49 +3144,57 @@ fn zirUnionDecl(
3142 break :blk decls_len;3144 break :blk decls_len;
3143 } else 0;3145 } else 0;
31443146
3145 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);3147 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
3146 errdefer new_decl_arena.deinit();3148 errdefer new_decl_arena.deinit();
3147 const new_decl_arena_allocator = new_decl_arena.allocator();
31483149
3149 const union_obj = try new_decl_arena_allocator.create(Module.Union);3150 // Because these three things each reference each other, `undefined`
3150 const type_tag = if (small.has_tag_type or small.auto_enum_tag)3151 // placeholders are used before being set after the union type gains an
3151 Type.Tag.union_tagged3152 // InternPool index.
3152 else if (small.layout != .Auto)3153
3153 Type.Tag.@"union"
3154 else switch (block.sema.mod.optimizeMode()) {
3155 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
3156 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
3157 };
3158 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
3159 union_payload.* = .{
3160 .base = .{ .tag = type_tag },
3161 .data = union_obj,
3162 };
3163 const union_ty = Type.initPayload(&union_payload.base);
3164 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
3165 const mod = sema.mod;
3166 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3154 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3167 .ty = Type.type,3155 .ty = Type.type,
3168 .val = union_val,3156 .val = undefined,
3169 }, small.name_strategy, "union", inst);3157 }, small.name_strategy, "union", inst);
3170 const new_decl = mod.declPtr(new_decl_index);3158 const new_decl = mod.declPtr(new_decl_index);
3171 new_decl.owns_tv = true;3159 new_decl.owns_tv = true;
3172 errdefer mod.abortAnonDecl(new_decl_index);3160 errdefer mod.abortAnonDecl(new_decl_index);
3173 union_obj.* = .{3161
3162 const new_namespace_index = try mod.createNamespace(.{
3163 .parent = block.namespace.toOptional(),
3164 .ty = undefined,
3165 .file_scope = block.getFileScope(mod),
3166 });
3167 const new_namespace = mod.namespacePtr(new_namespace_index);
3168 errdefer mod.destroyNamespace(new_namespace_index);
3169
3170 const union_index = try mod.createUnion(.{
3174 .owner_decl = new_decl_index,3171 .owner_decl = new_decl_index,
3175 .tag_ty = Type.null,3172 .tag_ty = Type.null,
3176 .fields = .{},3173 .fields = .{},
3177 .zir_index = inst,3174 .zir_index = inst,
3178 .layout = small.layout,3175 .layout = small.layout,
3179 .status = .none,3176 .status = .none,
3180 .namespace = try mod.createNamespace(.{3177 .namespace = new_namespace_index,
3181 .parent = block.namespace.toOptional(),3178 });
3182 .ty = union_ty,3179 errdefer mod.destroyUnion(union_index);
3183 .file_scope = block.getFileScope(mod),3180
3184 }),3181 const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
3185 };3182 .index = union_index,
3183 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3184 .tagged
3185 else if (small.layout != .Auto)
3186 .none
3187 else switch (block.sema.mod.optimizeMode()) {
3188 .Debug, .ReleaseSafe => .safety,
3189 .ReleaseFast, .ReleaseSmall => .none,
3190 },
3191 } });
3192 errdefer mod.intern_pool.remove(union_ty);
3193
3194 new_decl.val = union_ty.toValue();
3195 new_namespace.ty = union_ty.toType();
31863196
3187 _ = try mod.scanNamespace(union_obj.namespace, extra_index, decls_len, new_decl);3197 _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
31883198
3189 try new_decl.finalizeNewArena(&new_decl_arena);3199 try new_decl.finalizeNewArena(&new_decl_arena);
3190 return sema.analyzeDeclVal(block, src, new_decl_index);3200 return sema.analyzeDeclVal(block, src, new_decl_index);
...@@ -4246,6 +4256,8 @@ fn validateUnionInit(...@@ -4246,6 +4256,8 @@ fn validateUnionInit(
4246 instrs: []const Zir.Inst.Index,4256 instrs: []const Zir.Inst.Index,
4247 union_ptr: Air.Inst.Ref,4257 union_ptr: Air.Inst.Ref,
4248) CompileError!void {4258) CompileError!void {
4259 const mod = sema.mod;
4260
4249 if (instrs.len != 1) {4261 if (instrs.len != 1) {
4250 const msg = msg: {4262 const msg = msg: {
4251 const msg = try sema.errMsg(4263 const msg = try sema.errMsg(
...@@ -4343,7 +4355,7 @@ fn validateUnionInit(...@@ -4343,7 +4355,7 @@ fn validateUnionInit(
4343 break;4355 break;
4344 }4356 }
43454357
4346 const tag_ty = union_ty.unionTagTypeHypothetical();4358 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
4347 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);4359 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
4348 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);4360 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
43494361
...@@ -8273,7 +8285,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -8273,7 +8285,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
8273 .Enum => operand,8285 .Enum => operand,
8274 .Union => blk: {8286 .Union => blk: {
8275 const union_ty = try sema.resolveTypeFields(operand_ty);8287 const union_ty = try sema.resolveTypeFields(operand_ty);
8276 const tag_ty = union_ty.unionTagType() orelse {8288 const tag_ty = union_ty.unionTagType(mod) orelse {
8277 return sema.fail(8289 return sema.fail(
8278 block,8290 block,
8279 operand_src,8291 operand_src,
...@@ -10158,7 +10170,7 @@ fn zirSwitchCapture(...@@ -10158,7 +10170,7 @@ fn zirSwitchCapture(
10158 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;10170 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
10159 if (operand_ty.zigTypeTag(mod) == .Union) {10171 if (operand_ty.zigTypeTag(mod) == .Union) {
10160 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);10172 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
10161 const union_obj = operand_ty.cast(Type.Payload.Union).?.data;10173 const union_obj = mod.typeToUnion(operand_ty).?;
10162 const field_ty = union_obj.fields.values()[field_index].ty;10174 const field_ty = union_obj.fields.values()[field_index].ty;
10163 if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {10175 if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
10164 if (is_ref) {10176 if (is_ref) {
...@@ -10229,7 +10241,7 @@ fn zirSwitchCapture(...@@ -10229,7 +10241,7 @@ fn zirSwitchCapture(
1022910241
10230 switch (operand_ty.zigTypeTag(mod)) {10242 switch (operand_ty.zigTypeTag(mod)) {
10231 .Union => {10243 .Union => {
10232 const union_obj = operand_ty.cast(Type.Payload.Union).?.data;10244 const union_obj = mod.typeToUnion(operand_ty).?;
10233 const first_item = try sema.resolveInst(items[0]);10245 const first_item = try sema.resolveInst(items[0]);
10234 // Previous switch validation ensured this will succeed10246 // Previous switch validation ensured this will succeed
10235 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;10247 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
...@@ -10403,7 +10415,7 @@ fn zirSwitchCond(...@@ -10403,7 +10415,7 @@ fn zirSwitchCond(
1040310415
10404 .Union => {10416 .Union => {
10405 const union_ty = try sema.resolveTypeFields(operand_ty);10417 const union_ty = try sema.resolveTypeFields(operand_ty);
10406 const enum_ty = union_ty.unionTagType() orelse {10418 const enum_ty = union_ty.unionTagType(mod) orelse {
10407 const msg = msg: {10419 const msg = msg: {
10408 const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});10420 const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
10409 errdefer msg.destroy(sema.gpa);10421 errdefer msg.destroy(sema.gpa);
...@@ -11627,7 +11639,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11627,7 +11639,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11627 const analyze_body = if (union_originally and !special.is_inline)11639 const analyze_body = if (union_originally and !special.is_inline)
11628 for (seen_enum_fields, 0..) |seen_field, index| {11640 for (seen_enum_fields, 0..) |seen_field, index| {
11629 if (seen_field != null) continue;11641 if (seen_field != null) continue;
11630 const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;11642 const union_obj = mod.typeToUnion(maybe_union_ty).?;
11631 const field_ty = union_obj.fields.values()[index].ty;11643 const field_ty = union_obj.fields.values()[index].ty;
11632 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;11644 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
11633 } else false11645 } else false
...@@ -12068,7 +12080,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12068,7 +12080,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12068 }12080 }
12069 break :hf switch (ty.zigTypeTag(mod)) {12081 break :hf switch (ty.zigTypeTag(mod)) {
12070 .Struct => ty.structFields(mod).contains(field_name),12082 .Struct => ty.structFields(mod).contains(field_name),
12071 .Union => ty.unionFields().contains(field_name),12083 .Union => ty.unionFields(mod).contains(field_name),
12072 .Enum => ty.enumFields().contains(field_name),12084 .Enum => ty.enumFields().contains(field_name),
12073 .Array => mem.eql(u8, field_name, "len"),12085 .Array => mem.eql(u8, field_name, "len"),
12074 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{12086 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
...@@ -15415,7 +15427,7 @@ fn analyzeCmpUnionTag(...@@ -15415,7 +15427,7 @@ fn analyzeCmpUnionTag(
15415) CompileError!Air.Inst.Ref {15427) CompileError!Air.Inst.Ref {
15416 const mod = sema.mod;15428 const mod = sema.mod;
15417 const union_ty = try sema.resolveTypeFields(sema.typeOf(un));15429 const union_ty = try sema.resolveTypeFields(sema.typeOf(un));
15418 const union_tag_ty = union_ty.unionTagType() orelse {15430 const union_tag_ty = union_ty.unionTagType(mod) orelse {
15419 const msg = msg: {15431 const msg = msg: {
15420 const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});15432 const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
15421 errdefer msg.destroy(sema.gpa);15433 errdefer msg.destroy(sema.gpa);
...@@ -16403,7 +16415,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16403,7 +16415,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16403 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout16415 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
16404 const layout = union_ty.containerLayout(mod);16416 const layout = union_ty.containerLayout(mod);
1640516417
16406 const union_fields = union_ty.unionFields();16418 const union_fields = union_ty.unionFields(mod);
16407 const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());16419 const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
1640816420
16409 for (union_field_vals, 0..) |*field_val, i| {16421 for (union_field_vals, 0..) |*field_val, i| {
...@@ -16458,7 +16470,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16458,7 +16470,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1645816470
16459 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace(mod));16471 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace(mod));
1646016472
16461 const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {16473 const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: {
16462 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);16474 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
16463 break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);16475 break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
16464 } else Value.null;16476 } else Value.null;
...@@ -17877,12 +17889,13 @@ fn unionInit(...@@ -17877,12 +17889,13 @@ fn unionInit(
17877 field_name: []const u8,17889 field_name: []const u8,
17878 field_src: LazySrcLoc,17890 field_src: LazySrcLoc,
17879) CompileError!Air.Inst.Ref {17891) CompileError!Air.Inst.Ref {
17892 const mod = sema.mod;
17880 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);17893 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
17881 const field = union_ty.unionFields().values()[field_index];17894 const field = union_ty.unionFields(mod).values()[field_index];
17882 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);17895 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
1788317896
17884 if (try sema.resolveMaybeUndefVal(init)) |init_val| {17897 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
17885 const tag_ty = union_ty.unionTagTypeHypothetical();17898 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
17886 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);17899 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
17887 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);17900 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
17888 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{17901 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
...@@ -17983,7 +17996,7 @@ fn zirStructInit(...@@ -17983,7 +17996,7 @@ fn zirStructInit(
17983 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;17996 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
17984 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);17997 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
17985 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);17998 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
17986 const tag_ty = resolved_ty.unionTagTypeHypothetical();17999 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
17987 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);18000 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
17988 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);18001 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
1798918002
...@@ -18006,7 +18019,7 @@ fn zirStructInit(...@@ -18006,7 +18019,7 @@ fn zirStructInit(
18006 const alloc = try block.addTy(.alloc, alloc_ty);18019 const alloc = try block.addTy(.alloc, alloc_ty);
18007 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);18020 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
18008 try sema.storePtr(block, src, field_ptr, init_inst);18021 try sema.storePtr(block, src, field_ptr, init_inst);
18009 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);18022 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val);
18010 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);18023 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
18011 return sema.makePtrConst(block, alloc);18024 return sema.makePtrConst(block, alloc);
18012 }18025 }
...@@ -18544,7 +18557,7 @@ fn fieldType(...@@ -18544,7 +18557,7 @@ fn fieldType(
18544 return sema.addType(field.ty);18557 return sema.addType(field.ty);
18545 },18558 },
18546 .Union => {18559 .Union => {
18547 const union_obj = cur_ty.cast(Type.Payload.Union).?.data;18560 const union_obj = mod.typeToUnion(cur_ty).?;
18548 const field = union_obj.fields.get(field_name) orelse18561 const field = union_obj.fields.get(field_name) orelse
18549 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);18562 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
18550 return sema.addType(field.ty);18563 return sema.addType(field.ty);
...@@ -18726,7 +18739,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18726,7 +18739,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18726 return sema.addStrLit(block, bytes);18739 return sema.addStrLit(block, bytes);
18727 },18740 },
18728 .Enum => operand_ty,18741 .Enum => operand_ty,
18729 .Union => operand_ty.unionTagType() orelse {18742 .Union => operand_ty.unionTagType(mod) orelse {
18730 const msg = msg: {18743 const msg = msg: {
18731 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{18744 const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
18732 operand_ty.fmt(sema.mod),18745 operand_ty.fmt(sema.mod),
...@@ -19245,42 +19258,53 @@ fn zirReify(...@@ -19245,42 +19258,53 @@ fn zirReify(
19245 errdefer new_decl_arena.deinit();19258 errdefer new_decl_arena.deinit();
19246 const new_decl_arena_allocator = new_decl_arena.allocator();19259 const new_decl_arena_allocator = new_decl_arena.allocator();
1924719260
19248 const union_obj = try new_decl_arena_allocator.create(Module.Union);19261 // Because these three things each reference each other, `undefined`
19249 const type_tag = if (!tag_type_val.isNull(mod))19262 // placeholders are used before being set after the union type gains an
19250 Type.Tag.union_tagged19263 // InternPool index.
19251 else if (layout != .Auto)19264
19252 Type.Tag.@"union"
19253 else switch (mod.optimizeMode()) {
19254 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
19255 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
19256 };
19257 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
19258 union_payload.* = .{
19259 .base = .{ .tag = type_tag },
19260 .data = union_obj,
19261 };
19262 const union_ty = Type.initPayload(&union_payload.base);
19263 const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
19264 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{19265 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
19265 .ty = Type.type,19266 .ty = Type.type,
19266 .val = new_union_val,19267 .val = undefined,
19267 }, name_strategy, "union", inst);19268 }, name_strategy, "union", inst);
19268 const new_decl = mod.declPtr(new_decl_index);19269 const new_decl = mod.declPtr(new_decl_index);
19269 new_decl.owns_tv = true;19270 new_decl.owns_tv = true;
19270 errdefer mod.abortAnonDecl(new_decl_index);19271 errdefer mod.abortAnonDecl(new_decl_index);
19271 union_obj.* = .{19272
19273 const new_namespace_index = try mod.createNamespace(.{
19274 .parent = block.namespace.toOptional(),
19275 .ty = undefined,
19276 .file_scope = block.getFileScope(mod),
19277 });
19278 const new_namespace = mod.namespacePtr(new_namespace_index);
19279 errdefer mod.destroyNamespace(new_namespace_index);
19280
19281 const union_index = try mod.createUnion(.{
19272 .owner_decl = new_decl_index,19282 .owner_decl = new_decl_index,
19273 .tag_ty = Type.null,19283 .tag_ty = Type.null,
19274 .fields = .{},19284 .fields = .{},
19275 .zir_index = inst,19285 .zir_index = inst,
19276 .layout = layout,19286 .layout = layout,
19277 .status = .have_field_types,19287 .status = .have_field_types,
19278 .namespace = try mod.createNamespace(.{19288 .namespace = new_namespace_index,
19279 .parent = block.namespace.toOptional(),19289 });
19280 .ty = union_ty,19290 const union_obj = mod.unionPtr(union_index);
19281 .file_scope = block.getFileScope(mod),19291 errdefer mod.destroyUnion(union_index);
19282 }),19292
19283 };19293 const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
19294 .index = union_index,
19295 .runtime_tag = if (!tag_type_val.isNull(mod))
19296 .tagged
19297 else if (layout != .Auto)
19298 .none
19299 else switch (mod.optimizeMode()) {
19300 .Debug, .ReleaseSafe => .safety,
19301 .ReleaseFast, .ReleaseSmall => .none,
19302 },
19303 } });
19304 errdefer mod.intern_pool.remove(union_ty);
19305
19306 new_decl.val = union_ty.toValue();
19307 new_namespace.ty = union_ty.toType();
1928419308
19285 // Tag type19309 // Tag type
19286 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;19310 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
...@@ -21981,8 +22005,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -21981,8 +22005,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
21981 ptr_ty_data.@"align" = blk: {22005 ptr_ty_data.@"align" = blk: {
21982 if (mod.typeToStruct(parent_ty)) |struct_obj| {22006 if (mod.typeToStruct(parent_ty)) |struct_obj| {
21983 break :blk struct_obj.fields.values()[field_index].abi_align;22007 break :blk struct_obj.fields.values()[field_index].abi_align;
21984 } else if (parent_ty.cast(Type.Payload.Union)) |union_obj| {22008 } else if (mod.typeToUnion(parent_ty)) |union_obj| {
21985 break :blk union_obj.data.fields.values()[field_index].abi_align;22009 break :blk union_obj.fields.values()[field_index].abi_align;
21986 } else {22010 } else {
21987 break :blk 0;22011 break :blk 0;
21988 }22012 }
...@@ -23443,8 +23467,7 @@ fn explainWhyTypeIsComptimeInner(...@@ -23443,8 +23467,7 @@ fn explainWhyTypeIsComptimeInner(
23443 .Union => {23467 .Union => {
23444 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;23468 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
2344523469
23446 if (ty.cast(Type.Payload.Union)) |payload| {23470 if (mod.typeToUnion(ty)) |union_obj| {
23447 const union_obj = payload.data;
23448 for (union_obj.fields.values(), 0..) |field, i| {23471 for (union_obj.fields.values(), 0..) |field, i| {
23449 const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{23472 const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
23450 .index = i,23473 .index = i,
...@@ -24144,7 +24167,7 @@ fn fieldVal(...@@ -24144,7 +24167,7 @@ fn fieldVal(
24144 }24167 }
24145 }24168 }
24146 const union_ty = try sema.resolveTypeFields(child_type);24169 const union_ty = try sema.resolveTypeFields(child_type);
24147 if (union_ty.unionTagType()) |enum_ty| {24170 if (union_ty.unionTagType(mod)) |enum_ty| {
24148 if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {24171 if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
24149 const field_index = @intCast(u32, field_index_usize);24172 const field_index = @intCast(u32, field_index_usize);
24150 return sema.addConstant(24173 return sema.addConstant(
...@@ -24358,7 +24381,7 @@ fn fieldPtr(...@@ -24358,7 +24381,7 @@ fn fieldPtr(
24358 }24381 }
24359 }24382 }
24360 const union_ty = try sema.resolveTypeFields(child_type);24383 const union_ty = try sema.resolveTypeFields(child_type);
24361 if (union_ty.unionTagType()) |enum_ty| {24384 if (union_ty.unionTagType(mod)) |enum_ty| {
24362 if (enum_ty.enumFieldIndex(field_name)) |field_index| {24385 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
24363 const field_index_u32 = @intCast(u32, field_index);24386 const field_index_u32 = @intCast(u32, field_index);
24364 var anon_decl = try block.startAnonDecl();24387 var anon_decl = try block.startAnonDecl();
...@@ -24489,7 +24512,7 @@ fn fieldCallBind(...@@ -24489,7 +24512,7 @@ fn fieldCallBind(
24489 },24512 },
24490 .Union => {24513 .Union => {
24491 const union_ty = try sema.resolveTypeFields(concrete_ty);24514 const union_ty = try sema.resolveTypeFields(concrete_ty);
24492 const fields = union_ty.unionFields();24515 const fields = union_ty.unionFields(mod);
24493 const field_index_usize = fields.getIndex(field_name) orelse break :find_field;24516 const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
24494 const field_index = @intCast(u32, field_index_usize);24517 const field_index = @intCast(u32, field_index_usize);
24495 const field = fields.values()[field_index];24518 const field = fields.values()[field_index];
...@@ -24964,7 +24987,7 @@ fn unionFieldPtr(...@@ -24964,7 +24987,7 @@ fn unionFieldPtr(
2496424987
24965 const union_ptr_ty = sema.typeOf(union_ptr);24988 const union_ptr_ty = sema.typeOf(union_ptr);
24966 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);24989 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
24967 const union_obj = union_ty.cast(Type.Payload.Union).?.data;24990 const union_obj = mod.typeToUnion(union_ty).?;
24968 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);24991 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
24969 const field = union_obj.fields.values()[field_index];24992 const field = union_obj.fields.values()[field_index];
24970 const ptr_field_ty = try Type.ptr(arena, mod, .{24993 const ptr_field_ty = try Type.ptr(arena, mod, .{
...@@ -25028,7 +25051,7 @@ fn unionFieldPtr(...@@ -25028,7 +25051,7 @@ fn unionFieldPtr(
2502825051
25029 try sema.requireRuntimeBlock(block, src, null);25052 try sema.requireRuntimeBlock(block, src, null);
25030 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and25053 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
25031 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)25054 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
25032 {25055 {
25033 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);25056 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
25034 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);25057 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
...@@ -25057,7 +25080,7 @@ fn unionFieldVal(...@@ -25057,7 +25080,7 @@ fn unionFieldVal(
25057 assert(unresolved_union_ty.zigTypeTag(mod) == .Union);25080 assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
2505825081
25059 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);25082 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
25060 const union_obj = union_ty.cast(Type.Payload.Union).?.data;25083 const union_obj = mod.typeToUnion(union_ty).?;
25061 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);25084 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
25062 const field = union_obj.fields.values()[field_index];25085 const field = union_obj.fields.values()[field_index];
25063 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);25086 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
...@@ -25103,7 +25126,7 @@ fn unionFieldVal(...@@ -25103,7 +25126,7 @@ fn unionFieldVal(
2510325126
25104 try sema.requireRuntimeBlock(block, src, null);25127 try sema.requireRuntimeBlock(block, src, null);
25105 if (union_obj.layout == .Auto and block.wantSafety() and25128 if (union_obj.layout == .Auto and block.wantSafety() and
25106 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)25129 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
25107 {25130 {
25108 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);25131 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
25109 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);25132 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
...@@ -26189,7 +26212,7 @@ fn coerceExtra(...@@ -26189,7 +26212,7 @@ fn coerceExtra(
26189 },26212 },
26190 .Union => blk: {26213 .Union => blk: {
26191 // union to its own tag type26214 // union to its own tag type
26192 const union_tag_ty = inst_ty.unionTagType() orelse break :blk;26215 const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;
26193 if (union_tag_ty.eql(dest_ty, sema.mod)) {26216 if (union_tag_ty.eql(dest_ty, sema.mod)) {
26194 return sema.unionToTag(block, dest_ty, inst, inst_src);26217 return sema.unionToTag(block, dest_ty, inst, inst_src);
26195 }26218 }
...@@ -28622,7 +28645,7 @@ fn coerceEnumToUnion(...@@ -28622,7 +28645,7 @@ fn coerceEnumToUnion(
28622 const mod = sema.mod;28645 const mod = sema.mod;
28623 const inst_ty = sema.typeOf(inst);28646 const inst_ty = sema.typeOf(inst);
2862428647
28625 const tag_ty = union_ty.unionTagType() orelse {28648 const tag_ty = union_ty.unionTagType(mod) orelse {
28626 const msg = msg: {28649 const msg = msg: {
28627 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{28650 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
28628 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),28651 union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
...@@ -28649,7 +28672,7 @@ fn coerceEnumToUnion(...@@ -28649,7 +28672,7 @@ fn coerceEnumToUnion(
28649 return sema.failWithOwnedErrorMsg(msg);28672 return sema.failWithOwnedErrorMsg(msg);
28650 };28673 };
2865128674
28652 const union_obj = union_ty.cast(Type.Payload.Union).?.data;28675 const union_obj = mod.typeToUnion(union_ty).?;
28653 const field = union_obj.fields.values()[field_index];28676 const field = union_obj.fields.values()[field_index];
28654 const field_ty = try sema.resolveTypeFields(field.ty);28677 const field_ty = try sema.resolveTypeFields(field.ty);
28655 if (field_ty.zigTypeTag(mod) == .NoReturn) {28678 if (field_ty.zigTypeTag(mod) == .NoReturn) {
...@@ -28679,10 +28702,7 @@ fn coerceEnumToUnion(...@@ -28679,10 +28702,7 @@ fn coerceEnumToUnion(
28679 return sema.failWithOwnedErrorMsg(msg);28702 return sema.failWithOwnedErrorMsg(msg);
28680 };28703 };
2868128704
28682 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{28705 return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv));
28683 .tag = val,
28684 .val = opv,
28685 }));
28686 }28706 }
2868728707
28688 try sema.requireRuntimeBlock(block, inst_src, null);28708 try sema.requireRuntimeBlock(block, inst_src, null);
...@@ -28699,7 +28719,7 @@ fn coerceEnumToUnion(...@@ -28699,7 +28719,7 @@ fn coerceEnumToUnion(
28699 return sema.failWithOwnedErrorMsg(msg);28719 return sema.failWithOwnedErrorMsg(msg);
28700 }28720 }
2870128721
28702 const union_obj = union_ty.cast(Type.Payload.Union).?.data;28722 const union_obj = mod.typeToUnion(union_ty).?;
28703 {28723 {
28704 var msg: ?*Module.ErrorMsg = null;28724 var msg: ?*Module.ErrorMsg = null;
28705 errdefer if (msg) |some| some.destroy(sema.gpa);28725 errdefer if (msg) |some| some.destroy(sema.gpa);
...@@ -29350,10 +29370,13 @@ fn analyzeRef(...@@ -29350,10 +29370,13 @@ fn analyzeRef(
29350 const operand_ty = sema.typeOf(operand);29370 const operand_ty = sema.typeOf(operand);
2935129371
29352 if (try sema.resolveMaybeUndefVal(operand)) |val| {29372 if (try sema.resolveMaybeUndefVal(operand)) |val| {
29353 switch (val.tag()) {29373 switch (val.ip_index) {
29354 .extern_fn, .function => {29374 .none => switch (val.tag()) {
29355 const decl_index = val.pointerDecl().?;29375 .extern_fn, .function => {
29356 return sema.analyzeDeclRef(decl_index);29376 const decl_index = val.pointerDecl().?;
29377 return sema.analyzeDeclRef(decl_index);
29378 },
29379 else => {},
29357 },29380 },
29358 else => {},29381 else => {},
29359 }29382 }
...@@ -31523,8 +31546,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void...@@ -31523,8 +31546,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
31523}31546}
3152431547
31525fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {31548fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
31549 const mod = sema.mod;
31526 const resolved_ty = try sema.resolveTypeFields(ty);31550 const resolved_ty = try sema.resolveTypeFields(ty);
31527 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;31551 const union_obj = mod.typeToUnion(resolved_ty).?;
31528 switch (union_obj.status) {31552 switch (union_obj.status) {
31529 .none, .have_field_types => {},31553 .none, .have_field_types => {},
31530 .field_types_wip, .layout_wip => {31554 .field_types_wip, .layout_wip => {
...@@ -31617,27 +31641,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31617,27 +31641,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31617 return false;31641 return false;
31618 },31642 },
3161931643
31620 .@"union", .union_safety_tagged, .union_tagged => {
31621 const union_obj = ty.cast(Type.Payload.Union).?.data;
31622 switch (union_obj.requires_comptime) {
31623 .no, .wip => return false,
31624 .yes => return true,
31625 .unknown => {
31626 var requires_comptime = false;
31627 union_obj.requires_comptime = .wip;
31628 for (union_obj.fields.values()) |field| {
31629 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
31630 }
31631 if (requires_comptime) {
31632 union_obj.requires_comptime = .yes;
31633 } else {
31634 union_obj.requires_comptime = .no;
31635 }
31636 return requires_comptime;
31637 },
31638 }
31639 },
31640
31641 .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()),31644 .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()),
31642 .anyframe_T => {31645 .anyframe_T => {
31643 const child_ty = ty.castTag(.anyframe_T).?.data;31646 const child_ty = ty.castTag(.anyframe_T).?.data;
...@@ -31734,10 +31737,31 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31734,10 +31737,31 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31734 }31737 }
31735 },31738 },
3173631739
31737 .union_type => @panic("TODO"),31740 .union_type => |union_type| {
31741 const union_obj = mod.unionPtr(union_type.index);
31742 switch (union_obj.requires_comptime) {
31743 .no, .wip => return false,
31744 .yes => return true,
31745 .unknown => {
31746 var requires_comptime = false;
31747 union_obj.requires_comptime = .wip;
31748 for (union_obj.fields.values()) |field| {
31749 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
31750 }
31751 if (requires_comptime) {
31752 union_obj.requires_comptime = .yes;
31753 } else {
31754 union_obj.requires_comptime = .no;
31755 }
31756 return requires_comptime;
31757 },
31758 }
31759 },
31760
31738 .opaque_type => false,31761 .opaque_type => false,
3173931762
31740 // values, not types31763 // values, not types
31764 .un => unreachable,
31741 .simple_value => unreachable,31765 .simple_value => unreachable,
31742 .extern_func => unreachable,31766 .extern_func => unreachable,
31743 .int => unreachable,31767 .int => unreachable,
...@@ -31829,8 +31853,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {...@@ -31829,8 +31853,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
31829fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {31853fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
31830 try sema.resolveUnionLayout(ty);31854 try sema.resolveUnionLayout(ty);
3183131855
31856 const mod = sema.mod;
31832 const resolved_ty = try sema.resolveTypeFields(ty);31857 const resolved_ty = try sema.resolveTypeFields(ty);
31833 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;31858 const union_obj = mod.typeToUnion(resolved_ty).?;
31834 switch (union_obj.status) {31859 switch (union_obj.status) {
31835 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},31860 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
31836 .fully_resolved_wip, .fully_resolved => return,31861 .fully_resolved_wip, .fully_resolved => return,
...@@ -31858,15 +31883,8 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {...@@ -31858,15 +31883,8 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
31858 const mod = sema.mod;31883 const mod = sema.mod;
3185931884
31860 switch (ty.ip_index) {31885 switch (ty.ip_index) {
31861 .none => switch (ty.tag()) {31886 // TODO: After the InternPool transition is complete, change this to `unreachable`.
31862 .@"union", .union_safety_tagged, .union_tagged => {31887 .none => return ty,
31863 const union_obj = ty.cast(Type.Payload.Union).?.data;
31864 try sema.resolveTypeFieldsUnion(ty, union_obj);
31865 return ty;
31866 },
31867
31868 else => return ty,
31869 },
3187031888
31871 .u1_type,31889 .u1_type,
31872 .u8_type,31890 .u8_type,
...@@ -31957,7 +31975,12 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {...@@ -31957,7 +31975,12 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
31957 try sema.resolveTypeFieldsStruct(ty, struct_obj);31975 try sema.resolveTypeFieldsStruct(ty, struct_obj);
31958 return ty;31976 return ty;
31959 },31977 },
31960 .union_type => @panic("TODO"),31978 .union_type => |union_type| {
31979 const union_obj = mod.unionPtr(union_type.index);
31980 try sema.resolveTypeFieldsUnion(ty, union_obj);
31981 return ty;
31982 },
31983
31961 else => return ty,31984 else => return ty,
31962 },31985 },
31963 }31986 }
...@@ -33123,32 +33146,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33123,32 +33146,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33123 return null;33146 return null;
33124 }33147 }
33125 },33148 },
33126 .@"union", .union_safety_tagged, .union_tagged => {
33127 const resolved_ty = try sema.resolveTypeFields(ty);
33128 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
33129 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
33130 return null;
33131 const fields = union_obj.fields.values();
33132 if (fields.len == 0) return Value.@"unreachable";
33133 const only_field = fields[0];
33134 if (only_field.ty.eql(resolved_ty, sema.mod)) {
33135 const msg = try Module.ErrorMsg.create(
33136 sema.gpa,
33137 union_obj.srcLoc(sema.mod),
33138 "union '{}' depends on itself",
33139 .{ty.fmt(sema.mod)},
33140 );
33141 try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
33142 return sema.failWithOwnedErrorMsg(msg);
33143 }
33144 const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
33145 return null;
33146 // TODO make this not allocate.
33147 return try Value.Tag.@"union".create(sema.arena, .{
33148 .tag = tag_val,
33149 .val = val_val,
33150 });
33151 },
3315233149
33153 .array => {33150 .array => {
33154 if (ty.arrayLen(mod) == 0)33151 if (ty.arrayLen(mod) == 0)
...@@ -33268,10 +33265,37 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33268,10 +33265,37 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33268 return empty.toValue();33265 return empty.toValue();
33269 },33266 },
3327033267
33271 .union_type => @panic("TODO"),33268 .union_type => |union_type| {
33269 const resolved_ty = try sema.resolveTypeFields(ty);
33270 const union_obj = mod.unionPtr(union_type.index);
33271 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
33272 return null;
33273 const fields = union_obj.fields.values();
33274 if (fields.len == 0) return Value.@"unreachable";
33275 const only_field = fields[0];
33276 if (only_field.ty.eql(resolved_ty, sema.mod)) {
33277 const msg = try Module.ErrorMsg.create(
33278 sema.gpa,
33279 union_obj.srcLoc(sema.mod),
33280 "union '{}' depends on itself",
33281 .{ty.fmt(sema.mod)},
33282 );
33283 try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
33284 return sema.failWithOwnedErrorMsg(msg);
33285 }
33286 const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
33287 return null;
33288 const only = try mod.intern(.{ .un = .{
33289 .ty = resolved_ty.ip_index,
33290 .tag = tag_val.ip_index,
33291 .val = val_val.ip_index,
33292 } });
33293 return only.toValue();
33294 },
33272 .opaque_type => null,33295 .opaque_type => null,
3327333296
33274 // values, not types33297 // values, not types
33298 .un => unreachable,
33275 .simple_value => unreachable,33299 .simple_value => unreachable,
33276 .extern_func => unreachable,33300 .extern_func => unreachable,
33277 .int => unreachable,33301 .int => unreachable,
...@@ -33710,30 +33734,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33710,30 +33734,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33710 return false;33734 return false;
33711 },33735 },
3371233736
33713 .@"union", .union_safety_tagged, .union_tagged => {
33714 const union_obj = ty.cast(Type.Payload.Union).?.data;
33715 switch (union_obj.requires_comptime) {
33716 .no, .wip => return false,
33717 .yes => return true,
33718 .unknown => {
33719 if (union_obj.status == .field_types_wip)
33720 return false;
33721
33722 try sema.resolveTypeFieldsUnion(ty, union_obj);
33723
33724 union_obj.requires_comptime = .wip;
33725 for (union_obj.fields.values()) |field| {
33726 if (try sema.typeRequiresComptime(field.ty)) {
33727 union_obj.requires_comptime = .yes;
33728 return true;
33729 }
33730 }
33731 union_obj.requires_comptime = .no;
33732 return false;
33733 },
33734 }
33735 },
33736
33737 .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),33737 .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
33738 .anyframe_T => {33738 .anyframe_T => {
33739 const child_ty = ty.castTag(.anyframe_T).?.data;33739 const child_ty = ty.castTag(.anyframe_T).?.data;
...@@ -33837,10 +33837,34 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33837,10 +33837,34 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33837 }33837 }
33838 },33838 },
3383933839
33840 .union_type => @panic("TODO"),33840 .union_type => |union_type| {
33841 const union_obj = mod.unionPtr(union_type.index);
33842 switch (union_obj.requires_comptime) {
33843 .no, .wip => return false,
33844 .yes => return true,
33845 .unknown => {
33846 if (union_obj.status == .field_types_wip)
33847 return false;
33848
33849 try sema.resolveTypeFieldsUnion(ty, union_obj);
33850
33851 union_obj.requires_comptime = .wip;
33852 for (union_obj.fields.values()) |field| {
33853 if (try sema.typeRequiresComptime(field.ty)) {
33854 union_obj.requires_comptime = .yes;
33855 return true;
33856 }
33857 }
33858 union_obj.requires_comptime = .no;
33859 return false;
33860 },
33861 }
33862 },
33863
33841 .opaque_type => false,33864 .opaque_type => false,
3384233865
33843 // values, not types33866 // values, not types
33867 .un => unreachable,
33844 .simple_value => unreachable,33868 .simple_value => unreachable,
33845 .extern_func => unreachable,33869 .extern_func => unreachable,
33846 .int => unreachable,33870 .int => unreachable,
...@@ -33905,8 +33929,9 @@ fn unionFieldIndex(...@@ -33905,8 +33929,9 @@ fn unionFieldIndex(
33905 field_name: []const u8,33929 field_name: []const u8,
33906 field_src: LazySrcLoc,33930 field_src: LazySrcLoc,
33907) !u32 {33931) !u32 {
33932 const mod = sema.mod;
33908 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);33933 const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
33909 const union_obj = union_ty.cast(Type.Payload.Union).?.data;33934 const union_obj = mod.typeToUnion(union_ty).?;
33910 const field_index_usize = union_obj.fields.getIndex(field_name) orelse33935 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
33911 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);33936 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
33912 return @intCast(u32, field_index_usize);33937 return @intCast(u32, field_index_usize);
src/TypedValue.zig+2-2
...@@ -91,7 +91,7 @@ pub fn print(...@@ -91,7 +91,7 @@ pub fn print(
91 try writer.writeAll(".{ ");91 try writer.writeAll(".{ ");
9292
93 try print(.{93 try print(.{
94 .ty = ty.cast(Type.Payload.Union).?.data.tag_ty,94 .ty = mod.unionPtr(mod.intern_pool.indexToKey(ty.ip_index).union_type.index).tag_ty,
95 .val = union_val.tag,95 .val = union_val.tag,
96 }, writer, level - 1, mod);96 }, writer, level - 1, mod);
97 try writer.writeAll(" = ");97 try writer.writeAll(" = ");
...@@ -185,7 +185,7 @@ pub fn print(...@@ -185,7 +185,7 @@ pub fn print(
185 },185 },
186 }186 }
187 } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {187 } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
188 const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];188 const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index];
189 return writer.print(".{s}", .{field_name});189 return writer.print(".{s}", .{field_name});
190 } else if (field_ptr.container_ty.isSlice(mod)) {190 } else if (field_ptr.container_ty.isSlice(mod)) {
191 switch (field_ptr.field_index) {191 switch (field_ptr.field_index) {
src/arch/aarch64/abi.zig+2-2
...@@ -79,7 +79,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {...@@ -79,7 +79,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
79 const invalid = std.math.maxInt(u8);79 const invalid = std.math.maxInt(u8);
80 switch (ty.zigTypeTag(mod)) {80 switch (ty.zigTypeTag(mod)) {
81 .Union => {81 .Union => {
82 const fields = ty.unionFields();82 const fields = ty.unionFields(mod);
83 var max_count: u8 = 0;83 var max_count: u8 = 0;
84 for (fields.values()) |field| {84 for (fields.values()) |field| {
85 const field_count = countFloats(field.ty, mod, maybe_float_bits);85 const field_count = countFloats(field.ty, mod, maybe_float_bits);
...@@ -118,7 +118,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {...@@ -118,7 +118,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
118pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {118pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {
119 switch (ty.zigTypeTag(mod)) {119 switch (ty.zigTypeTag(mod)) {
120 .Union => {120 .Union => {
121 const fields = ty.unionFields();121 const fields = ty.unionFields(mod);
122 for (fields.values()) |field| {122 for (fields.values()) |field| {
123 if (getFloatArrayType(field.ty, mod)) |some| return some;123 if (getFloatArrayType(field.ty, mod)) |some| return some;
124 }124 }
src/arch/arm/abi.zig+2-2
...@@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
62 const float_count = countFloats(ty, mod, &maybe_float_bits);62 const float_count = countFloats(ty, mod, &maybe_float_bits);
63 if (float_count <= byval_float_count) return .byval;63 if (float_count <= byval_float_count) return .byval;
6464
65 for (ty.unionFields().values()) |field| {65 for (ty.unionFields(mod).values()) |field| {
66 if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) {66 if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) {
67 return Class.arrSize(bit_size, 64);67 return Class.arrSize(bit_size, 64);
68 }68 }
...@@ -121,7 +121,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 {...@@ -121,7 +121,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 {
121 const invalid = std.math.maxInt(u32);121 const invalid = std.math.maxInt(u32);
122 switch (ty.zigTypeTag(mod)) {122 switch (ty.zigTypeTag(mod)) {
123 .Union => {123 .Union => {
124 const fields = ty.unionFields();124 const fields = ty.unionFields(mod);
125 var max_count: u32 = 0;125 var max_count: u32 = 0;
126 for (fields.values()) |field| {126 for (fields.values()) |field| {
127 const field_count = countFloats(field.ty, mod, maybe_float_bits);127 const field_count = countFloats(field.ty, mod, maybe_float_bits);
src/arch/wasm/CodeGen.zig+5-5
...@@ -1739,8 +1739,8 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -1739,8 +1739,8 @@ fn isByRef(ty: Type, mod: *Module) bool {
1739 .Frame,1739 .Frame,
1740 => return ty.hasRuntimeBitsIgnoreComptime(mod),1740 => return ty.hasRuntimeBitsIgnoreComptime(mod),
1741 .Union => {1741 .Union => {
1742 if (ty.castTag(.@"union")) |union_ty| {1742 if (mod.typeToUnion(ty)) |union_obj| {
1743 if (union_ty.data.layout == .Packed) {1743 if (union_obj.layout == .Packed) {
1744 return ty.abiSize(mod) > 8;1744 return ty.abiSize(mod) > 8;
1745 }1745 }
1746 }1746 }
...@@ -3175,7 +3175,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3175,7 +3175,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3175 },3175 },
3176 .Union => {3176 .Union => {
3177 // in this case we have a packed union which will not be passed by reference.3177 // in this case we have a packed union which will not be passed by reference.
3178 const union_ty = ty.cast(Type.Payload.Union).?.data;3178 const union_ty = mod.typeToUnion(ty).?;
3179 const union_obj = val.castTag(.@"union").?.data;3179 const union_obj = val.castTag(.@"union").?.data;
3180 const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?;3180 const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?;
3181 const field_ty = union_ty.fields.values()[field_index].ty;3181 const field_ty = union_ty.fields.values()[field_index].ty;
...@@ -5086,12 +5086,12 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5086,12 +5086,12 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5086 const result = result: {5086 const result = result: {
5087 const union_ty = func.typeOfIndex(inst);5087 const union_ty = func.typeOfIndex(inst);
5088 const layout = union_ty.unionGetLayout(mod);5088 const layout = union_ty.unionGetLayout(mod);
5089 const union_obj = union_ty.cast(Type.Payload.Union).?.data;5089 const union_obj = mod.typeToUnion(union_ty).?;
5090 const field = union_obj.fields.values()[extra.field_index];5090 const field = union_obj.fields.values()[extra.field_index];
5091 const field_name = union_obj.fields.keys()[extra.field_index];5091 const field_name = union_obj.fields.keys()[extra.field_index];
50925092
5093 const tag_int = blk: {5093 const tag_int = blk: {
5094 const tag_ty = union_ty.unionTagTypeHypothetical();5094 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
5095 const enum_field_index = tag_ty.enumFieldIndex(field_name).?;5095 const enum_field_index = tag_ty.enumFieldIndex(field_name).?;
5096 var tag_val_payload: Value.Payload.U32 = .{5096 var tag_val_payload: Value.Payload.U32 = .{
5097 .base = .{ .tag = .enum_field_index },5097 .base = .{ .tag = .enum_field_index },
src/arch/wasm/abi.zig+5-5
...@@ -70,8 +70,8 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {...@@ -70,8 +70,8 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
70 }70 }
71 const layout = ty.unionGetLayout(mod);71 const layout = ty.unionGetLayout(mod);
72 std.debug.assert(layout.tag_size == 0);72 std.debug.assert(layout.tag_size == 0);
73 if (ty.unionFields().count() > 1) return memory;73 if (ty.unionFields(mod).count() > 1) return memory;
74 return classifyType(ty.unionFields().values()[0].ty, mod);74 return classifyType(ty.unionFields(mod).values()[0].ty, mod);
75 },75 },
76 .ErrorUnion,76 .ErrorUnion,
77 .Frame,77 .Frame,
...@@ -111,11 +111,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {...@@ -111,11 +111,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
111 if (ty.containerLayout(mod) != .Packed) {111 if (ty.containerLayout(mod) != .Packed) {
112 const layout = ty.unionGetLayout(mod);112 const layout = ty.unionGetLayout(mod);
113 if (layout.payload_size == 0 and layout.tag_size != 0) {113 if (layout.payload_size == 0 and layout.tag_size != 0) {
114 return scalarType(ty.unionTagTypeSafety().?, mod);114 return scalarType(ty.unionTagTypeSafety(mod).?, mod);
115 }115 }
116 std.debug.assert(ty.unionFields().count() == 1);116 std.debug.assert(ty.unionFields(mod).count() == 1);
117 }117 }
118 return scalarType(ty.unionFields().values()[0].ty, mod);118 return scalarType(ty.unionFields(mod).values()[0].ty, mod);
119 },119 },
120 else => return ty,120 else => return ty,
121 }121 }
src/arch/x86_64/CodeGen.zig+2-2
...@@ -11410,9 +11410,9 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11410,9 +11410,9 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1141011410
11411 const dst_mcv = try self.allocRegOrMem(inst, false);11411 const dst_mcv = try self.allocRegOrMem(inst, false);
1141211412
11413 const union_obj = union_ty.cast(Type.Payload.Union).?.data;11413 const union_obj = mod.typeToUnion(union_ty).?;
11414 const field_name = union_obj.fields.keys()[extra.field_index];11414 const field_name = union_obj.fields.keys()[extra.field_index];
11415 const tag_ty = union_ty.unionTagTypeSafety().?;11415 const tag_ty = union_obj.tag_ty;
11416 const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);11416 const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
11417 var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };11417 var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };
11418 const tag_val = Value.initPayload(&tag_pl.base);11418 const tag_val = Value.initPayload(&tag_pl.base);
src/arch/x86_64/abi.zig+1-1
...@@ -338,7 +338,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -338,7 +338,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
338 if (ty_size > 64)338 if (ty_size > 64)
339 return memory_class;339 return memory_class;
340340
341 const fields = ty.unionFields();341 const fields = ty.unionFields(mod);
342 for (fields.values()) |field| {342 for (fields.values()) |field| {
343 if (field.abi_align != 0) {343 if (field.abi_align != 0) {
344 if (field.abi_align < field.ty.abiAlignment(mod)) {344 if (field.abi_align < field.ty.abiAlignment(mod)) {
src/codegen.zig+3-3
...@@ -568,7 +568,7 @@ pub fn generateSymbol(...@@ -568,7 +568,7 @@ pub fn generateSymbol(
568568
569 if (layout.payload_size == 0) {569 if (layout.payload_size == 0) {
570 return generateSymbol(bin_file, src_loc, .{570 return generateSymbol(bin_file, src_loc, .{
571 .ty = typed_value.ty.unionTagType().?,571 .ty = typed_value.ty.unionTagType(mod).?,
572 .val = union_obj.tag,572 .val = union_obj.tag,
573 }, code, debug_output, reloc_info);573 }, code, debug_output, reloc_info);
574 }574 }
...@@ -576,7 +576,7 @@ pub fn generateSymbol(...@@ -576,7 +576,7 @@ pub fn generateSymbol(
576 // Check if we should store the tag first.576 // Check if we should store the tag first.
577 if (layout.tag_align >= layout.payload_align) {577 if (layout.tag_align >= layout.payload_align) {
578 switch (try generateSymbol(bin_file, src_loc, .{578 switch (try generateSymbol(bin_file, src_loc, .{
579 .ty = typed_value.ty.unionTagType().?,579 .ty = typed_value.ty.unionTagType(mod).?,
580 .val = union_obj.tag,580 .val = union_obj.tag,
581 }, code, debug_output, reloc_info)) {581 }, code, debug_output, reloc_info)) {
582 .ok => {},582 .ok => {},
...@@ -584,7 +584,7 @@ pub fn generateSymbol(...@@ -584,7 +584,7 @@ pub fn generateSymbol(
584 }584 }
585 }585 }
586586
587 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;587 const union_ty = mod.typeToUnion(typed_value.ty).?;
588 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;588 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
589 assert(union_ty.haveFieldTypes());589 assert(union_ty.haveFieldTypes());
590 const field_ty = union_ty.fields.values()[field_index].ty;590 const field_ty = union_ty.fields.values()[field_index].ty;
src/codegen/c.zig+49-45
...@@ -853,7 +853,7 @@ pub const DeclGen = struct {...@@ -853,7 +853,7 @@ pub const DeclGen = struct {
853 }853 }
854854
855 try writer.writeByte('{');855 try writer.writeByte('{');
856 if (ty.unionTagTypeSafety()) |tag_ty| {856 if (ty.unionTagTypeSafety(mod)) |tag_ty| {
857 const layout = ty.unionGetLayout(mod);857 const layout = ty.unionGetLayout(mod);
858 if (layout.tag_size != 0) {858 if (layout.tag_size != 0) {
859 try writer.writeAll(" .tag = ");859 try writer.writeAll(" .tag = ");
...@@ -863,12 +863,12 @@ pub const DeclGen = struct {...@@ -863,12 +863,12 @@ pub const DeclGen = struct {
863 if (layout.tag_size != 0) try writer.writeByte(',');863 if (layout.tag_size != 0) try writer.writeByte(',');
864 try writer.writeAll(" .payload = {");864 try writer.writeAll(" .payload = {");
865 }865 }
866 for (ty.unionFields().values()) |field| {866 for (ty.unionFields(mod).values()) |field| {
867 if (!field.ty.hasRuntimeBits(mod)) continue;867 if (!field.ty.hasRuntimeBits(mod)) continue;
868 try dg.renderValue(writer, field.ty, val, initializer_type);868 try dg.renderValue(writer, field.ty, val, initializer_type);
869 break;869 break;
870 }870 }
871 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');871 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
872 return writer.writeByte('}');872 return writer.writeByte('}');
873 },873 },
874 .ErrorUnion => {874 .ErrorUnion => {
...@@ -1451,8 +1451,8 @@ pub const DeclGen = struct {...@@ -1451,8 +1451,8 @@ pub const DeclGen = struct {
1451 }1451 }
14521452
1453 const field_i = ty.unionTagFieldIndex(union_obj.tag, mod).?;1453 const field_i = ty.unionTagFieldIndex(union_obj.tag, mod).?;
1454 const field_ty = ty.unionFields().values()[field_i].ty;1454 const field_ty = ty.unionFields(mod).values()[field_i].ty;
1455 const field_name = ty.unionFields().keys()[field_i];1455 const field_name = ty.unionFields(mod).keys()[field_i];
1456 if (ty.containerLayout(mod) == .Packed) {1456 if (ty.containerLayout(mod) == .Packed) {
1457 if (field_ty.hasRuntimeBits(mod)) {1457 if (field_ty.hasRuntimeBits(mod)) {
1458 if (field_ty.isPtrAtRuntime(mod)) {1458 if (field_ty.isPtrAtRuntime(mod)) {
...@@ -1472,7 +1472,7 @@ pub const DeclGen = struct {...@@ -1472,7 +1472,7 @@ pub const DeclGen = struct {
1472 }1472 }
14731473
1474 try writer.writeByte('{');1474 try writer.writeByte('{');
1475 if (ty.unionTagTypeSafety()) |tag_ty| {1475 if (ty.unionTagTypeSafety(mod)) |tag_ty| {
1476 const layout = ty.unionGetLayout(mod);1476 const layout = ty.unionGetLayout(mod);
1477 if (layout.tag_size != 0) {1477 if (layout.tag_size != 0) {
1478 try writer.writeAll(" .tag = ");1478 try writer.writeAll(" .tag = ");
...@@ -1486,12 +1486,12 @@ pub const DeclGen = struct {...@@ -1486,12 +1486,12 @@ pub const DeclGen = struct {
1486 try writer.print(" .{ } = ", .{fmtIdent(field_name)});1486 try writer.print(" .{ } = ", .{fmtIdent(field_name)});
1487 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);1487 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
1488 try writer.writeByte(' ');1488 try writer.writeByte(' ');
1489 } else for (ty.unionFields().values()) |field| {1489 } else for (ty.unionFields(mod).values()) |field| {
1490 if (!field.ty.hasRuntimeBits(mod)) continue;1490 if (!field.ty.hasRuntimeBits(mod)) continue;
1491 try dg.renderValue(writer, field.ty, Value.undef, initializer_type);1491 try dg.renderValue(writer, field.ty, Value.undef, initializer_type);
1492 break;1492 break;
1493 }1493 }
1494 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');1494 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
1495 try writer.writeByte('}');1495 try writer.writeByte('}');
1496 },1496 },
14971497
...@@ -5238,13 +5238,13 @@ fn fieldLocation(...@@ -5238,13 +5238,13 @@ fn fieldLocation(
5238 .Auto, .Extern => {5238 .Auto, .Extern => {
5239 const field_ty = container_ty.structFieldType(field_index, mod);5239 const field_ty = container_ty.structFieldType(field_index, mod);
5240 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))5240 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
5241 return if (container_ty.unionTagTypeSafety() != null and5241 return if (container_ty.unionTagTypeSafety(mod) != null and
5242 !container_ty.unionHasAllZeroBitFieldTypes(mod))5242 !container_ty.unionHasAllZeroBitFieldTypes(mod))
5243 .{ .field = .{ .identifier = "payload" } }5243 .{ .field = .{ .identifier = "payload" } }
5244 else5244 else
5245 .begin;5245 .begin;
5246 const field_name = container_ty.unionFields().keys()[field_index];5246 const field_name = container_ty.unionFields(mod).keys()[field_index];
5247 return .{ .field = if (container_ty.unionTagTypeSafety()) |_|5247 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
5248 .{ .payload_identifier = field_name }5248 .{ .payload_identifier = field_name }
5249 else5249 else
5250 .{ .identifier = field_name } };5250 .{ .identifier = field_name } };
...@@ -5424,37 +5424,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5424,37 +5424,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5424 else5424 else
5425 .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) },5425 .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) },
54265426
5427 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout(mod) == .Packed) {
5428 const operand_lval = if (struct_byval == .constant) blk: {
5429 const operand_local = try f.allocLocal(inst, struct_ty);
5430 try f.writeCValue(writer, operand_local, .Other);
5431 try writer.writeAll(" = ");
5432 try f.writeCValue(writer, struct_byval, .Initializer);
5433 try writer.writeAll(";\n");
5434 break :blk operand_local;
5435 } else struct_byval;
5436
5437 const local = try f.allocLocal(inst, inst_ty);
5438 try writer.writeAll("memcpy(&");
5439 try f.writeCValue(writer, local, .Other);
5440 try writer.writeAll(", &");
5441 try f.writeCValue(writer, operand_lval, .Other);
5442 try writer.writeAll(", sizeof(");
5443 try f.renderType(writer, inst_ty);
5444 try writer.writeAll("));\n");
5445
5446 if (struct_byval == .constant) {
5447 try freeLocal(f, inst, operand_lval.new_local, 0);
5448 }
5449
5450 return local;
5451 } else field_name: {
5452 const name = struct_ty.unionFields().keys()[extra.field_index];
5453 break :field_name if (struct_ty.unionTagTypeSafety()) |_|
5454 .{ .payload_identifier = name }
5455 else
5456 .{ .identifier = name };
5457 },
5458 else => unreachable,5427 else => unreachable,
5459 },5428 },
5460 else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) {5429 else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) {
...@@ -5520,6 +5489,41 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5520,6 +5489,41 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5520 return local;5489 return local;
5521 },5490 },
5522 },5491 },
5492 .union_type => |union_type| field_name: {
5493 const union_obj = mod.unionPtr(union_type.index);
5494 if (union_obj.layout == .Packed) {
5495 const operand_lval = if (struct_byval == .constant) blk: {
5496 const operand_local = try f.allocLocal(inst, struct_ty);
5497 try f.writeCValue(writer, operand_local, .Other);
5498 try writer.writeAll(" = ");
5499 try f.writeCValue(writer, struct_byval, .Initializer);
5500 try writer.writeAll(";\n");
5501 break :blk operand_local;
5502 } else struct_byval;
5503
5504 const local = try f.allocLocal(inst, inst_ty);
5505 try writer.writeAll("memcpy(&");
5506 try f.writeCValue(writer, local, .Other);
5507 try writer.writeAll(", &");
5508 try f.writeCValue(writer, operand_lval, .Other);
5509 try writer.writeAll(", sizeof(");
5510 try f.renderType(writer, inst_ty);
5511 try writer.writeAll("));\n");
5512
5513 if (struct_byval == .constant) {
5514 try freeLocal(f, inst, operand_lval.new_local, 0);
5515 }
5516
5517 return local;
5518 } else {
5519 const name = union_obj.fields.keys()[extra.field_index];
5520 break :field_name if (union_type.hasTag()) .{
5521 .payload_identifier = name,
5522 } else .{
5523 .identifier = name,
5524 };
5525 }
5526 },
5523 else => unreachable,5527 else => unreachable,
5524 },5528 },
5525 };5529 };
...@@ -6461,7 +6465,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6461,7 +6465,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6461 const union_ty = f.typeOf(bin_op.lhs).childType(mod);6465 const union_ty = f.typeOf(bin_op.lhs).childType(mod);
6462 const layout = union_ty.unionGetLayout(mod);6466 const layout = union_ty.unionGetLayout(mod);
6463 if (layout.tag_size == 0) return .none;6467 if (layout.tag_size == 0) return .none;
6464 const tag_ty = union_ty.unionTagTypeSafety().?;6468 const tag_ty = union_ty.unionTagTypeSafety(mod).?;
64656469
6466 const writer = f.object.writer();6470 const writer = f.object.writer();
6467 const a = try Assignment.start(f, writer, tag_ty);6471 const a = try Assignment.start(f, writer, tag_ty);
...@@ -6907,7 +6911,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6907,7 +6911,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6907 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;6911 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
69086912
6909 const union_ty = f.typeOfIndex(inst);6913 const union_ty = f.typeOfIndex(inst);
6910 const union_obj = union_ty.cast(Type.Payload.Union).?.data;6914 const union_obj = mod.typeToUnion(union_ty).?;
6911 const field_name = union_obj.fields.keys()[extra.field_index];6915 const field_name = union_obj.fields.keys()[extra.field_index];
6912 const payload_ty = f.typeOf(extra.init);6916 const payload_ty = f.typeOf(extra.init);
6913 const payload = try f.resolveInst(extra.init);6917 const payload = try f.resolveInst(extra.init);
...@@ -6923,7 +6927,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6923,7 +6927,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6923 return local;6927 return local;
6924 }6928 }
69256929
6926 const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: {6930 const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: {
6927 const layout = union_ty.unionGetLayout(mod);6931 const layout = union_ty.unionGetLayout(mod);
6928 if (layout.tag_size != 0) {6932 if (layout.tag_size != 0) {
6929 const field_index = tag_ty.enumFieldIndex(field_name).?;6933 const field_index = tag_ty.enumFieldIndex(field_name).?;
src/codegen/c/type.zig+13-13
...@@ -303,7 +303,7 @@ pub const CType = extern union {...@@ -303,7 +303,7 @@ pub const CType = extern union {
303 );303 );
304 }304 }
305 pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {305 pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {
306 const union_obj = union_ty.cast(Type.Payload.Union).?.data;306 const union_obj = mod.typeToUnion(union_ty).?;
307 const union_payload_align = union_obj.abiAlignment(mod, false);307 const union_payload_align = union_obj.abiAlignment(mod, false);
308 return init(union_payload_align, union_payload_align);308 return init(union_payload_align, union_payload_align);
309 }309 }
...@@ -1498,7 +1498,7 @@ pub const CType = extern union {...@@ -1498,7 +1498,7 @@ pub const CType = extern union {
1498 if (lookup.isMutable()) {1498 if (lookup.isMutable()) {
1499 for (0..switch (zig_ty_tag) {1499 for (0..switch (zig_ty_tag) {
1500 .Struct => ty.structFieldCount(mod),1500 .Struct => ty.structFieldCount(mod),
1501 .Union => ty.unionFields().count(),1501 .Union => ty.unionFields(mod).count(),
1502 else => unreachable,1502 else => unreachable,
1503 }) |field_i| {1503 }) |field_i| {
1504 const field_ty = ty.structFieldType(field_i, mod);1504 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1531,7 +1531,7 @@ pub const CType = extern union {...@@ -1531,7 +1531,7 @@ pub const CType = extern union {
1531 .payload => unreachable,1531 .payload => unreachable,
1532 });1532 });
1533 } else {1533 } else {
1534 const tag_ty = ty.unionTagTypeSafety();1534 const tag_ty = ty.unionTagTypeSafety(mod);
1535 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;1535 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1536 const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;1536 const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
1537 switch (kind) {1537 switch (kind) {
...@@ -1580,7 +1580,7 @@ pub const CType = extern union {...@@ -1580,7 +1580,7 @@ pub const CType = extern union {
1580 var is_packed = false;1580 var is_packed = false;
1581 for (0..switch (zig_ty_tag) {1581 for (0..switch (zig_ty_tag) {
1582 .Struct => ty.structFieldCount(mod),1582 .Struct => ty.structFieldCount(mod),
1583 .Union => ty.unionFields().count(),1583 .Union => ty.unionFields(mod).count(),
1584 else => unreachable,1584 else => unreachable,
1585 }) |field_i| {1585 }) |field_i| {
1586 const field_ty = ty.structFieldType(field_i, mod);1586 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1930,7 +1930,7 @@ pub const CType = extern union {...@@ -1930,7 +1930,7 @@ pub const CType = extern union {
1930 const zig_ty_tag = ty.zigTypeTag(mod);1930 const zig_ty_tag = ty.zigTypeTag(mod);
1931 const fields_len = switch (zig_ty_tag) {1931 const fields_len = switch (zig_ty_tag) {
1932 .Struct => ty.structFieldCount(mod),1932 .Struct => ty.structFieldCount(mod),
1933 .Union => ty.unionFields().count(),1933 .Union => ty.unionFields(mod).count(),
1934 else => unreachable,1934 else => unreachable,
1935 };1935 };
19361936
...@@ -1956,7 +1956,7 @@ pub const CType = extern union {...@@ -1956,7 +1956,7 @@ pub const CType = extern union {
1956 else1956 else
1957 arena.dupeZ(u8, switch (zig_ty_tag) {1957 arena.dupeZ(u8, switch (zig_ty_tag) {
1958 .Struct => ty.structFieldName(field_i, mod),1958 .Struct => ty.structFieldName(field_i, mod),
1959 .Union => ty.unionFields().keys()[field_i],1959 .Union => ty.unionFields(mod).keys()[field_i],
1960 else => unreachable,1960 else => unreachable,
1961 }),1961 }),
1962 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {1962 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {
...@@ -1986,7 +1986,7 @@ pub const CType = extern union {...@@ -1986,7 +1986,7 @@ pub const CType = extern union {
1986 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{1986 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
1987 .fields = fields_pl,1987 .fields = fields_pl,
1988 .owner_decl = ty.getOwnerDecl(mod),1988 .owner_decl = ty.getOwnerDecl(mod),
1989 .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,1989 .id = if (ty.unionTagTypeSafety(mod)) |_| 0 else unreachable,
1990 } };1990 } };
1991 return initPayload(unnamed_pl);1991 return initPayload(unnamed_pl);
1992 },1992 },
...@@ -2085,7 +2085,7 @@ pub const CType = extern union {...@@ -2085,7 +2085,7 @@ pub const CType = extern union {
2085 var c_field_i: usize = 0;2085 var c_field_i: usize = 0;
2086 for (0..switch (zig_ty_tag) {2086 for (0..switch (zig_ty_tag) {
2087 .Struct => ty.structFieldCount(mod),2087 .Struct => ty.structFieldCount(mod),
2088 .Union => ty.unionFields().count(),2088 .Union => ty.unionFields(mod).count(),
2089 else => unreachable,2089 else => unreachable,
2090 }) |field_i| {2090 }) |field_i| {
2091 const field_ty = ty.structFieldType(field_i, mod);2091 const field_ty = ty.structFieldType(field_i, mod);
...@@ -2106,7 +2106,7 @@ pub const CType = extern union {...@@ -2106,7 +2106,7 @@ pub const CType = extern union {
2106 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable2106 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
2107 else switch (zig_ty_tag) {2107 else switch (zig_ty_tag) {
2108 .Struct => ty.structFieldName(field_i, mod),2108 .Struct => ty.structFieldName(field_i, mod),
2109 .Union => ty.unionFields().keys()[field_i],2109 .Union => ty.unionFields(mod).keys()[field_i],
2110 else => unreachable,2110 else => unreachable,
2111 },2111 },
2112 mem.span(c_field.name),2112 mem.span(c_field.name),
...@@ -2122,7 +2122,7 @@ pub const CType = extern union {...@@ -2122,7 +2122,7 @@ pub const CType = extern union {
2122 .packed_unnamed_union,2122 .packed_unnamed_union,
2123 => switch (self.kind) {2123 => switch (self.kind) {
2124 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,2124 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
2125 .payload => if (ty.unionTagTypeSafety()) |_| {2125 .payload => if (ty.unionTagTypeSafety(mod)) |_| {
2126 const data = cty.cast(Payload.Unnamed).?.data;2126 const data = cty.cast(Payload.Unnamed).?.data;
2127 return ty.getOwnerDecl(mod) == data.owner_decl and data.id == 0;2127 return ty.getOwnerDecl(mod) == data.owner_decl and data.id == 0;
2128 } else unreachable,2128 } else unreachable,
...@@ -2211,7 +2211,7 @@ pub const CType = extern union {...@@ -2211,7 +2211,7 @@ pub const CType = extern union {
2211 const zig_ty_tag = ty.zigTypeTag(mod);2211 const zig_ty_tag = ty.zigTypeTag(mod);
2212 for (0..switch (ty.zigTypeTag(mod)) {2212 for (0..switch (ty.zigTypeTag(mod)) {
2213 .Struct => ty.structFieldCount(mod),2213 .Struct => ty.structFieldCount(mod),
2214 .Union => ty.unionFields().count(),2214 .Union => ty.unionFields(mod).count(),
2215 else => unreachable,2215 else => unreachable,
2216 }) |field_i| {2216 }) |field_i| {
2217 const field_ty = ty.structFieldType(field_i, mod);2217 const field_ty = ty.structFieldType(field_i, mod);
...@@ -2228,7 +2228,7 @@ pub const CType = extern union {...@@ -2228,7 +2228,7 @@ pub const CType = extern union {
2228 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable2228 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
2229 else switch (zig_ty_tag) {2229 else switch (zig_ty_tag) {
2230 .Struct => ty.structFieldName(field_i, mod),2230 .Struct => ty.structFieldName(field_i, mod),
2231 .Union => ty.unionFields().keys()[field_i],2231 .Union => ty.unionFields(mod).keys()[field_i],
2232 else => unreachable,2232 else => unreachable,
2233 });2233 });
2234 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");2234 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
...@@ -2241,7 +2241,7 @@ pub const CType = extern union {...@@ -2241,7 +2241,7 @@ pub const CType = extern union {
2241 .packed_unnamed_union,2241 .packed_unnamed_union,
2242 => switch (self.kind) {2242 => switch (self.kind) {
2243 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,2243 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
2244 .payload => if (ty.unionTagTypeSafety()) |_| {2244 .payload => if (ty.unionTagTypeSafety(mod)) |_| {
2245 autoHash(hasher, ty.getOwnerDecl(mod));2245 autoHash(hasher, ty.getOwnerDecl(mod));
2246 autoHash(hasher, @as(u32, 0));2246 autoHash(hasher, @as(u32, 0));
2247 } else unreachable,2247 } else unreachable,
src/codegen/llvm.zig+7-7
...@@ -2178,7 +2178,7 @@ pub const Object = struct {...@@ -2178,7 +2178,7 @@ pub const Object = struct {
2178 break :blk fwd_decl;2178 break :blk fwd_decl;
2179 };2179 };
21802180
2181 const union_obj = ty.cast(Type.Payload.Union).?.data;2181 const union_obj = mod.typeToUnion(ty).?;
2182 if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {2182 if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
2183 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);2183 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
2184 dib.replaceTemporary(fwd_decl, union_di_ty);2184 dib.replaceTemporary(fwd_decl, union_di_ty);
...@@ -3063,7 +3063,7 @@ pub const DeclGen = struct {...@@ -3063,7 +3063,7 @@ pub const DeclGen = struct {
3063 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());3063 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
30643064
3065 const layout = t.unionGetLayout(mod);3065 const layout = t.unionGetLayout(mod);
3066 const union_obj = t.cast(Type.Payload.Union).?.data;3066 const union_obj = mod.typeToUnion(t).?;
30673067
3068 if (union_obj.layout == .Packed) {3068 if (union_obj.layout == .Packed) {
3069 const bitsize = @intCast(c_uint, t.bitSize(mod));3069 const bitsize = @intCast(c_uint, t.bitSize(mod));
...@@ -3797,11 +3797,11 @@ pub const DeclGen = struct {...@@ -3797,11 +3797,11 @@ pub const DeclGen = struct {
37973797
3798 if (layout.payload_size == 0) {3798 if (layout.payload_size == 0) {
3799 return lowerValue(dg, .{3799 return lowerValue(dg, .{
3800 .ty = tv.ty.unionTagTypeSafety().?,3800 .ty = tv.ty.unionTagTypeSafety(mod).?,
3801 .val = tag_and_val.tag,3801 .val = tag_and_val.tag,
3802 });3802 });
3803 }3803 }
3804 const union_obj = tv.ty.cast(Type.Payload.Union).?.data;3804 const union_obj = mod.typeToUnion(tv.ty).?;
3805 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;3805 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
3806 assert(union_obj.haveFieldTypes());3806 assert(union_obj.haveFieldTypes());
38073807
...@@ -3851,7 +3851,7 @@ pub const DeclGen = struct {...@@ -3851,7 +3851,7 @@ pub const DeclGen = struct {
3851 }3851 }
3852 }3852 }
3853 const llvm_tag_value = try lowerValue(dg, .{3853 const llvm_tag_value = try lowerValue(dg, .{
3854 .ty = tv.ty.unionTagTypeSafety().?,3854 .ty = tv.ty.unionTagTypeSafety(mod).?,
3855 .val = tag_and_val.tag,3855 .val = tag_and_val.tag,
3856 });3856 });
3857 var fields: [3]*llvm.Value = undefined;3857 var fields: [3]*llvm.Value = undefined;
...@@ -9410,7 +9410,7 @@ pub const FuncGen = struct {...@@ -9410,7 +9410,7 @@ pub const FuncGen = struct {
9410 const union_ty = self.typeOfIndex(inst);9410 const union_ty = self.typeOfIndex(inst);
9411 const union_llvm_ty = try self.dg.lowerType(union_ty);9411 const union_llvm_ty = try self.dg.lowerType(union_ty);
9412 const layout = union_ty.unionGetLayout(mod);9412 const layout = union_ty.unionGetLayout(mod);
9413 const union_obj = union_ty.cast(Type.Payload.Union).?.data;9413 const union_obj = mod.typeToUnion(union_ty).?;
94149414
9415 if (union_obj.layout == .Packed) {9415 if (union_obj.layout == .Packed) {
9416 const big_bits = union_ty.bitSize(mod);9416 const big_bits = union_ty.bitSize(mod);
...@@ -9427,7 +9427,7 @@ pub const FuncGen = struct {...@@ -9427,7 +9427,7 @@ pub const FuncGen = struct {
9427 }9427 }
94289428
9429 const tag_int = blk: {9429 const tag_int = blk: {
9430 const tag_ty = union_ty.unionTagTypeHypothetical();9430 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
9431 const union_field_name = union_obj.fields.keys()[extra.field_index];9431 const union_field_name = union_obj.fields.keys()[extra.field_index];
9432 const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;9432 const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
9433 var tag_val_payload: Value.Payload.U32 = .{9433 var tag_val_payload: Value.Payload.U32 = .{
src/codegen/spirv.zig+5-5
...@@ -755,10 +755,10 @@ pub const DeclGen = struct {...@@ -755,10 +755,10 @@ pub const DeclGen = struct {
755 const layout = ty.unionGetLayout(mod);755 const layout = ty.unionGetLayout(mod);
756756
757 if (layout.payload_size == 0) {757 if (layout.payload_size == 0) {
758 return try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);758 return try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
759 }759 }
760760
761 const union_ty = ty.cast(Type.Payload.Union).?.data;761 const union_ty = mod.typeToUnion(ty).?;
762 if (union_ty.layout == .Packed) {762 if (union_ty.layout == .Packed) {
763 return dg.todo("packed union constants", .{});763 return dg.todo("packed union constants", .{});
764 }764 }
...@@ -770,7 +770,7 @@ pub const DeclGen = struct {...@@ -770,7 +770,7 @@ pub const DeclGen = struct {
770 const tag_first = layout.tag_align >= layout.payload_align;770 const tag_first = layout.tag_align >= layout.payload_align;
771771
772 if (has_tag and tag_first) {772 if (has_tag and tag_first) {
773 try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);773 try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
774 }774 }
775775
776 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {776 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
...@@ -782,7 +782,7 @@ pub const DeclGen = struct {...@@ -782,7 +782,7 @@ pub const DeclGen = struct {
782 try self.addUndef(payload_padding_len);782 try self.addUndef(payload_padding_len);
783783
784 if (has_tag and !tag_first) {784 if (has_tag and !tag_first) {
785 try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);785 try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
786 }786 }
787787
788 try self.addUndef(layout.padding);788 try self.addUndef(layout.padding);
...@@ -1121,7 +1121,7 @@ pub const DeclGen = struct {...@@ -1121,7 +1121,7 @@ pub const DeclGen = struct {
1121 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {1121 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
1122 const mod = self.module;1122 const mod = self.module;
1123 const layout = ty.unionGetLayout(mod);1123 const layout = ty.unionGetLayout(mod);
1124 const union_ty = ty.cast(Type.Payload.Union).?.data;1124 const union_ty = mod.typeToUnion(ty).?;
11251125
1126 if (union_ty.layout == .Packed) {1126 if (union_ty.layout == .Packed) {
1127 return self.todo("packed union types", .{});1127 return self.todo("packed union types", .{});
src/link/Dwarf.zig+2-2
...@@ -432,7 +432,7 @@ pub const DeclState = struct {...@@ -432,7 +432,7 @@ pub const DeclState = struct {
432 },432 },
433 .Union => {433 .Union => {
434 const layout = ty.unionGetLayout(mod);434 const layout = ty.unionGetLayout(mod);
435 const union_obj = ty.cast(Type.Payload.Union).?.data;435 const union_obj = mod.typeToUnion(ty).?;
436 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;436 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
437 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;437 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
438 const is_tagged = layout.tag_size > 0;438 const is_tagged = layout.tag_size > 0;
...@@ -476,7 +476,7 @@ pub const DeclState = struct {...@@ -476,7 +476,7 @@ pub const DeclState = struct {
476 try dbg_info_buffer.writer().print("{s}\x00", .{union_name});476 try dbg_info_buffer.writer().print("{s}\x00", .{union_name});
477 }477 }
478478
479 const fields = ty.unionFields();479 const fields = ty.unionFields(mod);
480 for (fields.keys()) |field_name| {480 for (fields.keys()) |field_name| {
481 const field = fields.get(field_name).?;481 const field = fields.get(field_name).?;
482 if (!field.ty.hasRuntimeBits(mod)) continue;482 if (!field.ty.hasRuntimeBits(mod)) continue;
src/type.zig+176-223
...@@ -68,11 +68,6 @@ pub const Type = struct {...@@ -68,11 +68,6 @@ pub const Type = struct {
68 .enum_simple,68 .enum_simple,
69 .enum_numbered,69 .enum_numbered,
70 => return .Enum,70 => return .Enum,
71
72 .@"union",
73 .union_safety_tagged,
74 .union_tagged,
75 => return .Union,
76 },71 },
77 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {72 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
78 .int_type => return .Int,73 .int_type => return .Int,
...@@ -140,6 +135,7 @@ pub const Type = struct {...@@ -140,6 +135,7 @@ pub const Type = struct {
140 },135 },
141136
142 // values, not types137 // values, not types
138 .un => unreachable,
143 .extern_func => unreachable,139 .extern_func => unreachable,
144 .int => unreachable,140 .int => unreachable,
145 .ptr => unreachable,141 .ptr => unreachable,
...@@ -585,12 +581,6 @@ pub const Type = struct {...@@ -585,12 +581,6 @@ pub const Type = struct {
585 const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;581 const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;
586 return a_enum_obj == b_enum_obj;582 return a_enum_obj == b_enum_obj;
587 },583 },
588
589 .@"union", .union_safety_tagged, .union_tagged => {
590 const a_union_obj = a.cast(Payload.Union).?.data;
591 const b_union_obj = (b.cast(Payload.Union) orelse return false).data;
592 return a_union_obj == b_union_obj;
593 },
594 }584 }
595 }585 }
596586
...@@ -752,12 +742,6 @@ pub const Type = struct {...@@ -752,12 +742,6 @@ pub const Type = struct {
752 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);742 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
753 std.hash.autoHash(hasher, enum_obj);743 std.hash.autoHash(hasher, enum_obj);
754 },744 },
755
756 .@"union", .union_safety_tagged, .union_tagged => {
757 const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;
758 std.hash.autoHash(hasher, std.builtin.TypeId.Union);
759 std.hash.autoHash(hasher, union_obj);
760 },
761 }745 }
762 }746 }
763747
...@@ -935,7 +919,6 @@ pub const Type = struct {...@@ -935,7 +919,6 @@ pub const Type = struct {
935 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),919 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
936 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),920 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
937 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),921 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
938 .@"union", .union_safety_tagged, .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union),
939 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),922 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
940 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),923 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
941 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),924 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
...@@ -1011,12 +994,6 @@ pub const Type = struct {...@@ -1011,12 +994,6 @@ pub const Type = struct {
1011 while (true) {994 while (true) {
1012 const t = ty.tag();995 const t = ty.tag();
1013 switch (t) {996 switch (t) {
1014 .@"union", .union_safety_tagged, .union_tagged => {
1015 const union_obj = ty.cast(Payload.Union).?.data;
1016 return writer.print("({s} decl={d})", .{
1017 @tagName(t), union_obj.owner_decl,
1018 });
1019 },
1020 .enum_full, .enum_nonexhaustive => {997 .enum_full, .enum_nonexhaustive => {
1021 const enum_full = ty.cast(Payload.EnumFull).?.data;998 const enum_full = ty.cast(Payload.EnumFull).?.data;
1022 return writer.print("({s} decl={d})", .{999 return writer.print("({s} decl={d})", .{
...@@ -1221,11 +1198,6 @@ pub const Type = struct {...@@ -1221,11 +1198,6 @@ pub const Type = struct {
1221 .inferred_alloc_const => unreachable,1198 .inferred_alloc_const => unreachable,
1222 .inferred_alloc_mut => unreachable,1199 .inferred_alloc_mut => unreachable,
12231200
1224 .@"union", .union_safety_tagged, .union_tagged => {
1225 const union_obj = ty.cast(Payload.Union).?.data;
1226 const decl = mod.declPtr(union_obj.owner_decl);
1227 try decl.renderFullyQualifiedName(mod, writer);
1228 },
1229 .enum_full, .enum_nonexhaustive => {1201 .enum_full, .enum_nonexhaustive => {
1230 const enum_full = ty.cast(Payload.EnumFull).?.data;1202 const enum_full = ty.cast(Payload.EnumFull).?.data;
1231 const decl = mod.declPtr(enum_full.owner_decl);1203 const decl = mod.declPtr(enum_full.owner_decl);
...@@ -1518,13 +1490,18 @@ pub const Type = struct {...@@ -1518,13 +1490,18 @@ pub const Type = struct {
1518 }1490 }
1519 },1491 },
15201492
1521 .union_type => @panic("TODO"),1493 .union_type => |union_type| {
1494 const union_obj = mod.unionPtr(union_type.index);
1495 const decl = mod.declPtr(union_obj.owner_decl);
1496 try decl.renderFullyQualifiedName(mod, writer);
1497 },
1522 .opaque_type => |opaque_type| {1498 .opaque_type => |opaque_type| {
1523 const decl = mod.declPtr(opaque_type.decl);1499 const decl = mod.declPtr(opaque_type.decl);
1524 try decl.renderFullyQualifiedName(mod, writer);1500 try decl.renderFullyQualifiedName(mod, writer);
1525 },1501 },
15261502
1527 // values, not types1503 // values, not types
1504 .un => unreachable,
1528 .simple_value => unreachable,1505 .simple_value => unreachable,
1529 .extern_func => unreachable,1506 .extern_func => unreachable,
1530 .int => unreachable,1507 .int => unreachable,
...@@ -1627,45 +1604,6 @@ pub const Type = struct {...@@ -1627,45 +1604,6 @@ pub const Type = struct {
1627 return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);1604 return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
1628 },1605 },
16291606
1630 .@"union" => {
1631 const union_obj = ty.castTag(.@"union").?.data;
1632 if (union_obj.status == .field_types_wip) {
1633 // In this case, we guess that hasRuntimeBits() for this type is true,
1634 // and then later if our guess was incorrect, we emit a compile error.
1635 union_obj.assumed_runtime_bits = true;
1636 return true;
1637 }
1638 switch (strat) {
1639 .sema => |sema| _ = try sema.resolveTypeFields(ty),
1640 .eager => assert(union_obj.haveFieldTypes()),
1641 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
1642 }
1643 for (union_obj.fields.values()) |value| {
1644 if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
1645 return true;
1646 } else {
1647 return false;
1648 }
1649 },
1650 .union_safety_tagged, .union_tagged => {
1651 const union_obj = ty.cast(Payload.Union).?.data;
1652 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) {
1653 return true;
1654 }
1655
1656 switch (strat) {
1657 .sema => |sema| _ = try sema.resolveTypeFields(ty),
1658 .eager => assert(union_obj.haveFieldTypes()),
1659 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
1660 }
1661 for (union_obj.fields.values()) |value| {
1662 if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
1663 return true;
1664 } else {
1665 return false;
1666 }
1667 },
1668
1669 .array => return ty.arrayLen(mod) != 0 and1607 .array => return ty.arrayLen(mod) != 0 and
1670 try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),1608 try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
1671 .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),1609 .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
...@@ -1795,10 +1733,40 @@ pub const Type = struct {...@@ -1795,10 +1733,40 @@ pub const Type = struct {
1795 }1733 }
1796 },1734 },
17971735
1798 .union_type => @panic("TODO"),1736 .union_type => |union_type| {
1737 const union_obj = mod.unionPtr(union_type.index);
1738 switch (union_type.runtime_tag) {
1739 .none => {
1740 if (union_obj.status == .field_types_wip) {
1741 // In this case, we guess that hasRuntimeBits() for this type is true,
1742 // and then later if our guess was incorrect, we emit a compile error.
1743 union_obj.assumed_runtime_bits = true;
1744 return true;
1745 }
1746 },
1747 .safety, .tagged => {
1748 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) {
1749 return true;
1750 }
1751 },
1752 }
1753 switch (strat) {
1754 .sema => |sema| _ = try sema.resolveTypeFields(ty),
1755 .eager => assert(union_obj.haveFieldTypes()),
1756 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
1757 }
1758 for (union_obj.fields.values()) |value| {
1759 if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
1760 return true;
1761 } else {
1762 return false;
1763 }
1764 },
1765
1799 .opaque_type => true,1766 .opaque_type => true,
18001767
1801 // values, not types1768 // values, not types
1769 .un => unreachable,
1802 .simple_value => unreachable,1770 .simple_value => unreachable,
1803 .extern_func => unreachable,1771 .extern_func => unreachable,
1804 .int => unreachable,1772 .int => unreachable,
...@@ -1847,8 +1815,6 @@ pub const Type = struct {...@@ -1847,8 +1815,6 @@ pub const Type = struct {
1847 => ty.childType(mod).hasWellDefinedLayout(mod),1815 => ty.childType(mod).hasWellDefinedLayout(mod),
18481816
1849 .optional => ty.isPtrLikeOptional(mod),1817 .optional => ty.isPtrLikeOptional(mod),
1850 .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto,
1851 .union_tagged => false,
1852 },1818 },
1853 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {1819 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
1854 .int_type => true,1820 .int_type => true,
...@@ -1912,10 +1878,14 @@ pub const Type = struct {...@@ -1912,10 +1878,14 @@ pub const Type = struct {
1912 };1878 };
1913 return struct_obj.layout != .Auto;1879 return struct_obj.layout != .Auto;
1914 },1880 },
1915 .union_type => @panic("TODO"),1881 .union_type => |union_type| switch (union_type.runtime_tag) {
1882 .none, .safety => mod.unionPtr(union_type.index).layout != .Auto,
1883 .tagged => false,
1884 },
1916 .opaque_type => false,1885 .opaque_type => false,
19171886
1918 // values, not types1887 // values, not types
1888 .un => unreachable,
1919 .simple_value => unreachable,1889 .simple_value => unreachable,
1920 .extern_func => unreachable,1890 .extern_func => unreachable,
1921 .int => unreachable,1891 .int => unreachable,
...@@ -2146,14 +2116,6 @@ pub const Type = struct {...@@ -2146,14 +2116,6 @@ pub const Type = struct {
2146 const int_tag_ty = try ty.intTagType(mod);2116 const int_tag_ty = try ty.intTagType(mod);
2147 return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) };2117 return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) };
2148 },2118 },
2149 .@"union" => {
2150 const union_obj = ty.castTag(.@"union").?.data;
2151 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, false);
2152 },
2153 .union_safety_tagged, .union_tagged => {
2154 const union_obj = ty.cast(Payload.Union).?.data;
2155 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, true);
2156 },
21572119
2158 .inferred_alloc_const,2120 .inferred_alloc_const,
2159 .inferred_alloc_mut,2121 .inferred_alloc_mut,
...@@ -2312,10 +2274,14 @@ pub const Type = struct {...@@ -2312,10 +2274,14 @@ pub const Type = struct {
2312 }2274 }
2313 return AbiAlignmentAdvanced{ .scalar = big_align };2275 return AbiAlignmentAdvanced{ .scalar = big_align };
2314 },2276 },
2315 .union_type => @panic("TODO"),2277 .union_type => |union_type| {
2278 const union_obj = mod.unionPtr(union_type.index);
2279 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2280 },
2316 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },2281 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
23172282
2318 // values, not types2283 // values, not types
2284 .un => unreachable,
2319 .simple_value => unreachable,2285 .simple_value => unreachable,
2320 .extern_func => unreachable,2286 .extern_func => unreachable,
2321 .int => unreachable,2287 .int => unreachable,
...@@ -2508,14 +2474,6 @@ pub const Type = struct {...@@ -2508,14 +2474,6 @@ pub const Type = struct {
2508 const int_tag_ty = try ty.intTagType(mod);2474 const int_tag_ty = try ty.intTagType(mod);
2509 return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) };2475 return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) };
2510 },2476 },
2511 .@"union" => {
2512 const union_obj = ty.castTag(.@"union").?.data;
2513 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, false);
2514 },
2515 .union_safety_tagged, .union_tagged => {
2516 const union_obj = ty.cast(Payload.Union).?.data;
2517 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, true);
2518 },
25192477
2520 .array => {2478 .array => {
2521 const payload = ty.castTag(.array).?.data;2479 const payload = ty.castTag(.array).?.data;
...@@ -2737,10 +2695,14 @@ pub const Type = struct {...@@ -2737,10 +2695,14 @@ pub const Type = struct {
2737 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };2695 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
2738 },2696 },
2739 },2697 },
2740 .union_type => @panic("TODO"),2698 .union_type => |union_type| {
2699 const union_obj = mod.unionPtr(union_type.index);
2700 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
2701 },
2741 .opaque_type => unreachable, // no size available2702 .opaque_type => unreachable, // no size available
27422703
2743 // values, not types2704 // values, not types
2705 .un => unreachable,
2744 .simple_value => unreachable,2706 .simple_value => unreachable,
2745 .extern_func => unreachable,2707 .extern_func => unreachable,
2746 .int => unreachable,2708 .int => unreachable,
...@@ -2860,21 +2822,6 @@ pub const Type = struct {...@@ -2860,21 +2822,6 @@ pub const Type = struct {
2860 return try bitSizeAdvanced(int_tag_ty, mod, opt_sema);2822 return try bitSizeAdvanced(int_tag_ty, mod, opt_sema);
2861 },2823 },
28622824
2863 .@"union", .union_safety_tagged, .union_tagged => {
2864 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
2865 if (ty.containerLayout(mod) != .Packed) {
2866 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
2867 }
2868 const union_obj = ty.cast(Payload.Union).?.data;
2869 assert(union_obj.haveFieldTypes());
2870
2871 var size: u64 = 0;
2872 for (union_obj.fields.values()) |field| {
2873 size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema));
2874 }
2875 return size;
2876 },
2877
2878 .array => {2825 .array => {
2879 const payload = ty.castTag(.array).?.data;2826 const payload = ty.castTag(.array).?.data;
2880 const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));2827 const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));
...@@ -2996,10 +2943,24 @@ pub const Type = struct {...@@ -2996,10 +2943,24 @@ pub const Type = struct {
2996 return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);2943 return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);
2997 },2944 },
29982945
2999 .union_type => @panic("TODO"),2946 .union_type => |union_type| {
2947 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
2948 if (ty.containerLayout(mod) != .Packed) {
2949 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
2950 }
2951 const union_obj = mod.unionPtr(union_type.index);
2952 assert(union_obj.haveFieldTypes());
2953
2954 var size: u64 = 0;
2955 for (union_obj.fields.values()) |field| {
2956 size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema));
2957 }
2958 return size;
2959 },
3000 .opaque_type => unreachable,2960 .opaque_type => unreachable,
30012961
3002 // values, not types2962 // values, not types
2963 .un => unreachable,
3003 .simple_value => unreachable,2964 .simple_value => unreachable,
3004 .extern_func => unreachable,2965 .extern_func => unreachable,
3005 .int => unreachable,2966 .int => unreachable,
...@@ -3022,8 +2983,8 @@ pub const Type = struct {...@@ -3022,8 +2983,8 @@ pub const Type = struct {
3022 return true;2983 return true;
3023 },2984 },
3024 .Union => {2985 .Union => {
3025 if (ty.cast(Payload.Union)) |union_ty| {2986 if (mod.typeToUnion(ty)) |union_obj| {
3026 return union_ty.data.haveLayout();2987 return union_obj.haveLayout();
3027 }2988 }
3028 return true;2989 return true;
3029 },2990 },
...@@ -3413,76 +3374,71 @@ pub const Type = struct {...@@ -3413,76 +3374,71 @@ pub const Type = struct {
34133374
3414 /// Returns the tag type of a union, if the type is a union and it has a tag type.3375 /// Returns the tag type of a union, if the type is a union and it has a tag type.
3415 /// Otherwise, returns `null`.3376 /// Otherwise, returns `null`.
3416 pub fn unionTagType(ty: Type) ?Type {3377 pub fn unionTagType(ty: Type, mod: *Module) ?Type {
3417 return switch (ty.tag()) {3378 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
3418 .union_tagged => {3379 .union_type => |union_type| switch (union_type.runtime_tag) {
3419 const union_obj = ty.castTag(.union_tagged).?.data;3380 .tagged => {
3420 assert(union_obj.haveFieldTypes());3381 const union_obj = mod.unionPtr(union_type.index);
3421 return union_obj.tag_ty;3382 assert(union_obj.haveFieldTypes());
3383 return union_obj.tag_ty;
3384 },
3385 else => null,
3422 },3386 },
3423
3424 else => null,3387 else => null,
3425 };3388 };
3426 }3389 }
34273390
3428 /// Same as `unionTagType` but includes safety tag.3391 /// Same as `unionTagType` but includes safety tag.
3429 /// Codegen should use this version.3392 /// Codegen should use this version.
3430 pub fn unionTagTypeSafety(ty: Type) ?Type {3393 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
3431 return switch (ty.tag()) {3394 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
3432 .union_safety_tagged, .union_tagged => {3395 .union_type => |union_type| {
3433 const union_obj = ty.cast(Payload.Union).?.data;3396 if (!union_type.hasTag()) return null;
3397 const union_obj = mod.unionPtr(union_type.index);
3434 assert(union_obj.haveFieldTypes());3398 assert(union_obj.haveFieldTypes());
3435 return union_obj.tag_ty;3399 return union_obj.tag_ty;
3436 },3400 },
3437
3438 else => null,3401 else => null,
3439 };3402 };
3440 }3403 }
34413404
3442 /// Asserts the type is a union; returns the tag type, even if the tag will3405 /// Asserts the type is a union; returns the tag type, even if the tag will
3443 /// not be stored at runtime.3406 /// not be stored at runtime.
3444 pub fn unionTagTypeHypothetical(ty: Type) Type {3407 pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
3445 const union_obj = ty.cast(Payload.Union).?.data;3408 const union_obj = mod.typeToUnion(ty).?;
3446 assert(union_obj.haveFieldTypes());3409 assert(union_obj.haveFieldTypes());
3447 return union_obj.tag_ty;3410 return union_obj.tag_ty;
3448 }3411 }
34493412
3450 pub fn unionFields(ty: Type) Module.Union.Fields {3413 pub fn unionFields(ty: Type, mod: *Module) Module.Union.Fields {
3451 const union_obj = ty.cast(Payload.Union).?.data;3414 const union_obj = mod.typeToUnion(ty).?;
3452 assert(union_obj.haveFieldTypes());3415 assert(union_obj.haveFieldTypes());
3453 return union_obj.fields;3416 return union_obj.fields;
3454 }3417 }
34553418
3456 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {3419 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
3457 const union_obj = ty.cast(Payload.Union).?.data;3420 const union_obj = mod.typeToUnion(ty).?;
3458 const index = ty.unionTagFieldIndex(enum_tag, mod).?;3421 const index = ty.unionTagFieldIndex(enum_tag, mod).?;
3459 assert(union_obj.haveFieldTypes());3422 assert(union_obj.haveFieldTypes());
3460 return union_obj.fields.values()[index].ty;3423 return union_obj.fields.values()[index].ty;
3461 }3424 }
34623425
3463 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {3426 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
3464 const union_obj = ty.cast(Payload.Union).?.data;3427 const union_obj = mod.typeToUnion(ty).?;
3465 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;3428 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
3466 const name = union_obj.tag_ty.enumFieldName(index);3429 const name = union_obj.tag_ty.enumFieldName(index);
3467 return union_obj.fields.getIndex(name);3430 return union_obj.fields.getIndex(name);
3468 }3431 }
34693432
3470 pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {3433 pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
3471 return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes(mod);3434 const union_obj = mod.typeToUnion(ty).?;
3435 return union_obj.hasAllZeroBitFieldTypes(mod);
3472 }3436 }
34733437
3474 pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout {3438 pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout {
3475 switch (ty.tag()) {3439 const union_type = mod.intern_pool.indexToKey(ty.ip_index).union_type;
3476 .@"union" => {3440 const union_obj = mod.unionPtr(union_type.index);
3477 const union_obj = ty.castTag(.@"union").?.data;3441 return union_obj.getLayout(mod, union_type.hasTag());
3478 return union_obj.getLayout(mod, false);
3479 },
3480 .union_safety_tagged, .union_tagged => {
3481 const union_obj = ty.cast(Payload.Union).?.data;
3482 return union_obj.getLayout(mod, true);
3483 },
3484 else => unreachable,
3485 }
3486 }3442 }
34873443
3488 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {3444 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
...@@ -3490,9 +3446,6 @@ pub const Type = struct {...@@ -3490,9 +3446,6 @@ pub const Type = struct {
3490 .empty_struct_type => .Auto,3446 .empty_struct_type => .Auto,
3491 .none => switch (ty.tag()) {3447 .none => switch (ty.tag()) {
3492 .tuple, .anon_struct => .Auto,3448 .tuple, .anon_struct => .Auto,
3493 .@"union" => ty.castTag(.@"union").?.data.layout,
3494 .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout,
3495 .union_tagged => ty.castTag(.union_tagged).?.data.layout,
3496 else => unreachable,3449 else => unreachable,
3497 },3450 },
3498 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {3451 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
...@@ -3500,6 +3453,10 @@ pub const Type = struct {...@@ -3500,6 +3453,10 @@ pub const Type = struct {
3500 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;3453 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
3501 return struct_obj.layout;3454 return struct_obj.layout;
3502 },3455 },
3456 .union_type => |union_type| {
3457 const union_obj = mod.unionPtr(union_type.index);
3458 return union_obj.layout;
3459 },
3503 else => unreachable,3460 else => unreachable,
3504 },3461 },
3505 };3462 };
...@@ -3777,6 +3734,7 @@ pub const Type = struct {...@@ -3777,6 +3734,7 @@ pub const Type = struct {
3777 .opaque_type => unreachable,3734 .opaque_type => unreachable,
37783735
3779 // values, not types3736 // values, not types
3737 .un => unreachable,
3780 .simple_value => unreachable,3738 .simple_value => unreachable,
3781 .extern_func => unreachable,3739 .extern_func => unreachable,
3782 .int => unreachable,3740 .int => unreachable,
...@@ -4038,16 +3996,6 @@ pub const Type = struct {...@@ -4038,16 +3996,6 @@ pub const Type = struct {
4038 return null;3996 return null;
4039 }3997 }
4040 },3998 },
4041 .@"union", .union_safety_tagged, .union_tagged => {
4042 const union_obj = ty.cast(Payload.Union).?.data;
4043 const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;
4044 if (union_obj.fields.count() == 0) return Value.@"unreachable";
4045 const only_field = union_obj.fields.values()[0];
4046 const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;
4047 _ = tag_val;
4048 _ = val_val;
4049 return Value.empty_struct;
4050 },
40513999
4052 .array => {4000 .array => {
4053 if (ty.arrayLen(mod) == 0)4001 if (ty.arrayLen(mod) == 0)
...@@ -4153,10 +4101,23 @@ pub const Type = struct {...@@ -4153,10 +4101,23 @@ pub const Type = struct {
4153 return empty.toValue();4101 return empty.toValue();
4154 },4102 },
41554103
4156 .union_type => @panic("TODO"),4104 .union_type => |union_type| {
4105 const union_obj = mod.unionPtr(union_type.index);
4106 const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;
4107 if (union_obj.fields.count() == 0) return Value.@"unreachable";
4108 const only_field = union_obj.fields.values()[0];
4109 const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;
4110 const only = try mod.intern(.{ .un = .{
4111 .ty = ty.ip_index,
4112 .tag = tag_val.ip_index,
4113 .val = val_val.ip_index,
4114 } });
4115 return only.toValue();
4116 },
4157 .opaque_type => return null,4117 .opaque_type => return null,
41584118
4159 // values, not types4119 // values, not types
4120 .un => unreachable,
4160 .simple_value => unreachable,4121 .simple_value => unreachable,
4161 .extern_func => unreachable,4122 .extern_func => unreachable,
4162 .int => unreachable,4123 .int => unreachable,
...@@ -4216,20 +4177,6 @@ pub const Type = struct {...@@ -4216,20 +4177,6 @@ pub const Type = struct {
4216 return false;4177 return false;
4217 },4178 },
42184179
4219 .@"union", .union_safety_tagged, .union_tagged => {
4220 const union_obj = ty.cast(Type.Payload.Union).?.data;
4221 switch (union_obj.requires_comptime) {
4222 .wip, .unknown => {
4223 // Return false to avoid incorrect dependency loops.
4224 // This will be handled correctly once merged with
4225 // `Sema.typeRequiresComptime`.
4226 return false;
4227 },
4228 .no => return false,
4229 .yes => return true,
4230 }
4231 },
4232
4233 .error_union => return ty.errorUnionPayload().comptimeOnly(mod),4180 .error_union => return ty.errorUnionPayload().comptimeOnly(mod),
4234 .anyframe_T => {4181 .anyframe_T => {
4235 const child_ty = ty.castTag(.anyframe_T).?.data;4182 const child_ty = ty.castTag(.anyframe_T).?.data;
...@@ -4321,10 +4268,24 @@ pub const Type = struct {...@@ -4321,10 +4268,24 @@ pub const Type = struct {
4321 }4268 }
4322 },4269 },
43234270
4324 .union_type => @panic("TODO"),4271 .union_type => |union_type| {
4272 const union_obj = mod.unionPtr(union_type.index);
4273 switch (union_obj.requires_comptime) {
4274 .wip, .unknown => {
4275 // Return false to avoid incorrect dependency loops.
4276 // This will be handled correctly once merged with
4277 // `Sema.typeRequiresComptime`.
4278 return false;
4279 },
4280 .no => return false,
4281 .yes => return true,
4282 }
4283 },
4284
4325 .opaque_type => false,4285 .opaque_type => false,
43264286
4327 // values, not types4287 // values, not types
4288 .un => unreachable,
4328 .simple_value => unreachable,4289 .simple_value => unreachable,
4329 .extern_func => unreachable,4290 .extern_func => unreachable,
4330 .int => unreachable,4291 .int => unreachable,
...@@ -4378,15 +4339,13 @@ pub const Type = struct {...@@ -4378,15 +4339,13 @@ pub const Type = struct {
4378 .none => switch (ty.tag()) {4339 .none => switch (ty.tag()) {
4379 .enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),4340 .enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),
4380 .enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),4341 .enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),
4381 .@"union" => ty.castTag(.@"union").?.data.namespace.toOptional(),
4382 .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.namespace.toOptional(),
4383 .union_tagged => ty.castTag(.union_tagged).?.data.namespace.toOptional(),
4384
4385 else => .none,4342 else => .none,
4386 },4343 },
4387 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {4344 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4388 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),4345 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
4389 .struct_type => |struct_type| struct_type.namespace,4346 .struct_type => |struct_type| struct_type.namespace,
4347 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
4348
4390 else => .none,4349 else => .none,
4391 },4350 },
4392 };4351 };
...@@ -4474,20 +4433,23 @@ pub const Type = struct {...@@ -4474,20 +4433,23 @@ pub const Type = struct {
44744433
4475 /// Asserts the type is an enum or a union.4434 /// Asserts the type is an enum or a union.
4476 pub fn intTagType(ty: Type, mod: *Module) !Type {4435 pub fn intTagType(ty: Type, mod: *Module) !Type {
4477 switch (ty.tag()) {4436 return switch (ty.ip_index) {
4478 .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty,4437 .none => switch (ty.tag()) {
4479 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,4438 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.tag_ty,
4480 .enum_simple => {4439 .enum_numbered => ty.castTag(.enum_numbered).?.data.tag_ty,
4481 const enum_simple = ty.castTag(.enum_simple).?.data;4440 .enum_simple => {
4482 const field_count = enum_simple.fields.count();4441 const enum_simple = ty.castTag(.enum_simple).?.data;
4483 const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);4442 const field_count = enum_simple.fields.count();
4484 return mod.intType(.unsigned, bits);4443 const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
4444 return mod.intType(.unsigned, bits);
4445 },
4446 else => unreachable,
4485 },4447 },
4486 .union_tagged => {4448 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
4487 return ty.castTag(.union_tagged).?.data.tag_ty.intTagType(mod);4449 .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),
4450 else => unreachable,
4488 },4451 },
4489 else => unreachable,4452 };
4490 }
4491 }4453 }
44924454
4493 pub fn isNonexhaustiveEnum(ty: Type) bool {4455 pub fn isNonexhaustiveEnum(ty: Type) bool {
...@@ -4663,10 +4625,6 @@ pub const Type = struct {...@@ -4663,10 +4625,6 @@ pub const Type = struct {
4663 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {4625 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
4664 return switch (ty.ip_index) {4626 return switch (ty.ip_index) {
4665 .none => switch (ty.tag()) {4627 .none => switch (ty.tag()) {
4666 .@"union", .union_safety_tagged, .union_tagged => {
4667 const union_obj = ty.cast(Payload.Union).?.data;
4668 return union_obj.fields.values()[index].ty;
4669 },
4670 .tuple => return ty.castTag(.tuple).?.data.types[index],4628 .tuple => return ty.castTag(.tuple).?.data.types[index],
4671 .anon_struct => return ty.castTag(.anon_struct).?.data.types[index],4629 .anon_struct => return ty.castTag(.anon_struct).?.data.types[index],
4672 else => unreachable,4630 else => unreachable,
...@@ -4676,6 +4634,10 @@ pub const Type = struct {...@@ -4676,6 +4634,10 @@ pub const Type = struct {
4676 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;4634 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
4677 return struct_obj.fields.values()[index].ty;4635 return struct_obj.fields.values()[index].ty;
4678 },4636 },
4637 .union_type => |union_type| {
4638 const union_obj = mod.unionPtr(union_type.index);
4639 return union_obj.fields.values()[index].ty;
4640 },
4679 else => unreachable,4641 else => unreachable,
4680 },4642 },
4681 };4643 };
...@@ -4684,10 +4646,6 @@ pub const Type = struct {...@@ -4684,10 +4646,6 @@ pub const Type = struct {
4684 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {4646 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
4685 switch (ty.ip_index) {4647 switch (ty.ip_index) {
4686 .none => switch (ty.tag()) {4648 .none => switch (ty.tag()) {
4687 .@"union", .union_safety_tagged, .union_tagged => {
4688 const union_obj = ty.cast(Payload.Union).?.data;
4689 return union_obj.fields.values()[index].normalAlignment(mod);
4690 },
4691 .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod),4649 .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod),
4692 .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod),4650 .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod),
4693 else => unreachable,4651 else => unreachable,
...@@ -4698,6 +4656,10 @@ pub const Type = struct {...@@ -4698,6 +4656,10 @@ pub const Type = struct {
4698 assert(struct_obj.layout != .Packed);4656 assert(struct_obj.layout != .Packed);
4699 return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);4657 return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);
4700 },4658 },
4659 .union_type => |union_type| {
4660 const union_obj = mod.unionPtr(union_type.index);
4661 return union_obj.fields.values()[index].normalAlignment(mod);
4662 },
4701 else => unreachable,4663 else => unreachable,
4702 },4664 },
4703 }4665 }
...@@ -4889,18 +4851,6 @@ pub const Type = struct {...@@ -4889,18 +4851,6 @@ pub const Type = struct {
4889 return offset;4851 return offset;
4890 },4852 },
48914853
4892 .@"union" => return 0,
4893 .union_safety_tagged, .union_tagged => {
4894 const union_obj = ty.cast(Payload.Union).?.data;
4895 const layout = union_obj.getLayout(mod, true);
4896 if (layout.tag_align >= layout.payload_align) {
4897 // {Tag, Payload}
4898 return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
4899 } else {
4900 // {Payload, Tag}
4901 return 0;
4902 }
4903 },
4904 else => unreachable,4854 else => unreachable,
4905 },4855 },
4906 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {4856 else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
...@@ -4917,6 +4867,20 @@ pub const Type = struct {...@@ -4917,6 +4867,20 @@ pub const Type = struct {
4917 return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1));4867 return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1));
4918 },4868 },
49194869
4870 .union_type => |union_type| {
4871 if (!union_type.hasTag())
4872 return 0;
4873 const union_obj = mod.unionPtr(union_type.index);
4874 const layout = union_obj.getLayout(mod, true);
4875 if (layout.tag_align >= layout.payload_align) {
4876 // {Tag, Payload}
4877 return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
4878 } else {
4879 // {Payload, Tag}
4880 return 0;
4881 }
4882 },
4883
4920 else => unreachable,4884 else => unreachable,
4921 },4885 },
4922 }4886 }
...@@ -4946,10 +4910,6 @@ pub const Type = struct {...@@ -4946,10 +4910,6 @@ pub const Type = struct {
4946 const error_set = ty.castTag(.error_set).?.data;4910 const error_set = ty.castTag(.error_set).?.data;
4947 return error_set.srcLoc(mod);4911 return error_set.srcLoc(mod);
4948 },4912 },
4949 .@"union", .union_safety_tagged, .union_tagged => {
4950 const union_obj = ty.cast(Payload.Union).?.data;
4951 return union_obj.srcLoc(mod);
4952 },
49534913
4954 else => return null,4914 else => return null,
4955 },4915 },
...@@ -4958,7 +4918,10 @@ pub const Type = struct {...@@ -4958,7 +4918,10 @@ pub const Type = struct {
4958 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;4918 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
4959 return struct_obj.srcLoc(mod);4919 return struct_obj.srcLoc(mod);
4960 },4920 },
4961 .union_type => @panic("TODO"),4921 .union_type => |union_type| {
4922 const union_obj = mod.unionPtr(union_type.index);
4923 return union_obj.srcLoc(mod);
4924 },
4962 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),4925 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
4963 else => null,4926 else => null,
4964 },4927 },
...@@ -4985,10 +4948,6 @@ pub const Type = struct {...@@ -4985,10 +4948,6 @@ pub const Type = struct {
4985 const error_set = ty.castTag(.error_set).?.data;4948 const error_set = ty.castTag(.error_set).?.data;
4986 return error_set.owner_decl;4949 return error_set.owner_decl;
4987 },4950 },
4988 .@"union", .union_safety_tagged, .union_tagged => {
4989 const union_obj = ty.cast(Payload.Union).?.data;
4990 return union_obj.owner_decl;
4991 },
49924951
4993 else => return null,4952 else => return null,
4994 },4953 },
...@@ -4997,7 +4956,10 @@ pub const Type = struct {...@@ -4997,7 +4956,10 @@ pub const Type = struct {
4997 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;4956 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
4998 return struct_obj.owner_decl;4957 return struct_obj.owner_decl;
4999 },4958 },
5000 .union_type => @panic("TODO"),4959 .union_type => |union_type| {
4960 const union_obj = mod.unionPtr(union_type.index);
4961 return union_obj.owner_decl;
4962 },
5001 .opaque_type => |opaque_type| opaque_type.decl,4963 .opaque_type => |opaque_type| opaque_type.decl,
5002 else => null,4964 else => null,
5003 },4965 },
...@@ -5039,9 +5001,6 @@ pub const Type = struct {...@@ -5039,9 +5001,6 @@ pub const Type = struct {
5039 /// The type is the inferred error set of a specific function.5001 /// The type is the inferred error set of a specific function.
5040 error_set_inferred,5002 error_set_inferred,
5041 error_set_merged,5003 error_set_merged,
5042 @"union",
5043 union_safety_tagged,
5044 union_tagged,
5045 enum_simple,5004 enum_simple,
5046 enum_numbered,5005 enum_numbered,
5047 enum_full,5006 enum_full,
...@@ -5070,7 +5029,6 @@ pub const Type = struct {...@@ -5070,7 +5029,6 @@ pub const Type = struct {
5070 .function => Payload.Function,5029 .function => Payload.Function,
5071 .error_union => Payload.ErrorUnion,5030 .error_union => Payload.ErrorUnion,
5072 .error_set_single => Payload.Name,5031 .error_set_single => Payload.Name,
5073 .@"union", .union_safety_tagged, .union_tagged => Payload.Union,
5074 .enum_full, .enum_nonexhaustive => Payload.EnumFull,5032 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
5075 .enum_simple => Payload.EnumSimple,5033 .enum_simple => Payload.EnumSimple,
5076 .enum_numbered => Payload.EnumNumbered,5034 .enum_numbered => Payload.EnumNumbered,
...@@ -5373,11 +5331,6 @@ pub const Type = struct {...@@ -5373,11 +5331,6 @@ pub const Type = struct {
5373 };5331 };
5374 };5332 };
53755333
5376 pub const Union = struct {
5377 base: Payload,
5378 data: *Module.Union,
5379 };
5380
5381 pub const EnumFull = struct {5334 pub const EnumFull = struct {
5382 base: Payload,5335 base: Payload,
5383 data: *Module.EnumFull,5336 data: *Module.EnumFull,
src/value.zig+6-6
...@@ -715,7 +715,7 @@ pub const Value = struct {...@@ -715,7 +715,7 @@ pub const Value = struct {
715 }715 }
716716
717 pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {717 pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
718 if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(), mod);718 if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(mod), mod);
719719
720 const field_index = switch (val.tag()) {720 const field_index = switch (val.tag()) {
721 .enum_field_index => val.castTag(.enum_field_index).?.data,721 .enum_field_index => val.castTag(.enum_field_index).?.data,
...@@ -1138,7 +1138,7 @@ pub const Value = struct {...@@ -1138,7 +1138,7 @@ pub const Value = struct {
1138 .Extern => unreachable, // Handled in non-packed writeToMemory1138 .Extern => unreachable, // Handled in non-packed writeToMemory
1139 .Packed => {1139 .Packed => {
1140 const field_index = ty.unionTagFieldIndex(val.unionTag(), mod);1140 const field_index = ty.unionTagFieldIndex(val.unionTag(), mod);
1141 const field_type = ty.unionFields().values()[field_index.?].ty;1141 const field_type = ty.unionFields(mod).values()[field_index.?].ty;
1142 const field_val = try val.fieldValue(field_type, mod, field_index.?);1142 const field_val = try val.fieldValue(field_type, mod, field_index.?);
11431143
1144 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);1144 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
...@@ -2021,7 +2021,7 @@ pub const Value = struct {...@@ -2021,7 +2021,7 @@ pub const Value = struct {
2021 const b_union = b.castTag(.@"union").?.data;2021 const b_union = b.castTag(.@"union").?.data;
2022 switch (ty.containerLayout(mod)) {2022 switch (ty.containerLayout(mod)) {
2023 .Packed, .Extern => {2023 .Packed, .Extern => {
2024 const tag_ty = ty.unionTagTypeHypothetical();2024 const tag_ty = ty.unionTagTypeHypothetical(mod);
2025 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {2025 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
2026 // In this case, we must disregard mismatching tags and compare2026 // In this case, we must disregard mismatching tags and compare
2027 // based on the in-memory bytes of the payloads.2027 // based on the in-memory bytes of the payloads.
...@@ -2029,7 +2029,7 @@ pub const Value = struct {...@@ -2029,7 +2029,7 @@ pub const Value = struct {
2029 }2029 }
2030 },2030 },
2031 .Auto => {2031 .Auto => {
2032 const tag_ty = ty.unionTagTypeHypothetical();2032 const tag_ty = ty.unionTagTypeHypothetical(mod);
2033 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {2033 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
2034 return false;2034 return false;
2035 }2035 }
...@@ -2118,7 +2118,7 @@ pub const Value = struct {...@@ -2118,7 +2118,7 @@ pub const Value = struct {
2118 return false;2118 return false;
2119 }2119 }
2120 const field_name = tuple.names[0];2120 const field_name = tuple.names[0];
2121 const union_obj = ty.cast(Type.Payload.Union).?.data;2121 const union_obj = mod.typeToUnion(ty).?;
2122 const field_index = union_obj.fields.getIndex(field_name) orelse return false;2122 const field_index = union_obj.fields.getIndex(field_name) orelse return false;
2123 const tag_and_val = b.castTag(.@"union").?.data;2123 const tag_and_val = b.castTag(.@"union").?.data;
2124 var field_tag_buf: Value.Payload.U32 = .{2124 var field_tag_buf: Value.Payload.U32 = .{
...@@ -2297,7 +2297,7 @@ pub const Value = struct {...@@ -2297,7 +2297,7 @@ pub const Value = struct {
2297 },2297 },
2298 .Union => {2298 .Union => {
2299 const union_obj = val.cast(Payload.Union).?.data;2299 const union_obj = val.cast(Payload.Union).?.data;
2300 if (ty.unionTagType()) |tag_ty| {2300 if (ty.unionTagType(mod)) |tag_ty| {
2301 union_obj.tag.hash(tag_ty, hasher, mod);2301 union_obj.tag.hash(tag_ty, hasher, mod);
2302 }2302 }
2303 const active_field_ty = ty.unionFieldType(union_obj.tag, mod);2303 const active_field_ty = ty.unionFieldType(union_obj.tag, mod);