aboutsummaryrefslogtreecommitdiff
path: root/src/InternPool.zig
diff options
context:
space:
mode:
authorkcbanner <kcbanner@gmail.com>2023-10-21 16:49:30 -0400
committermlugg <mlugg@mlugg.co.uk>2023-11-07 00:49:35 +0000
commitf10499be0a16ec58d98387b49189401f2af2094f (patch)
tree1dee8acd698e9bb489a9926004d4cdf16f7ce72d /src/InternPool.zig
parent234693bcbba6f55ff6e975ddbedf0fad4dfaa8f1 (diff)
downloadzig-f10499be0a16ec58d98387b49189401f2af2094f.tar.gz
zig-f10499be0a16ec58d98387b49189401f2af2094f.zip
sema: analyze field init bodies in a second pass
This change allows struct field inits to use layout information of their own struct without causing a circular dependency. `semaStructFields` caches the ranges of the init bodies in the `StructType` trailing data. The init bodies are then resolved by `resolveStructFieldInits`, which is called before the inits are actually required. Within the init bodies, the struct decl's instruction is repurposed to refer to the field type itself. This is to allow us to easily rebuild the inst_map mapping required for the init body instructions to refer to the field type. Thanks to @mlugg for the guidance on this one!
Diffstat (limited to 'src/InternPool.zig')
-rw-r--r--src/InternPool.zig74
1 files changed, 72 insertions, 2 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig
index b70034641e..c2439ccc8e 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -463,6 +463,7 @@ pub const Key = union(enum) {
pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
if (s.field_inits.len == 0) return .none;
+ assert(s.haveFieldInits(ip));
return s.field_inits.get(ip)[i];
}
@@ -497,6 +498,14 @@ pub const Key = union(enum) {
return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
}
+ /// The returned pointer expires with any addition to the `InternPool`.
+ /// Asserts that the struct is packed.
+ pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {
+ assert(self.layout == .Packed);
+ const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
+ return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
+ }
+
pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
if (s.layout == .Packed) return false;
const flags_ptr = s.flagsPtr(ip);
@@ -546,6 +555,30 @@ pub const Key = union(enum) {
s.flagsPtr(ip).alignment_wip = false;
}
+ pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
+ switch (s.layout) {
+ .Packed => {
+ const flag = &s.packedFlagsPtr(ip).field_inits_wip;
+ if (flag.*) return true;
+ flag.* = true;
+ return false;
+ },
+ .Auto, .Extern => {
+ const flag = &s.flagsPtr(ip).field_inits_wip;
+ if (flag.*) return true;
+ flag.* = true;
+ return false;
+ },
+ }
+ }
+
+ pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
+ switch (s.layout) {
+ .Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
+ .Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
+ }
+ }
+
pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
if (s.layout == .Packed) return true;
const flags_ptr = s.flagsPtr(ip);
@@ -588,6 +621,20 @@ pub const Key = union(enum) {
return types.len == 0 or types[0] != .none;
}
+ pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
+ return switch (s.layout) {
+ .Packed => s.packedFlagsPtr(ip).inits_resolved,
+ .Auto, .Extern => s.flagsPtr(ip).inits_resolved,
+ };
+ }
+
+ pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
+ switch (s.layout) {
+ .Packed => s.packedFlagsPtr(ip).inits_resolved = true,
+ .Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
+ }
+ }
+
pub fn haveLayout(s: @This(), ip: *InternPool) bool {
return switch (s.layout) {
.Packed => s.backingIntType(ip).* != .none,
@@ -3000,6 +3047,14 @@ pub const Tag = enum(u8) {
namespace: Module.Namespace.OptionalIndex,
backing_int_ty: Index,
names_map: MapIndex,
+ flags: Flags,
+
+ pub const Flags = packed struct(u32) {
+ /// Dependency loop detection when resolving field inits.
+ field_inits_wip: bool,
+ inits_resolved: bool,
+ _: u30 = 0,
+ };
};
/// At first I thought of storing the denormalized data externally, such as...
@@ -3045,6 +3100,7 @@ pub const Tag = enum(u8) {
requires_comptime: RequiresComptime,
is_tuple: bool,
assumed_runtime_bits: bool,
+ assumed_pointer_aligned: bool,
has_namespace: bool,
any_comptime_fields: bool,
any_default_inits: bool,
@@ -3057,14 +3113,18 @@ pub const Tag = enum(u8) {
field_types_wip: bool,
/// Dependency loop detection when resolving struct layout.
layout_wip: bool,
- /// Determines whether `size`, `alignment`, runtime field order, and
+ /// Indicates whether `size`, `alignment`, runtime field order, and
/// field offets are populated.
layout_resolved: bool,
+ /// Dependency loop detection when resolving field inits.
+ field_inits_wip: bool,
+ /// Indicates whether `field_inits` has been resolved.
+ inits_resolved: bool,
// The types and all its fields have had their layout resolved. Even through pointer,
// which `layout_resolved` does not ensure.
fully_resolved: bool,
- _: u11 = 0,
+ _: u8 = 0,
};
};
};
@@ -5347,6 +5407,7 @@ pub const StructTypeInit = struct {
is_tuple: bool,
any_comptime_fields: bool,
any_default_inits: bool,
+ inits_resolved: bool,
any_aligned_fields: bool,
};
@@ -5399,6 +5460,10 @@ pub fn getStructType(
.namespace = ini.namespace,
.backing_int_ty = .none,
.names_map = names_map,
+ .flags = .{
+ .field_inits_wip = false,
+ .inits_resolved = ini.inits_resolved,
+ },
}),
});
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
@@ -5431,6 +5496,7 @@ pub fn getStructType(
.requires_comptime = ini.requires_comptime,
.is_tuple = ini.is_tuple,
.assumed_runtime_bits = false,
+ .assumed_pointer_aligned = false,
.has_namespace = ini.namespace != .none,
.any_comptime_fields = ini.any_comptime_fields,
.any_default_inits = ini.any_default_inits,
@@ -5440,6 +5506,8 @@ pub fn getStructType(
.field_types_wip = false,
.layout_wip = false,
.layout_resolved = false,
+ .field_inits_wip = false,
+ .inits_resolved = ini.inits_resolved,
.fully_resolved = false,
},
}),
@@ -6451,6 +6519,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
Tag.TypePointer.PackedOffset,
Tag.TypeUnion.Flags,
Tag.TypeStruct.Flags,
+ Tag.TypeStructPacked.Flags,
Tag.Variable.Flags,
=> @bitCast(@field(extra, field.name)),
@@ -6525,6 +6594,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
Tag.TypePointer.PackedOffset,
Tag.TypeUnion.Flags,
Tag.TypeStruct.Flags,
+ Tag.TypeStructPacked.Flags,
Tag.Variable.Flags,
FuncAnalysis,
=> @bitCast(int32),