| 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 | 137 | payload_type: Index, |
| 138 | 138 | }, |
| 139 | 139 | simple_type: SimpleType, |
| 140 | /// If `empty_struct_type` is handled separately, then this value may be | |
| 141 | /// safely assumed to never be `none`. | |
| 140 | /// This represents a struct that has been explicitly declared in source code, | |
| 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 | 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 | 148 | union_type: UnionType, |
| 144 | 149 | opaque_type: OpaqueType, |
| 145 | 150 | enum_type: EnumType, |
| ... | ... | @@ -168,7 +173,7 @@ pub const Key = union(enum) { |
| 168 | 173 | /// Each element/field stored as an `Index`. |
| 169 | 174 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| 170 | 175 | /// so the slice length will be one more than the type's array length. |
| 171 | aggregate: Aggregate, | |
| 176 | aggregate: Key.Aggregate, | |
| 172 | 177 | /// An instance of a union. |
| 173 | 178 | un: Union, |
| 174 | 179 | |
| ... | ... | @@ -222,22 +227,25 @@ pub const Key = union(enum) { |
| 222 | 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 | 230 | pub const StructType = struct { |
| 232 | /// The `none` tag is used to represent two cases: | |
| 233 | /// * `@TypeOf(.{})`, in which case `namespace` will also be `none`. | |
| 234 | /// * A struct with no fields, in which case `namespace` will be populated. | |
| 231 | /// The `none` tag is used to represent a struct with no fields. | |
| 235 | 232 | index: Module.Struct.OptionalIndex, |
| 236 | /// This will be `none` only in the case of `@TypeOf(.{})` | |
| 237 | /// (`Index.empty_struct_type`). | |
| 233 | /// May be `none` if the struct has no declarations. | |
| 238 | 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 | 249 | pub const UnionType = struct { |
| 242 | 250 | index: Module.Union.Index, |
| 243 | 251 | runtime_tag: RuntimeTag, |
| ... | ... | @@ -498,6 +506,12 @@ pub const Key = union(enum) { |
| 498 | 506 | std.hash.autoHash(hasher, aggregate.ty); |
| 499 | 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 | 664 | if (a_info.ty != b_info.ty) return false; |
| 651 | 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 | 686 | .union_type, |
| 667 | 687 | .opaque_type, |
| 668 | 688 | .enum_type, |
| 689 | .anon_struct_type, | |
| 669 | 690 | => .type_type, |
| 670 | 691 | |
| 671 | 692 | inline .ptr, |
| ... | ... | @@ -1020,9 +1041,10 @@ pub const static_keys = [_]Key{ |
| 1020 | 1041 | .{ .simple_type = .var_args_param }, |
| 1021 | 1042 | |
| 1022 | 1043 | // empty_struct_type |
| 1023 | .{ .struct_type = .{ | |
| 1024 | .namespace = .none, | |
| 1025 | .index = .none, | |
| 1044 | .{ .anon_struct_type = .{ | |
| 1045 | .types = &.{}, | |
| 1046 | .names = &.{}, | |
| 1047 | .values = &.{}, | |
| 1026 | 1048 | } }, |
| 1027 | 1049 | |
| 1028 | 1050 | .{ .simple_value = .undefined }, |
| ... | ... | @@ -1144,6 +1166,12 @@ pub const Tag = enum(u8) { |
| 1144 | 1166 | /// Module.Struct object allocated for it. |
| 1145 | 1167 | /// data is Module.Namespace.Index. |
| 1146 | 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 | 1175 | /// A tagged union type. |
| 1148 | 1176 | /// `data` is `Module.Union.Index`. |
| 1149 | 1177 | type_union_tagged, |
| ... | ... | @@ -1249,6 +1277,26 @@ pub const Tag = enum(u8) { |
| 1249 | 1277 | only_possible_value, |
| 1250 | 1278 | /// data is extra index to Key.Union. |
| 1251 | 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 | 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 | 1620 | } |
| 1573 | 1621 | |
| 1574 | 1622 | pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1623 | assert(index != .none); | |
| 1575 | 1624 | const item = ip.items.get(@enumToInt(index)); |
| 1576 | 1625 | const data = item.data; |
| 1577 | 1626 | return switch (item.tag) { |
| ... | ... | @@ -1659,6 +1708,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1659 | 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 | 1735 | .type_union_untagged => .{ .union_type = .{ |
| 1663 | 1736 | .index = @intToEnum(Module.Union.Index, data), |
| 1664 | 1737 | .runtime_tag = .none, |
| ... | ... | @@ -1797,6 +1870,15 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1797 | 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 | 1882 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, |
| 1801 | 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 | 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 | 2106 | .union_type => |union_type| { |
| 1986 | 2107 | ip.items.appendAssumeCapacity(.{ |
| 1987 | 2108 | .tag = switch (union_type.runtime_tag) { |
| ... | ... | @@ -2269,6 +2390,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2269 | 2390 | }, |
| 2270 | 2391 | |
| 2271 | 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 | 2403 | if (aggregate.fields.len == 0) { |
| 2273 | 2404 | ip.items.appendAssumeCapacity(.{ |
| 2274 | 2405 | .tag = .only_possible_value, |
| ... | ... | @@ -2276,7 +2407,19 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2276 | 2407 | }); |
| 2277 | 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 | 2425 | .un => |un| { |
| ... | ... | @@ -2913,6 +3056,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 2913 | 3056 | .type_opaque => @sizeOf(Key.OpaqueType), |
| 2914 | 3057 | .type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl), |
| 2915 | 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 | 3068 | .type_union_tagged, |
| 2918 | 3069 | .type_union_untagged, |
| ... | ... | @@ -2942,6 +3093,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 2942 | 3093 | }, |
| 2943 | 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 | 3102 | .float_f16 => 0, |
| 2946 | 3103 | .float_f32 => 0, |
| 2947 | 3104 | .float_f64 => @sizeOf(Float64), |
| ... | ... | @@ -3079,3 +3236,13 @@ pub fn toEnum(ip: InternPool, comptime E: type, i: Index) E { |
| 3079 | 3236 | const int = ip.indexToKey(i).enum_tag.int; |
| 3080 | 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 | 7896 | } |
| 7897 | 7897 | |
| 7898 | 7898 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 7899 | if (!ty.isSimpleTupleOrAnonStruct()) return; | |
| 7900 | const tuple = ty.tupleFields(); | |
| 7901 | for (tuple.values, 0..) |field_val, i| { | |
| 7902 | try sema.resolveTupleLazyValues(block, src, tuple.types[i]); | |
| 7903 | if (field_val.ip_index == .unreachable_value) continue; | |
| 7904 | try sema.resolveLazyValue(field_val); | |
| 7899 | const mod = sema.mod; | |
| 7900 | const tuple = switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 7901 | .anon_struct_type => |tuple| tuple, | |
| 7902 | else => return, | |
| 7903 | }; | |
| 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 | 12041 | const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 12039 | 12042 | const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); |
| 12040 | 12043 | const ty = try sema.resolveTypeFields(unresolved_ty); |
| 12044 | const ip = &mod.intern_pool; | |
| 12041 | 12045 | |
| 12042 | 12046 | const has_field = hf: { |
| 12043 | if (ty.isSlice(mod)) { | |
| 12044 | if (mem.eql(u8, field_name, "ptr")) break :hf true; | |
| 12045 | if (mem.eql(u8, field_name, "len")) break :hf true; | |
| 12046 | break :hf false; | |
| 12047 | } | |
| 12048 | if (ty.castTag(.anon_struct)) |pl| { | |
| 12049 | break :hf for (pl.data.names) |name| { | |
| 12050 | if (mem.eql(u8, name, field_name)) break true; | |
| 12051 | } else false; | |
| 12052 | } | |
| 12053 | if (ty.isTuple(mod)) { | |
| 12054 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; | |
| 12055 | break :hf field_index < ty.structFieldCount(mod); | |
| 12056 | } | |
| 12057 | break :hf switch (ty.zigTypeTag(mod)) { | |
| 12058 | .Struct => ty.structFields(mod).contains(field_name), | |
| 12059 | .Union => ty.unionFields(mod).contains(field_name), | |
| 12060 | .Enum => ty.enumFieldIndex(field_name, mod) != null, | |
| 12061 | .Array => mem.eql(u8, field_name, "len"), | |
| 12062 | else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | |
| 12063 | ty.fmt(sema.mod), | |
| 12064 | }), | |
| 12065 | }; | |
| 12047 | switch (ip.indexToKey(ty.ip_index)) { | |
| 12048 | .ptr_type => |ptr_type| switch (ptr_type.size) { | |
| 12049 | .Slice => { | |
| 12050 | if (mem.eql(u8, field_name, "ptr")) break :hf true; | |
| 12051 | if (mem.eql(u8, field_name, "len")) break :hf true; | |
| 12052 | break :hf false; | |
| 12053 | }, | |
| 12054 | else => {}, | |
| 12055 | }, | |
| 12056 | .anon_struct_type => |anon_struct| { | |
| 12057 | if (anon_struct.names.len != 0) { | |
| 12058 | // If the string is not interned, then the field certainly is not present. | |
| 12059 | const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; | |
| 12060 | break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, name_interned) != null; | |
| 12061 | } else { | |
| 12062 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; | |
| 12063 | break :hf field_index < ty.structFieldCount(mod); | |
| 12064 | } | |
| 12065 | }, | |
| 12066 | .struct_type => |struct_type| { | |
| 12067 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; | |
| 12068 | assert(struct_obj.haveFieldTypes()); | |
| 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 | 12088 | if (has_field) { |
| 12068 | 12089 | return Air.Inst.Ref.bool_true; |
| ... | ... | @@ -12632,42 +12653,48 @@ fn analyzeTupleCat( |
| 12632 | 12653 | } |
| 12633 | 12654 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); |
| 12634 | 12655 | |
| 12635 | const types = try sema.arena.alloc(Type, final_len); | |
| 12636 | const values = try sema.arena.alloc(Value, final_len); | |
| 12656 | const types = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12657 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12637 | 12658 | |
| 12638 | 12659 | const opt_runtime_src = rs: { |
| 12639 | 12660 | var runtime_src: ?LazySrcLoc = null; |
| 12640 | 12661 | var i: u32 = 0; |
| 12641 | 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 | 12664 | const default_val = lhs_ty.structFieldDefaultValue(i, mod); |
| 12644 | values[i] = default_val; | |
| 12665 | values[i] = default_val.ip_index; | |
| 12645 | 12666 | const operand_src = lhs_src; // TODO better source location |
| 12646 | 12667 | if (default_val.ip_index == .unreachable_value) { |
| 12647 | 12668 | runtime_src = operand_src; |
| 12669 | values[i] = .none; | |
| 12648 | 12670 | } |
| 12649 | 12671 | } |
| 12650 | 12672 | i = 0; |
| 12651 | 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 | 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 | 12677 | const operand_src = rhs_src; // TODO better source location |
| 12656 | 12678 | if (default_val.ip_index == .unreachable_value) { |
| 12657 | 12679 | runtime_src = operand_src; |
| 12680 | values[i + lhs_len] = .none; | |
| 12658 | 12681 | } |
| 12659 | 12682 | } |
| 12660 | 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 | 12687 | .types = types, |
| 12665 | 12688 | .values = values, |
| 12666 | }); | |
| 12689 | .names = &.{}, | |
| 12690 | } }); | |
| 12667 | 12691 | |
| 12668 | 12692 | const runtime_src = opt_runtime_src orelse { |
| 12669 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 12670 | return sema.addConstant(tuple_ty, tuple_val); | |
| 12693 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 12694 | .ty = tuple_ty, | |
| 12695 | .fields = values, | |
| 12696 | } }); | |
| 12697 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | |
| 12671 | 12698 | }; |
| 12672 | 12699 | |
| 12673 | 12700 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -12685,7 +12712,7 @@ fn analyzeTupleCat( |
| 12685 | 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 | 12718 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -12938,7 +12965,7 @@ fn analyzeTupleMul( |
| 12938 | 12965 | block: *Block, |
| 12939 | 12966 | src_node: i32, |
| 12940 | 12967 | operand: Air.Inst.Ref, |
| 12941 | factor: u64, | |
| 12968 | factor: usize, | |
| 12942 | 12969 | ) CompileError!Air.Inst.Ref { |
| 12943 | 12970 | const mod = sema.mod; |
| 12944 | 12971 | const operand_ty = sema.typeOf(operand); |
| ... | ... | @@ -12947,44 +12974,45 @@ fn analyzeTupleMul( |
| 12947 | 12974 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12948 | 12975 | |
| 12949 | 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 | 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 | 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); | |
| 12957 | ||
| 12958 | const types = try sema.arena.alloc(Type, final_len); | |
| 12959 | const values = try sema.arena.alloc(Value, final_len); | |
| 12983 | const types = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12984 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12960 | 12985 | |
| 12961 | 12986 | const opt_runtime_src = rs: { |
| 12962 | 12987 | var runtime_src: ?LazySrcLoc = null; |
| 12963 | var i: u32 = 0; | |
| 12964 | while (i < tuple_len) : (i += 1) { | |
| 12965 | types[i] = operand_ty.structFieldType(i, mod); | |
| 12966 | values[i] = operand_ty.structFieldDefaultValue(i, mod); | |
| 12988 | for (0..tuple_len) |i| { | |
| 12989 | types[i] = operand_ty.structFieldType(i, mod).ip_index; | |
| 12990 | values[i] = operand_ty.structFieldDefaultValue(i, mod).ip_index; | |
| 12967 | 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 | 12993 | runtime_src = operand_src; |
| 12994 | values[i] = .none; // TODO don't treat unreachable_value as special | |
| 12970 | 12995 | } |
| 12971 | 12996 | } |
| 12972 | i = 0; | |
| 12973 | while (i < factor) : (i += 1) { | |
| 12974 | mem.copyForwards(Type, types[tuple_len * i ..], types[0..tuple_len]); | |
| 12975 | mem.copyForwards(Value, values[tuple_len * i ..], values[0..tuple_len]); | |
| 12997 | for (0..factor) |i| { | |
| 12998 | mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); | |
| 12999 | mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); | |
| 12976 | 13000 | } |
| 12977 | 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 | 13005 | .types = types, |
| 12982 | 13006 | .values = values, |
| 12983 | }); | |
| 13007 | .names = &.{}, | |
| 13008 | } }); | |
| 12984 | 13009 | |
| 12985 | 13010 | const runtime_src = opt_runtime_src orelse { |
| 12986 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 12987 | return sema.addConstant(tuple_ty, tuple_val); | |
| 13011 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 13012 | .ty = tuple_ty, | |
| 13013 | .fields = values, | |
| 13014 | } }); | |
| 13015 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | |
| 12988 | 13016 | }; |
| 12989 | 13017 | |
| 12990 | 13018 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -13000,7 +13028,7 @@ fn analyzeTupleMul( |
| 13000 | 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 | 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 | 13048 | if (lhs_ty.isTuple(mod)) { |
| 13021 | 13049 | // In `**` rhs must be comptime-known, but lhs can be runtime-known |
| 13022 | 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 | 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 | 14562 | .child = .u1_type, |
| 14534 | 14563 | }) else Type.u1; |
| 14535 | 14564 | |
| 14536 | const types = try sema.arena.alloc(Type, 2); | |
| 14537 | const values = try sema.arena.alloc(Value, 2); | |
| 14538 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | |
| 14539 | .types = types, | |
| 14540 | .values = values, | |
| 14541 | }); | |
| 14542 | ||
| 14543 | types[0] = ty; | |
| 14544 | types[1] = ov_ty; | |
| 14545 | values[0] = Value.@"unreachable"; | |
| 14546 | values[1] = Value.@"unreachable"; | |
| 14547 | ||
| 14548 | return tuple_ty; | |
| 14565 | const types = [2]InternPool.Index{ ty.ip_index, ov_ty.ip_index }; | |
| 14566 | const values = [2]InternPool.Index{ .none, .none }; | |
| 14567 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ | |
| 14568 | .types = &types, | |
| 14569 | .values = &values, | |
| 14570 | .names = &.{}, | |
| 14571 | } }); | |
| 14572 | return tuple_ty.toType(); | |
| 14549 | 14573 | } |
| 14550 | 14574 | |
| 14551 | 14575 | fn analyzeArithmetic( |
| ... | ... | @@ -16506,57 +16530,66 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16506 | 16530 | const layout = struct_ty.containerLayout(mod); |
| 16507 | 16531 | |
| 16508 | 16532 | const struct_field_vals = fv: { |
| 16509 | if (struct_ty.isSimpleTupleOrAnonStruct()) { | |
| 16510 | const tuple = struct_ty.tupleFields(); | |
| 16511 | const field_types = tuple.types; | |
| 16512 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); | |
| 16513 | for (struct_field_vals, 0..) |*struct_field_val, i| { | |
| 16514 | const field_ty = field_types[i]; | |
| 16515 | const name_val = v: { | |
| 16516 | var anon_decl = try block.startAnonDecl(); | |
| 16517 | defer anon_decl.deinit(); | |
| 16518 | const bytes = if (struct_ty.castTag(.anon_struct)) |payload| | |
| 16519 | try anon_decl.arena().dupeZ(u8, payload.data.names[i]) | |
| 16520 | else | |
| 16521 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | |
| 16522 | const new_decl = try anon_decl.finish( | |
| 16523 | try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod), | |
| 16524 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16525 | 0, // default alignment | |
| 16526 | ); | |
| 16527 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | |
| 16528 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16529 | .len = try mod.intValue(Type.usize, bytes.len), | |
| 16530 | }); | |
| 16531 | }; | |
| 16532 | ||
| 16533 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | |
| 16534 | const field_val = tuple.values[i]; | |
| 16535 | const is_comptime = field_val.ip_index != .unreachable_value; | |
| 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()); | |
| 16533 | const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | |
| 16534 | .anon_struct_type => |tuple| { | |
| 16535 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, tuple.types.len); | |
| 16536 | for ( | |
| 16537 | tuple.types, | |
| 16538 | tuple.values, | |
| 16539 | struct_field_vals, | |
| 16540 | 0.., | |
| 16541 | ) |field_ty, field_val, *struct_field_val, i| { | |
| 16542 | const name_val = v: { | |
| 16543 | var anon_decl = try block.startAnonDecl(); | |
| 16544 | defer anon_decl.deinit(); | |
| 16545 | const bytes = if (tuple.names.len != 0) | |
| 16546 | // https://github.com/ziglang/zig/issues/15709 | |
| 16547 | @as([]const u8, mod.intern_pool.stringToSlice(tuple.names[i])) | |
| 16548 | else | |
| 16549 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | |
| 16550 | const new_decl = try anon_decl.finish( | |
| 16551 | try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod), | |
| 16552 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16553 | 0, // default alignment | |
| 16554 | ); | |
| 16555 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | |
| 16556 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16557 | .len = try mod.intValue(Type.usize, bytes.len), | |
| 16558 | }); | |
| 16559 | }; | |
| 16556 | 16560 | |
| 16557 | for (struct_field_vals, 0..) |*field_val, i| { | |
| 16558 | const field = struct_fields.values()[i]; | |
| 16559 | const name = struct_fields.keys()[i]; | |
| 16561 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | |
| 16562 | const is_comptime = field_val != .none; | |
| 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 | 16593 | const name_val = v: { |
| 16561 | 16594 | var anon_decl = try block.startAnonDecl(); |
| 16562 | 16595 | defer anon_decl.deinit(); |
| ... | ... | @@ -18013,7 +18046,7 @@ fn zirStructInit( |
| 18013 | 18046 | try sema.requireRuntimeBlock(block, src, null); |
| 18014 | 18047 | try sema.queueFullTypeResolution(resolved_ty); |
| 18015 | 18048 | return block.addUnionInit(resolved_ty, field_index, init_inst); |
| 18016 | } else if (resolved_ty.isAnonStruct()) { | |
| 18049 | } else if (resolved_ty.isAnonStruct(mod)) { | |
| 18017 | 18050 | return sema.fail(block, src, "TODO anon struct init validation", .{}); |
| 18018 | 18051 | } |
| 18019 | 18052 | unreachable; |
| ... | ... | @@ -18034,60 +18067,54 @@ fn finishStructInit( |
| 18034 | 18067 | var root_msg: ?*Module.ErrorMsg = null; |
| 18035 | 18068 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 18036 | 18069 | |
| 18037 | if (struct_ty.isAnonStruct()) { | |
| 18038 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; | |
| 18039 | for (struct_obj.values, 0..) |default_val, i| { | |
| 18040 | 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; | |
| 18070 | switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | |
| 18071 | .anon_struct_type => |anon_struct| { | |
| 18072 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { | |
| 18073 | if (field_inits[i] != .none) continue; | |
| 18060 | 18074 | |
| 18061 | const default_val = struct_ty.structFieldDefaultValue(i, mod); | |
| 18062 | if (default_val.ip_index == .unreachable_value) { | |
| 18063 | const template = "missing tuple field with index {d}"; | |
| 18064 | if (root_msg) |msg| { | |
| 18065 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 18075 | if (default_val == .none) { | |
| 18076 | if (anon_struct.names.len == 0) { | |
| 18077 | const template = "missing tuple field with index {d}"; | |
| 18078 | if (root_msg) |msg| { | |
| 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 | 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 | } | |
| 18073 | } else { | |
| 18074 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 18075 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 18076 | if (field_inits[i] != .none) continue; | |
| 18097 | }, | |
| 18098 | .struct_type => |struct_type| { | |
| 18099 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 18100 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 18101 | if (field_inits[i] != .none) continue; | |
| 18077 | 18102 | |
| 18078 | if (field.default_val.ip_index == .unreachable_value) { | |
| 18079 | const field_name = struct_obj.fields.keys()[i]; | |
| 18080 | const template = "missing struct field: {s}"; | |
| 18081 | const args = .{field_name}; | |
| 18082 | if (root_msg) |msg| { | |
| 18083 | try sema.errNote(block, init_src, msg, template, args); | |
| 18103 | if (field.default_val.ip_index == .unreachable_value) { | |
| 18104 | const field_name = struct_obj.fields.keys()[i]; | |
| 18105 | const template = "missing struct field: {s}"; | |
| 18106 | const args = .{field_name}; | |
| 18107 | if (root_msg) |msg| { | |
| 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 | 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 | 18120 | if (root_msg) |msg| { |
| ... | ... | @@ -18159,31 +18186,33 @@ fn zirStructInitAnon( |
| 18159 | 18186 | is_ref: bool, |
| 18160 | 18187 | ) CompileError!Air.Inst.Ref { |
| 18161 | 18188 | const mod = sema.mod; |
| 18189 | const gpa = sema.gpa; | |
| 18162 | 18190 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18163 | 18191 | const src = inst_data.src(); |
| 18164 | 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); | |
| 18166 | const values = try sema.arena.alloc(Value, types.len); | |
| 18167 | var fields = std.StringArrayHashMapUnmanaged(u32){}; | |
| 18168 | defer fields.deinit(sema.gpa); | |
| 18169 | try fields.ensureUnusedCapacity(sema.gpa, types.len); | |
| 18193 | const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); | |
| 18194 | const values = try sema.arena.alloc(InternPool.Index, types.len); | |
| 18195 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); | |
| 18196 | try fields.ensureUnusedCapacity(types.len); | |
| 18170 | 18197 | |
| 18171 | 18198 | // Find which field forces the expression to be runtime, if any. |
| 18172 | 18199 | const opt_runtime_index = rs: { |
| 18173 | 18200 | var runtime_index: ?usize = null; |
| 18174 | 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 | 18204 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18177 | 18205 | extra_index = item.end; |
| 18178 | 18206 | |
| 18179 | 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 | 18210 | if (gop.found_existing) { |
| 18182 | 18211 | const msg = msg: { |
| 18183 | 18212 | const decl = sema.mod.declPtr(block.src_decl); |
| 18184 | 18213 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18185 | 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 | 18217 | const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); |
| 18189 | 18218 | try sema.errNote(block, prev_source, msg, "other field here", .{}); |
| ... | ... | @@ -18191,41 +18220,44 @@ fn zirStructInitAnon( |
| 18191 | 18220 | }; |
| 18192 | 18221 | return sema.failWithOwnedErrorMsg(msg); |
| 18193 | 18222 | } |
| 18194 | gop.value_ptr.* = @intCast(u32, i); | |
| 18223 | gop.value_ptr.* = i; | |
| 18195 | 18224 | |
| 18196 | 18225 | const init = try sema.resolveInst(item.data.init); |
| 18197 | field_ty.* = sema.typeOf(init); | |
| 18198 | if (types[i].zigTypeTag(mod) == .Opaque) { | |
| 18226 | field_ty.* = sema.typeOf(init).ip_index; | |
| 18227 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { | |
| 18199 | 18228 | const msg = msg: { |
| 18200 | 18229 | const decl = sema.mod.declPtr(block.src_decl); |
| 18201 | 18230 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18202 | 18231 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18203 | 18232 | errdefer msg.destroy(sema.gpa); |
| 18204 | 18233 | |
| 18205 | try sema.addDeclaredHereNote(msg, types[i]); | |
| 18234 | try sema.addDeclaredHereNote(msg, types[i].toType()); | |
| 18206 | 18235 | break :msg msg; |
| 18207 | 18236 | }; |
| 18208 | 18237 | return sema.failWithOwnedErrorMsg(msg); |
| 18209 | 18238 | } |
| 18210 | 18239 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18211 | values[i] = init_val; | |
| 18240 | values[i] = init_val.ip_index; | |
| 18212 | 18241 | } else { |
| 18213 | values[i] = Value.@"unreachable"; | |
| 18242 | values[i] = .none; | |
| 18214 | 18243 | runtime_index = i; |
| 18215 | 18244 | } |
| 18216 | 18245 | } |
| 18217 | 18246 | break :rs runtime_index; |
| 18218 | 18247 | }; |
| 18219 | 18248 | |
| 18220 | const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ | |
| 18221 | .names = try sema.arena.dupe([]const u8, fields.keys()), | |
| 18249 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ | |
| 18250 | .names = fields.keys(), | |
| 18222 | 18251 | .types = types, |
| 18223 | 18252 | .values = values, |
| 18224 | }); | |
| 18253 | } }); | |
| 18225 | 18254 | |
| 18226 | 18255 | const runtime_index = opt_runtime_index orelse { |
| 18227 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 18228 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | |
| 18256 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 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 | 18263 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| ... | ... | @@ -18241,7 +18273,7 @@ fn zirStructInitAnon( |
| 18241 | 18273 | if (is_ref) { |
| 18242 | 18274 | const target = sema.mod.getTarget(); |
| 18243 | 18275 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18244 | .pointee_type = tuple_ty, | |
| 18276 | .pointee_type = tuple_ty.toType(), | |
| 18245 | 18277 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18246 | 18278 | }); |
| 18247 | 18279 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | ... | @@ -18254,9 +18286,9 @@ fn zirStructInitAnon( |
| 18254 | 18286 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18255 | 18287 | .mutable = true, |
| 18256 | 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 | 18292 | const init = try sema.resolveInst(item.data.init); |
| 18261 | 18293 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18262 | 18294 | _ = try block.addBinOp(.store, field_ptr, init); |
| ... | ... | @@ -18274,7 +18306,7 @@ fn zirStructInitAnon( |
| 18274 | 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 | 18312 | fn zirArrayInit( |
| ... | ... | @@ -18400,43 +18432,47 @@ fn zirArrayInitAnon( |
| 18400 | 18432 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 18401 | 18433 | const mod = sema.mod; |
| 18402 | 18434 | |
| 18403 | const types = try sema.arena.alloc(Type, operands.len); | |
| 18404 | const values = try sema.arena.alloc(Value, operands.len); | |
| 18435 | const types = try sema.arena.alloc(InternPool.Index, operands.len); | |
| 18436 | const values = try sema.arena.alloc(InternPool.Index, operands.len); | |
| 18405 | 18437 | |
| 18406 | 18438 | const opt_runtime_src = rs: { |
| 18407 | 18439 | var runtime_src: ?LazySrcLoc = null; |
| 18408 | 18440 | for (operands, 0..) |operand, i| { |
| 18409 | 18441 | const operand_src = src; // TODO better source location |
| 18410 | 18442 | const elem = try sema.resolveInst(operand); |
| 18411 | types[i] = sema.typeOf(elem); | |
| 18412 | if (types[i].zigTypeTag(mod) == .Opaque) { | |
| 18443 | types[i] = sema.typeOf(elem).ip_index; | |
| 18444 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { | |
| 18413 | 18445 | const msg = msg: { |
| 18414 | 18446 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18415 | 18447 | errdefer msg.destroy(sema.gpa); |
| 18416 | 18448 | |
| 18417 | try sema.addDeclaredHereNote(msg, types[i]); | |
| 18449 | try sema.addDeclaredHereNote(msg, types[i].toType()); | |
| 18418 | 18450 | break :msg msg; |
| 18419 | 18451 | }; |
| 18420 | 18452 | return sema.failWithOwnedErrorMsg(msg); |
| 18421 | 18453 | } |
| 18422 | 18454 | if (try sema.resolveMaybeUndefVal(elem)) |val| { |
| 18423 | values[i] = val; | |
| 18455 | values[i] = val.ip_index; | |
| 18424 | 18456 | } else { |
| 18425 | values[i] = Value.@"unreachable"; | |
| 18457 | values[i] = .none; | |
| 18426 | 18458 | runtime_src = operand_src; |
| 18427 | 18459 | } |
| 18428 | 18460 | } |
| 18429 | 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 | 18465 | .types = types, |
| 18434 | 18466 | .values = values, |
| 18435 | }); | |
| 18467 | .names = &.{}, | |
| 18468 | } }); | |
| 18436 | 18469 | |
| 18437 | 18470 | const runtime_src = opt_runtime_src orelse { |
| 18438 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 18439 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | |
| 18471 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 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 | 18478 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -18444,7 +18480,7 @@ fn zirArrayInitAnon( |
| 18444 | 18480 | if (is_ref) { |
| 18445 | 18481 | const target = sema.mod.getTarget(); |
| 18446 | 18482 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18447 | .pointee_type = tuple_ty, | |
| 18483 | .pointee_type = tuple_ty.toType(), | |
| 18448 | 18484 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18449 | 18485 | }); |
| 18450 | 18486 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | ... | @@ -18453,9 +18489,9 @@ fn zirArrayInitAnon( |
| 18453 | 18489 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18454 | 18490 | .mutable = true, |
| 18455 | 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 | 18495 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18460 | 18496 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); |
| 18461 | 18497 | } |
| ... | ... | @@ -18469,7 +18505,7 @@ fn zirArrayInitAnon( |
| 18469 | 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 | 18511 | fn addConstantMaybeRef( |
| ... | ... | @@ -18532,15 +18568,18 @@ fn fieldType( |
| 18532 | 18568 | const resolved_ty = try sema.resolveTypeFields(cur_ty); |
| 18533 | 18569 | cur_ty = resolved_ty; |
| 18534 | 18570 | switch (cur_ty.zigTypeTag(mod)) { |
| 18535 | .Struct => { | |
| 18536 | if (cur_ty.isAnonStruct()) { | |
| 18571 | .Struct => switch (mod.intern_pool.indexToKey(cur_ty.ip_index)) { | |
| 18572 | .anon_struct_type => |anon_struct| { | |
| 18537 | 18573 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); |
| 18538 | return sema.addType(cur_ty.tupleFields().types[field_index]); | |
| 18539 | } | |
| 18540 | const struct_obj = mod.typeToStruct(cur_ty).?; | |
| 18541 | const field = struct_obj.fields.get(field_name) orelse | |
| 18542 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 18543 | return sema.addType(field.ty); | |
| 18574 | return sema.addType(anon_struct.types[field_index].toType()); | |
| 18575 | }, | |
| 18576 | .struct_type => |struct_type| { | |
| 18577 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 18578 | const field = struct_obj.fields.get(field_name) orelse | |
| 18579 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 18580 | return sema.addType(field.ty); | |
| 18581 | }, | |
| 18582 | else => unreachable, | |
| 18544 | 18583 | }, |
| 18545 | 18584 | .Union => { |
| 18546 | 18585 | const union_obj = mod.typeToUnion(cur_ty).?; |
| ... | ... | @@ -24697,7 +24736,7 @@ fn structFieldPtr( |
| 24697 | 24736 | } |
| 24698 | 24737 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24699 | 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 | 24740 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24702 | 24741 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 24703 | 24742 | } |
| ... | ... | @@ -24721,11 +24760,11 @@ fn structFieldPtrByIndex( |
| 24721 | 24760 | struct_ty: Type, |
| 24722 | 24761 | initializing: bool, |
| 24723 | 24762 | ) CompileError!Air.Inst.Ref { |
| 24724 | if (struct_ty.isAnonStruct()) { | |
| 24763 | const mod = sema.mod; | |
| 24764 | if (struct_ty.isAnonStruct(mod)) { | |
| 24725 | 24765 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); |
| 24726 | 24766 | } |
| 24727 | 24767 | |
| 24728 | const mod = sema.mod; | |
| 24729 | 24768 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 24730 | 24769 | const field = struct_obj.fields.values()[field_index]; |
| 24731 | 24770 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| ... | ... | @@ -24830,45 +24869,42 @@ fn structFieldVal( |
| 24830 | 24869 | assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); |
| 24831 | 24870 | |
| 24832 | 24871 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24833 | switch (struct_ty.ip_index) { | |
| 24834 | .empty_struct_type => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | |
| 24835 | .none => switch (struct_ty.tag()) { | |
| 24836 | .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); | |
| 24872 | switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | |
| 24873 | .struct_type => |struct_type| { | |
| 24874 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 24875 | 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 | |
| 24849 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 24850 | const field_index = @intCast(u32, field_index_usize); | |
| 24851 | const field = struct_obj.fields.values()[field_index]; | |
| 24852 | ||
| 24853 | if (field.is_comptime) { | |
| 24854 | return sema.addConstant(field.ty, field.default_val); | |
| 24855 | } | |
| 24877 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 24878 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 24879 | const field_index = @intCast(u32, field_index_usize); | |
| 24880 | const field = struct_obj.fields.values()[field_index]; | |
| 24856 | 24881 | |
| 24857 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { | |
| 24858 | if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty); | |
| 24859 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | |
| 24860 | return sema.addConstant(field.ty, opv); | |
| 24861 | } | |
| 24882 | if (field.is_comptime) { | |
| 24883 | return sema.addConstant(field.ty, field.default_val); | |
| 24884 | } | |
| 24862 | 24885 | |
| 24863 | const field_values = struct_val.castTag(.aggregate).?.data; | |
| 24864 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 24886 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { | |
| 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); | |
| 24868 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | |
| 24869 | }, | |
| 24870 | else => unreachable, | |
| 24892 | const field_values = struct_val.castTag(.aggregate).?.data; | |
| 24893 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 24894 | } | |
| 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 | 25967 | .Union => { |
| 25932 | 25968 | // pointer to anonymous struct to pointer to union |
| 25933 | 25969 | if (inst_ty.isSinglePointer(mod) and |
| 25934 | inst_ty.childType(mod).isAnonStruct() and | |
| 25970 | inst_ty.childType(mod).isAnonStruct(mod) and | |
| 25935 | 25971 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25936 | 25972 | { |
| 25937 | 25973 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | ... | @@ -25940,7 +25976,7 @@ fn coerceExtra( |
| 25940 | 25976 | .Struct => { |
| 25941 | 25977 | // pointer to anonymous struct to pointer to struct |
| 25942 | 25978 | if (inst_ty.isSinglePointer(mod) and |
| 25943 | inst_ty.childType(mod).isAnonStruct() and | |
| 25979 | inst_ty.childType(mod).isAnonStruct(mod) and | |
| 25944 | 25980 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25945 | 25981 | { |
| 25946 | 25982 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { |
| ... | ... | @@ -26231,7 +26267,7 @@ fn coerceExtra( |
| 26231 | 26267 | .Union => switch (inst_ty.zigTypeTag(mod)) { |
| 26232 | 26268 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26233 | 26269 | .Struct => { |
| 26234 | if (inst_ty.isAnonStruct()) { | |
| 26270 | if (inst_ty.isAnonStruct(mod)) { | |
| 26235 | 26271 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26236 | 26272 | } |
| 26237 | 26273 | }, |
| ... | ... | @@ -28771,8 +28807,8 @@ fn coerceAnonStructToUnion( |
| 28771 | 28807 | return sema.failWithOwnedErrorMsg(msg); |
| 28772 | 28808 | } |
| 28773 | 28809 | |
| 28774 | const anon_struct = inst_ty.castTag(.anon_struct).?.data; | |
| 28775 | const field_name = anon_struct.names[0]; | |
| 28810 | const anon_struct = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; | |
| 28811 | const field_name = mod.intern_pool.stringToSlice(anon_struct.names[0]); | |
| 28776 | 28812 | const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); |
| 28777 | 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 | 29046 | @memset(field_refs, .none); |
| 29011 | 29047 | |
| 29012 | 29048 | const inst_ty = sema.typeOf(inst); |
| 29049 | const anon_struct = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; | |
| 29013 | 29050 | var runtime_src: ?LazySrcLoc = null; |
| 29014 | const field_count = inst_ty.structFieldCount(mod); | |
| 29015 | var field_i: u32 = 0; | |
| 29016 | while (field_i < field_count) : (field_i += 1) { | |
| 29051 | for (0..anon_struct.types.len) |field_index_usize| { | |
| 29052 | const field_i = @intCast(u32, field_index_usize); | |
| 29017 | 29053 | const field_src = inst_src; // TODO better source location |
| 29018 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | |
| 29019 | payload.data.names[field_i] | |
| 29054 | const field_name = if (anon_struct.names.len != 0) | |
| 29055 | // https://github.com/ziglang/zig/issues/15709 | |
| 29056 | @as([]const u8, mod.intern_pool.stringToSlice(anon_struct.names[field_i])) | |
| 29020 | 29057 | else |
| 29021 | 29058 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); |
| 29022 | 29059 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| ... | ... | @@ -29094,21 +29131,22 @@ fn coerceTupleToTuple( |
| 29094 | 29131 | inst_src: LazySrcLoc, |
| 29095 | 29132 | ) !Air.Inst.Ref { |
| 29096 | 29133 | const mod = sema.mod; |
| 29097 | const dest_field_count = tuple_ty.structFieldCount(mod); | |
| 29098 | const field_vals = try sema.arena.alloc(Value, dest_field_count); | |
| 29134 | const dest_tuple = mod.intern_pool.indexToKey(tuple_ty.ip_index).anon_struct_type; | |
| 29135 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_tuple.types.len); | |
| 29099 | 29136 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 29100 | 29137 | @memset(field_refs, .none); |
| 29101 | 29138 | |
| 29102 | 29139 | const inst_ty = sema.typeOf(inst); |
| 29103 | const inst_field_count = inst_ty.structFieldCount(mod); | |
| 29104 | if (inst_field_count > dest_field_count) return error.NotCoercible; | |
| 29140 | const src_tuple = mod.intern_pool.indexToKey(inst_ty.ip_index).anon_struct_type; | |
| 29141 | if (src_tuple.types.len > dest_tuple.types.len) return error.NotCoercible; | |
| 29105 | 29142 | |
| 29106 | 29143 | var runtime_src: ?LazySrcLoc = null; |
| 29107 | var field_i: u32 = 0; | |
| 29108 | while (field_i < inst_field_count) : (field_i += 1) { | |
| 29144 | for (dest_tuple.types, dest_tuple.values, 0..) |field_ty, default_val, field_index_usize| { | |
| 29145 | const field_i = @intCast(u32, field_index_usize); | |
| 29109 | 29146 | const field_src = inst_src; // TODO better source location |
| 29110 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | |
| 29111 | payload.data.names[field_i] | |
| 29147 | const field_name = if (src_tuple.names.len != 0) | |
| 29148 | // https://github.com/ziglang/zig/issues/15709 | |
| 29149 | @as([]const u8, mod.intern_pool.stringToSlice(src_tuple.names[field_i])) | |
| 29112 | 29150 | else |
| 29113 | 29151 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); |
| 29114 | 29152 | |
| ... | ... | @@ -29118,23 +29156,21 @@ fn coerceTupleToTuple( |
| 29118 | 29156 | |
| 29119 | 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 | 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 | 29161 | field_refs[field_index] = coerced; |
| 29126 | if (default_val.ip_index != .unreachable_value) { | |
| 29162 | if (default_val != .none) { | |
| 29127 | 29163 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 29128 | 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 | 29168 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 29133 | 29169 | } |
| 29134 | 29170 | } |
| 29135 | 29171 | if (runtime_src == null) { |
| 29136 | 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 | 29174 | } else { |
| 29139 | 29175 | runtime_src = field_src; |
| 29140 | 29176 | } |
| ... | ... | @@ -29145,14 +29181,16 @@ fn coerceTupleToTuple( |
| 29145 | 29181 | var root_msg: ?*Module.ErrorMsg = null; |
| 29146 | 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 | 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 | 29192 | const field_src = inst_src; // TODO better source location |
| 29155 | if (default_val.ip_index == .unreachable_value) { | |
| 29193 | if (default_val == .none) { | |
| 29156 | 29194 | if (tuple_ty.isTuple(mod)) { |
| 29157 | 29195 | const template = "missing tuple field: {d}"; |
| 29158 | 29196 | if (root_msg) |msg| { |
| ... | ... | @@ -29174,7 +29212,7 @@ fn coerceTupleToTuple( |
| 29174 | 29212 | if (runtime_src == null) { |
| 29175 | 29213 | field_vals[i] = default_val; |
| 29176 | 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 | 29229 | |
| 29192 | 29230 | return sema.addConstant( |
| 29193 | 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 | 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 | 31635 | .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), |
| 31606 | 31636 | .anyframe_T => { |
| 31607 | 31637 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | ... | @@ -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 | 31733 | .union_type => |union_type| { |
| 31694 | 31734 | const union_obj = mod.unionPtr(union_type.index); |
| 31695 | 31735 | switch (union_obj.requires_comptime) { |
| ... | ... | @@ -31740,20 +31780,16 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { |
| 31740 | 31780 | return sema.resolveTypeFully(child_ty); |
| 31741 | 31781 | }, |
| 31742 | 31782 | .Struct => switch (ty.ip_index) { |
| 31743 | .none => switch (ty.tag()) { | |
| 31744 | .tuple, .anon_struct => { | |
| 31745 | const tuple = ty.tupleFields(); | |
| 31746 | ||
| 31783 | .none => {}, // TODO make this unreachable when all types are migrated to InternPool | |
| 31784 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 31785 | .struct_type => return sema.resolveStructFully(ty), | |
| 31786 | .anon_struct_type => |tuple| { | |
| 31747 | 31787 | for (tuple.types) |field_ty| { |
| 31748 | try sema.resolveTypeFully(field_ty); | |
| 31788 | try sema.resolveTypeFully(field_ty.toType()); | |
| 31749 | 31789 | } |
| 31750 | 31790 | }, |
| 31751 | 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 | 31794 | .Union => return sema.resolveUnionFully(ty), |
| 31759 | 31795 | .Array => return sema.resolveTypeFully(ty.childType(mod)), |
| ... | ... | @@ -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 | 33077 | .inferred_alloc_const => unreachable, |
| 33053 | 33078 | .inferred_alloc_mut => unreachable, |
| 33054 | 33079 | }, |
| ... | ... | @@ -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 | 33208 | const empty = try mod.intern(.{ .aggregate = .{ |
| 33155 | 33209 | .ty = ty.ip_index, |
| 33156 | 33210 | .fields = &.{}, |
| ... | ... | @@ -33647,17 +33701,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33647 | 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 | 33704 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), |
| 33662 | 33705 | .anyframe_T => { |
| 33663 | 33706 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | ... | @@ -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 | 33808 | .union_type => |union_type| { |
| 33757 | 33809 | const union_obj = mod.unionPtr(union_type.index); |
| ... | ... | @@ -33865,7 +33917,7 @@ fn structFieldIndex( |
| 33865 | 33917 | ) !u32 { |
| 33866 | 33918 | const mod = sema.mod; |
| 33867 | 33919 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 33868 | if (struct_ty.isAnonStruct()) { | |
| 33920 | if (struct_ty.isAnonStruct(mod)) { | |
| 33869 | 33921 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 33870 | 33922 | } else { |
| 33871 | 33923 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| ... | ... | @@ -33882,9 +33934,10 @@ fn anonStructFieldIndex( |
| 33882 | 33934 | field_name: []const u8, |
| 33883 | 33935 | field_src: LazySrcLoc, |
| 33884 | 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 | 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 | 33941 | return @intCast(u32, i); |
| 33889 | 33942 | } |
| 33890 | 33943 | } |
src/TypedValue.zig+10-10| ... | ... | @@ -177,13 +177,16 @@ pub fn print( |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { |
| 180 | switch (field_ptr.container_ty.tag()) { | |
| 181 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | |
| 182 | else => { | |
| 183 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index, mod); | |
| 184 | return writer.print(".{s}", .{field_name}); | |
| 180 | switch (mod.intern_pool.indexToKey(field_ptr.container_ty.ip_index)) { | |
| 181 | .anon_struct_type => |anon_struct| { | |
| 182 | if (anon_struct.names.len == 0) { | |
| 183 | return writer.print(".@\"{d}\"", .{field_ptr.field_index}); | |
| 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 | 190 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { |
| 188 | 191 | const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index]; |
| 189 | 192 | return writer.print(".{s}", .{field_name}); |
| ... | ... | @@ -396,12 +399,9 @@ fn printAggregate( |
| 396 | 399 | while (i < max_len) : (i += 1) { |
| 397 | 400 | if (i != 0) try writer.writeAll(", "); |
| 398 | 401 | switch (ty.ip_index) { |
| 399 | .none => switch (ty.tag()) { | |
| 400 | .anon_struct => try writer.print(".{s} = ", .{ty.structFieldName(i, mod)}), | |
| 401 | else => {}, | |
| 402 | }, | |
| 402 | .none => {}, // TODO make this unreachable after finishing InternPool migration | |
| 403 | 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 | 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 | 11411 | const union_obj = mod.typeToUnion(union_ty).?; |
| 11412 | 11412 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 11413 | 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 | 11415 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 11416 | 11416 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); |
| 11417 | 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 | 3417 | const op_inst = Air.refToIndex(un_op); |
| 3418 | 3418 | const op_ty = f.typeOf(un_op); |
| 3419 | 3419 | const ret_ty = if (is_ptr) op_ty.childType(mod) else op_ty; |
| 3420 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | |
| 3421 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, mod); | |
| 3420 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); | |
| 3422 | 3421 | |
| 3423 | 3422 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { |
| 3424 | 3423 | try reap(f, inst, &.{un_op}); |
| ... | ... | @@ -4115,8 +4114,7 @@ fn airCall( |
| 4115 | 4114 | } |
| 4116 | 4115 | resolved_arg.* = try f.resolveInst(arg); |
| 4117 | 4116 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { |
| 4118 | var lowered_arg_buf: LowerFnRetTyBuffer = undefined; | |
| 4119 | const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, mod); | |
| 4117 | const lowered_arg_ty = try lowerFnRetTy(arg_ty, mod); | |
| 4120 | 4118 | |
| 4121 | 4119 | const array_local = try f.allocLocal(inst, lowered_arg_ty); |
| 4122 | 4120 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -4146,8 +4144,7 @@ fn airCall( |
| 4146 | 4144 | }; |
| 4147 | 4145 | |
| 4148 | 4146 | const ret_ty = fn_ty.fnReturnType(); |
| 4149 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | |
| 4150 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, mod); | |
| 4147 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); | |
| 4151 | 4148 | |
| 4152 | 4149 | const result_local = result: { |
| 4153 | 4150 | if (modifier == .always_tail) { |
| ... | ... | @@ -5200,7 +5197,7 @@ fn fieldLocation( |
| 5200 | 5197 | const field_ty = container_ty.structFieldType(next_field_index, mod); |
| 5201 | 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 | 5201 | .{ .field = next_field_index } |
| 5205 | 5202 | else |
| 5206 | 5203 | .{ .identifier = container_ty.structFieldName(next_field_index, mod) } }; |
| ... | ... | @@ -5395,16 +5392,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5395 | 5392 | |
| 5396 | 5393 | const field_name: CValue = switch (struct_ty.ip_index) { |
| 5397 | 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 | 5395 | else => unreachable, |
| 5404 | 5396 | }, |
| 5405 | 5397 | else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 5406 | 5398 | .struct_type => switch (struct_ty.containerLayout(mod)) { |
| 5407 | .Auto, .Extern => if (struct_ty.isSimpleTuple()) | |
| 5399 | .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) | |
| 5408 | 5400 | .{ .field = extra.field_index } |
| 5409 | 5401 | else |
| 5410 | 5402 | .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, |
| ... | ... | @@ -5465,6 +5457,12 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5465 | 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 | 5466 | .union_type => |union_type| field_name: { |
| 5469 | 5467 | const union_obj = mod.unionPtr(union_type.index); |
| 5470 | 5468 | if (union_obj.layout == .Packed) { |
| ... | ... | @@ -6791,7 +6789,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6791 | 6789 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6792 | 6790 | |
| 6793 | 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 | 6793 | .{ .field = field_i } |
| 6796 | 6794 | else |
| 6797 | 6795 | .{ .identifier = inst_ty.structFieldName(field_i, mod) }); |
| ... | ... | @@ -7704,25 +7702,21 @@ const Vectorize = struct { |
| 7704 | 7702 | } |
| 7705 | 7703 | }; |
| 7706 | 7704 | |
| 7707 | const LowerFnRetTyBuffer = struct { | |
| 7708 | names: [1][]const u8, | |
| 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; | |
| 7705 | fn lowerFnRetTy(ret_ty: Type, mod: *Module) !Type { | |
| 7706 | if (ret_ty.ip_index == .noreturn_type) return Type.noreturn; | |
| 7715 | 7707 | |
| 7716 | 7708 | if (lowersToArray(ret_ty, mod)) { |
| 7717 | buffer.names = [1][]const u8{"array"}; | |
| 7718 | buffer.types = [1]Type{ret_ty}; | |
| 7719 | buffer.values = [1]Value{Value.@"unreachable"}; | |
| 7720 | buffer.payload = .{ .data = .{ | |
| 7721 | .names = &buffer.names, | |
| 7722 | .types = &buffer.types, | |
| 7723 | .values = &buffer.values, | |
| 7724 | } }; | |
| 7725 | return Type.initPayload(&buffer.payload.base); | |
| 7709 | const names = [1]InternPool.NullTerminatedString{ | |
| 7710 | try mod.intern_pool.getOrPutString(mod.gpa, "array"), | |
| 7711 | }; | |
| 7712 | const types = [1]InternPool.Index{ret_ty.ip_index}; | |
| 7713 | const values = [1]InternPool.Index{.none}; | |
| 7714 | const interned = try mod.intern(.{ .anon_struct_type = .{ | |
| 7715 | .names = &names, | |
| 7716 | .types = &types, | |
| 7717 | .values = &values, | |
| 7718 | } }); | |
| 7719 | return interned.toType(); | |
| 7726 | 7720 | } |
| 7727 | 7721 | |
| 7728 | 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 | 1951 | |
| 1952 | 1952 | defer c_field_i += 1; |
| 1953 | 1953 | fields_pl[c_field_i] = .{ |
| 1954 | .name = try if (ty.isSimpleTuple()) | |
| 1954 | .name = try if (ty.isSimpleTuple(mod)) | |
| 1955 | 1955 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) |
| 1956 | 1956 | else |
| 1957 | 1957 | arena.dupeZ(u8, switch (zig_ty_tag) { |
| ... | ... | @@ -2102,7 +2102,7 @@ pub const CType = extern union { |
| 2102 | 2102 | .payload => unreachable, |
| 2103 | 2103 | }) or !mem.eql( |
| 2104 | 2104 | u8, |
| 2105 | if (ty.isSimpleTuple()) | |
| 2105 | if (ty.isSimpleTuple(mod)) | |
| 2106 | 2106 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2107 | 2107 | else switch (zig_ty_tag) { |
| 2108 | 2108 | .Struct => ty.structFieldName(field_i, mod), |
| ... | ... | @@ -2224,7 +2224,7 @@ pub const CType = extern union { |
| 2224 | 2224 | .global => .global, |
| 2225 | 2225 | .payload => unreachable, |
| 2226 | 2226 | }); |
| 2227 | hasher.update(if (ty.isSimpleTuple()) | |
| 2227 | hasher.update(if (ty.isSimpleTuple(mod)) | |
| 2228 | 2228 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2229 | 2229 | else switch (zig_ty_tag) { |
| 2230 | 2230 | .Struct => ty.structFieldName(field_i, mod), |
src/codegen/llvm.zig+263-255| ... | ... | @@ -2009,83 +2009,84 @@ pub const Object = struct { |
| 2009 | 2009 | break :blk fwd_decl; |
| 2010 | 2010 | }; |
| 2011 | 2011 | |
| 2012 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 2013 | const tuple = ty.tupleFields(); | |
| 2014 | ||
| 2015 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 2016 | defer di_fields.deinit(gpa); | |
| 2017 | ||
| 2018 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 2019 | ||
| 2020 | comptime assert(struct_layout_version == 2); | |
| 2021 | var offset: u64 = 0; | |
| 2022 | ||
| 2023 | for (tuple.types, 0..) |field_ty, i| { | |
| 2024 | const field_val = tuple.values[i]; | |
| 2025 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2026 | ||
| 2027 | const field_size = field_ty.abiSize(mod); | |
| 2028 | const field_align = field_ty.abiAlignment(mod); | |
| 2029 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2030 | offset = field_offset + field_size; | |
| 2031 | ||
| 2032 | const field_name = if (ty.castTag(.anon_struct)) |payload| | |
| 2033 | try gpa.dupeZ(u8, payload.data.names[i]) | |
| 2034 | else | |
| 2035 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | |
| 2036 | defer gpa.free(field_name); | |
| 2012 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 2013 | .anon_struct_type => |tuple| { | |
| 2014 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 2015 | defer di_fields.deinit(gpa); | |
| 2016 | ||
| 2017 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 2018 | ||
| 2019 | comptime assert(struct_layout_version == 2); | |
| 2020 | var offset: u64 = 0; | |
| 2021 | ||
| 2022 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 2023 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 2024 | ||
| 2025 | const field_size = field_ty.toType().abiSize(mod); | |
| 2026 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 2027 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2028 | offset = field_offset + field_size; | |
| 2029 | ||
| 2030 | const field_name = if (tuple.names.len != 0) | |
| 2031 | mod.intern_pool.stringToSlice(tuple.names[i]) | |
| 2032 | else | |
| 2033 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | |
| 2034 | defer gpa.free(field_name); | |
| 2035 | ||
| 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( | |
| 2039 | fwd_decl.toScope(), | |
| 2040 | field_name, | |
| 2049 | const full_di_ty = dib.createStructType( | |
| 2050 | compile_unit_scope, | |
| 2051 | name.ptr, | |
| 2041 | 2052 | null, // file |
| 2042 | 2053 | 0, // line |
| 2043 | field_size * 8, // size in bits | |
| 2044 | field_align * 8, // align in bits | |
| 2045 | field_offset * 8, // offset in bits | |
| 2054 | ty.abiSize(mod) * 8, // size in bits | |
| 2055 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2046 | 2056 | 0, // flags |
| 2047 | try o.lowerDebugType(field_ty, .full), | |
| 2048 | )); | |
| 2049 | } | |
| 2050 | ||
| 2051 | const full_di_ty = dib.createStructType( | |
| 2052 | compile_unit_scope, | |
| 2053 | name.ptr, | |
| 2054 | null, // file | |
| 2055 | 0, // line | |
| 2056 | ty.abiSize(mod) * 8, // size in bits | |
| 2057 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2058 | 0, // flags | |
| 2059 | null, // derived from | |
| 2060 | di_fields.items.ptr, | |
| 2061 | @intCast(c_int, di_fields.items.len), | |
| 2062 | 0, // run time lang | |
| 2063 | null, // vtable holder | |
| 2064 | "", // unique id | |
| 2065 | ); | |
| 2066 | dib.replaceTemporary(fwd_decl, full_di_ty); | |
| 2067 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | |
| 2068 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | |
| 2069 | return full_di_ty; | |
| 2070 | } | |
| 2071 | ||
| 2072 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 2073 | if (!struct_obj.haveFieldTypes()) { | |
| 2074 | // This can happen if a struct type makes it all the way to | |
| 2075 | // flush() without ever being instantiated or referenced (even | |
| 2076 | // via pointer). The only reason we are hearing about it now is | |
| 2077 | // that it is being used as a namespace to put other debug types | |
| 2078 | // into. Therefore we can satisfy this by making an empty namespace, | |
| 2079 | // rather than changing the frontend to unnecessarily resolve the | |
| 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 | } | |
| 2057 | null, // derived from | |
| 2058 | di_fields.items.ptr, | |
| 2059 | @intCast(c_int, di_fields.items.len), | |
| 2060 | 0, // run time lang | |
| 2061 | null, // vtable holder | |
| 2062 | "", // unique id | |
| 2063 | ); | |
| 2064 | dib.replaceTemporary(fwd_decl, full_di_ty); | |
| 2065 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | |
| 2066 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | |
| 2067 | return full_di_ty; | |
| 2068 | }, | |
| 2069 | .struct_type => |struct_type| s: { | |
| 2070 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | |
| 2071 | ||
| 2072 | if (!struct_obj.haveFieldTypes()) { | |
| 2073 | // This can happen if a struct type makes it all the way to | |
| 2074 | // flush() without ever being instantiated or referenced (even | |
| 2075 | // via pointer). The only reason we are hearing about it now is | |
| 2076 | // that it is being used as a namespace to put other debug types | |
| 2077 | // into. Therefore we can satisfy this by making an empty namespace, | |
| 2078 | // rather than changing the frontend to unnecessarily resolve the | |
| 2079 | // struct field types. | |
| 2080 | const owner_decl_index = ty.getOwnerDecl(mod); | |
| 2081 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | |
| 2082 | dib.replaceTemporary(fwd_decl, struct_di_ty); | |
| 2083 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | |
| 2084 | // means we can't use `gop` anymore. | |
| 2085 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module }); | |
| 2086 | return struct_di_ty; | |
| 2087 | } | |
| 2088 | }, | |
| 2089 | else => {}, | |
| 2089 | 2090 | } |
| 2090 | 2091 | |
| 2091 | 2092 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| ... | ... | @@ -2931,59 +2932,61 @@ pub const DeclGen = struct { |
| 2931 | 2932 | // reference, we need to copy it here. |
| 2932 | 2933 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 2933 | 2934 | |
| 2934 | if (t.isSimpleTupleOrAnonStruct()) { | |
| 2935 | const tuple = t.tupleFields(); | |
| 2936 | const llvm_struct_ty = dg.context.structCreateNamed(""); | |
| 2937 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | |
| 2935 | const struct_type = switch (mod.intern_pool.indexToKey(t.ip_index)) { | |
| 2936 | .anon_struct_type => |tuple| { | |
| 2937 | const llvm_struct_ty = dg.context.structCreateNamed(""); | |
| 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 | defer llvm_field_types.deinit(gpa); | |
| 2940 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | |
| 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 | var offset: u64 = 0; | |
| 2946 | var big_align: u32 = 0; | |
| 2945 | comptime assert(struct_layout_version == 2); | |
| 2946 | var offset: u64 = 0; | |
| 2947 | var big_align: u32 = 0; | |
| 2947 | 2948 | |
| 2948 | for (tuple.types, 0..) |field_ty, i| { | |
| 2949 | const field_val = tuple.values[i]; | |
| 2950 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2949 | for (tuple.types, tuple.values) |field_ty, field_val| { | |
| 2950 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 2951 | 2951 | |
| 2952 | const field_align = field_ty.abiAlignment(mod); | |
| 2953 | big_align = @max(big_align, field_align); | |
| 2954 | const prev_offset = offset; | |
| 2955 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2952 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 2953 | big_align = @max(big_align, field_align); | |
| 2954 | const prev_offset = offset; | |
| 2955 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2956 | 2956 | |
| 2957 | const padding_len = offset - prev_offset; | |
| 2958 | if (padding_len > 0) { | |
| 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); | |
| 2961 | } | |
| 2962 | const field_llvm_ty = try dg.lowerType(field_ty); | |
| 2963 | try llvm_field_types.append(gpa, field_llvm_ty); | |
| 2957 | const padding_len = offset - prev_offset; | |
| 2958 | if (padding_len > 0) { | |
| 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); | |
| 2961 | } | |
| 2962 | const field_llvm_ty = try dg.lowerType(field_ty.toType()); | |
| 2963 | try llvm_field_types.append(gpa, field_llvm_ty); | |
| 2964 | 2964 | |
| 2965 | offset += field_ty.abiSize(mod); | |
| 2966 | } | |
| 2967 | { | |
| 2968 | const prev_offset = offset; | |
| 2969 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 2970 | const padding_len = offset - prev_offset; | |
| 2971 | if (padding_len > 0) { | |
| 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); | |
| 2965 | offset += field_ty.toType().abiSize(mod); | |
| 2966 | } | |
| 2967 | { | |
| 2968 | const prev_offset = offset; | |
| 2969 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 2970 | const padding_len = offset - prev_offset; | |
| 2971 | if (padding_len > 0) { | |
| 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); | |
| 2974 | } | |
| 2974 | 2975 | } |
| 2975 | } | |
| 2976 | 2976 | |
| 2977 | llvm_struct_ty.structSetBody( | |
| 2978 | llvm_field_types.items.ptr, | |
| 2979 | @intCast(c_uint, llvm_field_types.items.len), | |
| 2980 | .False, | |
| 2981 | ); | |
| 2977 | llvm_struct_ty.structSetBody( | |
| 2978 | llvm_field_types.items.ptr, | |
| 2979 | @intCast(c_uint, llvm_field_types.items.len), | |
| 2980 | .False, | |
| 2981 | ); | |
| 2982 | 2982 | |
| 2983 | return llvm_struct_ty; | |
| 2984 | } | |
| 2983 | return llvm_struct_ty; | |
| 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 | 2991 | if (struct_obj.layout == .Packed) { |
| 2989 | 2992 | assert(struct_obj.haveLayout()); |
| ... | ... | @@ -3625,71 +3628,74 @@ pub const DeclGen = struct { |
| 3625 | 3628 | const field_vals = tv.val.castTag(.aggregate).?.data; |
| 3626 | 3629 | const gpa = dg.gpa; |
| 3627 | 3630 | |
| 3628 | if (tv.ty.isSimpleTupleOrAnonStruct()) { | |
| 3629 | const tuple = tv.ty.tupleFields(); | |
| 3630 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 3631 | defer llvm_fields.deinit(gpa); | |
| 3631 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { | |
| 3632 | .anon_struct_type => |tuple| { | |
| 3633 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 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); | |
| 3636 | var offset: u64 = 0; | |
| 3637 | var big_align: u32 = 0; | |
| 3638 | var need_unnamed = false; | |
| 3638 | comptime assert(struct_layout_version == 2); | |
| 3639 | var offset: u64 = 0; | |
| 3640 | var big_align: u32 = 0; | |
| 3641 | var need_unnamed = false; | |
| 3639 | 3642 | |
| 3640 | for (tuple.types, 0..) |field_ty, i| { | |
| 3641 | if (tuple.values[i].ip_index != .unreachable_value) continue; | |
| 3642 | if (!field_ty.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 | } | |
| 3643 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3644 | if (field_val != .none) continue; | |
| 3645 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3656 | 3646 | |
| 3657 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3658 | .ty = field_ty, | |
| 3659 | .val = field_vals[i], | |
| 3660 | }); | |
| 3647 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 3648 | big_align = @max(big_align, field_align); | |
| 3649 | const prev_offset = offset; | |
| 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); | |
| 3667 | } | |
| 3668 | { | |
| 3669 | const prev_offset = offset; | |
| 3670 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3671 | const padding_len = offset - prev_offset; | |
| 3672 | if (padding_len > 0) { | |
| 3673 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3674 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3665 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); | |
| 3666 | ||
| 3667 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3668 | ||
| 3669 | offset += field_ty.toType().abiSize(mod); | |
| 3670 | } | |
| 3671 | { | |
| 3672 | const prev_offset = offset; | |
| 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) { | |
| 3679 | return dg.context.constStruct( | |
| 3680 | llvm_fields.items.ptr, | |
| 3681 | @intCast(c_uint, llvm_fields.items.len), | |
| 3682 | .False, | |
| 3683 | ); | |
| 3684 | } else { | |
| 3685 | return llvm_struct_ty.constNamedStruct( | |
| 3686 | llvm_fields.items.ptr, | |
| 3687 | @intCast(c_uint, llvm_fields.items.len), | |
| 3688 | ); | |
| 3689 | } | |
| 3690 | } | |
| 3681 | if (need_unnamed) { | |
| 3682 | return dg.context.constStruct( | |
| 3683 | llvm_fields.items.ptr, | |
| 3684 | @intCast(c_uint, llvm_fields.items.len), | |
| 3685 | .False, | |
| 3686 | ); | |
| 3687 | } else { | |
| 3688 | return llvm_struct_ty.constNamedStruct( | |
| 3689 | llvm_fields.items.ptr, | |
| 3690 | @intCast(c_uint, llvm_fields.items.len), | |
| 3691 | ); | |
| 3692 | } | |
| 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 | 3700 | if (struct_obj.layout == .Packed) { |
| 3695 | 3701 | assert(struct_obj.haveLayout()); |
| ... | ... | @@ -4077,13 +4083,11 @@ pub const DeclGen = struct { |
| 4077 | 4083 | return field_addr.constIntToPtr(final_llvm_ty); |
| 4078 | 4084 | } |
| 4079 | 4085 | |
| 4080 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 4081 | ||
| 4082 | 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 | 4088 | const indices: [2]*llvm.Value = .{ |
| 4085 | 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 | 4092 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4089 | 4093 | } else { |
| ... | ... | @@ -6006,8 +6010,7 @@ pub const FuncGen = struct { |
| 6006 | 6010 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); |
| 6007 | 6011 | }, |
| 6008 | 6012 | else => { |
| 6009 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6010 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, mod, &ptr_ty_buf).?; | |
| 6013 | const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index; | |
| 6011 | 6014 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); |
| 6012 | 6015 | }, |
| 6013 | 6016 | }, |
| ... | ... | @@ -6035,16 +6038,22 @@ pub const FuncGen = struct { |
| 6035 | 6038 | switch (struct_ty.zigTypeTag(mod)) { |
| 6036 | 6039 | .Struct => { |
| 6037 | 6040 | assert(struct_ty.containerLayout(mod) != .Packed); |
| 6038 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6039 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, mod, &ptr_ty_buf).?; | |
| 6041 | const llvm_field = llvmField(struct_ty, field_index, mod).?; | |
| 6040 | 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, ""); | |
| 6042 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | |
| 6043 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, ""); | |
| 6044 | const field_ptr_ty = try mod.ptrType(.{ | |
| 6045 | .elem_type = llvm_field.ty.ip_index, | |
| 6046 | .alignment = llvm_field.alignment, | |
| 6047 | }); | |
| 6043 | 6048 | if (isByRef(field_ty, mod)) { |
| 6044 | 6049 | if (canElideLoad(self, body_tail)) |
| 6045 | 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 | 6057 | } else { |
| 6049 | 6058 | return self.load(field_ptr, field_ptr_ty); |
| 6050 | 6059 | } |
| ... | ... | @@ -6912,12 +6921,14 @@ pub const FuncGen = struct { |
| 6912 | 6921 | const struct_ty = self.air.getRefType(ty_pl.ty); |
| 6913 | 6922 | const field_index = ty_pl.payload; |
| 6914 | 6923 | |
| 6915 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6916 | 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 | 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, ""); | |
| 6920 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | |
| 6927 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, ""); | |
| 6928 | const field_ptr_ty = try mod.ptrType(.{ | |
| 6929 | .elem_type = llvm_field.ty.ip_index, | |
| 6930 | .alignment = llvm_field.alignment, | |
| 6931 | }); | |
| 6921 | 6932 | return self.load(field_ptr, field_ptr_ty); |
| 6922 | 6933 | } |
| 6923 | 6934 | |
| ... | ... | @@ -7430,9 +7441,8 @@ pub const FuncGen = struct { |
| 7430 | 7441 | const result = self.builder.buildExtractValue(result_struct, 0, ""); |
| 7431 | 7442 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); |
| 7432 | 7443 | |
| 7433 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 7434 | const result_index = llvmFieldIndex(dest_ty, 0, mod, &ty_buf).?; | |
| 7435 | const overflow_index = llvmFieldIndex(dest_ty, 1, mod, &ty_buf).?; | |
| 7444 | const result_index = llvmField(dest_ty, 0, mod).?.index; | |
| 7445 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; | |
| 7436 | 7446 | |
| 7437 | 7447 | if (isByRef(dest_ty, mod)) { |
| 7438 | 7448 | const result_alignment = dest_ty.abiAlignment(mod); |
| ... | ... | @@ -7736,9 +7746,8 @@ pub const FuncGen = struct { |
| 7736 | 7746 | |
| 7737 | 7747 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 7738 | 7748 | |
| 7739 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 7740 | const result_index = llvmFieldIndex(dest_ty, 0, mod, &ty_buf).?; | |
| 7741 | const overflow_index = llvmFieldIndex(dest_ty, 1, mod, &ty_buf).?; | |
| 7749 | const result_index = llvmField(dest_ty, 0, mod).?.index; | |
| 7750 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; | |
| 7742 | 7751 | |
| 7743 | 7752 | if (isByRef(dest_ty, mod)) { |
| 7744 | 7753 | const result_alignment = dest_ty.abiAlignment(mod); |
| ... | ... | @@ -9300,8 +9309,6 @@ pub const FuncGen = struct { |
| 9300 | 9309 | return running_int; |
| 9301 | 9310 | } |
| 9302 | 9311 | |
| 9303 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 9304 | ||
| 9305 | 9312 | if (isByRef(result_ty, mod)) { |
| 9306 | 9313 | const llvm_u32 = self.context.intType(32); |
| 9307 | 9314 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| ... | ... | @@ -9313,7 +9320,7 @@ pub const FuncGen = struct { |
| 9313 | 9320 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9314 | 9321 | |
| 9315 | 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 | 9324 | indices[1] = llvm_u32.constInt(llvm_i, .False); |
| 9318 | 9325 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); |
| 9319 | 9326 | var field_ptr_payload: Type.Payload.Pointer = .{ |
| ... | ... | @@ -9334,7 +9341,7 @@ pub const FuncGen = struct { |
| 9334 | 9341 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9335 | 9342 | |
| 9336 | 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 | 9345 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); |
| 9339 | 9346 | } |
| 9340 | 9347 | return result; |
| ... | ... | @@ -9796,9 +9803,8 @@ pub const FuncGen = struct { |
| 9796 | 9803 | else => { |
| 9797 | 9804 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); |
| 9798 | 9805 | |
| 9799 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 9800 | if (llvmFieldIndex(struct_ty, field_index, mod, &ty_buf)) |llvm_field_index| { | |
| 9801 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field_index, ""); | |
| 9806 | if (llvmField(struct_ty, field_index, mod)) |llvm_field| { | |
| 9807 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, ""); | |
| 9802 | 9808 | } else { |
| 9803 | 9809 | // If we found no index then this means this is a zero sized field at the |
| 9804 | 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 | 10463 | }; |
| 10458 | 10464 | } |
| 10459 | 10465 | |
| 10466 | const LlvmField = struct { | |
| 10467 | index: c_uint, | |
| 10468 | ty: Type, | |
| 10469 | alignment: u32, | |
| 10470 | }; | |
| 10471 | ||
| 10460 | 10472 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 10461 | 10473 | /// field could not be found. |
| 10462 | 10474 | /// This only happens if you want the field index of a zero sized field at |
| 10463 | 10475 | /// the end of the struct. |
| 10464 | fn llvmFieldIndex( | |
| 10465 | ty: Type, | |
| 10466 | field_index: usize, | |
| 10467 | mod: *Module, | |
| 10468 | ptr_pl_buf: *Type.Payload.Pointer, | |
| 10469 | ) ?c_uint { | |
| 10476 | fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField { | |
| 10470 | 10477 | // Detects where we inserted extra padding fields so that we can skip |
| 10471 | 10478 | // over them in this function. |
| 10472 | 10479 | comptime assert(struct_layout_version == 2); |
| 10473 | 10480 | var offset: u64 = 0; |
| 10474 | 10481 | var big_align: u32 = 0; |
| 10475 | 10482 | |
| 10476 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 10477 | const tuple = ty.tupleFields(); | |
| 10478 | var llvm_field_index: c_uint = 0; | |
| 10479 | for (tuple.types, 0..) |field_ty, i| { | |
| 10480 | if (tuple.values[i].ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 10483 | const struct_type = switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 10484 | .anon_struct_type => |tuple| { | |
| 10485 | var llvm_field_index: c_uint = 0; | |
| 10486 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 10487 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 10481 | 10488 | |
| 10482 | const field_align = field_ty.abiAlignment(mod); | |
| 10483 | big_align = @max(big_align, field_align); | |
| 10484 | const prev_offset = offset; | |
| 10485 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 10489 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 10490 | big_align = @max(big_align, field_align); | |
| 10491 | const prev_offset = offset; | |
| 10492 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 10486 | 10493 | |
| 10487 | const padding_len = offset - prev_offset; | |
| 10488 | if (padding_len > 0) { | |
| 10489 | llvm_field_index += 1; | |
| 10490 | } | |
| 10494 | const padding_len = offset - prev_offset; | |
| 10495 | if (padding_len > 0) { | |
| 10496 | llvm_field_index += 1; | |
| 10497 | } | |
| 10491 | 10498 | |
| 10492 | if (field_index <= i) { | |
| 10493 | ptr_pl_buf.* = .{ | |
| 10494 | .data = .{ | |
| 10495 | .pointee_type = field_ty, | |
| 10496 | .@"align" = field_align, | |
| 10497 | .@"addrspace" = .generic, | |
| 10498 | }, | |
| 10499 | }; | |
| 10500 | return llvm_field_index; | |
| 10501 | } | |
| 10499 | if (field_index <= i) { | |
| 10500 | return .{ | |
| 10501 | .index = llvm_field_index, | |
| 10502 | .ty = field_ty.toType(), | |
| 10503 | .alignment = field_align, | |
| 10504 | }; | |
| 10505 | } | |
| 10502 | 10506 | |
| 10503 | llvm_field_index += 1; | |
| 10504 | offset += field_ty.abiSize(mod); | |
| 10505 | } | |
| 10506 | return null; | |
| 10507 | } | |
| 10508 | const layout = ty.containerLayout(mod); | |
| 10507 | llvm_field_index += 1; | |
| 10508 | offset += field_ty.toType().abiSize(mod); | |
| 10509 | } | |
| 10510 | return null; | |
| 10511 | }, | |
| 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 | 10517 | assert(layout != .Packed); |
| 10510 | 10518 | |
| 10511 | 10519 | var llvm_field_index: c_uint = 0; |
| 10512 | var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod); | |
| 10520 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 10513 | 10521 | while (it.next()) |field_and_index| { |
| 10514 | 10522 | const field = field_and_index.field; |
| 10515 | 10523 | const field_align = field.alignment(mod, layout); |
| ... | ... | @@ -10523,14 +10531,11 @@ fn llvmFieldIndex( |
| 10523 | 10531 | } |
| 10524 | 10532 | |
| 10525 | 10533 | if (field_index == field_and_index.index) { |
| 10526 | ptr_pl_buf.* = .{ | |
| 10527 | .data = .{ | |
| 10528 | .pointee_type = field.ty, | |
| 10529 | .@"align" = field_align, | |
| 10530 | .@"addrspace" = .generic, | |
| 10531 | }, | |
| 10534 | return .{ | |
| 10535 | .index = llvm_field_index, | |
| 10536 | .ty = field.ty, | |
| 10537 | .alignment = field_align, | |
| 10532 | 10538 | }; |
| 10533 | return llvm_field_index; | |
| 10534 | 10539 | } |
| 10535 | 10540 | |
| 10536 | 10541 | llvm_field_index += 1; |
| ... | ... | @@ -11089,21 +11094,24 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11089 | 11094 | .Struct => { |
| 11090 | 11095 | // Packed structs are represented to LLVM as integers. |
| 11091 | 11096 | if (ty.containerLayout(mod) == .Packed) return false; |
| 11092 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 11093 | const tuple = ty.tupleFields(); | |
| 11094 | var count: usize = 0; | |
| 11095 | for (tuple.values, 0..) |field_val, i| { | |
| 11096 | if (field_val.ip_index != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue; | |
| 11097 | ||
| 11098 | count += 1; | |
| 11099 | if (count > max_fields_byval) return true; | |
| 11100 | if (isByRef(tuple.types[i], mod)) return true; | |
| 11101 | } | |
| 11102 | return false; | |
| 11103 | } | |
| 11097 | const struct_type = switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 11098 | .anon_struct_type => |tuple| { | |
| 11099 | var count: usize = 0; | |
| 11100 | for (tuple.types, tuple.values) |field_ty, field_val| { | |
| 11101 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 11102 | ||
| 11103 | count += 1; | |
| 11104 | if (count > max_fields_byval) return true; | |
| 11105 | if (isByRef(field_ty.toType(), mod)) return true; | |
| 11106 | } | |
| 11107 | return false; | |
| 11108 | }, | |
| 11109 | .struct_type => |s| s, | |
| 11110 | else => unreachable, | |
| 11111 | }; | |
| 11112 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 11104 | 11113 | var count: usize = 0; |
| 11105 | const fields = ty.structFields(mod); | |
| 11106 | for (fields.values()) |field| { | |
| 11114 | for (struct_obj.fields.values()) |field| { | |
| 11107 | 11115 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 11108 | 11116 | |
| 11109 | 11117 | count += 1; |
src/codegen/spirv.zig+6-5| ... | ... | @@ -682,7 +682,7 @@ pub const DeclGen = struct { |
| 682 | 682 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), |
| 683 | 683 | }, |
| 684 | 684 | .Struct => { |
| 685 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 685 | if (ty.isSimpleTupleOrAnonStruct(mod)) { | |
| 686 | 686 | unreachable; // TODO |
| 687 | 687 | } else { |
| 688 | 688 | const struct_ty = mod.typeToStruct(ty).?; |
| ... | ... | @@ -1319,7 +1319,8 @@ pub const DeclGen = struct { |
| 1319 | 1319 | defer self.gpa.free(member_names); |
| 1320 | 1320 | |
| 1321 | 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 | 1324 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 1324 | 1325 | |
| 1325 | 1326 | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| ... | ... | @@ -1327,7 +1328,7 @@ pub const DeclGen = struct { |
| 1327 | 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 | 1332 | defer self.module.gpa.free(name); |
| 1332 | 1333 | |
| 1333 | 1334 | return try self.spv.resolve(.{ .struct_type = .{ |
| ... | ... | @@ -2090,7 +2091,7 @@ pub const DeclGen = struct { |
| 2090 | 2091 | |
| 2091 | 2092 | var i: usize = 0; |
| 2092 | 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 | 2095 | if (elem.isUndef(mod)) { |
| 2095 | 2096 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); |
| 2096 | 2097 | } else { |
| ... | ... | @@ -2805,7 +2806,7 @@ pub const DeclGen = struct { |
| 2805 | 2806 | const value = try self.resolve(bin_op.rhs); |
| 2806 | 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 | 2810 | if (val_is_undef) { |
| 2810 | 2811 | const undef = try self.spv.constUndef(ptr_ty_ref); |
| 2811 | 2812 | try self.store(ptr_ty, ptr, undef); |
src/link/Dwarf.zig+12-10| ... | ... | @@ -333,13 +333,12 @@ pub const DeclState = struct { |
| 333 | 333 | // DW.AT.byte_size, DW.FORM.udata |
| 334 | 334 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 335 | 335 | |
| 336 | switch (ty.tag()) { | |
| 337 | .tuple, .anon_struct => { | |
| 336 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 337 | .anon_struct_type => |fields| { | |
| 338 | 338 | // DW.AT.name, DW.FORM.string |
| 339 | 339 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 340 | 340 | |
| 341 | const fields = ty.tupleFields(); | |
| 342 | for (fields.types, 0..) |field, field_index| { | |
| 341 | for (fields.types, 0..) |field_ty, field_index| { | |
| 343 | 342 | // DW.AT.member |
| 344 | 343 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 345 | 344 | // DW.AT.name, DW.FORM.string |
| ... | ... | @@ -347,28 +346,30 @@ pub const DeclState = struct { |
| 347 | 346 | // DW.AT.type, DW.FORM.ref4 |
| 348 | 347 | var index = dbg_info_buffer.items.len; |
| 349 | 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 | 350 | // DW.AT.data_member_location, DW.FORM.udata |
| 352 | 351 | const field_off = ty.structFieldOffset(field_index, mod); |
| 353 | 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 | 357 | // DW.AT.name, DW.FORM.string |
| 358 | 358 | const struct_name = try ty.nameAllocArena(arena, mod); |
| 359 | 359 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); |
| 360 | 360 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); |
| 361 | 361 | dbg_info_buffer.appendAssumeCapacity(0); |
| 362 | 362 | |
| 363 | const struct_obj = mod.typeToStruct(ty).?; | |
| 364 | 363 | if (struct_obj.layout == .Packed) { |
| 365 | 364 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 366 | 365 | break :blk; |
| 367 | 366 | } |
| 368 | 367 | |
| 369 | const fields = ty.structFields(mod); | |
| 370 | for (fields.keys(), 0..) |field_name, field_index| { | |
| 371 | const field = fields.get(field_name).?; | |
| 368 | for ( | |
| 369 | struct_obj.fields.keys(), | |
| 370 | struct_obj.fields.values(), | |
| 371 | 0.., | |
| 372 | ) |field_name, field, field_index| { | |
| 372 | 373 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 373 | 374 | // DW.AT.member |
| 374 | 375 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| ... | ... | @@ -385,6 +386,7 @@ pub const DeclState = struct { |
| 385 | 386 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 386 | 387 | } |
| 387 | 388 | }, |
| 389 | else => unreachable, | |
| 388 | 390 | } |
| 389 | 391 | |
| 390 | 392 | // DW.AT.structure_type delimit children |
src/type.zig+238-568| ... | ... | @@ -54,10 +54,6 @@ pub const Type = struct { |
| 54 | 54 | .error_union => return .ErrorUnion, |
| 55 | 55 | |
| 56 | 56 | .anyframe_T => return .AnyFrame, |
| 57 | ||
| 58 | .tuple, | |
| 59 | .anon_struct, | |
| 60 | => return .Struct, | |
| 61 | 57 | }, |
| 62 | 58 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 63 | 59 | .int_type => return .Int, |
| ... | ... | @@ -66,7 +62,7 @@ pub const Type = struct { |
| 66 | 62 | .vector_type => return .Vector, |
| 67 | 63 | .opt_type => return .Optional, |
| 68 | 64 | .error_union_type => return .ErrorUnion, |
| 69 | .struct_type => return .Struct, | |
| 65 | .struct_type, .anon_struct_type => return .Struct, | |
| 70 | 66 | .union_type => return .Union, |
| 71 | 67 | .opaque_type => return .Opaque, |
| 72 | 68 | .enum_type => return .Enum, |
| ... | ... | @@ -465,76 +461,6 @@ pub const Type = struct { |
| 465 | 461 | if (b.zigTypeTag(mod) != .AnyFrame) return false; |
| 466 | 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 | 567 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); |
| 642 | 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 | 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 | 634 | .function => { |
| 772 | 635 | const payload = self.castTag(.function).?.data; |
| 773 | 636 | const param_types = try allocator.alloc(Type, payload.param_types.len); |
| ... | ... | @@ -935,42 +798,6 @@ pub const Type = struct { |
| 935 | 798 | ty = return_type; |
| 936 | 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 | 801 | .optional => { |
| 975 | 802 | const child_type = ty.castTag(.optional).?.data; |
| 976 | 803 | try writer.writeByte('?'); |
| ... | ... | @@ -1131,45 +958,6 @@ pub const Type = struct { |
| 1131 | 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 | 961 | .pointer => { |
| 1174 | 962 | const info = ty.ptrInfo(mod); |
| 1175 | 963 | |
| ... | ... | @@ -1335,6 +1123,27 @@ pub const Type = struct { |
| 1335 | 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 | 1148 | .union_type => |union_type| { |
| 1340 | 1149 | const union_obj = mod.unionPtr(union_type.index); |
| ... | ... | @@ -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 | 1255 | .inferred_alloc_const => unreachable, |
| 1457 | 1256 | .inferred_alloc_mut => unreachable, |
| 1458 | 1257 | }, |
| ... | ... | @@ -1567,6 +1366,13 @@ pub const Type = struct { |
| 1567 | 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 | 1377 | .union_type => |union_type| { |
| 1572 | 1378 | const union_obj = mod.unionPtr(union_type.index); |
| ... | ... | @@ -1634,8 +1440,6 @@ pub const Type = struct { |
| 1634 | 1440 | .function, |
| 1635 | 1441 | .error_union, |
| 1636 | 1442 | .anyframe_T, |
| 1637 | .tuple, | |
| 1638 | .anon_struct, | |
| 1639 | 1443 | => false, |
| 1640 | 1444 | |
| 1641 | 1445 | .inferred_alloc_mut => unreachable, |
| ... | ... | @@ -1705,6 +1509,7 @@ pub const Type = struct { |
| 1705 | 1509 | }; |
| 1706 | 1510 | return struct_obj.layout != .Auto; |
| 1707 | 1511 | }, |
| 1512 | .anon_struct_type => false, | |
| 1708 | 1513 | .union_type => |union_type| switch (union_type.runtime_tag) { |
| 1709 | 1514 | .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, |
| 1710 | 1515 | .tagged => false, |
| ... | ... | @@ -1923,26 +1728,6 @@ pub const Type = struct { |
| 1923 | 1728 | .optional => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 1924 | 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 | 1731 | .inferred_alloc_const, |
| 1947 | 1732 | .inferred_alloc_mut, |
| 1948 | 1733 | => unreachable, |
| ... | ... | @@ -2100,6 +1885,24 @@ pub const Type = struct { |
| 2100 | 1885 | } |
| 2101 | 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 | 1906 | .union_type => |union_type| { |
| 2104 | 1907 | const union_obj = mod.unionPtr(union_type.index); |
| 2105 | 1908 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| ... | ... | @@ -2287,18 +2090,6 @@ pub const Type = struct { |
| 2287 | 2090 | .inferred_alloc_const => unreachable, |
| 2288 | 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 | 2093 | .anyframe_T => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2303 | 2094 | |
| 2304 | 2095 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| ... | ... | @@ -2496,6 +2287,18 @@ pub const Type = struct { |
| 2496 | 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 | 2302 | .union_type => |union_type| { |
| 2500 | 2303 | const union_obj = mod.unionPtr(union_type.index); |
| 2501 | 2304 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| ... | ... | @@ -2609,18 +2412,6 @@ pub const Type = struct { |
| 2609 | 2412 | .inferred_alloc_const => unreachable, |
| 2610 | 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 | 2415 | .anyframe_T => return target.ptrBitWidth(), |
| 2625 | 2416 | |
| 2626 | 2417 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| ... | ... | @@ -2724,6 +2515,11 @@ pub const Type = struct { |
| 2724 | 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 | 2523 | .union_type => |union_type| { |
| 2728 | 2524 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 2729 | 2525 | if (ty.containerLayout(mod) != .Packed) { |
| ... | ... | @@ -3220,23 +3016,17 @@ pub const Type = struct { |
| 3220 | 3016 | } |
| 3221 | 3017 | |
| 3222 | 3018 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { |
| 3223 | return switch (ty.ip_index) { | |
| 3224 | .empty_struct_type => .Auto, | |
| 3225 | .none => switch (ty.tag()) { | |
| 3226 | .tuple, .anon_struct => .Auto, | |
| 3227 | else => unreachable, | |
| 3019 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 3020 | .struct_type => |struct_type| { | |
| 3021 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | |
| 3022 | return struct_obj.layout; | |
| 3228 | 3023 | }, |
| 3229 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 3230 | .struct_type => |struct_type| { | |
| 3231 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | |
| 3232 | return struct_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, | |
| 3024 | .anon_struct_type => .Auto, | |
| 3025 | .union_type => |union_type| { | |
| 3026 | const union_obj = mod.unionPtr(union_type.index); | |
| 3027 | return union_obj.layout; | |
| 3239 | 3028 | }, |
| 3029 | else => unreachable, | |
| 3240 | 3030 | }; |
| 3241 | 3031 | } |
| 3242 | 3032 | |
| ... | ... | @@ -3349,23 +3139,16 @@ pub const Type = struct { |
| 3349 | 3139 | } |
| 3350 | 3140 | |
| 3351 | 3141 | pub fn arrayLenIp(ty: Type, ip: InternPool) u64 { |
| 3352 | return switch (ty.ip_index) { | |
| 3353 | .empty_struct_type => 0, | |
| 3354 | .none => switch (ty.tag()) { | |
| 3355 | .tuple => ty.castTag(.tuple).?.data.types.len, | |
| 3356 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | |
| 3357 | ||
| 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, | |
| 3142 | return switch (ip.indexToKey(ty.ip_index)) { | |
| 3143 | .vector_type => |vector_type| vector_type.len, | |
| 3144 | .array_type => |array_type| array_type.len, | |
| 3145 | .struct_type => |struct_type| { | |
| 3146 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; | |
| 3147 | return struct_obj.fields.count(); | |
| 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 | 3157 | } |
| 3375 | 3158 | |
| 3376 | 3159 | pub fn vectorLen(ty: Type, mod: *const Module) u32 { |
| 3377 | return switch (ty.ip_index) { | |
| 3378 | .none => switch (ty.tag()) { | |
| 3379 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), | |
| 3380 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | |
| 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 | }, | |
| 3160 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 3161 | .vector_type => |vector_type| vector_type.len, | |
| 3162 | .anon_struct_type => |tuple| @intCast(u32, tuple.types.len), | |
| 3163 | else => unreachable, | |
| 3387 | 3164 | }; |
| 3388 | 3165 | } |
| 3389 | 3166 | |
| ... | ... | @@ -3391,8 +3168,6 @@ pub const Type = struct { |
| 3391 | 3168 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { |
| 3392 | 3169 | return switch (ty.ip_index) { |
| 3393 | 3170 | .none => switch (ty.tag()) { |
| 3394 | .tuple => null, | |
| 3395 | ||
| 3396 | 3171 | .pointer => ty.castTag(.pointer).?.data.sentinel, |
| 3397 | 3172 | |
| 3398 | 3173 | else => unreachable, |
| ... | ... | @@ -3400,6 +3175,7 @@ pub const Type = struct { |
| 3400 | 3175 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3401 | 3176 | .vector_type, |
| 3402 | 3177 | .struct_type, |
| 3178 | .anon_struct_type, | |
| 3403 | 3179 | => null, |
| 3404 | 3180 | |
| 3405 | 3181 | .array_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, |
| ... | ... | @@ -3486,10 +3262,12 @@ pub const Type = struct { |
| 3486 | 3262 | ty = struct_obj.backing_int_ty; |
| 3487 | 3263 | }, |
| 3488 | 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 | 3269 | .ptr_type => unreachable, |
| 3491 | 3270 | .array_type => unreachable, |
| 3492 | .vector_type => |vector_type| ty = vector_type.child.toType(), | |
| 3493 | 3271 | |
| 3494 | 3272 | .opt_type => unreachable, |
| 3495 | 3273 | .error_union_type => unreachable, |
| ... | ... | @@ -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 | 3492 | .inferred_alloc_const => unreachable, |
| 3726 | 3493 | .inferred_alloc_mut => unreachable, |
| 3727 | 3494 | }, |
| ... | ... | @@ -3810,7 +3577,33 @@ pub const Type = struct { |
| 3810 | 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 | 3607 | const empty = try mod.intern(.{ .aggregate = .{ |
| 3815 | 3608 | .ty = ty.ip_index, |
| 3816 | 3609 | .fields = &.{}, |
| ... | ... | @@ -3915,15 +3708,6 @@ pub const Type = struct { |
| 3915 | 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 | 3711 | .error_union => return ty.errorUnionPayload().comptimeOnly(mod), |
| 3928 | 3712 | .anyframe_T => { |
| 3929 | 3713 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| ... | ... | @@ -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 | 3802 | .union_type => |union_type| { |
| 4011 | 3803 | const union_obj = mod.unionPtr(union_type.index); |
| 4012 | 3804 | switch (union_obj.requires_comptime) { |
| ... | ... | @@ -4275,171 +4067,116 @@ pub const Type = struct { |
| 4275 | 4067 | } |
| 4276 | 4068 | |
| 4277 | 4069 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) []const u8 { |
| 4278 | switch (ty.ip_index) { | |
| 4279 | .none => switch (ty.tag()) { | |
| 4280 | .anon_struct => return ty.castTag(.anon_struct).?.data.names[field_index], | |
| 4281 | else => unreachable, | |
| 4070 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4071 | .struct_type => |struct_type| { | |
| 4072 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 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)) { | |
| 4284 | .struct_type => |struct_type| { | |
| 4285 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4286 | assert(struct_obj.haveFieldTypes()); | |
| 4287 | return struct_obj.fields.keys()[field_index]; | |
| 4288 | }, | |
| 4289 | else => unreachable, | |
| 4076 | .anon_struct_type => |anon_struct| { | |
| 4077 | const name = anon_struct.names[field_index]; | |
| 4078 | return mod.intern_pool.stringToSlice(name); | |
| 4290 | 4079 | }, |
| 4080 | else => unreachable, | |
| 4291 | 4081 | } |
| 4292 | 4082 | } |
| 4293 | 4083 | |
| 4294 | 4084 | pub fn structFieldCount(ty: Type, mod: *Module) usize { |
| 4295 | return switch (ty.ip_index) { | |
| 4296 | .empty_struct_type => 0, | |
| 4297 | .none => switch (ty.tag()) { | |
| 4298 | .tuple => ty.castTag(.tuple).?.data.types.len, | |
| 4299 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | |
| 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, | |
| 4085 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4086 | .struct_type => |struct_type| { | |
| 4087 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | |
| 4088 | assert(struct_obj.haveFieldTypes()); | |
| 4089 | return struct_obj.fields.count(); | |
| 4309 | 4090 | }, |
| 4091 | .anon_struct_type => |anon_struct| anon_struct.types.len, | |
| 4092 | else => unreachable, | |
| 4310 | 4093 | }; |
| 4311 | 4094 | } |
| 4312 | 4095 | |
| 4313 | 4096 | /// Supports structs and unions. |
| 4314 | 4097 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { |
| 4315 | return switch (ty.ip_index) { | |
| 4316 | .none => switch (ty.tag()) { | |
| 4317 | .tuple => return ty.castTag(.tuple).?.data.types[index], | |
| 4318 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | |
| 4319 | else => unreachable, | |
| 4098 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4099 | .struct_type => |struct_type| { | |
| 4100 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4101 | return struct_obj.fields.values()[index].ty; | |
| 4320 | 4102 | }, |
| 4321 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4322 | .struct_type => |struct_type| { | |
| 4323 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 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, | |
| 4103 | .union_type => |union_type| { | |
| 4104 | const union_obj = mod.unionPtr(union_type.index); | |
| 4105 | return union_obj.fields.values()[index].ty; | |
| 4331 | 4106 | }, |
| 4107 | .anon_struct_type => |anon_struct| anon_struct.types[index].toType(), | |
| 4108 | else => unreachable, | |
| 4332 | 4109 | }; |
| 4333 | 4110 | } |
| 4334 | 4111 | |
| 4335 | 4112 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { |
| 4336 | switch (ty.ip_index) { | |
| 4337 | .none => switch (ty.tag()) { | |
| 4338 | .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod), | |
| 4339 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod), | |
| 4340 | else => unreachable, | |
| 4113 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4114 | .struct_type => |struct_type| { | |
| 4115 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4116 | assert(struct_obj.layout != .Packed); | |
| 4117 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); | |
| 4341 | 4118 | }, |
| 4342 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4343 | .struct_type => |struct_type| { | |
| 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, | |
| 4119 | .anon_struct_type => |anon_struct| { | |
| 4120 | return anon_struct.types[index].toType().abiAlignment(mod); | |
| 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 | 4130 | pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value { |
| 4358 | switch (ty.ip_index) { | |
| 4359 | .none => switch (ty.tag()) { | |
| 4360 | .tuple => { | |
| 4361 | const tuple = ty.castTag(.tuple).?.data; | |
| 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, | |
| 4131 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4132 | .struct_type => |struct_type| { | |
| 4133 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4134 | return struct_obj.fields.values()[index].default_val; | |
| 4369 | 4135 | }, |
| 4370 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4371 | .struct_type => |struct_type| { | |
| 4372 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4373 | return struct_obj.fields.values()[index].default_val; | |
| 4374 | }, | |
| 4375 | else => unreachable, | |
| 4136 | .anon_struct_type => |anon_struct| { | |
| 4137 | const val = anon_struct.values[index]; | |
| 4138 | // TODO: avoid using `unreachable` to indicate this. | |
| 4139 | if (val == .none) return Value.@"unreachable"; | |
| 4140 | return val.toValue(); | |
| 4376 | 4141 | }, |
| 4142 | else => unreachable, | |
| 4377 | 4143 | } |
| 4378 | 4144 | } |
| 4379 | 4145 | |
| 4380 | 4146 | pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value { |
| 4381 | switch (ty.ip_index) { | |
| 4382 | .none => switch (ty.tag()) { | |
| 4383 | .tuple => { | |
| 4384 | const tuple = ty.castTag(.tuple).?.data; | |
| 4385 | const val = tuple.values[index]; | |
| 4386 | if (val.ip_index == .unreachable_value) { | |
| 4387 | return tuple.types[index].onePossibleValue(mod); | |
| 4388 | } else { | |
| 4389 | return val; | |
| 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, | |
| 4147 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4148 | .struct_type => |struct_type| { | |
| 4149 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4150 | const field = struct_obj.fields.values()[index]; | |
| 4151 | if (field.is_comptime) { | |
| 4152 | return field.default_val; | |
| 4153 | } else { | |
| 4154 | return field.ty.onePossibleValue(mod); | |
| 4155 | } | |
| 4402 | 4156 | }, |
| 4403 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4404 | .struct_type => |struct_type| { | |
| 4405 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4406 | const field = struct_obj.fields.values()[index]; | |
| 4407 | if (field.is_comptime) { | |
| 4408 | return field.default_val; | |
| 4409 | } else { | |
| 4410 | return field.ty.onePossibleValue(mod); | |
| 4411 | } | |
| 4412 | }, | |
| 4413 | else => unreachable, | |
| 4157 | .anon_struct_type => |tuple| { | |
| 4158 | const val = tuple.values[index]; | |
| 4159 | if (val == .none) { | |
| 4160 | return tuple.types[index].toType().onePossibleValue(mod); | |
| 4161 | } else { | |
| 4162 | return val.toValue(); | |
| 4163 | } | |
| 4414 | 4164 | }, |
| 4165 | else => unreachable, | |
| 4415 | 4166 | } |
| 4416 | 4167 | } |
| 4417 | 4168 | |
| 4418 | 4169 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { |
| 4419 | switch (ty.ip_index) { | |
| 4420 | .none => switch (ty.tag()) { | |
| 4421 | .tuple => { | |
| 4422 | const tuple = ty.castTag(.tuple).?.data; | |
| 4423 | const val = tuple.values[index]; | |
| 4424 | return val.ip_index != .unreachable_value; | |
| 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, | |
| 4170 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4171 | .struct_type => |struct_type| { | |
| 4172 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 4173 | if (struct_obj.layout == .Packed) return false; | |
| 4174 | const field = struct_obj.fields.values()[index]; | |
| 4175 | return field.is_comptime; | |
| 4441 | 4176 | }, |
| 4442 | } | |
| 4177 | .anon_struct_type => |anon_struct| anon_struct.values[index] != .none, | |
| 4178 | else => unreachable, | |
| 4179 | }; | |
| 4443 | 4180 | } |
| 4444 | 4181 | |
| 4445 | 4182 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { |
| ... | ... | @@ -4516,46 +4253,43 @@ pub const Type = struct { |
| 4516 | 4253 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { |
| 4517 | 4254 | switch (ty.ip_index) { |
| 4518 | 4255 | .none => switch (ty.tag()) { |
| 4519 | .tuple, .anon_struct => { | |
| 4520 | const tuple = ty.tupleFields(); | |
| 4256 | else => unreachable, | |
| 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 | 4273 | var offset: u64 = 0; |
| 4523 | 4274 | var big_align: u32 = 0; |
| 4524 | 4275 | |
| 4525 | for (tuple.types, 0..) |field_ty, i| { | |
| 4526 | const field_val = tuple.values[i]; | |
| 4527 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) { | |
| 4276 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 4277 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { | |
| 4528 | 4278 | // comptime field |
| 4529 | 4279 | if (i == index) return offset; |
| 4530 | 4280 | continue; |
| 4531 | 4281 | } |
| 4532 | 4282 | |
| 4533 | const field_align = field_ty.abiAlignment(mod); | |
| 4283 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 4534 | 4284 | big_align = @max(big_align, field_align); |
| 4535 | 4285 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 4536 | 4286 | if (i == index) return offset; |
| 4537 | offset += field_ty.abiSize(mod); | |
| 4287 | offset += field_ty.toType().abiSize(mod); | |
| 4538 | 4288 | } |
| 4539 | 4289 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); |
| 4540 | 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 | 4293 | .union_type => |union_type| { |
| 4560 | 4294 | if (!union_type.hasTag()) |
| 4561 | 4295 | return 0; |
| ... | ... | @@ -4655,10 +4389,6 @@ pub const Type = struct { |
| 4655 | 4389 | inferred_alloc_const, // See last_no_payload_tag below. |
| 4656 | 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 | 4392 | pointer, |
| 4663 | 4393 | function, |
| 4664 | 4394 | optional, |
| ... | ... | @@ -4691,8 +4421,6 @@ pub const Type = struct { |
| 4691 | 4421 | .function => Payload.Function, |
| 4692 | 4422 | .error_union => Payload.ErrorUnion, |
| 4693 | 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 | 4451 | |
| 4724 | 4452 | pub fn isTuple(ty: Type, mod: *Module) bool { |
| 4725 | 4453 | return switch (ty.ip_index) { |
| 4726 | .none => switch (ty.tag()) { | |
| 4727 | .tuple => true, | |
| 4728 | else => false, | |
| 4729 | }, | |
| 4730 | else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4454 | .none => false, | |
| 4455 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4731 | 4456 | .struct_type => |struct_type| { |
| 4732 | 4457 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; |
| 4733 | 4458 | return struct_obj.is_tuple; |
| 4734 | 4459 | }, |
| 4460 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, | |
| 4735 | 4461 | else => false, |
| 4736 | 4462 | }, |
| 4737 | 4463 | }; |
| 4738 | 4464 | } |
| 4739 | 4465 | |
| 4740 | pub fn isAnonStruct(ty: Type) bool { | |
| 4741 | return switch (ty.ip_index) { | |
| 4742 | .empty_struct_type => true, | |
| 4743 | .none => switch (ty.tag()) { | |
| 4744 | .anon_struct => true, | |
| 4745 | else => false, | |
| 4746 | }, | |
| 4466 | pub fn isAnonStruct(ty: Type, mod: *Module) bool { | |
| 4467 | if (ty.ip_index == .empty_struct_type) return true; | |
| 4468 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4469 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0, | |
| 4747 | 4470 | else => false, |
| 4748 | 4471 | }; |
| 4749 | 4472 | } |
| 4750 | 4473 | |
| 4751 | 4474 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 4752 | return switch (ty.ip_index) { | |
| 4753 | .empty_struct_type => true, | |
| 4754 | .none => switch (ty.tag()) { | |
| 4755 | .tuple, .anon_struct => true, | |
| 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, | |
| 4475 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4476 | .struct_type => |struct_type| { | |
| 4477 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 4478 | return struct_obj.is_tuple; | |
| 4774 | 4479 | }, |
| 4480 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, | |
| 4775 | 4481 | else => false, |
| 4776 | 4482 | }; |
| 4777 | 4483 | } |
| 4778 | 4484 | |
| 4779 | pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { | |
| 4780 | return switch (ty.ip_index) { | |
| 4781 | .empty_struct_type => true, | |
| 4782 | .none => switch (ty.tag()) { | |
| 4783 | .tuple, .anon_struct => true, | |
| 4784 | else => false, | |
| 4785 | }, | |
| 4485 | pub fn isSimpleTuple(ty: Type, mod: *Module) bool { | |
| 4486 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4487 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, | |
| 4786 | 4488 | else => false, |
| 4787 | 4489 | }; |
| 4788 | 4490 | } |
| 4789 | 4491 | |
| 4790 | // Only allowed for simple tuple types | |
| 4791 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { | |
| 4792 | return switch (ty.ip_index) { | |
| 4793 | .empty_struct_type => .{ .types = &.{}, .values = &.{} }, | |
| 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, | |
| 4492 | pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool { | |
| 4493 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 4494 | .anon_struct_type => true, | |
| 4495 | else => false, | |
| 4803 | 4496 | }; |
| 4804 | 4497 | } |
| 4805 | 4498 | |
| ... | ... | @@ -4947,29 +4640,6 @@ pub const Type = struct { |
| 4947 | 4640 | /// memory is owned by `Module` |
| 4948 | 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 | 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 | 1889 | const b_field_vals = b.castTag(.aggregate).?.data; |
| 1890 | 1890 | assert(a_field_vals.len == b_field_vals.len); |
| 1891 | 1891 | |
| 1892 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 1893 | const types = ty.tupleFields().types; | |
| 1894 | assert(types.len == a_field_vals.len); | |
| 1895 | for (types, 0..) |field_ty, i| { | |
| 1896 | if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, opt_sema))) { | |
| 1897 | return false; | |
| 1892 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 1893 | .anon_struct_type => |anon_struct| { | |
| 1894 | assert(anon_struct.types.len == a_field_vals.len); | |
| 1895 | for (anon_struct.types, 0..) |field_ty, i| { | |
| 1896 | if (!(try eqlAdvanced(a_field_vals[i], field_ty.toType(), b_field_vals[i], field_ty.toType(), mod, opt_sema))) { | |
| 1897 | return false; | |
| 1898 | } | |
| 1898 | 1899 | } |
| 1899 | } | |
| 1900 | return true; | |
| 1901 | } | |
| 1902 | ||
| 1903 | if (ty.zigTypeTag(mod) == .Struct) { | |
| 1904 | const fields = ty.structFields(mod).values(); | |
| 1905 | assert(fields.len == a_field_vals.len); | |
| 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))) { | |
| 1908 | return false; | |
| 1900 | return true; | |
| 1901 | }, | |
| 1902 | .struct_type => |struct_type| { | |
| 1903 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 1904 | const fields = struct_obj.fields.values(); | |
| 1905 | assert(fields.len == a_field_vals.len); | |
| 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))) { | |
| 1908 | return false; | |
| 1909 | } | |
| 1909 | 1910 | } |
| 1910 | } | |
| 1911 | return true; | |
| 1911 | return true; | |
| 1912 | }, | |
| 1913 | else => {}, | |
| 1912 | 1914 | } |
| 1913 | 1915 | |
| 1914 | 1916 | const elem_ty = ty.childType(mod); |
| ... | ... | @@ -2017,20 +2019,6 @@ pub const Value = struct { |
| 2017 | 2019 | if ((try ty.onePossibleValue(mod)) != null) { |
| 2018 | 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 | 2022 | return false; |
| 2035 | 2023 | }, |
| 2036 | 2024 | .Float => { |