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