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 };