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