zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 038f53f1 (88453B) - Raw


      1 const std = @import("std");
      2 const cstr = std.cstr;
      3 const mem = std.mem;
      4 const Allocator = mem.Allocator;
      5 const assert = std.debug.assert;
      6 const autoHash = std.hash.autoHash;
      7 const Target = std.Target;
      8 
      9 const Module = @import("../../Module.zig");
     10 const Type = @import("../../type.zig").Type;
     11 
     12 pub const CType = extern union {
     13     /// If the tag value is less than Tag.no_payload_count, then no pointer
     14     /// dereference is needed.
     15     tag_if_small_enough: Tag,
     16     ptr_otherwise: *const Payload,
     17 
     18     pub fn initTag(small_tag: Tag) CType {
     19         assert(!small_tag.hasPayload());
     20         return .{ .tag_if_small_enough = small_tag };
     21     }
     22 
     23     pub fn initPayload(pl: anytype) CType {
     24         const T = @typeInfo(@TypeOf(pl)).Pointer.child;
     25         return switch (pl.base.tag) {
     26             inline else => |t| if (comptime t.hasPayload() and t.Type() == T) .{
     27                 .ptr_otherwise = &pl.base,
     28             } else unreachable,
     29         };
     30     }
     31 
     32     pub fn hasPayload(self: CType) bool {
     33         return self.tag_if_small_enough.hasPayload();
     34     }
     35 
     36     pub fn tag(self: CType) Tag {
     37         return if (self.hasPayload()) self.ptr_otherwise.tag else self.tag_if_small_enough;
     38     }
     39 
     40     pub fn cast(self: CType, comptime T: type) ?*const T {
     41         if (!self.hasPayload()) return null;
     42         const pl = self.ptr_otherwise;
     43         return switch (pl.tag) {
     44             inline else => |t| if (comptime t.hasPayload() and t.Type() == T)
     45                 @fieldParentPtr(T, "base", pl)
     46             else
     47                 null,
     48         };
     49     }
     50 
     51     pub fn castTag(self: CType, comptime t: Tag) ?*const t.Type() {
     52         return if (self.tag() == t) @fieldParentPtr(t.Type(), "base", self.ptr_otherwise) else null;
     53     }
     54 
     55     pub const Tag = enum(usize) {
     56         // The first section of this enum are tags that require no payload.
     57         void,
     58 
     59         // C basic types
     60         char,
     61 
     62         @"signed char",
     63         short,
     64         int,
     65         long,
     66         @"long long",
     67 
     68         _Bool,
     69         @"unsigned char",
     70         @"unsigned short",
     71         @"unsigned int",
     72         @"unsigned long",
     73         @"unsigned long long",
     74 
     75         float,
     76         double,
     77         @"long double",
     78 
     79         // C header types
     80         //  - stdbool.h
     81         bool,
     82         //  - stddef.h
     83         size_t,
     84         ptrdiff_t,
     85         //  - stdint.h
     86         uint8_t,
     87         int8_t,
     88         uint16_t,
     89         int16_t,
     90         uint32_t,
     91         int32_t,
     92         uint64_t,
     93         int64_t,
     94         uintptr_t,
     95         intptr_t,
     96 
     97         // zig.h types
     98         zig_u128,
     99         zig_i128,
    100         zig_f16,
    101         zig_f32,
    102         zig_f64,
    103         zig_f80,
    104         zig_f128,
    105         zig_c_longdouble, // Keep last_no_payload_tag updated!
    106 
    107         // After this, the tag requires a payload.
    108         pointer,
    109         pointer_const,
    110         pointer_volatile,
    111         pointer_const_volatile,
    112         array,
    113         vector,
    114         fwd_anon_struct,
    115         fwd_anon_union,
    116         fwd_struct,
    117         fwd_union,
    118         unnamed_struct,
    119         unnamed_union,
    120         packed_unnamed_struct,
    121         packed_unnamed_union,
    122         anon_struct,
    123         anon_union,
    124         @"struct",
    125         @"union",
    126         packed_struct,
    127         packed_union,
    128         function,
    129         varargs_function,
    130 
    131         pub const last_no_payload_tag = Tag.zig_c_longdouble;
    132         pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
    133 
    134         pub fn hasPayload(self: Tag) bool {
    135             return @enumToInt(self) >= no_payload_count;
    136         }
    137 
    138         pub fn toIndex(self: Tag) Index {
    139             assert(!self.hasPayload());
    140             return @intCast(Index, @enumToInt(self));
    141         }
    142 
    143         pub fn Type(comptime self: Tag) type {
    144             return switch (self) {
    145                 .void,
    146                 .char,
    147                 .@"signed char",
    148                 .short,
    149                 .int,
    150                 .long,
    151                 .@"long long",
    152                 ._Bool,
    153                 .@"unsigned char",
    154                 .@"unsigned short",
    155                 .@"unsigned int",
    156                 .@"unsigned long",
    157                 .@"unsigned long long",
    158                 .float,
    159                 .double,
    160                 .@"long double",
    161                 .bool,
    162                 .size_t,
    163                 .ptrdiff_t,
    164                 .uint8_t,
    165                 .int8_t,
    166                 .uint16_t,
    167                 .int16_t,
    168                 .uint32_t,
    169                 .int32_t,
    170                 .uint64_t,
    171                 .int64_t,
    172                 .uintptr_t,
    173                 .intptr_t,
    174                 .zig_u128,
    175                 .zig_i128,
    176                 .zig_f16,
    177                 .zig_f32,
    178                 .zig_f64,
    179                 .zig_f80,
    180                 .zig_f128,
    181                 .zig_c_longdouble,
    182                 => @compileError("Type Tag " ++ @tagName(self) ++ " has no payload"),
    183 
    184                 .pointer,
    185                 .pointer_const,
    186                 .pointer_volatile,
    187                 .pointer_const_volatile,
    188                 => Payload.Child,
    189 
    190                 .array,
    191                 .vector,
    192                 => Payload.Sequence,
    193 
    194                 .fwd_anon_struct,
    195                 .fwd_anon_union,
    196                 => Payload.Fields,
    197 
    198                 .fwd_struct,
    199                 .fwd_union,
    200                 => Payload.FwdDecl,
    201 
    202                 .unnamed_struct,
    203                 .unnamed_union,
    204                 .packed_unnamed_struct,
    205                 .packed_unnamed_union,
    206                 => Payload.Unnamed,
    207 
    208                 .anon_struct,
    209                 .anon_union,
    210                 .@"struct",
    211                 .@"union",
    212                 .packed_struct,
    213                 .packed_union,
    214                 => Payload.Aggregate,
    215 
    216                 .function,
    217                 .varargs_function,
    218                 => Payload.Function,
    219             };
    220         }
    221     };
    222 
    223     pub const Payload = struct {
    224         tag: Tag,
    225 
    226         pub const Child = struct {
    227             base: Payload,
    228             data: Index,
    229         };
    230 
    231         pub const Sequence = struct {
    232             base: Payload,
    233             data: struct {
    234                 len: u64,
    235                 elem_type: Index,
    236             },
    237         };
    238 
    239         pub const FwdDecl = struct {
    240             base: Payload,
    241             data: Module.Decl.Index,
    242         };
    243 
    244         pub const Fields = struct {
    245             base: Payload,
    246             data: Data,
    247 
    248             pub const Data = []const Field;
    249             pub const Field = struct {
    250                 name: [*:0]const u8,
    251                 type: Index,
    252                 alignas: AlignAs,
    253             };
    254         };
    255 
    256         pub const Unnamed = struct {
    257             base: Payload,
    258             data: struct {
    259                 fields: Fields.Data,
    260                 owner_decl: Module.Decl.Index,
    261                 id: u32,
    262             },
    263         };
    264 
    265         pub const Aggregate = struct {
    266             base: Payload,
    267             data: struct {
    268                 fields: Fields.Data,
    269                 fwd_decl: Index,
    270             },
    271         };
    272 
    273         pub const Function = struct {
    274             base: Payload,
    275             data: struct {
    276                 return_type: Index,
    277                 param_types: []const Index,
    278             },
    279         };
    280     };
    281 
    282     pub const AlignAs = struct {
    283         @"align": std.math.Log2Int(u32),
    284         abi: std.math.Log2Int(u32),
    285 
    286         pub fn init(alignment: u32, abi_alignment: u32) AlignAs {
    287             const actual_align = if (alignment != 0) alignment else abi_alignment;
    288             assert(std.math.isPowerOfTwo(actual_align));
    289             assert(std.math.isPowerOfTwo(abi_alignment));
    290             return .{
    291                 .@"align" = std.math.log2_int(u32, actual_align),
    292                 .abi = std.math.log2_int(u32, abi_alignment),
    293             };
    294         }
    295         pub fn abiAlign(ty: Type, target: Target) AlignAs {
    296             const abi_align = ty.abiAlignment(target);
    297             return init(abi_align, abi_align);
    298         }
    299         pub fn fieldAlign(struct_ty: Type, field_i: usize, target: Target) AlignAs {
    300             return init(
    301                 struct_ty.structFieldAlign(field_i, target),
    302                 struct_ty.structFieldType(field_i).abiAlignment(target),
    303             );
    304         }
    305         pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs {
    306             const union_obj = union_ty.cast(Type.Payload.Union).?.data;
    307             const union_payload_align = union_obj.abiAlignment(target, false);
    308             return init(union_payload_align, union_payload_align);
    309         }
    310 
    311         pub fn getAlign(self: AlignAs) u32 {
    312             return @as(u32, 1) << self.@"align";
    313         }
    314     };
    315 
    316     pub const Index = u32;
    317     pub const Store = struct {
    318         arena: std.heap.ArenaAllocator.State = .{},
    319         set: Set = .{},
    320 
    321         pub const Set = struct {
    322             pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext, true);
    323             const HashContext = struct {
    324                 store: *const Set,
    325 
    326                 pub fn hash(self: @This(), cty: CType) Map.Hash {
    327                     return @truncate(Map.Hash, cty.hash(self.store.*));
    328                 }
    329                 pub fn eql(_: @This(), lhs: CType, rhs: CType, _: usize) bool {
    330                     return lhs.eql(rhs);
    331                 }
    332             };
    333 
    334             map: Map = .{},
    335 
    336             pub fn indexToCType(self: Set, index: Index) CType {
    337                 if (index < Tag.no_payload_count) return initTag(@intToEnum(Tag, index));
    338                 return self.map.keys()[index - Tag.no_payload_count];
    339             }
    340 
    341             pub fn indexToHash(self: Set, index: Index) Map.Hash {
    342                 if (index < Tag.no_payload_count)
    343                     return (HashContext{ .store = &self }).hash(self.indexToCType(index));
    344                 return self.map.entries.items(.hash)[index - Tag.no_payload_count];
    345             }
    346 
    347             pub fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {
    348                 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } };
    349 
    350                 var convert: Convert = undefined;
    351                 convert.initType(ty, kind, lookup) catch unreachable;
    352 
    353                 const t = convert.tag();
    354                 if (!t.hasPayload()) return t.toIndex();
    355 
    356                 return if (self.map.getIndexAdapted(
    357                     ty,
    358                     TypeAdapter32{ .kind = kind, .lookup = lookup, .convert = &convert },
    359                 )) |idx| @intCast(Index, Tag.no_payload_count + idx) else null;
    360             }
    361         };
    362 
    363         pub const Promoted = struct {
    364             arena: std.heap.ArenaAllocator,
    365             set: Set,
    366 
    367             pub fn gpa(self: *Promoted) Allocator {
    368                 return self.arena.child_allocator;
    369             }
    370 
    371             pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
    372                 const t = cty.tag();
    373                 if (@enumToInt(t) < Tag.no_payload_count) return @intCast(Index, @enumToInt(t));
    374 
    375                 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
    376                 if (!gop.found_existing) gop.key_ptr.* = cty;
    377                 if (std.debug.runtime_safety) {
    378                     const key = &self.set.map.entries.items(.key)[gop.index];
    379                     assert(key == gop.key_ptr);
    380                     assert(cty.eql(key.*));
    381                     assert(cty.hash(self.set) == key.hash(self.set));
    382                 }
    383                 return @intCast(Index, Tag.no_payload_count + gop.index);
    384             }
    385 
    386             pub fn typeToIndex(
    387                 self: *Promoted,
    388                 ty: Type,
    389                 mod: *Module,
    390                 kind: Kind,
    391             ) Allocator.Error!Index {
    392                 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .mod = mod } };
    393 
    394                 var convert: Convert = undefined;
    395                 try convert.initType(ty, kind, lookup);
    396 
    397                 const t = convert.tag();
    398                 if (!t.hasPayload()) return t.toIndex();
    399 
    400                 const gop = try self.set.map.getOrPutContextAdapted(
    401                     self.gpa(),
    402                     ty,
    403                     TypeAdapter32{ .kind = kind, .lookup = lookup.freeze(), .convert = &convert },
    404                     .{ .store = &self.set },
    405                 );
    406                 if (!gop.found_existing) {
    407                     errdefer _ = self.set.map.pop();
    408                     gop.key_ptr.* = try createFromConvert(self, ty, lookup.getTarget(), kind, convert);
    409                 }
    410                 if (std.debug.runtime_safety) {
    411                     const adapter = TypeAdapter64{
    412                         .kind = kind,
    413                         .lookup = lookup.freeze(),
    414                         .convert = &convert,
    415                     };
    416                     const cty = &self.set.map.entries.items(.key)[gop.index];
    417                     assert(cty == gop.key_ptr);
    418                     assert(adapter.eql(ty, cty.*));
    419                     assert(adapter.hash(ty) == cty.hash(self.set));
    420                 }
    421                 return @intCast(Index, Tag.no_payload_count + gop.index);
    422             }
    423         };
    424 
    425         pub fn promote(self: Store, gpa: Allocator) Promoted {
    426             return .{ .arena = self.arena.promote(gpa), .set = self.set };
    427         }
    428 
    429         pub fn demote(self: *Store, promoted: Promoted) void {
    430             self.arena = promoted.arena.state;
    431             self.set = promoted.set;
    432         }
    433 
    434         pub fn indexToCType(self: Store, index: Index) CType {
    435             return self.set.indexToCType(index);
    436         }
    437 
    438         pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
    439             return self.set.indexToHash(index);
    440         }
    441 
    442         pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
    443             var promoted = self.promote(gpa);
    444             defer self.demote(promoted);
    445             return promoted.cTypeToIndex(cty);
    446         }
    447 
    448         pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !CType {
    449             const idx = try self.typeToIndex(gpa, ty, mod, kind);
    450             return self.indexToCType(idx);
    451         }
    452 
    453         pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !Index {
    454             var promoted = self.promote(gpa);
    455             defer self.demote(promoted);
    456             return promoted.typeToIndex(ty, mod, kind);
    457         }
    458 
    459         pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
    460             var promoted = self.promote(gpa);
    461             defer self.demote(promoted);
    462             promoted.set.map.clearRetainingCapacity();
    463             _ = promoted.arena.reset(.retain_capacity);
    464         }
    465 
    466         pub fn clearAndFree(self: *Store, gpa: Allocator) void {
    467             var promoted = self.promote(gpa);
    468             defer self.demote(promoted);
    469             promoted.set.map.clearAndFree(gpa);
    470             _ = promoted.arena.reset(.free_all);
    471         }
    472 
    473         pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
    474             self.set.map.shrinkRetainingCapacity(gpa, new_len);
    475         }
    476 
    477         pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
    478             self.set.map.shrinkAndFree(gpa, new_len);
    479         }
    480 
    481         pub fn count(self: Store) usize {
    482             return self.set.map.count();
    483         }
    484 
    485         pub fn move(self: *Store) Store {
    486             const moved = self.*;
    487             self.* = .{};
    488             return moved;
    489         }
    490 
    491         pub fn deinit(self: *Store, gpa: Allocator) void {
    492             var promoted = self.promote(gpa);
    493             promoted.set.map.deinit(gpa);
    494             _ = promoted.arena.deinit();
    495             self.* = undefined;
    496         }
    497     };
    498 
    499     pub fn isBool(self: CType) bool {
    500         return switch (self.tag()) {
    501             ._Bool,
    502             .bool,
    503             => true,
    504             else => false,
    505         };
    506     }
    507 
    508     pub fn isInteger(self: CType) bool {
    509         return switch (self.tag()) {
    510             .char,
    511             .@"signed char",
    512             .short,
    513             .int,
    514             .long,
    515             .@"long long",
    516             .@"unsigned char",
    517             .@"unsigned short",
    518             .@"unsigned int",
    519             .@"unsigned long",
    520             .@"unsigned long long",
    521             .size_t,
    522             .ptrdiff_t,
    523             .uint8_t,
    524             .int8_t,
    525             .uint16_t,
    526             .int16_t,
    527             .uint32_t,
    528             .int32_t,
    529             .uint64_t,
    530             .int64_t,
    531             .uintptr_t,
    532             .intptr_t,
    533             .zig_u128,
    534             .zig_i128,
    535             => true,
    536             else => false,
    537         };
    538     }
    539 
    540     pub fn signedness(self: CType) ?std.builtin.Signedness {
    541         return switch (self.tag()) {
    542             .char => null, // unknown signedness
    543             .@"signed char",
    544             .short,
    545             .int,
    546             .long,
    547             .@"long long",
    548             .ptrdiff_t,
    549             .int8_t,
    550             .int16_t,
    551             .int32_t,
    552             .int64_t,
    553             .intptr_t,
    554             .zig_i128,
    555             => .signed,
    556             .@"unsigned char",
    557             .@"unsigned short",
    558             .@"unsigned int",
    559             .@"unsigned long",
    560             .@"unsigned long long",
    561             .size_t,
    562             .uint8_t,
    563             .uint16_t,
    564             .uint32_t,
    565             .uint64_t,
    566             .uintptr_t,
    567             .zig_u128,
    568             => .unsigned,
    569             else => unreachable,
    570         };
    571     }
    572 
    573     pub fn isFloat(self: CType) bool {
    574         return switch (self.tag()) {
    575             .float,
    576             .double,
    577             .@"long double",
    578             .zig_f16,
    579             .zig_f32,
    580             .zig_f64,
    581             .zig_f80,
    582             .zig_f128,
    583             .zig_c_longdouble,
    584             => true,
    585             else => false,
    586         };
    587     }
    588 
    589     pub fn isPointer(self: CType) bool {
    590         return switch (self.tag()) {
    591             .pointer,
    592             .pointer_const,
    593             .pointer_volatile,
    594             .pointer_const_volatile,
    595             => true,
    596             else => false,
    597         };
    598     }
    599 
    600     pub fn isFunction(self: CType) bool {
    601         return switch (self.tag()) {
    602             .function,
    603             .varargs_function,
    604             => true,
    605             else => false,
    606         };
    607     }
    608 
    609     pub fn toSigned(self: CType) CType {
    610         return CType.initTag(switch (self.tag()) {
    611             .char, .@"signed char", .@"unsigned char" => .@"signed char",
    612             .short, .@"unsigned short" => .short,
    613             .int, .@"unsigned int" => .int,
    614             .long, .@"unsigned long" => .long,
    615             .@"long long", .@"unsigned long long" => .@"long long",
    616             .size_t, .ptrdiff_t => .ptrdiff_t,
    617             .uint8_t, .int8_t => .int8_t,
    618             .uint16_t, .int16_t => .int16_t,
    619             .uint32_t, .int32_t => .int32_t,
    620             .uint64_t, .int64_t => .int64_t,
    621             .uintptr_t, .intptr_t => .intptr_t,
    622             .zig_u128, .zig_i128 => .zig_i128,
    623             .float,
    624             .double,
    625             .@"long double",
    626             .zig_f16,
    627             .zig_f32,
    628             .zig_f80,
    629             .zig_f128,
    630             .zig_c_longdouble,
    631             => |t| t,
    632             else => unreachable,
    633         });
    634     }
    635 
    636     pub fn toUnsigned(self: CType) CType {
    637         return CType.initTag(switch (self.tag()) {
    638             .char, .@"signed char", .@"unsigned char" => .@"unsigned char",
    639             .short, .@"unsigned short" => .@"unsigned short",
    640             .int, .@"unsigned int" => .@"unsigned int",
    641             .long, .@"unsigned long" => .@"unsigned long",
    642             .@"long long", .@"unsigned long long" => .@"unsigned long long",
    643             .size_t, .ptrdiff_t => .size_t,
    644             .uint8_t, .int8_t => .uint8_t,
    645             .uint16_t, .int16_t => .uint16_t,
    646             .uint32_t, .int32_t => .uint32_t,
    647             .uint64_t, .int64_t => .uint64_t,
    648             .uintptr_t, .intptr_t => .uintptr_t,
    649             .zig_u128, .zig_i128 => .zig_u128,
    650             else => unreachable,
    651         });
    652     }
    653 
    654     pub fn toSignedness(self: CType, s: std.builtin.Signedness) CType {
    655         return switch (s) {
    656             .unsigned => self.toUnsigned(),
    657             .signed => self.toSigned(),
    658         };
    659     }
    660 
    661     pub fn getStandardDefineAbbrev(self: CType) ?[]const u8 {
    662         return switch (self.tag()) {
    663             .char => "CHAR",
    664             .@"signed char" => "SCHAR",
    665             .short => "SHRT",
    666             .int => "INT",
    667             .long => "LONG",
    668             .@"long long" => "LLONG",
    669             .@"unsigned char" => "UCHAR",
    670             .@"unsigned short" => "USHRT",
    671             .@"unsigned int" => "UINT",
    672             .@"unsigned long" => "ULONG",
    673             .@"unsigned long long" => "ULLONG",
    674             .float => "FLT",
    675             .double => "DBL",
    676             .@"long double" => "LDBL",
    677             .size_t => "SIZE",
    678             .ptrdiff_t => "PTRDIFF",
    679             .uint8_t => "UINT8",
    680             .int8_t => "INT8",
    681             .uint16_t => "UINT16",
    682             .int16_t => "INT16",
    683             .uint32_t => "UINT32",
    684             .int32_t => "INT32",
    685             .uint64_t => "UINT64",
    686             .int64_t => "INT64",
    687             .uintptr_t => "UINTPTR",
    688             .intptr_t => "INTPTR",
    689             else => null,
    690         };
    691     }
    692 
    693     pub fn renderLiteralPrefix(self: CType, writer: anytype, kind: Kind) @TypeOf(writer).Error!void {
    694         switch (self.tag()) {
    695             .void => unreachable,
    696             ._Bool,
    697             .char,
    698             .@"signed char",
    699             .short,
    700             .@"unsigned short",
    701             .bool,
    702             .size_t,
    703             .ptrdiff_t,
    704             .uintptr_t,
    705             .intptr_t,
    706             => |t| switch (kind) {
    707                 else => try writer.print("({s})", .{@tagName(t)}),
    708                 .global => {},
    709             },
    710             .int,
    711             .long,
    712             .@"long long",
    713             .@"unsigned char",
    714             .@"unsigned int",
    715             .@"unsigned long",
    716             .@"unsigned long long",
    717             .float,
    718             .double,
    719             .@"long double",
    720             => {},
    721             .uint8_t,
    722             .int8_t,
    723             .uint16_t,
    724             .int16_t,
    725             .uint32_t,
    726             .int32_t,
    727             .uint64_t,
    728             .int64_t,
    729             => try writer.print("{s}_C(", .{self.getStandardDefineAbbrev().?}),
    730             .zig_u128,
    731             .zig_i128,
    732             .zig_f16,
    733             .zig_f32,
    734             .zig_f64,
    735             .zig_f80,
    736             .zig_f128,
    737             .zig_c_longdouble,
    738             => |t| try writer.print("zig_{s}_{s}(", .{
    739                 switch (kind) {
    740                     else => "make",
    741                     .global => "init",
    742                 },
    743                 @tagName(t)["zig_".len..],
    744             }),
    745             .pointer,
    746             .pointer_const,
    747             .pointer_volatile,
    748             .pointer_const_volatile,
    749             => unreachable,
    750             .array,
    751             .vector,
    752             => try writer.writeByte('{'),
    753             .fwd_anon_struct,
    754             .fwd_anon_union,
    755             .fwd_struct,
    756             .fwd_union,
    757             .unnamed_struct,
    758             .unnamed_union,
    759             .packed_unnamed_struct,
    760             .packed_unnamed_union,
    761             .anon_struct,
    762             .anon_union,
    763             .@"struct",
    764             .@"union",
    765             .packed_struct,
    766             .packed_union,
    767             .function,
    768             .varargs_function,
    769             => unreachable,
    770         }
    771     }
    772 
    773     pub fn renderLiteralSuffix(self: CType, writer: anytype) @TypeOf(writer).Error!void {
    774         switch (self.tag()) {
    775             .void => unreachable,
    776             ._Bool => {},
    777             .char,
    778             .@"signed char",
    779             .short,
    780             .int,
    781             => {},
    782             .long => try writer.writeByte('l'),
    783             .@"long long" => try writer.writeAll("ll"),
    784             .@"unsigned char",
    785             .@"unsigned short",
    786             .@"unsigned int",
    787             => try writer.writeByte('u'),
    788             .@"unsigned long",
    789             .size_t,
    790             .uintptr_t,
    791             => try writer.writeAll("ul"),
    792             .@"unsigned long long" => try writer.writeAll("ull"),
    793             .float => try writer.writeByte('f'),
    794             .double => {},
    795             .@"long double" => try writer.writeByte('l'),
    796             .bool,
    797             .ptrdiff_t,
    798             .intptr_t,
    799             => {},
    800             .uint8_t,
    801             .int8_t,
    802             .uint16_t,
    803             .int16_t,
    804             .uint32_t,
    805             .int32_t,
    806             .uint64_t,
    807             .int64_t,
    808             .zig_u128,
    809             .zig_i128,
    810             .zig_f16,
    811             .zig_f32,
    812             .zig_f64,
    813             .zig_f80,
    814             .zig_f128,
    815             .zig_c_longdouble,
    816             => try writer.writeByte(')'),
    817             .pointer,
    818             .pointer_const,
    819             .pointer_volatile,
    820             .pointer_const_volatile,
    821             => unreachable,
    822             .array,
    823             .vector,
    824             => try writer.writeByte('}'),
    825             .fwd_anon_struct,
    826             .fwd_anon_union,
    827             .fwd_struct,
    828             .fwd_union,
    829             .unnamed_struct,
    830             .unnamed_union,
    831             .packed_unnamed_struct,
    832             .packed_unnamed_union,
    833             .anon_struct,
    834             .anon_union,
    835             .@"struct",
    836             .@"union",
    837             .packed_struct,
    838             .packed_union,
    839             .function,
    840             .varargs_function,
    841             => unreachable,
    842         }
    843     }
    844 
    845     pub fn floatActiveBits(self: CType, target: Target) u16 {
    846         return switch (self.tag()) {
    847             .float => target.c_type_bit_size(.float),
    848             .double => target.c_type_bit_size(.double),
    849             .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
    850             .zig_f16 => 16,
    851             .zig_f32 => 32,
    852             .zig_f64 => 64,
    853             .zig_f80 => 80,
    854             .zig_f128 => 128,
    855             else => unreachable,
    856         };
    857     }
    858 
    859     pub fn byteSize(self: CType, store: Store.Set, target: Target) u64 {
    860         return switch (self.tag()) {
    861             .void => 0,
    862             .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
    863             .short => target.c_type_byte_size(.short),
    864             .int => target.c_type_byte_size(.int),
    865             .long => target.c_type_byte_size(.long),
    866             .@"long long" => target.c_type_byte_size(.longlong),
    867             .@"unsigned short" => target.c_type_byte_size(.ushort),
    868             .@"unsigned int" => target.c_type_byte_size(.uint),
    869             .@"unsigned long" => target.c_type_byte_size(.ulong),
    870             .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
    871             .float => target.c_type_byte_size(.float),
    872             .double => target.c_type_byte_size(.double),
    873             .@"long double" => target.c_type_byte_size(.longdouble),
    874             .size_t,
    875             .ptrdiff_t,
    876             .uintptr_t,
    877             .intptr_t,
    878             .pointer,
    879             .pointer_const,
    880             .pointer_volatile,
    881             .pointer_const_volatile,
    882             => @divExact(target.cpu.arch.ptrBitWidth(), 8),
    883             .uint16_t, .int16_t, .zig_f16 => 2,
    884             .uint32_t, .int32_t, .zig_f32 => 4,
    885             .uint64_t, .int64_t, .zig_f64 => 8,
    886             .zig_u128, .zig_i128, .zig_f128 => 16,
    887             .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
    888                 target.c_type_byte_size(.longdouble)
    889             else
    890                 16,
    891             .zig_c_longdouble => target.c_type_byte_size(.longdouble),
    892 
    893             .array,
    894             .vector,
    895             => {
    896                 const data = self.cast(Payload.Sequence).?.data;
    897                 return data.len * store.indexToCType(data.elem_type).byteSize(store, target);
    898             },
    899 
    900             .fwd_anon_struct,
    901             .fwd_anon_union,
    902             .fwd_struct,
    903             .fwd_union,
    904             .unnamed_struct,
    905             .unnamed_union,
    906             .packed_unnamed_struct,
    907             .packed_unnamed_union,
    908             .anon_struct,
    909             .anon_union,
    910             .@"struct",
    911             .@"union",
    912             .packed_struct,
    913             .packed_union,
    914             .function,
    915             .varargs_function,
    916             => unreachable,
    917         };
    918     }
    919 
    920     pub fn isPacked(self: CType) bool {
    921         return switch (self.tag()) {
    922             else => false,
    923             .packed_unnamed_struct,
    924             .packed_unnamed_union,
    925             .packed_struct,
    926             .packed_union,
    927             => true,
    928         };
    929     }
    930 
    931     pub fn fields(self: CType) Payload.Fields.Data {
    932         return if (self.cast(Payload.Aggregate)) |pl|
    933             pl.data.fields
    934         else if (self.cast(Payload.Unnamed)) |pl|
    935             pl.data.fields
    936         else if (self.cast(Payload.Fields)) |pl|
    937             pl.data
    938         else
    939             unreachable;
    940     }
    941 
    942     pub fn eql(lhs: CType, rhs: CType) bool {
    943         return lhs.eqlContext(rhs, struct {
    944             pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
    945                 return lhs_idx == rhs_idx;
    946             }
    947         }{});
    948     }
    949 
    950     pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
    951         // As a shortcut, if the small tags / addresses match, we're done.
    952         if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
    953 
    954         const lhs_tag = lhs.tag();
    955         const rhs_tag = rhs.tag();
    956         if (lhs_tag != rhs_tag) return false;
    957 
    958         return switch (lhs_tag) {
    959             .void,
    960             .char,
    961             .@"signed char",
    962             .short,
    963             .int,
    964             .long,
    965             .@"long long",
    966             ._Bool,
    967             .@"unsigned char",
    968             .@"unsigned short",
    969             .@"unsigned int",
    970             .@"unsigned long",
    971             .@"unsigned long long",
    972             .float,
    973             .double,
    974             .@"long double",
    975             .bool,
    976             .size_t,
    977             .ptrdiff_t,
    978             .uint8_t,
    979             .int8_t,
    980             .uint16_t,
    981             .int16_t,
    982             .uint32_t,
    983             .int32_t,
    984             .uint64_t,
    985             .int64_t,
    986             .uintptr_t,
    987             .intptr_t,
    988             .zig_u128,
    989             .zig_i128,
    990             .zig_f16,
    991             .zig_f32,
    992             .zig_f64,
    993             .zig_f80,
    994             .zig_f128,
    995             .zig_c_longdouble,
    996             => false,
    997 
    998             .pointer,
    999             .pointer_const,
   1000             .pointer_volatile,
   1001             .pointer_const_volatile,
   1002             => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
   1003 
   1004             .array,
   1005             .vector,
   1006             => {
   1007                 const lhs_data = lhs.cast(Payload.Sequence).?.data;
   1008                 const rhs_data = rhs.cast(Payload.Sequence).?.data;
   1009                 return lhs_data.len == rhs_data.len and
   1010                     ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
   1011             },
   1012 
   1013             .fwd_anon_struct,
   1014             .fwd_anon_union,
   1015             => {
   1016                 const lhs_data = lhs.cast(Payload.Fields).?.data;
   1017                 const rhs_data = rhs.cast(Payload.Fields).?.data;
   1018                 if (lhs_data.len != rhs_data.len) return false;
   1019                 for (lhs_data, rhs_data) |lhs_field, rhs_field| {
   1020                     if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
   1021                     if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
   1022                     if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false;
   1023                 }
   1024                 return true;
   1025             },
   1026 
   1027             .fwd_struct,
   1028             .fwd_union,
   1029             => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
   1030 
   1031             .unnamed_struct,
   1032             .unnamed_union,
   1033             .packed_unnamed_struct,
   1034             .packed_unnamed_union,
   1035             => {
   1036                 const lhs_data = lhs.cast(Payload.Unnamed).?.data;
   1037                 const rhs_data = rhs.cast(Payload.Unnamed).?.data;
   1038                 return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
   1039             },
   1040 
   1041             .anon_struct,
   1042             .anon_union,
   1043             .@"struct",
   1044             .@"union",
   1045             .packed_struct,
   1046             .packed_union,
   1047             => ctx.eqlIndex(
   1048                 lhs.cast(Payload.Aggregate).?.data.fwd_decl,
   1049                 rhs.cast(Payload.Aggregate).?.data.fwd_decl,
   1050             ),
   1051 
   1052             .function,
   1053             .varargs_function,
   1054             => {
   1055                 const lhs_data = lhs.cast(Payload.Function).?.data;
   1056                 const rhs_data = rhs.cast(Payload.Function).?.data;
   1057                 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
   1058                 if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
   1059                 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
   1060                     if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
   1061                 }
   1062                 return true;
   1063             },
   1064         };
   1065     }
   1066 
   1067     pub fn hash(self: CType, store: Store.Set) u64 {
   1068         var hasher = std.hash.Wyhash.init(0);
   1069         self.updateHasher(&hasher, store);
   1070         return hasher.final();
   1071     }
   1072 
   1073     pub fn updateHasher(self: CType, hasher: anytype, store: Store.Set) void {
   1074         const t = self.tag();
   1075         autoHash(hasher, t);
   1076         switch (t) {
   1077             .void,
   1078             .char,
   1079             .@"signed char",
   1080             .short,
   1081             .int,
   1082             .long,
   1083             .@"long long",
   1084             ._Bool,
   1085             .@"unsigned char",
   1086             .@"unsigned short",
   1087             .@"unsigned int",
   1088             .@"unsigned long",
   1089             .@"unsigned long long",
   1090             .float,
   1091             .double,
   1092             .@"long double",
   1093             .bool,
   1094             .size_t,
   1095             .ptrdiff_t,
   1096             .uint8_t,
   1097             .int8_t,
   1098             .uint16_t,
   1099             .int16_t,
   1100             .uint32_t,
   1101             .int32_t,
   1102             .uint64_t,
   1103             .int64_t,
   1104             .uintptr_t,
   1105             .intptr_t,
   1106             .zig_u128,
   1107             .zig_i128,
   1108             .zig_f16,
   1109             .zig_f32,
   1110             .zig_f64,
   1111             .zig_f80,
   1112             .zig_f128,
   1113             .zig_c_longdouble,
   1114             => {},
   1115 
   1116             .pointer,
   1117             .pointer_const,
   1118             .pointer_volatile,
   1119             .pointer_const_volatile,
   1120             => store.indexToCType(self.cast(Payload.Child).?.data).updateHasher(hasher, store),
   1121 
   1122             .array,
   1123             .vector,
   1124             => {
   1125                 const data = self.cast(Payload.Sequence).?.data;
   1126                 autoHash(hasher, data.len);
   1127                 store.indexToCType(data.elem_type).updateHasher(hasher, store);
   1128             },
   1129 
   1130             .fwd_anon_struct,
   1131             .fwd_anon_union,
   1132             => for (self.cast(Payload.Fields).?.data) |field| {
   1133                 store.indexToCType(field.type).updateHasher(hasher, store);
   1134                 hasher.update(mem.span(field.name));
   1135                 autoHash(hasher, field.alignas.@"align");
   1136             },
   1137 
   1138             .fwd_struct,
   1139             .fwd_union,
   1140             => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
   1141 
   1142             .unnamed_struct,
   1143             .unnamed_union,
   1144             .packed_unnamed_struct,
   1145             .packed_unnamed_union,
   1146             => {
   1147                 const data = self.cast(Payload.Unnamed).?.data;
   1148                 autoHash(hasher, data.owner_decl);
   1149                 autoHash(hasher, data.id);
   1150             },
   1151 
   1152             .anon_struct,
   1153             .anon_union,
   1154             .@"struct",
   1155             .@"union",
   1156             .packed_struct,
   1157             .packed_union,
   1158             => store.indexToCType(self.cast(Payload.Aggregate).?.data.fwd_decl)
   1159                 .updateHasher(hasher, store),
   1160 
   1161             .function,
   1162             .varargs_function,
   1163             => {
   1164                 const data = self.cast(Payload.Function).?.data;
   1165                 store.indexToCType(data.return_type).updateHasher(hasher, store);
   1166                 for (data.param_types) |param_ty| {
   1167                     store.indexToCType(param_ty).updateHasher(hasher, store);
   1168                 }
   1169             },
   1170         }
   1171     }
   1172 
   1173     pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
   1174 
   1175     const Convert = struct {
   1176         storage: union {
   1177             none: void,
   1178             child: Payload.Child,
   1179             seq: Payload.Sequence,
   1180             fwd: Payload.FwdDecl,
   1181             anon: struct {
   1182                 fields: [2]Payload.Fields.Field,
   1183                 pl: union {
   1184                     forward: Payload.Fields,
   1185                     complete: Payload.Aggregate,
   1186                 },
   1187             },
   1188         },
   1189         value: union(enum) {
   1190             tag: Tag,
   1191             cty: CType,
   1192         },
   1193 
   1194         pub fn init(self: *@This(), t: Tag) void {
   1195             self.* = if (t.hasPayload()) .{
   1196                 .storage = .{ .none = {} },
   1197                 .value = .{ .tag = t },
   1198             } else .{
   1199                 .storage = .{ .none = {} },
   1200                 .value = .{ .cty = initTag(t) },
   1201             };
   1202         }
   1203 
   1204         pub fn tag(self: @This()) Tag {
   1205             return switch (self.value) {
   1206                 .tag => |t| t,
   1207                 .cty => |c| c.tag(),
   1208             };
   1209         }
   1210 
   1211         fn tagFromIntInfo(int_info: std.builtin.Type.Int) Tag {
   1212             return switch (int_info.bits) {
   1213                 0 => .void,
   1214                 1...8 => switch (int_info.signedness) {
   1215                     .unsigned => .uint8_t,
   1216                     .signed => .int8_t,
   1217                 },
   1218                 9...16 => switch (int_info.signedness) {
   1219                     .unsigned => .uint16_t,
   1220                     .signed => .int16_t,
   1221                 },
   1222                 17...32 => switch (int_info.signedness) {
   1223                     .unsigned => .uint32_t,
   1224                     .signed => .int32_t,
   1225                 },
   1226                 33...64 => switch (int_info.signedness) {
   1227                     .unsigned => .uint64_t,
   1228                     .signed => .int64_t,
   1229                 },
   1230                 65...128 => switch (int_info.signedness) {
   1231                     .unsigned => .zig_u128,
   1232                     .signed => .zig_i128,
   1233                 },
   1234                 else => .array,
   1235             };
   1236         }
   1237 
   1238         pub const Lookup = union(enum) {
   1239             fail: Target,
   1240             imm: struct {
   1241                 set: *const Store.Set,
   1242                 target: Target,
   1243             },
   1244             mut: struct {
   1245                 promoted: *Store.Promoted,
   1246                 mod: *Module,
   1247             },
   1248 
   1249             pub fn isMutable(self: @This()) bool {
   1250                 return switch (self) {
   1251                     .fail, .imm => false,
   1252                     .mut => true,
   1253                 };
   1254             }
   1255 
   1256             pub fn getTarget(self: @This()) Target {
   1257                 return switch (self) {
   1258                     .fail => |target| target,
   1259                     .imm => |imm| imm.target,
   1260                     .mut => |mut| mut.mod.getTarget(),
   1261                 };
   1262             }
   1263 
   1264             pub fn getSet(self: @This()) ?*const Store.Set {
   1265                 return switch (self) {
   1266                     .fail => null,
   1267                     .imm => |imm| imm.set,
   1268                     .mut => |mut| &mut.promoted.set,
   1269                 };
   1270             }
   1271 
   1272             pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index {
   1273                 return switch (self) {
   1274                     .fail => null,
   1275                     .imm => |imm| imm.set.typeToIndex(ty, imm.target, kind),
   1276                     .mut => |mut| try mut.promoted.typeToIndex(ty, mut.mod, kind),
   1277                 };
   1278             }
   1279 
   1280             pub fn indexToCType(self: @This(), index: Index) ?CType {
   1281                 return if (self.getSet()) |set| set.indexToCType(index) else null;
   1282             }
   1283 
   1284             pub fn freeze(self: @This()) @This() {
   1285                 return switch (self) {
   1286                     .fail, .imm => self,
   1287                     .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .target = self.getTarget() } },
   1288                 };
   1289             }
   1290         };
   1291 
   1292         fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
   1293             const Field = Payload.Fields.Field;
   1294             const slice = self.storage.anon.fields[0..fields_len];
   1295             std.sort.sort(Field, slice, {}, struct {
   1296                 fn before(_: void, lhs: Field, rhs: Field) bool {
   1297                     return lhs.alignas.@"align" > rhs.alignas.@"align";
   1298                 }
   1299             }.before);
   1300             return slice;
   1301         }
   1302 
   1303         fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
   1304             switch (kind) {
   1305                 .forward, .forward_parameter => {
   1306                     self.storage.anon.pl = .{ .forward = .{
   1307                         .base = .{ .tag = .fwd_anon_struct },
   1308                         .data = self.sortFields(fields_len),
   1309                     } };
   1310                     self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
   1311                 },
   1312                 .complete, .parameter, .global => {
   1313                     self.storage.anon.pl = .{ .complete = .{
   1314                         .base = .{ .tag = .anon_struct },
   1315                         .data = .{
   1316                             .fields = self.sortFields(fields_len),
   1317                             .fwd_decl = fwd_idx,
   1318                         },
   1319                     } };
   1320                     self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
   1321                 },
   1322                 .payload => unreachable,
   1323             }
   1324         }
   1325 
   1326         fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
   1327             if (switch (kind) {
   1328                 .forward_parameter => @as(Index, undefined),
   1329                 .parameter => try lookup.typeToIndex(ty, .forward_parameter),
   1330                 .forward, .complete, .global, .payload => unreachable,
   1331             }) |fwd_idx| {
   1332                 if (try lookup.typeToIndex(ty, switch (kind) {
   1333                     .forward_parameter => .forward,
   1334                     .parameter => .complete,
   1335                     .forward, .complete, .global, .payload => unreachable,
   1336                 })) |array_idx| {
   1337                     self.storage = .{ .anon = undefined };
   1338                     self.storage.anon.fields[0] = .{
   1339                         .name = "array",
   1340                         .type = array_idx,
   1341                         .alignas = AlignAs.abiAlign(ty, lookup.getTarget()),
   1342                     };
   1343                     self.initAnon(kind, fwd_idx, 1);
   1344                 } else self.init(switch (kind) {
   1345                     .forward_parameter => .fwd_anon_struct,
   1346                     .parameter => .anon_struct,
   1347                     .forward, .complete, .global, .payload => unreachable,
   1348                 });
   1349             } else self.init(.anon_struct);
   1350         }
   1351 
   1352         pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
   1353             const target = lookup.getTarget();
   1354 
   1355             self.* = undefined;
   1356             if (!ty.isFnOrHasRuntimeBitsIgnoreComptime())
   1357                 self.init(.void)
   1358             else if (ty.isAbiInt()) switch (ty.tag()) {
   1359                 .usize => self.init(.uintptr_t),
   1360                 .isize => self.init(.intptr_t),
   1361                 .c_short => self.init(.short),
   1362                 .c_ushort => self.init(.@"unsigned short"),
   1363                 .c_int => self.init(.int),
   1364                 .c_uint => self.init(.@"unsigned int"),
   1365                 .c_long => self.init(.long),
   1366                 .c_ulong => self.init(.@"unsigned long"),
   1367                 .c_longlong => self.init(.@"long long"),
   1368                 .c_ulonglong => self.init(.@"unsigned long long"),
   1369                 else => switch (tagFromIntInfo(ty.intInfo(target))) {
   1370                     .void => unreachable,
   1371                     else => |t| self.init(t),
   1372                     .array => switch (kind) {
   1373                         .forward, .complete, .global => {
   1374                             const abi_size = ty.abiSize(target);
   1375                             const abi_align = ty.abiAlignment(target);
   1376                             self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
   1377                                 .len = @divExact(abi_size, abi_align),
   1378                                 .elem_type = tagFromIntInfo(.{
   1379                                     .signedness = .unsigned,
   1380                                     .bits = @intCast(u16, abi_align * 8),
   1381                                 }).toIndex(),
   1382                             } } };
   1383                             self.value = .{ .cty = initPayload(&self.storage.seq) };
   1384                         },
   1385                         .forward_parameter,
   1386                         .parameter,
   1387                         => try self.initArrayParameter(ty, kind, lookup),
   1388                         .payload => unreachable,
   1389                     },
   1390                 },
   1391             } else switch (ty.zigTypeTag()) {
   1392                 .Frame => unreachable,
   1393                 .AnyFrame => unreachable,
   1394 
   1395                 .Int,
   1396                 .Enum,
   1397                 .ErrorSet,
   1398                 .Type,
   1399                 .Void,
   1400                 .NoReturn,
   1401                 .ComptimeFloat,
   1402                 .ComptimeInt,
   1403                 .Undefined,
   1404                 .Null,
   1405                 .EnumLiteral,
   1406                 => unreachable,
   1407 
   1408                 .Bool => self.init(.bool),
   1409 
   1410                 .Float => self.init(switch (ty.tag()) {
   1411                     .f16 => .zig_f16,
   1412                     .f32 => .zig_f32,
   1413                     .f64 => .zig_f64,
   1414                     .f80 => .zig_f80,
   1415                     .f128 => .zig_f128,
   1416                     .c_longdouble => .zig_c_longdouble,
   1417                     else => unreachable,
   1418                 }),
   1419 
   1420                 .Pointer => {
   1421                     const info = ty.ptrInfo().data;
   1422                     switch (info.size) {
   1423                         .Slice => {
   1424                             if (switch (kind) {
   1425                                 .forward, .forward_parameter => @as(Index, undefined),
   1426                                 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
   1427                                 .payload => unreachable,
   1428                             }) |fwd_idx| {
   1429                                 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   1430                                 const ptr_ty = ty.slicePtrFieldType(&buf);
   1431                                 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
   1432                                     self.storage = .{ .anon = undefined };
   1433                                     self.storage.anon.fields[0] = .{
   1434                                         .name = "ptr",
   1435                                         .type = ptr_idx,
   1436                                         .alignas = AlignAs.abiAlign(ptr_ty, target),
   1437                                     };
   1438                                     self.storage.anon.fields[1] = .{
   1439                                         .name = "len",
   1440                                         .type = Tag.uintptr_t.toIndex(),
   1441                                         .alignas = AlignAs.abiAlign(Type.usize, target),
   1442                                     };
   1443                                     self.initAnon(kind, fwd_idx, 2);
   1444                                 } else self.init(switch (kind) {
   1445                                     .forward, .forward_parameter => .fwd_anon_struct,
   1446                                     .complete, .parameter, .global => .anon_struct,
   1447                                     .payload => unreachable,
   1448                                 });
   1449                             } else self.init(.anon_struct);
   1450                         },
   1451 
   1452                         .One, .Many, .C => {
   1453                             const t: Tag = switch (info.@"volatile") {
   1454                                 false => switch (info.mutable) {
   1455                                     true => .pointer,
   1456                                     false => .pointer_const,
   1457                                 },
   1458                                 true => switch (info.mutable) {
   1459                                     true => .pointer_volatile,
   1460                                     false => .pointer_const_volatile,
   1461                                 },
   1462                             };
   1463 
   1464                             var host_int_pl = Type.Payload.Bits{
   1465                                 .base = .{ .tag = .int_unsigned },
   1466                                 .data = info.host_size * 8,
   1467                             };
   1468                             const pointee_ty = if (info.host_size > 0 and info.vector_index == .none)
   1469                                 Type.initPayload(&host_int_pl.base)
   1470                             else
   1471                                 info.pointee_type;
   1472 
   1473                             if (if (info.size == .C and pointee_ty.tag() == .u8)
   1474                                 Tag.char.toIndex()
   1475                             else
   1476                                 try lookup.typeToIndex(pointee_ty, .forward)) |child_idx|
   1477                             {
   1478                                 self.storage = .{ .child = .{
   1479                                     .base = .{ .tag = t },
   1480                                     .data = child_idx,
   1481                                 } };
   1482                                 self.value = .{ .cty = initPayload(&self.storage.child) };
   1483                             } else self.init(t);
   1484                         },
   1485                     }
   1486                 },
   1487 
   1488                 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout() == .Packed) {
   1489                     if (ty.castTag(.@"struct")) |struct_obj| {
   1490                         try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
   1491                     } else {
   1492                         var buf: Type.Payload.Bits = .{
   1493                             .base = .{ .tag = .int_unsigned },
   1494                             .data = @intCast(u16, ty.bitSize(target)),
   1495                         };
   1496                         try self.initType(Type.initPayload(&buf.base), kind, lookup);
   1497                     }
   1498                 } else if (ty.isTupleOrAnonStruct()) {
   1499                     if (lookup.isMutable()) {
   1500                         for (0..switch (zig_ty_tag) {
   1501                             .Struct => ty.structFieldCount(),
   1502                             .Union => ty.unionFields().count(),
   1503                             else => unreachable,
   1504                         }) |field_i| {
   1505                             const field_ty = ty.structFieldType(field_i);
   1506                             if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
   1507                                 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   1508                             _ = try lookup.typeToIndex(field_ty, switch (kind) {
   1509                                 .forward, .forward_parameter => .forward,
   1510                                 .complete, .parameter => .complete,
   1511                                 .global => .global,
   1512                                 .payload => unreachable,
   1513                             });
   1514                         }
   1515                         switch (kind) {
   1516                             .forward, .forward_parameter => {},
   1517                             .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
   1518                             .payload => unreachable,
   1519                         }
   1520                     }
   1521                     self.init(switch (kind) {
   1522                         .forward, .forward_parameter => switch (zig_ty_tag) {
   1523                             .Struct => .fwd_anon_struct,
   1524                             .Union => .fwd_anon_union,
   1525                             else => unreachable,
   1526                         },
   1527                         .complete, .parameter, .global => switch (zig_ty_tag) {
   1528                             .Struct => .anon_struct,
   1529                             .Union => .anon_union,
   1530                             else => unreachable,
   1531                         },
   1532                         .payload => unreachable,
   1533                     });
   1534                 } else {
   1535                     const tag_ty = ty.unionTagTypeSafety();
   1536                     const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
   1537                     const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
   1538                     switch (kind) {
   1539                         .forward, .forward_parameter => {
   1540                             self.storage = .{ .fwd = .{
   1541                                 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
   1542                                 .data = ty.getOwnerDecl(),
   1543                             } };
   1544                             self.value = .{ .cty = initPayload(&self.storage.fwd) };
   1545                         },
   1546                         .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
   1547                             const fwd_idx = try lookup.typeToIndex(ty, .forward);
   1548                             const payload_idx = try lookup.typeToIndex(ty, .payload);
   1549                             const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
   1550                             if (fwd_idx != null and payload_idx != null and tag_idx != null) {
   1551                                 self.storage = .{ .anon = undefined };
   1552                                 var field_count: usize = 0;
   1553                                 if (payload_idx != Tag.void.toIndex()) {
   1554                                     self.storage.anon.fields[field_count] = .{
   1555                                         .name = "payload",
   1556                                         .type = payload_idx.?,
   1557                                         .alignas = AlignAs.unionPayloadAlign(ty, target),
   1558                                     };
   1559                                     field_count += 1;
   1560                                 }
   1561                                 if (tag_idx != Tag.void.toIndex()) {
   1562                                     self.storage.anon.fields[field_count] = .{
   1563                                         .name = "tag",
   1564                                         .type = tag_idx.?,
   1565                                         .alignas = AlignAs.abiAlign(tag_ty.?, target),
   1566                                     };
   1567                                     field_count += 1;
   1568                                 }
   1569                                 self.storage.anon.pl = .{ .complete = .{
   1570                                     .base = .{ .tag = .@"struct" },
   1571                                     .data = .{
   1572                                         .fields = self.sortFields(field_count),
   1573                                         .fwd_decl = fwd_idx.?,
   1574                                     },
   1575                                 } };
   1576                                 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
   1577                             } else self.init(.@"struct");
   1578                         } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) {
   1579                             self.init(.void);
   1580                         } else {
   1581                             var is_packed = false;
   1582                             for (0..switch (zig_ty_tag) {
   1583                                 .Struct => ty.structFieldCount(),
   1584                                 .Union => ty.unionFields().count(),
   1585                                 else => unreachable,
   1586                             }) |field_i| {
   1587                                 const field_ty = ty.structFieldType(field_i);
   1588                                 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   1589 
   1590                                 const field_align = AlignAs.fieldAlign(ty, field_i, target);
   1591                                 if (field_align.@"align" < field_align.abi) {
   1592                                     is_packed = true;
   1593                                     if (!lookup.isMutable()) break;
   1594                                 }
   1595 
   1596                                 if (lookup.isMutable()) {
   1597                                     _ = try lookup.typeToIndex(field_ty, switch (kind) {
   1598                                         .forward, .forward_parameter => unreachable,
   1599                                         .complete, .parameter, .payload => .complete,
   1600                                         .global => .global,
   1601                                     });
   1602                                 }
   1603                             }
   1604                             switch (kind) {
   1605                                 .forward, .forward_parameter => unreachable,
   1606                                 .complete, .parameter, .global => {
   1607                                     _ = try lookup.typeToIndex(ty, .forward);
   1608                                     self.init(if (is_struct)
   1609                                         if (is_packed) .packed_struct else .@"struct"
   1610                                     else if (is_packed) .packed_union else .@"union");
   1611                                 },
   1612                                 .payload => self.init(if (is_packed)
   1613                                     .packed_unnamed_union
   1614                                 else
   1615                                     .unnamed_union),
   1616                             }
   1617                         },
   1618                     }
   1619                 },
   1620 
   1621                 .Array, .Vector => |zig_ty_tag| {
   1622                     switch (kind) {
   1623                         .forward, .complete, .global => {
   1624                             const t: Tag = switch (zig_ty_tag) {
   1625                                 .Array => .array,
   1626                                 .Vector => .vector,
   1627                                 else => unreachable,
   1628                             };
   1629                             if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {
   1630                                 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
   1631                                     .len = ty.arrayLenIncludingSentinel(),
   1632                                     .elem_type = child_idx,
   1633                                 } } };
   1634                                 self.value = .{ .cty = initPayload(&self.storage.seq) };
   1635                             } else self.init(t);
   1636                         },
   1637                         .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
   1638                         .payload => unreachable,
   1639                     }
   1640                 },
   1641 
   1642                 .Optional => {
   1643                     var buf: Type.Payload.ElemType = undefined;
   1644                     const payload_ty = ty.optionalChild(&buf);
   1645                     if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
   1646                         if (ty.optionalReprIsPayload()) {
   1647                             try self.initType(payload_ty, kind, lookup);
   1648                         } else if (switch (kind) {
   1649                             .forward, .forward_parameter => @as(Index, undefined),
   1650                             .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
   1651                             .payload => unreachable,
   1652                         }) |fwd_idx| {
   1653                             if (try lookup.typeToIndex(payload_ty, switch (kind) {
   1654                                 .forward, .forward_parameter => .forward,
   1655                                 .complete, .parameter => .complete,
   1656                                 .global => .global,
   1657                                 .payload => unreachable,
   1658                             })) |payload_idx| {
   1659                                 self.storage = .{ .anon = undefined };
   1660                                 self.storage.anon.fields[0] = .{
   1661                                     .name = "payload",
   1662                                     .type = payload_idx,
   1663                                     .alignas = AlignAs.abiAlign(payload_ty, target),
   1664                                 };
   1665                                 self.storage.anon.fields[1] = .{
   1666                                     .name = "is_null",
   1667                                     .type = Tag.bool.toIndex(),
   1668                                     .alignas = AlignAs.abiAlign(Type.bool, target),
   1669                                 };
   1670                                 self.initAnon(kind, fwd_idx, 2);
   1671                             } else self.init(switch (kind) {
   1672                                 .forward, .forward_parameter => .fwd_anon_struct,
   1673                                 .complete, .parameter, .global => .anon_struct,
   1674                                 .payload => unreachable,
   1675                             });
   1676                         } else self.init(.anon_struct);
   1677                     } else self.init(.bool);
   1678                 },
   1679 
   1680                 .ErrorUnion => {
   1681                     if (switch (kind) {
   1682                         .forward, .forward_parameter => @as(Index, undefined),
   1683                         .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
   1684                         .payload => unreachable,
   1685                     }) |fwd_idx| {
   1686                         const payload_ty = ty.errorUnionPayload();
   1687                         if (try lookup.typeToIndex(payload_ty, switch (kind) {
   1688                             .forward, .forward_parameter => .forward,
   1689                             .complete, .parameter => .complete,
   1690                             .global => .global,
   1691                             .payload => unreachable,
   1692                         })) |payload_idx| {
   1693                             const error_ty = ty.errorUnionSet();
   1694                             if (payload_idx == Tag.void.toIndex()) {
   1695                                 try self.initType(error_ty, kind, lookup);
   1696                             } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
   1697                                 self.storage = .{ .anon = undefined };
   1698                                 self.storage.anon.fields[0] = .{
   1699                                     .name = "payload",
   1700                                     .type = payload_idx,
   1701                                     .alignas = AlignAs.abiAlign(payload_ty, target),
   1702                                 };
   1703                                 self.storage.anon.fields[1] = .{
   1704                                     .name = "error",
   1705                                     .type = error_idx,
   1706                                     .alignas = AlignAs.abiAlign(error_ty, target),
   1707                                 };
   1708                                 self.initAnon(kind, fwd_idx, 2);
   1709                             } else self.init(switch (kind) {
   1710                                 .forward, .forward_parameter => .fwd_anon_struct,
   1711                                 .complete, .parameter, .global => .anon_struct,
   1712                                 .payload => unreachable,
   1713                             });
   1714                         } else self.init(switch (kind) {
   1715                             .forward, .forward_parameter => .fwd_anon_struct,
   1716                             .complete, .parameter, .global => .anon_struct,
   1717                             .payload => unreachable,
   1718                         });
   1719                     } else self.init(.anon_struct);
   1720                 },
   1721 
   1722                 .Opaque => switch (ty.tag()) {
   1723                     .anyopaque => self.init(.void),
   1724                     .@"opaque" => {
   1725                         self.storage = .{ .fwd = .{
   1726                             .base = .{ .tag = .fwd_struct },
   1727                             .data = ty.getOwnerDecl(),
   1728                         } };
   1729                         self.value = .{ .cty = initPayload(&self.storage.fwd) };
   1730                     },
   1731                     else => unreachable,
   1732                 },
   1733 
   1734                 .Fn => {
   1735                     const info = ty.fnInfo();
   1736                     if (!info.is_generic) {
   1737                         if (lookup.isMutable()) {
   1738                             const param_kind: Kind = switch (kind) {
   1739                                 .forward, .forward_parameter => .forward_parameter,
   1740                                 .complete, .parameter, .global => .parameter,
   1741                                 .payload => unreachable,
   1742                             };
   1743                             _ = try lookup.typeToIndex(info.return_type, param_kind);
   1744                             for (info.param_types) |param_type| {
   1745                                 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
   1746                                 _ = try lookup.typeToIndex(param_type, param_kind);
   1747                             }
   1748                         }
   1749                         self.init(if (info.is_var_args) .varargs_function else .function);
   1750                     } else self.init(.void);
   1751                 },
   1752             }
   1753         }
   1754     };
   1755 
   1756     pub fn copy(self: CType, arena: Allocator) !CType {
   1757         return self.copyContext(struct {
   1758             arena: Allocator,
   1759             pub fn copyIndex(_: @This(), idx: Index) Index {
   1760                 return idx;
   1761             }
   1762         }{ .arena = arena });
   1763     }
   1764 
   1765     fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
   1766         const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
   1767         for (new_fields, old_fields) |*new_field, old_field| {
   1768             new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
   1769             new_field.type = ctx.copyIndex(old_field.type);
   1770             new_field.alignas = old_field.alignas;
   1771         }
   1772         return new_fields;
   1773     }
   1774 
   1775     fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
   1776         const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
   1777         for (new_param_types, old_param_types) |*new_param_type, old_param_type|
   1778             new_param_type.* = ctx.copyIndex(old_param_type);
   1779         return new_param_types;
   1780     }
   1781 
   1782     pub fn copyContext(self: CType, ctx: anytype) !CType {
   1783         switch (self.tag()) {
   1784             .void,
   1785             .char,
   1786             .@"signed char",
   1787             .short,
   1788             .int,
   1789             .long,
   1790             .@"long long",
   1791             ._Bool,
   1792             .@"unsigned char",
   1793             .@"unsigned short",
   1794             .@"unsigned int",
   1795             .@"unsigned long",
   1796             .@"unsigned long long",
   1797             .float,
   1798             .double,
   1799             .@"long double",
   1800             .bool,
   1801             .size_t,
   1802             .ptrdiff_t,
   1803             .uint8_t,
   1804             .int8_t,
   1805             .uint16_t,
   1806             .int16_t,
   1807             .uint32_t,
   1808             .int32_t,
   1809             .uint64_t,
   1810             .int64_t,
   1811             .uintptr_t,
   1812             .intptr_t,
   1813             .zig_u128,
   1814             .zig_i128,
   1815             .zig_f16,
   1816             .zig_f32,
   1817             .zig_f64,
   1818             .zig_f80,
   1819             .zig_f128,
   1820             .zig_c_longdouble,
   1821             => return self,
   1822 
   1823             .pointer,
   1824             .pointer_const,
   1825             .pointer_volatile,
   1826             .pointer_const_volatile,
   1827             => {
   1828                 const pl = self.cast(Payload.Child).?;
   1829                 const new_pl = try ctx.arena.create(Payload.Child);
   1830                 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
   1831                 return initPayload(new_pl);
   1832             },
   1833 
   1834             .array,
   1835             .vector,
   1836             => {
   1837                 const pl = self.cast(Payload.Sequence).?;
   1838                 const new_pl = try ctx.arena.create(Payload.Sequence);
   1839                 new_pl.* = .{
   1840                     .base = .{ .tag = pl.base.tag },
   1841                     .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
   1842                 };
   1843                 return initPayload(new_pl);
   1844             },
   1845 
   1846             .fwd_anon_struct,
   1847             .fwd_anon_union,
   1848             => {
   1849                 const pl = self.cast(Payload.Fields).?;
   1850                 const new_pl = try ctx.arena.create(Payload.Fields);
   1851                 new_pl.* = .{
   1852                     .base = .{ .tag = pl.base.tag },
   1853                     .data = try copyFields(ctx, pl.data),
   1854                 };
   1855                 return initPayload(new_pl);
   1856             },
   1857 
   1858             .fwd_struct,
   1859             .fwd_union,
   1860             => {
   1861                 const pl = self.cast(Payload.FwdDecl).?;
   1862                 const new_pl = try ctx.arena.create(Payload.FwdDecl);
   1863                 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
   1864                 return initPayload(new_pl);
   1865             },
   1866 
   1867             .unnamed_struct,
   1868             .unnamed_union,
   1869             .packed_unnamed_struct,
   1870             .packed_unnamed_union,
   1871             => {
   1872                 const pl = self.cast(Payload.Unnamed).?;
   1873                 const new_pl = try ctx.arena.create(Payload.Unnamed);
   1874                 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
   1875                     .fields = try copyFields(ctx, pl.data.fields),
   1876                     .owner_decl = pl.data.owner_decl,
   1877                     .id = pl.data.id,
   1878                 } };
   1879                 return initPayload(new_pl);
   1880             },
   1881 
   1882             .anon_struct,
   1883             .anon_union,
   1884             .@"struct",
   1885             .@"union",
   1886             .packed_struct,
   1887             .packed_union,
   1888             => {
   1889                 const pl = self.cast(Payload.Aggregate).?;
   1890                 const new_pl = try ctx.arena.create(Payload.Aggregate);
   1891                 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
   1892                     .fields = try copyFields(ctx, pl.data.fields),
   1893                     .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
   1894                 } };
   1895                 return initPayload(new_pl);
   1896             },
   1897 
   1898             .function,
   1899             .varargs_function,
   1900             => {
   1901                 const pl = self.cast(Payload.Function).?;
   1902                 const new_pl = try ctx.arena.create(Payload.Function);
   1903                 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
   1904                     .return_type = ctx.copyIndex(pl.data.return_type),
   1905                     .param_types = try copyParams(ctx, pl.data.param_types),
   1906                 } };
   1907                 return initPayload(new_pl);
   1908             },
   1909         }
   1910     }
   1911 
   1912     fn createFromType(store: *Store.Promoted, ty: Type, target: Target, kind: Kind) !CType {
   1913         var convert: Convert = undefined;
   1914         try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .target = target } });
   1915         return createFromConvert(store, ty, target, kind, &convert);
   1916     }
   1917 
   1918     fn createFromConvert(
   1919         store: *Store.Promoted,
   1920         ty: Type,
   1921         target: Target,
   1922         kind: Kind,
   1923         convert: Convert,
   1924     ) !CType {
   1925         const arena = store.arena.allocator();
   1926         switch (convert.value) {
   1927             .cty => |c| return c.copy(arena),
   1928             .tag => |t| switch (t) {
   1929                 .fwd_anon_struct,
   1930                 .fwd_anon_union,
   1931                 .unnamed_struct,
   1932                 .unnamed_union,
   1933                 .packed_unnamed_struct,
   1934                 .packed_unnamed_union,
   1935                 .anon_struct,
   1936                 .anon_union,
   1937                 .@"struct",
   1938                 .@"union",
   1939                 .packed_struct,
   1940                 .packed_union,
   1941                 => {
   1942                     const zig_ty_tag = ty.zigTypeTag();
   1943                     const fields_len = switch (zig_ty_tag) {
   1944                         .Struct => ty.structFieldCount(),
   1945                         .Union => ty.unionFields().count(),
   1946                         else => unreachable,
   1947                     };
   1948 
   1949                     var c_fields_len: usize = 0;
   1950                     for (0..fields_len) |field_i| {
   1951                         const field_ty = ty.structFieldType(field_i);
   1952                         if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
   1953                             !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   1954                         c_fields_len += 1;
   1955                     }
   1956 
   1957                     const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
   1958                     var c_field_i: usize = 0;
   1959                     for (0..fields_len) |field_i| {
   1960                         const field_ty = ty.structFieldType(field_i);
   1961                         if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
   1962                             !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   1963 
   1964                         defer c_field_i += 1;
   1965                         fields_pl[c_field_i] = .{
   1966                             .name = try if (ty.isSimpleTuple())
   1967                                 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
   1968                             else
   1969                                 arena.dupeZ(u8, switch (zig_ty_tag) {
   1970                                     .Struct => ty.structFieldName(field_i),
   1971                                     .Union => ty.unionFields().keys()[field_i],
   1972                                     else => unreachable,
   1973                                 }),
   1974                             .type = store.set.typeToIndex(field_ty, target, switch (kind) {
   1975                                 .forward, .forward_parameter => .forward,
   1976                                 .complete, .parameter, .payload => .complete,
   1977                                 .global => .global,
   1978                             }).?,
   1979                             .alignas = AlignAs.fieldAlign(ty, field_i, target),
   1980                         };
   1981                     }
   1982 
   1983                     switch (t) {
   1984                         .fwd_anon_struct,
   1985                         .fwd_anon_union,
   1986                         => {
   1987                             const anon_pl = try arena.create(Payload.Fields);
   1988                             anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
   1989                             return initPayload(anon_pl);
   1990                         },
   1991 
   1992                         .unnamed_struct,
   1993                         .unnamed_union,
   1994                         .packed_unnamed_struct,
   1995                         .packed_unnamed_union,
   1996                         => {
   1997                             const unnamed_pl = try arena.create(Payload.Unnamed);
   1998                             unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
   1999                                 .fields = fields_pl,
   2000                                 .owner_decl = ty.getOwnerDecl(),
   2001                                 .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,
   2002                             } };
   2003                             return initPayload(unnamed_pl);
   2004                         },
   2005 
   2006                         .anon_struct,
   2007                         .anon_union,
   2008                         .@"struct",
   2009                         .@"union",
   2010                         .packed_struct,
   2011                         .packed_union,
   2012                         => {
   2013                             const struct_pl = try arena.create(Payload.Aggregate);
   2014                             struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
   2015                                 .fields = fields_pl,
   2016                                 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
   2017                             } };
   2018                             return initPayload(struct_pl);
   2019                         },
   2020 
   2021                         else => unreachable,
   2022                     }
   2023                 },
   2024 
   2025                 .function,
   2026                 .varargs_function,
   2027                 => {
   2028                     const info = ty.fnInfo();
   2029                     assert(!info.is_generic);
   2030                     const param_kind: Kind = switch (kind) {
   2031                         .forward, .forward_parameter => .forward_parameter,
   2032                         .complete, .parameter, .global => .parameter,
   2033                         .payload => unreachable,
   2034                     };
   2035 
   2036                     var c_params_len: usize = 0;
   2037                     for (info.param_types) |param_type| {
   2038                         if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
   2039                         c_params_len += 1;
   2040                     }
   2041 
   2042                     const params_pl = try arena.alloc(Index, c_params_len);
   2043                     var c_param_i: usize = 0;
   2044                     for (info.param_types) |param_type| {
   2045                         if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
   2046                         params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?;
   2047                         c_param_i += 1;
   2048                     }
   2049 
   2050                     const fn_pl = try arena.create(Payload.Function);
   2051                     fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
   2052                         .return_type = store.set.typeToIndex(info.return_type, target, param_kind).?,
   2053                         .param_types = params_pl,
   2054                     } };
   2055                     return initPayload(fn_pl);
   2056                 },
   2057 
   2058                 else => unreachable,
   2059             },
   2060         }
   2061     }
   2062 
   2063     pub const TypeAdapter64 = struct {
   2064         kind: Kind,
   2065         lookup: Convert.Lookup,
   2066         convert: *const Convert,
   2067 
   2068         fn eqlRecurse(self: @This(), ty: Type, cty: Index, kind: Kind) bool {
   2069             assert(!self.lookup.isMutable());
   2070 
   2071             var convert: Convert = undefined;
   2072             convert.initType(ty, kind, self.lookup) catch unreachable;
   2073 
   2074             const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
   2075             return self_recurse.eql(ty, self.lookup.indexToCType(cty).?);
   2076         }
   2077 
   2078         pub fn eql(self: @This(), ty: Type, cty: CType) bool {
   2079             switch (self.convert.value) {
   2080                 .cty => |c| return c.eql(cty),
   2081                 .tag => |t| {
   2082                     if (t != cty.tag()) return false;
   2083 
   2084                     const target = self.lookup.getTarget();
   2085                     switch (t) {
   2086                         .fwd_anon_struct,
   2087                         .fwd_anon_union,
   2088                         => {
   2089                             if (!ty.isTupleOrAnonStruct()) return false;
   2090 
   2091                             var name_buf: [
   2092                                 std.fmt.count("f{}", .{std.math.maxInt(usize)})
   2093                             ]u8 = undefined;
   2094                             const c_fields = cty.cast(Payload.Fields).?.data;
   2095 
   2096                             const zig_ty_tag = ty.zigTypeTag();
   2097                             var c_field_i: usize = 0;
   2098                             for (0..switch (zig_ty_tag) {
   2099                                 .Struct => ty.structFieldCount(),
   2100                                 .Union => ty.unionFields().count(),
   2101                                 else => unreachable,
   2102                             }) |field_i| {
   2103                                 const field_ty = ty.structFieldType(field_i);
   2104                                 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
   2105                                     !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   2106 
   2107                                 defer c_field_i += 1;
   2108                                 const c_field = &c_fields[c_field_i];
   2109 
   2110                                 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
   2111                                     .forward, .forward_parameter => .forward,
   2112                                     .complete, .parameter => .complete,
   2113                                     .global => .global,
   2114                                     .payload => unreachable,
   2115                                 }) or !mem.eql(
   2116                                     u8,
   2117                                     if (ty.isSimpleTuple())
   2118                                         std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
   2119                                     else switch (zig_ty_tag) {
   2120                                         .Struct => ty.structFieldName(field_i),
   2121                                         .Union => ty.unionFields().keys()[field_i],
   2122                                         else => unreachable,
   2123                                     },
   2124                                     mem.span(c_field.name),
   2125                                 ) or AlignAs.fieldAlign(ty, field_i, target).@"align" !=
   2126                                     c_field.alignas.@"align") return false;
   2127                             }
   2128                             return true;
   2129                         },
   2130 
   2131                         .unnamed_struct,
   2132                         .unnamed_union,
   2133                         .packed_unnamed_struct,
   2134                         .packed_unnamed_union,
   2135                         => switch (self.kind) {
   2136                             .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
   2137                             .payload => if (ty.unionTagTypeSafety()) |_| {
   2138                                 const data = cty.cast(Payload.Unnamed).?.data;
   2139                                 return ty.getOwnerDecl() == data.owner_decl and data.id == 0;
   2140                             } else unreachable,
   2141                         },
   2142 
   2143                         .anon_struct,
   2144                         .anon_union,
   2145                         .@"struct",
   2146                         .@"union",
   2147                         .packed_struct,
   2148                         .packed_union,
   2149                         => return self.eqlRecurse(
   2150                             ty,
   2151                             cty.cast(Payload.Aggregate).?.data.fwd_decl,
   2152                             .forward,
   2153                         ),
   2154 
   2155                         .function,
   2156                         .varargs_function,
   2157                         => {
   2158                             if (ty.zigTypeTag() != .Fn) return false;
   2159 
   2160                             const info = ty.fnInfo();
   2161                             assert(!info.is_generic);
   2162                             const data = cty.cast(Payload.Function).?.data;
   2163                             const param_kind: Kind = switch (self.kind) {
   2164                                 .forward, .forward_parameter => .forward_parameter,
   2165                                 .complete, .parameter, .global => .parameter,
   2166                                 .payload => unreachable,
   2167                             };
   2168 
   2169                             if (!self.eqlRecurse(info.return_type, data.return_type, param_kind))
   2170                                 return false;
   2171 
   2172                             var c_param_i: usize = 0;
   2173                             for (info.param_types) |param_type| {
   2174                                 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
   2175 
   2176                                 if (c_param_i >= data.param_types.len) return false;
   2177                                 const param_cty = data.param_types[c_param_i];
   2178                                 c_param_i += 1;
   2179 
   2180                                 if (!self.eqlRecurse(param_type, param_cty, param_kind))
   2181                                     return false;
   2182                             }
   2183                             return c_param_i == data.param_types.len;
   2184                         },
   2185 
   2186                         else => unreachable,
   2187                     }
   2188                 },
   2189             }
   2190         }
   2191 
   2192         pub fn hash(self: @This(), ty: Type) u64 {
   2193             var hasher = std.hash.Wyhash.init(0);
   2194             self.updateHasher(&hasher, ty);
   2195             return hasher.final();
   2196         }
   2197 
   2198         fn updateHasherRecurse(self: @This(), hasher: anytype, ty: Type, kind: Kind) void {
   2199             assert(!self.lookup.isMutable());
   2200 
   2201             var convert: Convert = undefined;
   2202             convert.initType(ty, kind, self.lookup) catch unreachable;
   2203 
   2204             const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
   2205             self_recurse.updateHasher(hasher, ty);
   2206         }
   2207 
   2208         pub fn updateHasher(self: @This(), hasher: anytype, ty: Type) void {
   2209             switch (self.convert.value) {
   2210                 .cty => |c| return c.updateHasher(hasher, self.lookup.getSet().?.*),
   2211                 .tag => |t| {
   2212                     autoHash(hasher, t);
   2213 
   2214                     const target = self.lookup.getTarget();
   2215                     switch (t) {
   2216                         .fwd_anon_struct,
   2217                         .fwd_anon_union,
   2218                         => {
   2219                             var name_buf: [
   2220                                 std.fmt.count("f{}", .{std.math.maxInt(usize)})
   2221                             ]u8 = undefined;
   2222 
   2223                             const zig_ty_tag = ty.zigTypeTag();
   2224                             for (0..switch (ty.zigTypeTag()) {
   2225                                 .Struct => ty.structFieldCount(),
   2226                                 .Union => ty.unionFields().count(),
   2227                                 else => unreachable,
   2228                             }) |field_i| {
   2229                                 const field_ty = ty.structFieldType(field_i);
   2230                                 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
   2231                                     !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   2232 
   2233                                 self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
   2234                                     .forward, .forward_parameter => .forward,
   2235                                     .complete, .parameter => .complete,
   2236                                     .global => .global,
   2237                                     .payload => unreachable,
   2238                                 });
   2239                                 hasher.update(if (ty.isSimpleTuple())
   2240                                     std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
   2241                                 else switch (zig_ty_tag) {
   2242                                     .Struct => ty.structFieldName(field_i),
   2243                                     .Union => ty.unionFields().keys()[field_i],
   2244                                     else => unreachable,
   2245                                 });
   2246                                 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, target).@"align");
   2247                             }
   2248                         },
   2249 
   2250                         .unnamed_struct,
   2251                         .unnamed_union,
   2252                         .packed_unnamed_struct,
   2253                         .packed_unnamed_union,
   2254                         => switch (self.kind) {
   2255                             .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
   2256                             .payload => if (ty.unionTagTypeSafety()) |_| {
   2257                                 autoHash(hasher, ty.getOwnerDecl());
   2258                                 autoHash(hasher, @as(u32, 0));
   2259                             } else unreachable,
   2260                         },
   2261 
   2262                         .anon_struct,
   2263                         .anon_union,
   2264                         .@"struct",
   2265                         .@"union",
   2266                         .packed_struct,
   2267                         .packed_union,
   2268                         => self.updateHasherRecurse(hasher, ty, .forward),
   2269 
   2270                         .function,
   2271                         .varargs_function,
   2272                         => {
   2273                             const info = ty.fnInfo();
   2274                             assert(!info.is_generic);
   2275                             const param_kind: Kind = switch (self.kind) {
   2276                                 .forward, .forward_parameter => .forward_parameter,
   2277                                 .complete, .parameter, .global => .parameter,
   2278                                 .payload => unreachable,
   2279                             };
   2280 
   2281                             self.updateHasherRecurse(hasher, info.return_type, param_kind);
   2282                             for (info.param_types) |param_type| {
   2283                                 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
   2284                                 self.updateHasherRecurse(hasher, param_type, param_kind);
   2285                             }
   2286                         },
   2287 
   2288                         else => unreachable,
   2289                     }
   2290                 },
   2291             }
   2292         }
   2293     };
   2294 
   2295     pub const TypeAdapter32 = struct {
   2296         kind: Kind,
   2297         lookup: Convert.Lookup,
   2298         convert: *const Convert,
   2299 
   2300         fn to64(self: @This()) TypeAdapter64 {
   2301             return .{ .kind = self.kind, .lookup = self.lookup, .convert = self.convert };
   2302         }
   2303 
   2304         pub fn eql(self: @This(), ty: Type, cty: CType, cty_index: usize) bool {
   2305             _ = cty_index;
   2306             return self.to64().eql(ty, cty);
   2307         }
   2308 
   2309         pub fn hash(self: @This(), ty: Type) u32 {
   2310             return @truncate(u32, self.to64().hash(ty));
   2311         }
   2312     };
   2313 };