Skip to content

Commit 99e04b5

Browse files
committed
sema: analyze field init bodies in a second pass
1 parent 1e6ecf8 commit 99e04b5

File tree

7 files changed

+381
-49
lines changed

7 files changed

+381
-49
lines changed

src/AstGen.zig

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

49494949
if (have_value) {
49504950
any_default_inits = true;
4951-
const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } };
4951+
4952+
// The decl_inst is used as here so that we can easily reconstruct a mapping
4953+
// between it and the field type when the fields inits are analzyed.
4954+
const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = Zir.indexToRef(decl_inst) } };
49524955

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

src/InternPool.zig

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ pub const Key = union(enum) {
371371
layout: std.builtin.Type.ContainerLayout,
372372
field_names: NullTerminatedString.Slice,
373373
field_types: Index.Slice,
374+
field_inits_bodies: InitBody.Slice,
374375
field_inits: Index.Slice,
375376
field_aligns: Alignment.Slice,
376377
runtime_order: RuntimeOrder.Slice,
@@ -401,6 +402,23 @@ pub const Key = union(enum) {
401402
}
402403
};
403404

405+
pub const InitBody = struct {
406+
start: Zir.Inst.Index,
407+
len: u32,
408+
409+
pub const Slice = struct {
410+
start: u32,
411+
len: u32,
412+
413+
pub fn get(this: @This(), ip: *const InternPool) []InitBody {
414+
// Workaround for not being able to case between slices of different lengths
415+
assert(ip.extra.items.len >= this.start + this.len * 2);
416+
const bodies_ptr: [*]InitBody = @ptrCast(ip.extra.items[this.start..].ptr);
417+
return bodies_ptr[0..this.len];
418+
}
419+
};
420+
};
421+
404422
pub const Offsets = struct {
405423
start: u32,
406424
len: u32,
@@ -464,6 +482,7 @@ pub const Key = union(enum) {
464482

465483
pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
466484
if (s.field_inits.len == 0) return .none;
485+
assert(s.haveFieldInits(ip));
467486
return s.field_inits.get(ip)[i];
468487
}
469488

@@ -498,6 +517,14 @@ pub const Key = union(enum) {
498517
return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
499518
}
500519

520+
/// The returned pointer expires with any addition to the `InternPool`.
521+
/// Asserts the is not packed.
522+
pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {
523+
assert(self.layout == .Packed);
524+
const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
525+
return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
526+
}
527+
501528
pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
502529
if (s.layout == .Packed) return false;
503530
const flags_ptr = s.flagsPtr(ip);
@@ -547,6 +574,28 @@ pub const Key = union(enum) {
547574
s.flagsPtr(ip).alignment_wip = false;
548575
}
549576

577+
pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
578+
switch (s.layout) {
579+
inline else => |layout| {
580+
const flag = if (layout == .Packed)
581+
&s.packedFlagsPtr(ip).field_inits_wip
582+
else
583+
&s.flagsPtr(ip).field_inits_wip;
584+
585+
if (flag.*) return true;
586+
flag.* = true;
587+
return false;
588+
},
589+
}
590+
}
591+
592+
pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
593+
switch (s.layout) {
594+
.Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
595+
.Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
596+
}
597+
}
598+
550599
pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
551600
if (s.layout == .Packed) return true;
552601
const flags_ptr = s.flagsPtr(ip);
@@ -589,6 +638,20 @@ pub const Key = union(enum) {
589638
return types.len == 0 or types[0] != .none;
590639
}
591640

