Commit 8ec6f730ef
Changed files (4)
src/InternPool.zig
@@ -501,6 +501,42 @@ pub const OptionalNullTerminatedString = enum(u32) {
}
};
+/// A single value captured in the closure of a namespace type. This is not a plain
+/// `Index` because we must differentiate between runtime-known values (where we
+/// store the type) and comptime-known values (where we store the value).
+pub const CaptureValue = packed struct(u32) {
+ tag: enum { @"comptime", runtime },
+ idx: u31,
+
+ pub fn wrap(val: Unwrapped) CaptureValue {
+ return switch (val) {
+ .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) },
+ .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) },
+ };
+ }
+ pub fn unwrap(val: CaptureValue) Unwrapped {
+ return switch (val.tag) {
+ .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) },
+ .runtime => .{ .runtime = @enumFromInt(val.idx) },
+ };
+ }
+
+ pub const Unwrapped = union(enum) {
+ /// Index refers to the value.
+ @"comptime": Index,
+ /// Index refers to the type.
+ runtime: Index,
+ };
+
+ pub const Slice = struct {
+ start: u32,
+ len: u32,
+ pub fn get(slice: Slice, ip: *const InternPool) []CaptureValue {
+ return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
+ }
+ };
+};
+
pub const Key = union(enum) {
int_type: IntType,
ptr_type: PtrType,
@@ -707,6 +743,7 @@ pub const Key = union(enum) {
/// This may be updated via `setTagType` later.
tag_ty: Index = .none,
zir_index: TrackedInst.Index.Optional,
+ captures: []const CaptureValue,
pub fn toEnumType(self: @This()) LoadedEnumType {
if (true) @compileError("AHHHH");
@@ -1660,6 +1697,7 @@ pub const LoadedUnionType = struct {
field_aligns: Alignment.Slice,
/// Index of the union_decl ZIR instruction.
zir_index: TrackedInst.Index.Optional,
+ captures: CaptureValue.Slice,
pub const RuntimeTag = enum(u2) {
none,
@@ -1791,24 +1829,47 @@ pub const LoadedUnionType = struct {
};
pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
- const extra_index = ip.items.items(.data)[@intFromEnum(index)];
- const type_union = ip.extraDataTrail(Tag.TypeUnion, extra_index);
+ const data = ip.items.items(.data)[@intFromEnum(index)];
+ const type_union = ip.extraDataTrail(Tag.TypeUnion, data);
const fields_len = type_union.data.fields_len;
+ var extra_index = type_union.end;
+ const captures_len = if (type_union.data.flags.any_captures) c: {
+ const len = ip.extra.items[extra_index];
+ extra_index += 1;
+ break :c len;
+ } else 0;
+
+ const captures: CaptureValue.Slice = .{
+ .start = extra_index,
+ .len = captures_len,
+ };
+ extra_index += captures_len;
+
+ const field_types: Index.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += fields_len;
+
+ const field_aligns: Alignment.Slice = if (type_union.data.flags.any_aligned_fields) a: {
+ const a: Alignment.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
+ break :a a;
+ } else .{ .start = 0, .len = 0 };
+
return .{
- .extra_index = extra_index,
+ .extra_index = data,
.decl = type_union.data.decl,
.namespace = type_union.data.namespace,
.enum_tag_ty = type_union.data.tag_ty,
- .field_types = .{
- .start = type_union.end,
- .len = fields_len,
- },
- .field_aligns = .{
- .start = type_union.end + fields_len,
- .len = if (type_union.data.flags.any_aligned_fields) fields_len else 0,
- },
+ .field_types = field_types,
+ .field_aligns = field_aligns,
.zir_index = type_union.data.zir_index,
+ .captures = captures,
};
}
@@ -1830,6 +1891,7 @@ pub const LoadedStructType = struct {
comptime_bits: ComptimeBits,
offsets: Offsets,
names_map: OptionalMapIndex,
+ captures: CaptureValue.Slice,
pub const ComptimeBits = struct {
start: u32,
@@ -2162,10 +2224,26 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
.comptime_bits = .{ .start = 0, .len = 0 },
.offsets = .{ .start = 0, .len = 0 },
.names_map = .none,
+ .captures = .{ .start = 0, .len = 0 },
};
const extra = ip.extraDataTrail(Tag.TypeStruct, item.data);
const fields_len = extra.data.fields_len;
- var extra_index = extra.end + fields_len; // skip field types
+ var extra_index = extra.end;
+ const captures_len = if (extra.data.flags.any_captures) c: {
+ const len = ip.extra.items[extra_index];
+ extra_index += 1;
+ break :c len;
+ } else 0;
+ const captures: CaptureValue.Slice = .{
+ .start = extra_index,
+ .len = captures_len,
+ };
+ extra_index += captures_len;
+ const field_types: Index.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += fields_len;
const names_map: OptionalMapIndex, const names: NullTerminatedString.Slice = if (!extra.data.flags.is_tuple) n: {
const names_map: OptionalMapIndex = @enumFromInt(ip.extra.items[extra_index]);
extra_index += 1;
@@ -2211,42 +2289,64 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
.zir_index = extra.data.zir_index,
.layout = if (extra.data.flags.is_extern) .Extern else .Auto,
.field_names = names,
- .field_types = .{ .start = extra.end, .len = fields_len },
+ .field_types = field_types,
.field_inits = inits,
.field_aligns = aligns,
.runtime_order = runtime_order,
.comptime_bits = comptime_bits,
.offsets = offsets,
.names_map = names_map,
+ .captures = captures,
};
},
.type_struct_packed, .type_struct_packed_inits => {
const extra = ip.extraDataTrail(Tag.TypeStructPacked, item.data);
const has_inits = item.tag == .type_struct_packed_inits;
const fields_len = extra.data.fields_len;
+ var extra_index = extra.end;
+ const captures_len = if (extra.data.flags.any_captures) c: {
+ const len = ip.extra.items[extra_index];
+ extra_index += 1;
+ break :c len;
+ } else 0;
+ const captures: CaptureValue.Slice = .{
+ .start = extra_index,
+ .len = captures_len,
+ };
+ extra_index += captures_len;
+ const field_types: Index.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += fields_len;
+ const field_names: NullTerminatedString.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += fields_len;
+ const field_inits: Index.Slice = if (has_inits) inits: {
+ const i: Index.Slice = .{
+ .start = extra_index,
+ .len = fields_len,
+ };
+ extra_index += fields_len;
+ break :inits i;
+ } else .{ .start = 0, .len = 0 };
return .{
.extra_index = item.data,
.decl = extra.data.decl.toOptional(),
.namespace = extra.data.namespace,
.zir_index = extra.data.zir_index,
.layout = .Packed,
- .field_names = .{
- .start = extra.end + fields_len,
- .len = fields_len,
- },
- .field_types = .{
- .start = extra.end,
- .len = fields_len,
- },
- .field_inits = if (has_inits) .{
- .start = extra.end + 2 * fields_len,
- .len = fields_len,
- } else .{ .start = 0, .len = 0 },
+ .field_names = field_names,
+ .field_types = field_types,
+ .field_inits = field_inits,
.field_aligns = .{ .start = 0, .len = 0 },
.runtime_order = .{ .start = 0, .len = 0 },
.comptime_bits = .{ .start = 0, .len = 0 },
.offsets = .{ .start = 0, .len = 0 },
.names_map = extra.data.names_map.toOptional(),
+ .captures = captures,
};
},
else => unreachable,
@@ -2273,6 +2373,7 @@ const LoadedEnumType = struct {
/// This is guaranteed to not be `.none` if explicit values are provided.
values_map: OptionalMapIndex,
zir_index: TrackedInst.Index.Optional,
+ captures: CaptureValue.Slice,
pub const TagMode = enum {
/// The integer tag type was auto-numbered by zig.
@@ -2332,7 +2433,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
.namespace = extra.data.namespace,
.tag_ty = extra.data.int_tag_type,
.names = .{
- .start = @intCast(extra.end),
+ .start = @intCast(extra.end + extra.data.captures_len),
.len = extra.data.fields_len,
},
.values = .{ .start = 0, .len = 0 },
@@ -2340,6 +2441,10 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
.names_map = extra.data.names_map,
.values_map = .none,
.zir_index = extra.data.zir_index,
+ .captures = .{
+ .start = @intCast(extra.end),
+ .len = extra.data.captures_len,
+ },
};
},
.type_enum_explicit, .type_enum_nonexhaustive => {
@@ -2349,11 +2454,11 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
.namespace = extra.data.namespace,
.tag_ty = extra.data.int_tag_type,
.names = .{
- .start = @intCast(extra.end),
+ .start = @intCast(extra.end + extra.data.captures_len),
.len = extra.data.fields_len,
},
.values = .{
- .start = @intCast(extra.end + extra.data.fields_len),
+ .start = @intCast(extra.end + extra.data.captures_len + extra.data.fields_len),
.len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
},
.tag_mode = switch (item.tag) {
@@ -2364,6 +2469,10 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
.names_map = extra.data.names_map,
.values_map = extra.data.values_map,
.zir_index = extra.data.zir_index,
+ .captures = .{
+ .start = @intCast(extra.end),
+ .len = extra.data.captures_len,
+ },
};
},
else => unreachable,
@@ -2378,12 +2487,22 @@ pub const LoadedOpaqueType = struct {
namespace: NamespaceIndex,
/// The index of the `opaque_decl` instruction.
zir_index: TrackedInst.Index.Optional,
+ captures: CaptureValue.Slice,
};
pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
assert(ip.items.items(.tag)[@intFromEnum(index)] == .type_opaque);
const extra_index = ip.items.items(.data)[@intFromEnum(index)];
- return ip.extraData(LoadedOpaqueType, extra_index);
+ const extra = ip.extraDataTrail(Tag.TypeOpaque, extra_index);
+ return .{
+ .decl = extra.data.decl,
+ .namespace = extra.data.namespace,
+ .zir_index = extra.data.zir_index,
+ .captures = .{
+ .start = extra.end,
+ .len = extra.data.captures_len,
+ },
+ };
}
pub const Item = struct {
@@ -2601,7 +2720,7 @@ pub const Index = enum(u32) {
type_enum_explicit: DataIsExtraIndexOfEnumExplicit,
type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
simple_type: struct { data: SimpleType },
- type_opaque: struct { data: *Key.OpaqueType },
+ type_opaque: struct { data: *Tag.TypeOpaque },
type_struct: struct { data: *Tag.TypeStruct },
type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
type_struct_packed: struct { data: *Tag.TypeStructPacked },
@@ -3036,7 +3155,7 @@ pub const Tag = enum(u8) {
/// data is SimpleType enum value.
simple_type,
/// An opaque type.
- /// data is index of Key.OpaqueType in extra.
+ /// data is index of Tag.TypeOpaque in extra.
type_opaque,
/// A non-packed struct type.
/// data is 0 or extra index of `TypeStruct`.
@@ -3239,7 +3358,6 @@ pub const Tag = enum(u8) {
memoized_call,
const ErrorUnionType = Key.ErrorUnionType;
- const OpaqueType = LoadedOpaqueType;
const TypeValue = Key.TypeValue;
const Error = Key.Error;
const EnumTag = Key.EnumTag;
@@ -3266,7 +3384,7 @@ pub const Tag = enum(u8) {
.type_enum_explicit => EnumExplicit,
.type_enum_nonexhaustive => EnumExplicit,
.simple_type => unreachable,
- .type_opaque => OpaqueType,
+ .type_opaque => TypeOpaque,
.type_struct => TypeStruct,
.type_struct_anon => TypeStructAnon,
.type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
@@ -3424,8 +3542,10 @@ pub const Tag = enum(u8) {
};
/// Trailing:
- /// 0. field type: Index for each field; declaration order
- /// 1. field align: Alignment for each field; declaration order
+ /// 0. captures_len: u32 // if `any_captures`
+ /// 1. capture: CaptureValue // for each `captures_len`
+ /// 2. field type: Index for each field; declaration order
+ /// 3. field align: Alignment for each field; declaration order
pub const TypeUnion = struct {
flags: Flags,
/// This could be provided through the tag type, but it is more convenient
@@ -3443,6 +3563,7 @@ pub const Tag = enum(u8) {
zir_index: TrackedInst.Index.Optional,
pub const Flags = packed struct(u32) {
+ any_captures: bool,
runtime_tag: LoadedUnionType.RuntimeTag,
/// If false, the field alignment trailing data is omitted.
any_aligned_fields: bool,
@@ -3452,14 +3573,16 @@ pub const Tag = enum(u8) {
assumed_runtime_bits: bool,
assumed_pointer_aligned: bool,
alignment: Alignment,
- _: u14 = 0,
+ _: u13 = 0,
};
};
/// Trailing:
- /// 0. type: Index for each fields_len
- /// 1. name: NullTerminatedString for each fields_len
- /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
+ /// 0. captures_len: u32 // if `any_captures`
+ /// 1. capture: CaptureValue // for each `captures_len`
+ /// 2. type: Index for each fields_len
+ /// 3. name: NullTerminatedString for each fields_len
+ /// 4. init: Index for each fields_len // if tag is type_struct_packed_inits
pub const TypeStructPacked = struct {
decl: DeclIndex,
zir_index: TrackedInst.Index.Optional,
@@ -3470,10 +3593,11 @@ pub const Tag = enum(u8) {
flags: Flags,
pub const Flags = packed struct(u32) {
+ any_captures: bool,
/// Dependency loop detection when resolving field inits.
field_inits_wip: bool,
inits_resolved: bool,
- _: u30 = 0,
+ _: u29 = 0,
};
};
@@ -3492,21 +3616,23 @@ pub const Tag = enum(u8) {
/// than coming up with some other scheme for the data.
///
/// Trailing:
- /// 0. type: Index for each field in declared order
- /// 1. if not is_tuple:
+ /// 0. captures_len: u32 // if `any_captures`
+ /// 1. capture: CaptureValue // for each `captures_len`
+ /// 2. type: Index for each field in declared order
+ /// 3. if not is_tuple:
/// names_map: MapIndex,
/// name: NullTerminatedString // for each field in declared order
- /// 2. if any_default_inits:
+ /// 4. if any_default_inits:
/// init: Index // for each field in declared order
- /// 3. if has_namespace:
+ /// 5. if has_namespace:
/// namespace: NamespaceIndex
- /// 4. if any_aligned_fields:
+ /// 6. if any_aligned_fields:
/// align: Alignment // for each field in declared order
- /// 5. if any_comptime_fields:
+ /// 7. if any_comptime_fields:
/// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
- /// 6. if not is_extern:
+ /// 8. if not is_extern:
/// field_index: RuntimeOrder // for each field in runtime order
- /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
+ /// 9. field_offset: u32 // for each field in declared order, undef until layout_resolved
pub const TypeStruct = struct {
decl: DeclIndex,
zir_index: TrackedInst.Index.Optional,
@@ -3515,6 +3641,7 @@ pub const Tag = enum(u8) {
size: u32,
pub const Flags = packed struct(u32) {
+ any_captures: bool,
is_extern: bool,
known_non_opv: bool,
requires_comptime: RequiresComptime,
@@ -3544,9 +3671,21 @@ pub const Tag = enum(u8) {
// which `layout_resolved` does not ensure.
fully_resolved: bool,
- _: u8 = 0,
+ _: u7 = 0,
};
};
+
+ /// Trailing:
+ /// 0. capture: CaptureValue // for each `captures_len`
+ pub const TypeOpaque = struct {
+ /// The opaque's owner Decl.
+ decl: DeclIndex,
+ /// Contains the declarations inside this opaque.
+ namespace: NamespaceIndex,
+ /// The index of the `opaque_decl` instruction.
+ zir_index: TrackedInst.Index.Optional,
+ captures_len: u32,
+ };
};
/// State that is mutable during semantic analysis. This data is not used for
@@ -3853,11 +3992,13 @@ pub const Array = struct {
};
/// Trailing:
-/// 0. field name: NullTerminatedString for each fields_len; declaration order
-/// 1. tag value: Index for each fields_len; declaration order
+/// 0. capture: CaptureValue // for each `captures_len`
+/// 1. field name: NullTerminatedString for each fields_len; declaration order
+/// 2. tag value: Index for each fields_len; declaration order
pub const EnumExplicit = struct {
/// The Decl that corresponds to the enum itself.
decl: DeclIndex,
+ captures_len: u32,
/// This may be `none` if there are no declarations.
namespace: OptionalNamespaceIndex,
/// An integer type which is used for the numerical value of the enum, which
@@ -3874,10 +4015,12 @@ pub const EnumExplicit = struct {
};
/// Trailing:
-/// 0. field name: NullTerminatedString for each fields_len; declaration order
+/// 0. capture: CaptureValue // for each `captures_len`
+/// 1. field name: NullTerminatedString for each fields_len; declaration order
pub const EnumAuto = struct {
/// The Decl that corresponds to the enum itself.
decl: DeclIndex,
+ captures_len: u32,
/// This may be `none` if there are no declarations.
namespace: OptionalNamespaceIndex,
/// An integer type which is used for the numerical value of the enum, which
@@ -4187,7 +4330,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.inferred_error_set_type = @enumFromInt(data),
},
- .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
+ .type_opaque => .{ .opaque_type = .{
+ .decl = ip.extraData(Tag.TypeOpaque, data).decl,
+ } },
.type_struct => .{ .struct_type = if (data == 0) .{
.decl = .none,
@@ -5497,7 +5642,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
}
pub const UnionTypeInit = struct {
- flags: Tag.TypeUnion.Flags,
+ flags: packed struct {
+ runtime_tag: LoadedUnionType.RuntimeTag,
+ any_aligned_fields: bool,
+ layout: std.builtin.Type.ContainerLayout,
+ status: LoadedUnionType.Status,
+ requires_comptime: RequiresComptime,
+ assumed_runtime_bits: bool,
+ assumed_pointer_aligned: bool,
+ alignment: Alignment,
+ },
decl: DeclIndex,
namespace: NamespaceIndex,
zir_index: TrackedInst.Index.Optional,
@@ -5509,6 +5663,7 @@ pub const UnionTypeInit = struct {
/// The logic for `any_aligned_fields` is asserted to have been done before
/// calling this function.
field_aligns: []const Alignment,
+ captures: []const CaptureValue,
};
pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!Index {
@@ -5516,12 +5671,24 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeUnion).Struct.fields.len +
+ @intFromBool(ini.captures.len != 0) + // captures_len
+ ini.captures.len + // captures
ini.fields_len + // field types
align_elements_len);
try ip.items.ensureUnusedCapacity(gpa, 1);
const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
- .flags = ini.flags,
+ .flags = .{
+ .any_captures = ini.captures.len != 0,
+ .runtime_tag = ini.flags.runtime_tag,
+ .any_aligned_fields = ini.flags.any_aligned_fields,
+ .layout = ini.flags.layout,
+ .status = ini.flags.status,
+ .requires_comptime = ini.flags.requires_comptime,
+ .assumed_runtime_bits = ini.flags.assumed_runtime_bits,
+ .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,
+ .alignment = ini.flags.alignment,
+ },
.fields_len = ini.fields_len,
.size = std.math.maxInt(u32),
.padding = std.math.maxInt(u32),
@@ -5531,6 +5698,11 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
.zir_index = ini.zir_index,
});
+ if (ini.captures.len != 0) {
+ ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
+ }
+
// field types
if (ini.field_types.len > 0) {
assert(ini.field_types.len == ini.fields_len);
@@ -5582,6 +5754,7 @@ pub const StructTypeInit = struct {
any_default_inits: bool,
inits_resolved: bool,
any_aligned_fields: bool,
+ captures: []const CaptureValue,
};
pub fn getStructType(
@@ -5605,6 +5778,8 @@ pub fn getStructType(
.Extern => true,
.Packed => {
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
+ @intFromBool(ini.captures.len != 0) + // captures_len
+ ini.captures.len + // captures
ini.fields_len + // types
ini.fields_len + // names
ini.fields_len); // inits
@@ -5618,11 +5793,16 @@ pub fn getStructType(
.backing_int_ty = .none,
.names_map = names_map,
.flags = .{
+ .any_captures = ini.captures.len != 0,
.field_inits_wip = false,
.inits_resolved = ini.inits_resolved,
},
}),
});
+ if (ini.captures.len != 0) {
+ ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
+ }
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
if (ini.any_default_inits) {
@@ -5637,6 +5817,8 @@ pub fn getStructType(
const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +
+ @intFromBool(ini.captures.len != 0) + // captures_len
+ ini.captures.len + // captures
(ini.fields_len * 5) + // types, names, inits, runtime order, offsets
align_elements_len + comptime_elements_len +
2); // names_map + namespace
@@ -5648,6 +5830,7 @@ pub fn getStructType(
.fields_len = ini.fields_len,
.size = std.math.maxInt(u32),
.flags = .{
+ .any_captures = ini.captures.len != 0,
.is_extern = is_extern,
.known_non_opv = ini.known_non_opv,
.requires_comptime = ini.requires_comptime,
@@ -5669,6 +5852,10 @@ pub fn getStructType(
},
}),
});
+ if (ini.captures.len != 0) {
+ ip.extra.appendAssumeCapacity(@intCast(ini.captures.len));
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
+ }
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
if (!ini.is_tuple) {
ip.extra.appendAssumeCapacity(@intFromEnum(names_map));
@@ -6405,11 +6592,12 @@ fn getIncompleteEnumAuto(
const names_map = try ip.addMap(gpa, enum_type.fields_len);
const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
- try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
+ try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.captures.len + enum_type.fields_len);
try ip.items.ensureUnusedCapacity(gpa, 1);
const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
.decl = enum_type.decl,
+ .captures_len = @intCast(enum_type.captures.len),
.namespace = enum_type.namespace,
.int_tag_type = int_tag_type,
.names_map = names_map,
@@ -6421,6 +6609,7 @@ fn getIncompleteEnumAuto(
.tag = .type_enum_auto,
.data = extra_index,
});
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.captures));
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
return .{
.index = @enumFromInt(ip.items.len - 1),
@@ -6455,11 +6644,12 @@ fn getIncompleteEnumExplicit(
if (enum_type.has_values) enum_type.fields_len else 0;
const extra_fields_len: u32 = @typeInfo(EnumExplicit).Struct.fields.len;
- try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + reserved_len);
+ try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.captures.len + reserved_len);
try ip.items.ensureUnusedCapacity(gpa, 1);
const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
.decl = enum_type.decl,
+ .captures_len = @intCast(enum_type.captures.len),
.namespace = enum_type.namespace,
.int_tag_type = enum_type.tag_ty,
.fields_len = enum_type.fields_len,
@@ -6472,6 +6662,7 @@ fn getIncompleteEnumExplicit(
.tag = tag,
.data = extra_index,
});
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(enum_type.captures));
// This is both fields and values (if present).
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
return .{
@@ -6492,6 +6683,7 @@ pub const GetEnumInit = struct {
values: []const Index,
tag_mode: LoadedEnumType.TagMode,
zir_index: TrackedInst.Index.Optional,
+ captures: []const CaptureValue,
};
pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
@@ -6513,11 +6705,12 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
const fields_len: u32 = @intCast(ini.names.len);
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
- fields_len);
+ ini.captures.len + fields_len);
ip.items.appendAssumeCapacity(.{
.tag = .type_enum_auto,
.data = ip.addExtraAssumeCapacity(EnumAuto{
.decl = ini.decl,
+ .captures_len = @intCast(ini.captures.len),
.namespace = ini.namespace,
.int_tag_type = ini.tag_ty,
.names_map = names_map,
@@ -6525,6 +6718,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
.zir_index = ini.zir_index,
}),
});
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
return @enumFromInt(ip.items.len - 1);
},
@@ -6533,7 +6727,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
}
}
-pub fn finishGetEnum(
+fn finishGetEnum(
ip: *InternPool,
gpa: Allocator,
ini: GetEnumInit,
@@ -6549,11 +6743,12 @@ pub fn finishGetEnum(
};
const fields_len: u32 = @intCast(ini.names.len);
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
- fields_len);
+ ini.captures.len + fields_len);
ip.items.appendAssumeCapacity(.{
.tag = tag,
.data = ip.addExtraAssumeCapacity(EnumExplicit{
.decl = ini.decl,
+ .captures_len = @intCast(ini.captures.len),
.namespace = ini.namespace,
.int_tag_type = ini.tag_ty,
.fields_len = fields_len,
@@ -6562,23 +6757,37 @@ pub fn finishGetEnum(
.zir_index = ini.zir_index,
}),
});
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
return @enumFromInt(ip.items.len - 1);
}
-pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, key: LoadedOpaqueType) Allocator.Error!Index {
+pub const OpaqueTypeIni = struct {
+ decl: DeclIndex,
+ namespace: NamespaceIndex,
+ zir_index: TrackedInst.Index.Optional,
+ captures: []const CaptureValue,
+};
+
+pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!Index {
const adapter: KeyAdapter = .{ .intern_pool = ip };
- try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(LoadedOpaqueType).Struct.fields.len);
+ try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(LoadedOpaqueType).Struct.fields.len + ini.captures.len);
try ip.items.ensureUnusedCapacity(gpa, 1);
const gop = try ip.map.getOrPutAdapted(gpa, Key{
- .opaque_type = .{ .decl = key.decl },
+ .opaque_type = .{ .decl = ini.decl },
}, adapter);
if (gop.found_existing) return @enumFromInt(gop.index);
ip.items.appendAssumeCapacity(.{
.tag = .type_opaque,
- .data = ip.addExtraAssumeCapacity(key),
+ .data = ip.addExtraAssumeCapacity(Tag.TypeOpaque{
+ .decl = ini.decl,
+ .namespace = ini.namespace,
+ .zir_index = ini.zir_index,
+ .captures_len = @intCast(ini.captures.len),
+ }),
});
+ ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.captures));
return @enumFromInt(gop.index);
}
@@ -7442,12 +7651,31 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);
},
.type_inferred_error_set => 0,
- .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
- .type_enum_auto => @sizeOf(EnumAuto),
- .type_opaque => @sizeOf(Key.OpaqueType),
+ .type_enum_explicit, .type_enum_nonexhaustive => b: {
+ const info = ip.extraData(EnumExplicit, data);
+ var ints = @typeInfo(EnumExplicit).Struct.fields.len + info.captures_len + info.fields_len;
+ if (info.values_map != .none) ints += info.fields_len;
+ break :b @sizeOf(u32) * ints;
+ },
+ .type_enum_auto => b: {
+ const info = ip.extraData(EnumAuto, data);
+ const ints = @typeInfo(EnumAuto).Struct.fields.len + info.captures_len + info.fields_len;
+ break :b @sizeOf(u32) * ints;
+ },
+ .type_opaque => b: {
+ const info = ip.extraData(Tag.TypeOpaque, data);
+ const ints = @typeInfo(Tag.TypeOpaque).Struct.fields.len + info.captures_len;
+ break :b @sizeOf(u32) * ints;
+ },
.type_struct => b: {
- const info = ip.extraData(Tag.TypeStruct, data);
+ if (data == 0) break :b 0;
+ const extra = ip.extraDataTrail(Tag.TypeStruct, data);
+ const info = extra.data;
var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;
+ if (info.flags.any_captures) {
+ const captures_len = ip.extra.items[extra.end];
+ ints += 1 + captures_len;
+ }
ints += info.fields_len; // types
if (!info.flags.is_tuple) {
ints += 1; // names_map
@@ -7470,14 +7698,24 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
},
.type_struct_packed => b: {
- const info = ip.extraData(Tag.TypeStructPacked, data);
+ const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
+ const captures_len = if (extra.data.flags.any_captures)
+ ip.extra.items[extra.end]
+ else
+ 0;
break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
- info.fields_len + info.fields_len);
+ @intFromBool(extra.data.flags.any_captures) + captures_len +
+ extra.data.fields_len * 2);
},
.type_struct_packed_inits => b: {
- const info = ip.extraData(Tag.TypeStructPacked, data);
+ const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
+ const captures_len = if (extra.data.flags.any_captures)
+ ip.extra.items[extra.end]
+ else
+ 0;
break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
- info.fields_len + info.fields_len + info.fields_len);
+ @intFromBool(extra.data.flags.any_captures) + captures_len +
+ extra.data.fields_len * 3);
},
.type_tuple_anon => b: {
const info = ip.extraData(TypeStructAnon, data);
@@ -7485,16 +7723,20 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
},
.type_union => b: {
- const info = ip.extraData(Tag.TypeUnion, data);
- const enum_info = ip.loadEnumType(info.tag_ty);
- const fields_len: u32 = @intCast(enum_info.names.len);
+ const extra = ip.extraDataTrail(Tag.TypeUnion, data);
+ const captures_len = if (extra.data.flags.any_captures)
+ ip.extra.items[extra.end]
+ else
+ 0;
const per_field = @sizeOf(u32); // field type
// 1 byte per field for alignment, rounded up to the nearest 4 bytes
- const alignments = if (info.flags.any_aligned_fields)
- ((fields_len + 3) / 4) * 4
+ const alignments = if (extra.data.flags.any_aligned_fields)
+ ((extra.data.fields_len + 3) / 4) * 4
else
0;
- break :b @sizeOf(Tag.TypeUnion) + (fields_len * per_field) + alignments;
+ break :b @sizeOf(Tag.TypeUnion) +
+ 4 * (@intFromBool(extra.data.flags.any_captures) + captures_len) +
+ (extra.data.fields_len * per_field) + alignments;
},
.type_function => b: {
@@ -7802,7 +8044,6 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)
.parent = undefined,
.file_scope = undefined,
.decl_index = undefined,
- .captures = undefined,
};
ip.namespaces_free_list.append(gpa, index) catch {
// In order to keep `destroyNamespace` a non-fallible function, we ignore memory
src/Module.zig
@@ -761,37 +761,6 @@ pub const Namespace = struct {
/// the Decl Value has to be resolved as a Type which has a Namespace.
/// Value is whether the usingnamespace decl is marked `pub`.
usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{},
- /// Allocated into `gpa`.
- /// The ordered set of values captured in this type's closure.
- /// `closure_get` instructions look up values in this list.
- captures: []CaptureValue,
-
- /// A single value captured in a container's closure. This is not an
- /// `InternPool.Index` so we can differentiate between runtime-known values
- /// (where only the type is comptime-known) and comptime-known values.
- pub const CaptureValue = enum(u32) {
- _,
- pub const Unwrapped = union(enum) {
- /// Index refers to the value.
- @"comptime": InternPool.Index,
- /// Index refers to the type.
- runtime: InternPool.Index,
- };
- pub fn wrap(val: Unwrapped) CaptureValue {
- return switch (val) {
- .@"comptime" => |i| @enumFromInt(@intFromEnum(i)),
- .runtime => |i| @enumFromInt((1 << 31) | @intFromEnum(i)),
- };
- }
- pub fn unwrap(val: CaptureValue) Unwrapped {
- const tag: u1 = @intCast(@intFromEnum(val) >> 31);
- const raw = @intFromEnum(val);
- return switch (tag) {
- 0 => .{ .@"comptime" = @enumFromInt(raw) },
- 1 => .{ .runtime = @enumFromInt(@as(u31, @truncate(raw))) },
- };
- }
- };
const Index = InternPool.NamespaceIndex;
const OptionalIndex = InternPool.OptionalNamespaceIndex;
@@ -2130,7 +2099,6 @@ pub fn deinit(zcu: *Zcu) void {
while (it.next()) |namespace| {
namespace.decls.deinit(gpa);
namespace.usingnamespace_set.deinit(gpa);
- gpa.free(namespace.captures);
}
}
@@ -3354,7 +3322,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
.parent = .none,
.decl_index = undefined,
.file_scope = file,
- .captures = &.{},
});
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index);
src/Sema.zig
@@ -2670,28 +2670,27 @@ fn analyzeAsInt(
}
/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
-/// resolves this into a list of `Namespace.CaptureValue` allocated by `gpa`.
-/// Caller owns returned memory.
-fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_index: usize, captures_len: u32) ![]Namespace.CaptureValue {
- const gpa = sema.gpa;
- const parent_captures: []const Namespace.CaptureValue = if (parent_namespace) |p| parent: {
- break :parent sema.mod.namespacePtr(p).captures;
- } else &.{};
+/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
+fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
+ const zcu = sema.mod;
+ const ip = &zcu.intern_pool;
+ const parent_captures: InternPool.CaptureValue.Slice = if (parent_namespace) |p| parent: {
+ break :parent zcu.namespacePtr(p).ty.getCaptures(zcu);
+ } else undefined; // never used so `undefined` is safe
- const captures = try gpa.alloc(Namespace.CaptureValue, captures_len);
- errdefer gpa.free(captures);
+ const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| {
const zir_capture: Zir.Inst.Capture = @enumFromInt(raw);
capture.* = switch (zir_capture.unwrap()) {
- .inst => |inst| Namespace.CaptureValue.wrap(capture: {
+ .inst => |inst| InternPool.CaptureValue.wrap(capture: {
const air_ref = try sema.resolveInst(inst.toRef());
if (try sema.resolveValue(air_ref)) |val| {
break :capture .{ .@"comptime" = val.toIntern() };
}
break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
}),
- .nested => |parent_idx| parent_captures[parent_idx],
+ .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
};
}
@@ -2731,7 +2730,7 @@ pub fn getStructType(
break :blk decls_len;
} else 0;
- mod.namespacePtr(namespace).captures = try sema.getCaptures(parent_namespace, extra_index, captures_len);
+ const captures = try sema.getCaptures(parent_namespace, extra_index, captures_len);
extra_index += captures_len;
if (small.has_backing_int) {
@@ -2761,6 +2760,7 @@ pub fn getStructType(
.any_comptime_fields = small.any_comptime_fields,
.inits_resolved = false,
.any_aligned_fields = small.any_aligned_fields,
+ .captures = captures,
});
return ty;
@@ -2801,7 +2801,6 @@ fn zirStructDecl(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = &.{}, // Will be set by `getStructType`
});
errdefer mod.destroyNamespace(new_namespace_index);
@@ -2997,7 +2996,6 @@ fn zirEnumDecl(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = captures,
});
errdefer if (!done) mod.destroyNamespace(new_namespace_index);
@@ -3029,6 +3027,7 @@ fn zirEnumDecl(
else
.explicit,
.zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
+ .captures = captures,
});
if (sema.builtin_type_target_index != .none) {
mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
@@ -3261,7 +3260,6 @@ fn zirUnionDecl(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = captures,
});
errdefer mod.destroyNamespace(new_namespace_index);
@@ -3291,6 +3289,7 @@ fn zirUnionDecl(
.enum_tag_ty = .none,
.field_types = &.{},
.field_aligns = &.{},
+ .captures = captures,
});
if (sema.builtin_type_target_index != .none) {
mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
@@ -3367,7 +3366,6 @@ fn zirOpaqueDecl(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = captures,
});
errdefer mod.destroyNamespace(new_namespace_index);
@@ -3375,6 +3373,7 @@ fn zirOpaqueDecl(
.decl = new_decl_index,
.namespace = new_namespace_index,
.zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
+ .captures = captures,
});
// TODO: figure out InternPool removals for incremental compilation
//errdefer mod.intern_pool.remove(opaque_ty);
@@ -17287,12 +17286,13 @@ fn zirThis(
fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const mod = sema.mod;
- const captures = mod.namespacePtr(block.namespace).captures;
+ const ip = &mod.intern_pool;
+ const captures = mod.namespacePtr(block.namespace).ty.getCaptures(mod);
const src_node: i32 = @bitCast(extended.operand);
const src = LazySrcLoc.nodeOffset(src_node);
- const capture_ty = switch (captures[extended.small].unwrap()) {
+ const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) {
.@"comptime" => |index| return Air.internedToRef(index),
.runtime => |index| index,
};
@@ -21360,6 +21360,7 @@ fn zirReify(
.explicit,
.tag_ty = int_tag_ty.toIntern(),
.zir_index = .none,
+ .captures = &.{},
});
// TODO: figure out InternPool removals for incremental compilation
//errdefer ip.remove(incomplete_enum.index);
@@ -21450,7 +21451,6 @@ fn zirReify(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = &.{},
});
errdefer mod.destroyNamespace(new_namespace_index);
@@ -21458,6 +21458,7 @@ fn zirReify(
.decl = new_decl_index,
.namespace = new_namespace_index,
.zir_index = .none,
+ .captures = &.{},
});
// TODO: figure out InternPool removals for incremental compilation
//errdefer ip.remove(opaque_ty);
@@ -21659,7 +21660,6 @@ fn zirReify(
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- .captures = &.{},
});
errdefer mod.destroyNamespace(new_namespace_index);
@@ -21688,6 +21688,7 @@ fn zirReify(
},
.field_types = union_fields.items(.type),
.field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{},
+ .captures = &.{},
});
new_decl.ty = Type.type;
@@ -21849,6 +21850,7 @@ fn reifyStruct(
.any_default_inits = true,
.inits_resolved = true,
.any_aligned_fields = true,
+ .captures = &.{},
});
// TODO: figure out InternPool removals for incremental compilation
//errdefer ip.remove(ty);
@@ -37404,6 +37406,7 @@ fn generateUnionTagTypeNumbered(
.values = enum_field_vals,
.tag_mode = .explicit,
.zir_index = .none,
+ .captures = &.{},
});
new_decl.ty = Type.type;
@@ -37455,6 +37458,7 @@ fn generateUnionTagTypeSimple(
.values = &.{},
.tag_mode = .auto,
.zir_index = .none,
+ .captures = &.{},
});
const new_decl = mod.declPtr(new_decl_index);
src/type.zig
@@ -3294,6 +3294,18 @@ pub const Type = struct {
};
}
+ /// Given a namespace type, returns its list of caotured values.
+ pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
+ const ip = &zcu.intern_pool;
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => ip.loadStructType(ty.toIntern()).captures,
+ .union_type => ip.loadUnionType(ty.toIntern()).captures,
+ .enum_type => ip.loadEnumType(ty.toIntern()).captures,
+ .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures,
+ else => unreachable,
+ };
+ }
+
pub const @"u1": Type = .{ .ip_index = .u1_type };
pub const @"u8": Type = .{ .ip_index = .u8_type };
pub const @"u16": Type = .{ .ip_index = .u16_type };