| author | |
| committer | |
| log | 6a9a918fbe4adc23dd7d7573c6f1e499f4be074e |
| tree | f94c3d80a82b04a905d725689740af1d8c90dc97 |
| parent | d18881de1be811c1dff52590223b92c916c4b773 |
Anonymous structs and anonymous tuples can be stored via a
only_possible_value tag because their type encodings, by definition,
will have every value specified, which can be used to populate the
fields slice in `Key.Aggregate`.
Also fix `isTupleOrAnonStruct`.3 files changed, 52 insertions(+), 46 deletions(-)
src/InternPool.zig+33-11| ... | @@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) { | ... | @@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) { |
| 1166 | /// Module.Struct object allocated for it. | 1166 | /// Module.Struct object allocated for it. |
| 1167 | /// data is Module.Namespace.Index. | 1167 | /// data is Module.Namespace.Index. |
| 1168 | type_struct_ns, | 1168 | type_struct_ns, |
| 1169 | /// An AnonStructType which stores types, names, and values for each field. | 1169 | /// An AnonStructType which stores types, names, and values for fields. |
| 1170 | /// data is extra index of `TypeStructAnon`. | 1170 | /// data is extra index of `TypeStructAnon`. |
| 1171 | type_struct_anon, | 1171 | type_struct_anon, |
| 1172 | /// An AnonStructType which has only types and values for each field. | 1172 | /// An AnonStructType which has only types and values for fields. |
| 1173 | /// data is extra index of `TypeStructAnon`. | 1173 | /// data is extra index of `TypeStructAnon`. |
| 1174 | type_tuple_anon, | 1174 | type_tuple_anon, |
| 1175 | /// A tagged union type. | 1175 | /// A tagged union type. |
| ... | @@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) { | ... | @@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) { |
| 1272 | /// only one possible value. Not all only-possible-values are encoded this way; | 1272 | /// only one possible value. Not all only-possible-values are encoded this way; |
| 1273 | /// for example structs which have all comptime fields are not encoded this way. | 1273 | /// for example structs which have all comptime fields are not encoded this way. |
| 1274 | /// The set of values that are encoded this way is: | 1274 | /// The set of values that are encoded this way is: |
| 1275 | /// * A struct which has 0 fields. | 1275 | /// * An array or vector which has length 0. |
| 1276 | /// * A struct which has all fields comptime-known. | ||
| 1276 | /// data is Index of the type, which is known to be zero bits at runtime. | 1277 | /// data is Index of the type, which is known to be zero bits at runtime. |
| 1277 | only_possible_value, | 1278 | only_possible_value, |
| 1278 | /// data is extra index to Key.Union. | 1279 | /// data is extra index to Key.Union. |
| ... | @@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1863 | .only_possible_value => { | 1864 | .only_possible_value => { |
| 1864 | const ty = @intToEnum(Index, data); | 1865 | const ty = @intToEnum(Index, data); |
| 1865 | return switch (ip.indexToKey(ty)) { | 1866 | return switch (ip.indexToKey(ty)) { |
| 1867 | // TODO: migrate structs to properly use the InternPool rather | ||
| 1868 | // than using the SegmentedList trick, then the struct type will | ||
| 1869 | // have a slice of comptime values that can be used here for when | ||
| 1870 | // the struct has one possible value due to all fields comptime (same | ||
| 1871 | // as the tuple case below). | ||
| 1866 | .struct_type => .{ .aggregate = .{ | 1872 | .struct_type => .{ .aggregate = .{ |
| 1867 | .ty = ty, | 1873 | .ty = ty, |
| 1868 | .fields = &.{}, | 1874 | .fields = &.{}, |
| 1869 | } }, | 1875 | } }, |
| 1876 | // There is only one possible value precisely due to the | ||
| 1877 | // fact that this values slice is fully populated! | ||
| 1878 | .anon_struct_type => |anon_struct_type| .{ .aggregate = .{ | ||
| 1879 | .ty = ty, | ||
| 1880 | .fields = anon_struct_type.values, | ||
| 1881 | } }, | ||
| 1870 | else => unreachable, | 1882 | else => unreachable, |
| 1871 | }; | 1883 | }; |
| 1872 | }, | 1884 | }, |
| ... | @@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2392 | .aggregate => |aggregate| { | 2404 | .aggregate => |aggregate| { |
| 2393 | assert(aggregate.ty != .none); | 2405 | assert(aggregate.ty != .none); |
| 2394 | for (aggregate.fields) |elem| assert(elem != .none); | 2406 | 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)); | 2407 | assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty)); |
| 2402 | 2408 | ||
| 2403 | if (aggregate.fields.len == 0) { | 2409 | if (aggregate.fields.len == 0) { |
| ... | @@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2408 | return @intToEnum(Index, ip.items.len - 1); | 2414 | return @intToEnum(Index, ip.items.len - 1); |
| 2409 | } | 2415 | } |
| 2410 | 2416 | ||
| 2417 | switch (ip.indexToKey(aggregate.ty)) { | ||
| 2418 | .anon_struct_type => |anon_struct_type| { | ||
| 2419 | if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) { | ||
| 2420 | // This encoding works thanks to the fact that, as we just verified, | ||
| 2421 | // the type itself contains a slice of values that can be provided | ||
| 2422 | // in the aggregate fields. | ||
| 2423 | ip.items.appendAssumeCapacity(.{ | ||
| 2424 | .tag = .only_possible_value, | ||
| 2425 | .data = @enumToInt(aggregate.ty), | ||
| 2426 | }); | ||
| 2427 | return @intToEnum(Index, ip.items.len - 1); | ||
| 2428 | } | ||
| 2429 | }, | ||
| 2430 | else => {}, | ||
| 2431 | } | ||
| 2432 | |||
| 2411 | try ip.extra.ensureUnusedCapacity( | 2433 | try ip.extra.ensureUnusedCapacity( |
| 2412 | gpa, | 2434 | gpa, |
| 2413 | @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len, | 2435 | @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len, |
| ... | @@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { | ... | @@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3121 | } | 3143 | } |
| 3122 | }; | 3144 | }; |
| 3123 | counts.sort(SortContext{ .map = &counts }); | 3145 | counts.sort(SortContext{ .map = &counts }); |
| 3124 | const len = @min(50, counts.count()); | 3146 | const len = @min(25, counts.count()); |
| 3125 | std.debug.print(" top 50 tags:\n", .{}); | 3147 | std.debug.print(" top 25 tags:\n", .{}); |
| 3126 | for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| { | 3148 | for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| { |
| 3127 | std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{ | 3149 | std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{ |
| 3128 | @tagName(tag), stats.count, stats.bytes, | 3150 | @tagName(tag), stats.count, stats.bytes, |
src/Sema.zig+9-18| ... | @@ -18237,6 +18237,7 @@ fn zirStructInitAnon( | ... | @@ -18237,6 +18237,7 @@ fn zirStructInitAnon( |
| 18237 | return sema.failWithOwnedErrorMsg(msg); | 18237 | return sema.failWithOwnedErrorMsg(msg); |
| 18238 | } | 18238 | } |
| 18239 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { | 18239 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18240 | assert(init_val.ip_index != .none); | ||
| 18240 | values[i] = init_val.ip_index; | 18241 | values[i] = init_val.ip_index; |
| 18241 | } else { | 18242 | } else { |
| 18242 | values[i] = .none; | 18243 | values[i] = .none; |
| ... | @@ -33181,8 +33182,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -33181,8 +33182,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33181 | // TODO: this is incorrect for structs with comptime fields, I think | 33182 | // TODO: this is incorrect for structs with comptime fields, I think |
| 33182 | // we should use a temporary allocator to construct an aggregate that | 33183 | // 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 | // 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 | // This TODO is repeated in the redundant implementation of |
| 33185 | // in the redundant implementation of one-possible-value in type.zig. | 33186 | // one-possible-value in type.zig. |
| 33186 | const empty = try mod.intern(.{ .aggregate = .{ | 33187 | const empty = try mod.intern(.{ .aggregate = .{ |
| 33187 | .ty = ty.ip_index, | 33188 | .ty = ty.ip_index, |
| 33188 | .fields = &.{}, | 33189 | .fields = &.{}, |
| ... | @@ -33191,25 +33192,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -33191,25 +33192,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33191 | }, | 33192 | }, |
| 33192 | 33193 | ||
| 33193 | .anon_struct_type => |tuple| { | 33194 | .anon_struct_type => |tuple| { |
| 33194 | for (tuple.types, tuple.values) |field_ty, val| { | 33195 | for (tuple.values) |val| { |
| 33195 | const is_comptime = val != .none; | 33196 | if (val == .none) return null; |
| 33196 | if (is_comptime) continue; | ||
| 33197 | if ((try sema.typeHasOnePossibleValue(field_ty.toType())) != null) continue; | ||
| 33198 | return null; | ||
| 33199 | } | 33197 | } |
| 33200 | // In this case the struct has no runtime-known fields and | 33198 | // In this case the struct has all comptime-known fields and |
| 33201 | // therefore has one possible value. | 33199 | // therefore has one possible value. |
| 33202 | 33200 | return (try mod.intern(.{ .aggregate = .{ | |
| 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. | ||
| 33208 | const empty = try mod.intern(.{ .aggregate = .{ | ||
| 33209 | .ty = ty.ip_index, | 33201 | .ty = ty.ip_index, |
| 33210 | .fields = &.{}, | 33202 | .fields = tuple.values, |
| 33211 | } }); | 33203 | } })).toValue(); |
| 33212 | return empty.toValue(); | ||
| 33213 | }, | 33204 | }, |
| 33214 | 33205 | ||
| 33215 | .union_type => |union_type| { | 33206 | .union_type => |union_type| { |
src/type.zig+10-17| ... | @@ -3583,8 +3583,8 @@ pub const Type = struct { | ... | @@ -3583,8 +3583,8 @@ pub const Type = struct { |
| 3583 | // TODO: this is incorrect for structs with comptime fields, I think | 3583 | // TODO: this is incorrect for structs with comptime fields, I think |
| 3584 | // we should use a temporary allocator to construct an aggregate that | 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. | 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 | 3586 | // This TODO is repeated in the redundant implementation of |
| 3587 | // the redundant implementation of one-possible-value logic in Sema.zig. | 3587 | // one-possible-value logic in Sema.zig. |
| 3588 | const empty = try mod.intern(.{ .aggregate = .{ | 3588 | const empty = try mod.intern(.{ .aggregate = .{ |
| 3589 | .ty = ty.ip_index, | 3589 | .ty = ty.ip_index, |
| 3590 | .fields = &.{}, | 3590 | .fields = &.{}, |
| ... | @@ -3593,22 +3593,15 @@ pub const Type = struct { | ... | @@ -3593,22 +3593,15 @@ pub const Type = struct { |
| 3593 | }, | 3593 | }, |
| 3594 | 3594 | ||
| 3595 | .anon_struct_type => |tuple| { | 3595 | .anon_struct_type => |tuple| { |
| 3596 | for (tuple.types, tuple.values) |field_ty, val| { | 3596 | for (tuple.values) |val| { |
| 3597 | if (val != .none) continue; // comptime field | 3597 | if (val == .none) return null; |
| 3598 | if ((try field_ty.toType().onePossibleValue(mod)) != null) continue; | ||
| 3599 | return null; | ||
| 3600 | } | 3598 | } |
| 3601 | 3599 | // In this case the struct has all comptime-known fields and | |
| 3602 | // TODO: this is incorrect for structs with comptime fields, I think | 3600 | // therefore has one possible value. |
| 3603 | // we should use a temporary allocator to construct an aggregate that | 3601 | return (try mod.intern(.{ .aggregate = .{ |
| 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. | ||
| 3607 | const empty = try mod.intern(.{ .aggregate = .{ | ||
| 3608 | .ty = ty.ip_index, | 3602 | .ty = ty.ip_index, |
| 3609 | .fields = &.{}, | 3603 | .fields = tuple.values, |
| 3610 | } }); | 3604 | } })).toValue(); |
| 3611 | return empty.toValue(); | ||
| 3612 | }, | 3605 | }, |
| 3613 | 3606 | ||
| 3614 | .union_type => |union_type| { | 3607 | .union_type => |union_type| { |
| ... | @@ -4477,7 +4470,7 @@ pub const Type = struct { | ... | @@ -4477,7 +4470,7 @@ pub const Type = struct { |
| 4477 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 4470 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; |
| 4478 | return struct_obj.is_tuple; | 4471 | return struct_obj.is_tuple; |
| 4479 | }, | 4472 | }, |
| 4480 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, | 4473 | .anon_struct_type => true, |
| 4481 | else => false, | 4474 | else => false, |
| 4482 | }; | 4475 | }; |
| 4483 | } | 4476 | } |