Skip to content

Commit b3462b7

Browse files
authored
Merge pull request #17692 from kcbanner/struct_field_init_pass
sema: analyze struct field bodies in a second pass, to allow them to use the layout of the struct itself
2 parents d78eda3 + 1acb6a5 commit b3462b7

File tree

10 files changed

+611
-105
lines changed

10 files changed

+611
-105
lines changed

src/AstGen.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4951,7 +4951,10 @@ fn structDeclInner(
49514951

49524952
if (have_value) {
49534953
any_default_inits = true;
4954-
const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } };
4954+
4955+
// The decl_inst is used as here so that we can easily reconstruct a mapping
4956+
// between it and the field type when the fields inits are analzyed.
4957+
const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = decl_inst.toRef() } };
49554958

49564959
const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr);
49574960
if (!block_scope.endsWithNoReturn()) {

src/Autodoc.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3808,6 +3808,11 @@ fn walkInstruction(
38083808
call_ctx,
38093809
);
38103810

3811+
// Inside field init bodies, the struct decl instruction is used to refer to the
3812+
// field type during the second pass of analysis.
3813+
try self.repurposed_insts.put(self.arena, inst, {});
3814+
defer _ = self.repurposed_insts.remove(inst);
3815+
38113816
var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
38123817
var field_default_refs: std.ArrayListUnmanaged(?DocData.Expr) = .{};
38133818
var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};

src/InternPool.zig

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ pub const Key = union(enum) {
463463

464464
pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
465465
if (s.field_inits.len == 0) return .none;
466+
assert(s.haveFieldInits(ip));
466467
return s.field_inits.get(ip)[i];
467468
}
468469

@@ -497,6 +498,14 @@ pub const Key = union(enum) {
497498
return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
498499
}
499500

501+
/// The returned pointer expires with any addition to the `InternPool`.
502+
/// Asserts that the struct is packed.
503+
pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {
504+
assert(self.layout == .Packed);
505+
const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
506+
return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
507+
}
508+
500509
pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
501510
if (s.layout == .Packed) return false;
502511
const flags_ptr = s.flagsPtr(ip);
@@ -546,6 +555,30 @@ pub const Key = union(enum) {
546555
s.flagsPtr(ip).alignment_wip = false;
547556
}
548557

558+
pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
559+
switch (s.layout) {
560+
.Packed => {
561+
const flag = &s.packedFlagsPtr(ip).field_inits_wip;
562+
if (flag.*) return true;
563+
flag.* = true;
564+
return false;
565+
},
566+
.Auto, .Extern => {
567+
const flag = &s.flagsPtr(ip).field_inits_wip;
568+
if (flag.*) return true;
569+
flag.* = true;
570+
return false;
571+
},
572+
}
573+
}
574+
575+
pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
576+
switch (s.layout) {
577+
.Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
578+
.Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
579+
}
580+
}
581+
549582
pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
550583
if (s.layout == .Packed) return true;
551584
const flags_ptr = s.flagsPtr(ip);
@@ -588,6 +621,20 @@ pub const Key = union(enum) {
588621
return types.len == 0 or types[0] != .none;
589622
}
590623

