mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 04:25:05 +00:00
stage2: encode one-possible-value tuple specially
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`.
This commit is contained in:
parent
d18881de1b
commit
6a9a918fbe
@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) {
|
||||
/// Module.Struct object allocated for it.
|
||||
/// data is Module.Namespace.Index.
|
||||
type_struct_ns,
|
||||
/// An AnonStructType which stores types, names, and values for each field.
|
||||
/// An AnonStructType which stores types, names, and values for fields.
|
||||
/// data is extra index of `TypeStructAnon`.
|
||||
type_struct_anon,
|
||||
/// An AnonStructType which has only types and values for each field.
|
||||
/// An AnonStructType which has only types and values for fields.
|
||||
/// data is extra index of `TypeStructAnon`.
|
||||
type_tuple_anon,
|
||||
/// A tagged union type.
|
||||
@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) {
|
||||
/// only one possible value. Not all only-possible-values are encoded this way;
|
||||
/// for example structs which have all comptime fields are not encoded this way.
|
||||
/// The set of values that are encoded this way is:
|
||||
/// * A struct which has 0 fields.
|
||||
/// * An array or vector which has length 0.
|
||||
/// * A struct which has all fields comptime-known.
|
||||
/// data is Index of the type, which is known to be zero bits at runtime.
|
||||
only_possible_value,
|
||||
/// data is extra index to Key.Union.
|
||||
@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
.only_possible_value => {
|
||||
const ty = @intToEnum(Index, data);
|
||||
return switch (ip.indexToKey(ty)) {
|
||||
// TODO: migrate structs to properly use the InternPool rather
|
||||
// than using the SegmentedList trick, then the struct type will
|
||||
// have a slice of comptime values that can be used here for when
|
||||
// the struct has one possible value due to all fields comptime (same
|
||||
// as the tuple case below).
|
||||
.struct_type => .{ .aggregate = .{
|
||||
.ty = ty,
|
||||
.fields = &.{},
|
||||
} },
|
||||
// There is only one possible value precisely due to the
|
||||
// fact that this values slice is fully populated!
|
||||
.anon_struct_type => |anon_struct_type| .{ .aggregate = .{
|
||||
.ty = ty,
|
||||
.fields = anon_struct_type.values,
|
||||
} },
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
.aggregate => |aggregate| {
|
||||
assert(aggregate.ty != .none);
|
||||
for (aggregate.fields) |elem| assert(elem != .none);
|
||||
if (aggregate.fields.len != ip.aggregateTypeLen(aggregate.ty)) {
|
||||
std.debug.print("aggregate fields len = {d}, type len = {d}\n", .{
|
||||
aggregate.fields.len,
|
||||
ip.aggregateTypeLen(aggregate.ty),
|
||||
});
|
||||
}
|
||||
assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty));
|
||||
|
||||
if (aggregate.fields.len == 0) {
|
||||
@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
|
||||
switch (ip.indexToKey(aggregate.ty)) {
|
||||
.anon_struct_type => |anon_struct_type| {
|
||||
if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) {
|
||||
// This encoding works thanks to the fact that, as we just verified,
|
||||
// the type itself contains a slice of values that can be provided
|
||||
// in the aggregate fields.
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .only_possible_value,
|
||||
.data = @enumToInt(aggregate.ty),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
try ip.extra.ensureUnusedCapacity(
|
||||
gpa,
|
||||
@typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len,
|
||||
@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||
}
|
||||
};
|
||||
counts.sort(SortContext{ .map = &counts });
|
||||
const len = @min(50, counts.count());
|
||||
std.debug.print(" top 50 tags:\n", .{});
|
||||
const len = @min(25, counts.count());
|
||||
std.debug.print(" top 25 tags:\n", .{});
|
||||
for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| {
|
||||
std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{
|
||||
@tagName(tag), stats.count, stats.bytes,
|
||||
|
||||
27
src/Sema.zig
27
src/Sema.zig
@ -18237,6 +18237,7 @@ fn zirStructInitAnon(
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if (try sema.resolveMaybeUndefVal(init)) |init_val| {
|
||||
assert(init_val.ip_index != .none);
|
||||
values[i] = init_val.ip_index;
|
||||
} else {
|
||||
values[i] = .none;
|
||||
@ -33181,8 +33182,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated for anon_struct_type below, as well as
|
||||
// in the redundant implementation of one-possible-value in type.zig.
|
||||
// This TODO is repeated in the redundant implementation of
|
||||
// one-possible-value in type.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.ip_index,
|
||||
.fields = &.{},
|
||||
@ -33191,25 +33192,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
},
|
||||
|
||||
.anon_struct_type => |tuple| {
|
||||
for (tuple.types, tuple.values) |field_ty, val| {
|
||||
const is_comptime = val != .none;
|
||||
if (is_comptime) continue;
|
||||
if ((try sema.typeHasOnePossibleValue(field_ty.toType())) != null) continue;
|
||||
return null;
|
||||
for (tuple.values) |val| {
|
||||
if (val == .none) return null;
|
||||
}
|
||||
// In this case the struct has no runtime-known fields and
|
||||
// In this case the struct has all comptime-known fields and
|
||||
// therefore has one possible value.
|
||||
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated for struct_type above, as well as
|
||||
// in the redundant implementation of one-possible-value in type.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.ip_index,
|
||||
.fields = &.{},
|
||||
} });
|
||||
return empty.toValue();
|
||||
.fields = tuple.values,
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
.union_type => |union_type| {
|
||||
|
||||
27
src/type.zig
27
src/type.zig
@ -3583,8 +3583,8 @@ pub const Type = struct {
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated for anon_struct_type below, as well as in
|
||||
// the redundant implementation of one-possible-value logic in Sema.zig.
|
||||
// This TODO is repeated in the redundant implementation of
|
||||
// one-possible-value logic in Sema.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.ip_index,
|
||||
.fields = &.{},
|
||||
@ -3593,22 +3593,15 @@ pub const Type = struct {
|
||||
},
|
||||
|
||||
.anon_struct_type => |tuple| {
|
||||
for (tuple.types, tuple.values) |field_ty, val| {
|
||||
if (val != .none) continue; // comptime field
|
||||
if ((try field_ty.toType().onePossibleValue(mod)) != null) continue;
|
||||
return null;
|
||||
for (tuple.values) |val| {
|
||||
if (val == .none) return null;
|
||||
}
|
||||
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated for struct_type above, as well as in
|
||||
// the redundant implementation of one-possible-value logic in Sema.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
// In this case the struct has all comptime-known fields and
|
||||
// therefore has one possible value.
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.ip_index,
|
||||
.fields = &.{},
|
||||
} });
|
||||
return empty.toValue();
|
||||
.fields = tuple.values,
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
.union_type => |union_type| {
|
||||
@ -4477,7 +4470,7 @@ pub const Type = struct {
|
||||
const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
|
||||
return struct_obj.is_tuple;
|
||||
},
|
||||
.anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,
|
||||
.anon_struct_type => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user