authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-05 06:02:58+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-06 21:26:37+00:00
logd0c022f7347b5cda34751a986a535aee3b1f45dc
tree40a178dcd2b152a7fe26977b94d636d93debf52c
parent8ec6f730eff1f6008b7eba1c749824a4a5734e5f
signaturelock-open Commit is signed but in an unrecognized format.

compiler: namespace type equivalence based on AST node + captures

This implements the accepted proposal #18816. Namespace-owning types (struct, enum, union, opaque) are no longer unique whenever analysed; instead, their identity is determined based on their AST node and the set of values they capture. Reified types (`@Type`) are deduplicated based on the structure of the type created. For instance, if two structs are created by the same reification with identical fields, layout, etc, they will be the same type. This commit does not produce a working compiler; the next commit, adding captures for decl references, is necessary. It felt appropriate to split this up. Resolves: #18816

5 files changed, 1709 insertions(+), 1262 deletions(-)

src/InternPool.zig+888-473
......@@ -344,6 +344,7 @@ const KeyAdapter = struct {
344344
345345 pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
346346 _ = b_void;
347 if (ctx.intern_pool.items.items(.tag)[b_map_index] == .removed) return false;
347348 return ctx.intern_pool.indexToKey(@as(Index, @enumFromInt(b_map_index))).eql(a, ctx.intern_pool);
348349 }
349350
......@@ -551,14 +552,14 @@ pub const Key = union(enum) {
551552 /// This represents a struct that has been explicitly declared in source code,
552553 /// or was created with `@Type`. It is unique and based on a declaration.
553554 /// It may be a tuple, if declared like this: `struct {A, B, C}`.
554 struct_type: StructType,
555 struct_type: NamespaceType,
555556 /// This is an anonymous struct or tuple type which has no corresponding
556557 /// declaration. It is used for types that have no `struct` keyword in the
557558 /// source code, and were not created via `@Type`.
558559 anon_struct_type: AnonStructType,
559 union_type: Key.UnionType,
560 opaque_type: OpaqueType,
561 enum_type: EnumType,
560 union_type: NamespaceType,
561 opaque_type: NamespaceType,
562 enum_type: NamespaceType,
562563 func_type: FuncType,
563564 error_set_type: ErrorSetType,
564565 /// The payload is the function body, either a `func_decl` or `func_instance`.
......@@ -703,66 +704,41 @@ pub const Key = union(enum) {
703704 }
704705 };
705706
706 /// This is the hashmap key. To fetch other data associated with the struct, see `loadStructType`.
707 pub const StructType = struct {
708 /// The struct's owner Decl. `none` when the struct is `@TypeOf(.{})`.
709 decl: OptionalDeclIndex,
710 };
711
712 /// This is the hashmap key. To fetch other data associated with the opaque, see `loadOpaqueType`.
713 pub const OpaqueType = struct {
714 /// The opaque's owner Decl.
715 decl: DeclIndex,
716 };
717
718 /// This is the hashmap key. To fetch other data associated with the union, see `loadUnionType`.
719 pub const UnionType = struct {
720 /// The union's owner Decl.
721 decl: DeclIndex,
722 };
723
724 /// This is the hashmap key. To fetch other data associated with the enum, see `loadEnumType`.
725 pub const EnumType = struct {
726 /// The enum's owner Decl.
727 decl: DeclIndex,
728 };
729
730 pub const IncompleteEnumType = struct {
731 /// Same as corresponding `EnumType` field.
732 decl: DeclIndex,
733 /// Same as corresponding `EnumType` field.
734 namespace: OptionalNamespaceIndex,
735 /// The field names and field values are not known yet, but
736 /// the number of fields must be known ahead of time.
737 fields_len: u32,
738 /// This information is needed so that the size does not change
739 /// later when populating field values.
740 has_values: bool,
741 /// Same as corresponding `EnumType` field.
742 tag_mode: LoadedEnumType.TagMode,
743 /// This may be updated via `setTagType` later.
744 tag_ty: Index = .none,
745 zir_index: TrackedInst.Index.Optional,
746 captures: []const CaptureValue,
747
748 pub fn toEnumType(self: @This()) LoadedEnumType {
749 if (true) @compileError("AHHHH");
750 return .{
751 .decl = self.decl,
752 .namespace = self.namespace,
753 .tag_ty = self.tag_ty,
754 .tag_mode = self.tag_mode,
755 .names = .{ .start = 0, .len = 0 },
756 .values = .{ .start = 0, .len = 0 },
757 .zir_index = self.zir_index,
758 };
759 }
760
761 /// Only the decl is used for hashing and equality, so we can construct
762 /// this minimal key for use with `map`.
763 pub fn toKey(self: @This()) Key {
764 return .{ .enum_type = .{ .decl = self.decl } };
765 }
707 /// This is the hashmap key. To fetch other data associated with the type, see:
708 /// * `loadStructType`
709 /// * `loadUnionType`
710 /// * `loadEnumType`
711 /// * `loadOpaqueType`
712 pub const NamespaceType = union(enum) {
713 /// This type corresponds to an actual source declaration, e.g. `struct { ... }`.
714 /// It is hashed based on its ZIR instruction index and set of captures.
715 declared: struct {
716 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
717 zir_index: TrackedInst.Index,
718 /// The captured values of this type. These values must be fully resolved per the language spec.
719 captures: union(enum) {
720 owned: CaptureValue.Slice,
721 external: []const CaptureValue,
722 },
723 },
724 /// This type is an automatically-generated enum tag type for a union.
725 /// It is hashed based on the index of the union type it corresponds to.
726 generated_tag: struct {
727 /// The union for which this is a tag type.
728 union_type: Index,
729 },
730 /// This type originates from a reification via `@Type`.
731 /// It is hased based on its ZIR instruction index and fields, attributes, etc.
732 /// To avoid making this key overly complex, the type-specific data is hased by Sema.
733 reified: struct {
734 /// A `reify` instruction.
735 zir_index: TrackedInst.Index,
736 /// A hash of this type's attributes, fields, etc, generated by Sema.
737 type_hash: u64,
738 },
739 /// This type is `@TypeOf(.{})`.
740 /// TODO: can we change the language spec to not special-case this type?
741 empty_struct: void,
766742 };
767743
768744 pub const FuncType = struct {
......@@ -1113,12 +1089,37 @@ pub const Key = union(enum) {
11131089 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
11141090 },
11151091
1116 inline .opaque_type,
1092 .variable => |variable| Hash.hash(seed, asBytes(&variable.decl)),
1093
1094 .opaque_type,
11171095 .enum_type,
1118 .variable,
11191096 .union_type,
11201097 .struct_type,
1121 => |x| Hash.hash(seed, asBytes(&x.decl)),
1098 => |namespace_type| {
1099 var hasher = Hash.init(seed);
1100 std.hash.autoHash(&hasher, std.meta.activeTag(namespace_type));
1101 switch (namespace_type) {
1102 .declared => |declared| {
1103 std.hash.autoHash(&hasher, declared.zir_index);
1104 const captures = switch (declared.captures) {
1105 .owned => |cvs| cvs.get(ip),
1106 .external => |cvs| cvs,
1107 };
1108 for (captures) |cv| {
1109 std.hash.autoHash(&hasher, cv);
1110 }
1111 },
1112 .generated_tag => |generated_tag| {
1113 std.hash.autoHash(&hasher, generated_tag.union_type);
1114 },
1115 .reified => |reified| {
1116 std.hash.autoHash(&hasher, reified.zir_index);
1117 std.hash.autoHash(&hasher, reified.type_hash);
1118 },
1119 .empty_struct => {},
1120 }
1121 return hasher.final();
1122 },
11221123
11231124 .int => |int| {
11241125 var hasher = Hash.init(seed);
......@@ -1523,21 +1524,31 @@ pub const Key = union(enum) {
15231524 }
15241525 },
15251526
1526 .opaque_type => |a_info| {
1527 const b_info = b.opaque_type;
1528 return a_info.decl == b_info.decl;
1529 },
1530 .enum_type => |a_info| {
1531 const b_info = b.enum_type;
1532 return a_info.decl == b_info.decl;
1533 },
1534 .union_type => |a_info| {
1535 const b_info = b.union_type;
1536 return a_info.decl == b_info.decl;
1537 },
1538 .struct_type => |a_info| {
1539 const b_info = b.struct_type;
1540 return a_info.decl == b_info.decl;
1527 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {
1528 const b_info = @field(b, @tagName(a_tag_ct));
1529 if (std.meta.activeTag(a_info) != b_info) return false;
1530 switch (a_info) {
1531 .declared => |a_d| {
1532 const b_d = b_info.declared;
1533 if (a_d.zir_index != b_d.zir_index) return false;
1534 const a_captures = switch (a_d.captures) {
1535 .owned => |s| s.get(ip),
1536 .external => |cvs| cvs,
1537 };
1538 const b_captures = switch (b_d.captures) {
1539 .owned => |s| s.get(ip),
1540 .external => |cvs| cvs,
1541 };
1542 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
1543 },
1544 .generated_tag => |a_gt| return a_gt.union_type == b_info.generated_tag.union_type,
1545 .reified => |a_r| {
1546 const b_r = b_info.reified;
1547 return a_r.zir_index == b_r.zir_index and
1548 a_r.type_hash == b_r.type_hash;
1549 },
1550 .empty_struct => return true,
1551 }
15411552 },
15421553 .aggregate => |a_info| {
15431554 const b_info = b.aggregate;
......@@ -1685,7 +1696,7 @@ pub const LoadedUnionType = struct {
16851696 /// The Decl that corresponds to the union itself.
16861697 decl: DeclIndex,
16871698 /// Represents the declarations inside this union.
1688 namespace: NamespaceIndex,
1699 namespace: OptionalNamespaceIndex,
16891700 /// The enum tag type.
16901701 enum_tag_ty: Index,
16911702 /// List of field types in declaration order.
......@@ -1695,8 +1706,8 @@ pub const LoadedUnionType = struct {
16951706 /// `none` means the ABI alignment of the type.
16961707 /// If this slice has length 0 it means all elements are `none`.
16971708 field_aligns: Alignment.Slice,
1698 /// Index of the union_decl ZIR instruction.
1699 zir_index: TrackedInst.Index.Optional,
1709 /// Index of the union_decl or reify ZIR instruction.
1710 zir_index: TrackedInst.Index,
17001711 captures: CaptureValue.Slice,
17011712
17021713 pub const RuntimeTag = enum(u2) {
......@@ -1845,6 +1856,9 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
18451856 .len = captures_len,
18461857 };
18471858 extra_index += captures_len;
1859 if (type_union.data.flags.is_reified) {
1860 extra_index += 2; // PackedU64
1861 }
18481862
18491863 const field_types: Index.Slice = .{
18501864 .start = extra_index,
......@@ -1880,7 +1894,8 @@ pub const LoadedStructType = struct {
18801894 decl: OptionalDeclIndex,
18811895 /// `none` when the struct has no declarations.
18821896 namespace: OptionalNamespaceIndex,
1883 /// Index of the `struct_decl` ZIR instruction.
1897 /// Index of the `struct_decl` or `reify` ZIR instruction.
1898 /// Only `none` when the struct is `@TypeOf(.{})`.
18841899 zir_index: TrackedInst.Index.Optional,
18851900 layout: std.builtin.Type.ContainerLayout,
18861901 field_names: NullTerminatedString.Slice,
......@@ -2239,6 +2254,9 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
22392254 .len = captures_len,
22402255 };
22412256 extra_index += captures_len;
2257 if (extra.data.flags.is_reified) {
2258 extra_index += 2; // PackedU64
2259 }
22422260 const field_types: Index.Slice = .{
22432261 .start = extra_index,
22442262 .len = fields_len,
......@@ -2286,7 +2304,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
22862304 .extra_index = item.data,
22872305 .decl = extra.data.decl.toOptional(),
22882306 .namespace = namespace,
2289 .zir_index = extra.data.zir_index,
2307 .zir_index = extra.data.zir_index.toOptional(),
22902308 .layout = if (extra.data.flags.is_extern) .Extern else .Auto,
22912309 .field_names = names,
22922310 .field_types = field_types,
......@@ -2314,6 +2332,9 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
23142332 .len = captures_len,
23152333 };
23162334 extra_index += captures_len;
2335 if (extra.data.flags.is_reified) {
2336 extra_index += 2; // PackedU64
2337 }
23172338 const field_types: Index.Slice = .{
23182339 .start = extra_index,
23192340 .len = fields_len,
......@@ -2336,7 +2357,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
23362357 .extra_index = item.data,
23372358 .decl = extra.data.decl.toOptional(),
23382359 .namespace = extra.data.namespace,
2339 .zir_index = extra.data.zir_index,
2360 .zir_index = extra.data.zir_index.toOptional(),
23402361 .layout = .Packed,
23412362 .field_names = field_names,
23422363 .field_types = field_types,
......@@ -2372,6 +2393,7 @@ const LoadedEnumType = struct {
23722393 names_map: MapIndex,
23732394 /// This is guaranteed to not be `.none` if explicit values are provided.
23742395 values_map: OptionalMapIndex,
2396 /// This is `none` only if this is a generated tag type.
23752397 zir_index: TrackedInst.Index.Optional,
23762398 captures: CaptureValue.Slice,
23772399
......@@ -2425,15 +2447,23 @@ const LoadedEnumType = struct {
24252447
24262448pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
24272449 const item = ip.items.get(@intFromEnum(index));
2428 switch (item.tag) {
2450 const tag_mode: LoadedEnumType.TagMode = switch (item.tag) {
24292451 .type_enum_auto => {
24302452 const extra = ip.extraDataTrail(EnumAuto, item.data);
2453 var extra_index: u32 = @intCast(extra.end);
2454 if (extra.data.zir_index == .none) {
2455 extra_index += 1; // owner_union
2456 }
2457 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
2458 extra_index += 2; // type_hash: PackedU64
2459 break :c 0;
2460 } else extra.data.captures_len;
24312461 return .{
24322462 .decl = extra.data.decl,
24332463 .namespace = extra.data.namespace,
24342464 .tag_ty = extra.data.int_tag_type,
24352465 .names = .{
2436 .start = @intCast(extra.end + extra.data.captures_len),
2466 .start = extra_index + captures_len,
24372467 .len = extra.data.fields_len,
24382468 },
24392469 .values = .{ .start = 0, .len = 0 },
......@@ -2442,41 +2472,45 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
24422472 .values_map = .none,
24432473 .zir_index = extra.data.zir_index,
24442474 .captures = .{
2445 .start = @intCast(extra.end),
2446 .len = extra.data.captures_len,
2447 },
2448 };
2449 },
2450 .type_enum_explicit, .type_enum_nonexhaustive => {
2451 const extra = ip.extraDataTrail(EnumExplicit, item.data);
2452 return .{
2453 .decl = extra.data.decl,
2454 .namespace = extra.data.namespace,
2455 .tag_ty = extra.data.int_tag_type,
2456 .names = .{
2457 .start = @intCast(extra.end + extra.data.captures_len),
2458 .len = extra.data.fields_len,
2459 },
2460 .values = .{
2461 .start = @intCast(extra.end + extra.data.captures_len + extra.data.fields_len),
2462 .len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
2463 },
2464 .tag_mode = switch (item.tag) {
2465 .type_enum_explicit => .explicit,
2466 .type_enum_nonexhaustive => .nonexhaustive,
2467 else => unreachable,
2468 },
2469 .names_map = extra.data.names_map,
2470 .values_map = extra.data.values_map,
2471 .zir_index = extra.data.zir_index,
2472 .captures = .{
2473 .start = @intCast(extra.end),
2474 .len = extra.data.captures_len,
2475 .start = extra_index,
2476 .len = captures_len,
24752477 },
24762478 };
24772479 },
2480 .type_enum_explicit => .explicit,
2481 .type_enum_nonexhaustive => .nonexhaustive,
24782482 else => unreachable,
2479 }
2483 };
2484 const extra = ip.extraDataTrail(EnumExplicit, item.data);
2485 var extra_index: u32 = @intCast(extra.end);
2486 if (extra.data.zir_index == .none) {
2487 extra_index += 1; // owner_union
2488 }
2489 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
2490 extra_index += 2; // type_hash: PackedU64
2491 break :c 0;
2492 } else extra.data.captures_len;
2493 return .{
2494 .decl = extra.data.decl,
2495 .namespace = extra.data.namespace,
2496 .tag_ty = extra.data.int_tag_type,
2497 .names = .{
2498 .start = extra_index + captures_len,
2499 .len = extra.data.fields_len,
2500 },
2501 .values = .{
2502 .start = extra_index + captures_len + extra.data.fields_len,
2503 .len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
2504 },
2505 .tag_mode = tag_mode,
2506 .names_map = extra.data.names_map,
2507 .values_map = extra.data.values_map,
2508 .zir_index = extra.data.zir_index,
2509 .captures = .{
2510 .start = extra_index,
2511 .len = captures_len,
2512 },
2513 };
24802514}
24812515
24822516/// Note that this type doubles as the payload for `Tag.type_opaque`.
......@@ -2484,9 +2518,9 @@ pub const LoadedOpaqueType = struct {
24842518 /// The opaque's owner Decl.
24852519 decl: DeclIndex,
24862520 /// Contains the declarations inside this opaque.
2487 namespace: NamespaceIndex,
2488 /// The index of the `opaque_decl` instruction.
2489 zir_index: TrackedInst.Index.Optional,
2521 namespace: OptionalNamespaceIndex,
2522 /// Index of the `opaque_decl` or `reify` instruction.
2523 zir_index: TrackedInst.Index,
24902524 captures: CaptureValue.Slice,
24912525};
24922526
......@@ -2494,13 +2528,17 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
24942528 assert(ip.items.items(.tag)[@intFromEnum(index)] == .type_opaque);
24952529 const extra_index = ip.items.items(.data)[@intFromEnum(index)];
24962530 const extra = ip.extraDataTrail(Tag.TypeOpaque, extra_index);
2531 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32))
2532 0
2533 else
2534 extra.data.captures_len;
24972535 return .{
24982536 .decl = extra.data.decl,
24992537 .namespace = extra.data.namespace,
25002538 .zir_index = extra.data.zir_index,
25012539 .captures = .{
25022540 .start = extra.end,
2503 .len = extra.data.captures_len,
2541 .len = captures_len,
25042542 },
25052543 };
25062544}
......@@ -2693,6 +2731,7 @@ pub const Index = enum(u32) {
26932731 },
26942732 };
26952733
2734 removed: void,
26962735 type_int_signed: struct { data: u32 },
26972736 type_int_unsigned: struct { data: u32 },
26982737 type_array_big: struct { data: *Array },
......@@ -3100,6 +3139,12 @@ comptime {
31003139}
31013140
31023141pub const Tag = enum(u8) {
3142 /// This special tag represents a value which was removed from this pool via
3143 /// `InternPool.remove`. The item remains allocated to preserve indices, but
3144 /// lookups will consider it not equal to any other item, and all queries
3145 /// assert not this tag. `data` is unused.
3146 removed,
3147
31033148 /// An integer type.
31043149 /// data is number of bits
31053150 type_int_signed,
......@@ -3367,6 +3412,7 @@ pub const Tag = enum(u8) {
33673412
33683413 fn Payload(comptime tag: Tag) type {
33693414 return switch (tag) {
3415 .removed => unreachable,
33703416 .type_int_signed => unreachable,
33713417 .type_int_unsigned => unreachable,
33723418 .type_array_big => Array,
......@@ -3544,8 +3590,9 @@ pub const Tag = enum(u8) {
35443590 /// Trailing:
35453591 /// 0. captures_len: u32 // if `any_captures`
35463592 /// 1. capture: CaptureValue // for each `captures_len`
3547 /// 2. field type: Index for each field; declaration order
3548 /// 3. field align: Alignment for each field; declaration order
3593 /// 2. type_hash: PackedU64 // if `is_reified`
3594 /// 3. field type: Index for each field; declaration order
3595 /// 4. field align: Alignment for each field; declaration order
35493596 pub const TypeUnion = struct {
35503597 flags: Flags,
35513598 /// This could be provided through the tag type, but it is more convenient
......@@ -3557,10 +3604,10 @@ pub const Tag = enum(u8) {
35573604 /// Only valid after .have_layout
35583605 padding: u32,
35593606 decl: DeclIndex,
3560 namespace: NamespaceIndex,
3607 namespace: OptionalNamespaceIndex,
35613608 /// The enum that provides the list of field names and values.
35623609 tag_ty: Index,
3563 zir_index: TrackedInst.Index.Optional,
3610 zir_index: TrackedInst.Index,
35643611
35653612 pub const Flags = packed struct(u32) {
35663613 any_captures: bool,
......@@ -3573,19 +3620,21 @@ pub const Tag = enum(u8) {
35733620 assumed_runtime_bits: bool,
35743621 assumed_pointer_aligned: bool,
35753622 alignment: Alignment,
3576 _: u13 = 0,
3623 is_reified: bool,
3624 _: u12 = 0,
35773625 };
35783626 };
35793627
35803628 /// Trailing:
35813629 /// 0. captures_len: u32 // if `any_captures`
35823630 /// 1. capture: CaptureValue // for each `captures_len`
3583 /// 2. type: Index for each fields_len
3584 /// 3. name: NullTerminatedString for each fields_len
3585 /// 4. init: Index for each fields_len // if tag is type_struct_packed_inits
3631 /// 2. type_hash: PackedU64 // if `is_reified`
3632 /// 3. type: Index for each fields_len
3633 /// 4. name: NullTerminatedString for each fields_len
3634 /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
35863635 pub const TypeStructPacked = struct {
35873636 decl: DeclIndex,
3588 zir_index: TrackedInst.Index.Optional,
3637 zir_index: TrackedInst.Index,
35893638 fields_len: u32,
35903639 namespace: OptionalNamespaceIndex,
35913640 backing_int_ty: Index,
......@@ -3597,7 +3646,8 @@ pub const Tag = enum(u8) {
35973646 /// Dependency loop detection when resolving field inits.
35983647 field_inits_wip: bool,
35993648 inits_resolved: bool,
3600 _: u29 = 0,
3649 is_reified: bool,
3650 _: u28 = 0,
36013651 };
36023652 };
36033653
......@@ -3618,24 +3668,25 @@ pub const Tag = enum(u8) {
36183668 /// Trailing:
36193669 /// 0. captures_len: u32 // if `any_captures`
36203670 /// 1. capture: CaptureValue // for each `captures_len`
3621 /// 2. type: Index for each field in declared order
3622 /// 3. if not is_tuple:
3671 /// 2. type_hash: PackedU64 // if `is_reified`
3672 /// 3. type: Index for each field in declared order
3673 /// 4. if not is_tuple:
36233674 /// names_map: MapIndex,
36243675 /// name: NullTerminatedString // for each field in declared order
3625 /// 4. if any_default_inits:
3676 /// 5. if any_default_inits:
36263677 /// init: Index // for each field in declared order
3627 /// 5. if has_namespace:
3678 /// 6. if has_namespace:
36283679 /// namespace: NamespaceIndex
3629 /// 6. if any_aligned_fields:
3680 /// 7. if any_aligned_fields:
36303681 /// align: Alignment // for each field in declared order
3631 /// 7. if any_comptime_fields:
3682 /// 8. if any_comptime_fields:
36323683 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
3633 /// 8. if not is_extern:
3684 /// 9. if not is_extern:
36343685 /// field_index: RuntimeOrder // for each field in runtime order
3635 /// 9. field_offset: u32 // for each field in declared order, undef until layout_resolved
3686 /// 10. field_offset: u32 // for each field in declared order, undef until layout_resolved
36363687 pub const TypeStruct = struct {
36373688 decl: DeclIndex,
3638 zir_index: TrackedInst.Index.Optional,
3689 zir_index: TrackedInst.Index,
36393690 fields_len: u32,
36403691 flags: Flags,
36413692 size: u32,
......@@ -3670,8 +3721,8 @@ pub const Tag = enum(u8) {
36703721 // The types and all its fields have had their layout resolved. Even through pointer,
36713722 // which `layout_resolved` does not ensure.
36723723 fully_resolved: bool,
3673
3674 _: u7 = 0,
3724 is_reified: bool,
3725 _: u6 = 0,
36753726 };
36763727 };
36773728
......@@ -3681,9 +3732,10 @@ pub const Tag = enum(u8) {
36813732 /// The opaque's owner Decl.
36823733 decl: DeclIndex,
36833734 /// Contains the declarations inside this opaque.
3684 namespace: NamespaceIndex,
3735 namespace: OptionalNamespaceIndex,
36853736 /// The index of the `opaque_decl` instruction.
3686 zir_index: TrackedInst.Index.Optional,
3737 zir_index: TrackedInst.Index,
3738 /// `std.math.maxInt(u32)` indicates this type is reified.
36873739 captures_len: u32,
36883740 };
36893741};
......@@ -3992,12 +4044,15 @@ pub const Array = struct {
39924044};
39934045
39944046/// Trailing:
3995/// 0. capture: CaptureValue // for each `captures_len`
3996/// 1. field name: NullTerminatedString for each fields_len; declaration order
3997/// 2. tag value: Index for each fields_len; declaration order
4047/// 0. owner_union: Index // if `zir_index == .none`
4048/// 1. capture: CaptureValue // for each `captures_len`
4049/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
4050/// 3. field name: NullTerminatedString for each fields_len; declaration order
4051/// 4. tag value: Index for each fields_len; declaration order
39984052pub const EnumExplicit = struct {
39994053 /// The Decl that corresponds to the enum itself.
40004054 decl: DeclIndex,
4055 /// `std.math.maxInt(u32)` indicates this type is reified.
40014056 captures_len: u32,
40024057 /// This may be `none` if there are no declarations.
40034058 namespace: OptionalNamespaceIndex,
......@@ -4011,15 +4066,20 @@ pub const EnumExplicit = struct {
40114066 /// If this is `none`, it means the trailing tag values are absent because
40124067 /// they are auto-numbered.
40134068 values_map: OptionalMapIndex,
4069 /// `none` means this is a generated tag type.
4070 /// There will be a trailing union type for which this is a tag.
40144071 zir_index: TrackedInst.Index.Optional,
40154072};
40164073
40174074/// Trailing:
4018/// 0. capture: CaptureValue // for each `captures_len`
4019/// 1. field name: NullTerminatedString for each fields_len; declaration order
4075/// 0. owner_union: Index // if `zir_index == .none`
4076/// 1. capture: CaptureValue // for each `captures_len`
4077/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
4078/// 3. field name: NullTerminatedString for each fields_len; declaration order
40204079pub const EnumAuto = struct {
40214080 /// The Decl that corresponds to the enum itself.
40224081 decl: DeclIndex,
4082 /// `std.math.maxInt(u32)` indicates this type is reified.
40234083 captures_len: u32,
40244084 /// This may be `none` if there are no declarations.
40254085 namespace: OptionalNamespaceIndex,
......@@ -4029,6 +4089,8 @@ pub const EnumAuto = struct {
40294089 fields_len: u32,
40304090 /// Maps field names to declaration index.
40314091 names_map: MapIndex,
4092 /// `none` means this is a generated tag type.
4093 /// There will be a trailing union type for which this is a tag.
40324094 zir_index: TrackedInst.Index.Optional,
40334095};
40344096
......@@ -4269,6 +4331,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
42694331 const item = ip.items.get(@intFromEnum(index));
42704332 const data = item.data;
42714333 return switch (item.tag) {
4334 .removed => unreachable,
42724335 .type_int_signed => .{
42734336 .int_type = .{
42744337 .signedness = .signed,
......@@ -4330,31 +4393,123 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
43304393 .inferred_error_set_type = @enumFromInt(data),
43314394 },
43324395
4333 .type_opaque => .{ .opaque_type = .{
4334 .decl = ip.extraData(Tag.TypeOpaque, data).decl,
4396 .type_opaque => .{ .opaque_type = ns: {
4397 const extra = ip.extraDataTrail(Tag.TypeOpaque, data);
4398 if (extra.data.captures_len == std.math.maxInt(u32)) {
4399 break :ns .{ .reified = .{
4400 .zir_index = extra.data.zir_index,
4401 .type_hash = 0,
4402 } };
4403 }
4404 break :ns .{ .declared = .{
4405 .zir_index = extra.data.zir_index,
4406 .captures = .{ .owned = .{
4407 .start = extra.end,
4408 .len = extra.data.captures_len,
4409 } },
4410 } };
43354411 } },
43364412
4337 .type_struct => .{ .struct_type = if (data == 0) .{
4338 .decl = .none,
4339 } else .{
4340 .decl = ip.extraData(Tag.TypeStruct, data).decl.toOptional(),
4413 .type_struct => .{ .struct_type = ns: {
4414 if (data == 0) break :ns .empty_struct;
4415 const extra = ip.extraDataTrail(Tag.TypeStruct, data);
4416 if (extra.data.flags.is_reified) {
4417 assert(!extra.data.flags.any_captures);
4418 break :ns .{ .reified = .{
4419 .zir_index = extra.data.zir_index,
4420 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4421 } };
4422 }
4423 break :ns .{ .declared = .{
4424 .zir_index = extra.data.zir_index,
4425 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4426 .start = extra.end + 1,
4427 .len = ip.extra.items[extra.end],
4428 } else .{ .start = 0, .len = 0 } },
4429 } };
43414430 } },
43424431
4343 .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = .{
4344 .decl = ip.extraData(Tag.TypeStructPacked, data).decl.toOptional(),
4432 .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = ns: {
4433 const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
4434 if (extra.data.flags.is_reified) {
4435 assert(!extra.data.flags.any_captures);
4436 break :ns .{ .reified = .{
4437 .zir_index = extra.data.zir_index,
4438 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4439 } };
4440 }
4441 break :ns .{ .declared = .{
4442 .zir_index = extra.data.zir_index,
4443 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4444 .start = extra.end + 1,
4445 .len = ip.extra.items[extra.end],
4446 } else .{ .start = 0, .len = 0 } },
4447 } };
43454448 } },
43464449
43474450 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
43484451 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },
4349 .type_union => .{ .union_type = .{
4350 .decl = ip.extraData(Tag.TypeUnion, data).decl,
4452 .type_union => .{ .union_type = ns: {
4453 const extra = ip.extraDataTrail(Tag.TypeUnion, data);
4454 if (extra.data.flags.is_reified) {
4455 assert(!extra.data.flags.any_captures);
4456 break :ns .{ .reified = .{
4457 .zir_index = extra.data.zir_index,
4458 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4459 } };
4460 }
4461 break :ns .{ .declared = .{
4462 .zir_index = extra.data.zir_index,
4463 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4464 .start = extra.end + 1,
4465 .len = ip.extra.items[extra.end],
4466 } else .{ .start = 0, .len = 0 } },
4467 } };
43514468 } },
43524469
4353 .type_enum_auto => .{ .enum_type = .{
4354 .decl = ip.extraData(EnumAuto, data).decl,
4470 .type_enum_auto => .{ .enum_type = ns: {
4471 const extra = ip.extraDataTrail(EnumAuto, data);
4472 const zir_index = extra.data.zir_index.unwrap() orelse {
4473 assert(extra.data.captures_len == 0);
4474 break :ns .{ .generated_tag = .{
4475 .union_type = @enumFromInt(ip.extra.items[extra.end]),
4476 } };
4477 };
4478 if (extra.data.captures_len == std.math.maxInt(u32)) {
4479 break :ns .{ .reified = .{
4480 .zir_index = zir_index,
4481 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4482 } };
4483 }
4484 break :ns .{ .declared = .{
4485 .zir_index = zir_index,
4486 .captures = .{ .owned = .{
4487 .start = extra.end,
4488 .len = extra.data.captures_len,
4489 } },
4490 } };
43554491 } },
4356 .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = .{
4357 .decl = ip.extraData(EnumExplicit, data).decl,
4492 .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
4493 const extra = ip.extraDataTrail(EnumExplicit, data);
4494 const zir_index = extra.data.zir_index.unwrap() orelse {
4495 assert(extra.data.captures_len == 0);
4496 break :ns .{ .generated_tag = .{
4497 .union_type = @enumFromInt(ip.extra.items[extra.end]),
4498 } };
4499 };
4500 if (extra.data.captures_len == std.math.maxInt(u32)) {
4501 break :ns .{ .reified = .{
4502 .zir_index = zir_index,
4503 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4504 } };
4505 }
4506 break :ns .{ .declared = .{
4507 .zir_index = zir_index,
4508 .captures = .{ .owned = .{
4509 .start = extra.end,
4510 .len = extra.data.captures_len,
4511 } },
4512 } };
43584513 } },
43594514 .type_function => .{ .func_type = ip.extraFuncType(data) },
43604515
......@@ -4979,7 +5134,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
49795134 .union_type => unreachable, // use getUnionType() instead
49805135 .opaque_type => unreachable, // use getOpaqueType() instead
49815136
4982 .enum_type => unreachable, // use getEnum() or getIncompleteEnum() instead
5137 .enum_type => unreachable, // use getEnumType() instead
49835138 .func_type => unreachable, // use getFuncType() instead
49845139 .extern_func => unreachable, // use getExternFunc() instead
49855140 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead
......@@ -5652,9 +5807,7 @@ pub const UnionTypeInit = struct {
56525807 assumed_pointer_aligned: bool,
56535808 alignment: Alignment,
56545809 },
5655 decl: DeclIndex,
5656 namespace: NamespaceIndex,
5657 zir_index: TrackedInst.Index.Optional,
5810 has_namespace: bool,
56585811 fields_len: u32,
56595812 enum_tag_ty: Index,
56605813 /// May have length 0 which leaves the values unset until later.
......@@ -5663,23 +5816,50 @@ pub const UnionTypeInit = struct {
56635816 /// The logic for `any_aligned_fields` is asserted to have been done before
56645817 /// calling this function.
56655818 field_aligns: []const Alignment,
5666 captures: []const CaptureValue,
5819 key: union(enum) {
5820 declared: struct {
5821 zir_index: TrackedInst.Index,
5822 captures: []const CaptureValue,
5823 },
5824 reified: struct {
5825 zir_index: TrackedInst.Index,
5826 type_hash: u64,
5827 },
5828 },
56675829};
56685830
5669pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!Index {
5670 const prev_extra_len = ip.extra.items.len;
5831pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!WipNamespaceType.Result {
5832 const adapter: KeyAdapter = .{ .intern_pool = ip };
5833 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .union_type = switch (ini.key) {
5834 .declared => |d| .{ .declared = .{
5835 .zir_index = d.zir_index,
5836 .captures = .{ .external = d.captures },
5837 } },
5838 .reified => |r| .{ .reified = .{
5839 .zir_index = r.zir_index,
5840 .type_hash = r.type_hash,
5841 } },
5842 } }, adapter);
5843 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
5844 errdefer _ = ip.map.pop();
5845
56715846 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
56725847 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
56735848 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeUnion).Struct.fields.len +
5674 @intFromBool(ini.captures.len != 0) + // captures_len
5675 ini.captures.len + // captures
5849 // TODO: fmt bug
5850 // zig fmt: off
5851 switch (ini.key) {
5852 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
5853 .reified => 2, // type_hash: PackedU64
5854 } +
5855 // zig fmt: on
56765856 ini.fields_len + // field types
56775857 align_elements_len);
56785858 try ip.items.ensureUnusedCapacity(gpa, 1);
56795859
5680 const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
5860 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
56815861 .flags = .{
5682 .any_captures = ini.captures.len != 0,
5862 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
56835863 .runtime_tag = ini.flags.runtime_tag,
56845864 .any_aligned_fields = ini.flags.any_aligned_fields,
56855865 .layout = ini.flags.layout,
......@@ -5688,19 +5868,30 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
56885868 .assumed_runtime_bits = ini.flags.assumed_runtime_bits,
56895869 .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,
56905870 .alignment = ini.flags.alignment,
5871 .is_reified = ini.key == .reified,
56915872 },
56925873 .fields_len = ini.fields_len,
56935874 .size = std.math.maxInt(u32),
56945875 .padding = std.math.maxInt(u32),
5695 .decl = ini.decl,
5696 .namespace = ini.namespace,
5876 .decl = undefined, // set by `finish`
5877 .namespace = .none, // set by `finish`
56975878 .tag_ty = ini.enum_tag_ty,
5698 .zir_index = ini.zir_index,
5879 .zir_index = switch (ini.key) {
5880 inline else => |x| x.zir_index,
5881 },
5882 });
5883
5884 ip.items.appendAssumeCapacity(.{
5885 .tag = .type_union,
5886 .data = extra_index,
56995887 });
57005888
5701 if (ini.captures.len != 0) {
5702 ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
5703 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
5889 switch (ini.key) {
5890 .declared => |d| if (d.captures.len != 0) {
5891 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
5892 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
5893 },
5894 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
57045895 }
57055896
57065897 // field types
......@@ -5725,27 +5916,41 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
57255916 assert(ini.field_aligns.len == 0);
57265917 }
57275918
5728 const adapter: KeyAdapter = .{ .intern_pool = ip };
5729 const gop = try ip.map.getOrPutAdapted(gpa, Key{
5730 .union_type = .{ .decl = ini.decl },
5731 }, adapter);
5732 if (gop.found_existing) {
5733 ip.extra.items.len = prev_extra_len;
5734 return @enumFromInt(gop.index);
5919 return .{ .wip = .{
5920 .index = @enumFromInt(ip.items.len - 1),
5921 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "decl").?,
5922 .namespace_extra_index = if (ini.has_namespace)
5923 extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?
5924 else
5925 null,
5926 } };
5927}
5928
5929pub const WipNamespaceType = struct {
5930 index: Index,
5931 decl_extra_index: u32,
5932 namespace_extra_index: ?u32,
5933 pub fn finish(wip: WipNamespaceType, ip: *InternPool, decl: DeclIndex, namespace: OptionalNamespaceIndex) Index {
5934 ip.extra.items[wip.decl_extra_index] = @intFromEnum(decl);
5935 if (wip.namespace_extra_index) |i| {
5936 ip.extra.items[i] = @intFromEnum(namespace.unwrap().?);
5937 } else {
5938 assert(namespace == .none);
5939 }
5940 return wip.index;
5941 }
5942 pub fn cancel(wip: WipNamespaceType, ip: *InternPool) void {
5943 ip.remove(wip.index);
57355944 }
57365945
5737 ip.items.appendAssumeCapacity(.{
5738 .tag = .type_union,
5739 .data = union_type_extra_index,
5740 });
5741 return @enumFromInt(ip.items.len - 1);
5742}
5946 pub const Result = union(enum) {
5947 wip: WipNamespaceType,
5948 existing: Index,
5949 };
5950};
57435951
57445952pub const StructTypeInit = struct {
5745 decl: DeclIndex,
5746 namespace: OptionalNamespaceIndex,
57475953 layout: std.builtin.Type.ContainerLayout,
5748 zir_index: TrackedInst.Index.Optional,
57495954 fields_len: u32,
57505955 known_non_opv: bool,
57515956 requires_comptime: RequiresComptime,
......@@ -5754,61 +5959,101 @@ pub const StructTypeInit = struct {
57545959 any_default_inits: bool,
57555960 inits_resolved: bool,
57565961 any_aligned_fields: bool,
5757 captures: []const CaptureValue,
5962 has_namespace: bool,
5963 key: union(enum) {
5964 declared: struct {
5965 zir_index: TrackedInst.Index,
5966 captures: []const CaptureValue,
5967 },
5968 reified: struct {
5969 zir_index: TrackedInst.Index,
5970 type_hash: u64,
5971 },
5972 },
57585973};
57595974
57605975pub fn getStructType(
57615976 ip: *InternPool,
57625977 gpa: Allocator,
57635978 ini: StructTypeInit,
5764) Allocator.Error!Index {
5979) Allocator.Error!WipNamespaceType.Result {
57655980 const adapter: KeyAdapter = .{ .intern_pool = ip };
5766 const key: Key = .{
5767 .struct_type = .{ .decl = ini.decl.toOptional() },
5768 };
5981 const key: Key = .{ .struct_type = switch (ini.key) {
5982 .declared => |d| .{ .declared = .{
5983 .zir_index = d.zir_index,
5984 .captures = .{ .external = d.captures },
5985 } },
5986 .reified => |r| .{ .reified = .{
5987 .zir_index = r.zir_index,
5988 .type_hash = r.type_hash,
5989 } },
5990 } };
57695991 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);
5770 if (gop.found_existing) return @enumFromInt(gop.index);
5992 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
57715993 errdefer _ = ip.map.pop();
57725994
57735995 const names_map = try ip.addMap(gpa, ini.fields_len);
57745996 errdefer _ = ip.maps.pop();
57755997
5998 const zir_index = switch (ini.key) {
5999 inline else => |x| x.zir_index,
6000 };
6001
57766002 const is_extern = switch (ini.layout) {
57776003 .Auto => false,
57786004 .Extern => true,
57796005 .Packed => {
57806006 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
5781 @intFromBool(ini.captures.len != 0) + // captures_len
5782 ini.captures.len + // captures
6007 // TODO: fmt bug
6008 // zig fmt: off
6009 switch (ini.key) {
6010 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
6011 .reified => 2, // type_hash: PackedU64
6012 } +
6013 // zig fmt: on
57836014 ini.fields_len + // types
57846015 ini.fields_len + // names
57856016 ini.fields_len); // inits
6017 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{
6018 .decl = undefined, // set by `finish`
6019 .zir_index = zir_index,
6020 .fields_len = ini.fields_len,
6021 .namespace = .none,
6022 .backing_int_ty = .none,
6023 .names_map = names_map,
6024 .flags = .{
6025 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
6026 .field_inits_wip = false,
6027 .inits_resolved = ini.inits_resolved,
6028 .is_reified = ini.key == .reified,
6029 },
6030 });
57866031 try ip.items.append(gpa, .{
57876032 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
5788 .data = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{
5789 .decl = ini.decl,
5790 .zir_index = ini.zir_index,
5791 .fields_len = ini.fields_len,
5792 .namespace = ini.namespace,
5793 .backing_int_ty = .none,
5794 .names_map = names_map,
5795 .flags = .{
5796 .any_captures = ini.captures.len != 0,
5797 .field_inits_wip = false,
5798 .inits_resolved = ini.inits_resolved,
5799 },
5800 }),
6033 .data = extra_index,
58016034 });
5802 if (ini.captures.len != 0) {
5803 ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
5804 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
6035 switch (ini.key) {
6036 .declared => |d| if (d.captures.len != 0) {
6037 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
6038 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
6039 },
6040 .reified => |r| {
6041 _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash));
6042 },
58056043 }
58066044 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
58076045 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
58086046 if (ini.any_default_inits) {
58096047 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
58106048 }
5811 return @enumFromInt(ip.items.len - 1);
6049 return .{ .wip = .{
6050 .index = @enumFromInt(ip.items.len - 1),
6051 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "decl").?,
6052 .namespace_extra_index = if (ini.has_namespace)
6053 extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?
6054 else
6055 null,
6056 } };
58126057 },
58136058 };
58146059
......@@ -5817,44 +6062,56 @@ pub fn getStructType(
58176062 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
58186063
58196064 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +
5820 @intFromBool(ini.captures.len != 0) + // captures_len
5821 ini.captures.len + // captures
6065 // TODO: fmt bug
6066 // zig fmt: off
6067 switch (ini.key) {
6068 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
6069 .reified => 2, // type_hash: PackedU64
6070 } +
6071 // zig fmt: on
58226072 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
58236073 align_elements_len + comptime_elements_len +
58246074 2); // names_map + namespace
6075 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeStruct{
6076 .decl = undefined, // set by `finish`
6077 .zir_index = zir_index,
6078 .fields_len = ini.fields_len,
6079 .size = std.math.maxInt(u32),
6080 .flags = .{
6081 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
6082 .is_extern = is_extern,
6083 .known_non_opv = ini.known_non_opv,
6084 .requires_comptime = ini.requires_comptime,
6085 .is_tuple = ini.is_tuple,
6086 .assumed_runtime_bits = false,
6087 .assumed_pointer_aligned = false,
6088 .has_namespace = ini.has_namespace,
6089 .any_comptime_fields = ini.any_comptime_fields,
6090 .any_default_inits = ini.any_default_inits,
6091 .any_aligned_fields = ini.any_aligned_fields,
6092 .alignment = .none,
6093 .alignment_wip = false,
6094 .field_types_wip = false,
6095 .layout_wip = false,
6096 .layout_resolved = false,
6097 .field_inits_wip = false,
6098 .inits_resolved = ini.inits_resolved,
6099 .fully_resolved = false,
6100 .is_reified = ini.key == .reified,
6101 },
6102 });
58256103 try ip.items.append(gpa, .{
58266104 .tag = .type_struct,
5827 .data = ip.addExtraAssumeCapacity(Tag.TypeStruct{
5828 .decl = ini.decl,
5829 .zir_index = ini.zir_index,
5830 .fields_len = ini.fields_len,
5831 .size = std.math.maxInt(u32),
5832 .flags = .{
5833 .any_captures = ini.captures.len != 0,
5834 .is_extern = is_extern,
5835 .known_non_opv = ini.known_non_opv,
5836 .requires_comptime = ini.requires_comptime,
5837 .is_tuple = ini.is_tuple,
5838 .assumed_runtime_bits = false,
5839 .assumed_pointer_aligned = false,
5840 .has_namespace = ini.namespace != .none,
5841 .any_comptime_fields = ini.any_comptime_fields,
5842 .any_default_inits = ini.any_default_inits,
5843 .any_aligned_fields = ini.any_aligned_fields,
5844 .alignment = .none,
5845 .alignment_wip = false,
5846 .field_types_wip = false,
5847 .layout_wip = false,
5848 .layout_resolved = false,
5849 .field_inits_wip = false,
5850 .inits_resolved = ini.inits_resolved,
5851 .fully_resolved = false,
5852 },
5853 }),
6105 .data = extra_index,
58546106 });
5855 if (ini.captures.len != 0) {
5856 ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
5857 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
6107 switch (ini.key) {
6108 .declared => |d| if (d.captures.len != 0) {
6109 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
6110 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
6111 },
6112 .reified => |r| {
6113 _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash));
6114 },
58586115 }
58596116 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
58606117 if (!ini.is_tuple) {
......@@ -5864,9 +6121,10 @@ pub fn getStructType(
58646121 if (ini.any_default_inits) {
58656122 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
58666123 }
5867 if (ini.namespace.unwrap()) |namespace| {
5868 ip.extra.appendAssumeCapacity(@intFromEnum(namespace));
5869 }
6124 const namespace_extra_index: ?u32 = if (ini.has_namespace) i: {
6125 ip.extra.appendAssumeCapacity(undefined); // set by `finish`
6126 break :i @intCast(ip.extra.items.len - 1);
6127 } else null;
58706128 if (ini.any_aligned_fields) {
58716129 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);
58726130 }
......@@ -5877,7 +6135,11 @@ pub fn getStructType(
58776135 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(LoadedStructType.RuntimeOrder.unresolved), ini.fields_len);
58786136 }
58796137 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);
5880 return @enumFromInt(ip.items.len - 1);
6138 return .{ .wip = .{
6139 .index = @enumFromInt(ip.items.len - 1),
6140 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "decl").?,
6141 .namespace_extra_index = namespace_extra_index,
6142 } };
58816143}
58826144
58836145pub const AnonStructTypeInit = struct {
......@@ -6513,282 +6775,399 @@ fn finishFuncInstance(
65136775 return func_index;
65146776}
65156777
6516/// Provides API for completing an enum type after calling `getIncompleteEnum`.
6517pub const IncompleteEnumType = struct {
6778pub const EnumTypeInit = struct {
6779 has_namespace: bool,
6780 has_values: bool,
6781 tag_mode: LoadedEnumType.TagMode,
6782 fields_len: u32,
6783 key: union(enum) {
6784 declared: struct {
6785 zir_index: TrackedInst.Index,
6786 captures: []const CaptureValue,
6787 },
6788 reified: struct {
6789 zir_index: TrackedInst.Index,
6790 type_hash: u64,
6791 },
6792 },
6793};
6794
6795pub const WipEnumType = struct {
65186796 index: Index,
65196797 tag_ty_index: u32,
6798 decl_index: u32,
6799 namespace_index: ?u32,
65206800 names_map: MapIndex,
65216801 names_start: u32,
65226802 values_map: OptionalMapIndex,
65236803 values_start: u32,
6804 expected_fields_len: if (std.debug.runtime_safety) u32 else void,
65246805
6525 pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void {
6526 assert(tag_ty == .noreturn_type or ip.isIntegerType(tag_ty));
6527 ip.extra.items[self.tag_ty_index] = @intFromEnum(tag_ty);
6528 }
6529
6530 /// Returns the already-existing field with the same name, if any.
6531 pub fn addFieldName(
6532 self: @This(),
6806 pub fn prepare(
6807 wip: WipEnumType,
65336808 ip: *InternPool,
6534 name: NullTerminatedString,
6535 ) ?u32 {
6536 return ip.addFieldName(self.names_map, self.names_start, name);
6809 decl: DeclIndex,
6810 namespace: OptionalNamespaceIndex,
6811 tag_ty: Index,
6812 ) void {
6813 assert(ip.isIntegerType(tag_ty));
6814 ip.extra.items[wip.tag_ty_index] = @intFromEnum(tag_ty);
6815 ip.extra.items[wip.decl_index] = @intFromEnum(decl);
6816 if (wip.namespace_index) |i| {
6817 ip.extra.items[i] = @intFromEnum(namespace.unwrap().?);
6818 } else {
6819 assert(namespace == .none);
6820 }
65376821 }
65386822
6539 /// Returns the already-existing field with the same value, if any.
6540 /// Make sure the type of the value has the integer tag type of the enum.
6541 pub fn addFieldValue(
6542 self: @This(),
6543 ip: *InternPool,
6544 value: Index,
6545 ) ?u32 {
6546 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));
6547 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];
6823 pub const FieldConflict = struct {
6824 kind: enum { name, value },
6825 prev_field_idx: u32,
6826 };
6827
6828 /// Returns the already-existing field with the same name or value, if any.
6829 /// If the enum is automatially numbered, `value` must be `.none`.
6830 /// Otherwise, the type of `value` must be the integer tag type of the enum.
6831 pub fn nextField(wip: WipEnumType, ip: *InternPool, name: NullTerminatedString, value: Index) ?FieldConflict {
6832 if (ip.addFieldName(wip.names_map, wip.names_start, name)) |conflict| {
6833 return .{ .kind = .name, .prev_field_idx = conflict };
6834 }
6835 if (value == .none) {
6836 assert(wip.values_map == .none);
6837 return null;
6838 }
6839 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[wip.tag_ty_index])));
6840 const map = &ip.maps.items[@intFromEnum(wip.values_map.unwrap().?)];
65486841 const field_index = map.count();
6549 const indexes = ip.extra.items[self.values_start..][0..field_index];
6842 const indexes = ip.extra.items[wip.values_start..][0..field_index];
65506843 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
65516844 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
6552 if (gop.found_existing) return @intCast(gop.index);
6553 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
6845 if (gop.found_existing) {
6846 return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) };
6847 }
6848 ip.extra.items[wip.values_start + field_index] = @intFromEnum(value);
65546849 return null;
65556850 }
6556};
65576851
6558/// This is used to create an enum type in the `InternPool`, with the ability
6559/// to update the tag type, field names, and field values later.
6560pub fn getIncompleteEnum(
6561 ip: *InternPool,
6562 gpa: Allocator,
6563 enum_type: Key.IncompleteEnumType,
6564) Allocator.Error!IncompleteEnumType {
6565 switch (enum_type.tag_mode) {
6566 .auto => return getIncompleteEnumAuto(ip, gpa, enum_type),
6567 .explicit => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_explicit),
6568 .nonexhaustive => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_nonexhaustive),
6852 pub fn finish(wip: WipEnumType, ip: *InternPool) Index {
6853 if (std.debug.runtime_safety) {
6854 const names_map = &ip.maps.items[@intFromEnum(wip.names_map)];
6855 assert(names_map.count() == wip.expected_fields_len);
6856 if (wip.values_map.unwrap()) |v| {
6857 const values_map = &ip.maps.items[@intFromEnum(v)];
6858 assert(values_map.count() == wip.expected_fields_len);
6859 }
6860 }
6861 return wip.index;
65696862 }
6570}
65716863
6572fn getIncompleteEnumAuto(
6573 ip: *InternPool,
6574 gpa: Allocator,
6575 enum_type: Key.IncompleteEnumType,
6576) Allocator.Error!IncompleteEnumType {
6577 const int_tag_type = if (enum_type.tag_ty != .none)
6578 enum_type.tag_ty
6579 else
6580 try ip.get(gpa, .{ .int_type = .{
6581 .bits = if (enum_type.fields_len == 0) 0 else std.math.log2_int_ceil(u32, enum_type.fields_len),
6582 .signedness = .unsigned,
6583 } });
6584
6585 // We must keep the map in sync with `items`. The hash and equality functions
6586 // for enum types only look at the decl field, which is present even in
6587 // an `IncompleteEnumType`.
6588 const adapter: KeyAdapter = .{ .intern_pool = ip };
6589 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
6590 assert(!gop.found_existing);
6591
6592 const names_map = try ip.addMap(gpa, enum_type.fields_len);
6593
6594 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
6595 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.captures.len + enum_type.fields_len);
6596 try ip.items.ensureUnusedCapacity(gpa, 1);
6597
6598 const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
6599 .decl = enum_type.decl,
6600 .captures_len = @intCast(enum_type.captures.len),
6601 .namespace = enum_type.namespace,
6602 .int_tag_type = int_tag_type,
6603 .names_map = names_map,
6604 .fields_len = enum_type.fields_len,
6605 .zir_index = enum_type.zir_index,
6606 });
6864 pub fn cancel(wip: WipEnumType, ip: *InternPool) void {
6865 ip.remove(wip.index);
6866 }
66076867
6608 ip.items.appendAssumeCapacity(.{
6609 .tag = .type_enum_auto,
6610 .data = extra_index,
6611 });
6612 ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.captures));
6613 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
6614 return .{
6615 .index = @enumFromInt(ip.items.len - 1),
6616 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
6617 .names_map = names_map,
6618 .names_start = extra_index + extra_fields_len,
6619 .values_map = .none,
6620 .values_start = undefined,
6868 pub const Result = union(enum) {
6869 wip: WipEnumType,
6870 existing: Index,
66216871 };
6622}
6872};
66236873
6624fn getIncompleteEnumExplicit(
6874pub fn getEnumType(
66256875 ip: *InternPool,
66266876 gpa: Allocator,
6627 enum_type: Key.IncompleteEnumType,
6628 tag: Tag,
6629) Allocator.Error!IncompleteEnumType {
6630 // We must keep the map in sync with `items`. The hash and equality functions
6631 // for enum types only look at the decl field, which is present even in
6632 // an `IncompleteEnumType`.
6877 ini: EnumTypeInit,
6878) Allocator.Error!WipEnumType.Result {
66336879 const adapter: KeyAdapter = .{ .intern_pool = ip };
6634 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
6635 assert(!gop.found_existing);
6636
6637 const names_map = try ip.addMap(gpa, enum_type.fields_len);
6638 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {
6639 const values_map = try ip.addMap(gpa, enum_type.fields_len);
6640 break :m values_map.toOptional();
6641 };
6642
6643 const reserved_len = enum_type.fields_len +
6644 if (enum_type.has_values) enum_type.fields_len else 0;
6880 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .enum_type = switch (ini.key) {
6881 .declared => |d| .{ .declared = .{
6882 .zir_index = d.zir_index,
6883 .captures = .{ .external = d.captures },
6884 } },
6885 .reified => |r| .{ .reified = .{
6886 .zir_index = r.zir_index,
6887 .type_hash = r.type_hash,
6888 } },
6889 } }, adapter);
6890 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
6891 assert(gop.index == ip.items.len);
6892 errdefer _ = ip.map.pop();
66456893
6646 const extra_fields_len: u32 = @typeInfo(EnumExplicit).Struct.fields.len;
6647 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.captures.len + reserved_len);
66486894 try ip.items.ensureUnusedCapacity(gpa, 1);
66496895
6650 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
6651 .decl = enum_type.decl,
6652 .captures_len = @intCast(enum_type.captures.len),
6653 .namespace = enum_type.namespace,
6654 .int_tag_type = enum_type.tag_ty,
6655 .fields_len = enum_type.fields_len,
6656 .names_map = names_map,
6657 .values_map = values_map,
6658 .zir_index = enum_type.zir_index,
6659 });
6896 const names_map = try ip.addMap(gpa, ini.fields_len);
6897 errdefer _ = ip.maps.pop();
66606898
6661 ip.items.appendAssumeCapacity(.{
6662 .tag = tag,
6663 .data = extra_index,
6664 });
6665 ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.captures));
6666 // This is both fields and values (if present).
6667 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
6668 return .{
6669 .index = @enumFromInt(ip.items.len - 1),
6670 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
6671 .names_map = names_map,
6672 .names_start = extra_index + extra_fields_len,
6673 .values_map = values_map,
6674 .values_start = extra_index + extra_fields_len + enum_type.fields_len,
6675 };
6899 switch (ini.tag_mode) {
6900 .auto => {
6901 assert(!ini.has_values);
6902 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6903 // TODO: fmt bug
6904 // zig fmt: off
6905 switch (ini.key) {
6906 .declared => |d| d.captures.len,
6907 .reified => 2, // type_hash: PackedU64
6908 } +
6909 // zig fmt: on
6910 ini.fields_len); // field types
6911
6912 const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
6913 .decl = undefined, // set by `prepare`
6914 .captures_len = switch (ini.key) {
6915 .declared => |d| @intCast(d.captures.len),
6916 .reified => std.math.maxInt(u32),
6917 },
6918 .namespace = .none,
6919 .int_tag_type = .none, // set by `prepare`
6920 .fields_len = ini.fields_len,
6921 .names_map = names_map,
6922 .zir_index = switch (ini.key) {
6923 inline else => |x| x.zir_index,
6924 }.toOptional(),
6925 });
6926 ip.items.appendAssumeCapacity(.{
6927 .tag = .type_enum_auto,
6928 .data = extra_index,
6929 });
6930 switch (ini.key) {
6931 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
6932 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
6933 }
6934 const names_start = ip.extra.items.len;
6935 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
6936 return .{ .wip = .{
6937 .index = @enumFromInt(gop.index),
6938 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
6939 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
6940 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
6941 .names_map = names_map,
6942 .names_start = @intCast(names_start),
6943 .values_map = .none,
6944 .values_start = undefined,
6945 .expected_fields_len = if (std.debug.runtime_safety) ini.fields_len else {},
6946 } };
6947 },
6948 .explicit, .nonexhaustive => {
6949 const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: {
6950 const values_map = try ip.addMap(gpa, ini.fields_len);
6951 break :m values_map.toOptional();
6952 };
6953 errdefer if (ini.has_values) {
6954 _ = ip.map.pop();
6955 };
6956
6957 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
6958 // TODO: fmt bug
6959 // zig fmt: off
6960 switch (ini.key) {
6961 .declared => |d| d.captures.len,
6962 .reified => 2, // type_hash: PackedU64
6963 } +
6964 // zig fmt: on
6965 ini.fields_len + // field types
6966 ini.fields_len * @intFromBool(ini.has_values)); // field values
6967
6968 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
6969 .decl = undefined, // set by `prepare`
6970 .captures_len = switch (ini.key) {
6971 .declared => |d| @intCast(d.captures.len),
6972 .reified => std.math.maxInt(u32),
6973 },
6974 .namespace = .none,
6975 .int_tag_type = .none, // set by `prepare`
6976 .fields_len = ini.fields_len,
6977 .names_map = names_map,
6978 .values_map = values_map,
6979 .zir_index = switch (ini.key) {
6980 inline else => |x| x.zir_index,
6981 }.toOptional(),
6982 });
6983 ip.items.appendAssumeCapacity(.{
6984 .tag = switch (ini.tag_mode) {
6985 .auto => unreachable,
6986 .explicit => .type_enum_explicit,
6987 .nonexhaustive => .type_enum_nonexhaustive,
6988 },
6989 .data = extra_index,
6990 });
6991 switch (ini.key) {
6992 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
6993 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
6994 }
6995 const names_start = ip.extra.items.len;
6996 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
6997 const values_start = ip.extra.items.len;
6998 if (ini.has_values) {
6999 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
7000 }
7001 return .{ .wip = .{
7002 .index = @enumFromInt(gop.index),
7003 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
7004 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
7005 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
7006 .names_map = names_map,
7007 .names_start = @intCast(names_start),
7008 .values_map = values_map,
7009 .values_start = @intCast(values_start),
7010 .expected_fields_len = if (std.debug.runtime_safety) ini.fields_len else {},
7011 } };
7012 },
7013 }
66767014}
66777015
6678pub const GetEnumInit = struct {
7016const GeneratedTagEnumTypeInit = struct {
66797017 decl: DeclIndex,
6680 namespace: OptionalNamespaceIndex,
7018 owner_union_ty: Index,
66817019 tag_ty: Index,
66827020 names: []const NullTerminatedString,
66837021 values: []const Index,
66847022 tag_mode: LoadedEnumType.TagMode,
6685 zir_index: TrackedInst.Index.Optional,
6686 captures: []const CaptureValue,
66877023};
66887024
6689pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
6690 const adapter: KeyAdapter = .{ .intern_pool = ip };
6691 const gop = try ip.map.getOrPutAdapted(gpa, Key{
6692 .enum_type = .{ .decl = ini.decl },
6693 }, adapter);
6694 if (gop.found_existing) return @enumFromInt(gop.index);
6695 errdefer _ = ip.map.pop();
7025/// Creates an enum type which was automatically-generated as the tag type of a
7026/// `union` with no explicit tag type. Since this is only called once per union
7027/// type, it asserts that no matching type yet exists.
7028pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTagEnumTypeInit) Allocator.Error!Index {
7029 assert(ip.isUnion(ini.owner_union_ty));
7030 assert(ip.isIntegerType(ini.tag_ty));
7031 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
7032
7033 try ip.map.ensureUnusedCapacity(gpa, 1);
66967034 try ip.items.ensureUnusedCapacity(gpa, 1);
66977035
6698 assert(ini.tag_ty == .noreturn_type or ip.isIntegerType(ini.tag_ty));
6699 for (ini.values) |value| assert(ip.typeOf(value) == ini.tag_ty);
7036 const names_map = try ip.addMap(gpa, ini.names.len);
7037 errdefer _ = ip.maps.pop();
7038 ip.addStringsToMap(names_map, ini.names);
7039
7040 const fields_len: u32 = @intCast(ini.names.len);
67007041
67017042 switch (ini.tag_mode) {
67027043 .auto => {
6703 const names_map = try ip.addMap(gpa, ini.names.len);
6704 addStringsToMap(ip, names_map, ini.names);
6705
6706 const fields_len: u32 = @intCast(ini.names.len);
67077044 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6708 ini.captures.len + fields_len);
7045 1 + // owner_union
7046 fields_len); // field names
67097047 ip.items.appendAssumeCapacity(.{
67107048 .tag = .type_enum_auto,
67117049 .data = ip.addExtraAssumeCapacity(EnumAuto{
67127050 .decl = ini.decl,
6713 .captures_len = @intCast(ini.captures.len),
6714 .namespace = ini.namespace,
7051 .captures_len = 0,
7052 .namespace = .none,
67157053 .int_tag_type = ini.tag_ty,
7054 .fields_len = fields_len,
67167055 .names_map = names_map,
7056 .zir_index = .none,
7057 }),
7058 });
7059 ip.extra.appendAssumeCapacity(@intFromEnum(ini.owner_union_ty));
7060 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
7061 },
7062 .explicit, .nonexhaustive => {
7063 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
7064 1 + // owner_union
7065 fields_len + // field names
7066 ini.values.len); // field values
7067
7068 const values_map: OptionalMapIndex = if (ini.values.len != 0) m: {
7069 const map = try ip.addMap(gpa, ini.values.len);
7070 addIndexesToMap(ip, map, ini.values);
7071 break :m map.toOptional();
7072 } else .none;
7073 // We don't clean up the values map on error!
7074 errdefer @compileError("error path leaks values_map");
7075
7076 ip.items.appendAssumeCapacity(.{
7077 .tag = switch (ini.tag_mode) {
7078 .explicit => .type_enum_explicit,
7079 .nonexhaustive => .type_enum_nonexhaustive,
7080 .auto => unreachable,
7081 },
7082 .data = ip.addExtraAssumeCapacity(EnumExplicit{
7083 .decl = ini.decl,
7084 .captures_len = 0,
7085 .namespace = .none,
7086 .int_tag_type = ini.tag_ty,
67177087 .fields_len = fields_len,
6718 .zir_index = ini.zir_index,
7088 .names_map = names_map,
7089 .values_map = values_map,
7090 .zir_index = .none,
67197091 }),
67207092 });
6721 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
7093 ip.extra.appendAssumeCapacity(@intFromEnum(ini.owner_union_ty));
67227094 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6723 return @enumFromInt(ip.items.len - 1);
7095 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
67247096 },
6725 .explicit => return finishGetEnum(ip, gpa, ini, .type_enum_explicit),
6726 .nonexhaustive => return finishGetEnum(ip, gpa, ini, .type_enum_nonexhaustive),
67277097 }
6728}
6729
6730fn finishGetEnum(
6731 ip: *InternPool,
6732 gpa: Allocator,
6733 ini: GetEnumInit,
6734 tag: Tag,
6735) Allocator.Error!Index {
6736 const names_map = try ip.addMap(gpa, ini.names.len);
6737 addStringsToMap(ip, names_map, ini.names);
7098 // Same as above
7099 errdefer @compileError("error path leaks values_map and extra data");
67387100
6739 const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {
6740 const values_map = try ip.addMap(gpa, ini.values.len);
6741 addIndexesToMap(ip, values_map, ini.values);
6742 break :m values_map.toOptional();
6743 };
6744 const fields_len: u32 = @intCast(ini.names.len);
6745 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
6746 ini.captures.len + fields_len);
6747 ip.items.appendAssumeCapacity(.{
6748 .tag = tag,
6749 .data = ip.addExtraAssumeCapacity(EnumExplicit{
6750 .decl = ini.decl,
6751 .captures_len = @intCast(ini.captures.len),
6752 .namespace = ini.namespace,
6753 .int_tag_type = ini.tag_ty,
6754 .fields_len = fields_len,
6755 .names_map = names_map,
6756 .values_map = values_map,
6757 .zir_index = ini.zir_index,
6758 }),
6759 });
6760 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
6761 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6762 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
6763 return @enumFromInt(ip.items.len - 1);
7101 // Capacity for this was ensured earlier
7102 const adapter: KeyAdapter = .{ .intern_pool = ip };
7103 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ .enum_type = .{
7104 .generated_tag = .{ .union_type = ini.owner_union_ty },
7105 } }, adapter);
7106 assert(!gop.found_existing);
7107 assert(gop.index == ip.items.len - 1);
7108 return @enumFromInt(gop.index);
67647109}
67657110
67667111pub const OpaqueTypeIni = struct {
6767 decl: DeclIndex,
6768 namespace: NamespaceIndex,
6769 zir_index: TrackedInst.Index.Optional,
6770 captures: []const CaptureValue,
7112 has_namespace: bool,
7113 key: union(enum) {
7114 declared: struct {
7115 zir_index: TrackedInst.Index,
7116 captures: []const CaptureValue,
7117 },
7118 reified: struct {
7119 zir_index: TrackedInst.Index,
7120 // No type hash since reifid opaques have no data other than the `@Type` location
7121 },
7122 },
67717123};
67727124
6773pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!Index {
7125pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!WipNamespaceType.Result {
67747126 const adapter: KeyAdapter = .{ .intern_pool = ip };
6775 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(LoadedOpaqueType).Struct.fields.len + ini.captures.len);
7127 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
7128 .declared => |d| .{ .declared = .{
7129 .zir_index = d.zir_index,
7130 .captures = .{ .external = d.captures },
7131 } },
7132 .reified => |r| .{ .reified = .{
7133 .zir_index = r.zir_index,
7134 .type_hash = 0,
7135 } },
7136 } }, adapter);
7137 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
7138 errdefer _ = ip.map.pop();
67767139 try ip.items.ensureUnusedCapacity(gpa, 1);
6777 const gop = try ip.map.getOrPutAdapted(gpa, Key{
6778 .opaque_type = .{ .decl = ini.decl },
6779 }, adapter);
6780 if (gop.found_existing) return @enumFromInt(gop.index);
7140 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeOpaque).Struct.fields.len + switch (ini.key) {
7141 .declared => |d| d.captures.len,
7142 .reified => 0,
7143 });
7144 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeOpaque{
7145 .decl = undefined, // set by `finish`
7146 .namespace = .none,
7147 .zir_index = switch (ini.key) {
7148 inline else => |x| x.zir_index,
7149 },
7150 .captures_len = switch (ini.key) {
7151 .declared => |d| @intCast(d.captures.len),
7152 .reified => std.math.maxInt(u32),
7153 },
7154 });
67817155 ip.items.appendAssumeCapacity(.{
67827156 .tag = .type_opaque,
6783 .data = ip.addExtraAssumeCapacity(Tag.TypeOpaque{
6784 .decl = ini.decl,
6785 .namespace = ini.namespace,
6786 .zir_index = ini.zir_index,
6787 .captures_len = @intCast(ini.captures.len),
6788 }),
7157 .data = extra_index,
67897158 });
6790 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
6791 return @enumFromInt(gop.index);
7159 switch (ini.key) {
7160 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
7161 .reified => {},
7162 }
7163 return .{ .wip = .{
7164 .index = @enumFromInt(gop.index),
7165 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "decl").?,
7166 .namespace_extra_index = if (ini.has_namespace)
7167 extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?
7168 else
7169 null,
7170 } };
67927171}
67937172
67947173pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
......@@ -6837,8 +7216,34 @@ fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex
68377216
68387217/// This operation only happens under compile error conditions.
68397218/// Leak the index until the next garbage collection.
6840/// TODO: this is a bit problematic to implement, can we get away without it?
6841pub const remove = @compileError("InternPool.remove is not currently a supported operation; put a TODO there instead");
7219/// Invalidates all references to this index.
7220pub fn remove(ip: *InternPool, index: Index) void {
7221 if (@intFromEnum(index) < static_keys.len) {
7222 // The item being removed replaced a special index via `InternPool.resolveBuiltinType`.
7223 // Restore the original item at this index.
7224 switch (static_keys[@intFromEnum(index)]) {
7225 .simple_type => |s| {
7226 ip.items.set(@intFromEnum(index), .{
7227 .tag = .simple_type,
7228 .data = @intFromEnum(s),
7229 });
7230 },
7231 else => unreachable,
7232 }
7233 return;
7234 }
7235
7236 if (@intFromEnum(index) == ip.items.len - 1) {
7237 // Happy case - we can just drop the item without affecting any other indices.
7238 ip.items.len -= 1;
7239 _ = ip.map.pop();
7240 } else {
7241 // We must preserve the item so that indices following it remain valid.
7242 // Thus, we will rewrite the tag to `removed`, leaking the item until
7243 // next GC but causing `KeyAdapter` to ignore it.
7244 ip.items.set(@intFromEnum(index), .{ .tag = .removed, .data = undefined });
7245 }
7246}
68427247
68437248fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void {
68447249 const limbs_len = @as(u32, @intCast(limbs.len));
......@@ -7635,6 +8040,10 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
76358040 if (!gop.found_existing) gop.value_ptr.* = .{};
76368041 gop.value_ptr.count += 1;
76378042 gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) {
8043 // Note that in this case, we have technically leaked some extra data
8044 // bytes which we do not account for here.
8045 .removed => 0,
8046
76388047 .type_int_signed => 0,
76398048 .type_int_unsigned => 0,
76408049 .type_array_small => @sizeOf(Vector),
......@@ -7852,6 +8261,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
78528261 for (tags, datas, 0..) |tag, data, i| {
78538262 try w.print("${d} = {s}(", .{ i, @tagName(tag) });
78548263 switch (tag) {
8264 .removed => {},
8265
78558266 .simple_type => try w.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(data)))}),
78568267 .simple_value => try w.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(data)))}),
78578268
......@@ -8258,6 +8669,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
82588669 // This optimization on tags is needed so that indexToKey can call
82598670 // typeOf without being recursive.
82608671 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8672 .removed => unreachable,
8673
82618674 .type_int_signed,
82628675 .type_int_unsigned,
82638676 .type_array_big,
......@@ -8575,6 +8988,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
85758988 .var_args_param_type => unreachable, // special tag
85768989
85778990 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8991 .removed => unreachable,
8992
85788993 .type_int_signed,
85798994 .type_int_unsigned,
85808995 => .Int,
src/Module.zig+70-68
......@@ -568,9 +568,9 @@ pub const Decl = struct {
568568 .empty_struct_type => .none,
569569 .none => .none,
570570 else => switch (ip.indexToKey(decl.val.toIntern())) {
571 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace.toOptional(),
571 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
572572 .struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
573 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace.toOptional(),
573 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
574574 .enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
575575 else => .none,
576576 },
......@@ -3302,6 +3302,70 @@ pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
33023302 return mod.semaFile(file);
33033303}
33043304
3305fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {
3306 const gpa = zcu.gpa;
3307 const ip = &zcu.intern_pool;
3308 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
3309 assert(extended.opcode == .struct_decl);
3310 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3311 assert(!small.has_captures_len);
3312 assert(!small.has_backing_int);
3313 assert(small.layout == .Auto);
3314 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3315 const fields_len = if (small.has_fields_len) blk: {
3316 const fields_len = file.zir.extra[extra_index];
3317 extra_index += 1;
3318 break :blk fields_len;
3319 } else 0;
3320 const decls_len = if (small.has_decls_len) blk: {
3321 const decls_len = file.zir.extra[extra_index];
3322 extra_index += 1;
3323 break :blk decls_len;
3324 } else 0;
3325 const decls = file.zir.bodySlice(extra_index, decls_len);
3326 extra_index += decls_len;
3327
3328 const tracked_inst = try ip.trackZir(gpa, file, .main_struct_inst);
3329 const wip_ty = switch (try ip.getStructType(gpa, .{
3330 .layout = .Auto,
3331 .fields_len = fields_len,
3332 .known_non_opv = small.known_non_opv,
3333 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
3334 .is_tuple = small.is_tuple,
3335 .any_comptime_fields = small.any_comptime_fields,
3336 .any_default_inits = small.any_default_inits,
3337 .inits_resolved = false,
3338 .any_aligned_fields = small.any_aligned_fields,
3339 .has_namespace = true,
3340 .key = .{ .declared = .{
3341 .zir_index = tracked_inst,
3342 .captures = &.{},
3343 } },
3344 })) {
3345 .existing => unreachable, // we wouldn't be analysing the file root if this type existed
3346 .wip => |wip| wip,
3347 };
3348 errdefer wip_ty.cancel(ip);
3349
3350 if (zcu.comp.debug_incremental) {
3351 try ip.addDependency(
3352 gpa,
3353 InternPool.Depender.wrap(.{ .decl = decl_index }),
3354 .{ .src_hash = tracked_inst },
3355 );
3356 }
3357
3358 const decl = zcu.declPtr(decl_index);
3359 decl.val = Value.fromInterned(wip_ty.index);
3360 decl.has_tv = true;
3361 decl.owns_tv = true;
3362 decl.analysis = .complete;
3363
3364 try zcu.scanNamespace(namespace_index, decls, decl);
3365
3366 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
3367}
3368
33053369/// Regardless of the file status, will create a `Decl` so that we
33063370/// can track dependencies and re-analyze when the file becomes outdated.
33073371pub fn semaFile(mod: *Module, file: *File) SemaError!void {
......@@ -3323,7 +3387,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33233387 .decl_index = undefined,
33243388 .file_scope = file,
33253389 });
3326 const new_namespace = mod.namespacePtr(new_namespace_index);
33273390 errdefer mod.destroyNamespace(new_namespace_index);
33283391
33293392 const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0);
......@@ -3331,7 +3394,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33313394 errdefer @panic("TODO error handling");
33323395
33333396 file.root_decl = new_decl_index.toOptional();
3334 new_namespace.decl_index = new_decl_index;
3397 mod.namespacePtr(new_namespace_index).decl_index = new_decl_index;
33353398
33363399 new_decl.name = try file.fullyQualifiedName(mod);
33373400 new_decl.name_fully_qualified = true;
......@@ -3350,63 +3413,10 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33503413 }
33513414 assert(file.zir_loaded);
33523415
3353 var sema_arena = std.heap.ArenaAllocator.init(gpa);
3354 defer sema_arena.deinit();
3355 const sema_arena_allocator = sema_arena.allocator();
3356
3357 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3358 defer comptime_mutable_decls.deinit();
3359
3360 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
3361 defer comptime_err_ret_trace.deinit();
3416 const struct_ty = try mod.getFileRootStruct(new_decl_index, new_namespace_index, file);
3417 errdefer mod.intern_pool.remove(struct_ty);
33623418
3363 var sema: Sema = .{
3364 .mod = mod,
3365 .gpa = gpa,
3366 .arena = sema_arena_allocator,
3367 .code = file.zir,
3368 .owner_decl = new_decl,
3369 .owner_decl_index = new_decl_index,
3370 .func_index = .none,
3371 .func_is_naked = false,
3372 .fn_ret_ty = Type.void,
3373 .fn_ret_ty_ies = null,
3374 .owner_func_index = .none,
3375 .comptime_mutable_decls = &comptime_mutable_decls,
3376 .comptime_err_ret_trace = &comptime_err_ret_trace,
3377 };
3378 defer sema.deinit();
3379
3380 const struct_ty = sema.getStructType(
3381 new_decl_index,
3382 new_namespace_index,
3383 null,
3384 try mod.intern_pool.trackZir(gpa, file, .main_struct_inst),
3385 ) catch |err| switch (err) {
3386 error.OutOfMemory => return error.OutOfMemory,
3387 // The following errors are from resolving capture values, but the root
3388 // struct of a file has no captures.
3389 error.AnalysisFail,
3390 error.NeededSourceLocation,
3391 error.GenericPoison,
3392 error.ComptimeReturn,
3393 error.ComptimeBreak,
3394 => unreachable,
3395 };
3396 // TODO: figure out InternPool removals for incremental compilation
3397 //errdefer ip.remove(struct_ty);
3398 for (comptime_mutable_decls.items) |decl_index| {
3399 const decl = mod.declPtr(decl_index);
3400 _ = try decl.internValue(mod);
3401 }
3402
3403 new_decl.val = Value.fromInterned(struct_ty);
3404 new_decl.has_tv = true;
3405 new_decl.owns_tv = true;
3406 new_decl.analysis = .complete;
3407
3408 const comp = mod.comp;
3409 switch (comp.cache_use) {
3419 switch (mod.comp.cache_use) {
34103420 .whole => |whole| if (whole.cache_manifest) |man| {
34113421 const source = file.getSource(gpa) catch |err| {
34123422 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
......@@ -5940,14 +5950,6 @@ pub fn atomicPtrAlignment(
59405950 return .none;
59415951}
59425952
5943pub fn opaqueSrcLoc(mod: *Module, opaque_type: InternPool.Key.OpaqueType) SrcLoc {
5944 return mod.declPtr(opaque_type.decl).srcLoc(mod);
5945}
5946
5947pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) !InternPool.NullTerminatedString {
5948 return mod.declPtr(opaque_type.decl).fullyQualifiedName(mod);
5949}
5950
59515953pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
59525954 return mod.declPtr(decl_index).getFileScope(mod);
59535955}
src/Sema.zig+730-691
......@@ -2685,7 +2685,7 @@ fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_
26852685 capture.* = switch (zir_capture.unwrap()) {
26862686 .inst => |inst| InternPool.CaptureValue.wrap(capture: {
26872687 const air_ref = try sema.resolveInst(inst.toRef());
2688 if (try sema.resolveValue(air_ref)) |val| {
2688 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
26892689 break :capture .{ .@"comptime" = val.toIntern() };
26902690 }
26912691 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
......@@ -2697,23 +2697,20 @@ fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_
26972697 return captures;
26982698}
26992699
2700pub fn getStructType(
2700fn zirStructDecl(
27012701 sema: *Sema,
2702 decl: InternPool.DeclIndex,
2703 namespace: InternPool.NamespaceIndex,
2704 /// The direct parent Namespace for resolving nested capture values.
2705 parent_namespace: ?InternPool.NamespaceIndex,
2706 tracked_inst: InternPool.TrackedInst.Index,
2707) !InternPool.Index {
2702 block: *Block,
2703 extended: Zir.Inst.Extended.InstData,
2704 inst: Zir.Inst.Index,
2705) CompileError!Air.Inst.Ref {
27082706 const mod = sema.mod;
27092707 const gpa = sema.gpa;
27102708 const ip = &mod.intern_pool;
2711 const zir_index = tracked_inst.resolve(ip);
2712 const extended = sema.code.instructions.items(.data)[@intFromEnum(zir_index)].extended;
2713 assert(extended.opcode == .struct_decl);
27142709 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2710 const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
2711 const src = extra.data.src();
2712 var extra_index = extra.end;
27152713
2716 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
27172714 const captures_len = if (small.has_captures_len) blk: {
27182715 const captures_len = sema.code.extra[extra_index];
27192716 extra_index += 1;
......@@ -2730,7 +2727,7 @@ pub fn getStructType(
27302727 break :blk decls_len;
27312728 } else 0;
27322729
2733 const captures = try sema.getCaptures(parent_namespace, extra_index, captures_len);
2730 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
27342731 extra_index += captures_len;
27352732
27362733 if (small.has_backing_int) {
......@@ -2743,50 +2740,38 @@ pub fn getStructType(
27432740 }
27442741 }
27452742
2746 const decls = sema.code.bodySlice(extra_index, decls_len);
2747 try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
2748 extra_index += decls_len;
2749
2750 const ty = try ip.getStructType(gpa, .{
2751 .decl = decl,
2752 .namespace = namespace.toOptional(),
2753 .zir_index = tracked_inst.toOptional(),
2743 const wip_ty = switch (try ip.getStructType(gpa, .{
27542744 .layout = small.layout,
2755 .known_non_opv = small.known_non_opv,
2756 .is_tuple = small.is_tuple,
27572745 .fields_len = fields_len,
2746 .known_non_opv = small.known_non_opv,
27582747 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
2759 .any_default_inits = small.any_default_inits,
2748 .is_tuple = small.is_tuple,
27602749 .any_comptime_fields = small.any_comptime_fields,
2750 .any_default_inits = small.any_default_inits,
27612751 .inits_resolved = false,
27622752 .any_aligned_fields = small.any_aligned_fields,
2763 .captures = captures,
2764 });
2765
2766 return ty;
2767}
2768
2769fn zirStructDecl(
2770 sema: *Sema,
2771 block: *Block,
2772 extended: Zir.Inst.Extended.InstData,
2773 inst: Zir.Inst.Index,
2774) CompileError!Air.Inst.Ref {
2775 const mod = sema.mod;
2776 const ip = &mod.intern_pool;
2777 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2778 const src = sema.code.extraData(Zir.Inst.StructDecl, extended.operand).data.src();
2779
2780 // Because these three things each reference each other, `undefined`
2781 // placeholders are used before being set after the struct type gains an
2782 // InternPool index.
2753 .has_namespace = true or decls_len > 0, // TODO: see below
2754 .key = .{ .declared = .{
2755 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
2756 .captures = captures,
2757 } },
2758 })) {
2759 .existing => |ty| return Air.internedToRef(ty),
2760 .wip => |wip| wip: {
2761 if (sema.builtin_type_target_index == .none) break :wip wip;
2762 var new = wip;
2763 new.index = sema.builtin_type_target_index;
2764 ip.resolveBuiltinType(new.index, wip.index);
2765 break :wip new;
2766 },
2767 };
2768 errdefer wip_ty.cancel(ip);
27832769
27842770 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2785 .ty = Type.noreturn,
2786 .val = Value.@"unreachable",
2771 .ty = Type.type,
2772 .val = Value.fromInterned(wip_ty.index),
27872773 }, small.name_strategy, "struct", inst);
2788 const new_decl = mod.declPtr(new_decl_index);
2789 new_decl.owns_tv = true;
2774 mod.declPtr(new_decl_index).owns_tv = true;
27902775 errdefer mod.abortAnonDecl(new_decl_index);
27912776
27922777 if (sema.mod.comp.debug_incremental) {
......@@ -2797,31 +2782,21 @@ fn zirStructDecl(
27972782 );
27982783 }
27992784
2800 const new_namespace_index = try mod.createNamespace(.{
2785 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
2786 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
28012787 .parent = block.namespace.toOptional(),
28022788 .decl_index = new_decl_index,
28032789 .file_scope = block.getFileScope(mod),
2804 });
2790 })).toOptional() else .none;
28052791 errdefer mod.destroyNamespace(new_namespace_index);
28062792
2807 const struct_ty = ty: {
2808 const tracked_inst = try ip.trackZir(mod.gpa, block.getFileScope(mod), inst);
2809 const ty = try sema.getStructType(new_decl_index, new_namespace_index, block.namespace, tracked_inst);
2810 if (sema.builtin_type_target_index != .none) {
2811 ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
2812 break :ty sema.builtin_type_target_index;
2813 }
2814 break :ty ty;
2815 };
2816 // TODO: figure out InternPool removals for incremental compilation
2817 //errdefer ip.remove(struct_ty);
2818
2819 new_decl.ty = Type.type;
2820 new_decl.val = Value.fromInterned(struct_ty);
2793 if (new_namespace_index.unwrap()) |ns| {
2794 const decls = sema.code.bodySlice(extra_index, decls_len);
2795 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
2796 }
28212797
2822 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
28232798 try mod.finalizeAnonDecl(new_decl_index);
2824 return decl_val;
2799 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
28252800}
28262801
28272802fn createAnonymousDeclTypeNamed(
......@@ -2931,6 +2906,7 @@ fn zirEnumDecl(
29312906
29322907 const mod = sema.mod;
29332908 const gpa = sema.gpa;
2909 const ip = &mod.intern_pool;
29342910 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
29352911 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
29362912 var extra_index: usize = extra.end;
......@@ -2968,39 +2944,10 @@ fn zirEnumDecl(
29682944 break :blk decls_len;
29692945 } else 0;
29702946
2971 // Because these three things each reference each other, `undefined`
2972 // placeholders are used before being set after the enum type gains an
2973 // InternPool index.
2974
2975 var done = false;
2976 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2977 .ty = Type.noreturn,
2978 .val = Value.@"unreachable",
2979 }, small.name_strategy, "enum", inst);
2980 const new_decl = mod.declPtr(new_decl_index);
2981 new_decl.owns_tv = true;
2982 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
2983
2984 if (sema.mod.comp.debug_incremental) {
2985 try mod.intern_pool.addDependency(
2986 sema.gpa,
2987 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
2988 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2989 );
2990 }
2991
29922947 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
29932948 extra_index += captures_len;
29942949
2995 const new_namespace_index = try mod.createNamespace(.{
2996 .parent = block.namespace.toOptional(),
2997 .decl_index = new_decl_index,
2998 .file_scope = block.getFileScope(mod),
2999 });
3000 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
3001
30022950 const decls = sema.code.bodySlice(extra_index, decls_len);
3003 try mod.scanNamespace(new_namespace_index, decls, new_decl);
30042951 extra_index += decls_len;
30052952
30062953 const body = sema.code.bodySlice(extra_index, body_len);
......@@ -3014,36 +2961,59 @@ fn zirEnumDecl(
30142961 if (bag != 0) break true;
30152962 } else false;
30162963
3017 const incomplete_enum = incomplete_enum: {
3018 var incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
3019 .decl = new_decl_index,
3020 .namespace = new_namespace_index.toOptional(),
3021 .fields_len = fields_len,
3022 .has_values = any_values,
3023 .tag_mode = if (small.nonexhaustive)
3024 .nonexhaustive
3025 else if (tag_type_ref == .none)
3026 .auto
3027 else
3028 .explicit,
3029 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
2964 const wip_ty = switch (try ip.getEnumType(gpa, .{
2965 .has_namespace = true or decls_len > 0, // TODO: see below
2966 .has_values = any_values,
2967 .tag_mode = if (small.nonexhaustive)
2968 .nonexhaustive
2969 else if (tag_type_ref == .none)
2970 .auto
2971 else
2972 .explicit,
2973 .fields_len = fields_len,
2974 .key = .{ .declared = .{
2975 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
30302976 .captures = captures,
3031 });
3032 if (sema.builtin_type_target_index != .none) {
3033 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
3034 incomplete_enum.index = sema.builtin_type_target_index;
3035 }
3036 break :incomplete_enum incomplete_enum;
2977 } },
2978 })) {
2979 .wip => |wip| wip: {
2980 if (sema.builtin_type_target_index == .none) break :wip wip;
2981 var new = wip;
2982 new.index = sema.builtin_type_target_index;
2983 ip.resolveBuiltinType(new.index, wip.index);
2984 break :wip new;
2985 },
2986 .existing => |ty| return Air.internedToRef(ty),
30372987 };
3038 // TODO: figure out InternPool removals for incremental compilation
3039 //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
2988 errdefer wip_ty.cancel(ip);
30402989
3041 new_decl.ty = Type.type;
3042 new_decl.val = Value.fromInterned(incomplete_enum.index);
2990 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2991 .ty = Type.type,
2992 .val = Value.fromInterned(wip_ty.index),
2993 }, small.name_strategy, "enum", inst);
2994 const new_decl = mod.declPtr(new_decl_index);
2995 new_decl.owns_tv = true;
2996 errdefer mod.abortAnonDecl(new_decl_index);
30432997
3044 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
3045 try mod.finalizeAnonDecl(new_decl_index);
3046 done = true;
2998 if (sema.mod.comp.debug_incremental) {
2999 try mod.intern_pool.addDependency(
3000 sema.gpa,
3001 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3002 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3003 );
3004 }
3005
3006 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3007 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
3008 .parent = block.namespace.toOptional(),
3009 .decl_index = new_decl_index,
3010 .file_scope = block.getFileScope(mod),
3011 })).toOptional() else .none;
3012 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
3013
3014 if (new_namespace_index.unwrap()) |ns| {
3015 try mod.scanNamespace(ns, decls, new_decl);
3016 }
30473017
30483018 const int_tag_ty = ty: {
30493019 // We create a block for the field type instructions because they
......@@ -3072,7 +3042,7 @@ fn zirEnumDecl(
30723042 .parent = null,
30733043 .sema = sema,
30743044 .src_decl = new_decl_index,
3075 .namespace = new_namespace_index,
3045 .namespace = new_namespace_index.unwrap() orelse block.namespace,
30763046 .instructions = .{},
30773047 .inlining = null,
30783048 .is_comptime = true,
......@@ -3088,7 +3058,6 @@ fn zirEnumDecl(
30883058 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
30893059 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
30903060 }
3091 incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
30923061 break :ty ty;
30933062 } else if (fields_len == 0) {
30943063 break :ty try mod.intType(.unsigned, 0);
......@@ -3098,6 +3067,8 @@ fn zirEnumDecl(
30983067 }
30993068 };
31003069
3070 wip_ty.prepare(ip, new_decl_index, new_namespace_index, int_tag_ty.toIntern());
3071
31013072 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
31023073 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
31033074 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
......@@ -3121,7 +3092,6 @@ fn zirEnumDecl(
31213092 extra_index += 2; // field name, doc comment
31223093
31233094 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
3124 assert(incomplete_enum.addFieldName(&mod.intern_pool, field_name) == null);
31253095
31263096 const tag_overflow = if (has_tag_value) overflow: {
31273097 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
......@@ -3142,12 +3112,13 @@ fn zirEnumDecl(
31423112 };
31433113 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
31443114 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
3145 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
3115 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3116 assert(conflict.kind == .value); // AstGen validated names are unique
31463117 const value_src = mod.fieldSrcLoc(new_decl_index, .{
31473118 .index = field_i,
31483119 .range = .value,
31493120 }).lazy;
3150 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3121 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
31513122 const msg = msg: {
31523123 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
31533124 errdefer msg.destroy(gpa);
......@@ -3164,9 +3135,10 @@ fn zirEnumDecl(
31643135 else
31653136 try mod.intValue(int_tag_ty, 0);
31663137 if (overflow != null) break :overflow true;
3167 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
3138 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3139 assert(conflict.kind == .value); // AstGen validated names are unique
31683140 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3169 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3141 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
31703142 const msg = msg: {
31713143 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
31723144 errdefer msg.destroy(gpa);
......@@ -3177,6 +3149,7 @@ fn zirEnumDecl(
31773149 }
31783150 break :overflow false;
31793151 } else overflow: {
3152 assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null);
31803153 last_tag_val = try mod.intValue(Type.comptime_int, field_i);
31813154 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
31823155 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
......@@ -3194,7 +3167,9 @@ fn zirEnumDecl(
31943167 return sema.failWithOwnedErrorMsg(block, msg);
31953168 }
31963169 }
3197 return decl_val;
3170
3171 try mod.finalizeAnonDecl(new_decl_index);
3172 return Air.internedToRef(wip_ty.finish(ip));
31983173}
31993174
32003175fn zirUnionDecl(
......@@ -3208,6 +3183,7 @@ fn zirUnionDecl(
32083183
32093184 const mod = sema.mod;
32103185 const gpa = sema.gpa;
3186 const ip = &mod.intern_pool;
32113187 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
32123188 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
32133189 var extra_index: usize = extra.end;
......@@ -3233,16 +3209,53 @@ fn zirUnionDecl(
32333209 break :blk decls_len;
32343210 } else 0;
32353211
3236 // Because these three things each reference each other, `undefined`
3237 // placeholders are used before being set after the union type gains an
3238 // InternPool index.
3212 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
3213 extra_index += captures_len;
3214
3215 const wip_ty = switch (try ip.getUnionType(gpa, .{
3216 .flags = .{
3217 .layout = small.layout,
3218 .status = .none,
3219 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3220 .tagged
3221 else if (small.layout != .Auto)
3222 .none
3223 else switch (block.wantSafety()) {
3224 true => .safety,
3225 false => .none,
3226 },
3227 .any_aligned_fields = small.any_aligned_fields,
3228 .requires_comptime = .unknown,
3229 .assumed_runtime_bits = false,
3230 .assumed_pointer_aligned = false,
3231 .alignment = .none,
3232 },
3233 .has_namespace = true or decls_len != 0, // TODO: see below
3234 .fields_len = fields_len,
3235 .enum_tag_ty = .none, // set later
3236 .field_types = &.{}, // set later
3237 .field_aligns = &.{}, // set later
3238 .key = .{ .declared = .{
3239 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3240 .captures = captures,
3241 } },
3242 })) {
3243 .wip => |wip| wip: {
3244 if (sema.builtin_type_target_index == .none) break :wip wip;
3245 var new = wip;
3246 new.index = sema.builtin_type_target_index;
3247 ip.resolveBuiltinType(new.index, wip.index);
3248 break :wip new;
3249 },
3250 .existing => |ty| return Air.internedToRef(ty),
3251 };
3252 errdefer wip_ty.cancel(ip);
32393253
32403254 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3241 .ty = Type.noreturn,
3242 .val = Value.@"unreachable",
3255 .ty = Type.type,
3256 .val = Value.fromInterned(wip_ty.index),
32433257 }, small.name_strategy, "union", inst);
3244 const new_decl = mod.declPtr(new_decl_index);
3245 new_decl.owns_tv = true;
3258 mod.declPtr(new_decl_index).owns_tv = true;
32463259 errdefer mod.abortAnonDecl(new_decl_index);
32473260
32483261 if (sema.mod.comp.debug_incremental) {
......@@ -3253,62 +3266,22 @@ fn zirUnionDecl(
32533266 );
32543267 }
32553268
3256 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
3257 extra_index += captures_len;
3258
3259 const new_namespace_index = try mod.createNamespace(.{
3269 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3270 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
32603271 .parent = block.namespace.toOptional(),
32613272 .decl_index = new_decl_index,
32623273 .file_scope = block.getFileScope(mod),
3263 });
3264 errdefer mod.destroyNamespace(new_namespace_index);
3265
3266 const union_ty = ty: {
3267 const ty = try mod.intern_pool.getUnionType(gpa, .{
3268 .flags = .{
3269 .layout = small.layout,
3270 .status = .none,
3271 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3272 .tagged
3273 else if (small.layout != .Auto)
3274 .none
3275 else switch (block.wantSafety()) {
3276 true => .safety,
3277 false => .none,
3278 },
3279 .any_aligned_fields = small.any_aligned_fields,
3280 .requires_comptime = .unknown,
3281 .assumed_runtime_bits = false,
3282 .assumed_pointer_aligned = false,
3283 .alignment = .none,
3284 },
3285 .decl = new_decl_index,
3286 .namespace = new_namespace_index,
3287 .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(),
3288 .fields_len = fields_len,
3289 .enum_tag_ty = .none,
3290 .field_types = &.{},
3291 .field_aligns = &.{},
3292 .captures = captures,
3293 });
3294 if (sema.builtin_type_target_index != .none) {
3295 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
3296 break :ty sema.builtin_type_target_index;
3297 }
3298 break :ty ty;
3299 };
3300 // TODO: figure out InternPool removals for incremental compilation
3301 //errdefer mod.intern_pool.remove(union_ty);
3274 })).toOptional() else .none;
3275 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
33023276
3303 new_decl.ty = Type.type;
3304 new_decl.val = Value.fromInterned(union_ty);
3305
3306 const decls = sema.code.bodySlice(extra_index, decls_len);
3307 try mod.scanNamespace(new_namespace_index, decls, new_decl);
3277 if (new_namespace_index.unwrap()) |ns| {
3278 const decls = sema.code.bodySlice(extra_index, decls_len);
3279 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3280 }
33083281
3309 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
33103282 try mod.finalizeAnonDecl(new_decl_index);
3311 return decl_val;
3283
3284 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
33123285}
33133286
33143287fn zirOpaqueDecl(
......@@ -3321,6 +3294,9 @@ fn zirOpaqueDecl(
33213294 defer tracy.end();
33223295
33233296 const mod = sema.mod;
3297 const gpa = sema.gpa;
3298 const ip = &mod.intern_pool;
3299
33243300 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
33253301 const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
33263302 var extra_index: usize = extra.end;
......@@ -3339,54 +3315,51 @@ fn zirOpaqueDecl(
33393315 break :blk decls_len;
33403316 } else 0;
33413317
3342 // Because these three things each reference each other, `undefined`
3343 // placeholders are used in two places before being set after the opaque
3344 // type gains an InternPool index.
3318 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
3319 extra_index += captures_len;
3320
3321 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
3322 .has_namespace = decls_len != 0,
3323 .key = .{ .declared = .{
3324 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3325 .captures = captures,
3326 } },
3327 })) {
3328 .wip => |wip| wip,
3329 .existing => |ty| return Air.internedToRef(ty),
3330 };
3331 errdefer wip_ty.cancel(ip);
33453332
33463333 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3347 .ty = Type.noreturn,
3348 .val = Value.@"unreachable",
3334 .ty = Type.type,
3335 .val = Value.fromInterned(wip_ty.index),
33493336 }, small.name_strategy, "opaque", inst);
3350 const new_decl = mod.declPtr(new_decl_index);
3351 new_decl.owns_tv = true;
3337 mod.declPtr(new_decl_index).owns_tv = true;
33523338 errdefer mod.abortAnonDecl(new_decl_index);
33533339
33543340 if (sema.mod.comp.debug_incremental) {
3355 try mod.intern_pool.addDependency(
3356 sema.gpa,
3341 try ip.addDependency(
3342 gpa,
33573343 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3358 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3344 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
33593345 );
33603346 }
33613347
3362 const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
3363 extra_index += captures_len;
3364
3365 const new_namespace_index = try mod.createNamespace(.{
3348 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try mod.createNamespace(.{
33663349 .parent = block.namespace.toOptional(),
33673350 .decl_index = new_decl_index,
33683351 .file_scope = block.getFileScope(mod),
3369 });
3370 errdefer mod.destroyNamespace(new_namespace_index);
3371
3372 const opaque_ty = try mod.intern_pool.getOpaqueType(sema.gpa, .{
3373 .decl = new_decl_index,
3374 .namespace = new_namespace_index,
3375 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3376 .captures = captures,
3377 });
3378 // TODO: figure out InternPool removals for incremental compilation
3379 //errdefer mod.intern_pool.remove(opaque_ty);
3380
3381 new_decl.ty = Type.type;
3382 new_decl.val = Value.fromInterned(opaque_ty);
3352 })).toOptional() else .none;
3353 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
33833354
3384 const decls = sema.code.bodySlice(extra_index, decls_len);
3385 try mod.scanNamespace(new_namespace_index, decls, new_decl);
3355 if (new_namespace_index.unwrap()) |ns| {
3356 const decls = sema.code.bodySlice(extra_index, decls_len);
3357 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3358 }
33863359
3387 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
33883360 try mod.finalizeAnonDecl(new_decl_index);
3389 return decl_val;
3361
3362 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
33903363}
33913364
33923365fn zirErrorSetDecl(
......@@ -21322,103 +21295,11 @@ fn zirReify(
2132221295 try ip.getOrPutString(gpa, "is_exhaustive"),
2132321296 ).?);
2132421297
21325 // Decls
2132621298 if (decls_val.sliceLen(mod) > 0) {
2132721299 return sema.fail(block, src, "reified enums must have no decls", .{});
2132821300 }
2132921301
21330 const int_tag_ty = tag_type_val.toType();
21331 if (int_tag_ty.zigTypeTag(mod) != .Int) {
21332 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
21333 }
21334
21335 // Because these things each reference each other, `undefined`
21336 // placeholders are used before being set after the enum type gains
21337 // an InternPool index.
21338
21339 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21340 .ty = Type.noreturn,
21341 .val = Value.@"unreachable",
21342 }, name_strategy, "enum", inst);
21343 const new_decl = mod.declPtr(new_decl_index);
21344 new_decl.owns_tv = true;
21345 errdefer {
21346 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21347 mod.abortAnonDecl(new_decl_index);
21348 }
21349
21350 // Define our empty enum decl
21351 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21352 const incomplete_enum = try ip.getIncompleteEnum(gpa, .{
21353 .decl = new_decl_index,
21354 .namespace = .none,
21355 .fields_len = fields_len,
21356 .has_values = true,
21357 .tag_mode = if (!is_exhaustive_val.toBool())
21358 .nonexhaustive
21359 else
21360 .explicit,
21361 .tag_ty = int_tag_ty.toIntern(),
21362 .zir_index = .none,
21363 .captures = &.{},
21364 });
21365 // TODO: figure out InternPool removals for incremental compilation
21366 //errdefer ip.remove(incomplete_enum.index);
21367
21368 new_decl.ty = Type.type;
21369 new_decl.val = Value.fromInterned(incomplete_enum.index);
21370
21371 for (0..fields_len) |field_i| {
21372 const elem_val = try fields_val.elemValue(mod, field_i);
21373 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21374 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21375 ip,
21376 try ip.getOrPutString(gpa, "name"),
21377 ).?);
21378 const value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21379 ip,
21380 try ip.getOrPutString(gpa, "value"),
21381 ).?);
21382
21383 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21384
21385 if (!try sema.intFitsInType(value_val, int_tag_ty, null)) {
21386 // TODO: better source location
21387 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21388 field_name.fmt(ip),
21389 value_val.fmtValue(Type.comptime_int, mod),
21390 int_tag_ty.fmt(mod),
21391 });
21392 }
21393
21394 if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
21395 const msg = msg: {
21396 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
21397 field_name.fmt(ip),
21398 });
21399 errdefer msg.destroy(gpa);
21400 _ = other_index; // TODO: this note is incorrect
21401 try sema.errNote(block, src, msg, "other field here", .{});
21402 break :msg msg;
21403 };
21404 return sema.failWithOwnedErrorMsg(block, msg);
21405 }
21406
21407 if (incomplete_enum.addFieldValue(ip, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
21408 const msg = msg: {
21409 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
21410 errdefer msg.destroy(gpa);
21411 _ = other; // TODO: this note is incorrect
21412 try sema.errNote(block, src, msg, "other enum tag value here", .{});
21413 break :msg msg;
21414 };
21415 return sema.failWithOwnedErrorMsg(block, msg);
21416 }
21417 }
21418
21419 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
21420 try mod.finalizeAnonDecl(new_decl_index);
21421 return decl_val;
21302 return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy);
2142221303 },
2142321304 .Opaque => {
2142421305 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
......@@ -21432,43 +21313,27 @@ fn zirReify(
2143221313 return sema.fail(block, src, "reified opaque must have no decls", .{});
2143321314 }
2143421315
21435 // Because these three things each reference each other,
21436 // `undefined` placeholders are used in two places before being set
21437 // after the opaque type gains an InternPool index.
21316 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
21317 .has_namespace = false,
21318 .key = .{ .reified = .{
21319 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21320 } },
21321 })) {
21322 .existing => |ty| return Air.internedToRef(ty),
21323 .wip => |wip| wip,
21324 };
21325 errdefer wip_ty.cancel(ip);
2143821326
2143921327 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21440 .ty = Type.noreturn,
21441 .val = Value.@"unreachable",
21328 .ty = Type.type,
21329 .val = Value.fromInterned(wip_ty.index),
2144221330 }, name_strategy, "opaque", inst);
21443 const new_decl = mod.declPtr(new_decl_index);
21444 new_decl.owns_tv = true;
21445 errdefer {
21446 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21447 mod.abortAnonDecl(new_decl_index);
21448 }
21449
21450 const new_namespace_index = try mod.createNamespace(.{
21451 .parent = block.namespace.toOptional(),
21452 .decl_index = new_decl_index,
21453 .file_scope = block.getFileScope(mod),
21454 });
21455 errdefer mod.destroyNamespace(new_namespace_index);
21456
21457 const opaque_ty = try ip.getOpaqueType(gpa, .{
21458 .decl = new_decl_index,
21459 .namespace = new_namespace_index,
21460 .zir_index = .none,
21461 .captures = &.{},
21462 });
21463 // TODO: figure out InternPool removals for incremental compilation
21464 //errdefer ip.remove(opaque_ty);
21465
21466 new_decl.ty = Type.type;
21467 new_decl.val = Value.fromInterned(opaque_ty);
21331 mod.declPtr(new_decl_index).owns_tv = true;
21332 errdefer mod.abortAnonDecl(new_decl_index);
2146821333
21469 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
2147021334 try mod.finalizeAnonDecl(new_decl_index);
21471 return decl_val;
21335
21336 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2147221337 },
2147321338 .Union => {
2147421339 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
......@@ -21489,214 +21354,12 @@ fn zirReify(
2148921354 try ip.getOrPutString(gpa, "decls"),
2149021355 ).?);
2149121356
21492 // Decls
2149321357 if (decls_val.sliceLen(mod) > 0) {
2149421358 return sema.fail(block, src, "reified unions must have no decls", .{});
2149521359 }
2149621360 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
21497 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21498
21499 // Tag type
21500 var explicit_tags_seen: []bool = &.{};
21501 var enum_field_names: []InternPool.NullTerminatedString = &.{};
21502 var enum_tag_ty: InternPool.Index = .none;
21503 if (tag_type_val.optionalValue(mod)) |payload_val| {
21504 enum_tag_ty = payload_val.toType().toIntern();
21505
21506 const enum_type = switch (ip.indexToKey(enum_tag_ty)) {
21507 .enum_type => ip.loadEnumType(enum_tag_ty),
21508 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
21509 };
21510
21511 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
21512 @memset(explicit_tags_seen, false);
21513 } else {
21514 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
21515 }
21516
21517 // Fields
21518 var any_aligned_fields: bool = false;
21519 var union_fields: std.MultiArrayList(struct {
21520 type: InternPool.Index,
21521 alignment: InternPool.Alignment,
21522 }) = .{};
21523 var field_name_table: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
21524 try field_name_table.ensureTotalCapacity(sema.arena, fields_len);
2152521361
21526 for (0..fields_len) |i| {
21527 const elem_val = try fields_val.elemValue(mod, i);
21528 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21529 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21530 ip,
21531 try ip.getOrPutString(gpa, "name"),
21532 ).?);
21533 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21534 ip,
21535 try ip.getOrPutString(gpa, "type"),
21536 ).?);
21537 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21538 ip,
21539 try ip.getOrPutString(gpa, "alignment"),
21540 ).?);
21541
21542 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21543
21544 if (enum_field_names.len != 0) {
21545 enum_field_names[i] = field_name;
21546 }
21547
21548 if (enum_tag_ty != .none) {
21549 const tag_info = ip.loadEnumType(enum_tag_ty);
21550 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
21551 return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
21552 field_name.fmt(ip), Type.fromInterned(enum_tag_ty).fmt(mod),
21553 });
21554 };
21555 assert(explicit_tags_seen.len == tag_info.names.len);
21556 // No check for duplicate because the check already happened in order
21557 // to create the enum type in the first place.
21558 assert(!explicit_tags_seen[enum_index]);
21559 explicit_tags_seen[enum_index] = true;
21560 }
21561
21562 const gop = field_name_table.getOrPutAssumeCapacity(field_name);
21563 if (gop.found_existing) {
21564 // TODO: better source location
21565 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21566 }
21567
21568 const field_ty = type_val.toType();
21569 const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
21570 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
21571 // TODO: better source location
21572 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{
21573 alignment_val_int,
21574 });
21575 }
21576 const field_align = Alignment.fromByteUnits(alignment_val_int);
21577 any_aligned_fields = any_aligned_fields or field_align != .none;
21578
21579 try union_fields.append(sema.arena, .{
21580 .type = field_ty.toIntern(),
21581 .alignment = field_align,
21582 });
21583
21584 if (field_ty.zigTypeTag(mod) == .Opaque) {
21585 const msg = msg: {
21586 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
21587 errdefer msg.destroy(gpa);
21588
21589 try sema.addDeclaredHereNote(msg, field_ty);
21590 break :msg msg;
21591 };
21592 return sema.failWithOwnedErrorMsg(block, msg);
21593 }
21594 if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
21595 const msg = msg: {
21596 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21597 errdefer msg.destroy(gpa);
21598
21599 const src_decl = mod.declPtr(block.src_decl);
21600 try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
21601
21602 try sema.addDeclaredHereNote(msg, field_ty);
21603 break :msg msg;
21604 };
21605 return sema.failWithOwnedErrorMsg(block, msg);
21606 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21607 const msg = msg: {
21608 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21609 errdefer msg.destroy(gpa);
21610
21611 const src_decl = mod.declPtr(block.src_decl);
21612 try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
21613
21614 try sema.addDeclaredHereNote(msg, field_ty);
21615 break :msg msg;
21616 };
21617 return sema.failWithOwnedErrorMsg(block, msg);
21618 }
21619 }
21620
21621 if (enum_tag_ty != .none) {
21622 const tag_info = ip.loadEnumType(enum_tag_ty);
21623 if (tag_info.names.len > fields_len) {
21624 const msg = msg: {
21625 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
21626 errdefer msg.destroy(gpa);
21627
21628 assert(explicit_tags_seen.len == tag_info.names.len);
21629 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
21630 if (explicit_tags_seen[field_index]) continue;
21631 try sema.addFieldErrNote(Type.fromInterned(enum_tag_ty), field_index, msg, "field '{}' missing, declared here", .{
21632 field_name.fmt(ip),
21633 });
21634 }
21635 try sema.addDeclaredHereNote(msg, Type.fromInterned(enum_tag_ty));
21636 break :msg msg;
21637 };
21638 return sema.failWithOwnedErrorMsg(block, msg);
21639 }
21640 } else {
21641 enum_tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, .none);
21642 }
21643
21644 // Because these three things each reference each other, `undefined`
21645 // placeholders are used before being set after the union type gains an
21646 // InternPool index.
21647
21648 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21649 .ty = Type.noreturn,
21650 .val = Value.@"unreachable",
21651 }, name_strategy, "union", inst);
21652 const new_decl = mod.declPtr(new_decl_index);
21653 new_decl.owns_tv = true;
21654 errdefer {
21655 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21656 mod.abortAnonDecl(new_decl_index);
21657 }
21658
21659 const new_namespace_index = try mod.createNamespace(.{
21660 .parent = block.namespace.toOptional(),
21661 .decl_index = new_decl_index,
21662 .file_scope = block.getFileScope(mod),
21663 });
21664 errdefer mod.destroyNamespace(new_namespace_index);
21665
21666 const union_ty = try ip.getUnionType(gpa, .{
21667 .decl = new_decl_index,
21668 .namespace = new_namespace_index,
21669 .enum_tag_ty = enum_tag_ty,
21670 .fields_len = fields_len,
21671 .zir_index = .none,
21672 .flags = .{
21673 .layout = layout,
21674 .status = .have_field_types,
21675 .runtime_tag = if (!tag_type_val.isNull(mod))
21676 .tagged
21677 else if (layout != .Auto)
21678 .none
21679 else switch (block.wantSafety()) {
21680 true => .safety,
21681 false => .none,
21682 },
21683 .any_aligned_fields = any_aligned_fields,
21684 .requires_comptime = .unknown,
21685 .assumed_runtime_bits = false,
21686 .assumed_pointer_aligned = false,
21687 .alignment = .none,
21688 },
21689 .field_types = union_fields.items(.type),
21690 .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{},
21691 .captures = &.{},
21692 });
21693
21694 new_decl.ty = Type.type;
21695 new_decl.val = Value.fromInterned(union_ty);
21696
21697 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
21698 try mod.finalizeAnonDecl(new_decl_index);
21699 return decl_val;
21362 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy);
2170021363 },
2170121364 .Fn => {
2170221365 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
......@@ -21795,127 +21458,491 @@ fn zirReify(
2179521458 }
2179621459}
2179721460
21798fn reifyStruct(
21461fn reifyEnum(
2179921462 sema: *Sema,
2180021463 block: *Block,
2180121464 inst: Zir.Inst.Index,
2180221465 src: LazySrcLoc,
21803 layout: std.builtin.Type.ContainerLayout,
21804 backing_int_val: Value,
21466 tag_ty: Type,
21467 is_exhaustive: bool,
2180521468 fields_val: Value,
2180621469 name_strategy: Zir.Inst.NameStrategy,
21807 is_tuple: bool,
2180821470) CompileError!Air.Inst.Ref {
2180921471 const mod = sema.mod;
2181021472 const gpa = sema.gpa;
2181121473 const ip = &mod.intern_pool;
2181221474
21813 if (is_tuple) switch (layout) {
21814 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
21815 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
21816 .Auto => {},
21475 // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
21476
21477 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21478
21479 // The validation work here is non-trivial, and it's possible the type already exists.
21480 // So in this first pass, let's just construct a hash to optimize for this case. If the
21481 // inputs turn out to be invalid, we can cancel the WIP type later.
21482
21483 // For deduplication purposes, we must create a hash including all details of this type.
21484 // TODO: use a longer hash!
21485 var hasher = std.hash.Wyhash.init(0);
21486 std.hash.autoHash(&hasher, tag_ty.toIntern());
21487 std.hash.autoHash(&hasher, is_exhaustive);
21488 std.hash.autoHash(&hasher, fields_len);
21489
21490 for (0..fields_len) |field_idx| {
21491 const field_info = try fields_val.elemValue(mod, field_idx);
21492
21493 const field_name_val = try field_info.fieldValue(mod, 0);
21494 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
21495
21496 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21497
21498 std.hash.autoHash(&hasher, .{
21499 field_name,
21500 field_value_val.toIntern(),
21501 });
21502 }
21503
21504 const wip_ty = switch (try ip.getEnumType(gpa, .{
21505 .has_namespace = false,
21506 .has_values = true,
21507 .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive,
21508 .fields_len = fields_len,
21509 .key = .{ .reified = .{
21510 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21511 .type_hash = hasher.final(),
21512 } },
21513 })) {
21514 .wip => |wip| wip,
21515 .existing => |ty| return Air.internedToRef(ty),
2181721516 };
21517 errdefer wip_ty.cancel(ip);
21518
21519 if (tag_ty.zigTypeTag(mod) != .Int) {
21520 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
21521 }
21522
21523 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21524 .ty = Type.type,
21525 .val = Value.fromInterned(wip_ty.index),
21526 }, name_strategy, "enum", inst);
21527 mod.declPtr(new_decl_index).owns_tv = true;
21528 errdefer mod.abortAnonDecl(new_decl_index);
21529
21530 wip_ty.prepare(ip, new_decl_index, .none, tag_ty.toIntern());
21531
21532 for (0..fields_len) |field_idx| {
21533 const field_info = try fields_val.elemValue(mod, field_idx);
2181821534
21819 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21535 const field_name_val = try field_info.fieldValue(mod, 0);
21536 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
2182021537
21821 // Because these three things each reference each other, `undefined`
21822 // placeholders are used before being set after the struct type gains an
21823 // InternPool index.
21538 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21539
21540 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
21541 // TODO: better source location
21542 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21543 field_name.fmt(ip),
21544 field_value_val.fmtValue(Type.comptime_int, mod),
21545 tag_ty.fmt(mod),
21546 });
21547 }
21548
21549 const coerced_field_val = try mod.getCoerced(field_value_val, tag_ty);
21550 if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
21551 return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
21552 .name => msg: {
21553 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{field_name.fmt(ip)});
21554 errdefer msg.destroy(gpa);
21555 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21556 try sema.errNote(block, src, msg, "other field here", .{});
21557 break :msg msg;
21558 },
21559 .value => msg: {
21560 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(Type.comptime_int, mod)});
21561 errdefer msg.destroy(gpa);
21562 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21563 try sema.errNote(block, src, msg, "other enum tag value here", .{});
21564 break :msg msg;
21565 },
21566 });
21567 }
21568 }
21569
21570 if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(mod)) {
21571 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
21572 }
21573
21574 try mod.finalizeAnonDecl(new_decl_index);
21575 return Air.internedToRef(wip_ty.finish(ip));
21576}
21577
21578fn reifyUnion(
21579 sema: *Sema,
21580 block: *Block,
21581 inst: Zir.Inst.Index,
21582 src: LazySrcLoc,
21583 layout: std.builtin.Type.ContainerLayout,
21584 opt_tag_type_val: Value,
21585 fields_val: Value,
21586 name_strategy: Zir.Inst.NameStrategy,
21587) CompileError!Air.Inst.Ref {
21588 const mod = sema.mod;
21589 const gpa = sema.gpa;
21590 const ip = &mod.intern_pool;
21591
21592 // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
21593
21594 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21595
21596 // The validation work here is non-trivial, and it's possible the type already exists.
21597 // So in this first pass, let's just construct a hash to optimize for this case. If the
21598 // inputs turn out to be invalid, we can cancel the WIP type later.
21599
21600 // For deduplication purposes, we must create a hash including all details of this type.
21601 // TODO: use a longer hash!
21602 var hasher = std.hash.Wyhash.init(0);
21603 std.hash.autoHash(&hasher, layout);
21604 std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
21605 std.hash.autoHash(&hasher, fields_len);
21606
21607 var any_aligns = false;
21608
21609 for (0..fields_len) |field_idx| {
21610 const field_info = try fields_val.elemValue(mod, field_idx);
21611
21612 const field_name_val = try field_info.fieldValue(mod, 0);
21613 const field_type_val = try field_info.fieldValue(mod, 1);
21614 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2));
21615
21616 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21617
21618 std.hash.autoHash(&hasher, .{
21619 field_name,
21620 field_type_val.toIntern(),
21621 field_align_val.toIntern(),
21622 });
21623
21624 if (field_align_val.toUnsignedInt(mod) != 0) {
21625 any_aligns = true;
21626 }
21627 }
21628
21629 const wip_ty = switch (try ip.getUnionType(gpa, .{
21630 .flags = .{
21631 .layout = layout,
21632 .status = .none,
21633 .runtime_tag = if (opt_tag_type_val.optionalValue(mod) != null)
21634 .tagged
21635 else if (layout != .Auto)
21636 .none
21637 else switch (block.wantSafety()) {
21638 true => .safety,
21639 false => .none,
21640 },
21641 .any_aligned_fields = any_aligns,
21642 .requires_comptime = .unknown,
21643 .assumed_runtime_bits = false,
21644 .assumed_pointer_aligned = false,
21645 .alignment = .none,
21646 },
21647 .has_namespace = false,
21648 .fields_len = fields_len,
21649 .enum_tag_ty = .none, // set later because not yet validated
21650 .field_types = &.{}, // set later
21651 .field_aligns = &.{}, // set later
21652 .key = .{ .reified = .{
21653 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21654 .type_hash = hasher.final(),
21655 } },
21656 })) {
21657 .wip => |wip| wip,
21658 .existing => |ty| return Air.internedToRef(ty),
21659 };
21660 errdefer wip_ty.cancel(ip);
2182421661
2182521662 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21826 .ty = Type.noreturn,
21827 .val = Value.@"unreachable",
21828 }, name_strategy, "struct", inst);
21829 const new_decl = mod.declPtr(new_decl_index);
21830 new_decl.owns_tv = true;
21831 errdefer {
21832 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21833 mod.abortAnonDecl(new_decl_index);
21663 .ty = Type.type,
21664 .val = Value.fromInterned(wip_ty.index),
21665 }, name_strategy, "union", inst);
21666 mod.declPtr(new_decl_index).owns_tv = true;
21667 errdefer mod.abortAnonDecl(new_decl_index);
21668
21669 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
21670 const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
21671
21672 const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(mod)) |tag_type_val| tag_ty: {
21673 switch (ip.indexToKey(tag_type_val.toIntern())) {
21674 .enum_type => {},
21675 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
21676 }
21677 const enum_tag_ty = tag_type_val.toType();
21678
21679 // We simply track which fields of the tag type have been seen.
21680 const tag_ty_fields_len = enum_tag_ty.enumFieldCount(mod);
21681 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
21682
21683 for (field_types, 0..) |*field_ty, field_idx| {
21684 const field_info = try fields_val.elemValue(mod, field_idx);
21685
21686 const field_name_val = try field_info.fieldValue(mod, 0);
21687 const field_type_val = try field_info.fieldValue(mod, 1);
21688
21689 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21690
21691 const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {
21692 // TODO: better source location
21693 return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
21694 field_name.fmt(ip), enum_tag_ty.fmt(mod),
21695 });
21696 };
21697 if (seen_tags.isSet(enum_index)) {
21698 // TODO: better source location
21699 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21700 }
21701 seen_tags.set(enum_index);
21702
21703 field_ty.* = field_type_val.toIntern();
21704 if (any_aligns) {
21705 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21706 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21707 // TODO: better source location
21708 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21709 }
21710 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21711 }
21712 }
21713
21714 if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
21715 const msg = try sema.errMsg(block, src, "enum fields missing in union", .{});
21716 errdefer msg.destroy(gpa);
21717 var it = seen_tags.iterator(.{ .kind = .unset });
21718 while (it.next()) |enum_index| {
21719 const field_name = enum_tag_ty.enumFieldName(enum_index, mod);
21720 try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{
21721 field_name.fmt(ip),
21722 });
21723 }
21724 try sema.addDeclaredHereNote(msg, enum_tag_ty);
21725 break :msg msg;
21726 });
21727
21728 break :tag_ty .{ enum_tag_ty.toIntern(), true };
21729 } else tag_ty: {
21730 // We must track field names and set up the tag type ourselves.
21731 var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
21732 try field_names.ensureTotalCapacity(sema.arena, fields_len);
21733
21734 for (field_types, 0..) |*field_ty, field_idx| {
21735 const field_info = try fields_val.elemValue(mod, field_idx);
21736
21737 const field_name_val = try field_info.fieldValue(mod, 0);
21738 const field_type_val = try field_info.fieldValue(mod, 1);
21739
21740 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21741 const gop = field_names.getOrPutAssumeCapacity(field_name);
21742 if (gop.found_existing) {
21743 // TODO: better source location
21744 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21745 }
21746
21747 field_ty.* = field_type_val.toIntern();
21748 if (any_aligns) {
21749 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21750 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21751 // TODO: better source location
21752 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21753 }
21754 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21755 }
21756 }
21757
21758 const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index));
21759 break :tag_ty .{ enum_tag_ty, false };
21760 };
21761 errdefer if (!has_explicit_tag) ip.remove(enum_tag_ty); // remove generated tag type on error
21762
21763 for (field_types) |field_ty_ip| {
21764 const field_ty = Type.fromInterned(field_ty_ip);
21765 if (field_ty.zigTypeTag(mod) == .Opaque) {
21766 return sema.failWithOwnedErrorMsg(block, msg: {
21767 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
21768 errdefer msg.destroy(gpa);
21769
21770 try sema.addDeclaredHereNote(msg, field_ty);
21771 break :msg msg;
21772 });
21773 }
21774 if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
21775 return sema.failWithOwnedErrorMsg(block, msg: {
21776 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21777 errdefer msg.destroy(gpa);
21778
21779 const src_decl = mod.declPtr(block.src_decl);
21780 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
21781
21782 try sema.addDeclaredHereNote(msg, field_ty);
21783 break :msg msg;
21784 });
21785 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21786 return sema.failWithOwnedErrorMsg(block, msg: {
21787 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21788 errdefer msg.destroy(gpa);
21789
21790 const src_decl = mod.declPtr(block.src_decl);
21791 try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
21792
21793 try sema.addDeclaredHereNote(msg, field_ty);
21794 break :msg msg;
21795 });
21796 }
2183421797 }
2183521798
21836 const ty = try ip.getStructType(gpa, .{
21837 .decl = new_decl_index,
21838 .namespace = .none,
21839 .zir_index = .none,
21799 const loaded_union = ip.loadUnionType(wip_ty.index);
21800 loaded_union.setFieldTypes(ip, field_types);
21801 if (any_aligns) {
21802 loaded_union.setFieldAligns(ip, field_aligns);
21803 }
21804 loaded_union.tagTypePtr(ip).* = enum_tag_ty;
21805 loaded_union.flagsPtr(ip).status = .have_field_types;
21806
21807 try mod.finalizeAnonDecl(new_decl_index);
21808 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
21809}
21810
21811fn reifyStruct(
21812 sema: *Sema,
21813 block: *Block,
21814 inst: Zir.Inst.Index,
21815 src: LazySrcLoc,
21816 layout: std.builtin.Type.ContainerLayout,
21817 opt_backing_int_val: Value,
21818 fields_val: Value,
21819 name_strategy: Zir.Inst.NameStrategy,
21820 is_tuple: bool,
21821) CompileError!Air.Inst.Ref {
21822 const mod = sema.mod;
21823 const gpa = sema.gpa;
21824 const ip = &mod.intern_pool;
21825
21826 // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
21827
21828 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21829
21830 // The validation work here is non-trivial, and it's possible the type already exists.
21831 // So in this first pass, let's just construct a hash to optimize for this case. If the
21832 // inputs turn out to be invalid, we can cancel the WIP type later.
21833
21834 // For deduplication purposes, we must create a hash including all details of this type.
21835 // TODO: use a longer hash!
21836 var hasher = std.hash.Wyhash.init(0);
21837 std.hash.autoHash(&hasher, layout);
21838 std.hash.autoHash(&hasher, opt_backing_int_val.toIntern());
21839 std.hash.autoHash(&hasher, is_tuple);
21840 std.hash.autoHash(&hasher, fields_len);
21841
21842 var any_comptime_fields = false;
21843 var any_default_inits = false;
21844 var any_aligned_fields = false;
21845
21846 for (0..fields_len) |field_idx| {
21847 const field_info = try fields_val.elemValue(mod, field_idx);
21848
21849 const field_name_val = try field_info.fieldValue(mod, 0);
21850 const field_type_val = try field_info.fieldValue(mod, 1);
21851 const field_default_value_val = try field_info.fieldValue(mod, 2);
21852 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
21853 const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4));
21854
21855 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21856 const field_is_comptime = field_is_comptime_val.toBool();
21857 const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {
21858 const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());
21859 // We need to do this deref here, so we won't check for this error case later on.
21860 const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
21861 block,
21862 src,
21863 .{ .needed_comptime_reason = "struct field default value must be comptime-known" },
21864 );
21865 // Resolve the value so that lazy values do not create distinct types.
21866 break :d (try sema.resolveLazyValue(val)).toIntern();
21867 } else .none;
21868
21869 std.hash.autoHash(&hasher, .{
21870 field_name,
21871 field_type_val.toIntern(),
21872 field_default_value,
21873 field_is_comptime,
21874 field_alignment_val.toIntern(),
21875 });
21876
21877 if (field_is_comptime) any_comptime_fields = true;
21878 if (field_default_value != .none) any_default_inits = true;
21879 switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, sema)) {
21880 .eq => {},
21881 .gt => any_aligned_fields = true,
21882 .lt => unreachable,
21883 }
21884 }
21885
21886 const wip_ty = switch (try ip.getStructType(gpa, .{
2184021887 .layout = layout,
21841 .known_non_opv = false,
2184221888 .fields_len = fields_len,
21889 .known_non_opv = false,
2184321890 .requires_comptime = .unknown,
2184421891 .is_tuple = is_tuple,
21845 // So that we don't have to scan ahead, we allocate space in the struct
21846 // type for alignments, comptime fields, and default inits. This might
21847 // result in wasted space, however, this is a permitted encoding of
21848 // struct types.
21849 .any_comptime_fields = true,
21850 .any_default_inits = true,
21892 .any_comptime_fields = any_comptime_fields,
21893 .any_default_inits = any_default_inits,
21894 .any_aligned_fields = any_aligned_fields,
2185121895 .inits_resolved = true,
21852 .any_aligned_fields = true,
21853 .captures = &.{},
21854 });
21855 // TODO: figure out InternPool removals for incremental compilation
21856 //errdefer ip.remove(ty);
21857 const struct_type = ip.loadStructType(ty);
21896 .has_namespace = false,
21897 .key = .{ .reified = .{
21898 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21899 .type_hash = hasher.final(),
21900 } },
21901 })) {
21902 .wip => |wip| wip,
21903 .existing => |ty| return Air.internedToRef(ty),
21904 };
21905 errdefer wip_ty.cancel(ip);
2185821906
21859 new_decl.ty = Type.type;
21860 new_decl.val = Value.fromInterned(ty);
21861
21862 // Fields
21863 for (0..fields_len) |i| {
21864 const elem_val = try fields_val.elemValue(mod, i);
21865 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21866 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21867 ip,
21868 try ip.getOrPutString(gpa, "name"),
21869 ).?);
21870 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21871 ip,
21872 try ip.getOrPutString(gpa, "type"),
21873 ).?);
21874 const default_value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21875 ip,
21876 try ip.getOrPutString(gpa, "default_value"),
21877 ).?);
21878 const is_comptime_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21879 ip,
21880 try ip.getOrPutString(gpa, "is_comptime"),
21881 ).?);
21882 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21883 ip,
21884 try ip.getOrPutString(gpa, "alignment"),
21885 ).?);
21886
21887 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
21888 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21889 }
21890 const abi_align = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
21891
21892 if (layout == .Packed) {
21893 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21894 if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
21895 } else {
21896 if (abi_align > 0 and !math.isPowerOfTwo(abi_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{abi_align});
21897 struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
21898 }
21899 if (layout == .Extern and is_comptime_val.toBool()) {
21900 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
21901 }
21907 if (is_tuple) switch (layout) {
21908 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
21909 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
21910 .Auto => {},
21911 };
21912
21913 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21914 .ty = Type.type,
21915 .val = Value.fromInterned(wip_ty.index),
21916 }, name_strategy, "struct", inst);
21917 mod.declPtr(new_decl_index).owns_tv = true;
21918 errdefer mod.abortAnonDecl(new_decl_index);
21919
21920 const struct_type = ip.loadStructType(wip_ty.index);
21921
21922 for (0..fields_len) |field_idx| {
21923 const field_info = try fields_val.elemValue(mod, field_idx);
2190221924
21903 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21925 const field_name_val = try field_info.fieldValue(mod, 0);
21926 const field_type_val = try field_info.fieldValue(mod, 1);
21927 const field_default_value_val = try field_info.fieldValue(mod, 2);
21928 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
21929 const field_alignment_val = try field_info.fieldValue(mod, 4);
2190421930
21931 const field_ty = field_type_val.toType();
21932 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
2190521933 if (is_tuple) {
21906 const field_index = field_name.toUnsigned(ip) orelse return sema.fail(
21934 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
2190721935 block,
2190821936 src,
2190921937 "tuple cannot have non-numeric field '{}'",
2191021938 .{field_name.fmt(ip)},
2191121939 );
21912
21913 if (field_index >= fields_len) {
21940 if (field_name_index != field_idx) {
2191421941 return sema.fail(
2191521942 block,
2191621943 src,
21917 "tuple field {} exceeds tuple field count",
21918 .{field_index},
21944 "tuple field name '{}' does not match field index {}",
21945 .{ field_name_index, field_idx },
2191921946 );
2192021947 }
2192121948 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
......@@ -21923,45 +21950,72 @@ fn reifyStruct(
2192321950 return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});
2192421951 }
2192521952
21926 const field_ty = type_val.toType();
21927 const default_val = if (default_value_val.optionalValue(mod)) |opt_val|
21928 (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse
21929 return sema.failWithNeededComptime(block, src, .{
21930 .needed_comptime_reason = "struct field default value must be comptime-known",
21931 })).toIntern()
21932 else
21933 .none;
21934 if (is_comptime_val.toBool() and default_val == .none) {
21953 if (any_aligned_fields) {
21954 if (!try sema.intFitsInType(field_alignment_val, Type.u32, null)) {
21955 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21956 }
21957
21958 const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema);
21959 if (byte_align == 0) {
21960 if (layout != .Packed) {
21961 struct_type.field_aligns.get(ip)[field_idx] = .none;
21962 }
21963 } else {
21964 if (layout == .Packed) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21965 if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21966 struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align);
21967 }
21968 }
21969
21970 const field_is_comptime = field_is_comptime_val.toBool();
21971 if (field_is_comptime) {
21972 assert(any_comptime_fields);
21973 switch (layout) {
21974 .Extern => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}),
21975 .Packed => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}),
21976 .Auto => struct_type.setFieldComptime(ip, field_idx),
21977 }
21978 }
21979
21980 const field_default: InternPool.Index = d: {
21981 if (!any_default_inits) break :d .none;
21982 const ptr_val = field_default_value_val.optionalValue(mod) orelse break :d .none;
21983 const ptr_ty = try mod.singleConstPtrType(field_ty);
21984 // Asserted comptime-dereferencable above.
21985 const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?;
21986 // We already resolved this for deduplication, so we may as well do it now.
21987 break :d (try sema.resolveLazyValue(val)).toIntern();
21988 };
21989
21990 if (field_is_comptime and field_default == .none) {
2193521991 return sema.fail(block, src, "comptime field without default initialization value", .{});
2193621992 }
2193721993
21938 struct_type.field_types.get(ip)[i] = field_ty.toIntern();
21939 struct_type.field_inits.get(ip)[i] = default_val;
21940 if (is_comptime_val.toBool())
21941 struct_type.setFieldComptime(ip, i);
21994 struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21995 if (field_default != .none) {
21996 struct_type.field_inits.get(ip)[field_idx] = field_default;
21997 }
2194221998
2194321999 if (field_ty.zigTypeTag(mod) == .Opaque) {
21944 const msg = msg: {
22000 return sema.failWithOwnedErrorMsg(block, msg: {
2194522001 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
2194622002 errdefer msg.destroy(gpa);
2194722003
2194822004 try sema.addDeclaredHereNote(msg, field_ty);
2194922005 break :msg msg;
21950 };
21951 return sema.failWithOwnedErrorMsg(block, msg);
22006 });
2195222007 }
2195322008 if (field_ty.zigTypeTag(mod) == .NoReturn) {
21954 const msg = msg: {
22009 return sema.failWithOwnedErrorMsg(block, msg: {
2195522010 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
2195622011 errdefer msg.destroy(gpa);
2195722012
2195822013 try sema.addDeclaredHereNote(msg, field_ty);
2195922014 break :msg msg;
21960 };
21961 return sema.failWithOwnedErrorMsg(block, msg);
22015 });
2196222016 }
2196322017 if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
21964 const msg = msg: {
22018 return sema.failWithOwnedErrorMsg(block, msg: {
2196522019 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2196622020 errdefer msg.destroy(gpa);
2196722021
......@@ -21970,10 +22024,9 @@ fn reifyStruct(
2197022024
2197122025 try sema.addDeclaredHereNote(msg, field_ty);
2197222026 break :msg msg;
21973 };
21974 return sema.failWithOwnedErrorMsg(block, msg);
22027 });
2197522028 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21976 const msg = msg: {
22029 return sema.failWithOwnedErrorMsg(block, msg: {
2197722030 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2197822031 errdefer msg.destroy(gpa);
2197922032
......@@ -21982,32 +22035,27 @@ fn reifyStruct(
2198222035
2198322036 try sema.addDeclaredHereNote(msg, field_ty);
2198422037 break :msg msg;
21985 };
21986 return sema.failWithOwnedErrorMsg(block, msg);
22038 });
2198722039 }
2198822040 }
2198922041
2199022042 if (layout == .Packed) {
21991 for (0..struct_type.field_types.len) |index| {
21992 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
22043 var fields_bit_sum: u64 = 0;
22044 for (0..struct_type.field_types.len) |field_idx| {
22045 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]);
2199322046 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
2199422047 error.AnalysisFail => {
2199522048 const msg = sema.err orelse return err;
21996 try sema.addFieldErrNote(Type.fromInterned(ty), index, msg, "while checking this field", .{});
22049 try sema.errNote(block, src, msg, "while checking a field of this struct", .{});
2199722050 return err;
2199822051 },
2199922052 else => return err,
2200022053 };
22001 }
22002
22003 var fields_bit_sum: u64 = 0;
22004 for (0..struct_type.field_types.len) |i| {
22005 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
2200622054 fields_bit_sum += field_ty.bitSize(mod);
2200722055 }
2200822056
22009 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
22010 const backing_int_ty = backing_int_ty_val.toType();
22057 if (opt_backing_int_val.optionalValue(mod)) |backing_int_val| {
22058 const backing_int_ty = backing_int_val.toType();
2201122059 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
2201222060 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
2201322061 } else {
......@@ -22016,9 +22064,8 @@ fn reifyStruct(
2201622064 }
2201722065 }
2201822066
22019 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
2202022067 try mod.finalizeAnonDecl(new_decl_index);
22021 return decl_val;
22068 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2202222069}
2202322070
2202422071fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -36963,8 +37010,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3696337010 const gpa = mod.gpa;
3696437011 const ip = &mod.intern_pool;
3696537012 const decl_index = union_type.decl;
36966 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
36967 const zir_index = union_type.zir_index.unwrap().?.resolve(ip);
37013 const zir = mod.namespacePtr(union_type.namespace.unwrap().?).file_scope.zir;
37014 const zir_index = union_type.zir_index.resolve(ip);
3696837015 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3696937016 assert(extended.opcode == .union_decl);
3697037017 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
......@@ -37037,7 +37084,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3703737084 .parent = null,
3703837085 .sema = &sema,
3703937086 .src_decl = decl_index,
37040 .namespace = union_type.namespace,
37087 .namespace = union_type.namespace.unwrap().?,
3704137088 .instructions = .{},
3704237089 .inlining = null,
3704337090 .is_comptime = true,
......@@ -37357,7 +37404,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3735737404 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
3735837405 union_type.tagTypePtr(ip).* = enum_ty;
3735937406 } else {
37360 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_type.decl.toOptional());
37407 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
3736137408 union_type.tagTypePtr(ip).* = enum_ty;
3736237409 }
3736337410}
......@@ -37374,7 +37421,7 @@ fn generateUnionTagTypeNumbered(
3737437421 block: *Block,
3737537422 enum_field_names: []const InternPool.NullTerminatedString,
3737637423 enum_field_vals: []const InternPool.Index,
37377 decl: *Module.Decl,
37424 union_owner_decl: *Module.Decl,
3737837425) !InternPool.Index {
3737937426 const mod = sema.mod;
3738037427 const gpa = sema.gpa;
......@@ -37383,7 +37430,7 @@ fn generateUnionTagTypeNumbered(
3738337430 const src_decl = mod.declPtr(block.src_decl);
3738437431 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
3738537432 errdefer mod.destroyDecl(new_decl_index);
37386 const fqn = try decl.fullyQualifiedName(mod);
37433 const fqn = try union_owner_decl.fullyQualifiedName(mod);
3738737434 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
3738837435 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
3738937436 .ty = Type.noreturn,
......@@ -37395,9 +37442,9 @@ fn generateUnionTagTypeNumbered(
3739537442 new_decl.owns_tv = true;
3739637443 new_decl.name_fully_qualified = true;
3739737444
37398 const enum_ty = try ip.getEnum(gpa, .{
37445 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
3739937446 .decl = new_decl_index,
37400 .namespace = .none,
37447 .owner_union_ty = union_owner_decl.val.toIntern(),
3740137448 .tag_ty = if (enum_field_vals.len == 0)
3740237449 (try mod.intType(.unsigned, 0)).toIntern()
3740337450 else
......@@ -37405,8 +37452,6 @@ fn generateUnionTagTypeNumbered(
3740537452 .names = enum_field_names,
3740637453 .values = enum_field_vals,
3740737454 .tag_mode = .explicit,
37408 .zir_index = .none,
37409 .captures = &.{},
3741037455 });
3741137456
3741237457 new_decl.ty = Type.type;
......@@ -37420,20 +37465,14 @@ fn generateUnionTagTypeSimple(
3742037465 sema: *Sema,
3742137466 block: *Block,
3742237467 enum_field_names: []const InternPool.NullTerminatedString,
37423 maybe_decl_index: InternPool.OptionalDeclIndex,
37468 union_owner_decl: *Module.Decl,
3742437469) !InternPool.Index {
3742537470 const mod = sema.mod;
3742637471 const ip = &mod.intern_pool;
3742737472 const gpa = sema.gpa;
3742837473
3742937474 const new_decl_index = new_decl_index: {
37430 const decl_index = maybe_decl_index.unwrap() orelse {
37431 break :new_decl_index try mod.createAnonymousDecl(block, .{
37432 .ty = Type.noreturn,
37433 .val = Value.@"unreachable",
37434 });
37435 };
37436 const fqn = try mod.declPtr(decl_index).fullyQualifiedName(mod);
37475 const fqn = try union_owner_decl.fullyQualifiedName(mod);
3743737476 const src_decl = mod.declPtr(block.src_decl);
3743837477 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
3743937478 errdefer mod.destroyDecl(new_decl_index);
......@@ -37447,9 +37486,9 @@ fn generateUnionTagTypeSimple(
3744737486 };
3744837487 errdefer mod.abortAnonDecl(new_decl_index);
3744937488
37450 const enum_ty = try ip.getEnum(gpa, .{
37489 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
3745137490 .decl = new_decl_index,
37452 .namespace = .none,
37491 .owner_union_ty = union_owner_decl.val.toIntern(),
3745337492 .tag_ty = if (enum_field_names.len == 0)
3745437493 (try mod.intType(.unsigned, 0)).toIntern()
3745537494 else
......@@ -37457,8 +37496,6 @@ fn generateUnionTagTypeSimple(
3745737496 .names = enum_field_names,
3745837497 .values = &.{},
3745937498 .tag_mode = .auto,
37460 .zir_index = .none,
37461 .captures = &.{},
3746237499 });
3746337500
3746437501 const new_decl = mod.declPtr(new_decl_index);
......@@ -37643,6 +37680,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3764337680 => unreachable,
3764437681
3764537682 _ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
37683 .removed => unreachable,
37684
3764637685 .type_int_signed, // i0 handled above
3764737686 .type_int_unsigned, // u0 handled above
3764837687 .type_pointer,
src/codegen/llvm.zig+3-4
......@@ -3548,12 +3548,11 @@ pub const Object = struct {
35483548 );
35493549 return ty;
35503550 },
3551 .opaque_type => |opaque_type| {
3551 .opaque_type => {
35523552 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
35533553 if (!gop.found_existing) {
3554 const name = try o.builder.string(ip.stringToSlice(
3555 try mod.opaqueFullyQualifiedName(opaque_type),
3556 ));
3554 const decl = mod.declPtr(ip.loadOpaqueType(t.toIntern()).decl);
3555 const name = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
35573556 gop.value_ptr.* = try o.builder.opaqueType(name);
35583557 }
35593558 return gop.value_ptr.*;
src/type.zig+18-26
......@@ -355,16 +355,16 @@ pub const Type = struct {
355355 try writer.writeAll("}");
356356 },
357357
358 .union_type => |union_type| {
359 const decl = mod.declPtr(union_type.decl);
358 .union_type => {
359 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
360360 try decl.renderFullyQualifiedName(mod, writer);
361361 },
362 .opaque_type => |opaque_type| {
363 const decl = mod.declPtr(opaque_type.decl);
362 .opaque_type => {
363 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
364364 try decl.renderFullyQualifiedName(mod, writer);
365365 },
366 .enum_type => |enum_type| {
367 const decl = mod.declPtr(enum_type.decl);
366 .enum_type => {
367 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
368368 try decl.renderFullyQualifiedName(mod, writer);
369369 },
370370 .func_type => |fn_info| {
......@@ -2845,9 +2845,9 @@ pub const Type = struct {
28452845 pub fn getNamespaceIndex(ty: Type, mod: *Module) InternPool.OptionalNamespaceIndex {
28462846 const ip = &mod.intern_pool;
28472847 return switch (ip.indexToKey(ty.toIntern())) {
2848 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(),
2848 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
28492849 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2850 .union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(),
2850 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
28512851 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
28522852
28532853 else => .none,
......@@ -3180,17 +3180,8 @@ pub const Type = struct {
31803180 }
31813181
31823182 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
3183 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3184 .struct_type => |struct_type| {
3185 return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod);
3186 },
3187 .union_type => |union_type| {
3188 return mod.declPtr(union_type.decl).srcLoc(mod);
3189 },
3190 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
3191 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),
3192 else => null,
3193 };
3183 const decl = ty.getOwnerDeclOrNull(mod) orelse return null;
3184 return mod.declPtr(decl).srcLoc(mod);
31943185 }
31953186
31963187 pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
......@@ -3198,11 +3189,12 @@ pub const Type = struct {
31983189 }
31993190
32003191 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3201 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3202 .struct_type => |struct_type| struct_type.decl.unwrap(),
3203 .union_type => |union_type| union_type.decl,
3204 .opaque_type => |opaque_type| opaque_type.decl,
3205 .enum_type => |enum_type| enum_type.decl,
3192 const ip = &mod.intern_pool;
3193 return switch (ip.indexToKey(ty.toIntern())) {
3194 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3195 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3196 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3197 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
32063198 else => null,
32073199 };
32083200 }
......@@ -3287,9 +3279,9 @@ pub const Type = struct {
32873279 const ip = &zcu.intern_pool;
32883280 return switch (ip.indexToKey(ty.toIntern())) {
32893281 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3290 .union_type => ip.loadUnionType(ty.toIntern()).zir_index.unwrap(),
3282 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
32913283 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3292 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index.unwrap(),
3284 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
32933285 else => null,
32943286 };
32953287 }