624+
pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
625+
return switch (s.layout) {
626+
.Packed => s.packedFlagsPtr(ip).inits_resolved,
627+
.Auto, .Extern => s.flagsPtr(ip).inits_resolved,
628+
};
629+
}
630+
631+
pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
632+
switch (s.layout) {
633+
.Packed => s.packedFlagsPtr(ip).inits_resolved = true,
634+
.Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
635+
}
636+
}
637+
591638
pub fn haveLayout(s: @This(), ip: *InternPool) bool {
592639
return switch (s.layout) {
593640
.Packed => s.backingIntType(ip).* != .none,
@@ -3000,6 +3047,14 @@ pub const Tag = enum(u8) {
30003047
namespace: Module.Namespace.OptionalIndex,
30013048
backing_int_ty: Index,
30023049
names_map: MapIndex,
3050+
flags: Flags,
3051+
3052+
pub const Flags = packed struct(u32) {
3053+
/// Dependency loop detection when resolving field inits.
3054+
field_inits_wip: bool,
3055+
inits_resolved: bool,
3056+
_: u30 = 0,
3057+
};
30033058
};
30043059

30053060
/// At first I thought of storing the denormalized data externally, such as...
@@ -3045,6 +3100,7 @@ pub const Tag = enum(u8) {
30453100
requires_comptime: RequiresComptime,
30463101
is_tuple: bool,
30473102
assumed_runtime_bits: bool,
3103+
assumed_pointer_aligned: bool,
30483104
has_namespace: bool,
30493105
any_comptime_fields: bool,
30503106
any_default_inits: bool,
@@ -3057,14 +3113,18 @@ pub const Tag = enum(u8) {
30573113
field_types_wip: bool,
30583114
/// Dependency loop detection when resolving struct layout.
30593115
layout_wip: bool,
3060-
/// Determines whether `size`, `alignment`, runtime field order, and
3116+
/// Indicates whether `size`, `alignment`, runtime field order, and
30613117
/// field offets are populated.
30623118
layout_resolved: bool,
3119+
/// Dependency loop detection when resolving field inits.
3120+
field_inits_wip: bool,
3121+
/// Indicates whether `field_inits` has been resolved.
3122+
inits_resolved: bool,
30633123
// The types and all its fields have had their layout resolved. Even through pointer,
30643124
// which `layout_resolved` does not ensure.
30653125
fully_resolved: bool,
30663126

3067-
_: u11 = 0,
3127+
_: u8 = 0,
30683128
};
30693129
};
30703130
};
@@ -5347,6 +5407,7 @@ pub const StructTypeInit = struct {
53475407
is_tuple: bool,
53485408
any_comptime_fields: bool,
53495409
any_default_inits: bool,
5410+
inits_resolved: bool,
53505411
any_aligned_fields: bool,
53515412
};
53525413

@@ -5399,6 +5460,10 @@ pub fn getStructType(
53995460
.namespace = ini.namespace,
54005461
.backing_int_ty = .none,
54015462
.names_map = names_map,
5463+
.flags = .{
5464+
.field_inits_wip = false,
5465+
.inits_resolved = ini.inits_resolved,
5466+
},
54025467
}),
54035468
});
54045469
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
@@ -5431,6 +5496,7 @@ pub fn getStructType(
54315496
.requires_comptime = ini.requires_comptime,
54325497
.is_tuple = ini.is_tuple,
54335498
.assumed_runtime_bits = false,
5499+
.assumed_pointer_aligned = false,
54345500
.has_namespace = ini.namespace != .none,
54355501
.any_comptime_fields = ini.any_comptime_fields,
54365502
.any_default_inits = ini.any_default_inits,
@@ -5440,6 +5506,8 @@ pub fn getStructType(
54405506
.field_types_wip = false,
54415507
.layout_wip = false,
54425508
.layout_resolved = false,
5509+
.field_inits_wip = false,
5510+
.inits_resolved = ini.inits_resolved,
54435511
.fully_resolved = false,
54445512
},
54455513
}),
@@ -6451,6 +6519,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
64516519
Tag.TypePointer.PackedOffset,
64526520
Tag.TypeUnion.Flags,
64536521
Tag.TypeStruct.Flags,
6522+
Tag.TypeStructPacked.Flags,
64546523
Tag.Variable.Flags,
64556524
=> @bitCast(@field(extra, field.name)),
64566525

@@ -6525,6 +6594,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
65256594
Tag.TypePointer.PackedOffset,
65266595
Tag.TypeUnion.Flags,
65276596
Tag.TypeStruct.Flags,
6597+
Tag.TypeStructPacked.Flags,
65286598
Tag.Variable.Flags,
65296599
FuncAnalysis,
65306600
=> @bitCast(int32),

0 commit comments

Comments
 (0)