authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-21 14:27:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-22 13:54:14-07:00
logada0010471163a3accca8976185fbb6bb59c914f
treed5035071ea3cb73677e381c0052e137fded064ac
parent6a5463951f0aa11cbdd5575cc78e85cd2ed10b46

compiler: move unions into InternPool

There are a couple concepts here worth understanding: Key.UnionType - This type is available *before* resolving the union's fields. The enum tag type, number of fields, and field names, field types, and field alignments are not available with this. InternPool.UnionType - This one can be obtained from the above type with `InternPool.loadUnionType` which asserts that the union's enum tag type has been resolved. This one has all the information available. Additionally: * ZIR: Turn an unused bit into `any_aligned_fields` flag to help semantic analysis know whether a union has explicit alignment on any fields (usually not). * Sema: delete `resolveTypeRequiresComptime` which had the same type signature and near-duplicate logic to `typeRequiresComptime`. - Make opaque types not report comptime-only (this was inconsistent between the two implementations of this function). * Implement accepted proposal #12556 which is a breaking change.

27 files changed, 1396 insertions(+), 1358 deletions(-)

lib/std/dwarf/call_frame.zig+7-7
...@@ -69,16 +69,9 @@ pub const Instruction = union(Opcode) {...@@ -69,16 +69,9 @@ pub const Instruction = union(Opcode) {
69 register: u8,69 register: u8,
70 offset: u64,70 offset: u64,
71 },71 },
72 offset_extended: struct {
73 register: u8,
74 offset: u64,
75 },
76 restore: struct {72 restore: struct {
77 register: u8,73 register: u8,
78 },74 },
79 restore_extended: struct {
80 register: u8,
81 },
82 nop: void,75 nop: void,
83 set_loc: struct {76 set_loc: struct {
84 address: u64,77 address: u64,
...@@ -92,6 +85,13 @@ pub const Instruction = union(Opcode) {...@@ -92,6 +85,13 @@ pub const Instruction = union(Opcode) {
92 advance_loc4: struct {85 advance_loc4: struct {
93 delta: u32,86 delta: u32,
94 },87 },
88 offset_extended: struct {
89 register: u8,
90 offset: u64,
91 },
92 restore_extended: struct {
93 register: u8,
94 },
95 undefined: struct {95 undefined: struct {
96 register: u8,96 register: u8,
97 },97 },
lib/std/meta.zig+2-2
...@@ -614,9 +614,9 @@ test "std.meta.FieldEnum" {...@@ -614,9 +614,9 @@ test "std.meta.FieldEnum" {
614 const Tagged = union(enum) { a: u8, b: void, c: f32 };614 const Tagged = union(enum) { a: u8, b: void, c: f32 };
615 try testing.expectEqual(Tag(Tagged), FieldEnum(Tagged));615 try testing.expectEqual(Tag(Tagged), FieldEnum(Tagged));
616616
617 const Tag2 = enum { b, c, a };617 const Tag2 = enum { a, b, c };
618 const Tagged2 = union(Tag2) { a: u8, b: void, c: f32 };618 const Tagged2 = union(Tag2) { a: u8, b: void, c: f32 };
619 try testing.expect(Tag(Tagged2) != FieldEnum(Tagged2));619 try testing.expect(Tag(Tagged2) == FieldEnum(Tagged2));
620620
621 const Tag3 = enum(u8) { a, b, c = 7 };621 const Tag3 = enum(u8) { a, b, c = 7 };
622 const Tagged3 = union(Tag3) { a: u8, b: void, c: f32 };622 const Tagged3 = union(Tag3) { a: u8, b: void, c: f32 };
src/AstGen.zig+5
...@@ -4696,6 +4696,7 @@ fn unionDeclInner(...@@ -4696,6 +4696,7 @@ fn unionDeclInner(
46964696
4697 const bits_per_field = 4;4697 const bits_per_field = 4;
4698 const max_field_size = 5;4698 const max_field_size = 5;
4699 var any_aligned_fields = false;
4699 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);4700 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
4700 defer wip_members.deinit();4701 defer wip_members.deinit();
47014702
...@@ -4733,6 +4734,7 @@ fn unionDeclInner(...@@ -4733,6 +4734,7 @@ fn unionDeclInner(
4733 if (have_align) {4734 if (have_align) {
4734 const align_inst = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .u32_type } }, member.ast.align_expr);4735 const align_inst = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .u32_type } }, member.ast.align_expr);
4735 wip_members.appendToField(@intFromEnum(align_inst));4736 wip_members.appendToField(@intFromEnum(align_inst));
4737 any_aligned_fields = true;
4736 }4738 }
4737 if (have_value) {4739 if (have_value) {
4738 if (arg_inst == .none) {4740 if (arg_inst == .none) {
...@@ -4783,6 +4785,7 @@ fn unionDeclInner(...@@ -4783,6 +4785,7 @@ fn unionDeclInner(
4783 .fields_len = field_count,4785 .fields_len = field_count,
4784 .decls_len = decl_count,4786 .decls_len = decl_count,
4785 .auto_enum_tag = auto_enum_tok != null,4787 .auto_enum_tag = auto_enum_tok != null,
4788 .any_aligned_fields = any_aligned_fields,
4786 });4789 });
47874790
4788 wip_members.finishBits(bits_per_field);4791 wip_members.finishBits(bits_per_field);
...@@ -11754,6 +11757,7 @@ const GenZir = struct {...@@ -11754,6 +11757,7 @@ const GenZir = struct {
11754 decls_len: u32,11757 decls_len: u32,
11755 layout: std.builtin.Type.ContainerLayout,11758 layout: std.builtin.Type.ContainerLayout,
11756 auto_enum_tag: bool,11759 auto_enum_tag: bool,
11760 any_aligned_fields: bool,
11757 }) !void {11761 }) !void {
11758 const astgen = gz.astgen;11762 const astgen = gz.astgen;
11759 const gpa = astgen.gpa;11763 const gpa = astgen.gpa;
...@@ -11790,6 +11794,7 @@ const GenZir = struct {...@@ -11790,6 +11794,7 @@ const GenZir = struct {
11790 .name_strategy = gz.anon_name_strategy,11794 .name_strategy = gz.anon_name_strategy,
11791 .layout = args.layout,11795 .layout = args.layout,
11792 .auto_enum_tag = args.auto_enum_tag,11796 .auto_enum_tag = args.auto_enum_tag,
11797 .any_aligned_fields = args.any_aligned_fields,
11793 }),11798 }),
11794 .operand = payload_index,11799 .operand = payload_index,
11795 } },11800 } },
src/InternPool.zig+385-125
...@@ -46,13 +46,6 @@ allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},...@@ -46,13 +46,6 @@ allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},
46/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.46/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
47structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},47structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
4848
49/// Union objects are stored in this data structure because:
50/// * They contain pointers such as the field maps.
51/// * They need to be mutated after creation.
52allocated_unions: std.SegmentedList(Module.Union, 0) = .{},
53/// When a Union object is freed from `allocated_unions`, it is pushed into this stack.
54unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
55
56/// Some types such as enums, structs, and unions need to store mappings from field names49/// Some types such as enums, structs, and unions need to store mappings from field names
57/// to field index, or value to field index. In such cases, they will store the underlying50/// to field index, or value to field index. In such cases, they will store the underlying
58/// field names and values directly, relying on one of these maps, stored separately,51/// field names and values directly, relying on one of these maps, stored separately,
...@@ -241,7 +234,7 @@ pub const Key = union(enum) {...@@ -241,7 +234,7 @@ pub const Key = union(enum) {
241 /// declaration. It is used for types that have no `struct` keyword in the234 /// declaration. It is used for types that have no `struct` keyword in the
242 /// source code, and were not created via `@Type`.235 /// source code, and were not created via `@Type`.
243 anon_struct_type: AnonStructType,236 anon_struct_type: AnonStructType,
244 union_type: UnionType,237 union_type: Key.UnionType,
245 opaque_type: OpaqueType,238 opaque_type: OpaqueType,
246 enum_type: EnumType,239 enum_type: EnumType,
247 func_type: FuncType,240 func_type: FuncType,
...@@ -391,17 +384,72 @@ pub const Key = union(enum) {...@@ -391,17 +384,72 @@ pub const Key = union(enum) {
391 }384 }
392 };385 };
393386
387 /// Serves two purposes:
388 /// * Being the key in the InternPool hash map, which only requires the `decl` field.
389 /// * Provide the other fields that do not require chasing the enum type.
394 pub const UnionType = struct {390 pub const UnionType = struct {
395 index: Module.Union.Index,391 /// The Decl that corresponds to the union itself.
396 runtime_tag: RuntimeTag,392 decl: Module.Decl.Index,
393 /// The index of the `Tag.TypeUnion` payload. Ignored by `get`,
394 /// populated by `indexToKey`.
395 extra_index: u32,
396 namespace: Module.Namespace.Index,
397 flags: Tag.TypeUnion.Flags,
398 /// The enum that provides the list of field names and values.
399 enum_tag_ty: Index,
400 zir_index: Zir.Inst.Index,
401
402 /// The returned pointer expires with any addition to the `InternPool`.
403 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
404 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
405 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
406 }
397407
398 pub const RuntimeTag = enum { none, safety, tagged };408 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {
409 return self.flagsPtr(ip).status.haveFieldTypes();
410 }
399411
400 pub fn hasTag(self: UnionType) bool {412 pub fn hasTag(self: @This(), ip: *const InternPool) bool {
401 return switch (self.runtime_tag) {413 return self.flagsPtr(ip).runtime_tag.hasTag();
402 .none => false,414 }
403 .tagged, .safety => true,415
404 };416 pub fn getLayout(self: @This(), ip: *const InternPool) std.builtin.Type.ContainerLayout {
417 return self.flagsPtr(ip).layout;
418 }
419
420 pub fn haveLayout(self: @This(), ip: *const InternPool) bool {
421 return self.flagsPtr(ip).status.haveLayout();
422 }
423
424 /// Pointer to an enum type which is used for the tag of the union.
425 /// This type is created even for untagged unions, even when the memory
426 /// layout does not store the tag.
427 /// Whether zig chooses this type or the user specifies it, it is stored here.
428 /// This will be set to the null type until status is `have_field_types`.
429 /// This accessor is provided so that the tag type can be mutated, and so that
430 /// when it is mutated, the mutations are observed.
431 /// The returned pointer is invalidated when something is added to the `InternPool`.
432 pub fn tagTypePtr(self: @This(), ip: *const InternPool) *Index {
433 const tag_ty_field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?;
434 return @ptrCast(&ip.extra.items[self.extra_index + tag_ty_field_index]);
435 }
436
437 pub fn setFieldTypes(self: @This(), ip: *InternPool, types: []const Index) void {
438 @memcpy((Index.Slice{
439 .start = @intCast(self.extra_index + @typeInfo(Tag.TypeUnion).Struct.fields.len),
440 .len = @intCast(types.len),
441 }).get(ip), types);
442 }
443
444 pub fn setFieldAligns(self: @This(), ip: *InternPool, aligns: []const Alignment) void {
445 if (aligns.len == 0) return;
446 assert(self.flagsPtr(ip).any_aligned_fields);
447 @memcpy((Alignment.Slice{
448 .start = @intCast(
449 self.extra_index + @typeInfo(Tag.TypeUnion).Struct.fields.len + aligns.len,
450 ),
451 .len = @intCast(aligns.len),
452 }).get(ip), aligns);
405 }453 }
406 };454 };
407455
...@@ -833,7 +881,6 @@ pub const Key = union(enum) {...@@ -833,7 +881,6 @@ pub const Key = union(enum) {
833 => |x| Hash.hash(seed, asBytes(&x)),881 => |x| Hash.hash(seed, asBytes(&x)),
834882
835 .int_type => |x| Hash.hash(seed + @intFromEnum(x.signedness), asBytes(&x.bits)),883 .int_type => |x| Hash.hash(seed + @intFromEnum(x.signedness), asBytes(&x.bits)),
836 .union_type => |x| Hash.hash(seed + @intFromEnum(x.runtime_tag), asBytes(&x.index)),
837884
838 .error_union => |x| switch (x.val) {885 .error_union => |x| switch (x.val) {
839 .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),886 .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),
...@@ -845,6 +892,7 @@ pub const Key = union(enum) {...@@ -845,6 +892,7 @@ pub const Key = union(enum) {
845 inline .opaque_type,892 inline .opaque_type,
846 .enum_type,893 .enum_type,
847 .variable,894 .variable,
895 .union_type,
848 => |x| Hash.hash(seed, asBytes(&x.decl)),896 => |x| Hash.hash(seed, asBytes(&x.decl)),
849897
850 .int => |int| {898 .int => |int| {
...@@ -1079,10 +1127,6 @@ pub const Key = union(enum) {...@@ -1079,10 +1127,6 @@ pub const Key = union(enum) {
1079 const b_info = b.struct_type;1127 const b_info = b.struct_type;
1080 return std.meta.eql(a_info, b_info);1128 return std.meta.eql(a_info, b_info);
1081 },1129 },
1082 .union_type => |a_info| {
1083 const b_info = b.union_type;
1084 return std.meta.eql(a_info, b_info);
1085 },
1086 .un => |a_info| {1130 .un => |a_info| {
1087 const b_info = b.un;1131 const b_info = b.un;
1088 return std.meta.eql(a_info, b_info);1132 return std.meta.eql(a_info, b_info);
...@@ -1250,6 +1294,10 @@ pub const Key = union(enum) {...@@ -1250,6 +1294,10 @@ pub const Key = union(enum) {
1250 const b_info = b.enum_type;1294 const b_info = b.enum_type;
1251 return a_info.decl == b_info.decl;1295 return a_info.decl == b_info.decl;
1252 },1296 },
1297 .union_type => |a_info| {
1298 const b_info = b.union_type;
1299 return a_info.decl == b_info.decl;
1300 },
1253 .aggregate => |a_info| {1301 .aggregate => |a_info| {
1254 const b_info = b.aggregate;1302 const b_info = b.aggregate;
1255 if (a_info.ty != b_info.ty) return false;1303 if (a_info.ty != b_info.ty) return false;
...@@ -1385,6 +1433,158 @@ pub const Key = union(enum) {...@@ -1385,6 +1433,158 @@ pub const Key = union(enum) {
1385 }1433 }
1386};1434};
13871435
1436// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
1437// minimal hashmap key, this type is a convenience type that contains info
1438// needed by semantic analysis.
1439pub const UnionType = struct {
1440 /// The Decl that corresponds to the union itself.
1441 decl: Module.Decl.Index,
1442 /// Represents the declarations inside this union.
1443 namespace: Module.Namespace.Index,
1444 /// The enum tag type.
1445 enum_tag_ty: Index,
1446 /// The integer tag type of the enum.
1447 int_tag_ty: Index,
1448 /// List of field names in declaration order.
1449 field_names: NullTerminatedString.Slice,
1450 /// List of field types in declaration order.
1451 /// These are `none` until `status` is `have_field_types` or `have_layout`.
1452 field_types: Index.Slice,
1453 /// List of field alignments in declaration order.
1454 /// `none` means the ABI alignment of the type.
1455 /// If this slice has length 0 it means all elements are `none`.
1456 field_aligns: Alignment.Slice,
1457 /// Index of the union_decl ZIR instruction.
1458 zir_index: Zir.Inst.Index,
1459 /// Index into extra array of the `flags` field.
1460 flags_index: u32,
1461 /// Copied from `enum_tag_ty`.
1462 names_map: OptionalMapIndex,
1463
1464 pub const RuntimeTag = enum(u2) {
1465 none,
1466 safety,
1467 tagged,
1468
1469 pub fn hasTag(self: RuntimeTag) bool {
1470 return switch (self) {
1471 .none => false,
1472 .tagged, .safety => true,
1473 };
1474 }
1475 };
1476
1477 pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1478
1479 pub const Status = enum(u3) {
1480 none,
1481 field_types_wip,
1482 have_field_types,
1483 layout_wip,
1484 have_layout,
1485 fully_resolved_wip,
1486 /// The types and all its fields have had their layout resolved.
1487 /// Even through pointer, which `have_layout` does not ensure.
1488 fully_resolved,
1489
1490 pub fn haveFieldTypes(status: Status) bool {
1491 return switch (status) {
1492 .none,
1493 .field_types_wip,
1494 => false,
1495 .have_field_types,
1496 .layout_wip,
1497 .have_layout,
1498 .fully_resolved_wip,
1499 .fully_resolved,
1500 => true,
1501 };
1502 }
1503
1504 pub fn haveLayout(status: Status) bool {
1505 return switch (status) {
1506 .none,
1507 .field_types_wip,
1508 .have_field_types,
1509 .layout_wip,
1510 => false,
1511 .have_layout,
1512 .fully_resolved_wip,
1513 .fully_resolved,
1514 => true,
1515 };
1516 }
1517 };
1518
1519 /// The returned pointer expires with any addition to the `InternPool`.
1520 pub fn flagsPtr(self: UnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {
1521 return @ptrCast(&ip.extra.items[self.flags_index]);
1522 }
1523
1524 /// Look up field index based on field name.
1525 pub fn nameIndex(self: UnionType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
1526 const map = &ip.maps.items[@intFromEnum(self.names_map.unwrap().?)];
1527 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };
1528 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
1529 return @intCast(field_index);
1530 }
1531
1532 pub fn hasTag(self: UnionType, ip: *const InternPool) bool {
1533 return self.flagsPtr(ip).runtime_tag.hasTag();
1534 }
1535
1536 pub fn haveLayout(self: UnionType, ip: *const InternPool) bool {
1537 return self.flagsPtr(ip).status.haveLayout();
1538 }
1539
1540 pub fn getLayout(self: UnionType, ip: *const InternPool) std.builtin.Type.ContainerLayout {
1541 return self.flagsPtr(ip).layout;
1542 }
1543
1544 pub fn fieldAlign(self: UnionType, ip: *const InternPool, field_index: u32) Alignment {
1545 if (self.field_aligns.len == 0) return .none;
1546 return self.field_aligns.get(ip)[field_index];
1547 }
1548
1549 /// This does not mutate the field of UnionType.
1550 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
1551 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
1552 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
1553 const ptr: *Zir.Inst.Index =
1554 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
1555 ptr.* = new_zir_index;
1556 }
1557};
1558
1559/// Fetch all the interesting fields of a union type into a convenient data
1560/// structure.
1561/// This asserts that the union's enum tag type has been resolved.
1562pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType {
1563 const type_union = ip.extraDataTrail(Tag.TypeUnion, key.extra_index);
1564 const enum_ty = type_union.data.tag_ty;
1565 const enum_info = ip.indexToKey(enum_ty).enum_type;
1566 const fields_len: u32 = @intCast(enum_info.names.len);
1567
1568 return .{
1569 .decl = type_union.data.decl,
1570 .namespace = type_union.data.namespace,
1571 .enum_tag_ty = enum_ty,
1572 .int_tag_ty = enum_info.tag_ty,
1573 .field_names = enum_info.names,
1574 .names_map = enum_info.names_map,
1575 .field_types = .{
1576 .start = type_union.end,
1577 .len = fields_len,
1578 },
1579 .field_aligns = .{
1580 .start = type_union.end + fields_len,
1581 .len = if (type_union.data.flags.any_aligned_fields) fields_len else 0,
1582 },
1583 .zir_index = type_union.data.zir_index,
1584 .flags_index = key.extra_index + std.meta.fieldIndex(Tag.TypeUnion, "flags").?,
1585 };
1586}
1587
1388pub const Item = struct {1588pub const Item = struct {
1389 tag: Tag,1589 tag: Tag,
1390 /// The doc comments on the respective Tag explain how to interpret this.1590 /// The doc comments on the respective Tag explain how to interpret this.
...@@ -1618,9 +1818,7 @@ pub const Index = enum(u32) {...@@ -1618,9 +1818,7 @@ pub const Index = enum(u32) {
1618 type_struct_ns: struct { data: Module.Namespace.Index },1818 type_struct_ns: struct { data: Module.Namespace.Index },
1619 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,1819 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
1620 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,1820 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,
1621 type_union_tagged: struct { data: Module.Union.Index },1821 type_union: struct { data: *Tag.TypeUnion },
1622 type_union_untagged: struct { data: Module.Union.Index },
1623 type_union_safety: struct { data: Module.Union.Index },
1624 type_function: struct {1822 type_function: struct {
1625 const @"data.flags.has_comptime_bits" = opaque {};1823 const @"data.flags.has_comptime_bits" = opaque {};
1626 const @"data.flags.has_noalias_bits" = opaque {};1824 const @"data.flags.has_noalias_bits" = opaque {};
...@@ -2057,15 +2255,9 @@ pub const Tag = enum(u8) {...@@ -2057,15 +2255,9 @@ pub const Tag = enum(u8) {
2057 /// An AnonStructType which has only types and values for fields.2255 /// An AnonStructType which has only types and values for fields.
2058 /// data is extra index of `TypeStructAnon`.2256 /// data is extra index of `TypeStructAnon`.
2059 type_tuple_anon,2257 type_tuple_anon,
2060 /// A tagged union type.2258 /// A union type.
2061 /// `data` is `Module.Union.Index`.2259 /// `data` is extra index of `TypeUnion`.
2062 type_union_tagged,2260 type_union,
2063 /// An untagged union type. It also has no safety tag.
2064 /// `data` is `Module.Union.Index`.
2065 type_union_untagged,
2066 /// An untagged union type which has a safety tag.
2067 /// `data` is `Module.Union.Index`.
2068 type_union_safety,
2069 /// A function body type.2261 /// A function body type.
2070 /// `data` is extra index to `TypeFunction`.2262 /// `data` is extra index to `TypeFunction`.
2071 type_function,2263 type_function,
...@@ -2273,9 +2465,7 @@ pub const Tag = enum(u8) {...@@ -2273,9 +2465,7 @@ pub const Tag = enum(u8) {
2273 .type_struct_ns => unreachable,2465 .type_struct_ns => unreachable,
2274 .type_struct_anon => TypeStructAnon,2466 .type_struct_anon => TypeStructAnon,
2275 .type_tuple_anon => TypeStructAnon,2467 .type_tuple_anon => TypeStructAnon,
2276 .type_union_tagged => unreachable,2468 .type_union => TypeUnion,
2277 .type_union_untagged => unreachable,
2278 .type_union_safety => unreachable,
2279 .type_function => TypeFunction,2469 .type_function => TypeFunction,
22802470
2281 .undef => unreachable,2471 .undef => unreachable,
...@@ -2425,6 +2615,30 @@ pub const Tag = enum(u8) {...@@ -2425,6 +2615,30 @@ pub const Tag = enum(u8) {
2425 _: u9 = 0,2615 _: u9 = 0,
2426 };2616 };
2427 };2617 };
2618
2619 /// The number of fields is provided by the `tag_ty` field.
2620 /// Trailing:
2621 /// 0. field type: Index for each field; declaration order
2622 /// 1. field align: Alignment for each field; declaration order
2623 pub const TypeUnion = struct {
2624 flags: Flags,
2625 decl: Module.Decl.Index,
2626 namespace: Module.Namespace.Index,
2627 /// The enum that provides the list of field names and values.
2628 tag_ty: Index,
2629 zir_index: Zir.Inst.Index,
2630
2631 pub const Flags = packed struct(u32) {
2632 runtime_tag: UnionType.RuntimeTag,
2633 /// If false, the field alignment trailing data is omitted.
2634 any_aligned_fields: bool,
2635 layout: std.builtin.Type.ContainerLayout,
2636 status: UnionType.Status,
2637 requires_comptime: UnionType.RequiresComptime,
2638 assumed_runtime_bits: bool,
2639 _: u21 = 0,
2640 };
2641 };
2428};2642};
24292643
2430/// State that is mutable during semantic analysis. This data is not used for2644/// State that is mutable during semantic analysis. This data is not used for
...@@ -2582,6 +2796,21 @@ pub const Alignment = enum(u6) {...@@ -2582,6 +2796,21 @@ pub const Alignment = enum(u6) {
2582 assert(lhs != .none and rhs != .none);2796 assert(lhs != .none and rhs != .none);
2583 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));2797 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
2584 }2798 }
2799
2800 /// An array of `Alignment` objects existing within the `extra` array.
2801 /// This type exists to provide a struct with lifetime that is
2802 /// not invalidated when items are added to the `InternPool`.
2803 pub const Slice = struct {
2804 start: u32,
2805 len: u32,
2806
2807 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
2808 // TODO: implement @ptrCast between slices changing the length
2809 //const bytes: []u8 = @ptrCast(ip.extra.items[slice.start..]);
2810 const bytes: []u8 = std.mem.sliceAsBytes(ip.extra.items[slice.start..]);
2811 return @ptrCast(bytes[0..slice.len]);
2812 }
2813 };
2585};2814};
25862815
2587/// Used for non-sentineled arrays that have length fitting in u32, as well as2816/// Used for non-sentineled arrays that have length fitting in u32, as well as
...@@ -2829,9 +3058,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -2829,9 +3058,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
2829 ip.structs_free_list.deinit(gpa);3058 ip.structs_free_list.deinit(gpa);
2830 ip.allocated_structs.deinit(gpa);3059 ip.allocated_structs.deinit(gpa);
28313060
2832 ip.unions_free_list.deinit(gpa);
2833 ip.allocated_unions.deinit(gpa);
2834
2835 ip.decls_free_list.deinit(gpa);3061 ip.decls_free_list.deinit(gpa);
2836 ip.allocated_decls.deinit(gpa);3062 ip.allocated_decls.deinit(gpa);
28373063
...@@ -2953,18 +3179,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -2953,18 +3179,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
2953 } };3179 } };
2954 },3180 },
29553181
2956 .type_union_untagged => .{ .union_type = .{3182 .type_union => .{ .union_type = extraUnionType(ip, data) },
2957 .index = @as(Module.Union.Index, @enumFromInt(data)),
2958 .runtime_tag = .none,
2959 } },
2960 .type_union_tagged => .{ .union_type = .{
2961 .index = @as(Module.Union.Index, @enumFromInt(data)),
2962 .runtime_tag = .tagged,
2963 } },
2964 .type_union_safety => .{ .union_type = .{
2965 .index = @as(Module.Union.Index, @enumFromInt(data)),
2966 .runtime_tag = .safety,
2967 } },
29683183
2969 .type_enum_auto => {3184 .type_enum_auto => {
2970 const enum_auto = ip.extraDataTrail(EnumAuto, data);3185 const enum_auto = ip.extraDataTrail(EnumAuto, data);
...@@ -3279,9 +3494,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3279,9 +3494,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
32793494
3280 .type_enum_auto,3495 .type_enum_auto,
3281 .type_enum_explicit,3496 .type_enum_explicit,
3282 .type_union_tagged,3497 .type_union,
3283 .type_union_untagged,
3284 .type_union_safety,
3285 => .{ .empty_enum_value = ty },3498 => .{ .empty_enum_value = ty },
32863499
3287 else => unreachable,3500 else => unreachable,
...@@ -3352,6 +3565,18 @@ fn extraErrorSet(ip: *const InternPool, extra_index: u32) Key.ErrorSetType {...@@ -3352,6 +3565,18 @@ fn extraErrorSet(ip: *const InternPool, extra_index: u32) Key.ErrorSetType {
3352 };3565 };
3353}3566}
33543567
3568fn extraUnionType(ip: *const InternPool, extra_index: u32) Key.UnionType {
3569 const type_union = ip.extraData(Tag.TypeUnion, extra_index);
3570 return .{
3571 .decl = type_union.decl,
3572 .namespace = type_union.namespace,
3573 .flags = type_union.flags,
3574 .enum_tag_ty = type_union.tag_ty,
3575 .zir_index = type_union.zir_index,
3576 .extra_index = extra_index,
3577 };
3578}
3579
3355fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {3580fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
3356 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);3581 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
3357 var index: usize = type_function.end;3582 var index: usize = type_function.end;
...@@ -3678,16 +3903,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3678,16 +3903,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3678 return @enumFromInt(ip.items.len - 1);3903 return @enumFromInt(ip.items.len - 1);
3679 },3904 },
36803905
3681 .union_type => |union_type| {3906 .union_type => unreachable, // use getUnionType() instead
3682 ip.items.appendAssumeCapacity(.{
3683 .tag = switch (union_type.runtime_tag) {
3684 .none => .type_union_untagged,
3685 .safety => .type_union_safety,
3686 .tagged => .type_union_tagged,
3687 },
3688 .data = @intFromEnum(union_type.index),
3689 });
3690 },
36913907
3692 .opaque_type => |opaque_type| {3908 .opaque_type => |opaque_type| {
3693 ip.items.appendAssumeCapacity(.{3909 ip.items.appendAssumeCapacity(.{
...@@ -3791,9 +4007,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3791,9 +4007,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3791 assert(ptr.addr == .field);4007 assert(ptr.addr == .field);
3792 assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count());4008 assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count());
3793 },4009 },
3794 .union_type => |union_type| {4010 .union_type => |union_key| {
4011 const union_type = ip.loadUnionType(union_key);
3795 assert(ptr.addr == .field);4012 assert(ptr.addr == .field);
3796 assert(base_index.index < ip.unionPtrConst(union_type.index).fields.count());4013 assert(base_index.index < union_type.field_names.len);
3797 },4014 },
3798 .ptr_type => |slice_type| {4015 .ptr_type => |slice_type| {
3799 assert(ptr.addr == .field);4016 assert(ptr.addr == .field);
...@@ -4359,6 +4576,76 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -4359,6 +4576,76 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
4359 return @enumFromInt(ip.items.len - 1);4576 return @enumFromInt(ip.items.len - 1);
4360}4577}
43614578
4579pub const UnionTypeInit = struct {
4580 flags: Tag.TypeUnion.Flags,
4581 decl: Module.Decl.Index,
4582 namespace: Module.Namespace.Index,
4583 zir_index: Zir.Inst.Index,
4584 fields_len: u32,
4585 enum_tag_ty: Index,
4586 /// May have length 0 which leaves the values unset until later.
4587 field_types: []const Index,
4588 /// May have length 0 which leaves the values unset until later.
4589 /// The logic for `any_aligned_fields` is asserted to have been done before
4590 /// calling this function.
4591 field_aligns: []const Alignment,
4592};
4593
4594pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!Index {
4595 const prev_extra_len = ip.extra.items.len;
4596 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
4597 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
4598 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeUnion).Struct.fields.len +
4599 ini.fields_len + // field types
4600 align_elements_len);
4601 try ip.items.ensureUnusedCapacity(gpa, 1);
4602
4603 const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
4604 .flags = ini.flags,
4605 .decl = ini.decl,
4606 .namespace = ini.namespace,
4607 .tag_ty = ini.enum_tag_ty,
4608 .zir_index = ini.zir_index,
4609 });
4610
4611 // field types
4612 if (ini.field_types.len > 0) {
4613 assert(ini.field_types.len == ini.fields_len);
4614 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.field_types));
4615 } else {
4616 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
4617 }
4618
4619 // field alignments
4620 if (ini.flags.any_aligned_fields) {
4621 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);
4622 if (ini.field_aligns.len > 0) {
4623 assert(ini.field_aligns.len == ini.fields_len);
4624 @memcpy((Alignment.Slice{
4625 .start = @intCast(ip.extra.items.len - align_elements_len),
4626 .len = @intCast(ini.field_aligns.len),
4627 }).get(ip), ini.field_aligns);
4628 }
4629 } else {
4630 assert(ini.field_aligns.len == 0);
4631 }
4632
4633 const adapter: KeyAdapter = .{ .intern_pool = ip };
4634 const gop = try ip.map.getOrPutAdapted(gpa, Key{
4635 .union_type = extraUnionType(ip, union_type_extra_index),
4636 }, adapter);
4637 if (gop.found_existing) {
4638 ip.extra.items.len = prev_extra_len;
4639 return @enumFromInt(gop.index);
4640 }
4641
4642 ip.items.appendAssumeCapacity(.{
4643 .tag = .type_union,
4644 .data = union_type_extra_index,
4645 });
4646 return @enumFromInt(ip.items.len - 1);
4647}
4648
4362/// This is equivalent to `Key.FuncType` but adjusted to have a slice for `param_types`.4649/// This is equivalent to `Key.FuncType` but adjusted to have a slice for `param_types`.
4363pub const GetFuncTypeKey = struct {4650pub const GetFuncTypeKey = struct {
4364 param_types: []Index,4651 param_types: []Index,
...@@ -5310,6 +5597,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -5310,6 +5597,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
5310 Tag.TypeFunction.Flags,5597 Tag.TypeFunction.Flags,
5311 Tag.TypePointer.PackedOffset,5598 Tag.TypePointer.PackedOffset,
5312 Tag.Variable.Flags,5599 Tag.Variable.Flags,
5600 Tag.TypeUnion.Flags,
5313 => @bitCast(@field(extra, field.name)),5601 => @bitCast(@field(extra, field.name)),
53145602
5315 else => @compileError("bad field type: " ++ @typeName(field.type)),5603 else => @compileError("bad field type: " ++ @typeName(field.type)),
...@@ -5380,6 +5668,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct...@@ -5380,6 +5668,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
5380 Tag.TypePointer.Flags,5668 Tag.TypePointer.Flags,
5381 Tag.TypeFunction.Flags,5669 Tag.TypeFunction.Flags,
5382 Tag.TypePointer.PackedOffset,5670 Tag.TypePointer.PackedOffset,
5671 Tag.TypeUnion.Flags,
5383 Tag.Variable.Flags,5672 Tag.Variable.Flags,
5384 FuncAnalysis,5673 FuncAnalysis,
5385 => @bitCast(int32),5674 => @bitCast(int32),
...@@ -5893,7 +6182,7 @@ pub fn indexToUnionType(ip: *const InternPool, val: Index) Module.Union.Optional...@@ -5893,7 +6182,7 @@ pub fn indexToUnionType(ip: *const InternPool, val: Index) Module.Union.Optional
5893 assert(val != .none);6182 assert(val != .none);
5894 const tags = ip.items.items(.tag);6183 const tags = ip.items.items(.tag);
5895 switch (tags[@intFromEnum(val)]) {6184 switch (tags[@intFromEnum(val)]) {
5896 .type_union_tagged, .type_union_untagged, .type_union_safety => {},6185 .type_union => {},
5897 else => return .none,6186 else => return .none,
5898 }6187 }
5899 const datas = ip.items.items(.data);6188 const datas = ip.items.items(.data);
...@@ -5946,6 +6235,10 @@ pub fn isEnumType(ip: *const InternPool, ty: Index) bool {...@@ -5946,6 +6235,10 @@ pub fn isEnumType(ip: *const InternPool, ty: Index) bool {
5946 };6235 };
5947}6236}
59486237
6238pub fn isUnion(ip: *const InternPool, ty: Index) bool {
6239 return ip.indexToKey(ty) == .union_type;
6240}
6241
5949pub fn isFunctionType(ip: *const InternPool, ty: Index) bool {6242pub fn isFunctionType(ip: *const InternPool, ty: Index) bool {
5950 return ip.indexToKey(ty) == .func_type;6243 return ip.indexToKey(ty) == .func_type;
5951}6244}
...@@ -6010,13 +6303,11 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6010,13 +6303,11 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6010 const limbs_size = 8 * ip.limbs.items.len;6303 const limbs_size = 8 * ip.limbs.items.len;
6011 // TODO: fields size is not taken into account6304 // TODO: fields size is not taken into account
6012 const structs_size = ip.allocated_structs.len *6305 const structs_size = ip.allocated_structs.len *
6013 (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));6306 (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace));
6014 const unions_size = ip.allocated_unions.len *6307 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);
6015 (@sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));
60166308
6017 // TODO: map overhead size is not taken into account6309 // TODO: map overhead size is not taken into account
6018 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size +6310 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + structs_size + decls_size;
6019 structs_size + unions_size;
60206311
6021 std.debug.print(6312 std.debug.print(
6022 \\InternPool size: {d} bytes6313 \\InternPool size: {d} bytes
...@@ -6024,7 +6315,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6024,7 +6315,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6024 \\ {d} extra: {d} bytes6315 \\ {d} extra: {d} bytes
6025 \\ {d} limbs: {d} bytes6316 \\ {d} limbs: {d} bytes
6026 \\ {d} structs: {d} bytes6317 \\ {d} structs: {d} bytes
6027 \\ {d} unions: {d} bytes6318 \\ {d} decls: {d} bytes
6028 \\6319 \\
6029 , .{6320 , .{
6030 total_size,6321 total_size,
...@@ -6036,8 +6327,8 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6036,8 +6327,8 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6036 limbs_size,6327 limbs_size,
6037 ip.allocated_structs.len,6328 ip.allocated_structs.len,
6038 structs_size,6329 structs_size,
6039 ip.allocated_unions.len,6330 ip.allocated_decls.len,
6040 unions_size,6331 decls_size,
6041 });6332 });
60426333
6043 const tags = ip.items.items(.tag);6334 const tags = ip.items.items(.tag);
...@@ -6076,7 +6367,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6076,7 +6367,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6076 const struct_obj = ip.structPtrConst(struct_index);6367 const struct_obj = ip.structPtrConst(struct_index);
6077 break :b @sizeOf(Module.Struct) +6368 break :b @sizeOf(Module.Struct) +
6078 @sizeOf(Module.Namespace) +6369 @sizeOf(Module.Namespace) +
6079 @sizeOf(Module.Decl) +
6080 (struct_obj.fields.count() * @sizeOf(Module.Struct.Field));6370 (struct_obj.fields.count() * @sizeOf(Module.Struct.Field));
6081 },6371 },
6082 .type_struct_ns => @sizeOf(Module.Namespace),6372 .type_struct_ns => @sizeOf(Module.Namespace),
...@@ -6089,10 +6379,18 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6089,10 +6379,18 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6089 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);6379 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);
6090 },6380 },
60916381
6092 .type_union_tagged,6382 .type_union => b: {
6093 .type_union_untagged,6383 const info = ip.extraData(Tag.TypeUnion, data);
6094 .type_union_safety,6384 const enum_info = ip.indexToKey(info.tag_ty).enum_type;
6095 => @sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),6385 const fields_len: u32 = @intCast(enum_info.names.len);
6386 const per_field = @sizeOf(u32); // field type
6387 // 1 byte per field for alignment, rounded up to the nearest 4 bytes
6388 const alignments = if (info.flags.any_aligned_fields)
6389 ((fields_len + 3) / 4) * 4
6390 else
6391 0;
6392 break :b @sizeOf(Tag.TypeUnion) + (fields_len * per_field) + alignments;
6393 },
60966394
6097 .type_function => b: {6395 .type_function => b: {
6098 const info = ip.extraData(Tag.TypeFunction, data);6396 const info = ip.extraData(Tag.TypeFunction, data);
...@@ -6161,15 +6459,14 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6161,15 +6459,14 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6161 .float_c_longdouble_f80 => @sizeOf(Float80),6459 .float_c_longdouble_f80 => @sizeOf(Float80),
6162 .float_c_longdouble_f128 => @sizeOf(Float128),6460 .float_c_longdouble_f128 => @sizeOf(Float128),
6163 .float_comptime_float => @sizeOf(Float128),6461 .float_comptime_float => @sizeOf(Float128),
6164 .variable => @sizeOf(Tag.Variable) + @sizeOf(Module.Decl),6462 .variable => @sizeOf(Tag.Variable),
6165 .extern_func => @sizeOf(Tag.ExternFunc) + @sizeOf(Module.Decl),6463 .extern_func => @sizeOf(Tag.ExternFunc),
6166 .func_decl => @sizeOf(Tag.FuncDecl) + @sizeOf(Module.Decl),6464 .func_decl => @sizeOf(Tag.FuncDecl),
6167 .func_instance => b: {6465 .func_instance => b: {
6168 const info = ip.extraData(Tag.FuncInstance, data);6466 const info = ip.extraData(Tag.FuncInstance, data);
6169 const ty = ip.typeOf(info.generic_owner);6467 const ty = ip.typeOf(info.generic_owner);
6170 const params_len = ip.indexToKey(ty).func_type.param_types.len;6468 const params_len = ip.indexToKey(ty).func_type.param_types.len;
6171 break :b @sizeOf(Tag.FuncInstance) + @sizeOf(Index) * params_len +6469 break :b @sizeOf(Tag.FuncInstance) + @sizeOf(Index) * params_len;
6172 @sizeOf(Module.Decl);
6173 },6470 },
6174 .func_coerced => @sizeOf(Tag.FuncCoerced),6471 .func_coerced => @sizeOf(Tag.FuncCoerced),
6175 .only_possible_value => 0,6472 .only_possible_value => 0,
...@@ -6230,9 +6527,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -6230,9 +6527,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
6230 .type_struct_ns,6527 .type_struct_ns,
6231 .type_struct_anon,6528 .type_struct_anon,
6232 .type_tuple_anon,6529 .type_tuple_anon,
6233 .type_union_tagged,6530 .type_union,
6234 .type_union_untagged,
6235 .type_union_safety,
6236 .type_function,6531 .type_function,
6237 .undef,6532 .undef,
6238 .runtime_value,6533 .runtime_value,
...@@ -6358,14 +6653,6 @@ pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.Optional...@@ -6358,14 +6653,6 @@ pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.Optional
6358 return structPtrConst(ip, index.unwrap() orelse return null);6653 return structPtrConst(ip, index.unwrap() orelse return null);
6359}6654}
63606655
6361pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union {
6362 return ip.allocated_unions.at(@intFromEnum(index));
6363}
6364
6365pub fn unionPtrConst(ip: *const InternPool, index: Module.Union.Index) *const Module.Union {
6366 return ip.allocated_unions.at(@intFromEnum(index));
6367}
6368
6369pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {6656pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {
6370 return ip.allocated_decls.at(@intFromEnum(index));6657 return ip.allocated_decls.at(@intFromEnum(index));
6371}6658}
...@@ -6400,28 +6687,6 @@ pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index...@@ -6400,28 +6687,6 @@ pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index
6400 };6687 };
6401}6688}
64026689
6403pub fn createUnion(
6404 ip: *InternPool,
6405 gpa: Allocator,
6406 initialization: Module.Union,
6407) Allocator.Error!Module.Union.Index {
6408 if (ip.unions_free_list.popOrNull()) |index| {
6409 ip.allocated_unions.at(@intFromEnum(index)).* = initialization;
6410 return index;
6411 }
6412 const ptr = try ip.allocated_unions.addOne(gpa);
6413 ptr.* = initialization;
6414 return @enumFromInt(ip.allocated_unions.len - 1);
6415}
6416
6417pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) void {
6418 ip.unionPtr(index).* = undefined;
6419 ip.unions_free_list.append(gpa, index) catch {
6420 // In order to keep `destroyUnion` a non-fallible function, we ignore memory
6421 // allocation failures here, instead leaking the Union until garbage collection.
6422 };
6423}
6424
6425pub fn createDecl(6690pub fn createDecl(
6426 ip: *InternPool,6691 ip: *InternPool,
6427 gpa: Allocator,6692 gpa: Allocator,
...@@ -6667,9 +6932,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -6667,9 +6932,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
6667 .type_struct_ns,6932 .type_struct_ns,
6668 .type_struct_anon,6933 .type_struct_anon,
6669 .type_tuple_anon,6934 .type_tuple_anon,
6670 .type_union_tagged,6935 .type_union,
6671 .type_union_untagged,
6672 .type_union_safety,
6673 .type_function,6936 .type_function,
6674 => .type_type,6937 => .type_type,
66756938
...@@ -7005,10 +7268,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -7005,10 +7268,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
7005 .type_tuple_anon,7268 .type_tuple_anon,
7006 => .Struct,7269 => .Struct,
70077270
7008 .type_union_tagged,7271 .type_union => .Union,
7009 .type_union_untagged,
7010 .type_union_safety,
7011 => .Union,
70127272
7013 .type_function => .Fn,7273 .type_function => .Fn,
70147274
src/Module.zig+141-261
...@@ -96,7 +96,7 @@ intern_pool: InternPool = .{},...@@ -96,7 +96,7 @@ intern_pool: InternPool = .{},
96/// Current uses that must be eliminated:96/// Current uses that must be eliminated:
97/// * Struct comptime_args97/// * Struct comptime_args
98/// * Struct optimized_order98/// * Struct optimized_order
99/// * Union fields99/// * comptime pointer mutation
100/// This memory lives until the Module is destroyed.100/// This memory lives until the Module is destroyed.
101tmp_hack_arena: std.heap.ArenaAllocator,101tmp_hack_arena: std.heap.ArenaAllocator,
102102
...@@ -736,7 +736,7 @@ pub const Decl = struct {...@@ -736,7 +736,7 @@ pub const Decl = struct {
736736
737 /// If the Decl owns its value and it is a union, return it,737 /// If the Decl owns its value and it is a union, return it,
738 /// otherwise null.738 /// otherwise null.
739 pub fn getOwnedUnion(decl: Decl, mod: *Module) ?*Union {739 pub fn getOwnedUnion(decl: Decl, mod: *Module) ?InternPool.UnionType {
740 if (!decl.owns_tv) return null;740 if (!decl.owns_tv) return null;
741 if (decl.val.ip_index == .none) return null;741 if (decl.val.ip_index == .none) return null;
742 return mod.typeToUnion(decl.val.toType());742 return mod.typeToUnion(decl.val.toType());
...@@ -778,7 +778,7 @@ pub const Decl = struct {...@@ -778,7 +778,7 @@ pub const Decl = struct {
778 else => switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {778 else => switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {
779 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),779 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
780 .struct_type => |struct_type| struct_type.namespace,780 .struct_type => |struct_type| struct_type.namespace,
781 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),781 .union_type => |union_type| union_type.namespace.toOptional(),
782 .enum_type => |enum_type| enum_type.namespace,782 .enum_type => |enum_type| enum_type.namespace,
783 else => .none,783 else => .none,
784 },784 },
...@@ -1064,246 +1064,6 @@ pub const Struct = struct {...@@ -1064,246 +1064,6 @@ pub const Struct = struct {
1064 }1064 }
1065};1065};
10661066
1067pub const Union = struct {
1068 /// An enum type which is used for the tag of the union.
1069 /// This type is created even for untagged unions, even when the memory
1070 /// layout does not store the tag.
1071 /// Whether zig chooses this type or the user specifies it, it is stored here.
1072 /// This will be set to the null type until status is `have_field_types`.
1073 tag_ty: Type,
1074 /// Set of field names in declaration order.
1075 fields: Fields,
1076 /// Represents the declarations inside this union.
1077 namespace: Namespace.Index,
1078 /// The Decl that corresponds to the union itself.
1079 owner_decl: Decl.Index,
1080 /// Index of the union_decl ZIR instruction.
1081 zir_index: Zir.Inst.Index,
1082
1083 layout: std.builtin.Type.ContainerLayout,
1084 status: enum {
1085 none,
1086 field_types_wip,
1087 have_field_types,
1088 layout_wip,
1089 have_layout,
1090 fully_resolved_wip,
1091 // The types and all its fields have had their layout resolved. Even through pointer,
1092 // which `have_layout` does not ensure.
1093 fully_resolved,
1094 },
1095 requires_comptime: PropertyBoolean = .unknown,
1096 assumed_runtime_bits: bool = false,
1097
1098 pub const Index = enum(u32) {
1099 _,
1100
1101 pub fn toOptional(i: Index) OptionalIndex {
1102 return @as(OptionalIndex, @enumFromInt(@intFromEnum(i)));
1103 }
1104 };
1105
1106 pub const OptionalIndex = enum(u32) {
1107 none = std.math.maxInt(u32),
1108 _,
1109
1110 pub fn init(oi: ?Index) OptionalIndex {
1111 return @as(OptionalIndex, @enumFromInt(@intFromEnum(oi orelse return .none)));
1112 }
1113
1114 pub fn unwrap(oi: OptionalIndex) ?Index {
1115 if (oi == .none) return null;
1116 return @as(Index, @enumFromInt(@intFromEnum(oi)));
1117 }
1118 };
1119
1120 pub const Field = struct {
1121 /// undefined until `status` is `have_field_types` or `have_layout`.
1122 ty: Type,
1123 /// 0 means the ABI alignment of the type.
1124 abi_align: Alignment,
1125
1126 /// Returns the field alignment, assuming the union is not packed.
1127 /// Keep implementation in sync with `Sema.unionFieldAlignment`.
1128 /// Prefer to call that function instead of this one during Sema.
1129 pub fn normalAlignment(field: Field, mod: *Module) u32 {
1130 return @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse field.ty.abiAlignment(mod)));
1131 }
1132 };
1133
1134 pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field);
1135
1136 pub fn getFullyQualifiedName(s: *Union, mod: *Module) !InternPool.NullTerminatedString {
1137 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod);
1138 }
1139
1140 pub fn srcLoc(self: Union, mod: *Module) SrcLoc {
1141 const owner_decl = mod.declPtr(self.owner_decl);
1142 return .{
1143 .file_scope = owner_decl.getFileScope(mod),
1144 .parent_decl_node = owner_decl.src_node,
1145 .lazy = LazySrcLoc.nodeOffset(0),
1146 };
1147 }
1148
1149 pub fn haveFieldTypes(u: Union) bool {
1150 return switch (u.status) {
1151 .none,
1152 .field_types_wip,
1153 => false,
1154 .have_field_types,
1155 .layout_wip,
1156 .have_layout,
1157 .fully_resolved_wip,
1158 .fully_resolved,
1159 => true,
1160 };
1161 }
1162
1163 pub fn hasAllZeroBitFieldTypes(u: Union, mod: *Module) bool {
1164 assert(u.haveFieldTypes());
1165 for (u.fields.values()) |field| {
1166 if (field.ty.hasRuntimeBits(mod)) return false;
1167 }
1168 return true;
1169 }
1170
1171 pub fn mostAlignedField(u: Union, mod: *Module) u32 {
1172 assert(u.haveFieldTypes());
1173 var most_alignment: u32 = 0;
1174 var most_index: usize = undefined;
1175 for (u.fields.values(), 0..) |field, i| {
1176 if (!field.ty.hasRuntimeBits(mod)) continue;
1177
1178 const field_align = field.normalAlignment(mod);
1179 if (field_align > most_alignment) {
1180 most_alignment = field_align;
1181 most_index = i;
1182 }
1183 }
1184 return @as(u32, @intCast(most_index));
1185 }
1186
1187 /// Returns 0 if the union is represented with 0 bits at runtime.
1188 pub fn abiAlignment(u: Union, mod: *Module, have_tag: bool) u32 {
1189 var max_align: u32 = 0;
1190 if (have_tag) max_align = u.tag_ty.abiAlignment(mod);
1191 for (u.fields.values()) |field| {
1192 if (!field.ty.hasRuntimeBits(mod)) continue;
1193
1194 const field_align = field.normalAlignment(mod);
1195 max_align = @max(max_align, field_align);
1196 }
1197 return max_align;
1198 }
1199
1200 pub fn abiSize(u: Union, mod: *Module, have_tag: bool) u64 {
1201 return u.getLayout(mod, have_tag).abi_size;
1202 }
1203
1204 pub const Layout = struct {
1205 abi_size: u64,
1206 abi_align: u32,
1207 most_aligned_field: u32,
1208 most_aligned_field_size: u64,
1209 biggest_field: u32,
1210 payload_size: u64,
1211 payload_align: u32,
1212 tag_align: u32,
1213 tag_size: u64,
1214 padding: u32,
1215 };
1216
1217 pub fn haveLayout(u: Union) bool {
1218 return switch (u.status) {
1219 .none,
1220 .field_types_wip,
1221 .have_field_types,
1222 .layout_wip,
1223 => false,
1224 .have_layout,
1225 .fully_resolved_wip,
1226 .fully_resolved,
1227 => true,
1228 };
1229 }
1230
1231 pub fn getLayout(u: Union, mod: *Module, have_tag: bool) Layout {
1232 assert(u.haveLayout());
1233 var most_aligned_field: u32 = undefined;
1234 var most_aligned_field_size: u64 = undefined;
1235 var biggest_field: u32 = undefined;
1236 var payload_size: u64 = 0;
1237 var payload_align: u32 = 0;
1238 const fields = u.fields.values();
1239 for (fields, 0..) |field, i| {
1240 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1241
1242 const field_align = field.abi_align.toByteUnitsOptional() orelse field.ty.abiAlignment(mod);
1243 const field_size = field.ty.abiSize(mod);
1244 if (field_size > payload_size) {
1245 payload_size = field_size;
1246 biggest_field = @as(u32, @intCast(i));
1247 }
1248 if (field_align > payload_align) {
1249 payload_align = @as(u32, @intCast(field_align));
1250 most_aligned_field = @as(u32, @intCast(i));
1251 most_aligned_field_size = field_size;
1252 }
1253 }
1254 payload_align = @max(payload_align, 1);
1255 if (!have_tag or !u.tag_ty.hasRuntimeBits(mod)) {
1256 return .{
1257 .abi_size = std.mem.alignForward(u64, payload_size, payload_align),
1258 .abi_align = payload_align,
1259 .most_aligned_field = most_aligned_field,
1260 .most_aligned_field_size = most_aligned_field_size,
1261 .biggest_field = biggest_field,
1262 .payload_size = payload_size,
1263 .payload_align = payload_align,
1264 .tag_align = 0,
1265 .tag_size = 0,
1266 .padding = 0,
1267 };
1268 }
1269 // Put the tag before or after the payload depending on which one's
1270 // alignment is greater.
1271 const tag_size = u.tag_ty.abiSize(mod);
1272 const tag_align = @max(1, u.tag_ty.abiAlignment(mod));
1273 var size: u64 = 0;
1274 var padding: u32 = undefined;
1275 if (tag_align >= payload_align) {
1276 // {Tag, Payload}
1277 size += tag_size;
1278 size = std.mem.alignForward(u64, size, payload_align);
1279 size += payload_size;
1280 const prev_size = size;
1281 size = std.mem.alignForward(u64, size, tag_align);
1282 padding = @as(u32, @intCast(size - prev_size));
1283 } else {
1284 // {Payload, Tag}
1285 size += payload_size;
1286 size = std.mem.alignForward(u64, size, tag_align);
1287 size += tag_size;
1288 const prev_size = size;
1289 size = std.mem.alignForward(u64, size, payload_align);
1290 padding = @as(u32, @intCast(size - prev_size));
1291 }
1292 return .{
1293 .abi_size = size,
1294 .abi_align = @max(tag_align, payload_align),
1295 .most_aligned_field = most_aligned_field,
1296 .most_aligned_field_size = most_aligned_field_size,
1297 .biggest_field = biggest_field,
1298 .payload_size = payload_size,
1299 .payload_align = payload_align,
1300 .tag_align = tag_align,
1301 .tag_size = tag_size,
1302 .padding = padding,
1303 };
1304 }
1305};
1306
1307pub const DeclAdapter = struct {1067pub const DeclAdapter = struct {
1308 mod: *Module,1068 mod: *Module,
13091069
...@@ -3182,10 +2942,6 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {...@@ -3182,10 +2942,6 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
3182 return mod.intern_pool.namespacePtr(index);2942 return mod.intern_pool.namespacePtr(index);
3183}2943}
31842944
3185pub fn unionPtr(mod: *Module, index: Union.Index) *Union {
3186 return mod.intern_pool.unionPtr(index);
3187}
3188
3189pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {2945pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
3190 return mod.intern_pool.structPtr(index);2946 return mod.intern_pool.structPtr(index);
3191}2947}
...@@ -3651,11 +3407,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {...@@ -3651,11 +3407,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
3651 };3407 };
3652 }3408 }
36533409
3654 if (decl.getOwnedUnion(mod)) |union_obj| {3410 if (decl.getOwnedUnion(mod)) |union_type| {
3655 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {3411 union_type.setZirIndex(ip, inst_map.get(union_type.zir_index) orelse {
3656 try file.deleted_decls.append(gpa, decl_index);3412 try file.deleted_decls.append(gpa, decl_index);
3657 continue;3413 continue;
3658 };3414 });
3659 }3415 }
36603416
3661 if (decl.getOwnedFunction(mod)) |func| {3417 if (decl.getOwnedFunction(mod)) |func| {
...@@ -5550,14 +5306,6 @@ pub fn destroyStruct(mod: *Module, index: Struct.Index) void {...@@ -5550,14 +5306,6 @@ pub fn destroyStruct(mod: *Module, index: Struct.Index) void {
5550 return mod.intern_pool.destroyStruct(mod.gpa, index);5306 return mod.intern_pool.destroyStruct(mod.gpa, index);
5551}5307}
55525308
5553pub fn createUnion(mod: *Module, initialization: Union) Allocator.Error!Union.Index {
5554 return mod.intern_pool.createUnion(mod.gpa, initialization);
5555}
5556
5557pub fn destroyUnion(mod: *Module, index: Union.Index) void {
5558 return mod.intern_pool.destroyUnion(mod.gpa, index);
5559}
5560
5561pub fn allocateNewDecl(5309pub fn allocateNewDecl(
5562 mod: *Module,5310 mod: *Module,
5563 namespace: Namespace.Index,5311 namespace: Namespace.Index,
...@@ -6956,10 +6704,14 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {...@@ -6956,10 +6704,14 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {
6956 return mod.structPtr(struct_index);6704 return mod.structPtr(struct_index);
6957}6705}
69586706
6959pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {6707/// This asserts that the union's enum tag type has been resolved.
6708pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
6960 if (ty.ip_index == .none) return null;6709 if (ty.ip_index == .none) return null;
6961 const union_index = mod.intern_pool.indexToUnionType(ty.toIntern()).unwrap() orelse return null;6710 const ip = &mod.intern_pool;
6962 return mod.unionPtr(union_index);6711 switch (ip.indexToKey(ty.ip_index)) {
6712 .union_type => |k| return ip.loadUnionType(k),
6713 else => return null,
6714 }
6963}6715}
69646716
6965pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {6717pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {
...@@ -7045,3 +6797,131 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]...@@ -7045,3 +6797,131 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]
7045 else => unreachable,6797 else => unreachable,
7046 };6798 };
7047}6799}
6800
6801pub const UnionLayout = struct {
6802 abi_size: u64,
6803 abi_align: u32,
6804 most_aligned_field: u32,
6805 most_aligned_field_size: u64,
6806 biggest_field: u32,
6807 payload_size: u64,
6808 payload_align: u32,
6809 tag_align: u32,
6810 tag_size: u64,
6811 padding: u32,
6812};
6813
6814pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6815 const ip = &mod.intern_pool;
6816 assert(u.haveLayout(ip));
6817 var most_aligned_field: u32 = undefined;
6818 var most_aligned_field_size: u64 = undefined;
6819 var biggest_field: u32 = undefined;
6820 var payload_size: u64 = 0;
6821 var payload_align: u32 = 0;
6822 for (u.field_types.get(ip), 0..) |field_ty, i| {
6823 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
6824
6825 const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse
6826 field_ty.toType().abiAlignment(mod);
6827 const field_size = field_ty.toType().abiSize(mod);
6828 if (field_size > payload_size) {
6829 payload_size = field_size;
6830 biggest_field = @intCast(i);
6831 }
6832 if (field_align > payload_align) {
6833 payload_align = @intCast(field_align);
6834 most_aligned_field = @intCast(i);
6835 most_aligned_field_size = field_size;
6836 }
6837 }
6838 payload_align = @max(payload_align, 1);
6839 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6840 if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) {
6841 return .{
6842 .abi_size = std.mem.alignForward(u64, payload_size, payload_align),
6843 .abi_align = payload_align,
6844 .most_aligned_field = most_aligned_field,
6845 .most_aligned_field_size = most_aligned_field_size,
6846 .biggest_field = biggest_field,
6847 .payload_size = payload_size,
6848 .payload_align = payload_align,
6849 .tag_align = 0,
6850 .tag_size = 0,
6851 .padding = 0,
6852 };
6853 }
6854 // Put the tag before or after the payload depending on which one's
6855 // alignment is greater.
6856 const tag_size = u.enum_tag_ty.toType().abiSize(mod);
6857 const tag_align = @max(1, u.enum_tag_ty.toType().abiAlignment(mod));
6858 var size: u64 = 0;
6859 var padding: u32 = undefined;
6860 if (tag_align >= payload_align) {
6861 // {Tag, Payload}
6862 size += tag_size;
6863 size = std.mem.alignForward(u64, size, payload_align);
6864 size += payload_size;
6865 const prev_size = size;
6866 size = std.mem.alignForward(u64, size, tag_align);
6867 padding = @as(u32, @intCast(size - prev_size));
6868 } else {
6869 // {Payload, Tag}
6870 size += payload_size;
6871 size = std.mem.alignForward(u64, size, tag_align);
6872 size += tag_size;
6873 const prev_size = size;
6874 size = std.mem.alignForward(u64, size, payload_align);
6875 padding = @as(u32, @intCast(size - prev_size));
6876 }
6877 return .{
6878 .abi_size = size,
6879 .abi_align = @max(tag_align, payload_align),
6880 .most_aligned_field = most_aligned_field,
6881 .most_aligned_field_size = most_aligned_field_size,
6882 .biggest_field = biggest_field,
6883 .payload_size = payload_size,
6884 .payload_align = payload_align,
6885 .tag_align = tag_align,
6886 .tag_size = tag_size,
6887 .padding = padding,
6888 };
6889}
6890
6891pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {
6892 return mod.getUnionLayout(u).abi_size;
6893}
6894
6895/// Returns 0 if the union is represented with 0 bits at runtime.
6896/// TODO: this returns alignment in byte units should should be a u64
6897pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
6898 const ip = &mod.intern_pool;
6899 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6900 var max_align: u32 = 0;
6901 if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod);
6902 for (u.field_types.get(ip), 0..) |field_ty, field_index| {
6903 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
6904
6905 const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index));
6906 max_align = @max(max_align, field_align);
6907 }
6908 return max_align;
6909}
6910
6911/// Returns the field alignment, assuming the union is not packed.
6912/// Keep implementation in sync with `Sema.unionFieldAlignment`.
6913/// Prefer to call that function instead of this one during Sema.
6914/// TODO: this returns alignment in byte units should should be a u64
6915pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 {
6916 const ip = &mod.intern_pool;
6917 if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a);
6918 const field_ty = u.field_types.get(ip)[field_index].toType();
6919 return field_ty.abiAlignment(mod);
6920}
6921
6922pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value) ?u32 {
6923 const ip = &mod.intern_pool;
6924 assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);
6925 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;
6926 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
6927}
src/Sema.zig+408-505
...@@ -3022,18 +3022,18 @@ fn zirEnumDecl(...@@ -3022,18 +3022,18 @@ fn zirEnumDecl(
30223022
3023 const mod = sema.mod;3023 const mod = sema.mod;
3024 const gpa = sema.gpa;3024 const gpa = sema.gpa;
3025 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));3025 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
3026 var extra_index: usize = extended.operand;3026 var extra_index: usize = extended.operand;
30273027
3028 const src: LazySrcLoc = if (small.has_src_node) blk: {3028 const src: LazySrcLoc = if (small.has_src_node) blk: {
3029 const node_offset = @as(i32, @bitCast(sema.code.extra[extra_index]));3029 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
3030 extra_index += 1;3030 extra_index += 1;
3031 break :blk LazySrcLoc.nodeOffset(node_offset);3031 break :blk LazySrcLoc.nodeOffset(node_offset);
3032 } else sema.src;3032 } else sema.src;
3033 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };3033 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
30343034
3035 const tag_type_ref = if (small.has_tag_type) blk: {3035 const tag_type_ref = if (small.has_tag_type) blk: {
3036 const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(sema.code.extra[extra_index]));3036 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
3037 extra_index += 1;3037 extra_index += 1;
3038 break :blk tag_type_ref;3038 break :blk tag_type_ref;
3039 } else .none;3039 } else .none;
...@@ -3310,7 +3310,11 @@ fn zirUnionDecl(...@@ -3310,7 +3310,11 @@ fn zirUnionDecl(
33103310
3311 extra_index += @intFromBool(small.has_tag_type);3311 extra_index += @intFromBool(small.has_tag_type);
3312 extra_index += @intFromBool(small.has_body_len);3312 extra_index += @intFromBool(small.has_body_len);
3313 extra_index += @intFromBool(small.has_fields_len);3313 const fields_len = if (small.has_fields_len) blk: {
3314 const fields_len = sema.code.extra[extra_index];
3315 extra_index += 1;
3316 break :blk fields_len;
3317 } else 0;
33143318
3315 const decls_len = if (small.has_decls_len) blk: {3319 const decls_len = if (small.has_decls_len) blk: {
3316 const decls_len = sema.code.extra[extra_index];3320 const decls_len = sema.code.extra[extra_index];
...@@ -3338,29 +3342,31 @@ fn zirUnionDecl(...@@ -3338,29 +3342,31 @@ fn zirUnionDecl(
3338 const new_namespace = mod.namespacePtr(new_namespace_index);3342 const new_namespace = mod.namespacePtr(new_namespace_index);
3339 errdefer mod.destroyNamespace(new_namespace_index);3343 errdefer mod.destroyNamespace(new_namespace_index);
33403344
3341 const union_index = try mod.createUnion(.{
3342 .owner_decl = new_decl_index,
3343 .tag_ty = Type.null,
3344 .fields = .{},
3345 .zir_index = inst,
3346 .layout = small.layout,
3347 .status = .none,
3348 .namespace = new_namespace_index,
3349 });
3350 errdefer mod.destroyUnion(union_index);
3351
3352 const union_ty = ty: {3345 const union_ty = ty: {
3353 const ty = try mod.intern_pool.get(gpa, .{ .union_type = .{3346 const ty = try mod.intern_pool.getUnionType(gpa, .{
3354 .index = union_index,3347 .flags = .{
3355 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)3348 .layout = small.layout,
3356 .tagged3349 .status = .none,
3357 else if (small.layout != .Auto)3350 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3358 .none3351 .tagged
3359 else switch (block.sema.mod.optimizeMode()) {3352 else if (small.layout != .Auto)
3360 .Debug, .ReleaseSafe => .safety,3353 .none
3361 .ReleaseFast, .ReleaseSmall => .none,3354 else switch (block.wantSafety()) {
3355 true => .safety,
3356 false => .none,
3357 },
3358 .any_aligned_fields = small.any_aligned_fields,
3359 .requires_comptime = .unknown,
3360 .assumed_runtime_bits = false,
3362 },3361 },
3363 } });3362 .decl = new_decl_index,
3363 .namespace = new_namespace_index,
3364 .zir_index = inst,
3365 .fields_len = fields_len,
3366 .enum_tag_ty = .none,
3367 .field_types = &.{},
3368 .field_aligns = &.{},
3369 });
3364 if (sema.builtin_type_target_index != .none) {3370 if (sema.builtin_type_target_index != .none) {
3365 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);3371 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
3366 break :ty sema.builtin_type_target_index;3372 break :ty sema.builtin_type_target_index;
...@@ -4505,8 +4511,7 @@ fn validateUnionInit(...@@ -4505,8 +4511,7 @@ fn validateUnionInit(
4505 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };4511 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
4506 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;4512 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
4507 const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start));4513 const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start));
4508 // Validate the field access but ignore the index since we want the tag enum field index.4514 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
4509 _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
4510 const air_tags = sema.air_instructions.items(.tag);4515 const air_tags = sema.air_instructions.items(.tag);
4511 const air_datas = sema.air_instructions.items(.data);4516 const air_datas = sema.air_instructions.items(.data);
4512 const field_ptr_ref = sema.inst_map.get(field_ptr).?;4517 const field_ptr_ref = sema.inst_map.get(field_ptr).?;
...@@ -4563,8 +4568,7 @@ fn validateUnionInit(...@@ -4563,8 +4568,7 @@ fn validateUnionInit(
4563 }4568 }
45644569
4565 const tag_ty = union_ty.unionTagTypeHypothetical(mod);4570 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
4566 const enum_field_index = @as(u32, @intCast(tag_ty.enumFieldIndex(field_name, mod).?));4571 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
4567 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
45684572
4569 if (init_val) |val| {4573 if (init_val) |val| {
4570 // Our task is to delete all the `field_ptr` and `store` instructions, and insert4574 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
...@@ -5227,14 +5231,15 @@ fn failWithBadStructFieldAccess(...@@ -5227,14 +5231,15 @@ fn failWithBadStructFieldAccess(
5227fn failWithBadUnionFieldAccess(5231fn failWithBadUnionFieldAccess(
5228 sema: *Sema,5232 sema: *Sema,
5229 block: *Block,5233 block: *Block,
5230 union_obj: *Module.Union,5234 union_obj: InternPool.UnionType,
5231 field_src: LazySrcLoc,5235 field_src: LazySrcLoc,
5232 field_name: InternPool.NullTerminatedString,5236 field_name: InternPool.NullTerminatedString,
5233) CompileError {5237) CompileError {
5234 const mod = sema.mod;5238 const mod = sema.mod;
5235 const gpa = sema.gpa;5239 const gpa = sema.gpa;
52365240
5237 const fqn = try union_obj.getFullyQualifiedName(mod);5241 const decl = mod.declPtr(union_obj.decl);
5242 const fqn = try decl.getFullyQualifiedName(mod);
52385243
5239 const msg = msg: {5244 const msg = msg: {
5240 const msg = try sema.errMsg(5245 const msg = try sema.errMsg(
...@@ -5244,7 +5249,7 @@ fn failWithBadUnionFieldAccess(...@@ -5244,7 +5249,7 @@ fn failWithBadUnionFieldAccess(
5244 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },5249 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
5245 );5250 );
5246 errdefer msg.destroy(gpa);5251 errdefer msg.destroy(gpa);
5247 try mod.errNoteNonLazy(union_obj.srcLoc(mod), msg, "union declared here", .{});5252 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "union declared here", .{});
5248 break :msg msg;5253 break :msg msg;
5249 };5254 };
5250 return sema.failWithOwnedErrorMsg(msg);5255 return sema.failWithOwnedErrorMsg(msg);
...@@ -10500,6 +10505,7 @@ const SwitchProngAnalysis = struct {...@@ -10500,6 +10505,7 @@ const SwitchProngAnalysis = struct {
10500 ) CompileError!Air.Inst.Ref {10505 ) CompileError!Air.Inst.Ref {
10501 const sema = spa.sema;10506 const sema = spa.sema;
10502 const mod = sema.mod;10507 const mod = sema.mod;
10508 const ip = &mod.intern_pool;
1050310509
10504 const zir_datas = sema.code.instructions.items(.data);10510 const zir_datas = sema.code.instructions.items(.data);
10505 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;10511 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
...@@ -10511,9 +10517,9 @@ const SwitchProngAnalysis = struct {...@@ -10511,9 +10517,9 @@ const SwitchProngAnalysis = struct {
10511 if (inline_case_capture != .none) {10517 if (inline_case_capture != .none) {
10512 const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;10518 const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;
10513 if (operand_ty.zigTypeTag(mod) == .Union) {10519 if (operand_ty.zigTypeTag(mod) == .Union) {
10514 const field_index = @as(u32, @intCast(operand_ty.unionTagFieldIndex(item_val, mod).?));10520 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, mod).?);
10515 const union_obj = mod.typeToUnion(operand_ty).?;10521 const union_obj = mod.typeToUnion(operand_ty).?;
10516 const field_ty = union_obj.fields.values()[field_index].ty;10522 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
10517 if (capture_byref) {10523 if (capture_byref) {
10518 const ptr_field_ty = try mod.ptrType(.{10524 const ptr_field_ty = try mod.ptrType(.{
10519 .child = field_ty.toIntern(),10525 .child = field_ty.toIntern(),
...@@ -10535,7 +10541,7 @@ const SwitchProngAnalysis = struct {...@@ -10535,7 +10541,7 @@ const SwitchProngAnalysis = struct {
10535 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);10541 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
10536 } else {10542 } else {
10537 if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| {10543 if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| {
10538 const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un;10544 const tag_and_val = ip.indexToKey(union_val.toIntern()).un;
10539 return Air.internedToRef(tag_and_val.val);10545 return Air.internedToRef(tag_and_val.val);
10540 }10546 }
10541 return block.addStructFieldVal(spa.operand, field_index, field_ty);10547 return block.addStructFieldVal(spa.operand, field_index, field_ty);
...@@ -10568,14 +10574,14 @@ const SwitchProngAnalysis = struct {...@@ -10568,14 +10574,14 @@ const SwitchProngAnalysis = struct {
10568 const union_obj = mod.typeToUnion(operand_ty).?;10574 const union_obj = mod.typeToUnion(operand_ty).?;
10569 const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;10575 const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
1057010576
10571 const first_field_index = @as(u32, @intCast(operand_ty.unionTagFieldIndex(first_item_val, mod).?));10577 const first_field_index: u32 = mod.unionTagFieldIndex(union_obj, first_item_val).?;
10572 const first_field = union_obj.fields.values()[first_field_index];10578 const first_field_ty = union_obj.field_types.get(ip)[first_field_index].toType();
1057310579
10574 const field_tys = try sema.arena.alloc(Type, case_vals.len);10580 const field_tys = try sema.arena.alloc(Type, case_vals.len);
10575 for (case_vals, field_tys) |item, *field_ty| {10581 for (case_vals, field_tys) |item, *field_ty| {
10576 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;10582 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
10577 const field_idx = @as(u32, @intCast(operand_ty.unionTagFieldIndex(item_val, sema.mod).?));10583 const field_idx = mod.unionTagFieldIndex(union_obj, item_val).?;
10578 field_ty.* = union_obj.fields.values()[field_idx].ty;10584 field_ty.* = union_obj.field_types.get(ip)[field_idx].toType();
10579 }10585 }
1058010586
10581 // Fast path: if all the operands are the same type already, we don't need to hit10587 // Fast path: if all the operands are the same type already, we don't need to hit
...@@ -10682,7 +10688,7 @@ const SwitchProngAnalysis = struct {...@@ -10682,7 +10688,7 @@ const SwitchProngAnalysis = struct {
1068210688
10683 if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {10689 if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {
10684 if (operand_val.isUndef(mod)) return mod.undefRef(capture_ty);10690 if (operand_val.isUndef(mod)) return mod.undefRef(capture_ty);
10685 const union_val = mod.intern_pool.indexToKey(operand_val.toIntern()).un;10691 const union_val = ip.indexToKey(operand_val.toIntern()).un;
10686 if (union_val.tag.toValue().isUndef(mod)) return mod.undefRef(capture_ty);10692 if (union_val.tag.toValue().isUndef(mod)) return mod.undefRef(capture_ty);
10687 const uncoerced = Air.internedToRef(union_val.val);10693 const uncoerced = Air.internedToRef(union_val.val);
10688 return sema.coerce(block, capture_ty, uncoerced, operand_src);10694 return sema.coerce(block, capture_ty, uncoerced, operand_src);
...@@ -10704,7 +10710,7 @@ const SwitchProngAnalysis = struct {...@@ -10704,7 +10710,7 @@ const SwitchProngAnalysis = struct {
10704 }10710 }
10705 // All fields are in-memory coercible to the resolved type!10711 // All fields are in-memory coercible to the resolved type!
10706 // Just take the first field and bitcast the result.10712 // Just take the first field and bitcast the result.
10707 const uncoerced = try block.addStructFieldVal(spa.operand, first_field_index, first_field.ty);10713 const uncoerced = try block.addStructFieldVal(spa.operand, first_field_index, first_field_ty);
10708 return block.addBitCast(capture_ty, uncoerced);10714 return block.addBitCast(capture_ty, uncoerced);
10709 };10715 };
1071010716
...@@ -12287,7 +12293,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -12287,7 +12293,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
12287 for (seen_enum_fields, 0..) |seen_field, index| {12293 for (seen_enum_fields, 0..) |seen_field, index| {
12288 if (seen_field != null) continue;12294 if (seen_field != null) continue;
12289 const union_obj = mod.typeToUnion(maybe_union_ty).?;12295 const union_obj = mod.typeToUnion(maybe_union_ty).?;
12290 const field_ty = union_obj.fields.values()[index].ty;12296 const field_ty = union_obj.field_types.get(ip)[index].toType();
12291 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;12297 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
12292 } else false12298 } else false
12293 else12299 else
...@@ -12800,9 +12806,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12800,9 +12806,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12800 break :hf struct_obj.fields.contains(field_name);12806 break :hf struct_obj.fields.contains(field_name);
12801 },12807 },
12802 .union_type => |union_type| {12808 .union_type => |union_type| {
12803 const union_obj = mod.unionPtr(union_type.index);12809 const union_obj = ip.loadUnionType(union_type);
12804 assert(union_obj.haveFieldTypes());12810 break :hf union_obj.nameIndex(ip, field_name) != null;
12805 break :hf union_obj.fields.contains(field_name);
12806 },12811 },
12807 .enum_type => |enum_type| {12812 .enum_type => |enum_type| {
12808 break :hf enum_type.nameIndex(ip, field_name) != null;12813 break :hf enum_type.nameIndex(ip, field_name) != null;
...@@ -17271,16 +17276,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17271,16 +17276,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17271 };17276 };
1727217277
17273 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout17278 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
17274 const layout = ty.containerLayout(mod);17279 const union_obj = mod.typeToUnion(ty).?;
17280 const layout = union_obj.getLayout(ip);
1727517281
17276 const union_fields = ty.unionFields(mod);17282 const union_field_vals = try gpa.alloc(InternPool.Index, union_obj.field_names.len);
17277 const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count());
17278 defer gpa.free(union_field_vals);17283 defer gpa.free(union_field_vals);
1727917284
17280 for (union_field_vals, 0..) |*field_val, i| {17285 for (union_field_vals, 0..) |*field_val, i| {
17281 const field = union_fields.values()[i];
17282 // TODO: write something like getCoercedInts to avoid needing to dupe17286 // TODO: write something like getCoercedInts to avoid needing to dupe
17283 const name = try sema.arena.dupe(u8, ip.stringToSlice(union_fields.keys()[i]));17287 const name = try sema.arena.dupe(u8, ip.stringToSlice(union_obj.field_names.get(ip)[i]));
17284 const name_val = v: {17288 const name_val = v: {
17285 var anon_decl = try block.startAnonDecl();17289 var anon_decl = try block.startAnonDecl();
17286 defer anon_decl.deinit();17290 defer anon_decl.deinit();
...@@ -17304,15 +17308,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17304,15 +17308,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17304 };17308 };
1730517309
17306 const alignment = switch (layout) {17310 const alignment = switch (layout) {
17307 .Auto, .Extern => try sema.unionFieldAlignment(field),17311 .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)),
17308 .Packed => 0,17312 .Packed => 0,
17309 };17313 };
1731017314
17315 const field_ty = union_obj.field_types.get(ip)[i];
17311 const union_field_fields = .{17316 const union_field_fields = .{
17312 // name: []const u8,17317 // name: []const u8,
17313 name_val,17318 name_val,
17314 // type: type,17319 // type: type,
17315 field.ty.toIntern(),17320 field_ty,
17316 // alignment: comptime_int,17321 // alignment: comptime_int,
17317 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),17322 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
17318 };17323 };
...@@ -18929,18 +18934,18 @@ fn unionInit(...@@ -18929,18 +18934,18 @@ fn unionInit(
18929 field_src: LazySrcLoc,18934 field_src: LazySrcLoc,
18930) CompileError!Air.Inst.Ref {18935) CompileError!Air.Inst.Ref {
18931 const mod = sema.mod;18936 const mod = sema.mod;
18937 const ip = &mod.intern_pool;
18932 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);18938 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
18933 const field = union_ty.unionFields(mod).values()[field_index];18939 const field_ty = mod.typeToUnion(union_ty).?.field_types.get(ip)[field_index].toType();
18934 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);18940 const init = try sema.coerce(block, field_ty, uncasted_init, init_src);
1893518941
18936 if (try sema.resolveMaybeUndefVal(init)) |init_val| {18942 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
18937 const tag_ty = union_ty.unionTagTypeHypothetical(mod);18943 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
18938 const enum_field_index = @as(u32, @intCast(tag_ty.enumFieldIndex(field_name, mod).?));18944 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
18939 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
18940 return Air.internedToRef((try mod.intern(.{ .un = .{18945 return Air.internedToRef((try mod.intern(.{ .un = .{
18941 .ty = union_ty.toIntern(),18946 .ty = union_ty.toIntern(),
18942 .tag = try tag_val.intern(tag_ty, mod),18947 .tag = try tag_val.intern(tag_ty, mod),
18943 .val = try init_val.intern(field.ty, mod),18948 .val = try init_val.intern(field_ty, mod),
18944 } })));18949 } })));
18945 }18950 }
1894618951
...@@ -18963,6 +18968,7 @@ fn zirStructInit(...@@ -18963,6 +18968,7 @@ fn zirStructInit(
18963 const src = inst_data.src();18968 const src = inst_data.src();
1896418969
18965 const mod = sema.mod;18970 const mod = sema.mod;
18971 const ip = &mod.intern_pool;
18966 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;18972 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
18967 const first_field_type_data = zir_datas[first_item.field_type].pl_node;18973 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
18968 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;18974 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
...@@ -18999,7 +19005,7 @@ fn zirStructInit(...@@ -18999,7 +19005,7 @@ fn zirStructInit(
18999 const field_type_data = zir_datas[item.data.field_type].pl_node;19005 const field_type_data = zir_datas[item.data.field_type].pl_node;
19000 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };19006 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
19001 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;19007 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
19002 const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));19008 const field_name = try ip.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
19003 const field_index = if (resolved_ty.isTuple(mod))19009 const field_index = if (resolved_ty.isTuple(mod))
19004 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)19010 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
19005 else19011 else
...@@ -19040,19 +19046,18 @@ fn zirStructInit(...@@ -19040,19 +19046,18 @@ fn zirStructInit(
19040 const field_type_data = zir_datas[item.data.field_type].pl_node;19046 const field_type_data = zir_datas[item.data.field_type].pl_node;
19041 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };19047 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
19042 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;19048 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
19043 const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));19049 const field_name = try ip.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
19044 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);19050 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
19045 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);19051 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
19046 const enum_field_index = @as(u32, @intCast(tag_ty.enumFieldIndex(field_name, mod).?));19052 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
19047 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
1904819053
19049 const init_inst = try sema.resolveInst(item.data.init);19054 const init_inst = try sema.resolveInst(item.data.init);
19050 if (try sema.resolveMaybeUndefVal(init_inst)) |val| {19055 if (try sema.resolveMaybeUndefVal(init_inst)) |val| {
19051 const field = resolved_ty.unionFields(mod).values()[field_index];19056 const field_ty = mod.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index].toType();
19052 return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{19057 return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{
19053 .ty = resolved_ty.toIntern(),19058 .ty = resolved_ty.toIntern(),
19054 .tag = try tag_val.intern(tag_ty, mod),19059 .tag = try tag_val.intern(tag_ty, mod),
19055 .val = try val.intern(field.ty, mod),19060 .val = try val.intern(field_ty, mod),
19056 } })).toValue(), is_ref);19061 } })).toValue(), is_ref);
19057 }19062 }
1905819063
...@@ -19662,11 +19667,12 @@ fn fieldType(...@@ -19662,11 +19667,12 @@ fn fieldType(
19662 ty_src: LazySrcLoc,19667 ty_src: LazySrcLoc,
19663) CompileError!Air.Inst.Ref {19668) CompileError!Air.Inst.Ref {
19664 const mod = sema.mod;19669 const mod = sema.mod;
19670 const ip = &mod.intern_pool;
19665 var cur_ty = aggregate_ty;19671 var cur_ty = aggregate_ty;
19666 while (true) {19672 while (true) {
19667 try sema.resolveTypeFields(cur_ty);19673 try sema.resolveTypeFields(cur_ty);
19668 switch (cur_ty.zigTypeTag(mod)) {19674 switch (cur_ty.zigTypeTag(mod)) {
19669 .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) {19675 .Struct => switch (ip.indexToKey(cur_ty.toIntern())) {
19670 .anon_struct_type => |anon_struct| {19676 .anon_struct_type => |anon_struct| {
19671 const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);19677 const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
19672 return Air.internedToRef(anon_struct.types[field_index]);19678 return Air.internedToRef(anon_struct.types[field_index]);
...@@ -19681,14 +19687,15 @@ fn fieldType(...@@ -19681,14 +19687,15 @@ fn fieldType(
19681 },19687 },
19682 .Union => {19688 .Union => {
19683 const union_obj = mod.typeToUnion(cur_ty).?;19689 const union_obj = mod.typeToUnion(cur_ty).?;
19684 const field = union_obj.fields.get(field_name) orelse19690 const field_index = union_obj.nameIndex(ip, field_name) orelse
19685 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);19691 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
19686 return Air.internedToRef(field.ty.toIntern());19692 const field_ty = union_obj.field_types.get(ip)[field_index];
19693 return Air.internedToRef(field_ty);
19687 },19694 },
19688 .Optional => {19695 .Optional => {
19689 // Struct/array init through optional requires the child type to not be a pointer.19696 // Struct/array init through optional requires the child type to not be a pointer.
19690 // If the child of .optional is a pointer it'll error on the next loop.19697 // If the child of .optional is a pointer it'll error on the next loop.
19691 cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType();19698 cur_ty = ip.indexToKey(cur_ty.toIntern()).opt_type.toType();
19692 continue;19699 continue;
19693 },19700 },
19694 .ErrorUnion => {19701 .ErrorUnion => {
...@@ -20396,68 +20403,16 @@ fn zirReify(...@@ -20396,68 +20403,16 @@ fn zirReify(
20396 return sema.fail(block, src, "reified unions must have no decls", .{});20403 return sema.fail(block, src, "reified unions must have no decls", .{});
20397 }20404 }
20398 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);20405 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
2039920406 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
20400 // Because these three things each reference each other, `undefined`
20401 // placeholders are used before being set after the union type gains an
20402 // InternPool index.
20403
20404 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
20405 .ty = Type.noreturn,
20406 .val = Value.@"unreachable",
20407 }, name_strategy, "union", inst);
20408 const new_decl = mod.declPtr(new_decl_index);
20409 new_decl.owns_tv = true;
20410 errdefer {
20411 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
20412 mod.abortAnonDecl(new_decl_index);
20413 }
20414
20415 const new_namespace_index = try mod.createNamespace(.{
20416 .parent = block.namespace.toOptional(),
20417 .ty = undefined,
20418 .file_scope = block.getFileScope(mod),
20419 });
20420 const new_namespace = mod.namespacePtr(new_namespace_index);
20421 errdefer mod.destroyNamespace(new_namespace_index);
20422
20423 const union_index = try mod.createUnion(.{
20424 .owner_decl = new_decl_index,
20425 .tag_ty = Type.null,
20426 .fields = .{},
20427 .zir_index = inst,
20428 .layout = layout,
20429 .status = .have_field_types,
20430 .namespace = new_namespace_index,
20431 });
20432 const union_obj = mod.unionPtr(union_index);
20433 errdefer mod.destroyUnion(union_index);
20434
20435 const union_ty = try ip.get(gpa, .{ .union_type = .{
20436 .index = union_index,
20437 .runtime_tag = if (!tag_type_val.isNull(mod))
20438 .tagged
20439 else if (layout != .Auto)
20440 .none
20441 else switch (mod.optimizeMode()) {
20442 .Debug, .ReleaseSafe => .safety,
20443 .ReleaseFast, .ReleaseSmall => .none,
20444 },
20445 } });
20446 // TODO: figure out InternPool removals for incremental compilation
20447 //errdefer ip.remove(union_ty);
20448
20449 new_decl.ty = Type.type;
20450 new_decl.val = union_ty.toValue();
20451 new_namespace.ty = union_ty.toType();
2045220407
20453 // Tag type20408 // Tag type
20454 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
20455 var explicit_tags_seen: []bool = &.{};20409 var explicit_tags_seen: []bool = &.{};
20456 var enum_field_names: []InternPool.NullTerminatedString = &.{};20410 var enum_field_names: []InternPool.NullTerminatedString = &.{};
20411 var enum_tag_ty: InternPool.Index = .none;
20457 if (tag_type_val.optionalValue(mod)) |payload_val| {20412 if (tag_type_val.optionalValue(mod)) |payload_val| {
20458 union_obj.tag_ty = payload_val.toType();20413 enum_tag_ty = payload_val.toType().toIntern();
2045920414
20460 const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) {20415 const enum_type = switch (ip.indexToKey(enum_tag_ty)) {
20461 .enum_type => |x| x,20416 .enum_type => |x| x,
20462 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),20417 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
20463 };20418 };
...@@ -20469,7 +20424,13 @@ fn zirReify(...@@ -20469,7 +20424,13 @@ fn zirReify(
20469 }20424 }
2047020425
20471 // Fields20426 // Fields
20472 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);20427 var any_aligned_fields: bool = false;
20428 var union_fields: std.MultiArrayList(struct {
20429 type: InternPool.Index,
20430 alignment: InternPool.Alignment,
20431 }) = .{};
20432 var field_name_table: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
20433 try field_name_table.ensureTotalCapacity(sema.arena, fields_len);
2047320434
20474 for (0..fields_len) |i| {20435 for (0..fields_len) |i| {
20475 const elem_val = try fields_val.elemValue(mod, i);20436 const elem_val = try fields_val.elemValue(mod, i);
...@@ -20491,15 +20452,15 @@ fn zirReify(...@@ -20491,15 +20452,15 @@ fn zirReify(
20491 }20452 }
2049220453
20493 if (explicit_tags_seen.len > 0) {20454 if (explicit_tags_seen.len > 0) {
20494 const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;20455 const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
20495 const enum_index = tag_info.nameIndex(ip, field_name) orelse {20456 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
20496 const msg = msg: {20457 const msg = msg: {
20497 const msg = try sema.errMsg(block, src, "no field named '{}' in enum '{}'", .{20458 const msg = try sema.errMsg(block, src, "no field named '{}' in enum '{}'", .{
20498 field_name.fmt(ip),20459 field_name.fmt(ip),
20499 union_obj.tag_ty.fmt(mod),20460 enum_tag_ty.toType().fmt(mod),
20500 });20461 });
20501 errdefer msg.destroy(gpa);20462 errdefer msg.destroy(gpa);
20502 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);20463 try sema.addDeclaredHereNote(msg, enum_tag_ty.toType());
20503 break :msg msg;20464 break :msg msg;
20504 };20465 };
20505 return sema.failWithOwnedErrorMsg(msg);20466 return sema.failWithOwnedErrorMsg(msg);
...@@ -20510,17 +20471,20 @@ fn zirReify(...@@ -20510,17 +20471,20 @@ fn zirReify(
20510 explicit_tags_seen[enum_index] = true;20471 explicit_tags_seen[enum_index] = true;
20511 }20472 }
2051220473
20513 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);20474 const gop = field_name_table.getOrPutAssumeCapacity(field_name);
20514 if (gop.found_existing) {20475 if (gop.found_existing) {
20515 // TODO: better source location20476 // TODO: better source location
20516 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});20477 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
20517 }20478 }
2051820479
20519 const field_ty = type_val.toType();20480 const field_ty = type_val.toType();
20520 gop.value_ptr.* = .{20481 const field_align = Alignment.fromByteUnits((try alignment_val.getUnsignedIntAdvanced(mod, sema)).?);
20521 .ty = field_ty,20482 any_aligned_fields = any_aligned_fields or field_align != .none;
20522 .abi_align = Alignment.fromByteUnits((try alignment_val.getUnsignedIntAdvanced(mod, sema)).?),20483
20523 };20484 try union_fields.append(sema.arena, .{
20485 .type = field_ty.toIntern(),
20486 .alignment = field_align,
20487 });
2052420488
20525 if (field_ty.zigTypeTag(mod) == .Opaque) {20489 if (field_ty.zigTypeTag(mod) == .Opaque) {
20526 const msg = msg: {20490 const msg = msg: {
...@@ -20532,7 +20496,7 @@ fn zirReify(...@@ -20532,7 +20496,7 @@ fn zirReify(
20532 };20496 };
20533 return sema.failWithOwnedErrorMsg(msg);20497 return sema.failWithOwnedErrorMsg(msg);
20534 }20498 }
20535 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {20499 if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
20536 const msg = msg: {20500 const msg = msg: {
20537 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});20501 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
20538 errdefer msg.destroy(gpa);20502 errdefer msg.destroy(gpa);
...@@ -20544,7 +20508,7 @@ fn zirReify(...@@ -20544,7 +20508,7 @@ fn zirReify(
20544 break :msg msg;20508 break :msg msg;
20545 };20509 };
20546 return sema.failWithOwnedErrorMsg(msg);20510 return sema.failWithOwnedErrorMsg(msg);
20547 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {20511 } else if (layout == .Packed and !(validatePackedType(field_ty, mod))) {
20548 const msg = msg: {20512 const msg = msg: {
20549 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});20513 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
20550 errdefer msg.destroy(gpa);20514 errdefer msg.destroy(gpa);
...@@ -20560,28 +20524,79 @@ fn zirReify(...@@ -20560,28 +20524,79 @@ fn zirReify(
20560 }20524 }
2056120525
20562 if (explicit_tags_seen.len > 0) {20526 if (explicit_tags_seen.len > 0) {
20563 const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;20527 const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
20564 if (tag_info.names.len > fields_len) {20528 if (tag_info.names.len > fields_len) {
20565 const msg = msg: {20529 const msg = msg: {
20566 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});20530 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
20567 errdefer msg.destroy(gpa);20531 errdefer msg.destroy(gpa);
2056820532
20569 const enum_ty = union_obj.tag_ty;
20570 for (tag_info.names.get(ip), 0..) |field_name, field_index| {20533 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
20571 if (explicit_tags_seen[field_index]) continue;20534 if (explicit_tags_seen[field_index]) continue;
20572 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{20535 try sema.addFieldErrNote(enum_tag_ty.toType(), field_index, msg, "field '{}' missing, declared here", .{
20573 field_name.fmt(ip),20536 field_name.fmt(ip),
20574 });20537 });
20575 }20538 }
20576 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);20539 try sema.addDeclaredHereNote(msg, enum_tag_ty.toType());
20577 break :msg msg;20540 break :msg msg;
20578 };20541 };
20579 return sema.failWithOwnedErrorMsg(msg);20542 return sema.failWithOwnedErrorMsg(msg);
20580 }20543 }
20581 } else {20544 } else {
20582 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null);20545 enum_tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, .none);
20546 }
20547
20548 // Because these three things each reference each other, `undefined`
20549 // placeholders are used before being set after the union type gains an
20550 // InternPool index.
20551
20552 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
20553 .ty = Type.noreturn,
20554 .val = Value.@"unreachable",
20555 }, name_strategy, "union", inst);
20556 const new_decl = mod.declPtr(new_decl_index);
20557 new_decl.owns_tv = true;
20558 errdefer {
20559 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
20560 mod.abortAnonDecl(new_decl_index);
20583 }20561 }
2058420562
20563 const new_namespace_index = try mod.createNamespace(.{
20564 .parent = block.namespace.toOptional(),
20565 .ty = undefined,
20566 .file_scope = block.getFileScope(mod),
20567 });
20568 const new_namespace = mod.namespacePtr(new_namespace_index);
20569 errdefer mod.destroyNamespace(new_namespace_index);
20570
20571 const union_ty = try ip.getUnionType(gpa, .{
20572 .decl = new_decl_index,
20573 .namespace = new_namespace_index,
20574 .enum_tag_ty = enum_tag_ty,
20575 .fields_len = fields_len,
20576 .zir_index = inst,
20577 .flags = .{
20578 .layout = layout,
20579 .status = .have_field_types,
20580 .runtime_tag = if (!tag_type_val.isNull(mod))
20581 .tagged
20582 else if (layout != .Auto)
20583 .none
20584 else switch (block.wantSafety()) {
20585 true => .safety,
20586 false => .none,
20587 },
20588 .any_aligned_fields = any_aligned_fields,
20589 .requires_comptime = .unknown,
20590 .assumed_runtime_bits = false,
20591 },
20592 .field_types = union_fields.items(.type),
20593 .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{},
20594 });
20595
20596 new_decl.ty = Type.type;
20597 new_decl.val = union_ty.toValue();
20598 new_namespace.ty = union_ty.toType();
20599
20585 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);20600 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
20586 try mod.finalizeAnonDecl(new_decl_index);20601 try mod.finalizeAnonDecl(new_decl_index);
20587 return decl_val;20602 return decl_val;
...@@ -23341,7 +23356,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -23341,7 +23356,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
23341 if (mod.typeToStruct(parent_ty)) |struct_obj| {23356 if (mod.typeToStruct(parent_ty)) |struct_obj| {
23342 break :blk struct_obj.fields.values()[field_index].abi_align;23357 break :blk struct_obj.fields.values()[field_index].abi_align;
23343 } else if (mod.typeToUnion(parent_ty)) |union_obj| {23358 } else if (mod.typeToUnion(parent_ty)) |union_obj| {
23344 break :blk union_obj.fields.values()[field_index].abi_align;23359 break :blk union_obj.fieldAlign(ip, field_index);
23345 } else {23360 } else {
23346 break :blk .none;23361 break :blk .none;
23347 }23362 }
...@@ -24683,18 +24698,28 @@ fn validateVarType(...@@ -24683,18 +24698,28 @@ fn validateVarType(
24683 is_extern: bool,24698 is_extern: bool,
24684) CompileError!void {24699) CompileError!void {
24685 const mod = sema.mod;24700 const mod = sema.mod;
24686 if (is_extern and !try sema.validateExternType(var_ty, .other)) {24701 if (is_extern) {
24687 const msg = msg: {24702 if (!try sema.validateExternType(var_ty, .other)) {
24688 const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});24703 const msg = msg: {
24689 errdefer msg.destroy(sema.gpa);24704 const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
24690 const src_decl = mod.declPtr(block.src_decl);24705 errdefer msg.destroy(sema.gpa);
24691 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);24706 const src_decl = mod.declPtr(block.src_decl);
24692 break :msg msg;24707 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
24693 };24708 break :msg msg;
24694 return sema.failWithOwnedErrorMsg(msg);24709 };
24710 return sema.failWithOwnedErrorMsg(msg);
24711 }
24712 } else {
24713 if (var_ty.zigTypeTag(mod) == .Opaque) {
24714 return sema.fail(
24715 block,
24716 src,
24717 "non-extern variable with opaque type '{}'",
24718 .{var_ty.fmt(mod)},
24719 );
24720 }
24695 }24721 }
2469624722
24697 if (is_extern and var_ty.zigTypeTag(mod) == .Opaque) return;
24698 if (!try sema.typeRequiresComptime(var_ty)) return;24723 if (!try sema.typeRequiresComptime(var_ty)) return;
2469924724
24700 const msg = msg: {24725 const msg = msg: {
...@@ -24735,6 +24760,7 @@ fn explainWhyTypeIsComptimeInner(...@@ -24735,6 +24760,7 @@ fn explainWhyTypeIsComptimeInner(
24735 type_set: *TypeSet,24760 type_set: *TypeSet,
24736) CompileError!void {24761) CompileError!void {
24737 const mod = sema.mod;24762 const mod = sema.mod;
24763 const ip = &mod.intern_pool;
24738 switch (ty.zigTypeTag(mod)) {24764 switch (ty.zigTypeTag(mod)) {
24739 .Bool,24765 .Bool,
24740 .Int,24766 .Int,
...@@ -24820,15 +24846,16 @@ fn explainWhyTypeIsComptimeInner(...@@ -24820,15 +24846,16 @@ fn explainWhyTypeIsComptimeInner(
24820 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;24846 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
2482124847
24822 if (mod.typeToUnion(ty)) |union_obj| {24848 if (mod.typeToUnion(ty)) |union_obj| {
24823 for (union_obj.fields.values(), 0..) |field, i| {24849 for (0..union_obj.field_types.len) |i| {
24824 const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{24850 const field_ty = union_obj.field_types.get(ip)[i].toType();
24851 const field_src_loc = mod.fieldSrcLoc(union_obj.decl, .{
24825 .index = i,24852 .index = i,
24826 .range = .type,24853 .range = .type,
24827 });24854 });
2482824855
24829 if (try sema.typeRequiresComptime(field.ty)) {24856 if (try sema.typeRequiresComptime(field_ty)) {
24830 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});24857 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
24831 try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set);24858 try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field_ty, type_set);
24832 }24859 }
24833 }24860 }
24834 }24861 }
...@@ -25886,12 +25913,11 @@ fn fieldCallBind(...@@ -25886,12 +25913,11 @@ fn fieldCallBind(
25886 },25913 },
25887 .Union => {25914 .Union => {
25888 try sema.resolveTypeFields(concrete_ty);25915 try sema.resolveTypeFields(concrete_ty);
25889 const fields = concrete_ty.unionFields(mod);25916 const union_obj = mod.typeToUnion(concrete_ty).?;
25890 const field_index_usize = fields.getIndex(field_name) orelse break :find_field;25917 const field_index = union_obj.nameIndex(ip, field_name) orelse break :find_field;
25891 const field_index = @as(u32, @intCast(field_index_usize));25918 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
25892 const field = fields.values()[field_index];
2589325919
25894 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);25920 return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
25895 },25921 },
25896 .Type => {25922 .Type => {
25897 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);25923 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
...@@ -26378,24 +26404,24 @@ fn unionFieldPtr(...@@ -26378,24 +26404,24 @@ fn unionFieldPtr(
26378 try sema.resolveTypeFields(union_ty);26404 try sema.resolveTypeFields(union_ty);
26379 const union_obj = mod.typeToUnion(union_ty).?;26405 const union_obj = mod.typeToUnion(union_ty).?;
26380 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26406 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
26381 const field = union_obj.fields.values()[field_index];26407 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
26382 const ptr_field_ty = try mod.ptrType(.{26408 const ptr_field_ty = try mod.ptrType(.{
26383 .child = field.ty.toIntern(),26409 .child = field_ty.toIntern(),
26384 .flags = .{26410 .flags = .{
26385 .is_const = union_ptr_info.flags.is_const,26411 .is_const = union_ptr_info.flags.is_const,
26386 .is_volatile = union_ptr_info.flags.is_volatile,26412 .is_volatile = union_ptr_info.flags.is_volatile,
26387 .address_space = union_ptr_info.flags.address_space,26413 .address_space = union_ptr_info.flags.address_space,
26388 .alignment = if (union_obj.layout == .Auto) blk: {26414 .alignment = if (union_obj.getLayout(ip) == .Auto) blk: {
26389 const union_align = union_ptr_info.flags.alignment.toByteUnitsOptional() orelse try sema.typeAbiAlignment(union_ty);26415 const union_align = union_ptr_info.flags.alignment.toByteUnitsOptional() orelse try sema.typeAbiAlignment(union_ty);
26390 const field_align = try sema.unionFieldAlignment(field);26416 const field_align = try sema.unionFieldAlignment(union_obj, field_index);
26391 break :blk InternPool.Alignment.fromByteUnits(@min(union_align, field_align));26417 break :blk InternPool.Alignment.fromByteUnits(@min(union_align, field_align));
26392 } else union_ptr_info.flags.alignment,26418 } else union_ptr_info.flags.alignment,
26393 },26419 },
26394 .packed_offset = union_ptr_info.packed_offset,26420 .packed_offset = union_ptr_info.packed_offset,
26395 });26421 });
26396 const enum_field_index = @as(u32, @intCast(union_obj.tag_ty.enumFieldIndex(field_name, mod).?));26422 const enum_field_index: u32 = @intCast(union_obj.enum_tag_ty.toType().enumFieldIndex(field_name, mod).?);
2639726423
26398 if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {26424 if (initializing and field_ty.zigTypeTag(mod) == .NoReturn) {
26399 const msg = msg: {26425 const msg = msg: {
26400 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});26426 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
26401 errdefer msg.destroy(sema.gpa);26427 errdefer msg.destroy(sema.gpa);
...@@ -26410,7 +26436,7 @@ fn unionFieldPtr(...@@ -26410,7 +26436,7 @@ fn unionFieldPtr(
26410 }26436 }
2641126437
26412 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {26438 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
26413 switch (union_obj.layout) {26439 switch (union_obj.getLayout(ip)) {
26414 .Auto => if (!initializing) {26440 .Auto => if (!initializing) {
26415 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse26441 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
26416 break :ct;26442 break :ct;
...@@ -26418,12 +26444,12 @@ fn unionFieldPtr(...@@ -26418,12 +26444,12 @@ fn unionFieldPtr(
26418 return sema.failWithUseOfUndef(block, src);26444 return sema.failWithUseOfUndef(block, src);
26419 }26445 }
26420 const un = ip.indexToKey(union_val.toIntern()).un;26446 const un = ip.indexToKey(union_val.toIntern()).un;
26421 const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);26447 const field_tag = try mod.enumValueFieldIndex(union_obj.enum_tag_ty.toType(), enum_field_index);
26422 const tag_matches = un.tag == field_tag.toIntern();26448 const tag_matches = un.tag == field_tag.toIntern();
26423 if (!tag_matches) {26449 if (!tag_matches) {
26424 const msg = msg: {26450 const msg = msg: {
26425 const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;26451 const active_index = union_obj.enum_tag_ty.toType().enumTagFieldIndex(un.tag.toValue(), mod).?;
26426 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);26452 const active_field_name = union_obj.enum_tag_ty.toType().enumFieldName(active_index, mod);
26427 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{26453 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
26428 field_name.fmt(ip),26454 field_name.fmt(ip),
26429 active_field_name.fmt(ip),26455 active_field_name.fmt(ip),
...@@ -26447,17 +26473,17 @@ fn unionFieldPtr(...@@ -26447,17 +26473,17 @@ fn unionFieldPtr(
26447 }26473 }
2644826474
26449 try sema.requireRuntimeBlock(block, src, null);26475 try sema.requireRuntimeBlock(block, src, null);
26450 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and26476 if (!initializing and union_obj.getLayout(ip) == .Auto and block.wantSafety() and
26451 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)26477 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
26452 {26478 {
26453 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);26479 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.enum_tag_ty.toType(), enum_field_index);
26454 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());26480 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
26455 // TODO would it be better if get_union_tag supported pointers to unions?26481 // TODO would it be better if get_union_tag supported pointers to unions?
26456 const union_val = try block.addTyOp(.load, union_ty, union_ptr);26482 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
26457 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);26483 const active_tag = try block.addTyOp(.get_union_tag, union_obj.enum_tag_ty.toType(), union_val);
26458 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);26484 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
26459 }26485 }
26460 if (field.ty.zigTypeTag(mod) == .NoReturn) {26486 if (field_ty.zigTypeTag(mod) == .NoReturn) {
26461 _ = try block.addNoOp(.unreach);26487 _ = try block.addNoOp(.unreach);
26462 return Air.Inst.Ref.unreachable_value;26488 return Air.Inst.Ref.unreachable_value;
26463 }26489 }
...@@ -26480,23 +26506,23 @@ fn unionFieldVal(...@@ -26480,23 +26506,23 @@ fn unionFieldVal(
26480 try sema.resolveTypeFields(union_ty);26506 try sema.resolveTypeFields(union_ty);
26481 const union_obj = mod.typeToUnion(union_ty).?;26507 const union_obj = mod.typeToUnion(union_ty).?;
26482 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26508 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
26483 const field = union_obj.fields.values()[field_index];26509 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
26484 const enum_field_index = @as(u32, @intCast(union_obj.tag_ty.enumFieldIndex(field_name, mod).?));26510 const enum_field_index: u32 = @intCast(union_obj.enum_tag_ty.toType().enumFieldIndex(field_name, mod).?);
2648526511
26486 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {26512 if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {
26487 if (union_val.isUndef(mod)) return mod.undefRef(field.ty);26513 if (union_val.isUndef(mod)) return mod.undefRef(field_ty);
2648826514
26489 const un = ip.indexToKey(union_val.toIntern()).un;26515 const un = ip.indexToKey(union_val.toIntern()).un;
26490 const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);26516 const field_tag = try mod.enumValueFieldIndex(union_obj.enum_tag_ty.toType(), enum_field_index);
26491 const tag_matches = un.tag == field_tag.toIntern();26517 const tag_matches = un.tag == field_tag.toIntern();
26492 switch (union_obj.layout) {26518 switch (union_obj.getLayout(ip)) {
26493 .Auto => {26519 .Auto => {
26494 if (tag_matches) {26520 if (tag_matches) {
26495 return Air.internedToRef(un.val);26521 return Air.internedToRef(un.val);
26496 } else {26522 } else {
26497 const msg = msg: {26523 const msg = msg: {
26498 const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;26524 const active_index = union_obj.enum_tag_ty.toType().enumTagFieldIndex(un.tag.toValue(), mod).?;
26499 const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);26525 const active_field_name = union_obj.enum_tag_ty.toType().enumFieldName(active_index, mod);
26500 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{26526 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
26501 field_name.fmt(ip), active_field_name.fmt(ip),26527 field_name.fmt(ip), active_field_name.fmt(ip),
26502 });26528 });
...@@ -26512,7 +26538,7 @@ fn unionFieldVal(...@@ -26512,7 +26538,7 @@ fn unionFieldVal(
26512 return Air.internedToRef(un.val);26538 return Air.internedToRef(un.val);
26513 } else {26539 } else {
26514 const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod);26540 const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod);
26515 if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| {26541 if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field_ty, 0)) |new_val| {
26516 return Air.internedToRef(new_val.toIntern());26542 return Air.internedToRef(new_val.toIntern());
26517 }26543 }
26518 }26544 }
...@@ -26521,19 +26547,19 @@ fn unionFieldVal(...@@ -26521,19 +26547,19 @@ fn unionFieldVal(
26521 }26547 }
2652226548
26523 try sema.requireRuntimeBlock(block, src, null);26549 try sema.requireRuntimeBlock(block, src, null);
26524 if (union_obj.layout == .Auto and block.wantSafety() and26550 if (union_obj.getLayout(ip) == .Auto and block.wantSafety() and
26525 union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)26551 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
26526 {26552 {
26527 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);26553 const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.enum_tag_ty.toType(), enum_field_index);
26528 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());26554 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
26529 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);26555 const active_tag = try block.addTyOp(.get_union_tag, union_obj.enum_tag_ty.toType(), union_byval);
26530 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);26556 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
26531 }26557 }
26532 if (field.ty.zigTypeTag(mod) == .NoReturn) {26558 if (field_ty.zigTypeTag(mod) == .NoReturn) {
26533 _ = try block.addNoOp(.unreach);26559 _ = try block.addNoOp(.unreach);
26534 return Air.Inst.Ref.unreachable_value;26560 return Air.Inst.Ref.unreachable_value;
26535 }26561 }
26536 return block.addStructFieldVal(union_byval, field_index, field.ty);26562 return block.addStructFieldVal(union_byval, field_index, field_ty);
26537}26563}
2653826564
26539fn elemPtr(26565fn elemPtr(
...@@ -30048,14 +30074,14 @@ fn coerceEnumToUnion(...@@ -30048,14 +30074,14 @@ fn coerceEnumToUnion(
30048 };30074 };
3004930075
30050 const union_obj = mod.typeToUnion(union_ty).?;30076 const union_obj = mod.typeToUnion(union_ty).?;
30051 const field = union_obj.fields.values()[field_index];30077 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
30052 try sema.resolveTypeFields(field.ty);30078 try sema.resolveTypeFields(field_ty);
30053 if (field.ty.zigTypeTag(mod) == .NoReturn) {30079 if (field_ty.zigTypeTag(mod) == .NoReturn) {
30054 const msg = msg: {30080 const msg = msg: {
30055 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});30081 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
30056 errdefer msg.destroy(sema.gpa);30082 errdefer msg.destroy(sema.gpa);
3005730083
30058 const field_name = union_obj.fields.keys()[field_index];30084 const field_name = union_obj.field_names.get(ip)[field_index];
30059 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{30085 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
30060 field_name.fmt(ip),30086 field_name.fmt(ip),
30061 });30087 });
...@@ -30064,12 +30090,12 @@ fn coerceEnumToUnion(...@@ -30064,12 +30090,12 @@ fn coerceEnumToUnion(
30064 };30090 };
30065 return sema.failWithOwnedErrorMsg(msg);30091 return sema.failWithOwnedErrorMsg(msg);
30066 }30092 }
30067 const opv = (try sema.typeHasOnePossibleValue(field.ty)) orelse {30093 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
30068 const msg = msg: {30094 const msg = msg: {
30069 const field_name = union_obj.fields.keys()[field_index];30095 const field_name = union_obj.field_names.get(ip)[field_index];
30070 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{30096 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{
30071 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),30097 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),
30072 field.ty.fmt(sema.mod), field_name.fmt(ip),30098 field_ty.fmt(sema.mod), field_name.fmt(ip),
30073 });30099 });
30074 errdefer msg.destroy(sema.gpa);30100 errdefer msg.destroy(sema.gpa);
3007530101
...@@ -30104,8 +30130,8 @@ fn coerceEnumToUnion(...@@ -30104,8 +30130,8 @@ fn coerceEnumToUnion(
30104 var msg: ?*Module.ErrorMsg = null;30130 var msg: ?*Module.ErrorMsg = null;
30105 errdefer if (msg) |some| some.destroy(sema.gpa);30131 errdefer if (msg) |some| some.destroy(sema.gpa);
3010630132
30107 for (union_obj.fields.values(), 0..) |field, i| {30133 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
30108 if (field.ty.zigTypeTag(mod) == .NoReturn) {30134 if (field_ty.toType().zigTypeTag(mod) == .NoReturn) {
30109 const err_msg = msg orelse try sema.errMsg(30135 const err_msg = msg orelse try sema.errMsg(
30110 block,30136 block,
30111 inst_src,30137 inst_src,
...@@ -30114,7 +30140,7 @@ fn coerceEnumToUnion(...@@ -30114,7 +30140,7 @@ fn coerceEnumToUnion(
30114 );30140 );
30115 msg = err_msg;30141 msg = err_msg;
3011630142
30117 try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{});30143 try sema.addFieldErrNote(union_ty, field_index, err_msg, "'noreturn' field here", .{});
30118 }30144 }
30119 }30145 }
30120 if (msg) |some| {30146 if (msg) |some| {
...@@ -30138,11 +30164,9 @@ fn coerceEnumToUnion(...@@ -30138,11 +30164,9 @@ fn coerceEnumToUnion(
30138 );30164 );
30139 errdefer msg.destroy(sema.gpa);30165 errdefer msg.destroy(sema.gpa);
3014030166
30141 var it = union_obj.fields.iterator();30167 for (0..union_obj.field_names.len) |field_index| {
30142 var field_index: usize = 0;30168 const field_name = union_obj.field_names.get(ip)[field_index];
30143 while (it.next()) |field| : (field_index += 1) {30169 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
30144 const field_name = field.key_ptr.*;
30145 const field_ty = field.value_ptr.ty;
30146 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;30170 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
30147 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{30171 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
30148 field_name.fmt(ip),30172 field_name.fmt(ip),
...@@ -30886,6 +30910,9 @@ fn analyzeLoad(...@@ -30886,6 +30910,9 @@ fn analyzeLoad(
30886 .Pointer => ptr_ty.childType(mod),30910 .Pointer => ptr_ty.childType(mod),
30887 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),30911 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
30888 };30912 };
30913 if (elem_ty.zigTypeTag(mod) == .Opaque) {
30914 return sema.fail(block, ptr_src, "cannot load opaque type '{}'", .{elem_ty.fmt(mod)});
30915 }
3088930916
30890 if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {30917 if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {
30891 return Air.internedToRef(opv.toIntern());30918 return Air.internedToRef(opv.toIntern());
...@@ -33816,7 +33843,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -33816,7 +33843,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
33816 }33843 }
3381733844
33818 struct_obj.status = .have_layout;33845 struct_obj.status = .have_layout;
33819 _ = try sema.resolveTypeRequiresComptime(ty);33846 _ = try sema.typeRequiresComptime(ty);
3382033847
33821 if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {33848 if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
33822 const msg = try Module.ErrorMsg.create(33849 const msg = try Module.ErrorMsg.create(
...@@ -34030,44 +34057,46 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void...@@ -34030,44 +34057,46 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
3403034057
34031fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {34058fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
34032 const mod = sema.mod;34059 const mod = sema.mod;
34060 const ip = &mod.intern_pool;
34033 try sema.resolveTypeFields(ty);34061 try sema.resolveTypeFields(ty);
34034 const union_obj = mod.typeToUnion(ty).?;34062 const union_obj = mod.typeToUnion(ty).?;
34035 switch (union_obj.status) {34063 switch (union_obj.flagsPtr(ip).status) {
34036 .none, .have_field_types => {},34064 .none, .have_field_types => {},
34037 .field_types_wip, .layout_wip => {34065 .field_types_wip, .layout_wip => {
34038 const msg = try Module.ErrorMsg.create(34066 const msg = try Module.ErrorMsg.create(
34039 sema.gpa,34067 sema.gpa,
34040 union_obj.srcLoc(sema.mod),34068 mod.declPtr(union_obj.decl).srcLoc(mod),
34041 "union '{}' depends on itself",34069 "union '{}' depends on itself",
34042 .{ty.fmt(sema.mod)},34070 .{ty.fmt(mod)},
34043 );34071 );
34044 return sema.failWithOwnedErrorMsg(msg);34072 return sema.failWithOwnedErrorMsg(msg);
34045 },34073 },
34046 .have_layout, .fully_resolved_wip, .fully_resolved => return,34074 .have_layout, .fully_resolved_wip, .fully_resolved => return,
34047 }34075 }
34048 const prev_status = union_obj.status;34076 const prev_status = union_obj.flagsPtr(ip).status;
34049 errdefer if (union_obj.status == .layout_wip) {34077 errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) {
34050 union_obj.status = prev_status;34078 union_obj.flagsPtr(ip).status = prev_status;
34051 };34079 };
3405234080
34053 union_obj.status = .layout_wip;34081 union_obj.flagsPtr(ip).status = .layout_wip;
34054 for (union_obj.fields.values(), 0..) |field, i| {34082 for (0..union_obj.field_types.len) |field_index| {
34055 sema.resolveTypeLayout(field.ty) catch |err| switch (err) {34083 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
34084 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
34056 error.AnalysisFail => {34085 error.AnalysisFail => {
34057 const msg = sema.err orelse return err;34086 const msg = sema.err orelse return err;
34058 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});34087 try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{});
34059 return err;34088 return err;
34060 },34089 },
34061 else => return err,34090 else => return err,
34062 };34091 };
34063 }34092 }
34064 union_obj.status = .have_layout;34093 union_obj.flagsPtr(ip).status = .have_layout;
34065 _ = try sema.resolveTypeRequiresComptime(ty);34094 _ = try sema.typeRequiresComptime(ty);
3406634095
34067 if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {34096 if (union_obj.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
34068 const msg = try Module.ErrorMsg.create(34097 const msg = try Module.ErrorMsg.create(
34069 sema.gpa,34098 sema.gpa,
34070 union_obj.srcLoc(sema.mod),34099 mod.declPtr(union_obj.decl).srcLoc(mod),
34071 "union layout depends on it having runtime bits",34100 "union layout depends on it having runtime bits",
34072 .{},34101 .{},
34073 );34102 );
...@@ -34075,163 +34104,6 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34075,163 +34104,6 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
34075 }34104 }
34076}34105}
3407734106
34078// In case of querying the ABI alignment of this struct, we will ask
34079// for hasRuntimeBits() of each field, so we need "requires comptime"
34080// to be known already before this function returns.
34081pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
34082 const mod = sema.mod;
34083
34084 return switch (ty.toIntern()) {
34085 .empty_struct_type => false,
34086 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
34087 .int_type => false,
34088 .ptr_type => |ptr_type| {
34089 const child_ty = ptr_type.child.toType();
34090 if (child_ty.zigTypeTag(mod) == .Fn) {
34091 return mod.typeToFunc(child_ty).?.is_generic;
34092 } else {
34093 return sema.resolveTypeRequiresComptime(child_ty);
34094 }
34095 },
34096 .anyframe_type => |child| {
34097 if (child == .none) return false;
34098 return sema.resolveTypeRequiresComptime(child.toType());
34099 },
34100 .array_type => |array_type| return sema.resolveTypeRequiresComptime(array_type.child.toType()),
34101 .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()),
34102 .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()),
34103 .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()),
34104 .error_set_type, .inferred_error_set_type => false,
34105
34106 .func_type => true,
34107
34108 .simple_type => |t| switch (t) {
34109 .f16,
34110 .f32,
34111 .f64,
34112 .f80,
34113 .f128,
34114 .usize,
34115 .isize,
34116 .c_char,
34117 .c_short,
34118 .c_ushort,
34119 .c_int,
34120 .c_uint,
34121 .c_long,
34122 .c_ulong,
34123 .c_longlong,
34124 .c_ulonglong,
34125 .c_longdouble,
34126 .anyopaque,
34127 .bool,
34128 .void,
34129 .anyerror,
34130 .adhoc_inferred_error_set,
34131 .noreturn,
34132 .generic_poison,
34133 .atomic_order,
34134 .atomic_rmw_op,
34135 .calling_convention,
34136 .address_space,
34137 .float_mode,
34138 .reduce_op,
34139 .call_modifier,
34140 .prefetch_options,
34141 .export_options,
34142 .extern_options,
34143 => false,
34144
34145 .type,
34146 .comptime_int,
34147 .comptime_float,
34148 .null,
34149 .undefined,
34150 .enum_literal,
34151 .type_info,
34152 => true,
34153 },
34154 .struct_type => |struct_type| {
34155 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
34156 switch (struct_obj.requires_comptime) {
34157 .no, .wip => return false,
34158 .yes => return true,
34159 .unknown => {
34160 var requires_comptime = false;
34161 struct_obj.requires_comptime = .wip;
34162 for (struct_obj.fields.values()) |field| {
34163 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
34164 }
34165 if (requires_comptime) {
34166 struct_obj.requires_comptime = .yes;
34167 } else {
34168 struct_obj.requires_comptime = .no;
34169 }
34170 return requires_comptime;
34171 },
34172 }
34173 },
34174
34175 .anon_struct_type => |tuple| {
34176 for (tuple.types, tuple.values) |field_ty, field_val| {
34177 const have_comptime_val = field_val != .none;
34178 if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) {
34179 return true;
34180 }
34181 }
34182 return false;
34183 },
34184
34185 .union_type => |union_type| {
34186 const union_obj = mod.unionPtr(union_type.index);
34187 switch (union_obj.requires_comptime) {
34188 .no, .wip => return false,
34189 .yes => return true,
34190 .unknown => {
34191 var requires_comptime = false;
34192 union_obj.requires_comptime = .wip;
34193 for (union_obj.fields.values()) |field| {
34194 if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
34195 }
34196 if (requires_comptime) {
34197 union_obj.requires_comptime = .yes;
34198 } else {
34199 union_obj.requires_comptime = .no;
34200 }
34201 return requires_comptime;
34202 },
34203 }
34204 },
34205
34206 .opaque_type => false,
34207
34208 .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()),
34209
34210 // values, not types
34211 .undef,
34212 .runtime_value,
34213 .simple_value,
34214 .variable,
34215 .extern_func,
34216 .func,
34217 .int,
34218 .err,
34219 .error_union,
34220 .enum_literal,
34221 .enum_tag,
34222 .empty_enum_value,
34223 .float,
34224 .ptr,
34225 .opt,
34226 .aggregate,
34227 .un,
34228 // memoization, not types
34229 .memoized_call,
34230 => unreachable,
34231 },
34232 };
34233}
34234
34235/// Returns `error.AnalysisFail` if any of the types (recursively) failed to34107/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
34236/// be resolved.34108/// be resolved.
34237pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {34109pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {
...@@ -34306,11 +34178,12 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {...@@ -34306,11 +34178,12 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
3430634178
34307fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {34179fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
34308 try sema.resolveUnionLayout(ty);34180 try sema.resolveUnionLayout(ty);
34181 try sema.resolveTypeFields(ty);
3430934182
34310 const mod = sema.mod;34183 const mod = sema.mod;
34311 try sema.resolveTypeFields(ty);34184 const ip = &mod.intern_pool;
34312 const union_obj = mod.typeToUnion(ty).?;34185 const union_obj = mod.typeToUnion(ty).?;
34313 switch (union_obj.status) {34186 switch (union_obj.flagsPtr(ip).status) {
34314 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},34187 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
34315 .fully_resolved_wip, .fully_resolved => return,34188 .fully_resolved_wip, .fully_resolved => return,
34316 }34189 }
...@@ -34319,14 +34192,15 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {...@@ -34319,14 +34192,15 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
34319 // After we have resolve union layout we have to go over the fields again to34192 // After we have resolve union layout we have to go over the fields again to
34320 // make sure pointer fields get their child types resolved as well.34193 // make sure pointer fields get their child types resolved as well.
34321 // See also similar code for structs.34194 // See also similar code for structs.
34322 const prev_status = union_obj.status;34195 const prev_status = union_obj.flagsPtr(ip).status;
34323 errdefer union_obj.status = prev_status;34196 errdefer union_obj.flagsPtr(ip).status = prev_status;
3432434197
34325 union_obj.status = .fully_resolved_wip;34198 union_obj.flagsPtr(ip).status = .fully_resolved_wip;
34326 for (union_obj.fields.values()) |field| {34199 for (0..union_obj.field_types.len) |field_index| {
34327 try sema.resolveTypeFully(field.ty);34200 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
34201 try sema.resolveTypeFully(field_ty);
34328 }34202 }
34329 union_obj.status = .fully_resolved;34203 union_obj.flagsPtr(ip).status = .fully_resolved;
34330 }34204 }
3433134205
34332 // And let's not forget comptime-only status.34206 // And let's not forget comptime-only status.
...@@ -34420,19 +34294,14 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {...@@ -34420,19 +34294,14 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
34420 else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) {34294 else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
34421 .type_struct,34295 .type_struct,
34422 .type_struct_ns,34296 .type_struct_ns,
34423 .type_union_tagged,34297 .type_union,
34424 .type_union_untagged,
34425 .type_union_safety,
34426 .simple_type,34298 .simple_type,
34427 => switch (mod.intern_pool.indexToKey(ty.toIntern())) {34299 => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
34428 .struct_type => |struct_type| {34300 .struct_type => |struct_type| {
34429 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return;34301 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return;
34430 try sema.resolveTypeFieldsStruct(ty, struct_obj);34302 try sema.resolveTypeFieldsStruct(ty, struct_obj);
34431 },34303 },
34432 .union_type => |union_type| {34304 .union_type => |union_type| try sema.resolveTypeFieldsUnion(ty, union_type),
34433 const union_obj = mod.unionPtr(union_type.index);
34434 try sema.resolveTypeFieldsUnion(ty, union_obj);
34435 },
34436 .simple_type => |simple_type| try sema.resolveSimpleType(simple_type),34305 .simple_type => |simple_type| try sema.resolveSimpleType(simple_type),
34437 else => unreachable,34306 else => unreachable,
34438 },34307 },
...@@ -34504,27 +34373,30 @@ fn resolveTypeFieldsStruct(...@@ -34504,27 +34373,30 @@ fn resolveTypeFieldsStruct(
34504 try semaStructFields(sema.mod, struct_obj);34373 try semaStructFields(sema.mod, struct_obj);
34505}34374}
3450634375
34507fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void {34376fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
34508 switch (sema.mod.declPtr(union_obj.owner_decl).analysis) {34377 const mod = sema.mod;
34378 const ip = &mod.intern_pool;
34379 const owner_decl = mod.declPtr(union_type.decl);
34380 switch (owner_decl.analysis) {
34509 .file_failure,34381 .file_failure,
34510 .dependency_failure,34382 .dependency_failure,
34511 .sema_failure,34383 .sema_failure,
34512 .sema_failure_retryable,34384 .sema_failure_retryable,
34513 => {34385 => {
34514 sema.owner_decl.analysis = .dependency_failure;34386 sema.owner_decl.analysis = .dependency_failure;
34515 sema.owner_decl.generation = sema.mod.generation;34387 sema.owner_decl.generation = mod.generation;
34516 return error.AnalysisFail;34388 return error.AnalysisFail;
34517 },34389 },
34518 else => {},34390 else => {},
34519 }34391 }
34520 switch (union_obj.status) {34392 switch (union_type.flagsPtr(ip).status) {
34521 .none => {},34393 .none => {},
34522 .field_types_wip => {34394 .field_types_wip => {
34523 const msg = try Module.ErrorMsg.create(34395 const msg = try Module.ErrorMsg.create(
34524 sema.gpa,34396 sema.gpa,
34525 union_obj.srcLoc(sema.mod),34397 owner_decl.srcLoc(mod),
34526 "union '{}' depends on itself",34398 "union '{}' depends on itself",
34527 .{ty.fmt(sema.mod)},34399 .{ty.fmt(mod)},
34528 );34400 );
34529 return sema.failWithOwnedErrorMsg(msg);34401 return sema.failWithOwnedErrorMsg(msg);
34530 },34402 },
...@@ -34536,10 +34408,10 @@ fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) Compi...@@ -34536,10 +34408,10 @@ fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) Compi
34536 => return,34408 => return,
34537 }34409 }
3453834410
34539 union_obj.status = .field_types_wip;34411 union_type.flagsPtr(ip).status = .field_types_wip;
34540 errdefer union_obj.status = .none;34412 errdefer union_type.flagsPtr(ip).status = .none;
34541 try semaUnionFields(sema.mod, union_obj);34413 try semaUnionFields(mod, sema.arena, union_type);
34542 union_obj.status = .have_field_types;34414 union_type.flagsPtr(ip).status = .have_field_types;
34543}34415}
3454434416
34545/// Returns a normal error set corresponding to the fully populated inferred34417/// Returns a normal error set corresponding to the fully populated inferred
...@@ -35027,24 +34899,24 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35027,24 +34899,24 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35027 struct_obj.have_field_inits = true;34899 struct_obj.have_field_inits = true;
35028}34900}
3502934901
35030fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {34902fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {
35031 const tracy = trace(@src());34903 const tracy = trace(@src());
35032 defer tracy.end();34904 defer tracy.end();
3503334905
35034 const gpa = mod.gpa;34906 const gpa = mod.gpa;
35035 const ip = &mod.intern_pool;34907 const ip = &mod.intern_pool;
35036 const decl_index = union_obj.owner_decl;34908 const decl_index = union_type.decl;
35037 const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir;34909 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
35038 const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;34910 const extended = zir.instructions.items(.data)[union_type.zir_index].extended;
35039 assert(extended.opcode == .union_decl);34911 assert(extended.opcode == .union_decl);
35040 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));34912 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
35041 var extra_index: usize = extended.operand;34913 var extra_index: usize = extended.operand;
3504234914
35043 const src = LazySrcLoc.nodeOffset(0);34915 const src = LazySrcLoc.nodeOffset(0);
35044 extra_index += @intFromBool(small.has_src_node);34916 extra_index += @intFromBool(small.has_src_node);
3504534917
35046 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {34918 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
35047 const ty_ref = @as(Zir.Inst.Ref, @enumFromInt(zir.extra[extra_index]));34919 const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35048 extra_index += 1;34920 extra_index += 1;
35049 break :blk ty_ref;34921 break :blk ty_ref;
35050 } else .none;34922 } else .none;
...@@ -35077,16 +34949,13 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35077,16 +34949,13 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3507734949
35078 const decl = mod.declPtr(decl_index);34950 const decl = mod.declPtr(decl_index);
3507934951
35080 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
35081 defer analysis_arena.deinit();
35082
35083 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);34952 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
35084 defer comptime_mutable_decls.deinit();34953 defer comptime_mutable_decls.deinit();
3508534954
35086 var sema: Sema = .{34955 var sema: Sema = .{
35087 .mod = mod,34956 .mod = mod,
35088 .gpa = gpa,34957 .gpa = gpa,
35089 .arena = analysis_arena.allocator(),34958 .arena = arena,
35090 .code = zir,34959 .code = zir,
35091 .owner_decl = decl,34960 .owner_decl = decl,
35092 .owner_decl_index = decl_index,34961 .owner_decl_index = decl_index,
...@@ -35106,7 +34975,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35106,7 +34975,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35106 .parent = null,34975 .parent = null,
35107 .sema = &sema,34976 .sema = &sema,
35108 .src_decl = decl_index,34977 .src_decl = decl_index,
35109 .namespace = union_obj.namespace,34978 .namespace = union_type.namespace,
35110 .wip_capture_scope = wip_captures.scope,34979 .wip_capture_scope = wip_captures.scope,
35111 .instructions = .{},34980 .instructions = .{},
35112 .inlining = null,34981 .inlining = null,
...@@ -35124,8 +34993,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35124,8 +34993,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35124 _ = try ct_decl.internValue(mod);34993 _ = try ct_decl.internValue(mod);
35125 }34994 }
3512634995
35127 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
35128
35129 var int_tag_ty: Type = undefined;34996 var int_tag_ty: Type = undefined;
35130 var enum_field_names: []InternPool.NullTerminatedString = &.{};34997 var enum_field_names: []InternPool.NullTerminatedString = &.{};
35131 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};34998 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
...@@ -35159,10 +35026,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35159,10 +35026,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35159 }35026 }
35160 } else {35027 } else {
35161 // The provided type is the enum tag type.35028 // The provided type is the enum tag type.
35162 union_obj.tag_ty = provided_ty;35029 union_type.tagTypePtr(ip).* = provided_ty.toIntern();
35163 const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) {35030 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
35164 .enum_type => |x| x,35031 .enum_type => |x| x,
35165 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}),35032 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(mod)}),
35166 };35033 };
35167 // The fields of the union must match the enum exactly.35034 // The fields of the union must match the enum exactly.
35168 // A flag per field is used to check for missing and extraneous fields.35035 // A flag per field is used to check for missing and extraneous fields.
...@@ -35176,6 +35043,15 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35176,6 +35043,15 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35176 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);35043 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
35177 }35044 }
3517835045
35046 var field_types: std.ArrayListUnmanaged(InternPool.Index) = .{};
35047 var field_aligns: std.ArrayListUnmanaged(InternPool.Alignment) = .{};
35048 var field_name_table: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
35049
35050 try field_types.ensureTotalCapacityPrecise(sema.arena, fields_len);
35051 if (small.any_aligned_fields)
35052 try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len);
35053 try field_name_table.ensureTotalCapacity(sema.arena, fields_len);
35054
35179 const bits_per_field = 4;35055 const bits_per_field = 4;
35180 const fields_per_u32 = 32 / bits_per_field;35056 const fields_per_u32 = 32 / bits_per_field;
35181 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;35057 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -35206,19 +35082,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35206,19 +35082,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35206 extra_index += 1;35082 extra_index += 1;
3520735083
35208 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {35084 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
35209 const field_type_ref = @as(Zir.Inst.Ref, @enumFromInt(zir.extra[extra_index]));35085 const field_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35210 extra_index += 1;35086 extra_index += 1;
35211 break :blk field_type_ref;35087 break :blk field_type_ref;
35212 } else .none;35088 } else .none;
3521335089
35214 const align_ref: Zir.Inst.Ref = if (has_align) blk: {35090 const align_ref: Zir.Inst.Ref = if (has_align) blk: {
35215 const align_ref = @as(Zir.Inst.Ref, @enumFromInt(zir.extra[extra_index]));35091 const align_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35216 extra_index += 1;35092 extra_index += 1;
35217 break :blk align_ref;35093 break :blk align_ref;
35218 } else .none;35094 } else .none;
3521935095
35220 const tag_ref: Air.Inst.Ref = if (has_tag) blk: {35096 const tag_ref: Air.Inst.Ref = if (has_tag) blk: {
35221 const tag_ref = @as(Zir.Inst.Ref, @enumFromInt(zir.extra[extra_index]));35097 const tag_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35222 extra_index += 1;35098 extra_index += 1;
35223 break :blk try sema.resolveInst(tag_ref);35099 break :blk try sema.resolveInst(tag_ref);
35224 } else .none;35100 } else .none;
...@@ -35227,7 +35103,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35227,7 +35103,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35227 const enum_tag_val = if (tag_ref != .none) blk: {35103 const enum_tag_val = if (tag_ref != .none) blk: {
35228 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {35104 const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
35229 error.NeededSourceLocation => {35105 error.NeededSourceLocation => {
35230 const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35106 const val_src = mod.fieldSrcLoc(union_type.decl, .{
35231 .index = field_i,35107 .index = field_i,
35232 .range = .value,35108 .range = .value,
35233 }).lazy;35109 }).lazy;
...@@ -35250,8 +35126,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35250,8 +35126,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35250 };35126 };
35251 const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());35127 const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
35252 if (gop.found_existing) {35128 if (gop.found_existing) {
35253 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;35129 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;
35254 const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;35130 const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;
35255 const msg = msg: {35131 const msg = msg: {
35256 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});35132 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});
35257 errdefer msg.destroy(gpa);35133 errdefer msg.destroy(gpa);
...@@ -35275,7 +35151,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35275,7 +35151,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35275 else35151 else
35276 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {35152 sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {
35277 error.NeededSourceLocation => {35153 error.NeededSourceLocation => {
35278 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35154 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35279 .index = field_i,35155 .index = field_i,
35280 .range = .type,35156 .range = .type,
35281 }).lazy;35157 }).lazy;
...@@ -35289,17 +35165,16 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35289,17 +35165,16 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35289 return error.GenericPoison;35165 return error.GenericPoison;
35290 }35166 }
3529135167
35292 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);35168 const gop = field_name_table.getOrPutAssumeCapacity(field_name);
35293 if (gop.found_existing) {35169 if (gop.found_existing) {
35294 const msg = msg: {35170 const msg = msg: {
35295 const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;35171 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;
35296 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{}'", .{35172 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{}'", .{
35297 field_name.fmt(ip),35173 field_name.fmt(ip),
35298 });35174 });
35299 errdefer msg.destroy(gpa);35175 errdefer msg.destroy(gpa);
3530035176
35301 const prev_field_index = union_obj.fields.getIndex(field_name).?;35177 const prev_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;
35302 const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy;
35303 try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});35178 try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});
35304 try sema.errNote(&block_scope, src, msg, "union declared here", .{});35179 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
35305 break :msg msg;35180 break :msg msg;
...@@ -35308,18 +35183,18 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35308,18 +35183,18 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35308 }35183 }
3530935184
35310 if (explicit_tags_seen.len > 0) {35185 if (explicit_tags_seen.len > 0) {
35311 const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;35186 const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
35312 const enum_index = tag_info.nameIndex(ip, field_name) orelse {35187 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
35313 const msg = msg: {35188 const msg = msg: {
35314 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35189 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35315 .index = field_i,35190 .index = field_i,
35316 .range = .type,35191 .range = .type,
35317 }).lazy;35192 }).lazy;
35318 const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{}' in enum '{}'", .{35193 const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{}' in enum '{}'", .{
35319 field_name.fmt(ip), union_obj.tag_ty.fmt(mod),35194 field_name.fmt(ip), union_type.tagTypePtr(ip).toType().fmt(mod),
35320 });35195 });
35321 errdefer msg.destroy(sema.gpa);35196 errdefer msg.destroy(sema.gpa);
35322 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);35197 try sema.addDeclaredHereNote(msg, union_type.tagTypePtr(ip).toType());
35323 break :msg msg;35198 break :msg msg;
35324 };35199 };
35325 return sema.failWithOwnedErrorMsg(msg);35200 return sema.failWithOwnedErrorMsg(msg);
...@@ -35328,11 +35203,29 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35328,11 +35203,29 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35328 // to create the enum type in the first place.35203 // to create the enum type in the first place.
35329 assert(!explicit_tags_seen[enum_index]);35204 assert(!explicit_tags_seen[enum_index]);
35330 explicit_tags_seen[enum_index] = true;35205 explicit_tags_seen[enum_index] = true;
35206
35207 // Enforce the enum fields and the union fields being in the same order.
35208 if (enum_index != field_i) {
35209 const msg = msg: {
35210 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35211 .index = field_i,
35212 .range = .type,
35213 }).lazy;
35214 const enum_field_src = mod.fieldSrcLoc(tag_info.decl, .{ .index = enum_index }).lazy;
35215 const msg = try sema.errMsg(&block_scope, ty_src, "union field '{}' ordered differently than corresponding enum field", .{
35216 field_name.fmt(ip),
35217 });
35218 errdefer msg.destroy(sema.gpa);
35219 try sema.errNote(&block_scope, enum_field_src, msg, "enum field here", .{});
35220 break :msg msg;
35221 };
35222 return sema.failWithOwnedErrorMsg(msg);
35223 }
35331 }35224 }
3533235225
35333 if (field_ty.zigTypeTag(mod) == .Opaque) {35226 if (field_ty.zigTypeTag(mod) == .Opaque) {
35334 const msg = msg: {35227 const msg = msg: {
35335 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35228 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35336 .index = field_i,35229 .index = field_i,
35337 .range = .type,35230 .range = .type,
35338 }).lazy;35231 }).lazy;
...@@ -35344,9 +35237,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35344,9 +35237,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35344 };35237 };
35345 return sema.failWithOwnedErrorMsg(msg);35238 return sema.failWithOwnedErrorMsg(msg);
35346 }35239 }
35347 if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {35240 const layout = union_type.getLayout(ip);
35241 if (layout == .Extern and
35242 !try sema.validateExternType(field_ty, .union_field))
35243 {
35348 const msg = msg: {35244 const msg = msg: {
35349 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35245 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35350 .index = field_i,35246 .index = field_i,
35351 .range = .type,35247 .range = .type,
35352 });35248 });
...@@ -35359,9 +35255,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35359,9 +35255,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35359 break :msg msg;35255 break :msg msg;
35360 };35256 };
35361 return sema.failWithOwnedErrorMsg(msg);35257 return sema.failWithOwnedErrorMsg(msg);
35362 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {35258 } else if (layout == .Packed and !validatePackedType(field_ty, mod)) {
35363 const msg = msg: {35259 const msg = msg: {
35364 const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35260 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
35365 .index = field_i,35261 .index = field_i,
35366 .range = .type,35262 .range = .type,
35367 });35263 });
...@@ -35376,51 +35272,55 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -35376,51 +35272,55 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
35376 return sema.failWithOwnedErrorMsg(msg);35272 return sema.failWithOwnedErrorMsg(msg);
35377 }35273 }
3537835274
35379 gop.value_ptr.* = .{35275 field_types.appendAssumeCapacity(field_ty.toIntern());
35380 .ty = field_ty,
35381 .abi_align = .none,
35382 };
3538335276
35384 if (align_ref != .none) {35277 if (small.any_aligned_fields) {
35385 gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {35278 field_aligns.appendAssumeCapacity(if (align_ref != .none)
35386 error.NeededSourceLocation => {35279 sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
35387 const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{35280 error.NeededSourceLocation => {
35388 .index = field_i,35281 const align_src = mod.fieldSrcLoc(union_type.decl, .{
35389 .range = .alignment,35282 .index = field_i,
35390 }).lazy;35283 .range = .alignment,
35391 _ = try sema.resolveAlign(&block_scope, align_src, align_ref);35284 }).lazy;
35392 unreachable;35285 _ = try sema.resolveAlign(&block_scope, align_src, align_ref);
35393 },35286 unreachable;
35394 else => |e| return e,35287 },
35395 };35288 else => |e| return e,
35289 }
35290 else
35291 .none);
35396 } else {35292 } else {
35397 gop.value_ptr.abi_align = .none;35293 assert(align_ref == .none);
35398 }35294 }
35399 }35295 }
3540035296
35297 union_type.setFieldTypes(ip, field_types.items);
35298 union_type.setFieldAligns(ip, field_aligns.items);
35299
35401 if (explicit_tags_seen.len > 0) {35300 if (explicit_tags_seen.len > 0) {
35402 const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;35301 const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
35403 if (tag_info.names.len > fields_len) {35302 if (tag_info.names.len > fields_len) {
35404 const msg = msg: {35303 const msg = msg: {
35405 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});35304 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
35406 errdefer msg.destroy(sema.gpa);35305 errdefer msg.destroy(sema.gpa);
3540735306
35408 const enum_ty = union_obj.tag_ty;
35409 for (tag_info.names.get(ip), 0..) |field_name, field_index| {35307 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
35410 if (explicit_tags_seen[field_index]) continue;35308 if (explicit_tags_seen[field_index]) continue;
35411 try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{35309 try sema.addFieldErrNote(union_type.tagTypePtr(ip).toType(), field_index, msg, "field '{}' missing, declared here", .{
35412 field_name.fmt(ip),35310 field_name.fmt(ip),
35413 });35311 });
35414 }35312 }
35415 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);35313 try sema.addDeclaredHereNote(msg, union_type.tagTypePtr(ip).toType());
35416 break :msg msg;35314 break :msg msg;
35417 };35315 };
35418 return sema.failWithOwnedErrorMsg(msg);35316 return sema.failWithOwnedErrorMsg(msg);
35419 }35317 }
35420 } else if (enum_field_vals.count() > 0) {35318 } else if (enum_field_vals.count() > 0) {
35421 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj);35319 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
35320 union_type.tagTypePtr(ip).* = enum_ty;
35422 } else {35321 } else {
35423 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj);35322 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_type.decl.toOptional());
35323 union_type.tagTypePtr(ip).* = enum_ty;
35424 }35324 }
35425}35325}
3542635326
...@@ -35434,8 +35334,8 @@ fn generateUnionTagTypeNumbered(...@@ -35434,8 +35334,8 @@ fn generateUnionTagTypeNumbered(
35434 block: *Block,35334 block: *Block,
35435 enum_field_names: []const InternPool.NullTerminatedString,35335 enum_field_names: []const InternPool.NullTerminatedString,
35436 enum_field_vals: []const InternPool.Index,35336 enum_field_vals: []const InternPool.Index,
35437 union_obj: *Module.Union,35337 decl: *Module.Decl,
35438) !Type {35338) !InternPool.Index {
35439 const mod = sema.mod;35339 const mod = sema.mod;
35440 const gpa = sema.gpa;35340 const gpa = sema.gpa;
35441 const ip = &mod.intern_pool;35341 const ip = &mod.intern_pool;
...@@ -35443,7 +35343,7 @@ fn generateUnionTagTypeNumbered(...@@ -35443,7 +35343,7 @@ fn generateUnionTagTypeNumbered(
35443 const src_decl = mod.declPtr(block.src_decl);35343 const src_decl = mod.declPtr(block.src_decl);
35444 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);35344 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
35445 errdefer mod.destroyDecl(new_decl_index);35345 errdefer mod.destroyDecl(new_decl_index);
35446 const fqn = try union_obj.getFullyQualifiedName(mod);35346 const fqn = try decl.getFullyQualifiedName(mod);
35447 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});35347 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
35448 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{35348 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
35449 .ty = Type.noreturn,35349 .ty = Type.noreturn,
...@@ -35472,30 +35372,30 @@ fn generateUnionTagTypeNumbered(...@@ -35472,30 +35372,30 @@ fn generateUnionTagTypeNumbered(
35472 new_decl.val = enum_ty.toValue();35372 new_decl.val = enum_ty.toValue();
3547335373
35474 try mod.finalizeAnonDecl(new_decl_index);35374 try mod.finalizeAnonDecl(new_decl_index);
35475 return enum_ty.toType();35375 return enum_ty;
35476}35376}
3547735377
35478fn generateUnionTagTypeSimple(35378fn generateUnionTagTypeSimple(
35479 sema: *Sema,35379 sema: *Sema,
35480 block: *Block,35380 block: *Block,
35481 enum_field_names: []const InternPool.NullTerminatedString,35381 enum_field_names: []const InternPool.NullTerminatedString,
35482 maybe_union_obj: ?*Module.Union,35382 maybe_decl_index: Module.Decl.OptionalIndex,
35483) !Type {35383) !InternPool.Index {
35484 const mod = sema.mod;35384 const mod = sema.mod;
35485 const ip = &mod.intern_pool;35385 const ip = &mod.intern_pool;
35486 const gpa = sema.gpa;35386 const gpa = sema.gpa;
3548735387
35488 const new_decl_index = new_decl_index: {35388 const new_decl_index = new_decl_index: {
35489 const union_obj = maybe_union_obj orelse {35389 const decl_index = maybe_decl_index.unwrap() orelse {
35490 break :new_decl_index try mod.createAnonymousDecl(block, .{35390 break :new_decl_index try mod.createAnonymousDecl(block, .{
35491 .ty = Type.noreturn,35391 .ty = Type.noreturn,
35492 .val = Value.@"unreachable",35392 .val = Value.@"unreachable",
35493 });35393 });
35494 };35394 };
35395 const fqn = try mod.declPtr(decl_index).getFullyQualifiedName(mod);
35495 const src_decl = mod.declPtr(block.src_decl);35396 const src_decl = mod.declPtr(block.src_decl);
35496 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);35397 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
35497 errdefer mod.destroyDecl(new_decl_index);35398 errdefer mod.destroyDecl(new_decl_index);
35498 const fqn = try union_obj.getFullyQualifiedName(mod);
35499 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});35399 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
35500 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{35400 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
35501 .ty = Type.noreturn,35401 .ty = Type.noreturn,
...@@ -35524,7 +35424,7 @@ fn generateUnionTagTypeSimple(...@@ -35524,7 +35424,7 @@ fn generateUnionTagTypeSimple(
35524 new_decl.val = enum_ty.toValue();35424 new_decl.val = enum_ty.toValue();
3552535425
35526 try mod.finalizeAnonDecl(new_decl_index);35426 try mod.finalizeAnonDecl(new_decl_index);
35527 return enum_ty.toType();35427 return enum_ty;
35528}35428}
3552935429
35530fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {35430fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
...@@ -35787,9 +35687,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -35787,9 +35687,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
35787 .type_struct_ns,35687 .type_struct_ns,
35788 .type_struct_anon,35688 .type_struct_anon,
35789 .type_tuple_anon,35689 .type_tuple_anon,
35790 .type_union_tagged,35690 .type_union,
35791 .type_union_untagged,
35792 .type_union_safety,
35793 => switch (ip.indexToKey(ty.toIntern())) {35691 => switch (ip.indexToKey(ty.toIntern())) {
35794 inline .array_type, .vector_type => |seq_type, seq_tag| {35692 inline .array_type, .vector_type => |seq_type, seq_tag| {
35795 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;35693 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
...@@ -35816,12 +35714,12 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -35816,12 +35714,12 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
35816 field_val.* = field.default_val;35714 field_val.* = field.default_val;
35817 continue;35715 continue;
35818 }35716 }
35819 if (field.ty.eql(ty, sema.mod)) {35717 if (field.ty.eql(ty, mod)) {
35820 const msg = try Module.ErrorMsg.create(35718 const msg = try Module.ErrorMsg.create(
35821 sema.gpa,35719 sema.gpa,
35822 s.srcLoc(sema.mod),35720 s.srcLoc(mod),
35823 "struct '{}' depends on itself",35721 "struct '{}' depends on itself",
35824 .{ty.fmt(sema.mod)},35722 .{ty.fmt(mod)},
35825 );35723 );
35826 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});35724 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
35827 return sema.failWithOwnedErrorMsg(msg);35725 return sema.failWithOwnedErrorMsg(msg);
...@@ -35862,26 +35760,25 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -35862,26 +35760,25 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3586235760
35863 .union_type => |union_type| {35761 .union_type => |union_type| {
35864 try sema.resolveTypeFields(ty);35762 try sema.resolveTypeFields(ty);
35865 const union_obj = mod.unionPtr(union_type.index);35763 const union_obj = ip.loadUnionType(union_type);
35866 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse35764 const tag_val = (try sema.typeHasOnePossibleValue(union_obj.enum_tag_ty.toType())) orelse
35867 return null;35765 return null;
35868 const fields = union_obj.fields.values();35766 if (union_obj.field_types.len == 0) {
35869 if (fields.len == 0) {
35870 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });35767 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
35871 return only.toValue();35768 return only.toValue();
35872 }35769 }
35873 const only_field = fields[0];35770 const only_field_ty = union_obj.field_types.get(ip)[0].toType();
35874 if (only_field.ty.eql(ty, sema.mod)) {35771 if (only_field_ty.eql(ty, mod)) {
35875 const msg = try Module.ErrorMsg.create(35772 const msg = try Module.ErrorMsg.create(
35876 sema.gpa,35773 sema.gpa,
35877 union_obj.srcLoc(sema.mod),35774 mod.declPtr(union_obj.decl).srcLoc(mod),
35878 "union '{}' depends on itself",35775 "union '{}' depends on itself",
35879 .{ty.fmt(sema.mod)},35776 .{ty.fmt(mod)},
35880 );35777 );
35881 try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{});35778 try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{});
35882 return sema.failWithOwnedErrorMsg(msg);35779 return sema.failWithOwnedErrorMsg(msg);
35883 }35780 }
35884 const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse35781 const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse
35885 return null;35782 return null;
35886 const only = try mod.intern(.{ .un = .{35783 const only = try mod.intern(.{ .un = .{
35887 .ty = ty.toIntern(),35784 .ty = ty.toIntern(),
...@@ -36225,10 +36122,11 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {...@@ -36225,10 +36122,11 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
36225/// elsewhere in value.zig36122/// elsewhere in value.zig
36226pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {36123pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
36227 const mod = sema.mod;36124 const mod = sema.mod;
36125 const ip = &mod.intern_pool;
36228 return switch (ty.toIntern()) {36126 return switch (ty.toIntern()) {
36229 .empty_struct_type => false,36127 .empty_struct_type => false,
3623036128
36231 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {36129 else => switch (ip.indexToKey(ty.toIntern())) {
36232 .int_type => return false,36130 .int_type => return false,
36233 .ptr_type => |ptr_type| {36131 .ptr_type => |ptr_type| {
36234 const child_ty = ptr_type.child.toType();36132 const child_ty = ptr_type.child.toType();
...@@ -36254,7 +36152,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -36254,7 +36152,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3625436152
36255 .func_type => true,36153 .func_type => true,
3625636154
36257 .simple_type => |t| return switch (t) {36155 .simple_type => |t| switch (t) {
36258 .f16,36156 .f16,
36259 .f32,36157 .f32,
36260 .f64,36158 .f64,
...@@ -36272,9 +36170,11 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -36272,9 +36170,11 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
36272 .c_longlong,36170 .c_longlong,
36273 .c_ulonglong,36171 .c_ulonglong,
36274 .c_longdouble,36172 .c_longdouble,
36173 .anyopaque,
36275 .bool,36174 .bool,
36276 .void,36175 .void,
36277 .anyerror,36176 .anyerror,
36177 .adhoc_inferred_error_set,
36278 .noreturn,36178 .noreturn,
36279 .generic_poison,36179 .generic_poison,
36280 .atomic_order,36180 .atomic_order,
...@@ -36287,10 +36187,8 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -36287,10 +36187,8 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
36287 .prefetch_options,36187 .prefetch_options,
36288 .export_options,36188 .export_options,
36289 .extern_options,36189 .extern_options,
36290 .adhoc_inferred_error_set,
36291 => false,36190 => false,
3629236191
36293 .anyopaque,
36294 .type,36192 .type,
36295 .comptime_int,36193 .comptime_int,
36296 .comptime_float,36194 .comptime_float,
...@@ -36335,30 +36233,31 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -36335,30 +36233,31 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
36335 },36233 },
3633636234
36337 .union_type => |union_type| {36235 .union_type => |union_type| {
36338 const union_obj = mod.unionPtr(union_type.index);36236 switch (union_type.flagsPtr(ip).requires_comptime) {
36339 switch (union_obj.requires_comptime) {
36340 .no, .wip => return false,36237 .no, .wip => return false,
36341 .yes => return true,36238 .yes => return true,
36342 .unknown => {36239 .unknown => {
36343 if (union_obj.status == .field_types_wip)36240 if (union_type.flagsPtr(ip).status == .field_types_wip)
36344 return false;36241 return false;
3634536242
36346 try sema.resolveTypeFieldsUnion(ty, union_obj);36243 try sema.resolveTypeFieldsUnion(ty, union_type);
36244 const union_obj = ip.loadUnionType(union_type);
3634736245
36348 union_obj.requires_comptime = .wip;36246 union_obj.flagsPtr(ip).requires_comptime = .wip;
36349 for (union_obj.fields.values()) |field| {36247 for (0..union_obj.field_types.len) |field_index| {
36350 if (try sema.typeRequiresComptime(field.ty)) {36248 const field_ty = union_obj.field_types.get(ip)[field_index];
36351 union_obj.requires_comptime = .yes;36249 if (try sema.typeRequiresComptime(field_ty.toType())) {
36250 union_obj.flagsPtr(ip).requires_comptime = .yes;
36352 return true;36251 return true;
36353 }36252 }
36354 }36253 }
36355 union_obj.requires_comptime = .no;36254 union_obj.flagsPtr(ip).requires_comptime = .no;
36356 return false;36255 return false;
36357 },36256 },
36358 }36257 }
36359 },36258 },
3636036259
36361 .opaque_type => true,36260 .opaque_type => false,
36362 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),36261 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
3636336262
36364 // values, not types36263 // values, not types
...@@ -36404,12 +36303,15 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {...@@ -36404,12 +36303,15 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {
36404}36303}
3640536304
36406/// Not valid to call for packed unions.36305/// Not valid to call for packed unions.
36407/// Keep implementation in sync with `Module.Union.Field.normalAlignment`.36306/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
36408fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 {36307/// TODO: this returns alignment in byte units should should be a u64
36409 return @as(u32, @intCast(if (field.ty.isNoReturn(sema.mod))36308fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 {
36410 036309 const mod = sema.mod;
36411 else36310 const ip = &mod.intern_pool;
36412 field.abi_align.toByteUnitsOptional() orelse try sema.typeAbiAlignment(field.ty)));36311 if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a);
36312 const field_ty = u.field_types.get(ip)[field_index].toType();
36313 if (field_ty.isNoReturn(sema.mod)) return 0;
36314 return @intCast(try sema.typeAbiAlignment(field_ty));
36413}36315}
3641436316
36415/// Keep implementation in sync with `Module.Struct.Field.alignment`.36317/// Keep implementation in sync with `Module.Struct.Field.alignment`.
...@@ -36459,11 +36361,12 @@ fn unionFieldIndex(...@@ -36459,11 +36361,12 @@ fn unionFieldIndex(
36459 field_src: LazySrcLoc,36361 field_src: LazySrcLoc,
36460) !u32 {36362) !u32 {
36461 const mod = sema.mod;36363 const mod = sema.mod;
36364 const ip = &mod.intern_pool;
36462 try sema.resolveTypeFields(union_ty);36365 try sema.resolveTypeFields(union_ty);
36463 const union_obj = mod.typeToUnion(union_ty).?;36366 const union_obj = mod.typeToUnion(union_ty).?;
36464 const field_index_usize = union_obj.fields.getIndex(field_name) orelse36367 const field_index = union_obj.nameIndex(ip, field_name) orelse
36465 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);36368 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
36466 return @as(u32, @intCast(field_index_usize));36369 return @intCast(field_index);
36467}36370}
3646836371
36469fn structFieldIndex(36372fn structFieldIndex(
src/TypedValue.zig+2-2
...@@ -88,7 +88,7 @@ pub fn print(...@@ -88,7 +88,7 @@ pub fn print(
88 try writer.writeAll(".{ ");88 try writer.writeAll(".{ ");
8989
90 try print(.{90 try print(.{
91 .ty = mod.unionPtr(ip.indexToKey(ty.toIntern()).union_type.index).tag_ty,91 .ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
92 .val = union_val.tag,92 .val = union_val.tag,
93 }, writer, level - 1, mod);93 }, writer, level - 1, mod);
94 try writer.writeAll(" = ");94 try writer.writeAll(" = ");
...@@ -357,7 +357,7 @@ pub fn print(...@@ -357,7 +357,7 @@ pub fn print(
357 try writer.print(".{i}", .{field_name.fmt(ip)});357 try writer.print(".{i}", .{field_name.fmt(ip)});
358 },358 },
359 .Union => {359 .Union => {
360 const field_name = container_ty.unionFields(mod).keys()[@as(usize, @intCast(field.index))];360 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];
361 try writer.print(".{i}", .{field_name.fmt(ip)});361 try writer.print(".{i}", .{field_name.fmt(ip)});
362 },362 },
363 .Pointer => {363 .Pointer => {
src/Zir.zig+2-1
...@@ -2956,7 +2956,8 @@ pub const Inst = struct {...@@ -2956,7 +2956,8 @@ pub const Inst = struct {
2956 /// true | true | union(enum(T)) { }2956 /// true | true | union(enum(T)) { }
2957 /// true | false | union(T) { }2957 /// true | false | union(T) { }
2958 auto_enum_tag: bool,2958 auto_enum_tag: bool,
2959 _: u6 = undefined,2959 any_aligned_fields: bool,
2960 _: u5 = undefined,
2960 };2961 };
2961 };2962 };
29622963
src/arch/aarch64/abi.zig+8-6
...@@ -75,14 +75,15 @@ pub fn classifyType(ty: Type, mod: *Module) Class {...@@ -75,14 +75,15 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
7575
76const sret_float_count = 4;76const sret_float_count = 4;
77fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {77fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
78 const ip = &mod.intern_pool;
78 const target = mod.getTarget();79 const target = mod.getTarget();
79 const invalid = std.math.maxInt(u8);80 const invalid = std.math.maxInt(u8);
80 switch (ty.zigTypeTag(mod)) {81 switch (ty.zigTypeTag(mod)) {
81 .Union => {82 .Union => {
82 const fields = ty.unionFields(mod);83 const union_obj = mod.typeToUnion(ty).?;
83 var max_count: u8 = 0;84 var max_count: u8 = 0;
84 for (fields.values()) |field| {85 for (union_obj.field_types.get(ip)) |field_ty| {
85 const field_count = countFloats(field.ty, mod, maybe_float_bits);86 const field_count = countFloats(field_ty.toType(), mod, maybe_float_bits);
86 if (field_count == invalid) return invalid;87 if (field_count == invalid) return invalid;
87 if (field_count > max_count) max_count = field_count;88 if (field_count > max_count) max_count = field_count;
88 if (max_count > sret_float_count) return invalid;89 if (max_count > sret_float_count) return invalid;
...@@ -116,11 +117,12 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {...@@ -116,11 +117,12 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
116}117}
117118
118pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {119pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {
120 const ip = &mod.intern_pool;
119 switch (ty.zigTypeTag(mod)) {121 switch (ty.zigTypeTag(mod)) {
120 .Union => {122 .Union => {
121 const fields = ty.unionFields(mod);123 const union_obj = mod.typeToUnion(ty).?;
122 for (fields.values()) |field| {124 for (union_obj.field_types.get(ip)) |field_ty| {
123 if (getFloatArrayType(field.ty, mod)) |some| return some;125 if (getFloatArrayType(field_ty.toType(), mod)) |some| return some;
124 }126 }
125 return null;127 return null;
126 },128 },
src/arch/arm/abi.zig+11-6
...@@ -29,6 +29,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -29,6 +29,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
2929
30 var maybe_float_bits: ?u16 = null;30 var maybe_float_bits: ?u16 = null;
31 const max_byval_size = 512;31 const max_byval_size = 512;
32 const ip = &mod.intern_pool;
32 switch (ty.zigTypeTag(mod)) {33 switch (ty.zigTypeTag(mod)) {
33 .Struct => {34 .Struct => {
34 const bit_size = ty.bitSize(mod);35 const bit_size = ty.bitSize(mod);
...@@ -54,7 +55,8 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -54,7 +55,8 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
54 },55 },
55 .Union => {56 .Union => {
56 const bit_size = ty.bitSize(mod);57 const bit_size = ty.bitSize(mod);
57 if (ty.containerLayout(mod) == .Packed) {58 const union_obj = mod.typeToUnion(ty).?;
59 if (union_obj.getLayout(ip) == .Packed) {
58 if (bit_size > 64) return .memory;60 if (bit_size > 64) return .memory;
59 return .byval;61 return .byval;
60 }62 }
...@@ -62,8 +64,10 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -62,8 +64,10 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
62 const float_count = countFloats(ty, mod, &maybe_float_bits);64 const float_count = countFloats(ty, mod, &maybe_float_bits);
63 if (float_count <= byval_float_count) return .byval;65 if (float_count <= byval_float_count) return .byval;
6466
65 for (ty.unionFields(mod).values()) |field| {67 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
66 if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) {68 if (field_ty.toType().bitSize(mod) > 32 or
69 mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)) > 32)
70 {
67 return Class.arrSize(bit_size, 64);71 return Class.arrSize(bit_size, 64);
68 }72 }
69 }73 }
...@@ -117,14 +121,15 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -117,14 +121,15 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
117121
118const byval_float_count = 4;122const byval_float_count = 4;
119fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 {123fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 {
124 const ip = &mod.intern_pool;
120 const target = mod.getTarget();125 const target = mod.getTarget();
121 const invalid = std.math.maxInt(u32);126 const invalid = std.math.maxInt(u32);
122 switch (ty.zigTypeTag(mod)) {127 switch (ty.zigTypeTag(mod)) {
123 .Union => {128 .Union => {
124 const fields = ty.unionFields(mod);129 const union_obj = mod.typeToUnion(ty).?;
125 var max_count: u32 = 0;130 var max_count: u32 = 0;
126 for (fields.values()) |field| {131 for (union_obj.field_types.get(ip)) |field_ty| {
127 const field_count = countFloats(field.ty, mod, maybe_float_bits);132 const field_count = countFloats(field_ty.toType(), mod, maybe_float_bits);
128 if (field_count == invalid) return invalid;133 if (field_count == invalid) return invalid;
129 if (field_count > max_count) max_count = field_count;134 if (field_count > max_count) max_count = field_count;
130 if (max_count > byval_float_count) return invalid;135 if (max_count > byval_float_count) return invalid;
src/arch/wasm/CodeGen.zig+33-29
...@@ -1717,6 +1717,7 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch {...@@ -1717,6 +1717,7 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch {
1717/// For a given `Type`, will return true when the type will be passed1717/// For a given `Type`, will return true when the type will be passed
1718/// by reference, rather than by value1718/// by reference, rather than by value
1719fn isByRef(ty: Type, mod: *Module) bool {1719fn isByRef(ty: Type, mod: *Module) bool {
1720 const ip = &mod.intern_pool;
1720 const target = mod.getTarget();1721 const target = mod.getTarget();
1721 switch (ty.zigTypeTag(mod)) {1722 switch (ty.zigTypeTag(mod)) {
1722 .Type,1723 .Type,
...@@ -1742,7 +1743,7 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -1742,7 +1743,7 @@ fn isByRef(ty: Type, mod: *Module) bool {
1742 => return ty.hasRuntimeBitsIgnoreComptime(mod),1743 => return ty.hasRuntimeBitsIgnoreComptime(mod),
1743 .Union => {1744 .Union => {
1744 if (mod.typeToUnion(ty)) |union_obj| {1745 if (mod.typeToUnion(ty)) |union_obj| {
1745 if (union_obj.layout == .Packed) {1746 if (union_obj.getLayout(ip) == .Packed) {
1746 return ty.abiSize(mod) > 8;1747 return ty.abiSize(mod) > 8;
1747 }1748 }
1748 }1749 }
...@@ -2974,7 +2975,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue...@@ -2974,7 +2975,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
2974 .Union => switch (parent_ty.containerLayout(mod)) {2975 .Union => switch (parent_ty.containerLayout(mod)) {
2975 .Packed => 0,2976 .Packed => 0,
2976 else => blk: {2977 else => blk: {
2977 const layout: Module.Union.Layout = parent_ty.unionGetLayout(mod);2978 const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod);
2978 if (layout.payload_size == 0) break :blk 0;2979 if (layout.payload_size == 0) break :blk 0;
2979 if (layout.payload_align > layout.tag_align) break :blk 0;2980 if (layout.payload_align > layout.tag_align) break :blk 0;
29802981
...@@ -3058,8 +3059,9 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(...@@ -3058,8 +3059,9 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
30583059
3059fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {3060fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3060 const mod = func.bin_file.base.options.module.?;3061 const mod = func.bin_file.base.options.module.?;
3062 const ip = &mod.intern_pool;
3061 var val = arg_val;3063 var val = arg_val;
3062 switch (mod.intern_pool.indexToKey(val.ip_index)) {3064 switch (ip.indexToKey(val.ip_index)) {
3063 .runtime_value => |rt| val = rt.val.toValue(),3065 .runtime_value => |rt| val = rt.val.toValue(),
3064 else => {},3066 else => {},
3065 }3067 }
...@@ -3110,7 +3112,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3110,7 +3112,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3110 => unreachable, // comptime-only types3112 => unreachable, // comptime-only types
3111 };3113 };
31123114
3113 switch (mod.intern_pool.indexToKey(val.ip_index)) {3115 switch (ip.indexToKey(val.ip_index)) {
3114 .int_type,3116 .int_type,
3115 .ptr_type,3117 .ptr_type,
3116 .array_type,3118 .array_type,
...@@ -3198,7 +3200,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3198,7 +3200,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3198 return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});3200 return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});
3199 },3201 },
3200 .enum_tag => |enum_tag| {3202 .enum_tag => |enum_tag| {
3201 const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);3203 const int_tag_ty = ip.typeOf(enum_tag.int);
3202 return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType());3204 return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType());
3203 },3205 },
3204 .float => |float| switch (float.storage) {3206 .float => |float| switch (float.storage) {
...@@ -3210,7 +3212,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3210,7 +3212,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3210 .ptr => |ptr| switch (ptr.addr) {3212 .ptr => |ptr| switch (ptr.addr) {
3211 .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),3213 .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),
3212 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),3214 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
3213 .int => |int| return func.lowerConstant(int.toValue(), mod.intern_pool.typeOf(int).toType()),3215 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),
3214 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),3216 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3215 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),3217 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
3216 },3218 },
...@@ -3224,7 +3226,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3224,7 +3226,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3224 } else {3226 } else {
3225 return WValue{ .imm32 = @intFromBool(!val.isNull(mod)) };3227 return WValue{ .imm32 = @intFromBool(!val.isNull(mod)) };
3226 },3228 },
3227 .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) {3229 .aggregate => switch (ip.indexToKey(ty.ip_index)) {
3228 .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}),3230 .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}),
3229 .vector_type => {3231 .vector_type => {
3230 assert(determineSimdStoreStrategy(ty, mod) == .direct);3232 assert(determineSimdStoreStrategy(ty, mod) == .direct);
...@@ -3245,11 +3247,12 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3245,11 +3247,12 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3245 },3247 },
3246 else => unreachable,3248 else => unreachable,
3247 },3249 },
3248 .un => |union_obj| {3250 .un => |un| {
3249 // in this case we have a packed union which will not be passed by reference.3251 // in this case we have a packed union which will not be passed by reference.
3250 const field_index = ty.unionTagFieldIndex(union_obj.tag.toValue(), func.bin_file.base.options.module.?).?;3252 const union_obj = mod.typeToUnion(ty).?;
3251 const field_ty = ty.unionFields(mod).values()[field_index].ty;3253 const field_index = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
3252 return func.lowerConstant(union_obj.val.toValue(), field_ty);3254 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
3255 return func.lowerConstant(un.val.toValue(), field_ty);
3253 },3256 },
3254 .memoized_call => unreachable,3257 .memoized_call => unreachable,
3255 }3258 }
...@@ -5163,6 +5166,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5163,6 +5166,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51635166
5164fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5167fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5165 const mod = func.bin_file.base.options.module.?;5168 const mod = func.bin_file.base.options.module.?;
5169 const ip = &mod.intern_pool;
5166 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;5170 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
5167 const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;5171 const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;
51685172
...@@ -5170,8 +5174,8 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5170,8 +5174,8 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5170 const union_ty = func.typeOfIndex(inst);5174 const union_ty = func.typeOfIndex(inst);
5171 const layout = union_ty.unionGetLayout(mod);5175 const layout = union_ty.unionGetLayout(mod);
5172 const union_obj = mod.typeToUnion(union_ty).?;5176 const union_obj = mod.typeToUnion(union_ty).?;
5173 const field = union_obj.fields.values()[extra.field_index];5177 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
5174 const field_name = union_obj.fields.keys()[extra.field_index];5178 const field_name = union_obj.field_names.get(ip)[extra.field_index];
51755179
5176 const tag_int = blk: {5180 const tag_int = blk: {
5177 const tag_ty = union_ty.unionTagTypeHypothetical(mod);5181 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
...@@ -5191,24 +5195,24 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5191,24 +5195,24 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5191 const result_ptr = try func.allocStack(union_ty);5195 const result_ptr = try func.allocStack(union_ty);
5192 const payload = try func.resolveInst(extra.init);5196 const payload = try func.resolveInst(extra.init);
5193 if (layout.tag_align >= layout.payload_align) {5197 if (layout.tag_align >= layout.payload_align) {
5194 if (isByRef(field.ty, mod)) {5198 if (isByRef(field_ty, mod)) {
5195 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);5199 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);
5196 try func.store(payload_ptr, payload, field.ty, 0);5200 try func.store(payload_ptr, payload, field_ty, 0);
5197 } else {5201 } else {
5198 try func.store(result_ptr, payload, field.ty, @as(u32, @intCast(layout.tag_size)));5202 try func.store(result_ptr, payload, field_ty, @intCast(layout.tag_size));
5199 }5203 }
52005204
5201 if (layout.tag_size > 0) {5205 if (layout.tag_size > 0) {
5202 try func.store(result_ptr, tag_int, union_obj.tag_ty, 0);5206 try func.store(result_ptr, tag_int, union_obj.enum_tag_ty.toType(), 0);
5203 }5207 }
5204 } else {5208 } else {
5205 try func.store(result_ptr, payload, field.ty, 0);5209 try func.store(result_ptr, payload, field_ty, 0);
5206 if (layout.tag_size > 0) {5210 if (layout.tag_size > 0) {
5207 try func.store(5211 try func.store(
5208 result_ptr,5212 result_ptr,
5209 tag_int,5213 tag_int,
5210 union_obj.tag_ty,5214 union_obj.enum_tag_ty.toType(),
5211 @as(u32, @intCast(layout.payload_size)),5215 @intCast(layout.payload_size),
5212 );5216 );
5213 }5217 }
5214 }5218 }
...@@ -5216,18 +5220,18 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5216,18 +5220,18 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5216 } else {5220 } else {
5217 const operand = try func.resolveInst(extra.init);5221 const operand = try func.resolveInst(extra.init);
5218 const union_int_type = try mod.intType(.unsigned, @as(u16, @intCast(union_ty.bitSize(mod))));5222 const union_int_type = try mod.intType(.unsigned, @as(u16, @intCast(union_ty.bitSize(mod))));
5219 if (field.ty.zigTypeTag(mod) == .Float) {5223 if (field_ty.zigTypeTag(mod) == .Float) {
5220 const int_type = try mod.intType(.unsigned, @as(u16, @intCast(field.ty.bitSize(mod))));5224 const int_type = try mod.intType(.unsigned, @intCast(field_ty.bitSize(mod)));
5221 const bitcasted = try func.bitcast(field.ty, int_type, operand);5225 const bitcasted = try func.bitcast(field_ty, int_type, operand);
5222 const casted = try func.trunc(bitcasted, int_type, union_int_type);5226 const casted = try func.trunc(bitcasted, int_type, union_int_type);
5223 break :result try casted.toLocal(func, field.ty);5227 break :result try casted.toLocal(func, field_ty);
5224 } else if (field.ty.isPtrAtRuntime(mod)) {5228 } else if (field_ty.isPtrAtRuntime(mod)) {
5225 const int_type = try mod.intType(.unsigned, @as(u16, @intCast(field.ty.bitSize(mod))));5229 const int_type = try mod.intType(.unsigned, @intCast(field_ty.bitSize(mod)));
5226 const casted = try func.intcast(operand, int_type, union_int_type);5230 const casted = try func.intcast(operand, int_type, union_int_type);
5227 break :result try casted.toLocal(func, field.ty);5231 break :result try casted.toLocal(func, field_ty);
5228 }5232 }
5229 const casted = try func.intcast(operand, field.ty, union_int_type);5233 const casted = try func.intcast(operand, field_ty, union_int_type);
5230 break :result try casted.toLocal(func, field.ty);5234 break :result try casted.toLocal(func, field_ty);
5231 }5235 }
5232 };5236 };
52335237
src/arch/wasm/abi.zig+18-11
...@@ -6,6 +6,7 @@...@@ -6,6 +6,7 @@
66
7const std = @import("std");7const std = @import("std");
8const Target = std.Target;8const Target = std.Target;
9const assert = std.debug.assert;
910
10const Type = @import("../../type.zig").Type;11const Type = @import("../../type.zig").Type;
11const Module = @import("../../Module.zig");12const Module = @import("../../Module.zig");
...@@ -22,6 +23,7 @@ const direct: [2]Class = .{ .direct, .none };...@@ -22,6 +23,7 @@ const direct: [2]Class = .{ .direct, .none };
22/// or returned as value within a wasm function.23/// or returned as value within a wasm function.
23/// When all elements result in `.none`, no value must be passed in or returned.24/// When all elements result in `.none`, no value must be passed in or returned.
24pub fn classifyType(ty: Type, mod: *Module) [2]Class {25pub fn classifyType(ty: Type, mod: *Module) [2]Class {
26 const ip = &mod.intern_pool;
25 const target = mod.getTarget();27 const target = mod.getTarget();
26 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none;28 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none;
27 switch (ty.zigTypeTag(mod)) {29 switch (ty.zigTypeTag(mod)) {
...@@ -56,22 +58,24 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {...@@ -56,22 +58,24 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
56 .Bool => return direct,58 .Bool => return direct,
57 .Array => return memory,59 .Array => return memory,
58 .Optional => {60 .Optional => {
59 std.debug.assert(ty.isPtrLikeOptional(mod));61 assert(ty.isPtrLikeOptional(mod));
60 return direct;62 return direct;
61 },63 },
62 .Pointer => {64 .Pointer => {
63 std.debug.assert(!ty.isSlice(mod));65 assert(!ty.isSlice(mod));
64 return direct;66 return direct;
65 },67 },
66 .Union => {68 .Union => {
67 if (ty.containerLayout(mod) == .Packed) {69 const union_obj = mod.typeToUnion(ty).?;
70 if (union_obj.getLayout(ip) == .Packed) {
68 if (ty.bitSize(mod) <= 64) return direct;71 if (ty.bitSize(mod) <= 64) return direct;
69 return .{ .direct, .direct };72 return .{ .direct, .direct };
70 }73 }
71 const layout = ty.unionGetLayout(mod);74 const layout = ty.unionGetLayout(mod);
72 std.debug.assert(layout.tag_size == 0);75 assert(layout.tag_size == 0);
73 if (ty.unionFields(mod).count() > 1) return memory;76 if (union_obj.field_names.len > 1) return memory;
74 return classifyType(ty.unionFields(mod).values()[0].ty, mod);77 const first_field_ty = union_obj.field_types.get(ip)[0].toType();
78 return classifyType(first_field_ty, mod);
75 },79 },
76 .ErrorUnion,80 .ErrorUnion,
77 .Frame,81 .Frame,
...@@ -94,6 +98,7 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {...@@ -94,6 +98,7 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
94/// Asserts given type can be represented as scalar, such as98/// Asserts given type can be represented as scalar, such as
95/// a struct with a single scalar field.99/// a struct with a single scalar field.
96pub fn scalarType(ty: Type, mod: *Module) Type {100pub fn scalarType(ty: Type, mod: *Module) Type {
101 const ip = &mod.intern_pool;
97 switch (ty.zigTypeTag(mod)) {102 switch (ty.zigTypeTag(mod)) {
98 .Struct => {103 .Struct => {
99 switch (ty.containerLayout(mod)) {104 switch (ty.containerLayout(mod)) {
...@@ -102,20 +107,22 @@ pub fn scalarType(ty: Type, mod: *Module) Type {...@@ -102,20 +107,22 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
102 return scalarType(struct_obj.backing_int_ty, mod);107 return scalarType(struct_obj.backing_int_ty, mod);
103 },108 },
104 else => {109 else => {
105 std.debug.assert(ty.structFieldCount(mod) == 1);110 assert(ty.structFieldCount(mod) == 1);
106 return scalarType(ty.structFieldType(0, mod), mod);111 return scalarType(ty.structFieldType(0, mod), mod);
107 },112 },
108 }113 }
109 },114 },
110 .Union => {115 .Union => {
111 if (ty.containerLayout(mod) != .Packed) {116 const union_obj = mod.typeToUnion(ty).?;
112 const layout = ty.unionGetLayout(mod);117 if (union_obj.getLayout(ip) != .Packed) {
118 const layout = mod.getUnionLayout(union_obj);
113 if (layout.payload_size == 0 and layout.tag_size != 0) {119 if (layout.payload_size == 0 and layout.tag_size != 0) {
114 return scalarType(ty.unionTagTypeSafety(mod).?, mod);120 return scalarType(ty.unionTagTypeSafety(mod).?, mod);
115 }121 }
116 std.debug.assert(ty.unionFields(mod).count() == 1);122 assert(union_obj.field_types.len == 1);
117 }123 }
118 return scalarType(ty.unionFields(mod).values()[0].ty, mod);124 const first_field_ty = union_obj.field_types.get(ip)[0].toType();
125 return scalarType(first_field_ty, mod);
119 },126 },
120 else => return ty,127 else => return ty,
121 }128 }
src/arch/x86_64/CodeGen.zig+3-2
...@@ -11534,6 +11534,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11534,6 +11534,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1153411534
11535fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {11535fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
11536 const mod = self.bin_file.options.module.?;11536 const mod = self.bin_file.options.module.?;
11537 const ip = &mod.intern_pool;
11537 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;11538 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
11538 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;11539 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
11539 const result: MCValue = result: {11540 const result: MCValue = result: {
...@@ -11553,8 +11554,8 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11553,8 +11554,8 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
11553 const dst_mcv = try self.allocRegOrMem(inst, false);11554 const dst_mcv = try self.allocRegOrMem(inst, false);
1155411555
11555 const union_obj = mod.typeToUnion(union_ty).?;11556 const union_obj = mod.typeToUnion(union_ty).?;
11556 const field_name = union_obj.fields.keys()[extra.field_index];11557 const field_name = union_obj.field_names.get(ip)[extra.field_index];
11557 const tag_ty = union_obj.tag_ty;11558 const tag_ty = union_obj.enum_tag_ty.toType();
11558 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;11559 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
11559 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);11560 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
11560 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);11561 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
src/arch/x86_64/abi.zig+8-7
...@@ -69,6 +69,7 @@ pub const Context = enum { ret, arg, other };...@@ -69,6 +69,7 @@ pub const Context = enum { ret, arg, other };
69/// There are a maximum of 8 possible return slots. Returned values are in69/// There are a maximum of 8 possible return slots. Returned values are in
70/// the beginning of the array; unused slots are filled with .none.70/// the beginning of the array; unused slots are filled with .none.
71pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {71pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
72 const ip = &mod.intern_pool;
72 const target = mod.getTarget();73 const target = mod.getTarget();
73 const memory_class = [_]Class{74 const memory_class = [_]Class{
74 .memory, .none, .none, .none,75 .memory, .none, .none, .none,
...@@ -328,8 +329,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -328,8 +329,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
328 // it contains unaligned fields, it has class MEMORY"329 // it contains unaligned fields, it has class MEMORY"
329 // "If the size of the aggregate exceeds a single eightbyte, each is classified330 // "If the size of the aggregate exceeds a single eightbyte, each is classified
330 // separately.".331 // separately.".
331 const ty_size = ty.abiSize(mod);332 const union_obj = mod.typeToUnion(ty).?;
332 if (ty.containerLayout(mod) == .Packed) {333 const ty_size = mod.unionAbiSize(union_obj);
334 if (union_obj.getLayout(ip) == .Packed) {
333 assert(ty_size <= 128);335 assert(ty_size <= 128);
334 result[0] = .integer;336 result[0] = .integer;
335 if (ty_size > 64) result[1] = .integer;337 if (ty_size > 64) result[1] = .integer;
...@@ -338,15 +340,14 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -338,15 +340,14 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
338 if (ty_size > 64)340 if (ty_size > 64)
339 return memory_class;341 return memory_class;
340342
341 const fields = ty.unionFields(mod);343 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
342 for (fields.values()) |field| {344 if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| {
343 if (field.abi_align != .none) {345 if (a < field_ty.toType().abiAlignment(mod)) {
344 if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) {
345 return memory_class;346 return memory_class;
346 }347 }
347 }348 }
348 // Combine this field with the previous one.349 // Combine this field with the previous one.
349 const field_class = classifySystemV(field.ty, mod, .other);350 const field_class = classifySystemV(field_ty.toType(), mod, .other);
350 for (&result, 0..) |*result_item, i| {351 for (&result, 0..) |*result_item, i| {
351 const field_item = field_class[i];352 const field_item = field_class[i];
352 // "If both classes are equal, this is the resulting class."353 // "If both classes are equal, this is the resulting class."
src/codegen.zig+11-11
...@@ -185,8 +185,9 @@ pub fn generateSymbol(...@@ -185,8 +185,9 @@ pub fn generateSymbol(
185 defer tracy.end();185 defer tracy.end();
186186
187 const mod = bin_file.options.module.?;187 const mod = bin_file.options.module.?;
188 const ip = &mod.intern_pool;
188 var typed_value = arg_tv;189 var typed_value = arg_tv;
189 switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {190 switch (ip.indexToKey(typed_value.val.toIntern())) {
190 .runtime_value => |rt| typed_value.val = rt.val.toValue(),191 .runtime_value => |rt| typed_value.val = rt.val.toValue(),
191 else => {},192 else => {},
192 }193 }
...@@ -205,7 +206,7 @@ pub fn generateSymbol(...@@ -205,7 +206,7 @@ pub fn generateSymbol(
205 return .ok;206 return .ok;
206 }207 }
207208
208 switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {209 switch (ip.indexToKey(typed_value.val.toIntern())) {
209 .int_type,210 .int_type,
210 .ptr_type,211 .ptr_type,
211 .array_type,212 .array_type,
...@@ -385,7 +386,7 @@ pub fn generateSymbol(...@@ -385,7 +386,7 @@ pub fn generateSymbol(
385 try code.appendNTimes(0, padding);386 try code.appendNTimes(0, padding);
386 }387 }
387 },388 },
388 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(typed_value.ty.toIntern())) {389 .aggregate => |aggregate| switch (ip.indexToKey(typed_value.ty.toIntern())) {
389 .array_type => |array_type| switch (aggregate.storage) {390 .array_type => |array_type| switch (aggregate.storage) {
390 .bytes => |bytes| try code.appendSlice(bytes),391 .bytes => |bytes| try code.appendSlice(bytes),
391 .elems, .repeated_elem => {392 .elems, .repeated_elem => {
...@@ -442,7 +443,7 @@ pub fn generateSymbol(...@@ -442,7 +443,7 @@ pub fn generateSymbol(
442 if (!field_ty.toType().hasRuntimeBits(mod)) continue;443 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
443444
444 const field_val = switch (aggregate.storage) {445 const field_val = switch (aggregate.storage) {
445 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{446 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
446 .ty = field_ty,447 .ty = field_ty,
447 .storage = .{ .u64 = bytes[index] },448 .storage = .{ .u64 = bytes[index] },
448 } }),449 } }),
...@@ -484,7 +485,7 @@ pub fn generateSymbol(...@@ -484,7 +485,7 @@ pub fn generateSymbol(
484 const field_ty = field.ty;485 const field_ty = field.ty;
485486
486 const field_val = switch (aggregate.storage) {487 const field_val = switch (aggregate.storage) {
487 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{488 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
488 .ty = field_ty.toIntern(),489 .ty = field_ty.toIntern(),
489 .storage = .{ .u64 = bytes[index] },490 .storage = .{ .u64 = bytes[index] },
490 } }),491 } }),
...@@ -522,8 +523,8 @@ pub fn generateSymbol(...@@ -522,8 +523,8 @@ pub fn generateSymbol(
522523
523 if (!field_ty.hasRuntimeBits(mod)) continue;524 if (!field_ty.hasRuntimeBits(mod)) continue;
524525
525 const field_val = switch (mod.intern_pool.indexToKey(typed_value.val.toIntern()).aggregate.storage) {526 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
526 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{527 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
527 .ty = field_ty.toIntern(),528 .ty = field_ty.toIntern(),
528 .storage = .{ .u64 = bytes[field_offset.field] },529 .storage = .{ .u64 = bytes[field_offset.field] },
529 } }),530 } }),
...@@ -570,10 +571,9 @@ pub fn generateSymbol(...@@ -570,10 +571,9 @@ pub fn generateSymbol(
570 }571 }
571 }572 }
572573
573 const union_ty = mod.typeToUnion(typed_value.ty).?;574 const union_obj = mod.typeToUnion(typed_value.ty).?;
574 const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;575 const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
575 assert(union_ty.haveFieldTypes());576 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
576 const field_ty = union_ty.fields.values()[field_index].ty;
577 if (!field_ty.hasRuntimeBits(mod)) {577 if (!field_ty.hasRuntimeBits(mod)) {
578 try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);578 try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
579 } else {579 } else {
...@@ -593,7 +593,7 @@ pub fn generateSymbol(...@@ -593,7 +593,7 @@ pub fn generateSymbol(
593593
594 if (layout.tag_size > 0 and layout.tag_align < layout.payload_align) {594 if (layout.tag_size > 0 and layout.tag_align < layout.payload_align) {
595 switch (try generateSymbol(bin_file, src_loc, .{595 switch (try generateSymbol(bin_file, src_loc, .{
596 .ty = union_ty.tag_ty,596 .ty = union_obj.enum_tag_ty.toType(),
597 .val = un.tag.toValue(),597 .val = un.tag.toValue(),
598 }, code, debug_output, reloc_info)) {598 }, code, debug_output, reloc_info)) {
599 .ok => {},599 .ok => {},
src/codegen/c.zig+54-47
...@@ -708,8 +708,10 @@ pub const DeclGen = struct {...@@ -708,8 +708,10 @@ pub const DeclGen = struct {
708 location: ValueRenderLocation,708 location: ValueRenderLocation,
709 ) error{ OutOfMemory, AnalysisFail }!void {709 ) error{ OutOfMemory, AnalysisFail }!void {
710 const mod = dg.module;710 const mod = dg.module;
711 const ip = &mod.intern_pool;
712
711 var val = arg_val;713 var val = arg_val;
712 switch (mod.intern_pool.indexToKey(val.ip_index)) {714 switch (ip.indexToKey(val.ip_index)) {
713 .runtime_value => |rt| val = rt.val.toValue(),715 .runtime_value => |rt| val = rt.val.toValue(),
714 else => {},716 else => {},
715 }717 }
...@@ -836,9 +838,10 @@ pub const DeclGen = struct {...@@ -836,9 +838,10 @@ pub const DeclGen = struct {
836 if (layout.tag_size != 0) try writer.writeByte(',');838 if (layout.tag_size != 0) try writer.writeByte(',');
837 try writer.writeAll(" .payload = {");839 try writer.writeAll(" .payload = {");
838 }840 }
839 for (ty.unionFields(mod).values()) |field| {841 const union_obj = mod.typeToUnion(ty).?;
840 if (!field.ty.hasRuntimeBits(mod)) continue;842 for (union_obj.field_types.get(ip)) |field_ty| {
841 try dg.renderValue(writer, field.ty, val, initializer_type);843 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
844 try dg.renderValue(writer, field_ty.toType(), val, initializer_type);
842 break;845 break;
843 }846 }
844 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');847 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
...@@ -912,7 +915,7 @@ pub const DeclGen = struct {...@@ -912,7 +915,7 @@ pub const DeclGen = struct {
912 unreachable;915 unreachable;
913 }916 }
914917
915 switch (mod.intern_pool.indexToKey(val.ip_index)) {918 switch (ip.indexToKey(val.ip_index)) {
916 // types, not values919 // types, not values
917 .int_type,920 .int_type,
918 .ptr_type,921 .ptr_type,
...@@ -962,7 +965,7 @@ pub const DeclGen = struct {...@@ -962,7 +965,7 @@ pub const DeclGen = struct {
962 },965 },
963 },966 },
964 .err => |err| try writer.print("zig_error_{}", .{967 .err => |err| try writer.print("zig_error_{}", .{
965 fmtIdent(mod.intern_pool.stringToSlice(err.name)),968 fmtIdent(ip.stringToSlice(err.name)),
966 }),969 }),
967 .error_union => |error_union| {970 .error_union => |error_union| {
968 const payload_ty = ty.errorUnionPayload(mod);971 const payload_ty = ty.errorUnionPayload(mod);
...@@ -1024,8 +1027,8 @@ pub const DeclGen = struct {...@@ -1024,8 +1027,8 @@ pub const DeclGen = struct {
1024 try writer.writeAll(" }");1027 try writer.writeAll(" }");
1025 },1028 },
1026 .enum_tag => {1029 .enum_tag => {
1027 const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag;1030 const enum_tag = ip.indexToKey(val.ip_index).enum_tag;
1028 const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);1031 const int_tag_ty = ip.typeOf(enum_tag.int);
1029 try dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location);1032 try dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location);
1030 },1033 },
1031 .float => {1034 .float => {
...@@ -1205,7 +1208,7 @@ pub const DeclGen = struct {...@@ -1205,7 +1208,7 @@ pub const DeclGen = struct {
1205 try dg.renderValue(writer, Type.bool, is_null_val, initializer_type);1208 try dg.renderValue(writer, Type.bool, is_null_val, initializer_type);
1206 try writer.writeAll(" }");1209 try writer.writeAll(" }");
1207 },1210 },
1208 .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) {1211 .aggregate => switch (ip.indexToKey(ty.ip_index)) {
1209 .array_type, .vector_type => {1212 .array_type, .vector_type => {
1210 if (location == .FunctionArgument) {1213 if (location == .FunctionArgument) {
1211 try writer.writeByte('(');1214 try writer.writeByte('(');
...@@ -1278,8 +1281,8 @@ pub const DeclGen = struct {...@@ -1278,8 +1281,8 @@ pub const DeclGen = struct {
12781281
1279 if (!empty) try writer.writeByte(',');1282 if (!empty) try writer.writeByte(',');
12801283
1281 const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {1284 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1282 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{1285 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1283 .ty = field_ty,1286 .ty = field_ty,
1284 .storage = .{ .u64 = bytes[field_i] },1287 .storage = .{ .u64 = bytes[field_i] },
1285 } }),1288 } }),
...@@ -1309,8 +1312,8 @@ pub const DeclGen = struct {...@@ -1309,8 +1312,8 @@ pub const DeclGen = struct {
1309 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1312 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
13101313
1311 if (!empty) try writer.writeByte(',');1314 if (!empty) try writer.writeByte(',');
1312 const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {1315 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1313 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{1316 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1314 .ty = field.ty.toIntern(),1317 .ty = field.ty.toIntern(),
1315 .storage = .{ .u64 = bytes[field_i] },1318 .storage = .{ .u64 = bytes[field_i] },
1316 } }),1319 } }),
...@@ -1358,8 +1361,8 @@ pub const DeclGen = struct {...@@ -1358,8 +1361,8 @@ pub const DeclGen = struct {
1358 if (field.is_comptime) continue;1361 if (field.is_comptime) continue;
1359 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1362 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
13601363
1361 const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {1364 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1362 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{1365 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1363 .ty = field.ty.toIntern(),1366 .ty = field.ty.toIntern(),
1364 .storage = .{ .u64 = bytes[field_i] },1367 .storage = .{ .u64 = bytes[field_i] },
1365 } }),1368 } }),
...@@ -1400,8 +1403,8 @@ pub const DeclGen = struct {...@@ -1400,8 +1403,8 @@ pub const DeclGen = struct {
1400 try dg.renderType(writer, ty);1403 try dg.renderType(writer, ty);
1401 try writer.writeByte(')');1404 try writer.writeByte(')');
14021405
1403 const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {1406 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1404 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{1407 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1405 .ty = field.ty.toIntern(),1408 .ty = field.ty.toIntern(),
1406 .storage = .{ .u64 = bytes[field_i] },1409 .storage = .{ .u64 = bytes[field_i] },
1407 } }),1410 } }),
...@@ -1435,10 +1438,11 @@ pub const DeclGen = struct {...@@ -1435,10 +1438,11 @@ pub const DeclGen = struct {
1435 try writer.writeByte(')');1438 try writer.writeByte(')');
1436 }1439 }
14371440
1438 const field_i = ty.unionTagFieldIndex(un.tag.toValue(), mod).?;1441 const union_obj = mod.typeToUnion(ty).?;
1439 const field_ty = ty.unionFields(mod).values()[field_i].ty;1442 const field_i = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
1440 const field_name = ty.unionFields(mod).keys()[field_i];1443 const field_ty = union_obj.field_types.get(ip)[field_i].toType();
1441 if (ty.containerLayout(mod) == .Packed) {1444 const field_name = union_obj.field_names.get(ip)[field_i];
1445 if (union_obj.getLayout(ip) == .Packed) {
1442 if (field_ty.hasRuntimeBits(mod)) {1446 if (field_ty.hasRuntimeBits(mod)) {
1443 if (field_ty.isPtrAtRuntime(mod)) {1447 if (field_ty.isPtrAtRuntime(mod)) {
1444 try writer.writeByte('(');1448 try writer.writeByte('(');
...@@ -1458,7 +1462,7 @@ pub const DeclGen = struct {...@@ -1458,7 +1462,7 @@ pub const DeclGen = struct {
14581462
1459 try writer.writeByte('{');1463 try writer.writeByte('{');
1460 if (ty.unionTagTypeSafety(mod)) |tag_ty| {1464 if (ty.unionTagTypeSafety(mod)) |tag_ty| {
1461 const layout = ty.unionGetLayout(mod);1465 const layout = mod.getUnionLayout(union_obj);
1462 if (layout.tag_size != 0) {1466 if (layout.tag_size != 0) {
1463 try writer.writeAll(" .tag = ");1467 try writer.writeAll(" .tag = ");
1464 try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);1468 try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);
...@@ -1468,12 +1472,12 @@ pub const DeclGen = struct {...@@ -1468,12 +1472,12 @@ pub const DeclGen = struct {
1468 try writer.writeAll(" .payload = {");1472 try writer.writeAll(" .payload = {");
1469 }1473 }
1470 if (field_ty.hasRuntimeBits(mod)) {1474 if (field_ty.hasRuntimeBits(mod)) {
1471 try writer.print(" .{ } = ", .{fmtIdent(mod.intern_pool.stringToSlice(field_name))});1475 try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
1472 try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);1476 try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
1473 try writer.writeByte(' ');1477 try writer.writeByte(' ');
1474 } else for (ty.unionFields(mod).values()) |field| {1478 } else for (union_obj.field_types.get(ip)) |this_field_ty| {
1475 if (!field.ty.hasRuntimeBits(mod)) continue;1479 if (!this_field_ty.toType().hasRuntimeBits(mod)) continue;
1476 try dg.renderValue(writer, field.ty, Value.undef, initializer_type);1480 try dg.renderValue(writer, this_field_ty.toType(), Value.undef, initializer_type);
1477 break;1481 break;
1478 }1482 }
1479 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');1483 if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
...@@ -5237,22 +5241,25 @@ fn fieldLocation(...@@ -5237,22 +5241,25 @@ fn fieldLocation(
5237 else5241 else
5238 .begin,5242 .begin,
5239 },5243 },
5240 .Union => switch (container_ty.containerLayout(mod)) {5244 .Union => {
5241 .Auto, .Extern => {5245 const union_obj = mod.typeToUnion(container_ty).?;
5242 const field_ty = container_ty.structFieldType(field_index, mod);5246 return switch (union_obj.getLayout(ip)) {
5243 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))5247 .Auto, .Extern => {
5244 return if (container_ty.unionTagTypeSafety(mod) != null and5248 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
5245 !container_ty.unionHasAllZeroBitFieldTypes(mod))5249 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
5246 .{ .field = .{ .identifier = "payload" } }5250 return if (container_ty.unionTagTypeSafety(mod) != null and
5251 !container_ty.unionHasAllZeroBitFieldTypes(mod))
5252 .{ .field = .{ .identifier = "payload" } }
5253 else
5254 .begin;
5255 const field_name = union_obj.field_names.get(ip)[field_index];
5256 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
5257 .{ .payload_identifier = ip.stringToSlice(field_name) }
5247 else5258 else
5248 .begin;5259 .{ .identifier = ip.stringToSlice(field_name) } };
5249 const field_name = container_ty.unionFields(mod).keys()[field_index];5260 },
5250 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|5261 .Packed => .begin,
5251 .{ .payload_identifier = ip.stringToSlice(field_name) }5262 };
5252 else
5253 .{ .identifier = ip.stringToSlice(field_name) } };
5254 },
5255 .Packed => .begin,
5256 },5263 },
5257 .Pointer => switch (container_ty.ptrSize(mod)) {5264 .Pointer => switch (container_ty.ptrSize(mod)) {
5258 .Slice => switch (field_index) {5265 .Slice => switch (field_index) {
...@@ -5479,8 +5486,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5479,8 +5486,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5479 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },5486 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },
54805487
5481 .union_type => |union_type| field_name: {5488 .union_type => |union_type| field_name: {
5482 const union_obj = mod.unionPtr(union_type.index);5489 const union_obj = ip.loadUnionType(union_type);
5483 if (union_obj.layout == .Packed) {5490 if (union_obj.flagsPtr(ip).layout == .Packed) {
5484 const operand_lval = if (struct_byval == .constant) blk: {5491 const operand_lval = if (struct_byval == .constant) blk: {
5485 const operand_local = try f.allocLocal(inst, struct_ty);5492 const operand_local = try f.allocLocal(inst, struct_ty);
5486 try f.writeCValue(writer, operand_local, .Other);5493 try f.writeCValue(writer, operand_local, .Other);
...@@ -5505,8 +5512,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5505,8 +5512,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
55055512
5506 return local;5513 return local;
5507 } else {5514 } else {
5508 const name = union_obj.fields.keys()[extra.field_index];5515 const name = union_obj.field_names.get(ip)[extra.field_index];
5509 break :field_name if (union_type.hasTag()) .{5516 break :field_name if (union_type.hasTag(ip)) .{
5510 .payload_identifier = ip.stringToSlice(name),5517 .payload_identifier = ip.stringToSlice(name),
5511 } else .{5518 } else .{
5512 .identifier = ip.stringToSlice(name),5519 .identifier = ip.stringToSlice(name),
...@@ -6902,14 +6909,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6902,14 +6909,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
69026909
6903 const union_ty = f.typeOfIndex(inst);6910 const union_ty = f.typeOfIndex(inst);
6904 const union_obj = mod.typeToUnion(union_ty).?;6911 const union_obj = mod.typeToUnion(union_ty).?;
6905 const field_name = union_obj.fields.keys()[extra.field_index];6912 const field_name = union_obj.field_names.get(ip)[extra.field_index];
6906 const payload_ty = f.typeOf(extra.init);6913 const payload_ty = f.typeOf(extra.init);
6907 const payload = try f.resolveInst(extra.init);6914 const payload = try f.resolveInst(extra.init);
6908 try reap(f, inst, &.{extra.init});6915 try reap(f, inst, &.{extra.init});
69096916
6910 const writer = f.object.writer();6917 const writer = f.object.writer();
6911 const local = try f.allocLocal(inst, union_ty);6918 const local = try f.allocLocal(inst, union_ty);
6912 if (union_obj.layout == .Packed) {6919 if (union_obj.getLayout(ip) == .Packed) {
6913 try f.writeCValue(writer, local, .Other);6920 try f.writeCValue(writer, local, .Other);
6914 try writer.writeAll(" = ");6921 try writer.writeAll(" = ");
6915 try f.writeCValue(writer, payload, .Initializer);6922 try f.writeCValue(writer, payload, .Initializer);
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 pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {304 pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {
305 const union_obj = mod.typeToUnion(union_ty).?;305 const union_obj = mod.typeToUnion(union_ty).?;
306 const union_payload_align = union_obj.abiAlignment(mod, false);306 const union_payload_align = mod.unionAbiAlignment(union_obj);
307 return init(union_payload_align, union_payload_align);307 return init(union_payload_align, union_payload_align);
308 }308 }
309309
...@@ -1499,7 +1499,7 @@ pub const CType = extern union {...@@ -1499,7 +1499,7 @@ pub const CType = extern union {
1499 if (lookup.isMutable()) {1499 if (lookup.isMutable()) {
1500 for (0..switch (zig_ty_tag) {1500 for (0..switch (zig_ty_tag) {
1501 .Struct => ty.structFieldCount(mod),1501 .Struct => ty.structFieldCount(mod),
1502 .Union => ty.unionFields(mod).count(),1502 .Union => mod.typeToUnion(ty).?.field_names.len,
1503 else => unreachable,1503 else => unreachable,
1504 }) |field_i| {1504 }) |field_i| {
1505 const field_ty = ty.structFieldType(field_i, mod);1505 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1581,7 +1581,7 @@ pub const CType = extern union {...@@ -1581,7 +1581,7 @@ pub const CType = extern union {
1581 var is_packed = false;1581 var is_packed = false;
1582 for (0..switch (zig_ty_tag) {1582 for (0..switch (zig_ty_tag) {
1583 .Struct => ty.structFieldCount(mod),1583 .Struct => ty.structFieldCount(mod),
1584 .Union => ty.unionFields(mod).count(),1584 .Union => mod.typeToUnion(ty).?.field_names.len,
1585 else => unreachable,1585 else => unreachable,
1586 }) |field_i| {1586 }) |field_i| {
1587 const field_ty = ty.structFieldType(field_i, mod);1587 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1912,6 +1912,7 @@ pub const CType = extern union {...@@ -1912,6 +1912,7 @@ pub const CType = extern union {
1912 kind: Kind,1912 kind: Kind,
1913 convert: Convert,1913 convert: Convert,
1914 ) !CType {1914 ) !CType {
1915 const ip = &mod.intern_pool;
1915 const arena = store.arena.allocator();1916 const arena = store.arena.allocator();
1916 switch (convert.value) {1917 switch (convert.value) {
1917 .cty => |c| return c.copy(arena),1918 .cty => |c| return c.copy(arena),
...@@ -1932,7 +1933,7 @@ pub const CType = extern union {...@@ -1932,7 +1933,7 @@ pub const CType = extern union {
1932 const zig_ty_tag = ty.zigTypeTag(mod);1933 const zig_ty_tag = ty.zigTypeTag(mod);
1933 const fields_len = switch (zig_ty_tag) {1934 const fields_len = switch (zig_ty_tag) {
1934 .Struct => ty.structFieldCount(mod),1935 .Struct => ty.structFieldCount(mod),
1935 .Union => ty.unionFields(mod).count(),1936 .Union => mod.typeToUnion(ty).?.field_names.len,
1936 else => unreachable,1937 else => unreachable,
1937 };1938 };
19381939
...@@ -1956,9 +1957,9 @@ pub const CType = extern union {...@@ -1956,9 +1957,9 @@ pub const CType = extern union {
1956 .name = try if (ty.isSimpleTuple(mod))1957 .name = try if (ty.isSimpleTuple(mod))
1957 std.fmt.allocPrintZ(arena, "f{}", .{field_i})1958 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1958 else1959 else
1959 arena.dupeZ(u8, mod.intern_pool.stringToSlice(switch (zig_ty_tag) {1960 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1960 .Struct => ty.structFieldName(field_i, mod),1961 .Struct => ty.structFieldName(field_i, mod),
1961 .Union => ty.unionFields(mod).keys()[field_i],1962 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
1962 else => unreachable,1963 else => unreachable,
1963 })),1964 })),
1964 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {1965 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {
...@@ -2015,7 +2016,6 @@ pub const CType = extern union {...@@ -2015,7 +2016,6 @@ pub const CType = extern union {
2015 .function,2016 .function,
2016 .varargs_function,2017 .varargs_function,
2017 => {2018 => {
2018 const ip = &mod.intern_pool;
2019 const info = mod.typeToFunc(ty).?;2019 const info = mod.typeToFunc(ty).?;
2020 assert(!info.is_generic);2020 assert(!info.is_generic);
2021 const param_kind: Kind = switch (kind) {2021 const param_kind: Kind = switch (kind) {
...@@ -2068,6 +2068,7 @@ pub const CType = extern union {...@@ -2068,6 +2068,7 @@ pub const CType = extern union {
20682068
2069 pub fn eql(self: @This(), ty: Type, cty: CType) bool {2069 pub fn eql(self: @This(), ty: Type, cty: CType) bool {
2070 const mod = self.lookup.getModule();2070 const mod = self.lookup.getModule();
2071 const ip = &mod.intern_pool;
2071 switch (self.convert.value) {2072 switch (self.convert.value) {
2072 .cty => |c| return c.eql(cty),2073 .cty => |c| return c.eql(cty),
2073 .tag => |t| {2074 .tag => |t| {
...@@ -2088,7 +2089,7 @@ pub const CType = extern union {...@@ -2088,7 +2089,7 @@ pub const CType = extern union {
2088 var c_field_i: usize = 0;2089 var c_field_i: usize = 0;
2089 for (0..switch (zig_ty_tag) {2090 for (0..switch (zig_ty_tag) {
2090 .Struct => ty.structFieldCount(mod),2091 .Struct => ty.structFieldCount(mod),
2091 .Union => ty.unionFields(mod).count(),2092 .Union => mod.typeToUnion(ty).?.field_names.len,
2092 else => unreachable,2093 else => unreachable,
2093 }) |field_i| {2094 }) |field_i| {
2094 const field_ty = ty.structFieldType(field_i, mod);2095 const field_ty = ty.structFieldType(field_i, mod);
...@@ -2108,9 +2109,9 @@ pub const CType = extern union {...@@ -2108,9 +2109,9 @@ pub const CType = extern union {
2108 if (ty.isSimpleTuple(mod))2109 if (ty.isSimpleTuple(mod))
2109 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable2110 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
2110 else2111 else
2111 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {2112 ip.stringToSlice(switch (zig_ty_tag) {
2112 .Struct => ty.structFieldName(field_i, mod),2113 .Struct => ty.structFieldName(field_i, mod),
2113 .Union => ty.unionFields(mod).keys()[field_i],2114 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2114 else => unreachable,2115 else => unreachable,
2115 }),2116 }),
2116 mem.span(c_field.name),2117 mem.span(c_field.name),
...@@ -2149,7 +2150,6 @@ pub const CType = extern union {...@@ -2149,7 +2150,6 @@ pub const CType = extern union {
2149 => {2150 => {
2150 if (ty.zigTypeTag(mod) != .Fn) return false;2151 if (ty.zigTypeTag(mod) != .Fn) return false;
21512152
2152 const ip = &mod.intern_pool;
2153 const info = mod.typeToFunc(ty).?;2153 const info = mod.typeToFunc(ty).?;
2154 assert(!info.is_generic);2154 assert(!info.is_generic);
2155 const data = cty.cast(Payload.Function).?.data;2155 const data = cty.cast(Payload.Function).?.data;
...@@ -2217,7 +2217,7 @@ pub const CType = extern union {...@@ -2217,7 +2217,7 @@ pub const CType = extern union {
2217 const zig_ty_tag = ty.zigTypeTag(mod);2217 const zig_ty_tag = ty.zigTypeTag(mod);
2218 for (0..switch (ty.zigTypeTag(mod)) {2218 for (0..switch (ty.zigTypeTag(mod)) {
2219 .Struct => ty.structFieldCount(mod),2219 .Struct => ty.structFieldCount(mod),
2220 .Union => ty.unionFields(mod).count(),2220 .Union => mod.typeToUnion(ty).?.field_names.len,
2221 else => unreachable,2221 else => unreachable,
2222 }) |field_i| {2222 }) |field_i| {
2223 const field_ty = ty.structFieldType(field_i, mod);2223 const field_ty = ty.structFieldType(field_i, mod);
...@@ -2235,7 +2235,7 @@ pub const CType = extern union {...@@ -2235,7 +2235,7 @@ pub const CType = extern union {
2235 else2235 else
2236 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {2236 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
2237 .Struct => ty.structFieldName(field_i, mod),2237 .Struct => ty.structFieldName(field_i, mod),
2238 .Union => ty.unionFields(mod).keys()[field_i],2238 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2239 else => unreachable,2239 else => unreachable,
2240 }));2240 }));
2241 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");2241 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
src/codegen/llvm.zig+55-55
...@@ -2382,7 +2382,7 @@ pub const Object = struct {...@@ -2382,7 +2382,7 @@ pub const Object = struct {
2382 break :blk fwd_decl;2382 break :blk fwd_decl;
2383 };2383 };
23842384
2385 switch (mod.intern_pool.indexToKey(ty.toIntern())) {2385 switch (ip.indexToKey(ty.toIntern())) {
2386 .anon_struct_type => |tuple| {2386 .anon_struct_type => |tuple| {
2387 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};2387 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
2388 defer di_fields.deinit(gpa);2388 defer di_fields.deinit(gpa);
...@@ -2401,7 +2401,7 @@ pub const Object = struct {...@@ -2401,7 +2401,7 @@ pub const Object = struct {
2401 offset = field_offset + field_size;2401 offset = field_offset + field_size;
24022402
2403 const field_name = if (tuple.names.len != 0)2403 const field_name = if (tuple.names.len != 0)
2404 mod.intern_pool.stringToSlice(tuple.names[i])2404 ip.stringToSlice(tuple.names[i])
2405 else2405 else
2406 try std.fmt.allocPrintZ(gpa, "{d}", .{i});2406 try std.fmt.allocPrintZ(gpa, "{d}", .{i});
2407 defer if (tuple.names.len == 0) gpa.free(field_name);2407 defer if (tuple.names.len == 0) gpa.free(field_name);
...@@ -2491,7 +2491,7 @@ pub const Object = struct {...@@ -2491,7 +2491,7 @@ pub const Object = struct {
2491 const field_offset = std.mem.alignForward(u64, offset, field_align);2491 const field_offset = std.mem.alignForward(u64, offset, field_align);
2492 offset = field_offset + field_size;2492 offset = field_offset + field_size;
24932493
2494 const field_name = mod.intern_pool.stringToSlice(fields.keys()[field_and_index.index]);2494 const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]);
24952495
2496 try di_fields.append(gpa, dib.createMemberType(2496 try di_fields.append(gpa, dib.createMemberType(
2497 fwd_decl.toScope(),2497 fwd_decl.toScope(),
...@@ -2546,8 +2546,8 @@ pub const Object = struct {...@@ -2546,8 +2546,8 @@ pub const Object = struct {
2546 break :blk fwd_decl;2546 break :blk fwd_decl;
2547 };2547 };
25482548
2549 const union_obj = mod.typeToUnion(ty).?;2549 const union_type = ip.indexToKey(ty.toIntern()).union_type;
2550 if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {2550 if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
2551 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);2551 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
2552 dib.replaceTemporary(fwd_decl, union_di_ty);2552 dib.replaceTemporary(fwd_decl, union_di_ty);
2553 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`2553 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
...@@ -2556,10 +2556,11 @@ pub const Object = struct {...@@ -2556,10 +2556,11 @@ pub const Object = struct {
2556 return union_di_ty;2556 return union_di_ty;
2557 }2557 }
25582558
2559 const layout = ty.unionGetLayout(mod);2559 const union_obj = ip.loadUnionType(union_type);
2560 const layout = mod.getUnionLayout(union_obj);
25602561
2561 if (layout.payload_size == 0) {2562 if (layout.payload_size == 0) {
2562 const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full);2563 const tag_di_ty = try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full);
2563 const di_fields = [_]*llvm.DIType{tag_di_ty};2564 const di_fields = [_]*llvm.DIType{tag_di_ty};
2564 const full_di_ty = dib.createStructType(2565 const full_di_ty = dib.createStructType(
2565 compile_unit_scope,2566 compile_unit_scope,
...@@ -2586,22 +2587,20 @@ pub const Object = struct {...@@ -2586,22 +2587,20 @@ pub const Object = struct {
2586 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};2587 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
2587 defer di_fields.deinit(gpa);2588 defer di_fields.deinit(gpa);
25882589
2589 try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());2590 try di_fields.ensureUnusedCapacity(gpa, union_obj.field_names.len);
25902591
2591 var it = union_obj.fields.iterator();2592 for (0..union_obj.field_names.len) |field_index| {
2592 while (it.next()) |kv| {2593 const field_ty = union_obj.field_types.get(ip)[field_index];
2593 const field_name = kv.key_ptr.*;2594 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
2594 const field = kv.value_ptr.*;
25952595
2596 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2596 const field_size = field_ty.toType().abiSize(mod);
25972597 const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));
2598 const field_size = field.ty.abiSize(mod);
2599 const field_align = field.normalAlignment(mod);
26002598
2601 const field_di_ty = try o.lowerDebugType(field.ty, .full);2599 const field_di_ty = try o.lowerDebugType(field_ty.toType(), .full);
2600 const field_name = union_obj.field_names.get(ip)[field_index];
2602 di_fields.appendAssumeCapacity(dib.createMemberType(2601 di_fields.appendAssumeCapacity(dib.createMemberType(
2603 fwd_decl.toScope(),2602 fwd_decl.toScope(),
2604 mod.intern_pool.stringToSlice(field_name),2603 ip.stringToSlice(field_name),
2605 null, // file2604 null, // file
2606 0, // line2605 0, // line
2607 field_size * 8, // size in bits2606 field_size * 8, // size in bits
...@@ -2659,7 +2658,7 @@ pub const Object = struct {...@@ -2659,7 +2658,7 @@ pub const Object = struct {
2659 layout.tag_align * 8, // align in bits2658 layout.tag_align * 8, // align in bits
2660 tag_offset * 8, // offset in bits2659 tag_offset * 8, // offset in bits
2661 0, // flags2660 0, // flags
2662 try o.lowerDebugType(union_obj.tag_ty, .full),2661 try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),
2663 );2662 );
26642663
2665 const payload_di = dib.createMemberType(2664 const payload_di = dib.createMemberType(
...@@ -3078,6 +3077,7 @@ pub const Object = struct {...@@ -3078,6 +3077,7 @@ pub const Object = struct {
3078 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!Builder.Type {3077 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!Builder.Type {
3079 const mod = o.module;3078 const mod = o.module;
3080 const target = mod.getTarget();3079 const target = mod.getTarget();
3080 const ip = &mod.intern_pool;
3081 return switch (t.toIntern()) {3081 return switch (t.toIntern()) {
3082 .u0_type, .i0_type => unreachable,3082 .u0_type, .i0_type => unreachable,
3083 inline .u1_type,3083 inline .u1_type,
...@@ -3172,7 +3172,7 @@ pub const Object = struct {...@@ -3172,7 +3172,7 @@ pub const Object = struct {
3172 .var_args_param_type,3172 .var_args_param_type,
3173 .none,3173 .none,
3174 => unreachable,3174 => unreachable,
3175 else => switch (mod.intern_pool.indexToKey(t.toIntern())) {3175 else => switch (ip.indexToKey(t.toIntern())) {
3176 .int_type => |int_type| try o.builder.intType(int_type.bits),3176 .int_type => |int_type| try o.builder.intType(int_type.bits),
3177 .ptr_type => |ptr_type| type: {3177 .ptr_type => |ptr_type| type: {
3178 const ptr_ty = try o.builder.ptrType(3178 const ptr_ty = try o.builder.ptrType(
...@@ -3264,7 +3264,7 @@ pub const Object = struct {...@@ -3264,7 +3264,7 @@ pub const Object = struct {
3264 return int_ty;3264 return int_ty;
3265 }3265 }
32663266
3267 const name = try o.builder.string(mod.intern_pool.stringToSlice(3267 const name = try o.builder.string(ip.stringToSlice(
3268 try struct_obj.getFullyQualifiedName(mod),3268 try struct_obj.getFullyQualifiedName(mod),
3269 ));3269 ));
3270 const ty = try o.builder.opaqueType(name);3270 const ty = try o.builder.opaqueType(name);
...@@ -3357,40 +3357,40 @@ pub const Object = struct {...@@ -3357,40 +3357,40 @@ pub const Object = struct {
3357 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());3357 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3358 if (gop.found_existing) return gop.value_ptr.*;3358 if (gop.found_existing) return gop.value_ptr.*;
33593359
3360 const union_obj = mod.unionPtr(union_type.index);3360 const union_obj = ip.loadUnionType(union_type);
3361 const layout = union_obj.getLayout(mod, union_type.hasTag());3361 const layout = mod.getUnionLayout(union_obj);
33623362
3363 if (union_obj.layout == .Packed) {3363 if (union_obj.flagsPtr(ip).layout == .Packed) {
3364 const int_ty = try o.builder.intType(@intCast(t.bitSize(mod)));3364 const int_ty = try o.builder.intType(@intCast(t.bitSize(mod)));
3365 gop.value_ptr.* = int_ty;3365 gop.value_ptr.* = int_ty;
3366 return int_ty;3366 return int_ty;
3367 }3367 }
33683368
3369 if (layout.payload_size == 0) {3369 if (layout.payload_size == 0) {
3370 const enum_tag_ty = try o.lowerType(union_obj.tag_ty);3370 const enum_tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
3371 gop.value_ptr.* = enum_tag_ty;3371 gop.value_ptr.* = enum_tag_ty;
3372 return enum_tag_ty;3372 return enum_tag_ty;
3373 }3373 }
33743374
3375 const name = try o.builder.string(mod.intern_pool.stringToSlice(3375 const name = try o.builder.string(ip.stringToSlice(
3376 try union_obj.getFullyQualifiedName(mod),3376 try mod.declPtr(union_obj.decl).getFullyQualifiedName(mod),
3377 ));3377 ));
3378 const ty = try o.builder.opaqueType(name);3378 const ty = try o.builder.opaqueType(name);
3379 gop.value_ptr.* = ty; // must be done before any recursive calls3379 gop.value_ptr.* = ty; // must be done before any recursive calls
33803380
3381 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];3381 const aligned_field_ty = union_obj.field_types.get(ip)[layout.most_aligned_field].toType();
3382 const aligned_field_ty = try o.lowerType(aligned_field.ty);3382 const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty);
33833383
3384 const payload_ty = ty: {3384 const payload_ty = ty: {
3385 if (layout.most_aligned_field_size == layout.payload_size) {3385 if (layout.most_aligned_field_size == layout.payload_size) {
3386 break :ty aligned_field_ty;3386 break :ty aligned_field_llvm_ty;
3387 }3387 }
3388 const padding_len = if (layout.tag_size == 0)3388 const padding_len = if (layout.tag_size == 0)
3389 layout.abi_size - layout.most_aligned_field_size3389 layout.abi_size - layout.most_aligned_field_size
3390 else3390 else
3391 layout.payload_size - layout.most_aligned_field_size;3391 layout.payload_size - layout.most_aligned_field_size;
3392 break :ty try o.builder.structType(.@"packed", &.{3392 break :ty try o.builder.structType(.@"packed", &.{
3393 aligned_field_ty,3393 aligned_field_llvm_ty,
3394 try o.builder.arrayType(padding_len, .i8),3394 try o.builder.arrayType(padding_len, .i8),
3395 });3395 });
3396 };3396 };
...@@ -3402,7 +3402,7 @@ pub const Object = struct {...@@ -3402,7 +3402,7 @@ pub const Object = struct {
3402 );3402 );
3403 return ty;3403 return ty;
3404 }3404 }
3405 const enum_tag_ty = try o.lowerType(union_obj.tag_ty);3405 const enum_tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
34063406
3407 // Put the tag before or after the payload depending on which one's3407 // Put the tag before or after the payload depending on which one's
3408 // alignment is greater.3408 // alignment is greater.
...@@ -3430,7 +3430,7 @@ pub const Object = struct {...@@ -3430,7 +3430,7 @@ pub const Object = struct {
3430 .opaque_type => |opaque_type| {3430 .opaque_type => |opaque_type| {
3431 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());3431 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3432 if (!gop.found_existing) {3432 if (!gop.found_existing) {
3433 const name = try o.builder.string(mod.intern_pool.stringToSlice(3433 const name = try o.builder.string(ip.stringToSlice(
3434 try mod.opaqueFullyQualifiedName(opaque_type),3434 try mod.opaqueFullyQualifiedName(opaque_type),
3435 ));3435 ));
3436 gop.value_ptr.* = try o.builder.opaqueType(name);3436 gop.value_ptr.* = try o.builder.opaqueType(name);
...@@ -3551,10 +3551,11 @@ pub const Object = struct {...@@ -3551,10 +3551,11 @@ pub const Object = struct {
35513551
3552 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {3552 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
3553 const mod = o.module;3553 const mod = o.module;
3554 const ip = &mod.intern_pool;
3554 const target = mod.getTarget();3555 const target = mod.getTarget();
35553556
3556 var val = arg_val.toValue();3557 var val = arg_val.toValue();
3557 const arg_val_key = mod.intern_pool.indexToKey(arg_val);3558 const arg_val_key = ip.indexToKey(arg_val);
3558 switch (arg_val_key) {3559 switch (arg_val_key) {
3559 .runtime_value => |rt| val = rt.val.toValue(),3560 .runtime_value => |rt| val = rt.val.toValue(),
3560 else => {},3561 else => {},
...@@ -3563,7 +3564,7 @@ pub const Object = struct {...@@ -3563,7 +3564,7 @@ pub const Object = struct {
3563 return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));3564 return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
3564 }3565 }
35653566
3566 const val_key = mod.intern_pool.indexToKey(val.toIntern());3567 const val_key = ip.indexToKey(val.toIntern());
3567 const ty = val_key.typeOf().toType();3568 const ty = val_key.typeOf().toType();
3568 return switch (val_key) {3569 return switch (val_key) {
3569 .int_type,3570 .int_type,
...@@ -3749,7 +3750,7 @@ pub const Object = struct {...@@ -3749,7 +3750,7 @@ pub const Object = struct {
3749 fields[0..llvm_ty_fields.len],3750 fields[0..llvm_ty_fields.len],
3750 ), vals[0..llvm_ty_fields.len]);3751 ), vals[0..llvm_ty_fields.len]);
3751 },3752 },
3752 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) {3753 .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
3753 .array_type => |array_type| switch (aggregate.storage) {3754 .array_type => |array_type| switch (aggregate.storage) {
3754 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),3755 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
3755 .elems => |elems| {3756 .elems => |elems| {
...@@ -4024,11 +4025,10 @@ pub const Object = struct {...@@ -4024,11 +4025,10 @@ pub const Object = struct {
4024 if (layout.payload_size == 0) return o.lowerValue(un.tag);4025 if (layout.payload_size == 0) return o.lowerValue(un.tag);
40254026
4026 const union_obj = mod.typeToUnion(ty).?;4027 const union_obj = mod.typeToUnion(ty).?;
4027 const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?;4028 const field_index = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
4028 assert(union_obj.haveFieldTypes());
40294029
4030 const field_ty = union_obj.fields.values()[field_index].ty;4030 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
4031 if (union_obj.layout == .Packed) {4031 if (union_obj.getLayout(ip) == .Packed) {
4032 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);4032 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
4033 const small_int_val = try o.builder.castConst(4033 const small_int_val = try o.builder.castConst(
4034 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,4034 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
...@@ -9676,6 +9676,7 @@ pub const FuncGen = struct {...@@ -9676,6 +9676,7 @@ pub const FuncGen = struct {
9676 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {9676 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9677 const o = self.dg.object;9677 const o = self.dg.object;
9678 const mod = o.module;9678 const mod = o.module;
9679 const ip = &mod.intern_pool;
9679 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9680 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
9680 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;9681 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
9681 const union_ty = self.typeOfIndex(inst);9682 const union_ty = self.typeOfIndex(inst);
...@@ -9683,13 +9684,13 @@ pub const FuncGen = struct {...@@ -9683,13 +9684,13 @@ pub const FuncGen = struct {
9683 const layout = union_ty.unionGetLayout(mod);9684 const layout = union_ty.unionGetLayout(mod);
9684 const union_obj = mod.typeToUnion(union_ty).?;9685 const union_obj = mod.typeToUnion(union_ty).?;
96859686
9686 if (union_obj.layout == .Packed) {9687 if (union_obj.getLayout(ip) == .Packed) {
9687 const big_bits = union_ty.bitSize(mod);9688 const big_bits = union_ty.bitSize(mod);
9688 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));9689 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
9689 const field = union_obj.fields.values()[extra.field_index];9690 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
9690 const non_int_val = try self.resolveInst(extra.init);9691 const non_int_val = try self.resolveInst(extra.init);
9691 const small_int_ty = try o.builder.intType(@intCast(field.ty.bitSize(mod)));9692 const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
9692 const small_int_val = if (field.ty.isPtrAtRuntime(mod))9693 const small_int_val = if (field_ty.isPtrAtRuntime(mod))
9693 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")9694 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
9694 else9695 else
9695 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");9696 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
...@@ -9698,7 +9699,7 @@ pub const FuncGen = struct {...@@ -9698,7 +9699,7 @@ pub const FuncGen = struct {
96989699
9699 const tag_int = blk: {9700 const tag_int = blk: {
9700 const tag_ty = union_ty.unionTagTypeHypothetical(mod);9701 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
9701 const union_field_name = union_obj.fields.keys()[extra.field_index];9702 const union_field_name = union_obj.field_names.get(ip)[extra.field_index];
9702 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;9703 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
9703 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);9704 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
9704 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);9705 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
...@@ -9719,18 +9720,17 @@ pub const FuncGen = struct {...@@ -9719,18 +9720,17 @@ pub const FuncGen = struct {
9719 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);9720 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
9720 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);9721 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
9721 const llvm_payload = try self.resolveInst(extra.init);9722 const llvm_payload = try self.resolveInst(extra.init);
9722 assert(union_obj.haveFieldTypes());9723 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
9723 const field = union_obj.fields.values()[extra.field_index];9724 const field_llvm_ty = try o.lowerType(field_ty);
9724 const field_llvm_ty = try o.lowerType(field.ty);9725 const field_size = field_ty.abiSize(mod);
9725 const field_size = field.ty.abiSize(mod);9726 const field_align = mod.unionFieldNormalAlignment(union_obj, extra.field_index);
9726 const field_align = field.normalAlignment(mod);
9727 const llvm_usize = try o.lowerType(Type.usize);9727 const llvm_usize = try o.lowerType(Type.usize);
9728 const usize_zero = try o.builder.intValue(llvm_usize, 0);9728 const usize_zero = try o.builder.intValue(llvm_usize, 0);
9729 const i32_zero = try o.builder.intValue(.i32, 0);9729 const i32_zero = try o.builder.intValue(.i32, 0);
97309730
9731 const llvm_union_ty = t: {9731 const llvm_union_ty = t: {
9732 const payload_ty = p: {9732 const payload_ty = p: {
9733 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {9733 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
9734 const padding_len = layout.payload_size;9734 const padding_len = layout.payload_size;
9735 break :p try o.builder.arrayType(padding_len, .i8);9735 break :p try o.builder.arrayType(padding_len, .i8);
9736 }9736 }
...@@ -9743,7 +9743,7 @@ pub const FuncGen = struct {...@@ -9743,7 +9743,7 @@ pub const FuncGen = struct {
9743 });9743 });
9744 };9744 };
9745 if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});9745 if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});
9746 const tag_ty = try o.lowerType(union_obj.tag_ty);9746 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
9747 var fields: [3]Builder.Type = undefined;9747 var fields: [3]Builder.Type = undefined;
9748 var fields_len: usize = 2;9748 var fields_len: usize = 2;
9749 if (layout.tag_align >= layout.payload_align) {9749 if (layout.tag_align >= layout.payload_align) {
...@@ -9761,7 +9761,7 @@ pub const FuncGen = struct {...@@ -9761,7 +9761,7 @@ pub const FuncGen = struct {
9761 // Now we follow the layout as expressed above with GEP instructions to set the9761 // Now we follow the layout as expressed above with GEP instructions to set the
9762 // tag and the payload.9762 // tag and the payload.
9763 const field_ptr_ty = try mod.ptrType(.{9763 const field_ptr_ty = try mod.ptrType(.{
9764 .child = field.ty.toIntern(),9764 .child = field_ty.toIntern(),
9765 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },9765 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
9766 });9766 });
9767 if (layout.tag_size == 0) {9767 if (layout.tag_size == 0) {
...@@ -9786,9 +9786,9 @@ pub const FuncGen = struct {...@@ -9786,9 +9786,9 @@ pub const FuncGen = struct {
9786 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9786 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9787 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };9787 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
9788 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");9788 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
9789 const tag_ty = try o.lowerType(union_obj.tag_ty);9789 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
9790 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);9790 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
9791 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));9791 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.enum_tag_ty.toType().abiAlignment(mod));
9792 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);9792 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
9793 }9793 }
97949794
src/codegen/spirv.zig+15-13
...@@ -619,9 +619,10 @@ pub const DeclGen = struct {...@@ -619,9 +619,10 @@ pub const DeclGen = struct {
619 fn lower(self: *@This(), ty: Type, arg_val: Value) !void {619 fn lower(self: *@This(), ty: Type, arg_val: Value) !void {
620 const dg = self.dg;620 const dg = self.dg;
621 const mod = dg.module;621 const mod = dg.module;
622 const ip = &mod.intern_pool;
622623
623 var val = arg_val;624 var val = arg_val;
624 switch (mod.intern_pool.indexToKey(val.toIntern())) {625 switch (ip.indexToKey(val.toIntern())) {
625 .runtime_value => |rt| val = rt.val.toValue(),626 .runtime_value => |rt| val = rt.val.toValue(),
626 else => {},627 else => {},
627 }628 }
...@@ -631,7 +632,7 @@ pub const DeclGen = struct {...@@ -631,7 +632,7 @@ pub const DeclGen = struct {
631 return try self.addUndef(size);632 return try self.addUndef(size);
632 }633 }
633634
634 switch (mod.intern_pool.indexToKey(val.toIntern())) {635 switch (ip.indexToKey(val.toIntern())) {
635 .int_type,636 .int_type,
636 .ptr_type,637 .ptr_type,
637 .array_type,638 .array_type,
...@@ -770,7 +771,7 @@ pub const DeclGen = struct {...@@ -770,7 +771,7 @@ pub const DeclGen = struct {
770 try self.addConstBool(payload_val != null);771 try self.addConstBool(payload_val != null);
771 try self.addUndef(padding);772 try self.addUndef(padding);
772 },773 },
773 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) {774 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
774 .array_type => |array_type| {775 .array_type => |array_type| {
775 const elem_ty = array_type.child.toType();776 const elem_ty = array_type.child.toType();
776 switch (aggregate.storage) {777 switch (aggregate.storage) {
...@@ -801,7 +802,7 @@ pub const DeclGen = struct {...@@ -801,7 +802,7 @@ pub const DeclGen = struct {
801 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;802 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
802803
803 const field_val = switch (aggregate.storage) {804 const field_val = switch (aggregate.storage) {
804 .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{805 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
805 .ty = field.ty.toIntern(),806 .ty = field.ty.toIntern(),
806 .storage = .{ .u64 = bytes[i] },807 .storage = .{ .u64 = bytes[i] },
807 } }),808 } }),
...@@ -828,13 +829,13 @@ pub const DeclGen = struct {...@@ -828,13 +829,13 @@ pub const DeclGen = struct {
828 return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());829 return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());
829 }830 }
830831
831 const union_ty = mod.typeToUnion(ty).?;832 const union_obj = mod.typeToUnion(ty).?;
832 if (union_ty.layout == .Packed) {833 if (union_obj.getLayout(ip) == .Packed) {
833 return dg.todo("packed union constants", .{});834 return dg.todo("packed union constants", .{});
834 }835 }
835836
836 const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?;837 const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?;
837 const active_field_ty = union_ty.fields.values()[active_field].ty;838 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
838839
839 const has_tag = layout.tag_size != 0;840 const has_tag = layout.tag_size != 0;
840 const tag_first = layout.tag_align >= layout.payload_align;841 const tag_first = layout.tag_align >= layout.payload_align;
...@@ -1162,16 +1163,17 @@ pub const DeclGen = struct {...@@ -1162,16 +1163,17 @@ pub const DeclGen = struct {
1162 /// resulting struct will be *underaligned*.1163 /// resulting struct will be *underaligned*.
1163 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {1164 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
1164 const mod = self.module;1165 const mod = self.module;
1166 const ip = &mod.intern_pool;
1165 const layout = ty.unionGetLayout(mod);1167 const layout = ty.unionGetLayout(mod);
1166 const union_ty = mod.typeToUnion(ty).?;1168 const union_obj = mod.typeToUnion(ty).?;
11671169
1168 if (union_ty.layout == .Packed) {1170 if (union_obj.getLayout(ip) == .Packed) {
1169 return self.todo("packed union types", .{});1171 return self.todo("packed union types", .{});
1170 }1172 }
11711173
1172 if (layout.payload_size == 0) {1174 if (layout.payload_size == 0) {
1173 // No payload, so represent this as just the tag type.1175 // No payload, so represent this as just the tag type.
1174 return try self.resolveType(union_ty.tag_ty, .indirect);1176 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1175 }1177 }
11761178
1177 var member_types = std.BoundedArray(CacheRef, 4){};1179 var member_types = std.BoundedArray(CacheRef, 4){};
...@@ -1182,13 +1184,13 @@ pub const DeclGen = struct {...@@ -1182,13 +1184,13 @@ pub const DeclGen = struct {
1182 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?1184 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
11831185
1184 if (has_tag and tag_first) {1186 if (has_tag and tag_first) {
1185 const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect);1187 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1186 member_types.appendAssumeCapacity(tag_ty_ref);1188 member_types.appendAssumeCapacity(tag_ty_ref);
1187 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));1189 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));
1188 }1190 }
11891191
1190 const active_field = maybe_active_field orelse layout.most_aligned_field;1192 const active_field = maybe_active_field orelse layout.most_aligned_field;
1191 const active_field_ty = union_ty.fields.values()[active_field].ty;1193 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
11921194
1193 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {1195 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
1194 const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect);1196 const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect);
...@@ -1205,7 +1207,7 @@ pub const DeclGen = struct {...@@ -1205,7 +1207,7 @@ pub const DeclGen = struct {
1205 }1207 }
12061208
1207 if (has_tag and !tag_first) {1209 if (has_tag and !tag_first) {
1208 const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect);1210 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1209 member_types.appendAssumeCapacity(tag_ty_ref);1211 member_types.appendAssumeCapacity(tag_ty_ref);
1210 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));1212 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));
1211 }1213 }
src/link/Dwarf.zig+9-11
...@@ -166,6 +166,7 @@ pub const DeclState = struct {...@@ -166,6 +166,7 @@ pub const DeclState = struct {
166 const dbg_info_buffer = &self.dbg_info;166 const dbg_info_buffer = &self.dbg_info;
167 const target = mod.getTarget();167 const target = mod.getTarget();
168 const target_endian = target.cpu.arch.endian();168 const target_endian = target.cpu.arch.endian();
169 const ip = &mod.intern_pool;
169170
170 switch (ty.zigTypeTag(mod)) {171 switch (ty.zigTypeTag(mod)) {
171 .NoReturn => unreachable,172 .NoReturn => unreachable,
...@@ -321,7 +322,7 @@ pub const DeclState = struct {...@@ -321,7 +322,7 @@ pub const DeclState = struct {
321 // DW.AT.byte_size, DW.FORM.udata322 // DW.AT.byte_size, DW.FORM.udata
322 try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod));323 try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod));
323324
324 switch (mod.intern_pool.indexToKey(ty.ip_index)) {325 switch (ip.indexToKey(ty.ip_index)) {
325 .anon_struct_type => |fields| {326 .anon_struct_type => |fields| {
326 // DW.AT.name, DW.FORM.string327 // DW.AT.name, DW.FORM.string
327 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)});328 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)});
...@@ -357,7 +358,7 @@ pub const DeclState = struct {...@@ -357,7 +358,7 @@ pub const DeclState = struct {
357 0..,358 0..,
358 ) |field_name_ip, field, field_index| {359 ) |field_name_ip, field, field_index| {
359 if (!field.ty.hasRuntimeBits(mod)) continue;360 if (!field.ty.hasRuntimeBits(mod)) continue;
360 const field_name = mod.intern_pool.stringToSlice(field_name_ip);361 const field_name = ip.stringToSlice(field_name_ip);
361 // DW.AT.member362 // DW.AT.member
362 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);363 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
363 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member));364 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member));
...@@ -388,7 +389,6 @@ pub const DeclState = struct {...@@ -388,7 +389,6 @@ pub const DeclState = struct {
388 try ty.print(dbg_info_buffer.writer(), mod);389 try ty.print(dbg_info_buffer.writer(), mod);
389 try dbg_info_buffer.append(0);390 try dbg_info_buffer.append(0);
390391
391 const ip = &mod.intern_pool;
392 const enum_type = ip.indexToKey(ty.ip_index).enum_type;392 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
393 for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {393 for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {
394 const field_name = ip.stringToSlice(field_name_index);394 const field_name = ip.stringToSlice(field_name_index);
...@@ -414,8 +414,8 @@ pub const DeclState = struct {...@@ -414,8 +414,8 @@ pub const DeclState = struct {
414 try dbg_info_buffer.append(0);414 try dbg_info_buffer.append(0);
415 },415 },
416 .Union => {416 .Union => {
417 const layout = ty.unionGetLayout(mod);
418 const union_obj = mod.typeToUnion(ty).?;417 const union_obj = mod.typeToUnion(ty).?;
418 const layout = mod.getUnionLayout(union_obj);
419 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;419 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
420 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;420 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
421 // TODO this is temporary to match current state of unions in Zig - we don't yet have421 // TODO this is temporary to match current state of unions in Zig - we don't yet have
...@@ -457,19 +457,17 @@ pub const DeclState = struct {...@@ -457,19 +457,17 @@ pub const DeclState = struct {
457 try dbg_info_buffer.append(0);457 try dbg_info_buffer.append(0);
458 }458 }
459459
460 const fields = ty.unionFields(mod);460 for (union_obj.field_types.get(ip), union_obj.field_names.get(ip)) |field_ty, field_name| {
461 for (fields.keys()) |field_name| {461 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
462 const field = fields.get(field_name).?;
463 if (!field.ty.hasRuntimeBits(mod)) continue;
464 // DW.AT.member462 // DW.AT.member
465 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_member));463 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_member));
466 // DW.AT.name, DW.FORM.string464 // DW.AT.name, DW.FORM.string
467 try dbg_info_buffer.appendSlice(mod.intern_pool.stringToSlice(field_name));465 try dbg_info_buffer.appendSlice(ip.stringToSlice(field_name));
468 try dbg_info_buffer.append(0);466 try dbg_info_buffer.append(0);
469 // DW.AT.type, DW.FORM.ref4467 // DW.AT.type, DW.FORM.ref4
470 const index = dbg_info_buffer.items.len;468 const index = dbg_info_buffer.items.len;
471 try dbg_info_buffer.resize(index + 4);469 try dbg_info_buffer.resize(index + 4);
472 try self.addTypeRelocGlobal(atom_index, field.ty, @as(u32, @intCast(index)));470 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index));
473 // DW.AT.data_member_location, DW.FORM.udata471 // DW.AT.data_member_location, DW.FORM.udata
474 try dbg_info_buffer.append(0);472 try dbg_info_buffer.append(0);
475 }473 }
...@@ -486,7 +484,7 @@ pub const DeclState = struct {...@@ -486,7 +484,7 @@ pub const DeclState = struct {
486 // DW.AT.type, DW.FORM.ref4484 // DW.AT.type, DW.FORM.ref4
487 const index = dbg_info_buffer.items.len;485 const index = dbg_info_buffer.items.len;
488 try dbg_info_buffer.resize(index + 4);486 try dbg_info_buffer.resize(index + 4);
489 try self.addTypeRelocGlobal(atom_index, union_obj.tag_ty, @as(u32, @intCast(index)));487 try self.addTypeRelocGlobal(atom_index, union_obj.enum_tag_ty.toType(), @intCast(index));
490 // DW.AT.data_member_location, DW.FORM.udata488 // DW.AT.data_member_location, DW.FORM.udata
491 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);489 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
492490
src/type.zig+177-195
...@@ -349,8 +349,7 @@ pub const Type = struct {...@@ -349,8 +349,7 @@ pub const Type = struct {
349 },349 },
350350
351 .union_type => |union_type| {351 .union_type => |union_type| {
352 const union_obj = mod.unionPtr(union_type.index);352 const decl = mod.declPtr(union_type.decl);
353 const decl = mod.declPtr(union_obj.owner_decl);
354 try decl.renderFullyQualifiedName(mod, writer);353 try decl.renderFullyQualifiedName(mod, writer);
355 },354 },
356 .opaque_type => |opaque_type| {355 .opaque_type => |opaque_type| {
...@@ -462,10 +461,11 @@ pub const Type = struct {...@@ -462,10 +461,11 @@ pub const Type = struct {
462 ignore_comptime_only: bool,461 ignore_comptime_only: bool,
463 strat: AbiAlignmentAdvancedStrat,462 strat: AbiAlignmentAdvancedStrat,
464 ) RuntimeBitsError!bool {463 ) RuntimeBitsError!bool {
464 const ip = &mod.intern_pool;
465 return switch (ty.toIntern()) {465 return switch (ty.toIntern()) {
466 // False because it is a comptime-only type.466 // False because it is a comptime-only type.
467 .empty_struct_type => false,467 .empty_struct_type => false,
468 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {468 else => switch (ip.indexToKey(ty.toIntern())) {
469 .int_type => |int_type| int_type.bits != 0,469 .int_type => |int_type| int_type.bits != 0,
470 .ptr_type => |ptr_type| {470 .ptr_type => |ptr_type| {
471 // Pointers to zero-bit types still have a runtime address; however, pointers471 // Pointers to zero-bit types still have a runtime address; however, pointers
...@@ -595,29 +595,36 @@ pub const Type = struct {...@@ -595,29 +595,36 @@ pub const Type = struct {
595 },595 },
596596
597 .union_type => |union_type| {597 .union_type => |union_type| {
598 const union_obj = mod.unionPtr(union_type.index);598 switch (union_type.flagsPtr(ip).runtime_tag) {
599 switch (union_type.runtime_tag) {
600 .none => {599 .none => {
601 if (union_obj.status == .field_types_wip) {600 if (union_type.flagsPtr(ip).status == .field_types_wip) {
602 // In this case, we guess that hasRuntimeBits() for this type is true,601 // In this case, we guess that hasRuntimeBits() for this type is true,
603 // and then later if our guess was incorrect, we emit a compile error.602 // and then later if our guess was incorrect, we emit a compile error.
604 union_obj.assumed_runtime_bits = true;603 union_type.flagsPtr(ip).assumed_runtime_bits = true;
605 return true;604 return true;
606 }605 }
607 },606 },
608 .safety, .tagged => {607 .safety, .tagged => {
609 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) {608 const tag_ty = union_type.tagTypePtr(ip).*;
609 // tag_ty will be `none` if this union's tag type is not resolved yet,
610 // in which case we want control flow to continue down below.
611 if (tag_ty != .none and
612 try tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
613 {
610 return true;614 return true;
611 }615 }
612 },616 },
613 }617 }
614 switch (strat) {618 switch (strat) {
615 .sema => |sema| _ = try sema.resolveTypeFields(ty),619 .sema => |sema| _ = try sema.resolveTypeFields(ty),
616 .eager => assert(union_obj.haveFieldTypes()),620 .eager => assert(union_type.flagsPtr(ip).status.haveFieldTypes()),
617 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,621 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
622 return error.NeedLazy,
618 }623 }
619 for (union_obj.fields.values()) |value| {624 const union_obj = ip.loadUnionType(union_type);
620 if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))625 for (0..union_obj.field_types.len) |field_index| {
626 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
627 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
621 return true;628 return true;
622 } else {629 } else {
623 return false;630 return false;
...@@ -656,7 +663,8 @@ pub const Type = struct {...@@ -656,7 +663,8 @@ pub const Type = struct {
656 /// readFrom/writeToMemory are supported only for types with a well-663 /// readFrom/writeToMemory are supported only for types with a well-
657 /// defined memory layout664 /// defined memory layout
658 pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {665 pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {
659 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {666 const ip = &mod.intern_pool;
667 return switch (ip.indexToKey(ty.toIntern())) {
660 .int_type,668 .int_type,
661 .vector_type,669 .vector_type,
662 => true,670 => true,
...@@ -728,8 +736,8 @@ pub const Type = struct {...@@ -728,8 +736,8 @@ pub const Type = struct {
728 };736 };
729 return struct_obj.layout != .Auto;737 return struct_obj.layout != .Auto;
730 },738 },
731 .union_type => |union_type| switch (union_type.runtime_tag) {739 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
732 .none, .safety => mod.unionPtr(union_type.index).layout != .Auto,740 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
733 .tagged => false,741 .tagged => false,
734 },742 },
735 .enum_type => |enum_type| switch (enum_type.tag_mode) {743 .enum_type => |enum_type| switch (enum_type.tag_mode) {
...@@ -867,6 +875,7 @@ pub const Type = struct {...@@ -867,6 +875,7 @@ pub const Type = struct {
867 strat: AbiAlignmentAdvancedStrat,875 strat: AbiAlignmentAdvancedStrat,
868 ) Module.CompileError!AbiAlignmentAdvanced {876 ) Module.CompileError!AbiAlignmentAdvanced {
869 const target = mod.getTarget();877 const target = mod.getTarget();
878 const ip = &mod.intern_pool;
870879
871 const opt_sema = switch (strat) {880 const opt_sema = switch (strat) {
872 .sema => |sema| sema,881 .sema => |sema| sema,
...@@ -875,7 +884,7 @@ pub const Type = struct {...@@ -875,7 +884,7 @@ pub const Type = struct {
875884
876 switch (ty.toIntern()) {885 switch (ty.toIntern()) {
877 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 },886 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 },
878 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {887 else => switch (ip.indexToKey(ty.toIntern())) {
879 .int_type => |int_type| {888 .int_type => |int_type| {
880 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };889 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };
881 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) };890 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) };
...@@ -1066,8 +1075,65 @@ pub const Type = struct {...@@ -1066,8 +1075,65 @@ pub const Type = struct {
1066 },1075 },
10671076
1068 .union_type => |union_type| {1077 .union_type => |union_type| {
1069 const union_obj = mod.unionPtr(union_type.index);1078 if (opt_sema) |sema| {
1070 return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());1079 if (union_type.flagsPtr(ip).status == .field_types_wip) {
1080 // We'll guess "pointer-aligned", if the union has an
1081 // underaligned pointer field then some allocations
1082 // might require explicit alignment.
1083 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
1084 }
1085 _ = try sema.resolveTypeFields(ty);
1086 }
1087 if (!union_type.haveFieldTypes(ip)) switch (strat) {
1088 .eager => unreachable, // union layout not resolved
1089 .sema => unreachable, // handled above
1090 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1091 .ty = .comptime_int_type,
1092 .storage = .{ .lazy_align = ty.toIntern() },
1093 } })).toValue() },
1094 };
1095 const union_obj = ip.loadUnionType(union_type);
1096 if (union_obj.field_names.len == 0) {
1097 if (union_obj.hasTag(ip)) {
1098 return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat);
1099 } else {
1100 return AbiAlignmentAdvanced{
1101 .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern),
1102 };
1103 }
1104 }
1105
1106 var max_align: u32 = 0;
1107 if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod);
1108 for (0..union_obj.field_names.len) |field_index| {
1109 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
1110 const field_align = if (union_obj.field_aligns.len == 0)
1111 .none
1112 else
1113 union_obj.field_aligns.get(ip)[field_index];
1114 if (!(field_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1115 error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{
1116 .ty = .comptime_int_type,
1117 .storage = .{ .lazy_align = ty.toIntern() },
1118 } })).toValue() },
1119 else => |e| return e,
1120 })) continue;
1121
1122 const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse
1123 switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
1124 .scalar => |a| a,
1125 .val => switch (strat) {
1126 .eager => unreachable, // struct layout not resolved
1127 .sema => unreachable, // handled above
1128 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1129 .ty = .comptime_int_type,
1130 .storage = .{ .lazy_align = ty.toIntern() },
1131 } })).toValue() },
1132 },
1133 });
1134 max_align = @max(max_align, field_align_bytes);
1135 }
1136 return AbiAlignmentAdvanced{ .scalar = max_align };
1071 },1137 },
1072 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },1138 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
1073 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },1139 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
...@@ -1177,71 +1243,6 @@ pub const Type = struct {...@@ -1177,71 +1243,6 @@ pub const Type = struct {
1177 }1243 }
1178 }1244 }
11791245
1180 pub fn abiAlignmentAdvancedUnion(
1181 ty: Type,
1182 mod: *Module,
1183 strat: AbiAlignmentAdvancedStrat,
1184 union_obj: *Module.Union,
1185 have_tag: bool,
1186 ) Module.CompileError!AbiAlignmentAdvanced {
1187 const opt_sema = switch (strat) {
1188 .sema => |sema| sema,
1189 else => null,
1190 };
1191 if (opt_sema) |sema| {
1192 if (union_obj.status == .field_types_wip) {
1193 // We'll guess "pointer-aligned", if the union has an
1194 // underaligned pointer field then some allocations
1195 // might require explicit alignment.
1196 const target = mod.getTarget();
1197 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
1198 }
1199 _ = try sema.resolveTypeFields(ty);
1200 }
1201 if (!union_obj.haveFieldTypes()) switch (strat) {
1202 .eager => unreachable, // union layout not resolved
1203 .sema => unreachable, // handled above
1204 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1205 .ty = .comptime_int_type,
1206 .storage = .{ .lazy_align = ty.toIntern() },
1207 } })).toValue() },
1208 };
1209 if (union_obj.fields.count() == 0) {
1210 if (have_tag) {
1211 return abiAlignmentAdvanced(union_obj.tag_ty, mod, strat);
1212 } else {
1213 return AbiAlignmentAdvanced{ .scalar = @intFromBool(union_obj.layout == .Extern) };
1214 }
1215 }
1216
1217 var max_align: u32 = 0;
1218 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(mod);
1219 for (union_obj.fields.values()) |field| {
1220 if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1221 error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{
1222 .ty = .comptime_int_type,
1223 .storage = .{ .lazy_align = ty.toIntern() },
1224 } })).toValue() },
1225 else => |e| return e,
1226 })) continue;
1227
1228 const field_align = @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse
1229 switch (try field.ty.abiAlignmentAdvanced(mod, strat)) {
1230 .scalar => |a| a,
1231 .val => switch (strat) {
1232 .eager => unreachable, // struct layout not resolved
1233 .sema => unreachable, // handled above
1234 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1235 .ty = .comptime_int_type,
1236 .storage = .{ .lazy_align = ty.toIntern() },
1237 } })).toValue() },
1238 },
1239 }));
1240 max_align = @max(max_align, field_align);
1241 }
1242 return AbiAlignmentAdvanced{ .scalar = max_align };
1243 }
1244
1245 /// May capture a reference to `ty`.1246 /// May capture a reference to `ty`.
1246 pub fn lazyAbiSize(ty: Type, mod: *Module) !Value {1247 pub fn lazyAbiSize(ty: Type, mod: *Module) !Value {
1247 switch (try ty.abiSizeAdvanced(mod, .lazy)) {1248 switch (try ty.abiSizeAdvanced(mod, .lazy)) {
...@@ -1273,11 +1274,12 @@ pub const Type = struct {...@@ -1273,11 +1274,12 @@ pub const Type = struct {
1273 strat: AbiAlignmentAdvancedStrat,1274 strat: AbiAlignmentAdvancedStrat,
1274 ) Module.CompileError!AbiSizeAdvanced {1275 ) Module.CompileError!AbiSizeAdvanced {
1275 const target = mod.getTarget();1276 const target = mod.getTarget();
1277 const ip = &mod.intern_pool;
12761278
1277 switch (ty.toIntern()) {1279 switch (ty.toIntern()) {
1278 .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },1280 .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },
12791281
1280 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {1282 else => switch (ip.indexToKey(ty.toIntern())) {
1281 .int_type => |int_type| {1283 .int_type => |int_type| {
1282 if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };1284 if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1283 return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) };1285 return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) };
...@@ -1484,8 +1486,18 @@ pub const Type = struct {...@@ -1484,8 +1486,18 @@ pub const Type = struct {
1484 },1486 },
14851487
1486 .union_type => |union_type| {1488 .union_type => |union_type| {
1487 const union_obj = mod.unionPtr(union_type.index);1489 switch (strat) {
1488 return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());1490 .sema => |sema| try sema.resolveTypeLayout(ty),
1491 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
1492 .val = (try mod.intern(.{ .int = .{
1493 .ty = .comptime_int_type,
1494 .storage = .{ .lazy_size = ty.toIntern() },
1495 } })).toValue(),
1496 },
1497 .eager => {},
1498 }
1499 const union_obj = ip.loadUnionType(union_type);
1500 return AbiSizeAdvanced{ .scalar = mod.unionAbiSize(union_obj) };
1489 },1501 },
1490 .opaque_type => unreachable, // no size available1502 .opaque_type => unreachable, // no size available
1491 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },1503 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },
...@@ -1515,24 +1527,6 @@ pub const Type = struct {...@@ -1515,24 +1527,6 @@ pub const Type = struct {
1515 }1527 }
1516 }1528 }
15171529
1518 pub fn abiSizeAdvancedUnion(
1519 ty: Type,
1520 mod: *Module,
1521 strat: AbiAlignmentAdvancedStrat,
1522 union_obj: *Module.Union,
1523 have_tag: bool,
1524 ) Module.CompileError!AbiSizeAdvanced {
1525 switch (strat) {
1526 .sema => |sema| try sema.resolveTypeLayout(ty),
1527 .lazy => if (!union_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{
1528 .ty = .comptime_int_type,
1529 .storage = .{ .lazy_size = ty.toIntern() },
1530 } })).toValue() },
1531 .eager => {},
1532 }
1533 return AbiSizeAdvanced{ .scalar = union_obj.abiSize(mod, have_tag) };
1534 }
1535
1536 fn abiSizeAdvancedOptional(1530 fn abiSizeAdvancedOptional(
1537 ty: Type,1531 ty: Type,
1538 mod: *Module,1532 mod: *Module,
...@@ -1602,10 +1596,11 @@ pub const Type = struct {...@@ -1602,10 +1596,11 @@ pub const Type = struct {
1602 opt_sema: ?*Sema,1596 opt_sema: ?*Sema,
1603 ) Module.CompileError!u64 {1597 ) Module.CompileError!u64 {
1604 const target = mod.getTarget();1598 const target = mod.getTarget();
1599 const ip = &mod.intern_pool;
16051600
1606 const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;1601 const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
16071602
1608 switch (mod.intern_pool.indexToKey(ty.toIntern())) {1603 switch (ip.indexToKey(ty.toIntern())) {
1609 .int_type => |int_type| return int_type.bits,1604 .int_type => |int_type| return int_type.bits,
1610 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1605 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1611 .Slice => return target.ptrBitWidth() * 2,1606 .Slice => return target.ptrBitWidth() * 2,
...@@ -1714,12 +1709,13 @@ pub const Type = struct {...@@ -1714,12 +1709,13 @@ pub const Type = struct {
1714 if (ty.containerLayout(mod) != .Packed) {1709 if (ty.containerLayout(mod) != .Packed) {
1715 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1710 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1716 }1711 }
1717 const union_obj = mod.unionPtr(union_type.index);1712 const union_obj = ip.loadUnionType(union_type);
1718 assert(union_obj.haveFieldTypes());1713 assert(union_obj.flagsPtr(ip).status.haveFieldTypes());
17191714
1720 var size: u64 = 0;1715 var size: u64 = 0;
1721 for (union_obj.fields.values()) |field| {1716 for (0..union_obj.field_types.len) |field_index| {
1722 size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema));1717 const field_ty = union_obj.field_types.get(ip)[field_index];
1718 size = @max(size, try bitSizeAdvanced(field_ty.toType(), mod, opt_sema));
1723 }1719 }
1724 return size;1720 return size;
1725 },1721 },
...@@ -1753,33 +1749,24 @@ pub const Type = struct {...@@ -1753,33 +1749,24 @@ pub const Type = struct {
1753 /// Returns true if the type's layout is already resolved and it is safe1749 /// Returns true if the type's layout is already resolved and it is safe
1754 /// to use `abiSize`, `abiAlignment` and `bitSize` on it.1750 /// to use `abiSize`, `abiAlignment` and `bitSize` on it.
1755 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {1751 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1756 switch (ty.zigTypeTag(mod)) {1752 const ip = &mod.intern_pool;
1757 .Struct => {1753 return switch (ip.indexToKey(ty.toIntern())) {
1758 if (mod.typeToStruct(ty)) |struct_obj| {1754 .struct_type => |struct_type| {
1755 if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
1759 return struct_obj.haveLayout();1756 return struct_obj.haveLayout();
1757 } else {
1758 return true;
1760 }1759 }
1761 return true;
1762 },
1763 .Union => {
1764 if (mod.typeToUnion(ty)) |union_obj| {
1765 return union_obj.haveLayout();
1766 }
1767 return true;
1768 },1760 },
1769 .Array => {1761 .union_type => |union_type| union_type.haveLayout(ip),
1770 if (ty.arrayLenIncludingSentinel(mod) == 0) return true;1762 .array_type => |array_type| {
1771 return ty.childType(mod).layoutIsResolved(mod);1763 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
1772 },1764 return array_type.child.toType().layoutIsResolved(mod);
1773 .Optional => {
1774 const payload_ty = ty.optionalChild(mod);
1775 return payload_ty.layoutIsResolved(mod);
1776 },
1777 .ErrorUnion => {
1778 const payload_ty = ty.errorUnionPayload(mod);
1779 return payload_ty.layoutIsResolved(mod);
1780 },1765 },
1781 else => return true,1766 .opt_type => |child| child.toType().layoutIsResolved(mod),
1782 }1767 .error_union_type => |k| k.payload_type.toType().layoutIsResolved(mod),
1768 else => true,
1769 };
1783 }1770 }
17841771
1785 pub fn isSinglePointer(ty: Type, mod: *const Module) bool {1772 pub fn isSinglePointer(ty: Type, mod: *const Module) bool {
...@@ -1970,12 +1957,12 @@ pub const Type = struct {...@@ -1970,12 +1957,12 @@ pub const Type = struct {
1970 /// Returns the tag type of a union, if the type is a union and it has a tag type.1957 /// Returns the tag type of a union, if the type is a union and it has a tag type.
1971 /// Otherwise, returns `null`.1958 /// Otherwise, returns `null`.
1972 pub fn unionTagType(ty: Type, mod: *Module) ?Type {1959 pub fn unionTagType(ty: Type, mod: *Module) ?Type {
1973 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {1960 const ip = &mod.intern_pool;
1974 .union_type => |union_type| switch (union_type.runtime_tag) {1961 return switch (ip.indexToKey(ty.toIntern())) {
1962 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
1975 .tagged => {1963 .tagged => {
1976 const union_obj = mod.unionPtr(union_type.index);1964 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1977 assert(union_obj.haveFieldTypes());1965 return union_type.enum_tag_ty.toType();
1978 return union_obj.tag_ty;
1979 },1966 },
1980 else => null,1967 else => null,
1981 },1968 },
...@@ -1986,12 +1973,12 @@ pub const Type = struct {...@@ -1986,12 +1973,12 @@ pub const Type = struct {
1986 /// Same as `unionTagType` but includes safety tag.1973 /// Same as `unionTagType` but includes safety tag.
1987 /// Codegen should use this version.1974 /// Codegen should use this version.
1988 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {1975 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
1989 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {1976 const ip = &mod.intern_pool;
1977 return switch (ip.indexToKey(ty.toIntern())) {
1990 .union_type => |union_type| {1978 .union_type => |union_type| {
1991 if (!union_type.hasTag()) return null;1979 if (!union_type.hasTag(ip)) return null;
1992 const union_obj = mod.unionPtr(union_type.index);1980 assert(union_type.haveFieldTypes(ip));
1993 assert(union_obj.haveFieldTypes());1981 return union_type.enum_tag_ty.toType();
1994 return union_obj.tag_ty;
1995 },1982 },
1996 else => null,1983 else => null,
1997 };1984 };
...@@ -2001,52 +1988,46 @@ pub const Type = struct {...@@ -2001,52 +1988,46 @@ pub const Type = struct {
2001 /// not be stored at runtime.1988 /// not be stored at runtime.
2002 pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {1989 pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
2003 const union_obj = mod.typeToUnion(ty).?;1990 const union_obj = mod.typeToUnion(ty).?;
2004 assert(union_obj.haveFieldTypes());1991 return union_obj.enum_tag_ty.toType();
2005 return union_obj.tag_ty;
2006 }
2007
2008 pub fn unionFields(ty: Type, mod: *Module) Module.Union.Fields {
2009 const union_obj = mod.typeToUnion(ty).?;
2010 assert(union_obj.haveFieldTypes());
2011 return union_obj.fields;
2012 }1992 }
20131993
2014 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {1994 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
1995 const ip = &mod.intern_pool;
2015 const union_obj = mod.typeToUnion(ty).?;1996 const union_obj = mod.typeToUnion(ty).?;
2016 const index = ty.unionTagFieldIndex(enum_tag, mod).?;1997 const index = mod.unionTagFieldIndex(union_obj, enum_tag).?;
2017 assert(union_obj.haveFieldTypes());1998 return union_obj.field_types.get(ip)[index].toType();
2018 return union_obj.fields.values()[index].ty;
2019 }1999 }
20202000
2021 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {2001 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
2022 const union_obj = mod.typeToUnion(ty).?;2002 const union_obj = mod.typeToUnion(ty).?;
2023 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;2003 return mod.unionTagFieldIndex(union_obj, enum_tag);
2024 const name = union_obj.tag_ty.enumFieldName(index, mod);
2025 return union_obj.fields.getIndex(name);
2026 }2004 }
20272005
2028 pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {2006 pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
2007 const ip = &mod.intern_pool;
2029 const union_obj = mod.typeToUnion(ty).?;2008 const union_obj = mod.typeToUnion(ty).?;
2030 return union_obj.hasAllZeroBitFieldTypes(mod);2009 for (union_obj.field_types.get(ip)) |field_ty| {
2010 if (field_ty.toType().hasRuntimeBits(mod)) return false;
2011 }
2012 return true;
2031 }2013 }
20322014
2033 pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout {2015 pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
2034 const union_type = mod.intern_pool.indexToKey(ty.toIntern()).union_type;2016 const ip = &mod.intern_pool;
2035 const union_obj = mod.unionPtr(union_type.index);2017 const union_type = ip.indexToKey(ty.toIntern()).union_type;
2036 return union_obj.getLayout(mod, union_type.hasTag());2018 const union_obj = ip.loadUnionType(union_type);
2019 return mod.getUnionLayout(union_obj);
2037 }2020 }
20382021
2039 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {2022 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
2040 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2023 const ip = &mod.intern_pool;
2024 return switch (ip.indexToKey(ty.toIntern())) {
2041 .struct_type => |struct_type| {2025 .struct_type => |struct_type| {
2042 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;2026 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
2043 return struct_obj.layout;2027 return struct_obj.layout;
2044 },2028 },
2045 .anon_struct_type => .Auto,2029 .anon_struct_type => .Auto,
2046 .union_type => |union_type| {2030 .union_type => |union_type| union_type.flagsPtr(ip).layout,
2047 const union_obj = mod.unionPtr(union_type.index);
2048 return union_obj.layout;
2049 },
2050 else => unreachable,2031 else => unreachable,
2051 };2032 };
2052 }2033 }
...@@ -2570,14 +2551,16 @@ pub const Type = struct {...@@ -2570,14 +2551,16 @@ pub const Type = struct {
2570 },2551 },
25712552
2572 .union_type => |union_type| {2553 .union_type => |union_type| {
2573 const union_obj = mod.unionPtr(union_type.index);2554 const union_obj = ip.loadUnionType(union_type);
2574 const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;2555 const tag_val = (try union_obj.enum_tag_ty.toType().onePossibleValue(mod)) orelse
2575 if (union_obj.fields.count() == 0) {2556 return null;
2557 if (union_obj.field_names.len == 0) {
2576 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });2558 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2577 return only.toValue();2559 return only.toValue();
2578 }2560 }
2579 const only_field = union_obj.fields.values()[0];2561 const only_field_ty = union_obj.field_types.get(ip)[0];
2580 const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;2562 const val_val = (try only_field_ty.toType().onePossibleValue(mod)) orelse
2563 return null;
2581 const only = try mod.intern(.{ .un = .{2564 const only = try mod.intern(.{ .un = .{
2582 .ty = ty.toIntern(),2565 .ty = ty.toIntern(),
2583 .tag = tag_val.toIntern(),2566 .tag = tag_val.toIntern(),
...@@ -2657,10 +2640,11 @@ pub const Type = struct {...@@ -2657,10 +2640,11 @@ pub const Type = struct {
2657 /// TODO merge these implementations together with the "advanced" pattern seen2640 /// TODO merge these implementations together with the "advanced" pattern seen
2658 /// elsewhere in this file.2641 /// elsewhere in this file.
2659 pub fn comptimeOnly(ty: Type, mod: *Module) bool {2642 pub fn comptimeOnly(ty: Type, mod: *Module) bool {
2643 const ip = &mod.intern_pool;
2660 return switch (ty.toIntern()) {2644 return switch (ty.toIntern()) {
2661 .empty_struct_type => false,2645 .empty_struct_type => false,
26622646
2663 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {2647 else => switch (ip.indexToKey(ty.toIntern())) {
2664 .int_type => false,2648 .int_type => false,
2665 .ptr_type => |ptr_type| {2649 .ptr_type => |ptr_type| {
2666 const child_ty = ptr_type.child.toType();2650 const child_ty = ptr_type.child.toType();
...@@ -2704,6 +2688,7 @@ pub const Type = struct {...@@ -2704,6 +2688,7 @@ pub const Type = struct {
2704 .c_longlong,2688 .c_longlong,
2705 .c_ulonglong,2689 .c_ulonglong,
2706 .c_longdouble,2690 .c_longdouble,
2691 .anyopaque,
2707 .bool,2692 .bool,
2708 .void,2693 .void,
2709 .anyerror,2694 .anyerror,
...@@ -2722,7 +2707,6 @@ pub const Type = struct {...@@ -2722,7 +2707,6 @@ pub const Type = struct {
2722 .extern_options,2707 .extern_options,
2723 => false,2708 => false,
27242709
2725 .anyopaque,
2726 .type,2710 .type,
2727 .comptime_int,2711 .comptime_int,
2728 .comptime_float,2712 .comptime_float,
...@@ -2756,8 +2740,7 @@ pub const Type = struct {...@@ -2756,8 +2740,7 @@ pub const Type = struct {
2756 },2740 },
27572741
2758 .union_type => |union_type| {2742 .union_type => |union_type| {
2759 const union_obj = mod.unionPtr(union_type.index);2743 switch (union_type.flagsPtr(ip).requires_comptime) {
2760 switch (union_obj.requires_comptime) {
2761 .wip, .unknown => {2744 .wip, .unknown => {
2762 // Return false to avoid incorrect dependency loops.2745 // Return false to avoid incorrect dependency loops.
2763 // This will be handled correctly once merged with2746 // This will be handled correctly once merged with
...@@ -2769,7 +2752,7 @@ pub const Type = struct {...@@ -2769,7 +2752,7 @@ pub const Type = struct {
2769 }2752 }
2770 },2753 },
27712754
2772 .opaque_type => true,2755 .opaque_type => false,
27732756
2774 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),2757 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
27752758
...@@ -2847,7 +2830,7 @@ pub const Type = struct {...@@ -2847,7 +2830,7 @@ pub const Type = struct {
2847 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2830 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2848 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),2831 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
2849 .struct_type => |struct_type| struct_type.namespace,2832 .struct_type => |struct_type| struct_type.namespace,
2850 .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),2833 .union_type => |union_type| union_type.namespace.toOptional(),
2851 .enum_type => |enum_type| enum_type.namespace,2834 .enum_type => |enum_type| enum_type.namespace,
28522835
2853 else => .none,2836 else => .none,
...@@ -2935,7 +2918,7 @@ pub const Type = struct {...@@ -2935,7 +2918,7 @@ pub const Type = struct {
2935 /// Asserts the type is an enum or a union.2918 /// Asserts the type is an enum or a union.
2936 pub fn intTagType(ty: Type, mod: *Module) Type {2919 pub fn intTagType(ty: Type, mod: *Module) Type {
2937 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2920 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2938 .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),2921 .union_type => |union_type| union_type.enum_tag_ty.toType().intTagType(mod),
2939 .enum_type => |enum_type| enum_type.tag_ty.toType(),2922 .enum_type => |enum_type| enum_type.tag_ty.toType(),
2940 else => unreachable,2923 else => unreachable,
2941 };2924 };
...@@ -3038,15 +3021,16 @@ pub const Type = struct {...@@ -3038,15 +3021,16 @@ pub const Type = struct {
30383021
3039 /// Supports structs and unions.3022 /// Supports structs and unions.
3040 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {3023 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3041 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {3024 const ip = &mod.intern_pool;
3025 return switch (ip.indexToKey(ty.toIntern())) {
3042 .struct_type => |struct_type| {3026 .struct_type => |struct_type| {
3043 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3027 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3044 assert(struct_obj.haveFieldTypes());3028 assert(struct_obj.haveFieldTypes());
3045 return struct_obj.fields.values()[index].ty;3029 return struct_obj.fields.values()[index].ty;
3046 },3030 },
3047 .union_type => |union_type| {3031 .union_type => |union_type| {
3048 const union_obj = mod.unionPtr(union_type.index);3032 const union_obj = ip.loadUnionType(union_type);
3049 return union_obj.fields.values()[index].ty;3033 return union_obj.field_types.get(ip)[index].toType();
3050 },3034 },
3051 .anon_struct_type => |anon_struct| anon_struct.types[index].toType(),3035 .anon_struct_type => |anon_struct| anon_struct.types[index].toType(),
3052 else => unreachable,3036 else => unreachable,
...@@ -3054,7 +3038,8 @@ pub const Type = struct {...@@ -3054,7 +3038,8 @@ pub const Type = struct {
3054 }3038 }
30553039
3056 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {3040 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
3057 switch (mod.intern_pool.indexToKey(ty.toIntern())) {3041 const ip = &mod.intern_pool;
3042 switch (ip.indexToKey(ty.toIntern())) {
3058 .struct_type => |struct_type| {3043 .struct_type => |struct_type| {
3059 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3044 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3060 assert(struct_obj.layout != .Packed);3045 assert(struct_obj.layout != .Packed);
...@@ -3064,8 +3049,8 @@ pub const Type = struct {...@@ -3064,8 +3049,8 @@ pub const Type = struct {
3064 return anon_struct.types[index].toType().abiAlignment(mod);3049 return anon_struct.types[index].toType().abiAlignment(mod);
3065 },3050 },
3066 .union_type => |union_type| {3051 .union_type => |union_type| {
3067 const union_obj = mod.unionPtr(union_type.index);3052 const union_obj = ip.loadUnionType(union_type);
3068 return union_obj.fields.values()[index].normalAlignment(mod);3053 return mod.unionFieldNormalAlignment(union_obj, @intCast(index));
3069 },3054 },
3070 else => unreachable,3055 else => unreachable,
3071 }3056 }
...@@ -3198,7 +3183,8 @@ pub const Type = struct {...@@ -3198,7 +3183,8 @@ pub const Type = struct {
31983183
3199 /// Supports structs and unions.3184 /// Supports structs and unions.
3200 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {3185 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3201 switch (mod.intern_pool.indexToKey(ty.toIntern())) {3186 const ip = &mod.intern_pool;
3187 switch (ip.indexToKey(ty.toIntern())) {
3202 .struct_type => |struct_type| {3188 .struct_type => |struct_type| {
3203 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3189 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3204 assert(struct_obj.haveLayout());3190 assert(struct_obj.haveLayout());
...@@ -3234,10 +3220,10 @@ pub const Type = struct {...@@ -3234,10 +3220,10 @@ pub const Type = struct {
3234 },3220 },
32353221
3236 .union_type => |union_type| {3222 .union_type => |union_type| {
3237 if (!union_type.hasTag())3223 if (!union_type.hasTag(ip))
3238 return 0;3224 return 0;
3239 const union_obj = mod.unionPtr(union_type.index);3225 const union_obj = ip.loadUnionType(union_type);
3240 const layout = union_obj.getLayout(mod, true);3226 const layout = mod.getUnionLayout(union_obj);
3241 if (layout.tag_align >= layout.payload_align) {3227 if (layout.tag_align >= layout.payload_align) {
3242 // {Tag, Payload}3228 // {Tag, Payload}
3243 return std.mem.alignForward(u64, layout.tag_size, layout.payload_align);3229 return std.mem.alignForward(u64, layout.tag_size, layout.payload_align);
...@@ -3262,8 +3248,7 @@ pub const Type = struct {...@@ -3262,8 +3248,7 @@ pub const Type = struct {
3262 return struct_obj.srcLoc(mod);3248 return struct_obj.srcLoc(mod);
3263 },3249 },
3264 .union_type => |union_type| {3250 .union_type => |union_type| {
3265 const union_obj = mod.unionPtr(union_type.index);3251 return mod.declPtr(union_type.decl).srcLoc(mod);
3266 return union_obj.srcLoc(mod);
3267 },3252 },
3268 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),3253 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
3269 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),3254 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),
...@@ -3281,10 +3266,7 @@ pub const Type = struct {...@@ -3281,10 +3266,7 @@ pub const Type = struct {
3281 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;3266 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
3282 return struct_obj.owner_decl;3267 return struct_obj.owner_decl;
3283 },3268 },
3284 .union_type => |union_type| {3269 .union_type => |union_type| union_type.decl,
3285 const union_obj = mod.unionPtr(union_type.index);
3286 return union_obj.owner_decl;
3287 },
3288 .opaque_type => |opaque_type| opaque_type.decl,3270 .opaque_type => |opaque_type| opaque_type.decl,
3289 .enum_type => |enum_type| enum_type.decl,3271 .enum_type => |enum_type| enum_type.decl,
3290 else => null,3272 else => null,
src/value.zig+16-12
...@@ -734,6 +734,7 @@ pub const Value = struct {...@@ -734,6 +734,7 @@ pub const Value = struct {
734 buffer: []u8,734 buffer: []u8,
735 bit_offset: usize,735 bit_offset: usize,
736 ) error{ ReinterpretDeclRef, OutOfMemory }!void {736 ) error{ ReinterpretDeclRef, OutOfMemory }!void {
737 const ip = &mod.intern_pool;
737 const target = mod.getTarget();738 const target = mod.getTarget();
738 const endian = target.cpu.arch.endian();739 const endian = target.cpu.arch.endian();
739 if (val.isUndef(mod)) {740 if (val.isUndef(mod)) {
...@@ -759,7 +760,7 @@ pub const Value = struct {...@@ -759,7 +760,7 @@ pub const Value = struct {
759 const bits = ty.intInfo(mod).bits;760 const bits = ty.intInfo(mod).bits;
760 if (bits == 0) return;761 if (bits == 0) return;
761762
762 switch (mod.intern_pool.indexToKey((try val.intFromEnum(ty, mod)).toIntern()).int.storage) {763 switch (ip.indexToKey((try val.intFromEnum(ty, mod)).toIntern()).int.storage) {
763 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),764 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
764 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),765 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
765 else => unreachable,766 else => unreachable,
...@@ -794,7 +795,7 @@ pub const Value = struct {...@@ -794,7 +795,7 @@ pub const Value = struct {
794 .Packed => {795 .Packed => {
795 var bits: u16 = 0;796 var bits: u16 = 0;
796 const fields = ty.structFields(mod).values();797 const fields = ty.structFields(mod).values();
797 const storage = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage;798 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
798 for (fields, 0..) |field, i| {799 for (fields, 0..) |field, i| {
799 const field_bits = @as(u16, @intCast(field.ty.bitSize(mod)));800 const field_bits = @as(u16, @intCast(field.ty.bitSize(mod)));
800 const field_val = switch (storage) {801 const field_val = switch (storage) {
...@@ -807,16 +808,19 @@ pub const Value = struct {...@@ -807,16 +808,19 @@ pub const Value = struct {
807 }808 }
808 },809 },
809 },810 },
810 .Union => switch (ty.containerLayout(mod)) {811 .Union => {
811 .Auto => unreachable, // Sema is supposed to have emitted a compile error already812 const union_obj = mod.typeToUnion(ty).?;
812 .Extern => unreachable, // Handled in non-packed writeToMemory813 switch (union_obj.getLayout(ip)) {
813 .Packed => {814 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
814 const field_index = ty.unionTagFieldIndex(val.unionTag(mod), mod);815 .Extern => unreachable, // Handled in non-packed writeToMemory
815 const field_type = ty.unionFields(mod).values()[field_index.?].ty;816 .Packed => {
816 const field_val = try val.fieldValue(mod, field_index.?);817 const field_index = mod.unionTagFieldIndex(union_obj, val.unionTag(mod)).?;
817818 const field_type = union_obj.field_types.get(ip)[field_index].toType();
818 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);819 const field_val = try val.fieldValue(mod, field_index);
819 },820
821 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
822 },
823 }
820 },824 },
821 .Pointer => {825 .Pointer => {
822 assert(!ty.isSlice(mod)); // No well defined layout.826 assert(!ty.isSlice(mod)); // No well defined layout.
test/behavior/union.zig+1-26
...@@ -1347,31 +1347,6 @@ test "noreturn field in union" {...@@ -1347,31 +1347,6 @@ test "noreturn field in union" {
1347 try expect(count == 6);1347 try expect(count == 6);
1348}1348}
13491349
1350test "union and enum field order doesn't match" {
1351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1353 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1354 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1355
1356 const MyTag = enum(u32) {
1357 b = 1337,
1358 a = 1666,
1359 };
1360 const MyUnion = union(MyTag) {
1361 a: f32,
1362 b: void,
1363 };
1364 var x: MyUnion = .{ .a = 666 };
1365 switch (x) {
1366 .a => |my_f32| {
1367 try expect(@TypeOf(my_f32) == f32);
1368 },
1369 .b => unreachable,
1370 }
1371 x = .b;
1372 try expect(x == .b);
1373}
1374
1375test "@unionInit uses tag value instead of field index" {1350test "@unionInit uses tag value instead of field index" {
1376 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1377 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -1383,8 +1358,8 @@ test "@unionInit uses tag value instead of field index" {...@@ -1383,8 +1358,8 @@ test "@unionInit uses tag value instead of field index" {
1383 a = 3,1358 a = 3,
1384 };1359 };
1385 const U = union(E) {1360 const U = union(E) {
1386 a: usize,
1387 b: isize,1361 b: isize,
1362 a: usize,
1388 };1363 };
1389 var i: isize = -1;1364 var i: isize = -1;
1390 var u = @unionInit(U, "b", i);1365 var u = @unionInit(U, "b", i);
test/cases/compile_errors/access_inactive_union_field_comptime.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const Enum = enum(u32) { a, b };1const Enum = enum(u32) { b, a };
2const TaggedUnion = union(Enum) {2const TaggedUnion = union(Enum) {
3 b: []const u8,3 b: []const u8,
4 a: []const u8,4 a: []const u8,
test/cases/compile_errors/dereference_anyopaque.zig+1-2
...@@ -45,8 +45,7 @@ pub export fn entry() void {...@@ -45,8 +45,7 @@ pub export fn entry() void {
45// backend=llvm45// backend=llvm
46//46//
47// :11:22: error: comparison of 'void' with null47// :11:22: error: comparison of 'void' with null
48// :25:51: error: values of type 'anyopaque' must be comptime-known, but operand value is runtime-known48// :25:51: error: cannot load opaque type 'anyopaque'
49// :25:51: note: opaque type 'anyopaque' has undefined size
50// :25:51: error: values of type 'fn(*anyopaque, usize, u8, usize) ?[*]u8' must be comptime-known, but operand value is runtime-known49// :25:51: error: values of type 'fn(*anyopaque, usize, u8, usize) ?[*]u8' must be comptime-known, but operand value is runtime-known
51// :25:51: note: use '*const fn(*anyopaque, usize, u8, usize) ?[*]u8' for a function pointer type50// :25:51: note: use '*const fn(*anyopaque, usize, u8, usize) ?[*]u8' for a function pointer type
52// :25:51: error: values of type 'fn(*anyopaque, []u8, u8, usize, usize) bool' must be comptime-known, but operand value is runtime-known51// :25:51: error: values of type 'fn(*anyopaque, []u8, u8, usize, usize) bool' must be comptime-known, but operand value is runtime-known
test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig+4-6
...@@ -15,12 +15,12 @@ export fn b() void {...@@ -15,12 +15,12 @@ export fn b() void {
15 _ = bar;15 _ = bar;
16}16}
17export fn c() void {17export fn c() void {
18 const baz = &@as(opaque {}, undefined);18 const baz = &@as(O, undefined);
19 const qux = .{baz.*};19 const qux = .{baz.*};
20 _ = qux;20 _ = qux;
21}21}
22export fn d() void {22export fn d() void {
23 const baz = &@as(opaque {}, undefined);23 const baz = &@as(O, undefined);
24 const qux = .{ .a = baz.* };24 const qux = .{ .a = baz.* };
25 _ = qux;25 _ = qux;
26}26}
...@@ -33,7 +33,5 @@ export fn d() void {...@@ -33,7 +33,5 @@ export fn d() void {
33// :1:11: note: opaque declared here33// :1:11: note: opaque declared here
34// :7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions34// :7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions
35// :1:11: note: opaque declared here35// :1:11: note: opaque declared here
36// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs36// :19:22: error: cannot load opaque type 'tmp.O'
37// :18:22: note: opaque declared here37// :24:28: error: cannot load opaque type 'tmp.O'
38// :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs
39// :23:22: note: opaque declared here
test/cases/compile_errors/non-const_variables_of_things_that_require_const_variables.zig+6-2
...@@ -27,6 +27,10 @@ export fn entry7() void {...@@ -27,6 +27,10 @@ export fn entry7() void {
27 _ = f;27 _ = f;
28}28}
29const Opaque = opaque {};29const Opaque = opaque {};
30export fn entry8() void {
31 var e: Opaque = undefined;
32 _ = &e;
33}
3034
31// error35// error
32// backend=stage236// backend=stage2
...@@ -39,7 +43,7 @@ const Opaque = opaque {};...@@ -39,7 +43,7 @@ const Opaque = opaque {};
39// :14:9: error: variable of type 'comptime_float' must be const or comptime43// :14:9: error: variable of type 'comptime_float' must be const or comptime
40// :14:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type44// :14:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
41// :18:9: error: variable of type '@TypeOf(null)' must be const or comptime45// :18:9: error: variable of type '@TypeOf(null)' must be const or comptime
42// :22:20: error: values of type 'tmp.Opaque' must be comptime-known, but operand value is runtime-known46// :22:20: error: cannot load opaque type 'tmp.Opaque'
43// :22:20: note: opaque type 'tmp.Opaque' has undefined size
44// :26:9: error: variable of type 'type' must be const or comptime47// :26:9: error: variable of type 'type' must be const or comptime
45// :26:9: note: types are not available at runtime48// :26:9: note: types are not available at runtime
49// :31:12: error: non-extern variable with opaque type 'tmp.Opaque'