641+
pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
642+
return switch (s.layout) {
643+
.Packed => s.packedFlagsPtr(ip).inits_resolved,
644+
.Auto, .Extern => s.flagsPtr(ip).inits_resolved,
645+
};
646+
}
647+
648+
pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
649+
return switch (s.layout) {
650+
.Packed => s.packedFlagsPtr(ip).inits_resolved = true,
651+
.Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
652+
};
653+
}
654+
592655
pub fn haveLayout(s: @This(), ip: *InternPool) bool {
593656
return switch (s.layout) {
594657
.Packed => s.backingIntType(ip).* != .none,
@@ -2999,14 +3062,25 @@ pub const Tag = enum(u8) {
29993062
/// Trailing:
30003063
/// 0. type: Index for each fields_len
30013064
/// 1. name: NullTerminatedString for each fields_len
3002-
/// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
3065+
///
3066+
/// if tag is type_struct_packed_inits:
3067+
/// 2. body_indices: Zir.Inst.Index // for each field in declared order, a pair of start index and length.
3068+
/// 3. init: Index for each fields_len
30033069
pub const TypeStructPacked = struct {
30043070
decl: Module.Decl.Index,
30053071
zir_index: Zir.Inst.Index,
30063072
fields_len: u32,
30073073
namespace: Module.Namespace.OptionalIndex,
30083074
backing_int_ty: Index,
30093075
names_map: MapIndex,
3076+
flags: Flags,
3077+
3078+
pub const Flags = packed struct(u32) {
3079+
/// Dependency loop detection when resolving field inits.
3080+
field_inits_wip: bool,
3081+
inits_resolved: bool,
3082+
_: u30 = 0,
3083+
};
30103084
};
30113085

30123086
/// At first I thought of storing the denormalized data externally, such as...
@@ -3029,6 +3103,7 @@ pub const Tag = enum(u8) {
30293103
/// names_map: MapIndex,
30303104
/// name: NullTerminatedString // for each field in declared order
30313105
/// 2. if any_default_inits:
3106+
/// body_indices: Zir.Inst.Index // for each field in declared order, a pair of start index and length.
30323107
/// init: Index // for each field in declared order
30333108
/// 3. if has_namespace:
30343109
/// namespace: Module.Namespace.Index
@@ -3052,6 +3127,7 @@ pub const Tag = enum(u8) {
30523127
requires_comptime: RequiresComptime,
30533128
is_tuple: bool,
30543129
assumed_runtime_bits: bool,
3130+
assumed_pointer_aligned: bool,
30553131
has_namespace: bool,
30563132
any_comptime_fields: bool,
30573133
any_default_inits: bool,
@@ -3064,14 +3140,18 @@ pub const Tag = enum(u8) {
30643140
field_types_wip: bool,
30653141
/// Dependency loop detection when resolving struct layout.
30663142
layout_wip: bool,
3067-
/// Determines whether `size`, `alignment`, runtime field order, and
3143+
/// Indicates whether `size`, `alignment`, runtime field order, and
30683144
/// field offets are populated.
30693145
layout_resolved: bool,
3146+
/// Dependency loop detection when resolving field inits.
3147+
field_inits_wip: bool,
3148+
/// Indicates whether `field_inits` has been resolved.
3149+
inits_resolved: bool,
30703150
// The types and all its fields have had their layout resolved. Even through pointer,
30713151
// which `layout_resolved` does not ensure.
30723152
fully_resolved: bool,
30733153

3074-
_: u11 = 0,
3154+
_: u8 = 0,
30753155
};
30763156
};
30773157
};
@@ -3704,6 +3784,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
37043784
.layout = .Auto,
37053785
.field_names = .{ .start = 0, .len = 0 },
37063786
.field_types = .{ .start = 0, .len = 0 },
3787+
.field_inits_bodies = .{ .start = 0, .len = 0 },
37073788
.field_inits = .{ .start = 0, .len = 0 },
37083789
.field_aligns = .{ .start = 0, .len = 0 },
37093790
.runtime_order = .{ .start = 0, .len = 0 },
@@ -3720,6 +3801,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
37203801
.layout = .Auto,
37213802
.field_names = .{ .start = 0, .len = 0 },
37223803
.field_types = .{ .start = 0, .len = 0 },
3804+
.field_inits_bodies = .{ .start = 0, .len = 0 },
37233805
.field_inits = .{ .start = 0, .len = 0 },
37243806
.field_aligns = .{ .start = 0, .len = 0 },
37253807
.runtime_order = .{ .start = 0, .len = 0 },
@@ -4233,6 +4315,12 @@ fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
42334315
index += fields_len;
42344316
break :t .{ names_map.toOptional(), names };
42354317
};
4318+
const field_inits_bodies: Key.StructType.InitBody.Slice = t: {
4319+
if (!s.data.flags.any_default_inits) break :t .{ .start = 0, .len = 0 };
4320+
const offsets: Key.StructType.InitBody.Slice = .{ .start = index, .len = fields_len };
4321+
index += fields_len * 2;
4322+
break :t offsets;
4323+
};
42364324
const field_inits: Index.Slice = t: {
42374325
if (!s.data.flags.any_default_inits) break :t .{ .start = 0, .len = 0 };
42384326
const inits: Index.Slice = .{ .start = index, .len = fields_len };
@@ -4276,6 +4364,7 @@ fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
42764364
.field_types = field_types,
42774365
.names_map = names_map,
42784366
.field_names = field_names,
4367+
.field_inits_bodies = field_inits_bodies,
42794368
.field_inits = field_inits,
42804369
.namespace = namespace,
42814370
.field_aligns = field_aligns,
@@ -4302,13 +4391,20 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K
43024391
.start = type_struct_packed.end + fields_len,
43034392
.len = fields_len,
43044393
},
4305-
.field_inits = if (inits) .{
4394+
.field_inits_bodies = if (inits) .{
43064395
.start = type_struct_packed.end + fields_len * 2,
43074396
.len = fields_len,
43084397
} else .{
43094398
.start = 0,
43104399
.len = 0,
43114400
},
4401+
.field_inits = if (inits) .{
4402+
.start = type_struct_packed.end + fields_len * 4,
4403+
.len = fields_len,
4404+
} else .{
4405+
.start = 0,
4406+
.len = 0,
4407+
},
43124408
.field_aligns = .{ .start = 0, .len = 0 },
43134409
.runtime_order = .{ .start = 0, .len = 0 },
43144410
.comptime_bits = .{ .start = 0, .len = 0 },
@@ -5362,6 +5458,7 @@ pub const StructTypeInit = struct {
53625458
is_tuple: bool,
53635459
any_comptime_fields: bool,
53645460
any_default_inits: bool,
5461+
inits_resolved: bool,
53655462
any_aligned_fields: bool,
53665463
};
53675464

@@ -5382,6 +5479,7 @@ pub fn getStructType(
53825479
.layout = undefined,
53835480
.field_names = undefined,
53845481
.field_types = undefined,
5482+
.field_inits_bodies = undefined,
53855483
.field_inits = undefined,
53865484
.field_aligns = undefined,
53875485
.runtime_order = undefined,
@@ -5404,6 +5502,7 @@ pub fn getStructType(
54045502
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
54055503
ini.fields_len + // types
54065504
ini.fields_len + // names
5505+
ini.fields_len * 2 + // init bodies
54075506
ini.fields_len); // inits
54085507
try ip.items.append(gpa, .{
54095508
.tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
@@ -5414,11 +5513,16 @@ pub fn getStructType(
54145513
.namespace = ini.namespace,
54155514
.backing_int_ty = .none,
54165515
.names_map = names_map,
5516+
.flags = .{
5517+
.field_inits_wip = false,
5518+
.inits_resolved = ini.inits_resolved,
5519+
},
54175520
}),
54185521
});
54195522
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
54205523
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
54215524
if (ini.any_default_inits) {
5525+
ip.extra.appendNTimesAssumeCapacity(0, ini.fields_len * 2);
54225526
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
54235527
}
54245528
return @enumFromInt(ip.items.len - 1);
@@ -5430,7 +5534,7 @@ pub fn getStructType(
54305534
const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
54315535

54325536
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +
5433-
(ini.fields_len * 5) + // types, names, inits, runtime order, offsets
5537+
(ini.fields_len * 7) + // types, names, init bodies, inits, runtime order, offsets
54345538
align_elements_len + comptime_elements_len +
54355539
2); // names_map + namespace
54365540
try ip.items.append(gpa, .{
@@ -5446,6 +5550,7 @@ pub fn getStructType(
54465550
.requires_comptime = ini.requires_comptime,
54475551
.is_tuple = ini.is_tuple,
54485552
.assumed_runtime_bits = false,
5553+
.assumed_pointer_aligned = false,
54495554
.has_namespace = ini.namespace != .none,
54505555
.any_comptime_fields = ini.any_comptime_fields,
54515556
.any_default_inits = ini.any_default_inits,
@@ -5455,6 +5560,8 @@ pub fn getStructType(
54555560
.field_types_wip = false,
54565561
.layout_wip = false,
54575562
.layout_resolved = false,
5563+
.field_inits_wip = false,
5564+
.inits_resolved = ini.inits_resolved,
54585565
.fully_resolved = false,
54595566
},
54605567
}),
@@ -5465,6 +5572,7 @@ pub fn getStructType(
54655572
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
54665573
}
54675574
if (ini.any_default_inits) {
5575+
ip.extra.appendNTimesAssumeCapacity(0, ini.fields_len * 2);
54685576
ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
54695577
}
54705578
if (ini.namespace.unwrap()) |namespace| {
@@ -6465,6 +6573,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
64656573
Tag.TypePointer.PackedOffset,
64666574
Tag.TypeUnion.Flags,
64676575
Tag.TypeStruct.Flags,
6576+
Tag.TypeStructPacked.Flags,
64686577
Tag.Variable.Flags,
64696578
=> @bitCast(@field(extra, field.name)),
64706579

@@ -6538,6 +6647,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
65386647
Tag.TypePointer.PackedOffset,
65396648
Tag.TypeUnion.Flags,
65406649
Tag.TypeStruct.Flags,
6650+
Tag.TypeStructPacked.Flags,
65416651
Tag.Variable.Flags,
65426652
FuncAnalysis,
65436653
=> @bitCast(int32),

0 commit comments

Comments
 (0)