| author | |
| committer | |
| log | d18881de1be811c1dff52590223b92c916c4b773 |
| tree | c4c2f82134654737d0921efc360f900e428d5d92 |
| parent | 88dbd62bcbac24c09791a7838d2f08c2f540967a |
11 files changed, 1147 insertions(+), 1264 deletions(-)
src/InternPool.zig+185-18| ... | @@ -137,9 +137,14 @@ pub const Key = union(enum) { | ... | @@ -137,9 +137,14 @@ pub const Key = union(enum) { |
| 137 | payload_type: Index, | 137 | payload_type: Index, |
| 138 | }, | 138 | }, |
| 139 | simple_type: SimpleType, | 139 | simple_type: SimpleType, |
| 140 | /// If `empty_struct_type` is handled separately, then this value may be | 140 | /// This represents a struct that has been explicitly declared in source code, |
| 141 | /// safely assumed to never be `none`. | 141 | /// or was created with `@Type`. It is unique and based on a declaration. |
| 142 | /// It may be a tuple, if declared like this: `struct {A, B, C}`. | ||
| 142 | struct_type: StructType, | 143 | struct_type: StructType, |
| 144 | /// This is an anonymous struct or tuple type which has no corresponding | ||
| 145 | /// declaration. It is used for types that have no `struct` keyword in the | ||
| 146 | /// source code, and were not created via `@Type`. | ||
| 147 | anon_struct_type: AnonStructType, | ||
| 143 | union_type: UnionType, | 148 | union_type: UnionType, |
| 144 | opaque_type: OpaqueType, | 149 | opaque_type: OpaqueType, |
| 145 | enum_type: EnumType, | 150 | enum_type: EnumType, |
| ... | @@ -168,7 +173,7 @@ pub const Key = union(enum) { | ... | @@ -168,7 +173,7 @@ pub const Key = union(enum) { |
| 168 | /// Each element/field stored as an `Index`. | 173 | /// Each element/field stored as an `Index`. |
| 169 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, | 174 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| 170 | /// so the slice length will be one more than the type's array length. | 175 | /// so the slice length will be one more than the type's array length. |
| 171 | aggregate: Aggregate, | 176 | aggregate: Key.Aggregate, |
| 172 | /// An instance of a union. | 177 | /// An instance of a union. |
| 173 | un: Union, | 178 | un: Union, |
| 174 | 179 | ||
| ... | @@ -222,22 +227,25 @@ pub const Key = union(enum) { | ... | @@ -222,22 +227,25 @@ pub const Key = union(enum) { |
| 222 | namespace: Module.Namespace.Index, | 227 | namespace: Module.Namespace.Index, |
| 223 | }; | 228 | }; |
| 224 | 229 | ||
| 225 | /// There are three possibilities here: | ||
| 226 | /// * `@TypeOf(.{})` (untyped empty struct literal) | ||
| 227 | /// - namespace == .none, index == .none | ||
| 228 | /// * A struct which has a namepace, but no fields. | ||
| 229 | /// - index == .none | ||
| 230 | /// * A struct which has fields as well as a namepace. | ||
| 231 | pub const StructType = struct { | 230 | pub const StructType = struct { |
| 232 | /// The `none` tag is used to represent two cases: | 231 | /// The `none` tag is used to represent a struct with no fields. |
| 233 | /// * `@TypeOf(.{})`, in which case `namespace` will also be `none`. | ||
| 234 | /// * A struct with no fields, in which case `namespace` will be populated. | ||
| 235 | index: Module.Struct.OptionalIndex, | 232 | index: Module.Struct.OptionalIndex, |
| 236 | /// This will be `none` only in the case of `@TypeOf(.{})` | 233 | /// May be `none` if the struct has no declarations. |
| 237 | /// (`Index.empty_struct_type`). | ||
| 238 | namespace: Module.Namespace.OptionalIndex, | 234 | namespace: Module.Namespace.OptionalIndex, |
| 239 | }; | 235 | }; |
| 240 | 236 | ||
| 237 | pub const AnonStructType = struct { | ||
| 238 | types: []const Index, | ||
| 239 | /// This may be empty, indicating this is a tuple. | ||
| 240 | names: []const NullTerminatedString, | ||
| 241 | /// These elements may be `none`, indicating runtime-known. | ||
| 242 | values: []const Index, | ||
| 243 | |||
| 244 | pub fn isTuple(self: AnonStructType) bool { | ||
| 245 | return self.names.len == 0; | ||
| 246 | } | ||
| 247 | }; | ||
| 248 | |||
| 241 | pub const UnionType = struct { | 249 | pub const UnionType = struct { |
| 242 | index: Module.Union.Index, | 250 | index: Module.Union.Index, |
| 243 | runtime_tag: RuntimeTag, | 251 | runtime_tag: RuntimeTag, |
| ... | @@ -498,6 +506,12 @@ pub const Key = union(enum) { | ... | @@ -498,6 +506,12 @@ pub const Key = union(enum) { |
| 498 | std.hash.autoHash(hasher, aggregate.ty); | 506 | std.hash.autoHash(hasher, aggregate.ty); |
| 499 | for (aggregate.fields) |field| std.hash.autoHash(hasher, field); | 507 | for (aggregate.fields) |field| std.hash.autoHash(hasher, field); |
| 500 | }, | 508 | }, |
| 509 | |||
| 510 | .anon_struct_type => |anon_struct_type| { | ||
| 511 | for (anon_struct_type.types) |elem| std.hash.autoHash(hasher, elem); | ||
| 512 | for (anon_struct_type.values) |elem| std.hash.autoHash(hasher, elem); | ||
| 513 | for (anon_struct_type.names) |elem| std.hash.autoHash(hasher, elem); | ||
| 514 | }, | ||
| 501 | } | 515 | } |
| 502 | } | 516 | } |
| 503 | 517 | ||
| ... | @@ -650,6 +664,12 @@ pub const Key = union(enum) { | ... | @@ -650,6 +664,12 @@ pub const Key = union(enum) { |
| 650 | if (a_info.ty != b_info.ty) return false; | 664 | if (a_info.ty != b_info.ty) return false; |
| 651 | return std.mem.eql(Index, a_info.fields, b_info.fields); | 665 | return std.mem.eql(Index, a_info.fields, b_info.fields); |
| 652 | }, | 666 | }, |
| 667 | .anon_struct_type => |a_info| { | ||
| 668 | const b_info = b.anon_struct_type; | ||
| 669 | return std.mem.eql(Index, a_info.types, b_info.types) and | ||
| 670 | std.mem.eql(Index, a_info.values, b_info.values) and | ||
| 671 | std.mem.eql(NullTerminatedString, a_info.names, b_info.names); | ||
| 672 | }, | ||
| 653 | } | 673 | } |
| 654 | } | 674 | } |
| 655 | 675 | ||
| ... | @@ -666,6 +686,7 @@ pub const Key = union(enum) { | ... | @@ -666,6 +686,7 @@ pub const Key = union(enum) { |
| 666 | .union_type, | 686 | .union_type, |
| 667 | .opaque_type, | 687 | .opaque_type, |
| 668 | .enum_type, | 688 | .enum_type, |
| 689 | .anon_struct_type, | ||
| 669 | => .type_type, | 690 | => .type_type, |
| 670 | 691 | ||
| 671 | inline .ptr, | 692 | inline .ptr, |
| ... | @@ -1020,9 +1041,10 @@ pub const static_keys = [_]Key{ | ... | @@ -1020,9 +1041,10 @@ pub const static_keys = [_]Key{ |
| 1020 | .{ .simple_type = .var_args_param }, | 1041 | .{ .simple_type = .var_args_param }, |
| 1021 | 1042 | ||
| 1022 | // empty_struct_type | 1043 | // empty_struct_type |
| 1023 | .{ .struct_type = .{ | 1044 | .{ .anon_struct_type = .{ |
| 1024 | .namespace = .none, | 1045 | .types = &.{}, |
| 1025 | .index = .none, | 1046 | .names = &.{}, |
| 1047 | .values = &.{}, | ||
| 1026 | } }, | 1048 | } }, |
| 1027 | 1049 | ||
| 1028 | .{ .simple_value = .undefined }, | 1050 | .{ .simple_value = .undefined }, |
| ... | @@ -1144,6 +1166,12 @@ pub const Tag = enum(u8) { | ... | @@ -1144,6 +1166,12 @@ pub const Tag = enum(u8) { |
| 1144 | /// Module.Struct object allocated for it. | 1166 | /// Module.Struct object allocated for it. |
| 1145 | /// data is Module.Namespace.Index. | 1167 | /// data is Module.Namespace.Index. |
| 1146 | type_struct_ns, | 1168 | type_struct_ns, |
| 1169 | /// An AnonStructType which stores types, names, and values for each field. | ||
| 1170 | /// data is extra index of `TypeStructAnon`. | ||
| 1171 | type_struct_anon, | ||
| 1172 | /// An AnonStructType which has only types and values for each field. | ||
| 1173 | /// data is extra index of `TypeStructAnon`. | ||
| 1174 | type_tuple_anon, | ||
| 1147 | /// A tagged union type. | 1175 | /// A tagged union type. |
| 1148 | /// `data` is `Module.Union.Index`. | 1176 | /// `data` is `Module.Union.Index`. |
| 1149 | type_union_tagged, | 1177 | type_union_tagged, |
| ... | @@ -1249,6 +1277,26 @@ pub const Tag = enum(u8) { | ... | @@ -1249,6 +1277,26 @@ pub const Tag = enum(u8) { |
| 1249 | only_possible_value, | 1277 | only_possible_value, |
| 1250 | /// data is extra index to Key.Union. | 1278 | /// data is extra index to Key.Union. |
| 1251 | union_value, | 1279 | union_value, |
| 1280 | /// An instance of a struct, array, or vector. | ||
| 1281 | /// data is extra index to `Aggregate`. | ||
| 1282 | aggregate, | ||
| 1283 | }; | ||
| 1284 | |||
| 1285 | /// Trailing: | ||
| 1286 | /// 0. element: Index for each len | ||
| 1287 | /// len is determined by the aggregate type. | ||
| 1288 | pub const Aggregate = struct { | ||
| 1289 | /// The type of the aggregate. | ||
| 1290 | ty: Index, | ||
| 1291 | }; | ||
| 1292 | |||
| 1293 | /// Trailing: | ||
| 1294 | /// 0. type: Index for each fields_len | ||
| 1295 | /// 1. value: Index for each fields_len | ||
| 1296 | /// 2. name: NullTerminatedString for each fields_len | ||
| 1297 | /// The set of field names is omitted when the `Tag` is `type_tuple_anon`. | ||
| 1298 | pub const TypeStructAnon = struct { | ||
| 1299 | fields_len: u32, | ||
| 1252 | }; | 1300 | }; |
| 1253 | 1301 | ||
| 1254 | /// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to | 1302 | /// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to |
| ... | @@ -1572,6 +1620,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ... | @@ -1572,6 +1620,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 1572 | } | 1620 | } |
| 1573 | 1621 | ||
| 1574 | pub fn indexToKey(ip: InternPool, index: Index) Key { | 1622 | pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1623 | assert(index != .none); | ||
| 1575 | const item = ip.items.get(@enumToInt(index)); | 1624 | const item = ip.items.get(@enumToInt(index)); |
| 1576 | const data = item.data; | 1625 | const data = item.data; |
| 1577 | return switch (item.tag) { | 1626 | return switch (item.tag) { |
| ... | @@ -1659,6 +1708,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -1659,6 +1708,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1659 | .namespace = @intToEnum(Module.Namespace.Index, data).toOptional(), | 1708 | .namespace = @intToEnum(Module.Namespace.Index, data).toOptional(), |
| 1660 | } }, | 1709 | } }, |
| 1661 | 1710 | ||
| 1711 | .type_struct_anon => { | ||
| 1712 | const type_struct_anon = ip.extraDataTrail(TypeStructAnon, data); | ||
| 1713 | const fields_len = type_struct_anon.data.fields_len; | ||
| 1714 | const types = ip.extra.items[type_struct_anon.end..][0..fields_len]; | ||
| 1715 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | ||
| 1716 | const names = ip.extra.items[type_struct_anon.end + 2 * fields_len ..][0..fields_len]; | ||
| 1717 | return .{ .anon_struct_type = .{ | ||
| 1718 | .types = @ptrCast([]const Index, types), | ||
| 1719 | .values = @ptrCast([]const Index, values), | ||
| 1720 | .names = @ptrCast([]const NullTerminatedString, names), | ||
| 1721 | } }; | ||
| 1722 | }, | ||
| 1723 | .type_tuple_anon => { | ||
| 1724 | const type_struct_anon = ip.extraDataTrail(TypeStructAnon, data); | ||
| 1725 | const fields_len = type_struct_anon.data.fields_len; | ||
| 1726 | const types = ip.extra.items[type_struct_anon.end..][0..fields_len]; | ||
| 1727 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | ||
| 1728 | return .{ .anon_struct_type = .{ | ||
| 1729 | .types = @ptrCast([]const Index, types), | ||
| 1730 | .values = @ptrCast([]const Index, values), | ||
| 1731 | .names = &.{}, | ||
| 1732 | } }; | ||
| 1733 | }, | ||
| 1734 | |||
| 1662 | .type_union_untagged => .{ .union_type = .{ | 1735 | .type_union_untagged => .{ .union_type = .{ |
| 1663 | .index = @intToEnum(Module.Union.Index, data), | 1736 | .index = @intToEnum(Module.Union.Index, data), |
| 1664 | .runtime_tag = .none, | 1737 | .runtime_tag = .none, |
| ... | @@ -1797,6 +1870,15 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -1797,6 +1870,15 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1797 | else => unreachable, | 1870 | else => unreachable, |
| 1798 | }; | 1871 | }; |
| 1799 | }, | 1872 | }, |
| 1873 | .aggregate => { | ||
| 1874 | const extra = ip.extraDataTrail(Aggregate, data); | ||
| 1875 | const len = @intCast(u32, ip.aggregateTypeLen(extra.data.ty)); | ||
| 1876 | const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]); | ||
| 1877 | return .{ .aggregate = .{ | ||
| 1878 | .ty = extra.data.ty, | ||
| 1879 | .fields = fields, | ||
| 1880 | } }; | ||
| 1881 | }, | ||
| 1800 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, | 1882 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, |
| 1801 | .enum_tag => .{ .enum_tag = ip.extraData(Key.EnumTag, data) }, | 1883 | .enum_tag => .{ .enum_tag = ip.extraData(Key.EnumTag, data) }, |
| 1802 | }; | 1884 | }; |
| ... | @@ -1982,6 +2064,45 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -1982,6 +2064,45 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1982 | }); | 2064 | }); |
| 1983 | }, | 2065 | }, |
| 1984 | 2066 | ||
| 2067 | .anon_struct_type => |anon_struct_type| { | ||
| 2068 | assert(anon_struct_type.types.len == anon_struct_type.values.len); | ||
| 2069 | for (anon_struct_type.types) |elem| assert(elem != .none); | ||
| 2070 | |||
| 2071 | const fields_len = @intCast(u32, anon_struct_type.types.len); | ||
| 2072 | if (anon_struct_type.names.len == 0) { | ||
| 2073 | try ip.extra.ensureUnusedCapacity( | ||
| 2074 | gpa, | ||
| 2075 | @typeInfo(TypeStructAnon).Struct.fields.len + (fields_len * 2), | ||
| 2076 | ); | ||
| 2077 | ip.items.appendAssumeCapacity(.{ | ||
| 2078 | .tag = .type_tuple_anon, | ||
| 2079 | .data = ip.addExtraAssumeCapacity(TypeStructAnon{ | ||
| 2080 | .fields_len = fields_len, | ||
| 2081 | }), | ||
| 2082 | }); | ||
| 2083 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.types)); | ||
| 2084 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.values)); | ||
| 2085 | return @intToEnum(Index, ip.items.len - 1); | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | assert(anon_struct_type.names.len == anon_struct_type.types.len); | ||
| 2089 | |||
| 2090 | try ip.extra.ensureUnusedCapacity( | ||
| 2091 | gpa, | ||
| 2092 | @typeInfo(TypeStructAnon).Struct.fields.len + (fields_len * 3), | ||
| 2093 | ); | ||
| 2094 | ip.items.appendAssumeCapacity(.{ | ||
| 2095 | .tag = .type_struct_anon, | ||
| 2096 | .data = ip.addExtraAssumeCapacity(TypeStructAnon{ | ||
| 2097 | .fields_len = fields_len, | ||
| 2098 | }), | ||
| 2099 | }); | ||
| 2100 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.types)); | ||
| 2101 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.values)); | ||
| 2102 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.names)); | ||
| 2103 | return @intToEnum(Index, ip.items.len - 1); | ||
| 2104 | }, | ||
| 2105 | |||
| 1985 | .union_type => |union_type| { | 2106 | .union_type => |union_type| { |
| 1986 | ip.items.appendAssumeCapacity(.{ | 2107 | ip.items.appendAssumeCapacity(.{ |
| 1987 | .tag = switch (union_type.runtime_tag) { | 2108 | .tag = switch (union_type.runtime_tag) { |
| ... | @@ -2269,6 +2390,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2269,6 +2390,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2269 | }, | 2390 | }, |
| 2270 | 2391 | ||
| 2271 | .aggregate => |aggregate| { | 2392 | .aggregate => |aggregate| { |
| 2393 | assert(aggregate.ty != .none); | ||
| 2394 | for (aggregate.fields) |elem| assert(elem != .none); | ||
| 2395 | if (aggregate.fields.len != ip.aggregateTypeLen(aggregate.ty)) { | ||
| 2396 | std.debug.print("aggregate fields len = {d}, type len = {d}\n", .{ | ||
| 2397 | aggregate.fields.len, | ||
| 2398 | ip.aggregateTypeLen(aggregate.ty), | ||
| 2399 | }); | ||
| 2400 | } | ||
| 2401 | assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty)); | ||
| 2402 | |||
| 2272 | if (aggregate.fields.len == 0) { | 2403 | if (aggregate.fields.len == 0) { |
| 2273 | ip.items.appendAssumeCapacity(.{ | 2404 | ip.items.appendAssumeCapacity(.{ |
| 2274 | .tag = .only_possible_value, | 2405 | .tag = .only_possible_value, |
| ... | @@ -2276,7 +2407,19 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2276,7 +2407,19 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2276 | }); | 2407 | }); |
| 2277 | return @intToEnum(Index, ip.items.len - 1); | 2408 | return @intToEnum(Index, ip.items.len - 1); |
| 2278 | } | 2409 | } |
| 2279 | @panic("TODO"); | 2410 | |
| 2411 | try ip.extra.ensureUnusedCapacity( | ||
| 2412 | gpa, | ||
| 2413 | @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len, | ||
| 2414 | ); | ||
| 2415 | |||
| 2416 | ip.items.appendAssumeCapacity(.{ | ||
| 2417 | .tag = .aggregate, | ||
| 2418 | .data = ip.addExtraAssumeCapacity(Aggregate{ | ||
| 2419 | .ty = aggregate.ty, | ||
| 2420 | }), | ||
| 2421 | }); | ||
| 2422 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.fields)); | ||
| 2280 | }, | 2423 | }, |
| 2281 | 2424 | ||
| 2282 | .un => |un| { | 2425 | .un => |un| { |
| ... | @@ -2913,6 +3056,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { | ... | @@ -2913,6 +3056,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 2913 | .type_opaque => @sizeOf(Key.OpaqueType), | 3056 | .type_opaque => @sizeOf(Key.OpaqueType), |
| 2914 | .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl), | 3057 | .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl), |
| 2915 | .type_struct_ns => @sizeOf(Module.Namespace), | 3058 | .type_struct_ns => @sizeOf(Module.Namespace), |
| 3059 | .type_struct_anon => b: { | ||
| 3060 | const info = ip.extraData(TypeStructAnon, data); | ||
| 3061 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len); | ||
| 3062 | }, | ||
| 3063 | .type_tuple_anon => b: { | ||
| 3064 | const info = ip.extraData(TypeStructAnon, data); | ||
| 3065 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); | ||
| 3066 | }, | ||
| 2916 | 3067 | ||
| 2917 | .type_union_tagged, | 3068 | .type_union_tagged, |
| 2918 | .type_union_untagged, | 3069 | .type_union_untagged, |
| ... | @@ -2942,6 +3093,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { | ... | @@ -2942,6 +3093,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 2942 | }, | 3093 | }, |
| 2943 | .enum_tag => @sizeOf(Key.EnumTag), | 3094 | .enum_tag => @sizeOf(Key.EnumTag), |
| 2944 | 3095 | ||
| 3096 | .aggregate => b: { | ||
| 3097 | const info = ip.extraData(Aggregate, data); | ||
| 3098 | const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty)); | ||
| 3099 | break :b @sizeOf(Aggregate) + (@sizeOf(u32) * fields_len); | ||
| 3100 | }, | ||
| 3101 | |||
| 2945 | .float_f16 => 0, | 3102 | .float_f16 => 0, |
| 2946 | .float_f32 => 0, | 3103 | .float_f32 => 0, |
| 2947 | .float_f64 => @sizeOf(Float64), | 3104 | .float_f64 => @sizeOf(Float64), |
| ... | @@ -3079,3 +3236,13 @@ pub fn toEnum(ip: InternPool, comptime E: type, i: Index) E { | ... | @@ -3079,3 +3236,13 @@ pub fn toEnum(ip: InternPool, comptime E: type, i: Index) E { |
| 3079 | const int = ip.indexToKey(i).enum_tag.int; | 3236 | const int = ip.indexToKey(i).enum_tag.int; |
| 3080 | return @intToEnum(E, ip.indexToKey(int).int.storage.u64); | 3237 | return @intToEnum(E, ip.indexToKey(int).int.storage.u64); |
| 3081 | } | 3238 | } |
| 3239 | |||
| 3240 | pub fn aggregateTypeLen(ip: InternPool, ty: Index) u64 { | ||
| 3241 | return switch (ip.indexToKey(ty)) { | ||
| 3242 | .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(), | ||
| 3243 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | ||
| 3244 | .array_type => |array_type| array_type.len, | ||
| 3245 | .vector_type => |vector_type| vector_type.len, | ||
| 3246 | else => unreachable, | ||
| 3247 | }; | ||
| 3248 | } |
src/Sema.zig+384-331| ... | @@ -7896,12 +7896,15 @@ fn resolveGenericInstantiationType( | ... | @@ -7896,12 +7896,15 @@ fn resolveGenericInstantiationType( |
| 7896 | } | 7896 | } |
| 7897 | 7897 | ||
| 7898 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { | 7898 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 7899 | if (!ty.isSimpleTupleOrAnonStruct()) return; | 7899 | const mod = sema.mod; |
| 7900 | const tuple = ty.tupleFields(); | 7900 | const tuple = switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 7901 | for (tuple.values, 0..) |field_val, i| { | 7901 | .anon_struct_type => |tuple| tuple, |
| 7902 | try sema.resolveTupleLazyValues(block, src, tuple.types[i]); | 7902 | else => return, |
| 7903 | if (field_val.ip_index == .unreachable_value) continue; | 7903 | }; |
| 7904 | try sema.resolveLazyValue(field_val); | 7904 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 7905 | try sema.resolveTupleLazyValues(block, src, field_ty.toType()); | ||
| 7906 | if (field_val == .none) continue; | ||
| 7907 | try sema.resolveLazyValue(field_val.toValue()); | ||
| 7905 | } | 7908 | } |
| 7906 | } | 7909 | } |
| 7907 | 7910 | ||
| ... | @@ -12038,31 +12041,49 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12038,31 +12041,49 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12038 | const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); | 12041 | const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 12039 | const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); | 12042 | const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); |
| 12040 | const ty = try sema.resolveTypeFields(unresolved_ty); | 12043 | const ty = try sema.resolveTypeFields(unresolved_ty); |
| 12044 | const ip = &mod.intern_pool; | ||
| 12041 | 12045 | ||
| 12042 | const has_field = hf: { | 12046 | const has_field = hf: { |
| 12043 | if (ty.isSlice(mod)) { | 12047 | switch (ip.indexToKey(ty.ip_index)) { |
| 12044 | if (mem.eql(u8, field_name, "ptr")) break :hf true; | 12048 | .ptr_type => |ptr_type| switch (ptr_type.size) { |
| 12045 | if (mem.eql(u8, field_name, "len")) break :hf true; | 12049 | .Slice => { |
| 12046 | break :hf false; | 12050 | if (mem.eql(u8, field_name, "ptr")) break :hf true; |
| 12047 | } | 12051 | if (mem.eql(u8, field_name, "len")) break :hf true; |
| 12048 | if (ty.castTag(.anon_struct)) |pl| { | 12052 | break :hf false; |
| 12049 | break :hf for (pl.data.names) |name| { | 12053 | }, |
| 12050 | if (mem.eql(u8, name, field_name)) break true; | 12054 | else => {}, |
| 12051 | } else false; | 12055 | }, |
| 12052 | } | 12056 | .anon_struct_type => |anon_struct| { |
| 12053 | if (ty.isTuple(mod)) { | 12057 | if (anon_struct.names.len != 0) { |
| 12054 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; | 12058 | // If the string is not interned, then the field certainly is not present. |
| 12055 | break :hf field_index < ty.structFieldCount(mod); | 12059 | const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; |
| 12056 | } | 12060 | break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, name_interned) != null; |
| 12057 | break :hf switch (ty.zigTypeTag(mod)) { | 12061 | } else { |
| 12058 | .Struct => ty.structFields(mod).contains(field_name), | 12062 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; |
| 12059 | .Union => ty.unionFields(mod).contains(field_name), | 12063 | break :hf field_index < ty.structFieldCount(mod); |
| 12060 | .Enum => ty.enumFieldIndex(field_name, mod) != null, | 12064 | } |
| 12061 | .Array => mem.eql(u8, field_name, "len"), | 12065 | }, |
| 12062 | else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | 12066 | .struct_type => |struct_type| { |
| 12063 | ty.fmt(sema.mod), | 12067 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; |
| 12064 | }), | 12068 | assert(struct_obj.haveFieldTypes()); |
| 12065 | }; | 12069 | break :hf struct_obj.fields.contains(field_name); |
| 12070 | }, | ||
| 12071 | .union_type => |union_type| { | ||
| 12072 | const union_obj = mod.unionPtr(union_type.index); | ||
| 12073 | assert(union_obj.haveFieldTypes()); | ||
| 12074 | break :hf union_obj.fields.contains(field_name); | ||
| 12075 | }, | ||
| 12076 | .enum_type => |enum_type| { | ||
| 12077 | // If the string is not interned, then the field certainly is not present. | ||
| 12078 | const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; | ||
| 12079 | break :hf enum_type.nameIndex(ip, name_interned) != null; | ||
| 12080 | }, | ||
| 12081 | .array_type => break :hf mem.eql(u8, field_name, "len"), | ||
| 12082 | else => {}, | ||
| 12083 | } | ||
| 12084 | return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | ||
| 12085 | ty.fmt(sema.mod), | ||
| 12086 | }); | ||
| 12066 | }; | 12087 | }; |
| 12067 | if (has_field) { | 12088 | if (has_field) { |
| 12068 | return Air.Inst.Ref.bool_true; | 12089 | return Air.Inst.Ref.bool_true; |
| ... | @@ -12632,42 +12653,48 @@ fn analyzeTupleCat( | ... | @@ -12632,42 +12653,48 @@ fn analyzeTupleCat( |
| 12632 | } | 12653 | } |
| 12633 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); | 12654 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); |
| 12634 | 12655 | ||
| 12635 | const types = try sema.arena.alloc(Type, final_len); | 12656 | const types = try sema.arena.alloc(InternPool.Index, final_len); |
| 12636 | const values = try sema.arena.alloc(Value, final_len); | 12657 | const values = try sema.arena.alloc(InternPool.Index, final_len); |
| 12637 | 12658 | ||
| 12638 | const opt_runtime_src = rs: { | 12659 | const opt_runtime_src = rs: { |
| 12639 | var runtime_src: ?LazySrcLoc = null; | 12660 | var runtime_src: ?LazySrcLoc = null; |
| 12640 | var i: u32 = 0; | 12661 | var i: u32 = 0; |
| 12641 | while (i < lhs_len) : (i += 1) { | 12662 | while (i < lhs_len) : (i += 1) { |
| 12642 | types[i] = lhs_ty.structFieldType(i, mod); | 12663 | types[i] = lhs_ty.structFieldType(i, mod).ip_index; |
| 12643 | const default_val = lhs_ty.structFieldDefaultValue(i, mod); | 12664 | const default_val = lhs_ty.structFieldDefaultValue(i, mod); |
| 12644 | values[i] = default_val; | 12665 | values[i] = default_val.ip_index; |
| 12645 | const operand_src = lhs_src; // TODO better source location | 12666 | const operand_src = lhs_src; // TODO better source location |
| 12646 | if (default_val.ip_index == .unreachable_value) { | 12667 | if (default_val.ip_index == .unreachable_value) { |
| 12647 | runtime_src = operand_src; | 12668 | runtime_src = operand_src; |
| 12669 | values[i] = .none; | ||
| 12648 | } | 12670 | } |
| 12649 | } | 12671 | } |
| 12650 | i = 0; | 12672 | i = 0; |
| 12651 | while (i < rhs_len) : (i += 1) { | 12673 | while (i < rhs_len) : (i += 1) { |
| 12652 | types[i + lhs_len] = rhs_ty.structFieldType(i, mod); | 12674 | types[i + lhs_len] = rhs_ty.structFieldType(i, mod).ip_index; |
| 12653 | const default_val = rhs_ty.structFieldDefaultValue(i, mod); | 12675 | const default_val = rhs_ty.structFieldDefaultValue(i, mod); |
| 12654 | values[i + lhs_len] = default_val; | 12676 | values[i + lhs_len] = default_val.ip_index; |
| 12655 | const operand_src = rhs_src; // TODO better source location | 12677 | const operand_src = rhs_src; // TODO better source location |
| 12656 | if (default_val.ip_index == .unreachable_value) { | 12678 | if (default_val.ip_index == .unreachable_value) { |
| 12657 | runtime_src = operand_src; | 12679 | runtime_src = operand_src; |
| 12680 | values[i + lhs_len] = .none; | ||
| 12658 | } | 12681 | } |
| 12659 | } | 12682 | } |
| 12660 | break :rs runtime_src; | 12683 | break :rs runtime_src; |
| 12661 | }; | 12684 | }; |
| 12662 | 12685 | ||
| 12663 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 12686 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 12664 | .types = types, | 12687 | .types = types, |
| 12665 | .values = values, | 12688 | .values = values, |
| 12666 | }); | 12689 | .names = &.{}, |
| 12690 | } }); | ||
| 12667 | 12691 | ||
| 12668 | const runtime_src = opt_runtime_src orelse { | 12692 | const runtime_src = opt_runtime_src orelse { |
| 12669 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 12693 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 12670 | return sema.addConstant(tuple_ty, tuple_val); | 12694 | .ty = tuple_ty, |
| 12695 | .fields = values, | ||
| 12696 | } }); | ||
| 12697 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | ||
| 12671 | }; | 12698 | }; |
| 12672 | 12699 | ||
| 12673 | try sema.requireRuntimeBlock(block, src, runtime_src); | 12700 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -12685,7 +12712,7 @@ fn analyzeTupleCat( | ... | @@ -12685,7 +12712,7 @@ fn analyzeTupleCat( |
| 12685 | try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); | 12712 | try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); |
| 12686 | } | 12713 | } |
| 12687 | 12714 | ||
| 12688 | return block.addAggregateInit(tuple_ty, element_refs); | 12715 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 12689 | } | 12716 | } |
| 12690 | 12717 | ||
| 12691 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 12718 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -12938,7 +12965,7 @@ fn analyzeTupleMul( | ... | @@ -12938,7 +12965,7 @@ fn analyzeTupleMul( |
| 12938 | block: *Block, | 12965 | block: *Block, |
| 12939 | src_node: i32, | 12966 | src_node: i32, |
| 12940 | operand: Air.Inst.Ref, | 12967 | operand: Air.Inst.Ref, |
| 12941 | factor: u64, | 12968 | factor: usize, |
| 12942 | ) CompileError!Air.Inst.Ref { | 12969 | ) CompileError!Air.Inst.Ref { |
| 12943 | const mod = sema.mod; | 12970 | const mod = sema.mod; |
| 12944 | const operand_ty = sema.typeOf(operand); | 12971 | const operand_ty = sema.typeOf(operand); |
| ... | @@ -12947,44 +12974,45 @@ fn analyzeTupleMul( | ... | @@ -12947,44 +12974,45 @@ fn analyzeTupleMul( |
| 12947 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; | 12974 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12948 | 12975 | ||
| 12949 | const tuple_len = operand_ty.structFieldCount(mod); | 12976 | const tuple_len = operand_ty.structFieldCount(mod); |
| 12950 | const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch | 12977 | const final_len = std.math.mul(usize, tuple_len, factor) catch |
| 12951 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); | 12978 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 12952 | 12979 | ||
| 12953 | if (final_len_u64 == 0) { | 12980 | if (final_len == 0) { |
| 12954 | return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); | 12981 | return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); |
| 12955 | } | 12982 | } |
| 12956 | const final_len = try sema.usizeCast(block, rhs_src, final_len_u64); | 12983 | const types = try sema.arena.alloc(InternPool.Index, final_len); |
| 12957 | 12984 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12958 | const types = try sema.arena.alloc(Type, final_len); | ||
| 12959 | const values = try sema.arena.alloc(Value, final_len); | ||
| 12960 | 12985 | ||
| 12961 | const opt_runtime_src = rs: { | 12986 | const opt_runtime_src = rs: { |
| 12962 | var runtime_src: ?LazySrcLoc = null; | 12987 | var runtime_src: ?LazySrcLoc = null; |
| 12963 | var i: u32 = 0; | 12988 | for (0..tuple_len) |i| { |
| 12964 | while (i < tuple_len) : (i += 1) { | 12989 | types[i] = operand_ty.structFieldType(i, mod).ip_index; |
| 12965 | types[i] = operand_ty.structFieldType(i, mod); | 12990 | values[i] = operand_ty.structFieldDefaultValue(i, mod).ip_index; |
| 12966 | values[i] = operand_ty.structFieldDefaultValue(i, mod); | ||
| 12967 | const operand_src = lhs_src; // TODO better source location | 12991 | const operand_src = lhs_src; // TODO better source location |
| 12968 | if (values[i].ip_index == .unreachable_value) { | 12992 | if (values[i] == .unreachable_value) { |
| 12969 | runtime_src = operand_src; | 12993 | runtime_src = operand_src; |
| 12994 | values[i] = .none; // TODO don't treat unreachable_value as special | ||
| 12970 | } | 12995 | } |
| 12971 | } | 12996 | } |
| 12972 | i = 0; | 12997 | for (0..factor) |i| { |
| 12973 | while (i < factor) : (i += 1) { | 12998 | mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); |
| 12974 | mem.copyForwards(Type, types[tuple_len * i ..], types[0..tuple_len]); | 12999 | mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); |
| 12975 | mem.copyForwards(Value, values[tuple_len * i ..], values[0..tuple_len]); | ||
| 12976 | } | 13000 | } |
| 12977 | break :rs runtime_src; | 13001 | break :rs runtime_src; |
| 12978 | }; | 13002 | }; |
| 12979 | 13003 | ||
| 12980 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 13004 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 12981 | .types = types, | 13005 | .types = types, |
| 12982 | .values = values, | 13006 | .values = values, |
| 12983 | }); | 13007 | .names = &.{}, |
| 13008 | } }); | ||
| 12984 | 13009 | ||
| 12985 | const runtime_src = opt_runtime_src orelse { | 13010 | const runtime_src = opt_runtime_src orelse { |
| 12986 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 13011 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 12987 | return sema.addConstant(tuple_ty, tuple_val); | 13012 | .ty = tuple_ty, |
| 13013 | .fields = values, | ||
| 13014 | } }); | ||
| 13015 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | ||
| 12988 | }; | 13016 | }; |
| 12989 | 13017 | ||
| 12990 | try sema.requireRuntimeBlock(block, src, runtime_src); | 13018 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -13000,7 +13028,7 @@ fn analyzeTupleMul( | ... | @@ -13000,7 +13028,7 @@ fn analyzeTupleMul( |
| 13000 | @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]); | 13028 | @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]); |
| 13001 | } | 13029 | } |
| 13002 | 13030 | ||
| 13003 | return block.addAggregateInit(tuple_ty, element_refs); | 13031 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 13004 | } | 13032 | } |
| 13005 | 13033 | ||
| 13006 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13034 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -13020,7 +13048,8 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13020,7 +13048,8 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13020 | if (lhs_ty.isTuple(mod)) { | 13048 | if (lhs_ty.isTuple(mod)) { |
| 13021 | // In `**` rhs must be comptime-known, but lhs can be runtime-known | 13049 | // In `**` rhs must be comptime-known, but lhs can be runtime-known |
| 13022 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); | 13050 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); |
| 13023 | return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor); | 13051 | const factor_casted = try sema.usizeCast(block, rhs_src, factor); |
| 13052 | return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted); | ||
| 13024 | } | 13053 | } |
| 13025 | 13054 | ||
| 13026 | // Analyze the lhs first, to catch the case that someone tried to do exponentiation | 13055 | // Analyze the lhs first, to catch the case that someone tried to do exponentiation |
| ... | @@ -14533,19 +14562,14 @@ fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { | ... | @@ -14533,19 +14562,14 @@ fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { |
| 14533 | .child = .u1_type, | 14562 | .child = .u1_type, |
| 14534 | }) else Type.u1; | 14563 | }) else Type.u1; |
| 14535 | 14564 | ||
| 14536 | const types = try sema.arena.alloc(Type, 2); | 14565 | const types = [2]InternPool.Index{ ty.ip_index, ov_ty.ip_index }; |
| 14537 | const values = try sema.arena.alloc(Value, 2); | 14566 | const values = [2]InternPool.Index{ .none, .none }; |
| 14538 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 14567 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 14539 | .types = types, | 14568 | .types = &types, |
| 14540 | .values = values, | 14569 | .values = &values, |
| 14541 | }); | 14570 | .names = &.{}, |
| 14542 | 14571 | } }); | |
| 14543 | types[0] = ty; | 14572 | return tuple_ty.toType(); |
| 14544 | types[1] = ov_ty; | ||
| 14545 | values[0] = Value.@"unreachable"; | ||
| 14546 | values[1] = Value.@"unreachable"; | ||
| 14547 | |||
| 14548 | return tuple_ty; | ||
| 14549 | } | 14573 | } |
| 14550 | 14574 | ||
| 14551 | fn analyzeArithmetic( | 14575 | fn analyzeArithmetic( |
| ... | @@ -16506,57 +16530,66 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16506,57 +16530,66 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16506 | const layout = struct_ty.containerLayout(mod); | 16530 | const layout = struct_ty.containerLayout(mod); |
| 16507 | 16531 | ||
| 16508 | const struct_field_vals = fv: { | 16532 | const struct_field_vals = fv: { |
| 16509 | if (struct_ty.isSimpleTupleOrAnonStruct()) { | 16533 | const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 16510 | const tuple = struct_ty.tupleFields(); | 16534 | .anon_struct_type => |tuple| { |
| 16511 | const field_types = tuple.types; | 16535 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, tuple.types.len); |
| 16512 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); | 16536 | for ( |
| 16513 | for (struct_field_vals, 0..) |*struct_field_val, i| { | 16537 | tuple.types, |
| 16514 | const field_ty = field_types[i]; | 16538 | tuple.values, |
| 16515 | const name_val = v: { | 16539 | struct_field_vals, |
| 16516 | var anon_decl = try block.startAnonDecl(); | 16540 | 0.., |
| 16517 | defer anon_decl.deinit(); | 16541 | ) |field_ty, field_val, *struct_field_val, i| { |
| 16518 | const bytes = if (struct_ty.castTag(.anon_struct)) |payload| | 16542 | const name_val = v: { |
| 16519 | try anon_decl.arena().dupeZ(u8, payload.data.names[i]) | 16543 | var anon_decl = try block.startAnonDecl(); |
| 16520 | else | 16544 | defer anon_decl.deinit(); |
| 16521 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | 16545 | const bytes = if (tuple.names.len != 0) |
| 16522 | const new_decl = try anon_decl.finish( | 16546 | // https://github.com/ziglang/zig/issues/15709 |
| 16523 | try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod), | 16547 | @as([]const u8, mod.intern_pool.stringToSlice(tuple.names[i])) |
| 16524 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16548 | else |
| 16525 | 0, // default alignment | 16549 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); |
| 16526 | ); | 16550 | const new_decl = try anon_decl.finish( |
| 16527 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | 16551 | try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod), |
| 16528 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | 16552 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16529 | .len = try mod.intValue(Type.usize, bytes.len), | 16553 | 0, // default alignment |
| 16530 | }); | 16554 | ); |
| 16531 | }; | 16555 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ |
| 16532 | 16556 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16533 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | 16557 | .len = try mod.intValue(Type.usize, bytes.len), |
| 16534 | const field_val = tuple.values[i]; | 16558 | }); |
| 16535 | const is_comptime = field_val.ip_index != .unreachable_value; | 16559 | }; |
| 16536 | const opt_default_val = if (is_comptime) field_val else null; | ||
| 16537 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); | ||
| 16538 | struct_field_fields.* = .{ | ||
| 16539 | // name: []const u8, | ||
| 16540 | name_val, | ||
| 16541 | // type: type, | ||
| 16542 | try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty), | ||
| 16543 | // default_value: ?*const anyopaque, | ||
| 16544 | try default_val_ptr.copy(fields_anon_decl.arena()), | ||
| 16545 | // is_comptime: bool, | ||
| 16546 | Value.makeBool(is_comptime), | ||
| 16547 | // alignment: comptime_int, | ||
| 16548 | try field_ty.lazyAbiAlignment(mod, fields_anon_decl.arena()), | ||
| 16549 | }; | ||
| 16550 | struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | ||
| 16551 | } | ||
| 16552 | break :fv struct_field_vals; | ||
| 16553 | } | ||
| 16554 | const struct_fields = struct_ty.structFields(mod); | ||
| 16555 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count()); | ||
| 16556 | 16560 | ||
| 16557 | for (struct_field_vals, 0..) |*field_val, i| { | 16561 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); |
| 16558 | const field = struct_fields.values()[i]; | 16562 | const is_comptime = field_val != .none; |
| 16559 | const name = struct_fields.keys()[i]; | 16563 | const opt_default_val = if (is_comptime) field_val.toValue() else null; |
| 16564 | const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val); | ||
| 16565 | struct_field_fields.* = .{ | ||
| 16566 | // name: []const u8, | ||
| 16567 | name_val, | ||
| 16568 | // type: type, | ||
| 16569 | field_ty.toValue(), | ||
| 16570 | // default_value: ?*const anyopaque, | ||
| 16571 | try default_val_ptr.copy(fields_anon_decl.arena()), | ||
| 16572 | // is_comptime: bool, | ||
| 16573 | Value.makeBool(is_comptime), | ||
| 16574 | // alignment: comptime_int, | ||
| 16575 | try field_ty.toType().lazyAbiAlignment(mod, fields_anon_decl.arena()), | ||
| 16576 | }; | ||
| 16577 | struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | ||
| 16578 | } | ||
| 16579 | break :fv struct_field_vals; | ||
| 16580 | }, | ||
| 16581 | .struct_type => |s| s, | ||
| 16582 | else => unreachable, | ||
| 16583 | }; | ||
| 16584 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | ||
| 16585 | break :fv &[0]Value{}; | ||
| 16586 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_obj.fields.count()); | ||
| 16587 | |||
| 16588 | for ( | ||
| 16589 | struct_field_vals, | ||
| 16590 | struct_obj.fields.keys(), | ||
| 16591 | struct_obj.fields.values(), | ||
| 16592 | ) |*field_val, name, field| { | ||
| 16560 | const name_val = v: { | 16593 | const name_val = v: { |
| 16561 | var anon_decl = try block.startAnonDecl(); | 16594 | var anon_decl = try block.startAnonDecl(); |
| 16562 | defer anon_decl.deinit(); | 16595 | defer anon_decl.deinit(); |
| ... | @@ -18013,7 +18046,7 @@ fn zirStructInit( | ... | @@ -18013,7 +18046,7 @@ fn zirStructInit( |
| 18013 | try sema.requireRuntimeBlock(block, src, null); | 18046 | try sema.requireRuntimeBlock(block, src, null); |
| 18014 | try sema.queueFullTypeResolution(resolved_ty); | 18047 | try sema.queueFullTypeResolution(resolved_ty); |
| 18015 | return block.addUnionInit(resolved_ty, field_index, init_inst); | 18048 | return block.addUnionInit(resolved_ty, field_index, init_inst); |
| 18016 | } else if (resolved_ty.isAnonStruct()) { | 18049 | } else if (resolved_ty.isAnonStruct(mod)) { |
| 18017 | return sema.fail(block, src, "TODO anon struct init validation", .{}); | 18050 | return sema.fail(block, src, "TODO anon struct init validation", .{}); |
| 18018 | } | 18051 | } |
| 18019 | unreachable; | 18052 | unreachable; |
| ... | @@ -18034,60 +18067,54 @@ fn finishStructInit( | ... | @@ -18034,60 +18067,54 @@ fn finishStructInit( |
| 18034 | var root_msg: ?*Module.ErrorMsg = null; | 18067 | var root_msg: ?*Module.ErrorMsg = null; |
| 18035 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); | 18068 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 18036 | 18069 | ||
| 18037 | if (struct_ty.isAnonStruct()) { | 18070 | switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 18038 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; | 18071 | .anon_struct_type => |anon_struct| { |
| 18039 | for (struct_obj.values, 0..) |default_val, i| { | 18072 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { |
| 18040 | if (field_inits[i] != .none) continue; | 18073 | if (field_inits[i] != .none) continue; |
| 18041 | |||
| 18042 | if (default_val.ip_index == .unreachable_value) { | ||
| 18043 | const field_name = struct_obj.names[i]; | ||
| 18044 | const template = "missing struct field: {s}"; | ||
| 18045 | const args = .{field_name}; | ||
| 18046 | if (root_msg) |msg| { | ||
| 18047 | try sema.errNote(block, init_src, msg, template, args); | ||
| 18048 | } else { | ||
| 18049 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 18050 | } | ||
| 18051 | } else { | ||
| 18052 | field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); | ||
| 18053 | } | ||
| 18054 | } | ||
| 18055 | } else if (struct_ty.isTuple(mod)) { | ||
| 18056 | var i: u32 = 0; | ||
| 18057 | const len = struct_ty.structFieldCount(mod); | ||
| 18058 | while (i < len) : (i += 1) { | ||
| 18059 | if (field_inits[i] != .none) continue; | ||
| 18060 | 18074 | ||
| 18061 | const default_val = struct_ty.structFieldDefaultValue(i, mod); | 18075 | if (default_val == .none) { |
| 18062 | if (default_val.ip_index == .unreachable_value) { | 18076 | if (anon_struct.names.len == 0) { |
| 18063 | const template = "missing tuple field with index {d}"; | 18077 | const template = "missing tuple field with index {d}"; |
| 18064 | if (root_msg) |msg| { | 18078 | if (root_msg) |msg| { |
| 18065 | try sema.errNote(block, init_src, msg, template, .{i}); | 18079 | try sema.errNote(block, init_src, msg, template, .{i}); |
| 18080 | } else { | ||
| 18081 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | ||
| 18082 | } | ||
| 18083 | } else { | ||
| 18084 | const field_name = mod.intern_pool.stringToSlice(anon_struct.names[i]); | ||
| 18085 | const template = "missing struct field: {s}"; | ||
| 18086 | const args = .{field_name}; | ||
| 18087 | if (root_msg) |msg| { | ||
| 18088 | try sema.errNote(block, init_src, msg, template, args); | ||
| 18089 | } else { | ||
| 18090 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 18091 | } | ||
| 18092 | } | ||
| 18066 | } else { | 18093 | } else { |
| 18067 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | 18094 | field_inits[i] = try sema.addConstant(field_ty.toType(), default_val.toValue()); |
| 18068 | } | 18095 | } |
| 18069 | } else { | ||
| 18070 | field_inits[i] = try sema.addConstant(struct_ty.structFieldType(i, mod), default_val); | ||
| 18071 | } | 18096 | } |
| 18072 | } | 18097 | }, |
| 18073 | } else { | 18098 | .struct_type => |struct_type| { |
| 18074 | const struct_obj = mod.typeToStruct(struct_ty).?; | 18099 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 18075 | for (struct_obj.fields.values(), 0..) |field, i| { | 18100 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 18076 | if (field_inits[i] != .none) continue; | 18101 | if (field_inits[i] != .none) continue; |
| 18077 | 18102 | ||
| 18078 | if (field.default_val.ip_index == .unreachable_value) { | 18103 | if (field.default_val.ip_index == .unreachable_value) { |
| 18079 | const field_name = struct_obj.fields.keys()[i]; | 18104 | const field_name = struct_obj.fields.keys()[i]; |
| 18080 | const template = "missing struct field: {s}"; | 18105 | const template = "missing struct field: {s}"; |
| 18081 | const args = .{field_name}; | 18106 | const args = .{field_name}; |
| 18082 | if (root_msg) |msg| { | 18107 | if (root_msg) |msg| { |
| 18083 | try sema.errNote(block, init_src, msg, template, args); | 18108 | try sema.errNote(block, init_src, msg, template, args); |
| 18109 | } else { | ||
| 18110 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 18111 | } | ||
| 18084 | } else { | 18112 | } else { |
| 18085 | root_msg = try sema.errMsg(block, init_src, template, args); | 18113 | field_inits[i] = try sema.addConstant(field.ty, field.default_val); |
| 18086 | } | 18114 | } |
| 18087 | } else { | ||
| 18088 | field_inits[i] = try sema.addConstant(field.ty, field.default_val); | ||
| 18089 | } | 18115 | } |
| 18090 | } | 18116 | }, |
| 18117 | else => unreachable, | ||
| 18091 | } | 18118 | } |
| 18092 | 18119 | ||
| 18093 | if (root_msg) |msg| { | 18120 | if (root_msg) |msg| { |
| ... | @@ -18159,31 +18186,33 @@ fn zirStructInitAnon( | ... | @@ -18159,31 +18186,33 @@ fn zirStructInitAnon( |
| 18159 | is_ref: bool, | 18186 | is_ref: bool, |
| 18160 | ) CompileError!Air.Inst.Ref { | 18187 | ) CompileError!Air.Inst.Ref { |
| 18161 | const mod = sema.mod; | 18188 | const mod = sema.mod; |
| 18189 | const gpa = sema.gpa; | ||
| 18162 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 18190 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18163 | const src = inst_data.src(); | 18191 | const src = inst_data.src(); |
| 18164 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); | 18192 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); |
| 18165 | const types = try sema.arena.alloc(Type, extra.data.fields_len); | 18193 | const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); |
| 18166 | const values = try sema.arena.alloc(Value, types.len); | 18194 | const values = try sema.arena.alloc(InternPool.Index, types.len); |
| 18167 | var fields = std.StringArrayHashMapUnmanaged(u32){}; | 18195 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); |
| 18168 | defer fields.deinit(sema.gpa); | 18196 | try fields.ensureUnusedCapacity(types.len); |
| 18169 | try fields.ensureUnusedCapacity(sema.gpa, types.len); | ||
| 18170 | 18197 | ||
| 18171 | // Find which field forces the expression to be runtime, if any. | 18198 | // Find which field forces the expression to be runtime, if any. |
| 18172 | const opt_runtime_index = rs: { | 18199 | const opt_runtime_index = rs: { |
| 18173 | var runtime_index: ?usize = null; | 18200 | var runtime_index: ?usize = null; |
| 18174 | var extra_index = extra.end; | 18201 | var extra_index = extra.end; |
| 18175 | for (types, 0..) |*field_ty, i| { | 18202 | for (types, 0..) |*field_ty, i_usize| { |
| 18203 | const i = @intCast(u32, i_usize); | ||
| 18176 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | 18204 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18177 | extra_index = item.end; | 18205 | extra_index = item.end; |
| 18178 | 18206 | ||
| 18179 | const name = sema.code.nullTerminatedString(item.data.field_name); | 18207 | const name = sema.code.nullTerminatedString(item.data.field_name); |
| 18180 | const gop = fields.getOrPutAssumeCapacity(name); | 18208 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); |
| 18209 | const gop = fields.getOrPutAssumeCapacity(name_ip); | ||
| 18181 | if (gop.found_existing) { | 18210 | if (gop.found_existing) { |
| 18182 | const msg = msg: { | 18211 | const msg = msg: { |
| 18183 | const decl = sema.mod.declPtr(block.src_decl); | 18212 | const decl = sema.mod.declPtr(block.src_decl); |
| 18184 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | 18213 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18185 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); | 18214 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); |
| 18186 | errdefer msg.destroy(sema.gpa); | 18215 | errdefer msg.destroy(gpa); |
| 18187 | 18216 | ||
| 18188 | const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); | 18217 | const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); |
| 18189 | try sema.errNote(block, prev_source, msg, "other field here", .{}); | 18218 | try sema.errNote(block, prev_source, msg, "other field here", .{}); |
| ... | @@ -18191,41 +18220,44 @@ fn zirStructInitAnon( | ... | @@ -18191,41 +18220,44 @@ fn zirStructInitAnon( |
| 18191 | }; | 18220 | }; |
| 18192 | return sema.failWithOwnedErrorMsg(msg); | 18221 | return sema.failWithOwnedErrorMsg(msg); |
| 18193 | } | 18222 | } |
| 18194 | gop.value_ptr.* = @intCast(u32, i); | 18223 | gop.value_ptr.* = i; |
| 18195 | 18224 | ||
| 18196 | const init = try sema.resolveInst(item.data.init); | 18225 | const init = try sema.resolveInst(item.data.init); |
| 18197 | field_ty.* = sema.typeOf(init); | 18226 | field_ty.* = sema.typeOf(init).ip_index; |
| 18198 | if (types[i].zigTypeTag(mod) == .Opaque) { | 18227 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { |
| 18199 | const msg = msg: { | 18228 | const msg = msg: { |
| 18200 | const decl = sema.mod.declPtr(block.src_decl); | 18229 | const decl = sema.mod.declPtr(block.src_decl); |
| 18201 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | 18230 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18202 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 18231 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18203 | errdefer msg.destroy(sema.gpa); | 18232 | errdefer msg.destroy(sema.gpa); |
| 18204 | 18233 | ||
| 18205 | try sema.addDeclaredHereNote(msg, types[i]); | 18234 | try sema.addDeclaredHereNote(msg, types[i].toType()); |
| 18206 | break :msg msg; | 18235 | break :msg msg; |
| 18207 | }; | 18236 | }; |
| 18208 | return sema.failWithOwnedErrorMsg(msg); | 18237 | return sema.failWithOwnedErrorMsg(msg); |
| 18209 | } | 18238 | } |
| 18210 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { | 18239 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18211 | values[i] = init_val; | 18240 | values[i] = init_val.ip_index; |
| 18212 | } else { | 18241 | } else { |
| 18213 | values[i] = Value.@"unreachable"; | 18242 | values[i] = .none; |
| 18214 | runtime_index = i; | 18243 | runtime_index = i; |
| 18215 | } | 18244 | } |
| 18216 | } | 18245 | } |
| 18217 | break :rs runtime_index; | 18246 | break :rs runtime_index; |
| 18218 | }; | 18247 | }; |
| 18219 | 18248 | ||
| 18220 | const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ | 18249 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 18221 | .names = try sema.arena.dupe([]const u8, fields.keys()), | 18250 | .names = fields.keys(), |
| 18222 | .types = types, | 18251 | .types = types, |
| 18223 | .values = values, | 18252 | .values = values, |
| 18224 | }); | 18253 | } }); |
| 18225 | 18254 | ||
| 18226 | const runtime_index = opt_runtime_index orelse { | 18255 | const runtime_index = opt_runtime_index orelse { |
| 18227 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 18256 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 18228 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | 18257 | .ty = tuple_ty, |
| 18258 | .fields = values, | ||
| 18259 | } }); | ||
| 18260 | return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); | ||
| 18229 | }; | 18261 | }; |
| 18230 | 18262 | ||
| 18231 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { | 18263 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| ... | @@ -18241,7 +18273,7 @@ fn zirStructInitAnon( | ... | @@ -18241,7 +18273,7 @@ fn zirStructInitAnon( |
| 18241 | if (is_ref) { | 18273 | if (is_ref) { |
| 18242 | const target = sema.mod.getTarget(); | 18274 | const target = sema.mod.getTarget(); |
| 18243 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18275 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18244 | .pointee_type = tuple_ty, | 18276 | .pointee_type = tuple_ty.toType(), |
| 18245 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18277 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18246 | }); | 18278 | }); |
| 18247 | const alloc = try block.addTy(.alloc, alloc_ty); | 18279 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | @@ -18254,9 +18286,9 @@ fn zirStructInitAnon( | ... | @@ -18254,9 +18286,9 @@ fn zirStructInitAnon( |
| 18254 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18286 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18255 | .mutable = true, | 18287 | .mutable = true, |
| 18256 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18288 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18257 | .pointee_type = field_ty, | 18289 | .pointee_type = field_ty.toType(), |
| 18258 | }); | 18290 | }); |
| 18259 | if (values[i].ip_index == .unreachable_value) { | 18291 | if (values[i] == .none) { |
| 18260 | const init = try sema.resolveInst(item.data.init); | 18292 | const init = try sema.resolveInst(item.data.init); |
| 18261 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | 18293 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18262 | _ = try block.addBinOp(.store, field_ptr, init); | 18294 | _ = try block.addBinOp(.store, field_ptr, init); |
| ... | @@ -18274,7 +18306,7 @@ fn zirStructInitAnon( | ... | @@ -18274,7 +18306,7 @@ fn zirStructInitAnon( |
| 18274 | element_refs[i] = try sema.resolveInst(item.data.init); | 18306 | element_refs[i] = try sema.resolveInst(item.data.init); |
| 18275 | } | 18307 | } |
| 18276 | 18308 | ||
| 18277 | return block.addAggregateInit(tuple_ty, element_refs); | 18309 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 18278 | } | 18310 | } |
| 18279 | 18311 | ||
| 18280 | fn zirArrayInit( | 18312 | fn zirArrayInit( |
| ... | @@ -18400,43 +18432,47 @@ fn zirArrayInitAnon( | ... | @@ -18400,43 +18432,47 @@ fn zirArrayInitAnon( |
| 18400 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); | 18432 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 18401 | const mod = sema.mod; | 18433 | const mod = sema.mod; |
| 18402 | 18434 | ||
| 18403 | const types = try sema.arena.alloc(Type, operands.len); | 18435 | const types = try sema.arena.alloc(InternPool.Index, operands.len); |
| 18404 | const values = try sema.arena.alloc(Value, operands.len); | 18436 | const values = try sema.arena.alloc(InternPool.Index, operands.len); |
| 18405 | 18437 | ||
| 18406 | const opt_runtime_src = rs: { | 18438 | const opt_runtime_src = rs: { |
| 18407 | var runtime_src: ?LazySrcLoc = null; | 18439 | var runtime_src: ?LazySrcLoc = null; |
| 18408 | for (operands, 0..) |operand, i| { | 18440 | for (operands, 0..) |operand, i| { |
| 18409 | const operand_src = src; // TODO better source location | 18441 | const operand_src = src; // TODO better source location |
| 18410 | const elem = try sema.resolveInst(operand); | 18442 | const elem = try sema.resolveInst(operand); |
| 18411 | types[i] = sema.typeOf(elem); | 18443 | types[i] = sema.typeOf(elem).ip_index; |
| 18412 | if (types[i].zigTypeTag(mod) == .Opaque) { | 18444 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { |
| 18413 | const msg = msg: { | 18445 | const msg = msg: { |
| 18414 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 18446 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18415 | errdefer msg.destroy(sema.gpa); | 18447 | errdefer msg.destroy(sema.gpa); |
| 18416 | 18448 | ||
| 18417 | try sema.addDeclaredHereNote(msg, types[i]); | 18449 | try sema.addDeclaredHereNote(msg, types[i].toType()); |
| 18418 | break :msg msg; | 18450 | break :msg msg; |
| 18419 | }; | 18451 | }; |
| 18420 | return sema.failWithOwnedErrorMsg(msg); | 18452 | return sema.failWithOwnedErrorMsg(msg); |
| 18421 | } | 18453 | } |
| 18422 | if (try sema.resolveMaybeUndefVal(elem)) |val| { | 18454 | if (try sema.resolveMaybeUndefVal(elem)) |val| { |
| 18423 | values[i] = val; | 18455 | values[i] = val.ip_index; |
| 18424 | } else { | 18456 | } else { |
| 18425 | values[i] = Value.@"unreachable"; | 18457 | values[i] = .none; |
| 18426 | runtime_src = operand_src; | 18458 | runtime_src = operand_src; |
| 18427 | } | 18459 | } |
| 18428 | } | 18460 | } |
| 18429 | break :rs runtime_src; | 18461 | break :rs runtime_src; |
| 18430 | }; | 18462 | }; |
| 18431 | 18463 | ||
| 18432 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 18464 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 18433 | .types = types, | 18465 | .types = types, |
| 18434 | .values = values, | 18466 | .values = values, |
| 18435 | }); | 18467 | .names = &.{}, |
| 18468 | } }); | ||
| 18436 | 18469 | ||
| 18437 | const runtime_src = opt_runtime_src orelse { | 18470 | const runtime_src = opt_runtime_src orelse { |
| 18438 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 18471 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 18439 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | 18472 | .ty = tuple_ty, |
| 18473 | .fields = values, | ||
| 18474 | } }); | ||
| 18475 | return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); | ||
| 18440 | }; | 18476 | }; |
| 18441 | 18477 | ||
| 18442 | try sema.requireRuntimeBlock(block, src, runtime_src); | 18478 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -18444,7 +18480,7 @@ fn zirArrayInitAnon( | ... | @@ -18444,7 +18480,7 @@ fn zirArrayInitAnon( |
| 18444 | if (is_ref) { | 18480 | if (is_ref) { |
| 18445 | const target = sema.mod.getTarget(); | 18481 | const target = sema.mod.getTarget(); |
| 18446 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18482 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18447 | .pointee_type = tuple_ty, | 18483 | .pointee_type = tuple_ty.toType(), |
| 18448 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18484 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18449 | }); | 18485 | }); |
| 18450 | const alloc = try block.addTy(.alloc, alloc_ty); | 18486 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | @@ -18453,9 +18489,9 @@ fn zirArrayInitAnon( | ... | @@ -18453,9 +18489,9 @@ fn zirArrayInitAnon( |
| 18453 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18489 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18454 | .mutable = true, | 18490 | .mutable = true, |
| 18455 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18491 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18456 | .pointee_type = types[i], | 18492 | .pointee_type = types[i].toType(), |
| 18457 | }); | 18493 | }); |
| 18458 | if (values[i].ip_index == .unreachable_value) { | 18494 | if (values[i] == .none) { |
| 18459 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | 18495 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18460 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); | 18496 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); |
| 18461 | } | 18497 | } |
| ... | @@ -18469,7 +18505,7 @@ fn zirArrayInitAnon( | ... | @@ -18469,7 +18505,7 @@ fn zirArrayInitAnon( |
| 18469 | element_refs[i] = try sema.resolveInst(operand); | 18505 | element_refs[i] = try sema.resolveInst(operand); |
| 18470 | } | 18506 | } |
| 18471 | 18507 | ||
| 18472 | return block.addAggregateInit(tuple_ty, element_refs); | 18508 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 18473 | } | 18509 | } |
| 18474 | 18510 | ||
| 18475 | fn addConstantMaybeRef( | 18511 | fn addConstantMaybeRef( |
| ... | @@ -18532,15 +18568,18 @@ fn fieldType( | ... | @@ -18532,15 +18568,18 @@ fn fieldType( |
| 18532 | const resolved_ty = try sema.resolveTypeFields(cur_ty); | 18568 | const resolved_ty = try sema.resolveTypeFields(cur_ty); |
| 18533 | cur_ty = resolved_ty; | 18569 | cur_ty = resolved_ty; |
| 18534 | switch (cur_ty.zigTypeTag(mod)) { | 18570 | switch (cur_ty.zigTypeTag(mod)) { |
| 18535 | .Struct => { | 18571 | .Struct => switch (mod.intern_pool.indexToKey(cur_ty.ip_index)) { |
| 18536 | if (cur_ty.isAnonStruct()) { | 18572 | .anon_struct_type => |anon_struct| { |
| 18537 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); | 18573 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); |
| 18538 | return sema.addType(cur_ty.tupleFields().types[field_index]); | 18574 | return sema.addType(anon_struct.types[field_index].toType()); |
| 18539 | } | 18575 | }, |
| 18540 | const struct_obj = mod.typeToStruct(cur_ty).?; | 18576 | .struct_type => |struct_type| { |
| 18541 | const field = struct_obj.fields.get(field_name) orelse | 18577 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 18542 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 18578 | const field = struct_obj.fields.get(field_name) orelse |
| 18543 | return sema.addType(field.ty); | 18579 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| 18580 | return sema.addType(field.ty); | ||
| 18581 | }, | ||
| 18582 | else => unreachable, | ||
| 18544 | }, | 18583 | }, |
| 18545 | .Union => { | 18584 | .Union => { |
| 18546 | const union_obj = mod.typeToUnion(cur_ty).?; | 18585 | const union_obj = mod.typeToUnion(cur_ty).?; |
| ... | @@ -24697,7 +24736,7 @@ fn structFieldPtr( | ... | @@ -24697,7 +24736,7 @@ fn structFieldPtr( |
| 24697 | } | 24736 | } |
| 24698 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); | 24737 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24699 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); | 24738 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 24700 | } else if (struct_ty.isAnonStruct()) { | 24739 | } else if (struct_ty.isAnonStruct(mod)) { |
| 24701 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | 24740 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24702 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); | 24741 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 24703 | } | 24742 | } |
| ... | @@ -24721,11 +24760,11 @@ fn structFieldPtrByIndex( | ... | @@ -24721,11 +24760,11 @@ fn structFieldPtrByIndex( |
| 24721 | struct_ty: Type, | 24760 | struct_ty: Type, |
| 24722 | initializing: bool, | 24761 | initializing: bool, |
| 24723 | ) CompileError!Air.Inst.Ref { | 24762 | ) CompileError!Air.Inst.Ref { |
| 24724 | if (struct_ty.isAnonStruct()) { | 24763 | const mod = sema.mod; |
| 24764 | if (struct_ty.isAnonStruct(mod)) { | ||
| 24725 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); | 24765 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); |
| 24726 | } | 24766 | } |
| 24727 | 24767 | ||
| 24728 | const mod = sema.mod; | ||
| 24729 | const struct_obj = mod.typeToStruct(struct_ty).?; | 24768 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 24730 | const field = struct_obj.fields.values()[field_index]; | 24769 | const field = struct_obj.fields.values()[field_index]; |
| 24731 | const struct_ptr_ty = sema.typeOf(struct_ptr); | 24770 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| ... | @@ -24830,45 +24869,42 @@ fn structFieldVal( | ... | @@ -24830,45 +24869,42 @@ fn structFieldVal( |
| 24830 | assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); | 24869 | assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); |
| 24831 | 24870 | ||
| 24832 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); | 24871 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24833 | switch (struct_ty.ip_index) { | 24872 | switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 24834 | .empty_struct_type => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | 24873 | .struct_type => |struct_type| { |
| 24835 | .none => switch (struct_ty.tag()) { | 24874 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 24836 | .tuple => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | 24875 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); |
| 24837 | .anon_struct => { | ||
| 24838 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | ||
| 24839 | return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty); | ||
| 24840 | }, | ||
| 24841 | else => unreachable, | ||
| 24842 | }, | ||
| 24843 | else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | ||
| 24844 | .struct_type => |struct_type| { | ||
| 24845 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 24846 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | ||
| 24847 | 24876 | ||
| 24848 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 24877 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 24849 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | 24878 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| 24850 | const field_index = @intCast(u32, field_index_usize); | 24879 | const field_index = @intCast(u32, field_index_usize); |
| 24851 | const field = struct_obj.fields.values()[field_index]; | 24880 | const field = struct_obj.fields.values()[field_index]; |
| 24852 | |||
| 24853 | if (field.is_comptime) { | ||
| 24854 | return sema.addConstant(field.ty, field.default_val); | ||
| 24855 | } | ||
| 24856 | 24881 | ||
| 24857 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { | 24882 | if (field.is_comptime) { |
| 24858 | if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty); | 24883 | return sema.addConstant(field.ty, field.default_val); |
| 24859 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | 24884 | } |
| 24860 | return sema.addConstant(field.ty, opv); | ||
| 24861 | } | ||
| 24862 | 24885 | ||
| 24863 | const field_values = struct_val.castTag(.aggregate).?.data; | 24886 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { |
| 24864 | return sema.addConstant(field.ty, field_values[field_index]); | 24887 | if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty); |
| 24888 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | ||
| 24889 | return sema.addConstant(field.ty, opv); | ||
| 24865 | } | 24890 | } |
| 24866 | 24891 | ||
| 24867 | try sema.requireRuntimeBlock(block, src, null); | 24892 | const field_values = struct_val.castTag(.aggregate).?.data; |
| 24868 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | 24893 | return sema.addConstant(field.ty, field_values[field_index]); |
| 24869 | }, | 24894 | } |
| 24870 | else => unreachable, | 24895 | |
| 24896 | try sema.requireRuntimeBlock(block, src, null); | ||
| 24897 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | ||
| 24898 | }, | ||
| 24899 | .anon_struct_type => |anon_struct| { | ||
| 24900 | if (anon_struct.names.len == 0) { | ||
| 24901 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | ||
| 24902 | } else { | ||
| 24903 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | ||
| 24904 | return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty); | ||
| 24905 | } | ||
| 24871 | }, | 24906 | }, |
| 24907 | else => unreachable, | ||
| 24872 | } | 24908 | } |
| 24873 | } | 24909 | } |
| 24874 | 24910 | ||
| ... | @@ -25931,7 +25967,7 @@ fn coerceExtra( | ... | @@ -25931,7 +25967,7 @@ fn coerceExtra( |
| 25931 | .Union => { | 25967 | .Union => { |
| 25932 | // pointer to anonymous struct to pointer to union | 25968 | // pointer to anonymous struct to pointer to union |
| 25933 | if (inst_ty.isSinglePointer(mod) and | 25969 | if (inst_ty.isSinglePointer(mod) and |
| 25934 | inst_ty.childType(mod).isAnonStruct() and | 25970 | inst_ty.childType(mod).isAnonStruct(mod) and |
| 25935 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 25971 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25936 | { | 25972 | { |
| 25937 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); | 25973 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | @@ -25940,7 +25976,7 @@ fn coerceExtra( | ... | @@ -25940,7 +25976,7 @@ fn coerceExtra( |
| 25940 | .Struct => { | 25976 | .Struct => { |
| 25941 | // pointer to anonymous struct to pointer to struct | 25977 | // pointer to anonymous struct to pointer to struct |
| 25942 | if (inst_ty.isSinglePointer(mod) and | 25978 | if (inst_ty.isSinglePointer(mod) and |
| 25943 | inst_ty.childType(mod).isAnonStruct() and | 25979 | inst_ty.childType(mod).isAnonStruct(mod) and |
| 25944 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 25980 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25945 | { | 25981 | { |
| 25946 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { | 25982 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { |
| ... | @@ -26231,7 +26267,7 @@ fn coerceExtra( | ... | @@ -26231,7 +26267,7 @@ fn coerceExtra( |
| 26231 | .Union => switch (inst_ty.zigTypeTag(mod)) { | 26267 | .Union => switch (inst_ty.zigTypeTag(mod)) { |
| 26232 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), | 26268 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26233 | .Struct => { | 26269 | .Struct => { |
| 26234 | if (inst_ty.isAnonStruct()) { | 26270 | if (inst_ty.isAnonStruct(mod)) { |
| 26235 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); | 26271 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26236 | } | 26272 | } |
| 26237 | }, | 26273 | }, |
| ... | @@ -28771,8 +28807,8 @@ fn coerceAnonStructToUnion( | ... | @@ -28771,8 +28807,8 @@ fn coerceAnonStructToUnion( |
| 28771 | return sema.failWithOwnedErrorMsg(msg); | 28807 | return sema.failWithOwnedErrorMsg(msg); |
| 28772 | } | 28808 | } |
| 28773 | 28809 | ||
| 28774 | const anon_struct = inst_ty.castTag(.anon_struct).?.data; | 28810 | const anon_struct = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; |
| 28775 | const field_name = anon_struct.names[0]; | 28811 | const field_name = mod.intern_pool.stringToSlice(anon_struct.names[0]); |
| 28776 | const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); | 28812 | const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); |
| 28777 | return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); | 28813 | return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); |
| 28778 | } | 28814 | } |
| ... | @@ -29010,13 +29046,14 @@ fn coerceTupleToStruct( | ... | @@ -29010,13 +29046,14 @@ fn coerceTupleToStruct( |
| 29010 | @memset(field_refs, .none); | 29046 | @memset(field_refs, .none); |
| 29011 | 29047 | ||
| 29012 | const inst_ty = sema.typeOf(inst); | 29048 | const inst_ty = sema.typeOf(inst); |
| 29049 | const anon_struct = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; | ||
| 29013 | var runtime_src: ?LazySrcLoc = null; | 29050 | var runtime_src: ?LazySrcLoc = null; |
| 29014 | const field_count = inst_ty.structFieldCount(mod); | 29051 | for (0..anon_struct.types.len) |field_index_usize| { |
| 29015 | var field_i: u32 = 0; | 29052 | const field_i = @intCast(u32, field_index_usize); |
| 29016 | while (field_i < field_count) : (field_i += 1) { | ||
| 29017 | const field_src = inst_src; // TODO better source location | 29053 | const field_src = inst_src; // TODO better source location |
| 29018 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | 29054 | const field_name = if (anon_struct.names.len != 0) |
| 29019 | payload.data.names[field_i] | 29055 | // https://github.com/ziglang/zig/issues/15709 |
| 29056 | @as([]const u8, mod.intern_pool.stringToSlice(anon_struct.names[field_i])) | ||
| 29020 | else | 29057 | else |
| 29021 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); | 29058 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); |
| 29022 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); | 29059 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| ... | @@ -29094,21 +29131,22 @@ fn coerceTupleToTuple( | ... | @@ -29094,21 +29131,22 @@ fn coerceTupleToTuple( |
| 29094 | inst_src: LazySrcLoc, | 29131 | inst_src: LazySrcLoc, |
| 29095 | ) !Air.Inst.Ref { | 29132 | ) !Air.Inst.Ref { |
| 29096 | const mod = sema.mod; | 29133 | const mod = sema.mod; |
| 29097 | const dest_field_count = tuple_ty.structFieldCount(mod); | 29134 | const dest_tuple = mod.intern_pool.indexToKey(tuple_ty.ip_index).anon_struct_type; |
| 29098 | const field_vals = try sema.arena.alloc(Value, dest_field_count); | 29135 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_tuple.types.len); |
| 29099 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | 29136 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 29100 | @memset(field_refs, .none); | 29137 | @memset(field_refs, .none); |
| 29101 | 29138 | ||
| 29102 | const inst_ty = sema.typeOf(inst); | 29139 | const inst_ty = sema.typeOf(inst); |
| 29103 | const inst_field_count = inst_ty.structFieldCount(mod); | 29140 | const src_tuple = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; |
| 29104 | if (inst_field_count > dest_field_count) return error.NotCoercible; | 29141 | if (src_tuple.types.len > dest_tuple.types.len) return error.NotCoercible; |
| 29105 | 29142 | ||
| 29106 | var runtime_src: ?LazySrcLoc = null; | 29143 | var runtime_src: ?LazySrcLoc = null; |
| 29107 | var field_i: u32 = 0; | 29144 | for (dest_tuple.types, dest_tuple.values, 0..) |field_ty, default_val, field_index_usize| { |
| 29108 | while (field_i < inst_field_count) : (field_i += 1) { | 29145 | const field_i = @intCast(u32, field_index_usize); |
| 29109 | const field_src = inst_src; // TODO better source location | 29146 | const field_src = inst_src; // TODO better source location |
| 29110 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | 29147 | const field_name = if (src_tuple.names.len != 0) |
| 29111 | payload.data.names[field_i] | 29148 | // https://github.com/ziglang/zig/issues/15709 |
| 29149 | @as([]const u8, mod.intern_pool.stringToSlice(src_tuple.names[field_i])) | ||
| 29112 | else | 29150 | else |
| 29113 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); | 29151 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); |
| 29114 | 29152 | ||
| ... | @@ -29118,23 +29156,21 @@ fn coerceTupleToTuple( | ... | @@ -29118,23 +29156,21 @@ fn coerceTupleToTuple( |
| 29118 | 29156 | ||
| 29119 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); | 29157 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); |
| 29120 | 29158 | ||
| 29121 | const field_ty = tuple_ty.structFieldType(field_i, mod); | ||
| 29122 | const default_val = tuple_ty.structFieldDefaultValue(field_i, mod); | ||
| 29123 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); | 29159 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 29124 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); | 29160 | const coerced = try sema.coerce(block, field_ty.toType(), elem_ref, field_src); |
| 29125 | field_refs[field_index] = coerced; | 29161 | field_refs[field_index] = coerced; |
| 29126 | if (default_val.ip_index != .unreachable_value) { | 29162 | if (default_val != .none) { |
| 29127 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 29163 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 29128 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); | 29164 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); |
| 29129 | }; | 29165 | }; |
| 29130 | 29166 | ||
| 29131 | if (!init_val.eql(default_val, field_ty, sema.mod)) { | 29167 | if (!init_val.eql(default_val.toValue(), field_ty.toType(), sema.mod)) { |
| 29132 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); | 29168 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 29133 | } | 29169 | } |
| 29134 | } | 29170 | } |
| 29135 | if (runtime_src == null) { | 29171 | if (runtime_src == null) { |
| 29136 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { | 29172 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { |
| 29137 | field_vals[field_index] = field_val; | 29173 | field_vals[field_index] = field_val.ip_index; |
| 29138 | } else { | 29174 | } else { |
| 29139 | runtime_src = field_src; | 29175 | runtime_src = field_src; |
| 29140 | } | 29176 | } |
| ... | @@ -29145,14 +29181,16 @@ fn coerceTupleToTuple( | ... | @@ -29145,14 +29181,16 @@ fn coerceTupleToTuple( |
| 29145 | var root_msg: ?*Module.ErrorMsg = null; | 29181 | var root_msg: ?*Module.ErrorMsg = null; |
| 29146 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); | 29182 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 29147 | 29183 | ||
| 29148 | for (field_refs, 0..) |*field_ref, i| { | 29184 | for ( |
| 29185 | dest_tuple.types, | ||
| 29186 | dest_tuple.values, | ||
| 29187 | field_refs, | ||
| 29188 | 0.., | ||
| 29189 | ) |field_ty, default_val, *field_ref, i| { | ||
| 29149 | if (field_ref.* != .none) continue; | 29190 | if (field_ref.* != .none) continue; |
| 29150 | 29191 | ||
| 29151 | const default_val = tuple_ty.structFieldDefaultValue(i, mod); | ||
| 29152 | const field_ty = tuple_ty.structFieldType(i, mod); | ||
| 29153 | |||
| 29154 | const field_src = inst_src; // TODO better source location | 29192 | const field_src = inst_src; // TODO better source location |
| 29155 | if (default_val.ip_index == .unreachable_value) { | 29193 | if (default_val == .none) { |
| 29156 | if (tuple_ty.isTuple(mod)) { | 29194 | if (tuple_ty.isTuple(mod)) { |
| 29157 | const template = "missing tuple field: {d}"; | 29195 | const template = "missing tuple field: {d}"; |
| 29158 | if (root_msg) |msg| { | 29196 | if (root_msg) |msg| { |
| ... | @@ -29174,7 +29212,7 @@ fn coerceTupleToTuple( | ... | @@ -29174,7 +29212,7 @@ fn coerceTupleToTuple( |
| 29174 | if (runtime_src == null) { | 29212 | if (runtime_src == null) { |
| 29175 | field_vals[i] = default_val; | 29213 | field_vals[i] = default_val; |
| 29176 | } else { | 29214 | } else { |
| 29177 | field_ref.* = try sema.addConstant(field_ty, default_val); | 29215 | field_ref.* = try sema.addConstant(field_ty.toType(), default_val.toValue()); |
| 29178 | } | 29216 | } |
| 29179 | } | 29217 | } |
| 29180 | 29218 | ||
| ... | @@ -29191,7 +29229,10 @@ fn coerceTupleToTuple( | ... | @@ -29191,7 +29229,10 @@ fn coerceTupleToTuple( |
| 29191 | 29229 | ||
| 29192 | return sema.addConstant( | 29230 | return sema.addConstant( |
| 29193 | tuple_ty, | 29231 | tuple_ty, |
| 29194 | try Value.Tag.aggregate.create(sema.arena, field_vals), | 29232 | (try mod.intern(.{ .aggregate = .{ |
| 29233 | .ty = tuple_ty.ip_index, | ||
| 29234 | .fields = field_vals, | ||
| 29235 | } })).toValue(), | ||
| 29195 | ); | 29236 | ); |
| 29196 | } | 29237 | } |
| 29197 | 29238 | ||
| ... | @@ -31591,17 +31632,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -31591,17 +31632,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31591 | return sema.resolveTypeRequiresComptime(ty.optionalChild(mod)); | 31632 | return sema.resolveTypeRequiresComptime(ty.optionalChild(mod)); |
| 31592 | }, | 31633 | }, |
| 31593 | 31634 | ||
| 31594 | .tuple, .anon_struct => { | ||
| 31595 | const tuple = ty.tupleFields(); | ||
| 31596 | for (tuple.types, 0..) |field_ty, i| { | ||
| 31597 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | ||
| 31598 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) { | ||
| 31599 | return true; | ||
| 31600 | } | ||
| 31601 | } | ||
| 31602 | return false; | ||
| 31603 | }, | ||
| 31604 | |||
| 31605 | .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), | 31635 | .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), |
| 31606 | .anyframe_T => { | 31636 | .anyframe_T => { |
| 31607 | const child_ty = ty.castTag(.anyframe_T).?.data; | 31637 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | @@ -31690,6 +31720,16 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -31690,6 +31720,16 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31690 | } | 31720 | } |
| 31691 | }, | 31721 | }, |
| 31692 | 31722 | ||
| 31723 | .anon_struct_type => |tuple| { | ||
| 31724 | for (tuple.types, tuple.values) |field_ty, field_val| { | ||
| 31725 | const have_comptime_val = field_val != .none; | ||
| 31726 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) { | ||
| 31727 | return true; | ||
| 31728 | } | ||
| 31729 | } | ||
| 31730 | return false; | ||
| 31731 | }, | ||
| 31732 | |||
| 31693 | .union_type => |union_type| { | 31733 | .union_type => |union_type| { |
| 31694 | const union_obj = mod.unionPtr(union_type.index); | 31734 | const union_obj = mod.unionPtr(union_type.index); |
| 31695 | switch (union_obj.requires_comptime) { | 31735 | switch (union_obj.requires_comptime) { |
| ... | @@ -31740,20 +31780,16 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31740,20 +31780,16 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { |
| 31740 | return sema.resolveTypeFully(child_ty); | 31780 | return sema.resolveTypeFully(child_ty); |
| 31741 | }, | 31781 | }, |
| 31742 | .Struct => switch (ty.ip_index) { | 31782 | .Struct => switch (ty.ip_index) { |
| 31743 | .none => switch (ty.tag()) { | 31783 | .none => {}, // TODO make this unreachable when all types are migrated to InternPool |
| 31744 | .tuple, .anon_struct => { | 31784 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 31745 | const tuple = ty.tupleFields(); | 31785 | .struct_type => return sema.resolveStructFully(ty), |
| 31746 | 31786 | .anon_struct_type => |tuple| { | |
| 31747 | for (tuple.types) |field_ty| { | 31787 | for (tuple.types) |field_ty| { |
| 31748 | try sema.resolveTypeFully(field_ty); | 31788 | try sema.resolveTypeFully(field_ty.toType()); |
| 31749 | } | 31789 | } |
| 31750 | }, | 31790 | }, |
| 31751 | else => {}, | 31791 | else => {}, |
| 31752 | }, | 31792 | }, |
| 31753 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 31754 | .struct_type => return sema.resolveStructFully(ty), | ||
| 31755 | else => {}, | ||
| 31756 | }, | ||
| 31757 | }, | 31793 | }, |
| 31758 | .Union => return sema.resolveUnionFully(ty), | 31794 | .Union => return sema.resolveUnionFully(ty), |
| 31759 | .Array => return sema.resolveTypeFully(ty.childType(mod)), | 31795 | .Array => return sema.resolveTypeFully(ty.childType(mod)), |
| ... | @@ -33038,17 +33074,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -33038,17 +33074,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33038 | } | 33074 | } |
| 33039 | }, | 33075 | }, |
| 33040 | 33076 | ||
| 33041 | .tuple, .anon_struct => { | ||
| 33042 | const tuple = ty.tupleFields(); | ||
| 33043 | for (tuple.values, 0..) |val, i| { | ||
| 33044 | const is_comptime = val.ip_index != .unreachable_value; | ||
| 33045 | if (is_comptime) continue; | ||
| 33046 | if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue; | ||
| 33047 | return null; | ||
| 33048 | } | ||
| 33049 | return Value.empty_struct; | ||
| 33050 | }, | ||
| 33051 | |||
| 33052 | .inferred_alloc_const => unreachable, | 33077 | .inferred_alloc_const => unreachable, |
| 33053 | .inferred_alloc_mut => unreachable, | 33078 | .inferred_alloc_mut => unreachable, |
| 33054 | }, | 33079 | }, |
| ... | @@ -33150,7 +33175,36 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -33150,7 +33175,36 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33150 | } | 33175 | } |
| 33151 | } | 33176 | } |
| 33152 | } | 33177 | } |
| 33153 | // In this case the struct has no fields and therefore has one possible value. | 33178 | // In this case the struct has no runtime-known fields and |
| 33179 | // therefore has one possible value. | ||
| 33180 | |||
| 33181 | // TODO: this is incorrect for structs with comptime fields, I think | ||
| 33182 | // we should use a temporary allocator to construct an aggregate that | ||
| 33183 | // is populated with the comptime values and then intern that value here. | ||
| 33184 | // This TODO is repeated for anon_struct_type below, as well as | ||
| 33185 | // in the redundant implementation of one-possible-value in type.zig. | ||
| 33186 | const empty = try mod.intern(.{ .aggregate = .{ | ||
| 33187 | .ty = ty.ip_index, | ||
| 33188 | .fields = &.{}, | ||
| 33189 | } }); | ||
| 33190 | return empty.toValue(); | ||
| 33191 | }, | ||
| 33192 | |||
| 33193 | .anon_struct_type => |tuple| { | ||
| 33194 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 33195 | const is_comptime = val != .none; | ||
| 33196 | if (is_comptime) continue; | ||
| 33197 | if ((try sema.typeHasOnePossibleValue(field_ty.toType())) != null) continue; | ||
| 33198 | return null; | ||
| 33199 | } | ||
| 33200 | // In this case the struct has no runtime-known fields and | ||
| 33201 | // therefore has one possible value. | ||
| 33202 | |||
| 33203 | // TODO: this is incorrect for structs with comptime fields, I think | ||
| 33204 | // we should use a temporary allocator to construct an aggregate that | ||
| 33205 | // is populated with the comptime values and then intern that value here. | ||
| 33206 | // This TODO is repeated for struct_type above, as well as | ||
| 33207 | // in the redundant implementation of one-possible-value in type.zig. | ||
| 33154 | const empty = try mod.intern(.{ .aggregate = .{ | 33208 | const empty = try mod.intern(.{ .aggregate = .{ |
| 33155 | .ty = ty.ip_index, | 33209 | .ty = ty.ip_index, |
| 33156 | .fields = &.{}, | 33210 | .fields = &.{}, |
| ... | @@ -33647,17 +33701,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -33647,17 +33701,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33647 | return sema.typeRequiresComptime(ty.optionalChild(mod)); | 33701 | return sema.typeRequiresComptime(ty.optionalChild(mod)); |
| 33648 | }, | 33702 | }, |
| 33649 | 33703 | ||
| 33650 | .tuple, .anon_struct => { | ||
| 33651 | const tuple = ty.tupleFields(); | ||
| 33652 | for (tuple.types, 0..) |field_ty, i| { | ||
| 33653 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | ||
| 33654 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { | ||
| 33655 | return true; | ||
| 33656 | } | ||
| 33657 | } | ||
| 33658 | return false; | ||
| 33659 | }, | ||
| 33660 | |||
| 33661 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), | 33704 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), |
| 33662 | .anyframe_T => { | 33705 | .anyframe_T => { |
| 33663 | const child_ty = ty.castTag(.anyframe_T).?.data; | 33706 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | @@ -33752,6 +33795,15 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -33752,6 +33795,15 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33752 | }, | 33795 | }, |
| 33753 | } | 33796 | } |
| 33754 | }, | 33797 | }, |
| 33798 | .anon_struct_type => |tuple| { | ||
| 33799 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 33800 | const have_comptime_val = val != .none; | ||
| 33801 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) { | ||
| 33802 | return true; | ||
| 33803 | } | ||
| 33804 | } | ||
| 33805 | return false; | ||
| 33806 | }, | ||
| 33755 | 33807 | ||
| 33756 | .union_type => |union_type| { | 33808 | .union_type => |union_type| { |
| 33757 | const union_obj = mod.unionPtr(union_type.index); | 33809 | const union_obj = mod.unionPtr(union_type.index); |
| ... | @@ -33865,7 +33917,7 @@ fn structFieldIndex( | ... | @@ -33865,7 +33917,7 @@ fn structFieldIndex( |
| 33865 | ) !u32 { | 33917 | ) !u32 { |
| 33866 | const mod = sema.mod; | 33918 | const mod = sema.mod; |
| 33867 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); | 33919 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 33868 | if (struct_ty.isAnonStruct()) { | 33920 | if (struct_ty.isAnonStruct(mod)) { |
| 33869 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); | 33921 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 33870 | } else { | 33922 | } else { |
| 33871 | const struct_obj = mod.typeToStruct(struct_ty).?; | 33923 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| ... | @@ -33882,9 +33934,10 @@ fn anonStructFieldIndex( | ... | @@ -33882,9 +33934,10 @@ fn anonStructFieldIndex( |
| 33882 | field_name: []const u8, | 33934 | field_name: []const u8, |
| 33883 | field_src: LazySrcLoc, | 33935 | field_src: LazySrcLoc, |
| 33884 | ) !u32 { | 33936 | ) !u32 { |
| 33885 | const anon_struct = struct_ty.castTag(.anon_struct).?.data; | 33937 | const mod = sema.mod; |
| 33938 | const anon_struct = mod.intern_pool.indexToKey(struct_ty.ip_index).anon_struct_type; | ||
| 33886 | for (anon_struct.names, 0..) |name, i| { | 33939 | for (anon_struct.names, 0..) |name, i| { |
| 33887 | if (mem.eql(u8, name, field_name)) { | 33940 | if (mem.eql(u8, mod.intern_pool.stringToSlice(name), field_name)) { |
| 33888 | return @intCast(u32, i); | 33941 | return @intCast(u32, i); |
| 33889 | } | 33942 | } |
| 33890 | } | 33943 | } |
src/TypedValue.zig+10-10| ... | @@ -177,13 +177,16 @@ pub fn print( | ... | @@ -177,13 +177,16 @@ pub fn print( |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { | 179 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { |
| 180 | switch (field_ptr.container_ty.tag()) { | 180 | switch (mod.intern_pool.indexToKey(field_ptr.container_ty.ip_index)) { |
| 181 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | 181 | .anon_struct_type => |anon_struct| { |
| 182 | else => { | 182 | if (anon_struct.names.len == 0) { |
| 183 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index, mod); | 183 | return writer.print(".@\"{d}\"", .{field_ptr.field_index}); |
| 184 | return writer.print(".{s}", .{field_name}); | 184 | } |
| 185 | }, | 185 | }, |
| 186 | else => {}, | ||
| 186 | } | 187 | } |
| 188 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index, mod); | ||
| 189 | return writer.print(".{s}", .{field_name}); | ||
| 187 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { | 190 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { |
| 188 | const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index]; | 191 | const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index]; |
| 189 | return writer.print(".{s}", .{field_name}); | 192 | return writer.print(".{s}", .{field_name}); |
| ... | @@ -396,12 +399,9 @@ fn printAggregate( | ... | @@ -396,12 +399,9 @@ fn printAggregate( |
| 396 | while (i < max_len) : (i += 1) { | 399 | while (i < max_len) : (i += 1) { |
| 397 | if (i != 0) try writer.writeAll(", "); | 400 | if (i != 0) try writer.writeAll(", "); |
| 398 | switch (ty.ip_index) { | 401 | switch (ty.ip_index) { |
| 399 | .none => switch (ty.tag()) { | 402 | .none => {}, // TODO make this unreachable after finishing InternPool migration |
| 400 | .anon_struct => try writer.print(".{s} = ", .{ty.structFieldName(i, mod)}), | ||
| 401 | else => {}, | ||
| 402 | }, | ||
| 403 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 403 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 404 | .struct_type => try writer.print(".{s} = ", .{ty.structFieldName(i, mod)}), | 404 | .struct_type, .anon_struct_type => try writer.print(".{s} = ", .{ty.structFieldName(i, mod)}), |
| 405 | else => {}, | 405 | else => {}, |
| 406 | }, | 406 | }, |
| 407 | } | 407 | } |
src/arch/x86_64/CodeGen.zig+1-1| ... | @@ -11411,7 +11411,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11411,7 +11411,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11411 | const union_obj = mod.typeToUnion(union_ty).?; | 11411 | const union_obj = mod.typeToUnion(union_ty).?; |
| 11412 | const field_name = union_obj.fields.keys()[extra.field_index]; | 11412 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 11413 | const tag_ty = union_obj.tag_ty; | 11413 | const tag_ty = union_obj.tag_ty; |
| 11414 | const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); | 11414 | const field_index = tag_ty.enumFieldIndex(field_name, mod).?; |
| 11415 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); | 11415 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 11416 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); | 11416 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); |
| 11417 | const tag_int = tag_int_val.toUnsignedInt(mod); | 11417 | const tag_int = tag_int_val.toUnsignedInt(mod); |
src/codegen/c.zig+25-31| ... | @@ -3417,8 +3417,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | ... | @@ -3417,8 +3417,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3417 | const op_inst = Air.refToIndex(un_op); | 3417 | const op_inst = Air.refToIndex(un_op); |
| 3418 | const op_ty = f.typeOf(un_op); | 3418 | const op_ty = f.typeOf(un_op); |
| 3419 | const ret_ty = if (is_ptr) op_ty.childType(mod) else op_ty; | 3419 | const ret_ty = if (is_ptr) op_ty.childType(mod) else op_ty; |
| 3420 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 3420 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); |
| 3421 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, mod); | ||
| 3422 | 3421 | ||
| 3423 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { | 3422 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { |
| 3424 | try reap(f, inst, &.{un_op}); | 3423 | try reap(f, inst, &.{un_op}); |
| ... | @@ -4115,8 +4114,7 @@ fn airCall( | ... | @@ -4115,8 +4114,7 @@ fn airCall( |
| 4115 | } | 4114 | } |
| 4116 | resolved_arg.* = try f.resolveInst(arg); | 4115 | resolved_arg.* = try f.resolveInst(arg); |
| 4117 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { | 4116 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { |
| 4118 | var lowered_arg_buf: LowerFnRetTyBuffer = undefined; | 4117 | const lowered_arg_ty = try lowerFnRetTy(arg_ty, mod); |
| 4119 | const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, mod); | ||
| 4120 | 4118 | ||
| 4121 | const array_local = try f.allocLocal(inst, lowered_arg_ty); | 4119 | const array_local = try f.allocLocal(inst, lowered_arg_ty); |
| 4122 | try writer.writeAll("memcpy("); | 4120 | try writer.writeAll("memcpy("); |
| ... | @@ -4146,8 +4144,7 @@ fn airCall( | ... | @@ -4146,8 +4144,7 @@ fn airCall( |
| 4146 | }; | 4144 | }; |
| 4147 | 4145 | ||
| 4148 | const ret_ty = fn_ty.fnReturnType(); | 4146 | const ret_ty = fn_ty.fnReturnType(); |
| 4149 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 4147 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); |
| 4150 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, mod); | ||
| 4151 | 4148 | ||
| 4152 | const result_local = result: { | 4149 | const result_local = result: { |
| 4153 | if (modifier == .always_tail) { | 4150 | if (modifier == .always_tail) { |
| ... | @@ -5200,7 +5197,7 @@ fn fieldLocation( | ... | @@ -5200,7 +5197,7 @@ fn fieldLocation( |
| 5200 | const field_ty = container_ty.structFieldType(next_field_index, mod); | 5197 | const field_ty = container_ty.structFieldType(next_field_index, mod); |
| 5201 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 5198 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 5202 | 5199 | ||
| 5203 | break .{ .field = if (container_ty.isSimpleTuple()) | 5200 | break .{ .field = if (container_ty.isSimpleTuple(mod)) |
| 5204 | .{ .field = next_field_index } | 5201 | .{ .field = next_field_index } |
| 5205 | else | 5202 | else |
| 5206 | .{ .identifier = container_ty.structFieldName(next_field_index, mod) } }; | 5203 | .{ .identifier = container_ty.structFieldName(next_field_index, mod) } }; |
| ... | @@ -5395,16 +5392,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5395,16 +5392,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5395 | 5392 | ||
| 5396 | const field_name: CValue = switch (struct_ty.ip_index) { | 5393 | const field_name: CValue = switch (struct_ty.ip_index) { |
| 5397 | .none => switch (struct_ty.tag()) { | 5394 | .none => switch (struct_ty.tag()) { |
| 5398 | .tuple, .anon_struct => if (struct_ty.isSimpleTuple()) | ||
| 5399 | .{ .field = extra.field_index } | ||
| 5400 | else | ||
| 5401 | .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, | ||
| 5402 | |||
| 5403 | else => unreachable, | 5395 | else => unreachable, |
| 5404 | }, | 5396 | }, |
| 5405 | else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | 5397 | else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 5406 | .struct_type => switch (struct_ty.containerLayout(mod)) { | 5398 | .struct_type => switch (struct_ty.containerLayout(mod)) { |
| 5407 | .Auto, .Extern => if (struct_ty.isSimpleTuple()) | 5399 | .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) |
| 5408 | .{ .field = extra.field_index } | 5400 | .{ .field = extra.field_index } |
| 5409 | else | 5401 | else |
| 5410 | .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, | 5402 | .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, |
| ... | @@ -5465,6 +5457,12 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5465,6 +5457,12 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5465 | return local; | 5457 | return local; |
| 5466 | }, | 5458 | }, |
| 5467 | }, | 5459 | }, |
| 5460 | |||
| 5461 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0) | ||
| 5462 | .{ .field = extra.field_index } | ||
| 5463 | else | ||
| 5464 | .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, | ||
| 5465 | |||
| 5468 | .union_type => |union_type| field_name: { | 5466 | .union_type => |union_type| field_name: { |
| 5469 | const union_obj = mod.unionPtr(union_type.index); | 5467 | const union_obj = mod.unionPtr(union_type.index); |
| 5470 | if (union_obj.layout == .Packed) { | 5468 | if (union_obj.layout == .Packed) { |
| ... | @@ -6791,7 +6789,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6791,7 +6789,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6791 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 6789 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6792 | 6790 | ||
| 6793 | const a = try Assignment.start(f, writer, field_ty); | 6791 | const a = try Assignment.start(f, writer, field_ty); |
| 6794 | try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple()) | 6792 | try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod)) |
| 6795 | .{ .field = field_i } | 6793 | .{ .field = field_i } |
| 6796 | else | 6794 | else |
| 6797 | .{ .identifier = inst_ty.structFieldName(field_i, mod) }); | 6795 | .{ .identifier = inst_ty.structFieldName(field_i, mod) }); |
| ... | @@ -7704,25 +7702,21 @@ const Vectorize = struct { | ... | @@ -7704,25 +7702,21 @@ const Vectorize = struct { |
| 7704 | } | 7702 | } |
| 7705 | }; | 7703 | }; |
| 7706 | 7704 | ||
| 7707 | const LowerFnRetTyBuffer = struct { | 7705 | fn lowerFnRetTy(ret_ty: Type, mod: *Module) !Type { |
| 7708 | names: [1][]const u8, | 7706 | if (ret_ty.ip_index == .noreturn_type) return Type.noreturn; |
| 7709 | types: [1]Type, | ||
| 7710 | values: [1]Value, | ||
| 7711 | payload: Type.Payload.AnonStruct, | ||
| 7712 | }; | ||
| 7713 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, mod: *Module) Type { | ||
| 7714 | if (ret_ty.zigTypeTag(mod) == .NoReturn) return Type.noreturn; | ||
| 7715 | 7707 | ||
| 7716 | if (lowersToArray(ret_ty, mod)) { | 7708 | if (lowersToArray(ret_ty, mod)) { |
| 7717 | buffer.names = [1][]const u8{"array"}; | 7709 | const names = [1]InternPool.NullTerminatedString{ |
| 7718 | buffer.types = [1]Type{ret_ty}; | 7710 | try mod.intern_pool.getOrPutString(mod.gpa, "array"), |
| 7719 | buffer.values = [1]Value{Value.@"unreachable"}; | 7711 | }; |
| 7720 | buffer.payload = .{ .data = .{ | 7712 | const types = [1]InternPool.Index{ret_ty.ip_index}; |
| 7721 | .names = &buffer.names, | 7713 | const values = [1]InternPool.Index{.none}; |
| 7722 | .types = &buffer.types, | 7714 | const interned = try mod.intern(.{ .anon_struct_type = .{ |
| 7723 | .values = &buffer.values, | 7715 | .names = &names, |
| 7724 | } }; | 7716 | .types = &types, |
| 7725 | return Type.initPayload(&buffer.payload.base); | 7717 | .values = &values, |
| 7718 | } }); | ||
| 7719 | return interned.toType(); | ||
| 7726 | } | 7720 | } |
| 7727 | 7721 | ||
| 7728 | return if (ret_ty.hasRuntimeBitsIgnoreComptime(mod)) ret_ty else Type.void; | 7722 | return if (ret_ty.hasRuntimeBitsIgnoreComptime(mod)) ret_ty else Type.void; |
src/codegen/c/type.zig+3-3| ... | @@ -1951,7 +1951,7 @@ pub const CType = extern union { | ... | @@ -1951,7 +1951,7 @@ pub const CType = extern union { |
| 1951 | 1951 | ||
| 1952 | defer c_field_i += 1; | 1952 | defer c_field_i += 1; |
| 1953 | fields_pl[c_field_i] = .{ | 1953 | fields_pl[c_field_i] = .{ |
| 1954 | .name = try if (ty.isSimpleTuple()) | 1954 | .name = try if (ty.isSimpleTuple(mod)) |
| 1955 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) | 1955 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) |
| 1956 | else | 1956 | else |
| 1957 | arena.dupeZ(u8, switch (zig_ty_tag) { | 1957 | arena.dupeZ(u8, switch (zig_ty_tag) { |
| ... | @@ -2102,7 +2102,7 @@ pub const CType = extern union { | ... | @@ -2102,7 +2102,7 @@ pub const CType = extern union { |
| 2102 | .payload => unreachable, | 2102 | .payload => unreachable, |
| 2103 | }) or !mem.eql( | 2103 | }) or !mem.eql( |
| 2104 | u8, | 2104 | u8, |
| 2105 | if (ty.isSimpleTuple()) | 2105 | if (ty.isSimpleTuple(mod)) |
| 2106 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable | 2106 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2107 | else switch (zig_ty_tag) { | 2107 | else switch (zig_ty_tag) { |
| 2108 | .Struct => ty.structFieldName(field_i, mod), | 2108 | .Struct => ty.structFieldName(field_i, mod), |
| ... | @@ -2224,7 +2224,7 @@ pub const CType = extern union { | ... | @@ -2224,7 +2224,7 @@ pub const CType = extern union { |
| 2224 | .global => .global, | 2224 | .global => .global, |
| 2225 | .payload => unreachable, | 2225 | .payload => unreachable, |
| 2226 | }); | 2226 | }); |
| 2227 | hasher.update(if (ty.isSimpleTuple()) | 2227 | hasher.update(if (ty.isSimpleTuple(mod)) |
| 2228 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable | 2228 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2229 | else switch (zig_ty_tag) { | 2229 | else switch (zig_ty_tag) { |
| 2230 | .Struct => ty.structFieldName(field_i, mod), | 2230 | .Struct => ty.structFieldName(field_i, mod), |
src/codegen/llvm.zig+263-255| ... | @@ -2009,83 +2009,84 @@ pub const Object = struct { | ... | @@ -2009,83 +2009,84 @@ pub const Object = struct { |
| 2009 | break :blk fwd_decl; | 2009 | break :blk fwd_decl; |
| 2010 | }; | 2010 | }; |
| 2011 | 2011 | ||
| 2012 | if (ty.isSimpleTupleOrAnonStruct()) { | 2012 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 2013 | const tuple = ty.tupleFields(); | 2013 | .anon_struct_type => |tuple| { |
| 2014 | 2014 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 2015 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 2015 | defer di_fields.deinit(gpa); |
| 2016 | defer di_fields.deinit(gpa); | 2016 | |
| 2017 | 2017 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 2018 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | 2018 | |
| 2019 | 2019 | comptime assert(struct_layout_version == 2); | |
| 2020 | comptime assert(struct_layout_version == 2); | 2020 | var offset: u64 = 0; |
| 2021 | var offset: u64 = 0; | 2021 | |
| 2022 | 2022 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 2023 | for (tuple.types, 0..) |field_ty, i| { | 2023 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 2024 | const field_val = tuple.values[i]; | 2024 | |
| 2025 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | 2025 | const field_size = field_ty.toType().abiSize(mod); |
| 2026 | 2026 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 2027 | const field_size = field_ty.abiSize(mod); | 2027 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2028 | const field_align = field_ty.abiAlignment(mod); | 2028 | offset = field_offset + field_size; |
| 2029 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2029 | |
| 2030 | offset = field_offset + field_size; | 2030 | const field_name = if (tuple.names.len != 0) |
| 2031 | 2031 | mod.intern_pool.stringToSlice(tuple.names[i]) | |
| 2032 | const field_name = if (ty.castTag(.anon_struct)) |payload| | 2032 | else |
| 2033 | try gpa.dupeZ(u8, payload.data.names[i]) | 2033 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); |
| 2034 | else | 2034 | defer gpa.free(field_name); |
| 2035 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | 2035 | |
| 2036 | defer gpa.free(field_name); | 2036 | try di_fields.append(gpa, dib.createMemberType( |
| 2037 | fwd_decl.toScope(), | ||
| 2038 | field_name, | ||
| 2039 | null, // file | ||
| 2040 | 0, // line | ||
| 2041 | field_size * 8, // size in bits | ||
| 2042 | field_align * 8, // align in bits | ||
| 2043 | field_offset * 8, // offset in bits | ||
| 2044 | 0, // flags | ||
| 2045 | try o.lowerDebugType(field_ty.toType(), .full), | ||
| 2046 | )); | ||
| 2047 | } | ||
| 2037 | 2048 | ||
| 2038 | try di_fields.append(gpa, dib.createMemberType( | 2049 | const full_di_ty = dib.createStructType( |
| 2039 | fwd_decl.toScope(), | 2050 | compile_unit_scope, |
| 2040 | field_name, | 2051 | name.ptr, |
| 2041 | null, // file | 2052 | null, // file |
| 2042 | 0, // line | 2053 | 0, // line |
| 2043 | field_size * 8, // size in bits | 2054 | ty.abiSize(mod) * 8, // size in bits |
| 2044 | field_align * 8, // align in bits | 2055 | ty.abiAlignment(mod) * 8, // align in bits |
| 2045 | field_offset * 8, // offset in bits | ||
| 2046 | 0, // flags | 2056 | 0, // flags |
| 2047 | try o.lowerDebugType(field_ty, .full), | 2057 | null, // derived from |
| 2048 | )); | 2058 | di_fields.items.ptr, |
| 2049 | } | 2059 | @intCast(c_int, di_fields.items.len), |
| 2050 | 2060 | 0, // run time lang | |
| 2051 | const full_di_ty = dib.createStructType( | 2061 | null, // vtable holder |
| 2052 | compile_unit_scope, | 2062 | "", // unique id |
| 2053 | name.ptr, | 2063 | ); |
| 2054 | null, // file | 2064 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2055 | 0, // line | 2065 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2056 | ty.abiSize(mod) * 8, // size in bits | 2066 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); |
| 2057 | ty.abiAlignment(mod) * 8, // align in bits | 2067 | return full_di_ty; |
| 2058 | 0, // flags | 2068 | }, |
| 2059 | null, // derived from | 2069 | .struct_type => |struct_type| s: { |
| 2060 | di_fields.items.ptr, | 2070 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; |
| 2061 | @intCast(c_int, di_fields.items.len), | 2071 | |
| 2062 | 0, // run time lang | 2072 | if (!struct_obj.haveFieldTypes()) { |
| 2063 | null, // vtable holder | 2073 | // This can happen if a struct type makes it all the way to |
| 2064 | "", // unique id | 2074 | // flush() without ever being instantiated or referenced (even |
| 2065 | ); | 2075 | // via pointer). The only reason we are hearing about it now is |
| 2066 | dib.replaceTemporary(fwd_decl, full_di_ty); | 2076 | // that it is being used as a namespace to put other debug types |
| 2067 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2077 | // into. Therefore we can satisfy this by making an empty namespace, |
| 2068 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 2078 | // rather than changing the frontend to unnecessarily resolve the |
| 2069 | return full_di_ty; | 2079 | // struct field types. |
| 2070 | } | 2080 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 2071 | 2081 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | |
| 2072 | if (mod.typeToStruct(ty)) |struct_obj| { | 2082 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 2073 | if (!struct_obj.haveFieldTypes()) { | 2083 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2074 | // This can happen if a struct type makes it all the way to | 2084 | // means we can't use `gop` anymore. |
| 2075 | // flush() without ever being instantiated or referenced (even | 2085 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module }); |
| 2076 | // via pointer). The only reason we are hearing about it now is | 2086 | return struct_di_ty; |
| 2077 | // that it is being used as a namespace to put other debug types | 2087 | } |
| 2078 | // into. Therefore we can satisfy this by making an empty namespace, | 2088 | }, |
| 2079 | // rather than changing the frontend to unnecessarily resolve the | 2089 | else => {}, |
| 2080 | // struct field types. | ||
| 2081 | const owner_decl_index = ty.getOwnerDecl(mod); | ||
| 2082 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | ||
| 2083 | dib.replaceTemporary(fwd_decl, struct_di_ty); | ||
| 2084 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | ||
| 2085 | // means we can't use `gop` anymore. | ||
| 2086 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module }); | ||
| 2087 | return struct_di_ty; | ||
| 2088 | } | ||
| 2089 | } | 2090 | } |
| 2090 | 2091 | ||
| 2091 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { | 2092 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| ... | @@ -2931,59 +2932,61 @@ pub const DeclGen = struct { | ... | @@ -2931,59 +2932,61 @@ pub const DeclGen = struct { |
| 2931 | // reference, we need to copy it here. | 2932 | // reference, we need to copy it here. |
| 2932 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | 2933 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 2933 | 2934 | ||
| 2934 | if (t.isSimpleTupleOrAnonStruct()) { | 2935 | const struct_type = switch (mod.intern_pool.indexToKey(t.ip_index)) { |
| 2935 | const tuple = t.tupleFields(); | 2936 | .anon_struct_type => |tuple| { |
| 2936 | const llvm_struct_ty = dg.context.structCreateNamed(""); | 2937 | const llvm_struct_ty = dg.context.structCreateNamed(""); |
| 2937 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 2938 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 2938 | 2939 | ||
| 2939 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | 2940 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; |
| 2940 | defer llvm_field_types.deinit(gpa); | 2941 | defer llvm_field_types.deinit(gpa); |
| 2941 | 2942 | ||
| 2942 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); | 2943 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); |
| 2943 | 2944 | ||
| 2944 | comptime assert(struct_layout_version == 2); | 2945 | comptime assert(struct_layout_version == 2); |
| 2945 | var offset: u64 = 0; | 2946 | var offset: u64 = 0; |
| 2946 | var big_align: u32 = 0; | 2947 | var big_align: u32 = 0; |
| 2947 | 2948 | ||
| 2948 | for (tuple.types, 0..) |field_ty, i| { | 2949 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 2949 | const field_val = tuple.values[i]; | 2950 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 2950 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | ||
| 2951 | 2951 | ||
| 2952 | const field_align = field_ty.abiAlignment(mod); | 2952 | const field_align = field_ty.toType().abiAlignment(mod); |
| 2953 | big_align = @max(big_align, field_align); | 2953 | big_align = @max(big_align, field_align); |
| 2954 | const prev_offset = offset; | 2954 | const prev_offset = offset; |
| 2955 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2955 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2956 | 2956 | ||
| 2957 | const padding_len = offset - prev_offset; | 2957 | const padding_len = offset - prev_offset; |
| 2958 | if (padding_len > 0) { | 2958 | if (padding_len > 0) { |
| 2959 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 2959 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2960 | try llvm_field_types.append(gpa, llvm_array_ty); | 2960 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 2961 | } | 2961 | } |
| 2962 | const field_llvm_ty = try dg.lowerType(field_ty); | 2962 | const field_llvm_ty = try dg.lowerType(field_ty.toType()); |
| 2963 | try llvm_field_types.append(gpa, field_llvm_ty); | 2963 | try llvm_field_types.append(gpa, field_llvm_ty); |
| 2964 | 2964 | ||
| 2965 | offset += field_ty.abiSize(mod); | 2965 | offset += field_ty.toType().abiSize(mod); |
| 2966 | } | 2966 | } |
| 2967 | { | 2967 | { |
| 2968 | const prev_offset = offset; | 2968 | const prev_offset = offset; |
| 2969 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 2969 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 2970 | const padding_len = offset - prev_offset; | 2970 | const padding_len = offset - prev_offset; |
| 2971 | if (padding_len > 0) { | 2971 | if (padding_len > 0) { |
| 2972 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 2972 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2973 | try llvm_field_types.append(gpa, llvm_array_ty); | 2973 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 2974 | } | ||
| 2974 | } | 2975 | } |
| 2975 | } | ||
| 2976 | 2976 | ||
| 2977 | llvm_struct_ty.structSetBody( | 2977 | llvm_struct_ty.structSetBody( |
| 2978 | llvm_field_types.items.ptr, | 2978 | llvm_field_types.items.ptr, |
| 2979 | @intCast(c_uint, llvm_field_types.items.len), | 2979 | @intCast(c_uint, llvm_field_types.items.len), |
| 2980 | .False, | 2980 | .False, |
| 2981 | ); | 2981 | ); |
| 2982 | 2982 | ||
| 2983 | return llvm_struct_ty; | 2983 | return llvm_struct_ty; |
| 2984 | } | 2984 | }, |
| 2985 | .struct_type => |struct_type| struct_type, | ||
| 2986 | else => unreachable, | ||
| 2987 | }; | ||
| 2985 | 2988 | ||
| 2986 | const struct_obj = mod.typeToStruct(t).?; | 2989 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 2987 | 2990 | ||
| 2988 | if (struct_obj.layout == .Packed) { | 2991 | if (struct_obj.layout == .Packed) { |
| 2989 | assert(struct_obj.haveLayout()); | 2992 | assert(struct_obj.haveLayout()); |
| ... | @@ -3625,71 +3628,74 @@ pub const DeclGen = struct { | ... | @@ -3625,71 +3628,74 @@ pub const DeclGen = struct { |
| 3625 | const field_vals = tv.val.castTag(.aggregate).?.data; | 3628 | const field_vals = tv.val.castTag(.aggregate).?.data; |
| 3626 | const gpa = dg.gpa; | 3629 | const gpa = dg.gpa; |
| 3627 | 3630 | ||
| 3628 | if (tv.ty.isSimpleTupleOrAnonStruct()) { | 3631 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { |
| 3629 | const tuple = tv.ty.tupleFields(); | 3632 | .anon_struct_type => |tuple| { |
| 3630 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | 3633 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; |
| 3631 | defer llvm_fields.deinit(gpa); | 3634 | defer llvm_fields.deinit(gpa); |
| 3632 | 3635 | ||
| 3633 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | 3636 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); |
| 3634 | 3637 | ||
| 3635 | comptime assert(struct_layout_version == 2); | 3638 | comptime assert(struct_layout_version == 2); |
| 3636 | var offset: u64 = 0; | 3639 | var offset: u64 = 0; |
| 3637 | var big_align: u32 = 0; | 3640 | var big_align: u32 = 0; |
| 3638 | var need_unnamed = false; | 3641 | var need_unnamed = false; |
| 3639 | 3642 | ||
| 3640 | for (tuple.types, 0..) |field_ty, i| { | 3643 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 3641 | if (tuple.values[i].ip_index != .unreachable_value) continue; | 3644 | if (field_val != .none) continue; |
| 3642 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 3645 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3643 | |||
| 3644 | const field_align = field_ty.abiAlignment(mod); | ||
| 3645 | big_align = @max(big_align, field_align); | ||
| 3646 | const prev_offset = offset; | ||
| 3647 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | ||
| 3648 | |||
| 3649 | const padding_len = offset - prev_offset; | ||
| 3650 | if (padding_len > 0) { | ||
| 3651 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | ||
| 3652 | // TODO make this and all other padding elsewhere in debug | ||
| 3653 | // builds be 0xaa not undef. | ||
| 3654 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | ||
| 3655 | } | ||
| 3656 | 3646 | ||
| 3657 | const field_llvm_val = try dg.lowerValue(.{ | 3647 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3658 | .ty = field_ty, | 3648 | big_align = @max(big_align, field_align); |
| 3659 | .val = field_vals[i], | 3649 | const prev_offset = offset; |
| 3660 | }); | 3650 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 3661 | 3651 | ||
| 3662 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val); | 3652 | const padding_len = offset - prev_offset; |
| 3653 | if (padding_len > 0) { | ||
| 3654 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | ||
| 3655 | // TODO make this and all other padding elsewhere in debug | ||
| 3656 | // builds be 0xaa not undef. | ||
| 3657 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | ||
| 3658 | } | ||
| 3663 | 3659 | ||
| 3664 | llvm_fields.appendAssumeCapacity(field_llvm_val); | 3660 | const field_llvm_val = try dg.lowerValue(.{ |
| 3661 | .ty = field_ty.toType(), | ||
| 3662 | .val = field_vals[i], | ||
| 3663 | }); | ||
| 3665 | 3664 | ||
| 3666 | offset += field_ty.abiSize(mod); | 3665 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); |
| 3667 | } | 3666 | |
| 3668 | { | 3667 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 3669 | const prev_offset = offset; | 3668 | |
| 3670 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 3669 | offset += field_ty.toType().abiSize(mod); |
| 3671 | const padding_len = offset - prev_offset; | 3670 | } |
| 3672 | if (padding_len > 0) { | 3671 | { |
| 3673 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 3672 | const prev_offset = offset; |
| 3674 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | 3673 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 3674 | const padding_len = offset - prev_offset; | ||
| 3675 | if (padding_len > 0) { | ||
| 3676 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | ||
| 3677 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | ||
| 3678 | } | ||
| 3675 | } | 3679 | } |
| 3676 | } | ||
| 3677 | 3680 | ||
| 3678 | if (need_unnamed) { | 3681 | if (need_unnamed) { |
| 3679 | return dg.context.constStruct( | 3682 | return dg.context.constStruct( |
| 3680 | llvm_fields.items.ptr, | 3683 | llvm_fields.items.ptr, |
| 3681 | @intCast(c_uint, llvm_fields.items.len), | 3684 | @intCast(c_uint, llvm_fields.items.len), |
| 3682 | .False, | 3685 | .False, |
| 3683 | ); | 3686 | ); |
| 3684 | } else { | 3687 | } else { |
| 3685 | return llvm_struct_ty.constNamedStruct( | 3688 | return llvm_struct_ty.constNamedStruct( |
| 3686 | llvm_fields.items.ptr, | 3689 | llvm_fields.items.ptr, |
| 3687 | @intCast(c_uint, llvm_fields.items.len), | 3690 | @intCast(c_uint, llvm_fields.items.len), |
| 3688 | ); | 3691 | ); |
| 3689 | } | 3692 | } |
| 3690 | } | 3693 | }, |
| 3694 | .struct_type => |struct_type| struct_type, | ||
| 3695 | else => unreachable, | ||
| 3696 | }; | ||
| 3691 | 3697 | ||
| 3692 | const struct_obj = mod.typeToStruct(tv.ty).?; | 3698 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 3693 | 3699 | ||
| 3694 | if (struct_obj.layout == .Packed) { | 3700 | if (struct_obj.layout == .Packed) { |
| 3695 | assert(struct_obj.haveLayout()); | 3701 | assert(struct_obj.haveLayout()); |
| ... | @@ -4077,13 +4083,11 @@ pub const DeclGen = struct { | ... | @@ -4077,13 +4083,11 @@ pub const DeclGen = struct { |
| 4077 | return field_addr.constIntToPtr(final_llvm_ty); | 4083 | return field_addr.constIntToPtr(final_llvm_ty); |
| 4078 | } | 4084 | } |
| 4079 | 4085 | ||
| 4080 | var ty_buf: Type.Payload.Pointer = undefined; | ||
| 4081 | |||
| 4082 | const parent_llvm_ty = try dg.lowerType(parent_ty); | 4086 | const parent_llvm_ty = try dg.lowerType(parent_ty); |
| 4083 | if (llvmFieldIndex(parent_ty, field_index, mod, &ty_buf)) |llvm_field_index| { | 4087 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { |
| 4084 | const indices: [2]*llvm.Value = .{ | 4088 | const indices: [2]*llvm.Value = .{ |
| 4085 | llvm_u32.constInt(0, .False), | 4089 | llvm_u32.constInt(0, .False), |
| 4086 | llvm_u32.constInt(llvm_field_index, .False), | 4090 | llvm_u32.constInt(llvm_field.index, .False), |
| 4087 | }; | 4091 | }; |
| 4088 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 4092 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4089 | } else { | 4093 | } else { |
| ... | @@ -6006,8 +6010,7 @@ pub const FuncGen = struct { | ... | @@ -6006,8 +6010,7 @@ pub const FuncGen = struct { |
| 6006 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); | 6010 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); |
| 6007 | }, | 6011 | }, |
| 6008 | else => { | 6012 | else => { |
| 6009 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 6013 | const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index; |
| 6010 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, mod, &ptr_ty_buf).?; | ||
| 6011 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); | 6014 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); |
| 6012 | }, | 6015 | }, |
| 6013 | }, | 6016 | }, |
| ... | @@ -6035,16 +6038,22 @@ pub const FuncGen = struct { | ... | @@ -6035,16 +6038,22 @@ pub const FuncGen = struct { |
| 6035 | switch (struct_ty.zigTypeTag(mod)) { | 6038 | switch (struct_ty.zigTypeTag(mod)) { |
| 6036 | .Struct => { | 6039 | .Struct => { |
| 6037 | assert(struct_ty.containerLayout(mod) != .Packed); | 6040 | assert(struct_ty.containerLayout(mod) != .Packed); |
| 6038 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 6041 | const llvm_field = llvmField(struct_ty, field_index, mod).?; |
| 6039 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, mod, &ptr_ty_buf).?; | ||
| 6040 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); | 6042 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); |
| 6041 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, ""); | 6043 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, ""); |
| 6042 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | 6044 | const field_ptr_ty = try mod.ptrType(.{ |
| 6045 | .elem_type = llvm_field.ty.ip_index, | ||
| 6046 | .alignment = llvm_field.alignment, | ||
| 6047 | }); | ||
| 6043 | if (isByRef(field_ty, mod)) { | 6048 | if (isByRef(field_ty, mod)) { |
| 6044 | if (canElideLoad(self, body_tail)) | 6049 | if (canElideLoad(self, body_tail)) |
| 6045 | return field_ptr; | 6050 | return field_ptr; |
| 6046 | 6051 | ||
| 6047 | return self.loadByRef(field_ptr, field_ty, ptr_ty_buf.data.alignment(mod), false); | 6052 | const field_alignment = if (llvm_field.alignment != 0) |
| 6053 | llvm_field.alignment | ||
| 6054 | else | ||
| 6055 | llvm_field.ty.abiAlignment(mod); | ||
| 6056 | return self.loadByRef(field_ptr, field_ty, field_alignment, false); | ||
| 6048 | } else { | 6057 | } else { |
| 6049 | return self.load(field_ptr, field_ptr_ty); | 6058 | return self.load(field_ptr, field_ptr_ty); |
| 6050 | } | 6059 | } |
| ... | @@ -6912,12 +6921,14 @@ pub const FuncGen = struct { | ... | @@ -6912,12 +6921,14 @@ pub const FuncGen = struct { |
| 6912 | const struct_ty = self.air.getRefType(ty_pl.ty); | 6921 | const struct_ty = self.air.getRefType(ty_pl.ty); |
| 6913 | const field_index = ty_pl.payload; | 6922 | const field_index = ty_pl.payload; |
| 6914 | 6923 | ||
| 6915 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | ||
| 6916 | const mod = self.dg.module; | 6924 | const mod = self.dg.module; |
| 6917 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, mod, &ptr_ty_buf).?; | 6925 | const llvm_field = llvmField(struct_ty, field_index, mod).?; |
| 6918 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); | 6926 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); |
| 6919 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field_index, ""); | 6927 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, ""); |
| 6920 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | 6928 | const field_ptr_ty = try mod.ptrType(.{ |
| 6929 | .elem_type = llvm_field.ty.ip_index, | ||
| 6930 | .alignment = llvm_field.alignment, | ||
| 6931 | }); | ||
| 6921 | return self.load(field_ptr, field_ptr_ty); | 6932 | return self.load(field_ptr, field_ptr_ty); |
| 6922 | } | 6933 | } |
| 6923 | 6934 | ||
| ... | @@ -7430,9 +7441,8 @@ pub const FuncGen = struct { | ... | @@ -7430,9 +7441,8 @@ pub const FuncGen = struct { |
| 7430 | const result = self.builder.buildExtractValue(result_struct, 0, ""); | 7441 | const result = self.builder.buildExtractValue(result_struct, 0, ""); |
| 7431 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); | 7442 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); |
| 7432 | 7443 | ||
| 7433 | var ty_buf: Type.Payload.Pointer = undefined; | 7444 | const result_index = llvmField(dest_ty, 0, mod).?.index; |
| 7434 | const result_index = llvmFieldIndex(dest_ty, 0, mod, &ty_buf).?; | 7445 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; |
| 7435 | const overflow_index = llvmFieldIndex(dest_ty, 1, mod, &ty_buf).?; | ||
| 7436 | 7446 | ||
| 7437 | if (isByRef(dest_ty, mod)) { | 7447 | if (isByRef(dest_ty, mod)) { |
| 7438 | const result_alignment = dest_ty.abiAlignment(mod); | 7448 | const result_alignment = dest_ty.abiAlignment(mod); |
| ... | @@ -7736,9 +7746,8 @@ pub const FuncGen = struct { | ... | @@ -7736,9 +7746,8 @@ pub const FuncGen = struct { |
| 7736 | 7746 | ||
| 7737 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); | 7747 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 7738 | 7748 | ||
| 7739 | var ty_buf: Type.Payload.Pointer = undefined; | 7749 | const result_index = llvmField(dest_ty, 0, mod).?.index; |
| 7740 | const result_index = llvmFieldIndex(dest_ty, 0, mod, &ty_buf).?; | 7750 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; |
| 7741 | const overflow_index = llvmFieldIndex(dest_ty, 1, mod, &ty_buf).?; | ||
| 7742 | 7751 | ||
| 7743 | if (isByRef(dest_ty, mod)) { | 7752 | if (isByRef(dest_ty, mod)) { |
| 7744 | const result_alignment = dest_ty.abiAlignment(mod); | 7753 | const result_alignment = dest_ty.abiAlignment(mod); |
| ... | @@ -9300,8 +9309,6 @@ pub const FuncGen = struct { | ... | @@ -9300,8 +9309,6 @@ pub const FuncGen = struct { |
| 9300 | return running_int; | 9309 | return running_int; |
| 9301 | } | 9310 | } |
| 9302 | 9311 | ||
| 9303 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | ||
| 9304 | |||
| 9305 | if (isByRef(result_ty, mod)) { | 9312 | if (isByRef(result_ty, mod)) { |
| 9306 | const llvm_u32 = self.context.intType(32); | 9313 | const llvm_u32 = self.context.intType(32); |
| 9307 | // TODO in debug builds init to undef so that the padding will be 0xaa | 9314 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| ... | @@ -9313,7 +9320,7 @@ pub const FuncGen = struct { | ... | @@ -9313,7 +9320,7 @@ pub const FuncGen = struct { |
| 9313 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; | 9320 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9314 | 9321 | ||
| 9315 | const llvm_elem = try self.resolveInst(elem); | 9322 | const llvm_elem = try self.resolveInst(elem); |
| 9316 | const llvm_i = llvmFieldIndex(result_ty, i, mod, &ptr_ty_buf).?; | 9323 | const llvm_i = llvmField(result_ty, i, mod).?.index; |
| 9317 | indices[1] = llvm_u32.constInt(llvm_i, .False); | 9324 | indices[1] = llvm_u32.constInt(llvm_i, .False); |
| 9318 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); | 9325 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); |
| 9319 | var field_ptr_payload: Type.Payload.Pointer = .{ | 9326 | var field_ptr_payload: Type.Payload.Pointer = .{ |
| ... | @@ -9334,7 +9341,7 @@ pub const FuncGen = struct { | ... | @@ -9334,7 +9341,7 @@ pub const FuncGen = struct { |
| 9334 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; | 9341 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9335 | 9342 | ||
| 9336 | const llvm_elem = try self.resolveInst(elem); | 9343 | const llvm_elem = try self.resolveInst(elem); |
| 9337 | const llvm_i = llvmFieldIndex(result_ty, i, mod, &ptr_ty_buf).?; | 9344 | const llvm_i = llvmField(result_ty, i, mod).?.index; |
| 9338 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); | 9345 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); |
| 9339 | } | 9346 | } |
| 9340 | return result; | 9347 | return result; |
| ... | @@ -9796,9 +9803,8 @@ pub const FuncGen = struct { | ... | @@ -9796,9 +9803,8 @@ pub const FuncGen = struct { |
| 9796 | else => { | 9803 | else => { |
| 9797 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); | 9804 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); |
| 9798 | 9805 | ||
| 9799 | var ty_buf: Type.Payload.Pointer = undefined; | 9806 | if (llvmField(struct_ty, field_index, mod)) |llvm_field| { |
| 9800 | if (llvmFieldIndex(struct_ty, field_index, mod, &ty_buf)) |llvm_field_index| { | 9807 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, ""); |
| 9801 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field_index, ""); | ||
| 9802 | } else { | 9808 | } else { |
| 9803 | // If we found no index then this means this is a zero sized field at the | 9809 | // If we found no index then this means this is a zero sized field at the |
| 9804 | // end of the struct. Treat our struct pointer as an array of two and get | 9810 | // end of the struct. Treat our struct pointer as an array of two and get |
| ... | @@ -10457,59 +10463,61 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ | ... | @@ -10457,59 +10463,61 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ |
| 10457 | }; | 10463 | }; |
| 10458 | } | 10464 | } |
| 10459 | 10465 | ||
| 10466 | const LlvmField = struct { | ||
| 10467 | index: c_uint, | ||
| 10468 | ty: Type, | ||
| 10469 | alignment: u32, | ||
| 10470 | }; | ||
| 10471 | |||
| 10460 | /// Take into account 0 bit fields and padding. Returns null if an llvm | 10472 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 10461 | /// field could not be found. | 10473 | /// field could not be found. |
| 10462 | /// This only happens if you want the field index of a zero sized field at | 10474 | /// This only happens if you want the field index of a zero sized field at |
| 10463 | /// the end of the struct. | 10475 | /// the end of the struct. |
| 10464 | fn llvmFieldIndex( | 10476 | fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField { |
| 10465 | ty: Type, | ||
| 10466 | field_index: usize, | ||
| 10467 | mod: *Module, | ||
| 10468 | ptr_pl_buf: *Type.Payload.Pointer, | ||
| 10469 | ) ?c_uint { | ||
| 10470 | // Detects where we inserted extra padding fields so that we can skip | 10477 | // Detects where we inserted extra padding fields so that we can skip |
| 10471 | // over them in this function. | 10478 | // over them in this function. |
| 10472 | comptime assert(struct_layout_version == 2); | 10479 | comptime assert(struct_layout_version == 2); |
| 10473 | var offset: u64 = 0; | 10480 | var offset: u64 = 0; |
| 10474 | var big_align: u32 = 0; | 10481 | var big_align: u32 = 0; |
| 10475 | 10482 | ||
| 10476 | if (ty.isSimpleTupleOrAnonStruct()) { | 10483 | const struct_type = switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 10477 | const tuple = ty.tupleFields(); | 10484 | .anon_struct_type => |tuple| { |
| 10478 | var llvm_field_index: c_uint = 0; | 10485 | var llvm_field_index: c_uint = 0; |
| 10479 | for (tuple.types, 0..) |field_ty, i| { | 10486 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 10480 | if (tuple.values[i].ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | 10487 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 10481 | 10488 | ||
| 10482 | const field_align = field_ty.abiAlignment(mod); | 10489 | const field_align = field_ty.toType().abiAlignment(mod); |
| 10483 | big_align = @max(big_align, field_align); | 10490 | big_align = @max(big_align, field_align); |
| 10484 | const prev_offset = offset; | 10491 | const prev_offset = offset; |
| 10485 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 10492 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 10486 | 10493 | ||
| 10487 | const padding_len = offset - prev_offset; | 10494 | const padding_len = offset - prev_offset; |
| 10488 | if (padding_len > 0) { | 10495 | if (padding_len > 0) { |
| 10489 | llvm_field_index += 1; | 10496 | llvm_field_index += 1; |
| 10490 | } | 10497 | } |
| 10491 | 10498 | ||
| 10492 | if (field_index <= i) { | 10499 | if (field_index <= i) { |
| 10493 | ptr_pl_buf.* = .{ | 10500 | return .{ |
| 10494 | .data = .{ | 10501 | .index = llvm_field_index, |
| 10495 | .pointee_type = field_ty, | 10502 | .ty = field_ty.toType(), |
| 10496 | .@"align" = field_align, | 10503 | .alignment = field_align, |
| 10497 | .@"addrspace" = .generic, | 10504 | }; |
| 10498 | }, | 10505 | } |
| 10499 | }; | ||
| 10500 | return llvm_field_index; | ||
| 10501 | } | ||
| 10502 | 10506 | ||
| 10503 | llvm_field_index += 1; | 10507 | llvm_field_index += 1; |
| 10504 | offset += field_ty.abiSize(mod); | 10508 | offset += field_ty.toType().abiSize(mod); |
| 10505 | } | 10509 | } |
| 10506 | return null; | 10510 | return null; |
| 10507 | } | 10511 | }, |
| 10508 | const layout = ty.containerLayout(mod); | 10512 | .struct_type => |s| s, |
| 10513 | else => unreachable, | ||
| 10514 | }; | ||
| 10515 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 10516 | const layout = struct_obj.layout; | ||
| 10509 | assert(layout != .Packed); | 10517 | assert(layout != .Packed); |
| 10510 | 10518 | ||
| 10511 | var llvm_field_index: c_uint = 0; | 10519 | var llvm_field_index: c_uint = 0; |
| 10512 | var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod); | 10520 | var it = struct_obj.runtimeFieldIterator(mod); |
| 10513 | while (it.next()) |field_and_index| { | 10521 | while (it.next()) |field_and_index| { |
| 10514 | const field = field_and_index.field; | 10522 | const field = field_and_index.field; |
| 10515 | const field_align = field.alignment(mod, layout); | 10523 | const field_align = field.alignment(mod, layout); |
| ... | @@ -10523,14 +10531,11 @@ fn llvmFieldIndex( | ... | @@ -10523,14 +10531,11 @@ fn llvmFieldIndex( |
| 10523 | } | 10531 | } |
| 10524 | 10532 | ||
| 10525 | if (field_index == field_and_index.index) { | 10533 | if (field_index == field_and_index.index) { |
| 10526 | ptr_pl_buf.* = .{ | 10534 | return .{ |
| 10527 | .data = .{ | 10535 | .index = llvm_field_index, |
| 10528 | .pointee_type = field.ty, | 10536 | .ty = field.ty, |
| 10529 | .@"align" = field_align, | 10537 | .alignment = field_align, |
| 10530 | .@"addrspace" = .generic, | ||
| 10531 | }, | ||
| 10532 | }; | 10538 | }; |
| 10533 | return llvm_field_index; | ||
| 10534 | } | 10539 | } |
| 10535 | 10540 | ||
| 10536 | llvm_field_index += 1; | 10541 | llvm_field_index += 1; |
| ... | @@ -11089,21 +11094,24 @@ fn isByRef(ty: Type, mod: *Module) bool { | ... | @@ -11089,21 +11094,24 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11089 | .Struct => { | 11094 | .Struct => { |
| 11090 | // Packed structs are represented to LLVM as integers. | 11095 | // Packed structs are represented to LLVM as integers. |
| 11091 | if (ty.containerLayout(mod) == .Packed) return false; | 11096 | if (ty.containerLayout(mod) == .Packed) return false; |
| 11092 | if (ty.isSimpleTupleOrAnonStruct()) { | 11097 | const struct_type = switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 11093 | const tuple = ty.tupleFields(); | 11098 | .anon_struct_type => |tuple| { |
| 11094 | var count: usize = 0; | 11099 | var count: usize = 0; |
| 11095 | for (tuple.values, 0..) |field_val, i| { | 11100 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 11096 | if (field_val.ip_index != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue; | 11101 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 11097 | 11102 | ||
| 11098 | count += 1; | 11103 | count += 1; |
| 11099 | if (count > max_fields_byval) return true; | 11104 | if (count > max_fields_byval) return true; |
| 11100 | if (isByRef(tuple.types[i], mod)) return true; | 11105 | if (isByRef(field_ty.toType(), mod)) return true; |
| 11101 | } | 11106 | } |
| 11102 | return false; | 11107 | return false; |
| 11103 | } | 11108 | }, |
| 11109 | .struct_type => |s| s, | ||
| 11110 | else => unreachable, | ||
| 11111 | }; | ||
| 11112 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 11104 | var count: usize = 0; | 11113 | var count: usize = 0; |
| 11105 | const fields = ty.structFields(mod); | 11114 | for (struct_obj.fields.values()) |field| { |
| 11106 | for (fields.values()) |field| { | ||
| 11107 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | 11115 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 11108 | 11116 | ||
| 11109 | count += 1; | 11117 | count += 1; |
src/codegen/spirv.zig+6-5| ... | @@ -682,7 +682,7 @@ pub const DeclGen = struct { | ... | @@ -682,7 +682,7 @@ pub const DeclGen = struct { |
| 682 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | 682 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), |
| 683 | }, | 683 | }, |
| 684 | .Struct => { | 684 | .Struct => { |
| 685 | if (ty.isSimpleTupleOrAnonStruct()) { | 685 | if (ty.isSimpleTupleOrAnonStruct(mod)) { |
| 686 | unreachable; // TODO | 686 | unreachable; // TODO |
| 687 | } else { | 687 | } else { |
| 688 | const struct_ty = mod.typeToStruct(ty).?; | 688 | const struct_ty = mod.typeToStruct(ty).?; |
| ... | @@ -1319,7 +1319,8 @@ pub const DeclGen = struct { | ... | @@ -1319,7 +1319,8 @@ pub const DeclGen = struct { |
| 1319 | defer self.gpa.free(member_names); | 1319 | defer self.gpa.free(member_names); |
| 1320 | 1320 | ||
| 1321 | var member_index: usize = 0; | 1321 | var member_index: usize = 0; |
| 1322 | for (struct_ty.fields.values(), 0..) |field, i| { | 1322 | const struct_obj = void; // TODO |
| 1323 | for (struct_obj.fields.values(), 0..) |field, i| { | ||
| 1323 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | 1324 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 1324 | 1325 | ||
| 1325 | member_types[member_index] = try self.resolveType(field.ty, .indirect); | 1326 | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| ... | @@ -1327,7 +1328,7 @@ pub const DeclGen = struct { | ... | @@ -1327,7 +1328,7 @@ pub const DeclGen = struct { |
| 1327 | member_index += 1; | 1328 | member_index += 1; |
| 1328 | } | 1329 | } |
| 1329 | 1330 | ||
| 1330 | const name = try struct_ty.getFullyQualifiedName(self.module); | 1331 | const name = try struct_obj.getFullyQualifiedName(self.module); |
| 1331 | defer self.module.gpa.free(name); | 1332 | defer self.module.gpa.free(name); |
| 1332 | 1333 | ||
| 1333 | return try self.spv.resolve(.{ .struct_type = .{ | 1334 | return try self.spv.resolve(.{ .struct_type = .{ |
| ... | @@ -2090,7 +2091,7 @@ pub const DeclGen = struct { | ... | @@ -2090,7 +2091,7 @@ pub const DeclGen = struct { |
| 2090 | 2091 | ||
| 2091 | var i: usize = 0; | 2092 | var i: usize = 0; |
| 2092 | while (i < mask_len) : (i += 1) { | 2093 | while (i < mask_len) : (i += 1) { |
| 2093 | const elem = try mask.elemValue(self.module, i); | 2094 | const elem = try mask.elemValue(mod, i); |
| 2094 | if (elem.isUndef(mod)) { | 2095 | if (elem.isUndef(mod)) { |
| 2095 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); | 2096 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); |
| 2096 | } else { | 2097 | } else { |
| ... | @@ -2805,7 +2806,7 @@ pub const DeclGen = struct { | ... | @@ -2805,7 +2806,7 @@ pub const DeclGen = struct { |
| 2805 | const value = try self.resolve(bin_op.rhs); | 2806 | const value = try self.resolve(bin_op.rhs); |
| 2806 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); | 2807 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2807 | 2808 | ||
| 2808 | const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep() else false; | 2809 | const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; |
| 2809 | if (val_is_undef) { | 2810 | if (val_is_undef) { |
| 2810 | const undef = try self.spv.constUndef(ptr_ty_ref); | 2811 | const undef = try self.spv.constUndef(ptr_ty_ref); |
| 2811 | try self.store(ptr_ty, ptr, undef); | 2812 | try self.store(ptr_ty, ptr, undef); |
src/link/Dwarf.zig+12-10| ... | @@ -333,13 +333,12 @@ pub const DeclState = struct { | ... | @@ -333,13 +333,12 @@ pub const DeclState = struct { |
| 333 | // DW.AT.byte_size, DW.FORM.udata | 333 | // DW.AT.byte_size, DW.FORM.udata |
| 334 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); | 334 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 335 | 335 | ||
| 336 | switch (ty.tag()) { | 336 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 337 | .tuple, .anon_struct => { | 337 | .anon_struct_type => |fields| { |
| 338 | // DW.AT.name, DW.FORM.string | 338 | // DW.AT.name, DW.FORM.string |
| 339 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); | 339 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 340 | 340 | ||
| 341 | const fields = ty.tupleFields(); | 341 | for (fields.types, 0..) |field_ty, field_index| { |
| 342 | for (fields.types, 0..) |field, field_index| { | ||
| 343 | // DW.AT.member | 342 | // DW.AT.member |
| 344 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); | 343 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 345 | // DW.AT.name, DW.FORM.string | 344 | // DW.AT.name, DW.FORM.string |
| ... | @@ -347,28 +346,30 @@ pub const DeclState = struct { | ... | @@ -347,28 +346,30 @@ pub const DeclState = struct { |
| 347 | // DW.AT.type, DW.FORM.ref4 | 346 | // DW.AT.type, DW.FORM.ref4 |
| 348 | var index = dbg_info_buffer.items.len; | 347 | var index = dbg_info_buffer.items.len; |
| 349 | try dbg_info_buffer.resize(index + 4); | 348 | try dbg_info_buffer.resize(index + 4); |
| 350 | try self.addTypeRelocGlobal(atom_index, field, @intCast(u32, index)); | 349 | try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(u32, index)); |
| 351 | // DW.AT.data_member_location, DW.FORM.udata | 350 | // DW.AT.data_member_location, DW.FORM.udata |
| 352 | const field_off = ty.structFieldOffset(field_index, mod); | 351 | const field_off = ty.structFieldOffset(field_index, mod); |
| 353 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 352 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 354 | } | 353 | } |
| 355 | }, | 354 | }, |
| 356 | else => { | 355 | .struct_type => |struct_type| s: { |
| 356 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | ||
| 357 | // DW.AT.name, DW.FORM.string | 357 | // DW.AT.name, DW.FORM.string |
| 358 | const struct_name = try ty.nameAllocArena(arena, mod); | 358 | const struct_name = try ty.nameAllocArena(arena, mod); |
| 359 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); | 359 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); |
| 360 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); | 360 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); |
| 361 | dbg_info_buffer.appendAssumeCapacity(0); | 361 | dbg_info_buffer.appendAssumeCapacity(0); |
| 362 | 362 | ||
| 363 | const struct_obj = mod.typeToStruct(ty).?; | ||
| 364 | if (struct_obj.layout == .Packed) { | 363 | if (struct_obj.layout == .Packed) { |
| 365 | log.debug("TODO implement .debug_info for packed structs", .{}); | 364 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 366 | break :blk; | 365 | break :blk; |
| 367 | } | 366 | } |
| 368 | 367 | ||
| 369 | const fields = ty.structFields(mod); | 368 | for ( |
| 370 | for (fields.keys(), 0..) |field_name, field_index| { | 369 | struct_obj.fields.keys(), |
| 371 | const field = fields.get(field_name).?; | 370 | struct_obj.fields.values(), |
| 371 | 0.., | ||
| 372 | ) |field_name, field, field_index| { | ||
| 372 | if (!field.ty.hasRuntimeBits(mod)) continue; | 373 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 373 | // DW.AT.member | 374 | // DW.AT.member |
| 374 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | 375 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| ... | @@ -385,6 +386,7 @@ pub const DeclState = struct { | ... | @@ -385,6 +386,7 @@ pub const DeclState = struct { |
| 385 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 386 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 386 | } | 387 | } |
| 387 | }, | 388 | }, |
| 389 | else => unreachable, | ||
| 388 | } | 390 | } |
| 389 | 391 | ||
| 390 | // DW.AT.structure_type delimit children | 392 | // DW.AT.structure_type delimit children |
src/type.zig+238-568| ... | @@ -54,10 +54,6 @@ pub const Type = struct { | ... | @@ -54,10 +54,6 @@ pub const Type = struct { |
| 54 | .error_union => return .ErrorUnion, | 54 | .error_union => return .ErrorUnion, |
| 55 | 55 | ||
| 56 | .anyframe_T => return .AnyFrame, | 56 | .anyframe_T => return .AnyFrame, |
| 57 | |||
| 58 | .tuple, | ||
| 59 | .anon_struct, | ||
| 60 | => return .Struct, | ||
| 61 | }, | 57 | }, |
| 62 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 58 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 63 | .int_type => return .Int, | 59 | .int_type => return .Int, |
| ... | @@ -66,7 +62,7 @@ pub const Type = struct { | ... | @@ -66,7 +62,7 @@ pub const Type = struct { |
| 66 | .vector_type => return .Vector, | 62 | .vector_type => return .Vector, |
| 67 | .opt_type => return .Optional, | 63 | .opt_type => return .Optional, |
| 68 | .error_union_type => return .ErrorUnion, | 64 | .error_union_type => return .ErrorUnion, |
| 69 | .struct_type => return .Struct, | 65 | .struct_type, .anon_struct_type => return .Struct, |
| 70 | .union_type => return .Union, | 66 | .union_type => return .Union, |
| 71 | .opaque_type => return .Opaque, | 67 | .opaque_type => return .Opaque, |
| 72 | .enum_type => return .Enum, | 68 | .enum_type => return .Enum, |
| ... | @@ -465,76 +461,6 @@ pub const Type = struct { | ... | @@ -465,76 +461,6 @@ pub const Type = struct { |
| 465 | if (b.zigTypeTag(mod) != .AnyFrame) return false; | 461 | if (b.zigTypeTag(mod) != .AnyFrame) return false; |
| 466 | return a.elemType2(mod).eql(b.elemType2(mod), mod); | 462 | return a.elemType2(mod).eql(b.elemType2(mod), mod); |
| 467 | }, | 463 | }, |
| 468 | |||
| 469 | .tuple => { | ||
| 470 | if (!b.isSimpleTuple()) return false; | ||
| 471 | |||
| 472 | const a_tuple = a.tupleFields(); | ||
| 473 | const b_tuple = b.tupleFields(); | ||
| 474 | |||
| 475 | if (a_tuple.types.len != b_tuple.types.len) return false; | ||
| 476 | |||
| 477 | for (a_tuple.types, 0..) |a_ty, i| { | ||
| 478 | const b_ty = b_tuple.types[i]; | ||
| 479 | if (!eql(a_ty, b_ty, mod)) return false; | ||
| 480 | } | ||
| 481 | |||
| 482 | for (a_tuple.values, 0..) |a_val, i| { | ||
| 483 | const ty = a_tuple.types[i]; | ||
| 484 | const b_val = b_tuple.values[i]; | ||
| 485 | if (a_val.ip_index == .unreachable_value) { | ||
| 486 | if (b_val.ip_index == .unreachable_value) { | ||
| 487 | continue; | ||
| 488 | } else { | ||
| 489 | return false; | ||
| 490 | } | ||
| 491 | } else { | ||
| 492 | if (b_val.ip_index == .unreachable_value) { | ||
| 493 | return false; | ||
| 494 | } else { | ||
| 495 | if (!Value.eql(a_val, b_val, ty, mod)) return false; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | return true; | ||
| 501 | }, | ||
| 502 | .anon_struct => { | ||
| 503 | const a_struct_obj = a.castTag(.anon_struct).?.data; | ||
| 504 | const b_struct_obj = (b.castTag(.anon_struct) orelse return false).data; | ||
| 505 | |||
| 506 | if (a_struct_obj.types.len != b_struct_obj.types.len) return false; | ||
| 507 | |||
| 508 | for (a_struct_obj.names, 0..) |a_name, i| { | ||
| 509 | const b_name = b_struct_obj.names[i]; | ||
| 510 | if (!std.mem.eql(u8, a_name, b_name)) return false; | ||
| 511 | } | ||
| 512 | |||
| 513 | for (a_struct_obj.types, 0..) |a_ty, i| { | ||
| 514 | const b_ty = b_struct_obj.types[i]; | ||
| 515 | if (!eql(a_ty, b_ty, mod)) return false; | ||
| 516 | } | ||
| 517 | |||
| 518 | for (a_struct_obj.values, 0..) |a_val, i| { | ||
| 519 | const ty = a_struct_obj.types[i]; | ||
| 520 | const b_val = b_struct_obj.values[i]; | ||
| 521 | if (a_val.ip_index == .unreachable_value) { | ||
| 522 | if (b_val.ip_index == .unreachable_value) { | ||
| 523 | continue; | ||
| 524 | } else { | ||
| 525 | return false; | ||
| 526 | } | ||
| 527 | } else { | ||
| 528 | if (b_val.ip_index == .unreachable_value) { | ||
| 529 | return false; | ||
| 530 | } else { | ||
| 531 | if (!Value.eql(a_val, b_val, ty, mod)) return false; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | return true; | ||
| 537 | }, | ||
| 538 | } | 464 | } |
| 539 | } | 465 | } |
| 540 | 466 | ||
| ... | @@ -641,34 +567,6 @@ pub const Type = struct { | ... | @@ -641,34 +567,6 @@ pub const Type = struct { |
| 641 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); | 567 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); |
| 642 | hashWithHasher(ty.childType(mod), hasher, mod); | 568 | hashWithHasher(ty.childType(mod), hasher, mod); |
| 643 | }, | 569 | }, |
| 644 | |||
| 645 | .tuple => { | ||
| 646 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 647 | |||
| 648 | const tuple = ty.tupleFields(); | ||
| 649 | std.hash.autoHash(hasher, tuple.types.len); | ||
| 650 | |||
| 651 | for (tuple.types, 0..) |field_ty, i| { | ||
| 652 | hashWithHasher(field_ty, hasher, mod); | ||
| 653 | const field_val = tuple.values[i]; | ||
| 654 | if (field_val.ip_index == .unreachable_value) continue; | ||
| 655 | field_val.hash(field_ty, hasher, mod); | ||
| 656 | } | ||
| 657 | }, | ||
| 658 | .anon_struct => { | ||
| 659 | const struct_obj = ty.castTag(.anon_struct).?.data; | ||
| 660 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 661 | std.hash.autoHash(hasher, struct_obj.types.len); | ||
| 662 | |||
| 663 | for (struct_obj.types, 0..) |field_ty, i| { | ||
| 664 | const field_name = struct_obj.names[i]; | ||
| 665 | const field_val = struct_obj.values[i]; | ||
| 666 | hasher.update(field_name); | ||
| 667 | hashWithHasher(field_ty, hasher, mod); | ||
| 668 | if (field_val.ip_index == .unreachable_value) continue; | ||
| 669 | field_val.hash(field_ty, hasher, mod); | ||
| 670 | } | ||
| 671 | }, | ||
| 672 | } | 570 | } |
| 673 | } | 571 | } |
| 674 | 572 | ||
| ... | @@ -733,41 +631,6 @@ pub const Type = struct { | ... | @@ -733,41 +631,6 @@ pub const Type = struct { |
| 733 | }; | 631 | }; |
| 734 | }, | 632 | }, |
| 735 | 633 | ||
| 736 | .tuple => { | ||
| 737 | const payload = self.castTag(.tuple).?.data; | ||
| 738 | const types = try allocator.alloc(Type, payload.types.len); | ||
| 739 | const values = try allocator.alloc(Value, payload.values.len); | ||
| 740 | for (payload.types, 0..) |ty, i| { | ||
| 741 | types[i] = try ty.copy(allocator); | ||
| 742 | } | ||
| 743 | for (payload.values, 0..) |val, i| { | ||
| 744 | values[i] = try val.copy(allocator); | ||
| 745 | } | ||
| 746 | return Tag.tuple.create(allocator, .{ | ||
| 747 | .types = types, | ||
| 748 | .values = values, | ||
| 749 | }); | ||
| 750 | }, | ||
| 751 | .anon_struct => { | ||
| 752 | const payload = self.castTag(.anon_struct).?.data; | ||
| 753 | const names = try allocator.alloc([]const u8, payload.names.len); | ||
| 754 | const types = try allocator.alloc(Type, payload.types.len); | ||
| 755 | const values = try allocator.alloc(Value, payload.values.len); | ||
| 756 | for (payload.names, 0..) |name, i| { | ||
| 757 | names[i] = try allocator.dupe(u8, name); | ||
| 758 | } | ||
| 759 | for (payload.types, 0..) |ty, i| { | ||
| 760 | types[i] = try ty.copy(allocator); | ||
| 761 | } | ||
| 762 | for (payload.values, 0..) |val, i| { | ||
| 763 | values[i] = try val.copy(allocator); | ||
| 764 | } | ||
| 765 | return Tag.anon_struct.create(allocator, .{ | ||
| 766 | .names = names, | ||
| 767 | .types = types, | ||
| 768 | .values = values, | ||
| 769 | }); | ||
| 770 | }, | ||
| 771 | .function => { | 634 | .function => { |
| 772 | const payload = self.castTag(.function).?.data; | 635 | const payload = self.castTag(.function).?.data; |
| 773 | const param_types = try allocator.alloc(Type, payload.param_types.len); | 636 | const param_types = try allocator.alloc(Type, payload.param_types.len); |
| ... | @@ -935,42 +798,6 @@ pub const Type = struct { | ... | @@ -935,42 +798,6 @@ pub const Type = struct { |
| 935 | ty = return_type; | 798 | ty = return_type; |
| 936 | continue; | 799 | continue; |
| 937 | }, | 800 | }, |
| 938 | .tuple => { | ||
| 939 | const tuple = ty.castTag(.tuple).?.data; | ||
| 940 | try writer.writeAll("tuple{"); | ||
| 941 | for (tuple.types, 0..) |field_ty, i| { | ||
| 942 | if (i != 0) try writer.writeAll(", "); | ||
| 943 | const val = tuple.values[i]; | ||
| 944 | if (val.ip_index != .unreachable_value) { | ||
| 945 | try writer.writeAll("comptime "); | ||
| 946 | } | ||
| 947 | try field_ty.dump("", .{}, writer); | ||
| 948 | if (val.ip_index != .unreachable_value) { | ||
| 949 | try writer.print(" = {}", .{val.fmtDebug()}); | ||
| 950 | } | ||
| 951 | } | ||
| 952 | try writer.writeAll("}"); | ||
| 953 | return; | ||
| 954 | }, | ||
| 955 | .anon_struct => { | ||
| 956 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 957 | try writer.writeAll("struct{"); | ||
| 958 | for (anon_struct.types, 0..) |field_ty, i| { | ||
| 959 | if (i != 0) try writer.writeAll(", "); | ||
| 960 | const val = anon_struct.values[i]; | ||
| 961 | if (val.ip_index != .unreachable_value) { | ||
| 962 | try writer.writeAll("comptime "); | ||
| 963 | } | ||
| 964 | try writer.writeAll(anon_struct.names[i]); | ||
| 965 | try writer.writeAll(": "); | ||
| 966 | try field_ty.dump("", .{}, writer); | ||
| 967 | if (val.ip_index != .unreachable_value) { | ||
| 968 | try writer.print(" = {}", .{val.fmtDebug()}); | ||
| 969 | } | ||
| 970 | } | ||
| 971 | try writer.writeAll("}"); | ||
| 972 | return; | ||
| 973 | }, | ||
| 974 | .optional => { | 801 | .optional => { |
| 975 | const child_type = ty.castTag(.optional).?.data; | 802 | const child_type = ty.castTag(.optional).?.data; |
| 976 | try writer.writeByte('?'); | 803 | try writer.writeByte('?'); |
| ... | @@ -1131,45 +958,6 @@ pub const Type = struct { | ... | @@ -1131,45 +958,6 @@ pub const Type = struct { |
| 1131 | try print(error_union.payload, writer, mod); | 958 | try print(error_union.payload, writer, mod); |
| 1132 | }, | 959 | }, |
| 1133 | 960 | ||
| 1134 | .tuple => { | ||
| 1135 | const tuple = ty.castTag(.tuple).?.data; | ||
| 1136 | |||
| 1137 | try writer.writeAll("tuple{"); | ||
| 1138 | for (tuple.types, 0..) |field_ty, i| { | ||
| 1139 | if (i != 0) try writer.writeAll(", "); | ||
| 1140 | const val = tuple.values[i]; | ||
| 1141 | if (val.ip_index != .unreachable_value) { | ||
| 1142 | try writer.writeAll("comptime "); | ||
| 1143 | } | ||
| 1144 | try print(field_ty, writer, mod); | ||
| 1145 | if (val.ip_index != .unreachable_value) { | ||
| 1146 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); | ||
| 1147 | } | ||
| 1148 | } | ||
| 1149 | try writer.writeAll("}"); | ||
| 1150 | }, | ||
| 1151 | .anon_struct => { | ||
| 1152 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 1153 | |||
| 1154 | try writer.writeAll("struct{"); | ||
| 1155 | for (anon_struct.types, 0..) |field_ty, i| { | ||
| 1156 | if (i != 0) try writer.writeAll(", "); | ||
| 1157 | const val = anon_struct.values[i]; | ||
| 1158 | if (val.ip_index != .unreachable_value) { | ||
| 1159 | try writer.writeAll("comptime "); | ||
| 1160 | } | ||
| 1161 | try writer.writeAll(anon_struct.names[i]); | ||
| 1162 | try writer.writeAll(": "); | ||
| 1163 | |||
| 1164 | try print(field_ty, writer, mod); | ||
| 1165 | |||
| 1166 | if (val.ip_index != .unreachable_value) { | ||
| 1167 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); | ||
| 1168 | } | ||
| 1169 | } | ||
| 1170 | try writer.writeAll("}"); | ||
| 1171 | }, | ||
| 1172 | |||
| 1173 | .pointer => { | 961 | .pointer => { |
| 1174 | const info = ty.ptrInfo(mod); | 962 | const info = ty.ptrInfo(mod); |
| 1175 | 963 | ||
| ... | @@ -1335,6 +1123,27 @@ pub const Type = struct { | ... | @@ -1335,6 +1123,27 @@ pub const Type = struct { |
| 1335 | try writer.writeAll("@TypeOf(.{})"); | 1123 | try writer.writeAll("@TypeOf(.{})"); |
| 1336 | } | 1124 | } |
| 1337 | }, | 1125 | }, |
| 1126 | .anon_struct_type => |anon_struct| { | ||
| 1127 | try writer.writeAll("struct{"); | ||
| 1128 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, val, i| { | ||
| 1129 | if (i != 0) try writer.writeAll(", "); | ||
| 1130 | if (val != .none) { | ||
| 1131 | try writer.writeAll("comptime "); | ||
| 1132 | } | ||
| 1133 | if (anon_struct.names.len != 0) { | ||
| 1134 | const name = mod.intern_pool.stringToSlice(anon_struct.names[i]); | ||
| 1135 | try writer.writeAll(name); | ||
| 1136 | try writer.writeAll(": "); | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | try print(field_ty.toType(), writer, mod); | ||
| 1140 | |||
| 1141 | if (val != .none) { | ||
| 1142 | try writer.print(" = {}", .{val.toValue().fmtValue(field_ty.toType(), mod)}); | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | try writer.writeAll("}"); | ||
| 1146 | }, | ||
| 1338 | 1147 | ||
| 1339 | .union_type => |union_type| { | 1148 | .union_type => |union_type| { |
| 1340 | const union_obj = mod.unionPtr(union_type.index); | 1149 | const union_obj = mod.unionPtr(union_type.index); |
| ... | @@ -1443,16 +1252,6 @@ pub const Type = struct { | ... | @@ -1443,16 +1252,6 @@ pub const Type = struct { |
| 1443 | } | 1252 | } |
| 1444 | }, | 1253 | }, |
| 1445 | 1254 | ||
| 1446 | .tuple, .anon_struct => { | ||
| 1447 | const tuple = ty.tupleFields(); | ||
| 1448 | for (tuple.types, 0..) |field_ty, i| { | ||
| 1449 | const val = tuple.values[i]; | ||
| 1450 | if (val.ip_index != .unreachable_value) continue; // comptime field | ||
| 1451 | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; | ||
| 1452 | } | ||
| 1453 | return false; | ||
| 1454 | }, | ||
| 1455 | |||
| 1456 | .inferred_alloc_const => unreachable, | 1255 | .inferred_alloc_const => unreachable, |
| 1457 | .inferred_alloc_mut => unreachable, | 1256 | .inferred_alloc_mut => unreachable, |
| 1458 | }, | 1257 | }, |
| ... | @@ -1567,6 +1366,13 @@ pub const Type = struct { | ... | @@ -1567,6 +1366,13 @@ pub const Type = struct { |
| 1567 | return false; | 1366 | return false; |
| 1568 | } | 1367 | } |
| 1569 | }, | 1368 | }, |
| 1369 | .anon_struct_type => |tuple| { | ||
| 1370 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 1371 | if (val != .none) continue; // comptime field | ||
| 1372 | if (try field_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; | ||
| 1373 | } | ||
| 1374 | return false; | ||
| 1375 | }, | ||
| 1570 | 1376 | ||
| 1571 | .union_type => |union_type| { | 1377 | .union_type => |union_type| { |
| 1572 | const union_obj = mod.unionPtr(union_type.index); | 1378 | const union_obj = mod.unionPtr(union_type.index); |
| ... | @@ -1634,8 +1440,6 @@ pub const Type = struct { | ... | @@ -1634,8 +1440,6 @@ pub const Type = struct { |
| 1634 | .function, | 1440 | .function, |
| 1635 | .error_union, | 1441 | .error_union, |
| 1636 | .anyframe_T, | 1442 | .anyframe_T, |
| 1637 | .tuple, | ||
| 1638 | .anon_struct, | ||
| 1639 | => false, | 1443 | => false, |
| 1640 | 1444 | ||
| 1641 | .inferred_alloc_mut => unreachable, | 1445 | .inferred_alloc_mut => unreachable, |
| ... | @@ -1705,6 +1509,7 @@ pub const Type = struct { | ... | @@ -1705,6 +1509,7 @@ pub const Type = struct { |
| 1705 | }; | 1509 | }; |
| 1706 | return struct_obj.layout != .Auto; | 1510 | return struct_obj.layout != .Auto; |
| 1707 | }, | 1511 | }, |
| 1512 | .anon_struct_type => false, | ||
| 1708 | .union_type => |union_type| switch (union_type.runtime_tag) { | 1513 | .union_type => |union_type| switch (union_type.runtime_tag) { |
| 1709 | .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, | 1514 | .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, |
| 1710 | .tagged => false, | 1515 | .tagged => false, |
| ... | @@ -1923,26 +1728,6 @@ pub const Type = struct { | ... | @@ -1923,26 +1728,6 @@ pub const Type = struct { |
| 1923 | .optional => return abiAlignmentAdvancedOptional(ty, mod, strat), | 1728 | .optional => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 1924 | .error_union => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), | 1729 | .error_union => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), |
| 1925 | 1730 | ||
| 1926 | .tuple, .anon_struct => { | ||
| 1927 | const tuple = ty.tupleFields(); | ||
| 1928 | var big_align: u32 = 0; | ||
| 1929 | for (tuple.types, 0..) |field_ty, i| { | ||
| 1930 | const val = tuple.values[i]; | ||
| 1931 | if (val.ip_index != .unreachable_value) continue; // comptime field | ||
| 1932 | if (!(field_ty.hasRuntimeBits(mod))) continue; | ||
| 1933 | |||
| 1934 | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | ||
| 1935 | .scalar => |field_align| big_align = @max(big_align, field_align), | ||
| 1936 | .val => switch (strat) { | ||
| 1937 | .eager => unreachable, // field type alignment not resolved | ||
| 1938 | .sema => unreachable, // passed to abiAlignmentAdvanced above | ||
| 1939 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 1940 | }, | ||
| 1941 | } | ||
| 1942 | } | ||
| 1943 | return AbiAlignmentAdvanced{ .scalar = big_align }; | ||
| 1944 | }, | ||
| 1945 | |||
| 1946 | .inferred_alloc_const, | 1731 | .inferred_alloc_const, |
| 1947 | .inferred_alloc_mut, | 1732 | .inferred_alloc_mut, |
| 1948 | => unreachable, | 1733 | => unreachable, |
| ... | @@ -2100,6 +1885,24 @@ pub const Type = struct { | ... | @@ -2100,6 +1885,24 @@ pub const Type = struct { |
| 2100 | } | 1885 | } |
| 2101 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 1886 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 2102 | }, | 1887 | }, |
| 1888 | .anon_struct_type => |tuple| { | ||
| 1889 | var big_align: u32 = 0; | ||
| 1890 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 1891 | if (val != .none) continue; // comptime field | ||
| 1892 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; | ||
| 1893 | |||
| 1894 | switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) { | ||
| 1895 | .scalar => |field_align| big_align = @max(big_align, field_align), | ||
| 1896 | .val => switch (strat) { | ||
| 1897 | .eager => unreachable, // field type alignment not resolved | ||
| 1898 | .sema => unreachable, // passed to abiAlignmentAdvanced above | ||
| 1899 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 1900 | }, | ||
| 1901 | } | ||
| 1902 | } | ||
| 1903 | return AbiAlignmentAdvanced{ .scalar = big_align }; | ||
| 1904 | }, | ||
| 1905 | |||
| 2103 | .union_type => |union_type| { | 1906 | .union_type => |union_type| { |
| 2104 | const union_obj = mod.unionPtr(union_type.index); | 1907 | const union_obj = mod.unionPtr(union_type.index); |
| 2105 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); | 1908 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| ... | @@ -2287,18 +2090,6 @@ pub const Type = struct { | ... | @@ -2287,18 +2090,6 @@ pub const Type = struct { |
| 2287 | .inferred_alloc_const => unreachable, | 2090 | .inferred_alloc_const => unreachable, |
| 2288 | .inferred_alloc_mut => unreachable, | 2091 | .inferred_alloc_mut => unreachable, |
| 2289 | 2092 | ||
| 2290 | .tuple, .anon_struct => { | ||
| 2291 | switch (strat) { | ||
| 2292 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 2293 | .lazy, .eager => {}, | ||
| 2294 | } | ||
| 2295 | const field_count = ty.structFieldCount(mod); | ||
| 2296 | if (field_count == 0) { | ||
| 2297 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 2298 | } | ||
| 2299 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | ||
| 2300 | }, | ||
| 2301 | |||
| 2302 | .anyframe_T => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | 2093 | .anyframe_T => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2303 | 2094 | ||
| 2304 | .pointer => switch (ty.castTag(.pointer).?.data.size) { | 2095 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| ... | @@ -2496,6 +2287,18 @@ pub const Type = struct { | ... | @@ -2496,6 +2287,18 @@ pub const Type = struct { |
| 2496 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | 2287 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; |
| 2497 | }, | 2288 | }, |
| 2498 | }, | 2289 | }, |
| 2290 | .anon_struct_type => |tuple| { | ||
| 2291 | switch (strat) { | ||
| 2292 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 2293 | .lazy, .eager => {}, | ||
| 2294 | } | ||
| 2295 | const field_count = tuple.types.len; | ||
| 2296 | if (field_count == 0) { | ||
| 2297 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 2298 | } | ||
| 2299 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | ||
| 2300 | }, | ||
| 2301 | |||
| 2499 | .union_type => |union_type| { | 2302 | .union_type => |union_type| { |
| 2500 | const union_obj = mod.unionPtr(union_type.index); | 2303 | const union_obj = mod.unionPtr(union_type.index); |
| 2501 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); | 2304 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| ... | @@ -2609,18 +2412,6 @@ pub const Type = struct { | ... | @@ -2609,18 +2412,6 @@ pub const Type = struct { |
| 2609 | .inferred_alloc_const => unreachable, | 2412 | .inferred_alloc_const => unreachable, |
| 2610 | .inferred_alloc_mut => unreachable, | 2413 | .inferred_alloc_mut => unreachable, |
| 2611 | 2414 | ||
| 2612 | .tuple, .anon_struct => { | ||
| 2613 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | ||
| 2614 | if (ty.containerLayout(mod) != .Packed) { | ||
| 2615 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | ||
| 2616 | } | ||
| 2617 | var total: u64 = 0; | ||
| 2618 | for (ty.tupleFields().types) |field_ty| { | ||
| 2619 | total += try bitSizeAdvanced(field_ty, mod, opt_sema); | ||
| 2620 | } | ||
| 2621 | return total; | ||
| 2622 | }, | ||
| 2623 | |||
| 2624 | .anyframe_T => return target.ptrBitWidth(), | 2415 | .anyframe_T => return target.ptrBitWidth(), |
| 2625 | 2416 | ||
| 2626 | .pointer => switch (ty.castTag(.pointer).?.data.size) { | 2417 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| ... | @@ -2724,6 +2515,11 @@ pub const Type = struct { | ... | @@ -2724,6 +2515,11 @@ pub const Type = struct { |
| 2724 | return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); | 2515 | return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); |
| 2725 | }, | 2516 | }, |
| 2726 | 2517 | ||
| 2518 | .anon_struct_type => { | ||
| 2519 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | ||
| 2520 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | ||
| 2521 | }, | ||
| 2522 | |||
| 2727 | .union_type => |union_type| { | 2523 | .union_type => |union_type| { |
| 2728 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | 2524 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 2729 | if (ty.containerLayout(mod) != .Packed) { | 2525 | if (ty.containerLayout(mod) != .Packed) { |
| ... | @@ -3220,23 +3016,17 @@ pub const Type = struct { | ... | @@ -3220,23 +3016,17 @@ pub const Type = struct { |
| 3220 | } | 3016 | } |
| 3221 | 3017 | ||
| 3222 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { | 3018 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { |
| 3223 | return switch (ty.ip_index) { | 3019 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3224 | .empty_struct_type => .Auto, | 3020 | .struct_type => |struct_type| { |
| 3225 | .none => switch (ty.tag()) { | 3021 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; |
| 3226 | .tuple, .anon_struct => .Auto, | 3022 | return struct_obj.layout; |
| 3227 | else => unreachable, | ||
| 3228 | }, | 3023 | }, |
| 3229 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 3024 | .anon_struct_type => .Auto, |
| 3230 | .struct_type => |struct_type| { | 3025 | .union_type => |union_type| { |
| 3231 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | 3026 | const union_obj = mod.unionPtr(union_type.index); |
| 3232 | return struct_obj.layout; | 3027 | return union_obj.layout; |
| 3233 | }, | ||
| 3234 | .union_type => |union_type| { | ||
| 3235 | const union_obj = mod.unionPtr(union_type.index); | ||
| 3236 | return union_obj.layout; | ||
| 3237 | }, | ||
| 3238 | else => unreachable, | ||
| 3239 | }, | 3028 | }, |
| 3029 | else => unreachable, | ||
| 3240 | }; | 3030 | }; |
| 3241 | } | 3031 | } |
| 3242 | 3032 | ||
| ... | @@ -3349,23 +3139,16 @@ pub const Type = struct { | ... | @@ -3349,23 +3139,16 @@ pub const Type = struct { |
| 3349 | } | 3139 | } |
| 3350 | 3140 | ||
| 3351 | pub fn arrayLenIp(ty: Type, ip: InternPool) u64 { | 3141 | pub fn arrayLenIp(ty: Type, ip: InternPool) u64 { |
| 3352 | return switch (ty.ip_index) { | 3142 | return switch (ip.indexToKey(ty.ip_index)) { |
| 3353 | .empty_struct_type => 0, | 3143 | .vector_type => |vector_type| vector_type.len, |
| 3354 | .none => switch (ty.tag()) { | 3144 | .array_type => |array_type| array_type.len, |
| 3355 | .tuple => ty.castTag(.tuple).?.data.types.len, | 3145 | .struct_type => |struct_type| { |
| 3356 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | 3146 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; |
| 3357 | 3147 | return struct_obj.fields.count(); | |
| 3358 | else => unreachable, | ||
| 3359 | }, | ||
| 3360 | else => switch (ip.indexToKey(ty.ip_index)) { | ||
| 3361 | .vector_type => |vector_type| vector_type.len, | ||
| 3362 | .array_type => |array_type| array_type.len, | ||
| 3363 | .struct_type => |struct_type| { | ||
| 3364 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; | ||
| 3365 | return struct_obj.fields.count(); | ||
| 3366 | }, | ||
| 3367 | else => unreachable, | ||
| 3368 | }, | 3148 | }, |
| 3149 | .anon_struct_type => |tuple| tuple.types.len, | ||
| 3150 | |||
| 3151 | else => unreachable, | ||
| 3369 | }; | 3152 | }; |
| 3370 | } | 3153 | } |
| 3371 | 3154 | ||
| ... | @@ -3374,16 +3157,10 @@ pub const Type = struct { | ... | @@ -3374,16 +3157,10 @@ pub const Type = struct { |
| 3374 | } | 3157 | } |
| 3375 | 3158 | ||
| 3376 | pub fn vectorLen(ty: Type, mod: *const Module) u32 { | 3159 | pub fn vectorLen(ty: Type, mod: *const Module) u32 { |
| 3377 | return switch (ty.ip_index) { | 3160 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3378 | .none => switch (ty.tag()) { | 3161 | .vector_type => |vector_type| vector_type.len, |
| 3379 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), | 3162 | .anon_struct_type => |tuple| @intCast(u32, tuple.types.len), |
| 3380 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | 3163 | else => unreachable, |
| 3381 | else => unreachable, | ||
| 3382 | }, | ||
| 3383 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 3384 | .vector_type => |vector_type| vector_type.len, | ||
| 3385 | else => unreachable, | ||
| 3386 | }, | ||
| 3387 | }; | 3164 | }; |
| 3388 | } | 3165 | } |
| 3389 | 3166 | ||
| ... | @@ -3391,8 +3168,6 @@ pub const Type = struct { | ... | @@ -3391,8 +3168,6 @@ pub const Type = struct { |
| 3391 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { | 3168 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { |
| 3392 | return switch (ty.ip_index) { | 3169 | return switch (ty.ip_index) { |
| 3393 | .none => switch (ty.tag()) { | 3170 | .none => switch (ty.tag()) { |
| 3394 | .tuple => null, | ||
| 3395 | |||
| 3396 | .pointer => ty.castTag(.pointer).?.data.sentinel, | 3171 | .pointer => ty.castTag(.pointer).?.data.sentinel, |
| 3397 | 3172 | ||
| 3398 | else => unreachable, | 3173 | else => unreachable, |
| ... | @@ -3400,6 +3175,7 @@ pub const Type = struct { | ... | @@ -3400,6 +3175,7 @@ pub const Type = struct { |
| 3400 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 3175 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3401 | .vector_type, | 3176 | .vector_type, |
| 3402 | .struct_type, | 3177 | .struct_type, |
| 3178 | .anon_struct_type, | ||
| 3403 | => null, | 3179 | => null, |
| 3404 | 3180 | ||
| 3405 | .array_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, | 3181 | .array_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, |
| ... | @@ -3486,10 +3262,12 @@ pub const Type = struct { | ... | @@ -3486,10 +3262,12 @@ pub const Type = struct { |
| 3486 | ty = struct_obj.backing_int_ty; | 3262 | ty = struct_obj.backing_int_ty; |
| 3487 | }, | 3263 | }, |
| 3488 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), | 3264 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), |
| 3265 | .vector_type => |vector_type| ty = vector_type.child.toType(), | ||
| 3266 | |||
| 3267 | .anon_struct_type => unreachable, | ||
| 3489 | 3268 | ||
| 3490 | .ptr_type => unreachable, | 3269 | .ptr_type => unreachable, |
| 3491 | .array_type => unreachable, | 3270 | .array_type => unreachable, |
| 3492 | .vector_type => |vector_type| ty = vector_type.child.toType(), | ||
| 3493 | 3271 | ||
| 3494 | .opt_type => unreachable, | 3272 | .opt_type => unreachable, |
| 3495 | .error_union_type => unreachable, | 3273 | .error_union_type => unreachable, |
| ... | @@ -3711,17 +3489,6 @@ pub const Type = struct { | ... | @@ -3711,17 +3489,6 @@ pub const Type = struct { |
| 3711 | } | 3489 | } |
| 3712 | }, | 3490 | }, |
| 3713 | 3491 | ||
| 3714 | .tuple, .anon_struct => { | ||
| 3715 | const tuple = ty.tupleFields(); | ||
| 3716 | for (tuple.values, 0..) |val, i| { | ||
| 3717 | const is_comptime = val.ip_index != .unreachable_value; | ||
| 3718 | if (is_comptime) continue; | ||
| 3719 | if ((try tuple.types[i].onePossibleValue(mod)) != null) continue; | ||
| 3720 | return null; | ||
| 3721 | } | ||
| 3722 | return Value.empty_struct; | ||
| 3723 | }, | ||
| 3724 | |||
| 3725 | .inferred_alloc_const => unreachable, | 3492 | .inferred_alloc_const => unreachable, |
| 3726 | .inferred_alloc_mut => unreachable, | 3493 | .inferred_alloc_mut => unreachable, |
| 3727 | }, | 3494 | }, |
| ... | @@ -3810,7 +3577,33 @@ pub const Type = struct { | ... | @@ -3810,7 +3577,33 @@ pub const Type = struct { |
| 3810 | return null; | 3577 | return null; |
| 3811 | } | 3578 | } |
| 3812 | } | 3579 | } |
| 3813 | // In this case the struct has no fields and therefore has one possible value. | 3580 | // In this case the struct has no runtime-known fields and |
| 3581 | // therefore has one possible value. | ||
| 3582 | |||
| 3583 | // TODO: this is incorrect for structs with comptime fields, I think | ||
| 3584 | // we should use a temporary allocator to construct an aggregate that | ||
| 3585 | // is populated with the comptime values and then intern that value here. | ||
| 3586 | // This TODO is repeated for anon_struct_type below, as well as in | ||
| 3587 | // the redundant implementation of one-possible-value logic in Sema.zig. | ||
| 3588 | const empty = try mod.intern(.{ .aggregate = .{ | ||
| 3589 | .ty = ty.ip_index, | ||
| 3590 | .fields = &.{}, | ||
| 3591 | } }); | ||
| 3592 | return empty.toValue(); | ||
| 3593 | }, | ||
| 3594 | |||
| 3595 | .anon_struct_type => |tuple| { | ||
| 3596 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 3597 | if (val != .none) continue; // comptime field | ||
| 3598 | if ((try field_ty.toType().onePossibleValue(mod)) != null) continue; | ||
| 3599 | return null; | ||
| 3600 | } | ||
| 3601 | |||
| 3602 | // TODO: this is incorrect for structs with comptime fields, I think | ||
| 3603 | // we should use a temporary allocator to construct an aggregate that | ||
| 3604 | // is populated with the comptime values and then intern that value here. | ||
| 3605 | // This TODO is repeated for struct_type above, as well as in | ||
| 3606 | // the redundant implementation of one-possible-value logic in Sema.zig. | ||
| 3814 | const empty = try mod.intern(.{ .aggregate = .{ | 3607 | const empty = try mod.intern(.{ .aggregate = .{ |
| 3815 | .ty = ty.ip_index, | 3608 | .ty = ty.ip_index, |
| 3816 | .fields = &.{}, | 3609 | .fields = &.{}, |
| ... | @@ -3915,15 +3708,6 @@ pub const Type = struct { | ... | @@ -3915,15 +3708,6 @@ pub const Type = struct { |
| 3915 | return ty.optionalChild(mod).comptimeOnly(mod); | 3708 | return ty.optionalChild(mod).comptimeOnly(mod); |
| 3916 | }, | 3709 | }, |
| 3917 | 3710 | ||
| 3918 | .tuple, .anon_struct => { | ||
| 3919 | const tuple = ty.tupleFields(); | ||
| 3920 | for (tuple.types, 0..) |field_ty, i| { | ||
| 3921 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | ||
| 3922 | if (!have_comptime_val and field_ty.comptimeOnly(mod)) return true; | ||
| 3923 | } | ||
| 3924 | return false; | ||
| 3925 | }, | ||
| 3926 | |||
| 3927 | .error_union => return ty.errorUnionPayload().comptimeOnly(mod), | 3711 | .error_union => return ty.errorUnionPayload().comptimeOnly(mod), |
| 3928 | .anyframe_T => { | 3712 | .anyframe_T => { |
| 3929 | const child_ty = ty.castTag(.anyframe_T).?.data; | 3713 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | @@ -4007,6 +3791,14 @@ pub const Type = struct { | ... | @@ -4007,6 +3791,14 @@ pub const Type = struct { |
| 4007 | } | 3791 | } |
| 4008 | }, | 3792 | }, |
| 4009 | 3793 | ||
| 3794 | .anon_struct_type => |tuple| { | ||
| 3795 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 3796 | const have_comptime_val = val != .none; | ||
| 3797 | if (!have_comptime_val and field_ty.toType().comptimeOnly(mod)) return true; | ||
| 3798 | } | ||
| 3799 | return false; | ||
| 3800 | }, | ||
| 3801 | |||
| 4010 | .union_type => |union_type| { | 3802 | .union_type => |union_type| { |
| 4011 | const union_obj = mod.unionPtr(union_type.index); | 3803 | const union_obj = mod.unionPtr(union_type.index); |
| 4012 | switch (union_obj.requires_comptime) { | 3804 | switch (union_obj.requires_comptime) { |
| ... | @@ -4275,171 +4067,116 @@ pub const Type = struct { | ... | @@ -4275,171 +4067,116 @@ pub const Type = struct { |
| 4275 | } | 4067 | } |
| 4276 | 4068 | ||
| 4277 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) []const u8 { | 4069 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) []const u8 { |
| 4278 | switch (ty.ip_index) { | 4070 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4279 | .none => switch (ty.tag()) { | 4071 | .struct_type => |struct_type| { |
| 4280 | .anon_struct => return ty.castTag(.anon_struct).?.data.names[field_index], | 4072 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4281 | else => unreachable, | 4073 | assert(struct_obj.haveFieldTypes()); |
| 4074 | return struct_obj.fields.keys()[field_index]; | ||
| 4282 | }, | 4075 | }, |
| 4283 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 4076 | .anon_struct_type => |anon_struct| { |
| 4284 | .struct_type => |struct_type| { | 4077 | const name = anon_struct.names[field_index]; |
| 4285 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 4078 | return mod.intern_pool.stringToSlice(name); |
| 4286 | assert(struct_obj.haveFieldTypes()); | ||
| 4287 | return struct_obj.fields.keys()[field_index]; | ||
| 4288 | }, | ||
| 4289 | else => unreachable, | ||
| 4290 | }, | 4079 | }, |
| 4080 | else => unreachable, | ||
| 4291 | } | 4081 | } |
| 4292 | } | 4082 | } |
| 4293 | 4083 | ||
| 4294 | pub fn structFieldCount(ty: Type, mod: *Module) usize { | 4084 | pub fn structFieldCount(ty: Type, mod: *Module) usize { |
| 4295 | return switch (ty.ip_index) { | 4085 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4296 | .empty_struct_type => 0, | 4086 | .struct_type => |struct_type| { |
| 4297 | .none => switch (ty.tag()) { | 4087 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; |
| 4298 | .tuple => ty.castTag(.tuple).?.data.types.len, | 4088 | assert(struct_obj.haveFieldTypes()); |
| 4299 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | 4089 | return struct_obj.fields.count(); |
| 4300 | else => unreachable, | ||
| 4301 | }, | ||
| 4302 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4303 | .struct_type => |struct_type| { | ||
| 4304 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | ||
| 4305 | assert(struct_obj.haveFieldTypes()); | ||
| 4306 | return struct_obj.fields.count(); | ||
| 4307 | }, | ||
| 4308 | else => unreachable, | ||
| 4309 | }, | 4090 | }, |
| 4091 | .anon_struct_type => |anon_struct| anon_struct.types.len, | ||
| 4092 | else => unreachable, | ||
| 4310 | }; | 4093 | }; |
| 4311 | } | 4094 | } |
| 4312 | 4095 | ||
| 4313 | /// Supports structs and unions. | 4096 | /// Supports structs and unions. |
| 4314 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { | 4097 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { |
| 4315 | return switch (ty.ip_index) { | 4098 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4316 | .none => switch (ty.tag()) { | 4099 | .struct_type => |struct_type| { |
| 4317 | .tuple => return ty.castTag(.tuple).?.data.types[index], | 4100 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4318 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | 4101 | return struct_obj.fields.values()[index].ty; |
| 4319 | else => unreachable, | ||
| 4320 | }, | 4102 | }, |
| 4321 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 4103 | .union_type => |union_type| { |
| 4322 | .struct_type => |struct_type| { | 4104 | const union_obj = mod.unionPtr(union_type.index); |
| 4323 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 4105 | return union_obj.fields.values()[index].ty; |
| 4324 | return struct_obj.fields.values()[index].ty; | ||
| 4325 | }, | ||
| 4326 | .union_type => |union_type| { | ||
| 4327 | const union_obj = mod.unionPtr(union_type.index); | ||
| 4328 | return union_obj.fields.values()[index].ty; | ||
| 4329 | }, | ||
| 4330 | else => unreachable, | ||
| 4331 | }, | 4106 | }, |
| 4107 | .anon_struct_type => |anon_struct| anon_struct.types[index].toType(), | ||
| 4108 | else => unreachable, | ||
| 4332 | }; | 4109 | }; |
| 4333 | } | 4110 | } |
| 4334 | 4111 | ||
| 4335 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { | 4112 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { |
| 4336 | switch (ty.ip_index) { | 4113 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4337 | .none => switch (ty.tag()) { | 4114 | .struct_type => |struct_type| { |
| 4338 | .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod), | 4115 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4339 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod), | 4116 | assert(struct_obj.layout != .Packed); |
| 4340 | else => unreachable, | 4117 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); |
| 4341 | }, | 4118 | }, |
| 4342 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 4119 | .anon_struct_type => |anon_struct| { |
| 4343 | .struct_type => |struct_type| { | 4120 | return anon_struct.types[index].toType().abiAlignment(mod); |
| 4344 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 4345 | assert(struct_obj.layout != .Packed); | ||
| 4346 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); | ||
| 4347 | }, | ||
| 4348 | .union_type => |union_type| { | ||
| 4349 | const union_obj = mod.unionPtr(union_type.index); | ||
| 4350 | return union_obj.fields.values()[index].normalAlignment(mod); | ||
| 4351 | }, | ||
| 4352 | else => unreachable, | ||
| 4353 | }, | 4121 | }, |
| 4122 | .union_type => |union_type| { | ||
| 4123 | const union_obj = mod.unionPtr(union_type.index); | ||
| 4124 | return union_obj.fields.values()[index].normalAlignment(mod); | ||
| 4125 | }, | ||
| 4126 | else => unreachable, | ||
| 4354 | } | 4127 | } |
| 4355 | } | 4128 | } |
| 4356 | 4129 | ||
| 4357 | pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value { | 4130 | pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value { |
| 4358 | switch (ty.ip_index) { | 4131 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4359 | .none => switch (ty.tag()) { | 4132 | .struct_type => |struct_type| { |
| 4360 | .tuple => { | 4133 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4361 | const tuple = ty.castTag(.tuple).?.data; | 4134 | return struct_obj.fields.values()[index].default_val; |
| 4362 | return tuple.values[index]; | ||
| 4363 | }, | ||
| 4364 | .anon_struct => { | ||
| 4365 | const struct_obj = ty.castTag(.anon_struct).?.data; | ||
| 4366 | return struct_obj.values[index]; | ||
| 4367 | }, | ||
| 4368 | else => unreachable, | ||
| 4369 | }, | 4135 | }, |
| 4370 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 4136 | .anon_struct_type => |anon_struct| { |
| 4371 | .struct_type => |struct_type| { | 4137 | const val = anon_struct.values[index]; |
| 4372 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 4138 | // TODO: avoid using `unreachable` to indicate this. |
| 4373 | return struct_obj.fields.values()[index].default_val; | 4139 | if (val == .none) return Value.@"unreachable"; |
| 4374 | }, | 4140 | return val.toValue(); |
| 4375 | else => unreachable, | ||
| 4376 | }, | 4141 | }, |
| 4142 | else => unreachable, | ||
| 4377 | } | 4143 | } |
| 4378 | } | 4144 | } |
| 4379 | 4145 | ||
| 4380 | pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value { | 4146 | pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value { |
| 4381 | switch (ty.ip_index) { | 4147 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4382 | .none => switch (ty.tag()) { | 4148 | .struct_type => |struct_type| { |
| 4383 | .tuple => { | 4149 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4384 | const tuple = ty.castTag(.tuple).?.data; | 4150 | const field = struct_obj.fields.values()[index]; |
| 4385 | const val = tuple.values[index]; | 4151 | if (field.is_comptime) { |
| 4386 | if (val.ip_index == .unreachable_value) { | 4152 | return field.default_val; |
| 4387 | return tuple.types[index].onePossibleValue(mod); | 4153 | } else { |
| 4388 | } else { | 4154 | return field.ty.onePossibleValue(mod); |
| 4389 | return val; | 4155 | } |
| 4390 | } | ||
| 4391 | }, | ||
| 4392 | .anon_struct => { | ||
| 4393 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 4394 | const val = anon_struct.values[index]; | ||
| 4395 | if (val.ip_index == .unreachable_value) { | ||
| 4396 | return anon_struct.types[index].onePossibleValue(mod); | ||
| 4397 | } else { | ||
| 4398 | return val; | ||
| 4399 | } | ||
| 4400 | }, | ||
| 4401 | else => unreachable, | ||
| 4402 | }, | 4156 | }, |
| 4403 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | 4157 | .anon_struct_type => |tuple| { |
| 4404 | .struct_type => |struct_type| { | 4158 | const val = tuple.values[index]; |
| 4405 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 4159 | if (val == .none) { |
| 4406 | const field = struct_obj.fields.values()[index]; | 4160 | return tuple.types[index].toType().onePossibleValue(mod); |
| 4407 | if (field.is_comptime) { | 4161 | } else { |
| 4408 | return field.default_val; | 4162 | return val.toValue(); |
| 4409 | } else { | 4163 | } |
| 4410 | return field.ty.onePossibleValue(mod); | ||
| 4411 | } | ||
| 4412 | }, | ||
| 4413 | else => unreachable, | ||
| 4414 | }, | 4164 | }, |
| 4165 | else => unreachable, | ||
| 4415 | } | 4166 | } |
| 4416 | } | 4167 | } |
| 4417 | 4168 | ||
| 4418 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { | 4169 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { |
| 4419 | switch (ty.ip_index) { | 4170 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4420 | .none => switch (ty.tag()) { | 4171 | .struct_type => |struct_type| { |
| 4421 | .tuple => { | 4172 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 4422 | const tuple = ty.castTag(.tuple).?.data; | 4173 | if (struct_obj.layout == .Packed) return false; |
| 4423 | const val = tuple.values[index]; | 4174 | const field = struct_obj.fields.values()[index]; |
| 4424 | return val.ip_index != .unreachable_value; | 4175 | return field.is_comptime; |
| 4425 | }, | ||
| 4426 | .anon_struct => { | ||
| 4427 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 4428 | const val = anon_struct.values[index]; | ||
| 4429 | return val.ip_index != .unreachable_value; | ||
| 4430 | }, | ||
| 4431 | else => unreachable, | ||
| 4432 | }, | ||
| 4433 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4434 | .struct_type => |struct_type| { | ||
| 4435 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 4436 | if (struct_obj.layout == .Packed) return false; | ||
| 4437 | const field = struct_obj.fields.values()[index]; | ||
| 4438 | return field.is_comptime; | ||
| 4439 | }, | ||
| 4440 | else => unreachable, | ||
| 4441 | }, | 4176 | }, |
| 4442 | } | 4177 | .anon_struct_type => |anon_struct| anon_struct.values[index] != .none, |
| 4178 | else => unreachable, | ||
| 4179 | }; | ||
| 4443 | } | 4180 | } |
| 4444 | 4181 | ||
| 4445 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { | 4182 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { |
| ... | @@ -4516,46 +4253,43 @@ pub const Type = struct { | ... | @@ -4516,46 +4253,43 @@ pub const Type = struct { |
| 4516 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { | 4253 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { |
| 4517 | switch (ty.ip_index) { | 4254 | switch (ty.ip_index) { |
| 4518 | .none => switch (ty.tag()) { | 4255 | .none => switch (ty.tag()) { |
| 4519 | .tuple, .anon_struct => { | 4256 | else => unreachable, |
| 4520 | const tuple = ty.tupleFields(); | 4257 | }, |
| 4258 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4259 | .struct_type => |struct_type| { | ||
| 4260 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 4261 | assert(struct_obj.haveLayout()); | ||
| 4262 | assert(struct_obj.layout != .Packed); | ||
| 4263 | var it = ty.iterateStructOffsets(mod); | ||
| 4264 | while (it.next()) |field_offset| { | ||
| 4265 | if (index == field_offset.field) | ||
| 4266 | return field_offset.offset; | ||
| 4267 | } | ||
| 4521 | 4268 | ||
| 4269 | return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1)); | ||
| 4270 | }, | ||
| 4271 | |||
| 4272 | .anon_struct_type => |tuple| { | ||
| 4522 | var offset: u64 = 0; | 4273 | var offset: u64 = 0; |
| 4523 | var big_align: u32 = 0; | 4274 | var big_align: u32 = 0; |
| 4524 | 4275 | ||
| 4525 | for (tuple.types, 0..) |field_ty, i| { | 4276 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 4526 | const field_val = tuple.values[i]; | 4277 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { |
| 4527 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) { | ||
| 4528 | // comptime field | 4278 | // comptime field |
| 4529 | if (i == index) return offset; | 4279 | if (i == index) return offset; |
| 4530 | continue; | 4280 | continue; |
| 4531 | } | 4281 | } |
| 4532 | 4282 | ||
| 4533 | const field_align = field_ty.abiAlignment(mod); | 4283 | const field_align = field_ty.toType().abiAlignment(mod); |
| 4534 | big_align = @max(big_align, field_align); | 4284 | big_align = @max(big_align, field_align); |
| 4535 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 4285 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 4536 | if (i == index) return offset; | 4286 | if (i == index) return offset; |
| 4537 | offset += field_ty.abiSize(mod); | 4287 | offset += field_ty.toType().abiSize(mod); |
| 4538 | } | 4288 | } |
| 4539 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); | 4289 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); |
| 4540 | return offset; | 4290 | return offset; |
| 4541 | }, | 4291 | }, |
| 4542 | 4292 | ||
| 4543 | else => unreachable, | ||
| 4544 | }, | ||
| 4545 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4546 | .struct_type => |struct_type| { | ||
| 4547 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 4548 | assert(struct_obj.haveLayout()); | ||
| 4549 | assert(struct_obj.layout != .Packed); | ||
| 4550 | var it = ty.iterateStructOffsets(mod); | ||
| 4551 | while (it.next()) |field_offset| { | ||
| 4552 | if (index == field_offset.field) | ||
| 4553 | return field_offset.offset; | ||
| 4554 | } | ||
| 4555 | |||
| 4556 | return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1)); | ||
| 4557 | }, | ||
| 4558 | |||
| 4559 | .union_type => |union_type| { | 4293 | .union_type => |union_type| { |
| 4560 | if (!union_type.hasTag()) | 4294 | if (!union_type.hasTag()) |
| 4561 | return 0; | 4295 | return 0; |
| ... | @@ -4655,10 +4389,6 @@ pub const Type = struct { | ... | @@ -4655,10 +4389,6 @@ pub const Type = struct { |
| 4655 | inferred_alloc_const, // See last_no_payload_tag below. | 4389 | inferred_alloc_const, // See last_no_payload_tag below. |
| 4656 | // After this, the tag requires a payload. | 4390 | // After this, the tag requires a payload. |
| 4657 | 4391 | ||
| 4658 | /// Possible Value tags for this: @"struct" | ||
| 4659 | tuple, | ||
| 4660 | /// Possible Value tags for this: @"struct" | ||
| 4661 | anon_struct, | ||
| 4662 | pointer, | 4392 | pointer, |
| 4663 | function, | 4393 | function, |
| 4664 | optional, | 4394 | optional, |
| ... | @@ -4691,8 +4421,6 @@ pub const Type = struct { | ... | @@ -4691,8 +4421,6 @@ pub const Type = struct { |
| 4691 | .function => Payload.Function, | 4421 | .function => Payload.Function, |
| 4692 | .error_union => Payload.ErrorUnion, | 4422 | .error_union => Payload.ErrorUnion, |
| 4693 | .error_set_single => Payload.Name, | 4423 | .error_set_single => Payload.Name, |
| 4694 | .tuple => Payload.Tuple, | ||
| 4695 | .anon_struct => Payload.AnonStruct, | ||
| 4696 | }; | 4424 | }; |
| 4697 | } | 4425 | } |
| 4698 | 4426 | ||
| ... | @@ -4723,83 +4451,48 @@ pub const Type = struct { | ... | @@ -4723,83 +4451,48 @@ pub const Type = struct { |
| 4723 | 4451 | ||
| 4724 | pub fn isTuple(ty: Type, mod: *Module) bool { | 4452 | pub fn isTuple(ty: Type, mod: *Module) bool { |
| 4725 | return switch (ty.ip_index) { | 4453 | return switch (ty.ip_index) { |
| 4726 | .none => switch (ty.tag()) { | 4454 | .none => false, |
| 4727 | .tuple => true, | 4455 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4728 | else => false, | ||
| 4729 | }, | ||
| 4730 | else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4731 | .struct_type => |struct_type| { | 4456 | .struct_type => |struct_type| { |
| 4732 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 4457 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; |
| 4733 | return struct_obj.is_tuple; | 4458 | return struct_obj.is_tuple; |
| 4734 | }, | 4459 | }, |
| 4460 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, | ||
| 4735 | else => false, | 4461 | else => false, |
| 4736 | }, | 4462 | }, |
| 4737 | }; | 4463 | }; |
| 4738 | } | 4464 | } |
| 4739 | 4465 | ||
| 4740 | pub fn isAnonStruct(ty: Type) bool { | 4466 | pub fn isAnonStruct(ty: Type, mod: *Module) bool { |
| 4741 | return switch (ty.ip_index) { | 4467 | if (ty.ip_index == .empty_struct_type) return true; |
| 4742 | .empty_struct_type => true, | 4468 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4743 | .none => switch (ty.tag()) { | 4469 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0, |
| 4744 | .anon_struct => true, | ||
| 4745 | else => false, | ||
| 4746 | }, | ||
| 4747 | else => false, | 4470 | else => false, |
| 4748 | }; | 4471 | }; |
| 4749 | } | 4472 | } |
| 4750 | 4473 | ||
| 4751 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { | 4474 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 4752 | return switch (ty.ip_index) { | 4475 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4753 | .empty_struct_type => true, | 4476 | .struct_type => |struct_type| { |
| 4754 | .none => switch (ty.tag()) { | 4477 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; |
| 4755 | .tuple, .anon_struct => true, | 4478 | return struct_obj.is_tuple; |
| 4756 | else => false, | ||
| 4757 | }, | ||
| 4758 | else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 4759 | .struct_type => |struct_type| { | ||
| 4760 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | ||
| 4761 | return struct_obj.is_tuple; | ||
| 4762 | }, | ||
| 4763 | else => false, | ||
| 4764 | }, | ||
| 4765 | }; | ||
| 4766 | } | ||
| 4767 | |||
| 4768 | pub fn isSimpleTuple(ty: Type) bool { | ||
| 4769 | return switch (ty.ip_index) { | ||
| 4770 | .empty_struct_type => true, | ||
| 4771 | .none => switch (ty.tag()) { | ||
| 4772 | .tuple => true, | ||
| 4773 | else => false, | ||
| 4774 | }, | 4479 | }, |
| 4480 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, | ||
| 4775 | else => false, | 4481 | else => false, |
| 4776 | }; | 4482 | }; |
| 4777 | } | 4483 | } |
| 4778 | 4484 | ||
| 4779 | pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { | 4485 | pub fn isSimpleTuple(ty: Type, mod: *Module) bool { |
| 4780 | return switch (ty.ip_index) { | 4486 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4781 | .empty_struct_type => true, | 4487 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, |
| 4782 | .none => switch (ty.tag()) { | ||
| 4783 | .tuple, .anon_struct => true, | ||
| 4784 | else => false, | ||
| 4785 | }, | ||
| 4786 | else => false, | 4488 | else => false, |
| 4787 | }; | 4489 | }; |
| 4788 | } | 4490 | } |
| 4789 | 4491 | ||
| 4790 | // Only allowed for simple tuple types | 4492 | pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 4791 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { | 4493 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4792 | return switch (ty.ip_index) { | 4494 | .anon_struct_type => true, |
| 4793 | .empty_struct_type => .{ .types = &.{}, .values = &.{} }, | 4495 | else => false, |
| 4794 | .none => switch (ty.tag()) { | ||
| 4795 | .tuple => ty.castTag(.tuple).?.data, | ||
| 4796 | .anon_struct => .{ | ||
| 4797 | .types = ty.castTag(.anon_struct).?.data.types, | ||
| 4798 | .values = ty.castTag(.anon_struct).?.data.values, | ||
| 4799 | }, | ||
| 4800 | else => unreachable, | ||
| 4801 | }, | ||
| 4802 | else => unreachable, | ||
| 4803 | }; | 4496 | }; |
| 4804 | } | 4497 | } |
| 4805 | 4498 | ||
| ... | @@ -4947,29 +4640,6 @@ pub const Type = struct { | ... | @@ -4947,29 +4640,6 @@ pub const Type = struct { |
| 4947 | /// memory is owned by `Module` | 4640 | /// memory is owned by `Module` |
| 4948 | data: []const u8, | 4641 | data: []const u8, |
| 4949 | }; | 4642 | }; |
| 4950 | |||
| 4951 | pub const Tuple = struct { | ||
| 4952 | base: Payload = .{ .tag = .tuple }, | ||
| 4953 | data: Data, | ||
| 4954 | |||
| 4955 | pub const Data = struct { | ||
| 4956 | types: []Type, | ||
| 4957 | /// unreachable_value elements are used to indicate runtime-known. | ||
| 4958 | values: []Value, | ||
| 4959 | }; | ||
| 4960 | }; | ||
| 4961 | |||
| 4962 | pub const AnonStruct = struct { | ||
| 4963 | base: Payload = .{ .tag = .anon_struct }, | ||
| 4964 | data: Data, | ||
| 4965 | |||
| 4966 | pub const Data = struct { | ||
| 4967 | names: []const []const u8, | ||
| 4968 | types: []Type, | ||
| 4969 | /// unreachable_value elements are used to indicate runtime-known. | ||
| 4970 | values: []Value, | ||
| 4971 | }; | ||
| 4972 | }; | ||
| 4973 | }; | 4643 | }; |
| 4974 | 4644 | ||
| 4975 | pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined }; | 4645 | pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined }; |
src/value.zig+20-32| ... | @@ -1889,26 +1889,28 @@ pub const Value = struct { | ... | @@ -1889,26 +1889,28 @@ pub const Value = struct { |
| 1889 | const b_field_vals = b.castTag(.aggregate).?.data; | 1889 | const b_field_vals = b.castTag(.aggregate).?.data; |
| 1890 | assert(a_field_vals.len == b_field_vals.len); | 1890 | assert(a_field_vals.len == b_field_vals.len); |
| 1891 | 1891 | ||
| 1892 | if (ty.isSimpleTupleOrAnonStruct()) { | 1892 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1893 | const types = ty.tupleFields().types; | 1893 | .anon_struct_type => |anon_struct| { |
| 1894 | assert(types.len == a_field_vals.len); | 1894 | assert(anon_struct.types.len == a_field_vals.len); |
| 1895 | for (types, 0..) |field_ty, i| { | 1895 | for (anon_struct.types, 0..) |field_ty, i| { |
| 1896 | if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, opt_sema))) { | 1896 | if (!(try eqlAdvanced(a_field_vals[i], field_ty.toType(), b_field_vals[i], field_ty.toType(), mod, opt_sema))) { |
| 1897 | return false; | 1897 | return false; |
| 1898 | } | ||
| 1898 | } | 1899 | } |
| 1899 | } | 1900 | return true; |
| 1900 | return true; | 1901 | }, |
| 1901 | } | 1902 | .struct_type => |struct_type| { |
| 1902 | 1903 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 1903 | if (ty.zigTypeTag(mod) == .Struct) { | 1904 | const fields = struct_obj.fields.values(); |
| 1904 | const fields = ty.structFields(mod).values(); | 1905 | assert(fields.len == a_field_vals.len); |
| 1905 | assert(fields.len == a_field_vals.len); | 1906 | for (fields, 0..) |field, i| { |
| 1906 | for (fields, 0..) |field, i| { | 1907 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { |
| 1907 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { | 1908 | return false; |
| 1908 | return false; | 1909 | } |
| 1909 | } | 1910 | } |
| 1910 | } | 1911 | return true; |
| 1911 | return true; | 1912 | }, |
| 1913 | else => {}, | ||
| 1912 | } | 1914 | } |
| 1913 | 1915 | ||
| 1914 | const elem_ty = ty.childType(mod); | 1916 | const elem_ty = ty.childType(mod); |
| ... | @@ -2017,20 +2019,6 @@ pub const Value = struct { | ... | @@ -2017,20 +2019,6 @@ pub const Value = struct { |
| 2017 | if ((try ty.onePossibleValue(mod)) != null) { | 2019 | if ((try ty.onePossibleValue(mod)) != null) { |
| 2018 | return true; | 2020 | return true; |
| 2019 | } | 2021 | } |
| 2020 | if (a_ty.castTag(.anon_struct)) |payload| { | ||
| 2021 | const tuple = payload.data; | ||
| 2022 | if (tuple.values.len != 1) { | ||
| 2023 | return false; | ||
| 2024 | } | ||
| 2025 | const field_name = tuple.names[0]; | ||
| 2026 | const union_obj = mod.typeToUnion(ty).?; | ||
| 2027 | const field_index = @intCast(u32, union_obj.fields.getIndex(field_name) orelse return false); | ||
| 2028 | const tag_and_val = b.castTag(.@"union").?.data; | ||
| 2029 | const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, field_index); | ||
| 2030 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod); | ||
| 2031 | if (!tag_matches) return false; | ||
| 2032 | return eqlAdvanced(tag_and_val.val, union_obj.tag_ty, tuple.values[0], tuple.types[0], mod, opt_sema); | ||
| 2033 | } | ||
| 2034 | return false; | 2022 | return false; |
| 2035 | }, | 2023 | }, |
| 2036 | .Float => { | 2024 | .Float => { |