authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-16 12:46:52+01:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-17 18:50:10-04:00
log84c2ebd6c6b16752d8d030d5904d0a525283cbf5
tree442234d4a737c6fbcf4f165ac18fa2a31cef9ac1
parent65cbdefe4d923efd8fd2cfb555cc02a52c5635fc

frontend: incremental compilation progress

Another big commit, sorry! This commit makes all fixes necessary for incremental updates of the compiler itself (specifically, adding a breakpoint to `zirCompileLog`) to succeed, at least on the frontend. The biggest change here is a reform to how types are handled. It works like this: * When a type is first created in `zirStructDecl` etc, its namespace is scanned. If the type requires resolution, an `interned` dependency is declared for the containing `AnalUnit`. * `zirThis` also declared an `interned` dependency for its `AnalUnit` on the namespace's owner type. * If the type's namespace changes, the surrounding source declaration changes hash, so `zirStructDecl` etc will be hit again. We check whether the namespace has been scanned this generation, and re-scan it if not. * Namespace lookups also check whether the namespace in question requires a re-scan based on the generation. This is because there's no guarantee that the `zirStructDecl` is re-analyzed before the namespace lookup is re-analyzed. * If a type's structure (essentially its fields) change, then the type's `Cau` is considered outdated. When the type is re-analyzed due to being outdated, or the `zirStructDecl` is re-analyzed by being transitively outdated, or a corresponding `zirThis` is re-analyzed by being transitively outdated, the struct type is recreated at a new `InternPool` index. The namespace's owner is updated (but not re-scanned, since that is handled by the mechanisms above), and the old type, while remaining a valid `Index`, is removed from the map metadata so it will never be found by lookups. `zirStructDecl` and `zirThis` store an `interned` dependency on the *new* type.

5 files changed, 949 insertions(+), 333 deletions(-)

src/Compilation.zig+2
...@@ -3569,6 +3569,8 @@ pub fn performAllTheWork(...@@ -3569,6 +3569,8 @@ pub fn performAllTheWork(
3569 mod.sema_prog_node = std.Progress.Node.none;3569 mod.sema_prog_node = std.Progress.Node.none;
3570 mod.codegen_prog_node.end();3570 mod.codegen_prog_node.end();
3571 mod.codegen_prog_node = std.Progress.Node.none;3571 mod.codegen_prog_node = std.Progress.Node.none;
3572
3573 mod.generation += 1;
3572 };3574 };
3573 try comp.performAllTheWorkInner(main_progress_node);3575 try comp.performAllTheWorkInner(main_progress_node);
3574 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;3576 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
src/InternPool.zig+88-25
...@@ -684,10 +684,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -684,10 +684,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
684 .ip = ip,684 .ip = ip,
685 .next_entry = .none,685 .next_entry = .none,
686 };686 };
687 if (ip.dep_entries.items[@intFromEnum(first_entry)].depender == .none) return .{
688 .ip = ip,
689 .next_entry = .none,
690 };
691 return .{687 return .{
692 .ip = ip,688 .ip = ip,
693 .next_entry = first_entry.toOptional(),689 .next_entry = first_entry.toOptional(),
...@@ -724,7 +720,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -724,7 +720,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
724720
725 if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {721 if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {
726 // Dummy entry, so we can reuse it rather than allocating a new one!722 // Dummy entry, so we can reuse it rather than allocating a new one!
727 ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].next = .none;
728 break :new_index gop.value_ptr.*;723 break :new_index gop.value_ptr.*;
729 }724 }
730725
...@@ -732,7 +727,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -732,7 +727,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
732 const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: {727 const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: {
733 break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] };728 break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] };
734 } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() };729 } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() };
735 ptr.next = if (gop.found_existing) gop.value_ptr.*.toOptional() else .none;730 if (gop.found_existing) {
731 ptr.next = gop.value_ptr.*.toOptional();
732 ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].prev = new_index.toOptional();
733 } else {
734 ptr.next = .none;
735 }
736 gop.value_ptr.* = new_index;736 gop.value_ptr.* = new_index;
737 break :new_index new_index;737 break :new_index new_index;
738 },738 },
...@@ -754,10 +754,9 @@ pub const NamespaceNameKey = struct {...@@ -754,10 +754,9 @@ pub const NamespaceNameKey = struct {
754};754};
755755
756pub const DepEntry = extern struct {756pub const DepEntry = extern struct {
757 /// If null, this is a dummy entry - all other fields are `undefined`. It is757 /// If null, this is a dummy entry. `next_dependee` is undefined. This is the first
758 /// the first and only entry in one of `intern_pool.*_deps`, and does not758 /// entry in one of `*_deps`, and does not appear in any list by `first_dependency`,
759 /// appear in any list by `first_dependency`, but is not in759 /// but is not in `free_dep_entries` since `*_deps` stores a reference to it.
760 /// `free_dep_entries` since `*_deps` stores a reference to it.
761 depender: AnalUnit.Optional,760 depender: AnalUnit.Optional,
762 /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee.761 /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee.
763 /// Used to iterate all dependers for a given dependee during an update.762 /// Used to iterate all dependers for a given dependee during an update.
...@@ -2689,7 +2688,12 @@ pub const Key = union(enum) {...@@ -2689,7 +2688,12 @@ pub const Key = union(enum) {
26892688
2690 .variable => |a_info| {2689 .variable => |a_info| {
2691 const b_info = b.variable;2690 const b_info = b.variable;
2692 return a_info.owner_nav == b_info.owner_nav;2691 return a_info.owner_nav == b_info.owner_nav and
2692 a_info.ty == b_info.ty and
2693 a_info.init == b_info.init and
2694 a_info.lib_name == b_info.lib_name and
2695 a_info.is_threadlocal == b_info.is_threadlocal and
2696 a_info.is_weak_linkage == b_info.is_weak_linkage;
2693 },2697 },
2694 .@"extern" => |a_info| {2698 .@"extern" => |a_info| {
2695 const b_info = b.@"extern";2699 const b_info = b.@"extern";
...@@ -8016,6 +8020,10 @@ pub const UnionTypeInit = struct {...@@ -8016,6 +8020,10 @@ pub const UnionTypeInit = struct {
8016 zir_index: TrackedInst.Index,8020 zir_index: TrackedInst.Index,
8017 captures: []const CaptureValue,8021 captures: []const CaptureValue,
8018 },8022 },
8023 declared_owned_captures: struct {
8024 zir_index: TrackedInst.Index,
8025 captures: CaptureValue.Slice,
8026 },
8019 reified: struct {8027 reified: struct {
8020 zir_index: TrackedInst.Index,8028 zir_index: TrackedInst.Index,
8021 type_hash: u64,8029 type_hash: u64,
...@@ -8037,6 +8045,10 @@ pub fn getUnionType(...@@ -8037,6 +8045,10 @@ pub fn getUnionType(
8037 .zir_index = d.zir_index,8045 .zir_index = d.zir_index,
8038 .captures = .{ .external = d.captures },8046 .captures = .{ .external = d.captures },
8039 } },8047 } },
8048 .declared_owned_captures => |d| .{ .declared = .{
8049 .zir_index = d.zir_index,
8050 .captures = .{ .owned = d.captures },
8051 } },
8040 .reified => |r| .{ .reified = .{8052 .reified => |r| .{ .reified = .{
8041 .zir_index = r.zir_index,8053 .zir_index = r.zir_index,
8042 .type_hash = r.type_hash,8054 .type_hash = r.type_hash,
...@@ -8060,7 +8072,7 @@ pub fn getUnionType(...@@ -8060,7 +8072,7 @@ pub fn getUnionType(
8060 // TODO: fmt bug8072 // TODO: fmt bug
8061 // zig fmt: off8073 // zig fmt: off
8062 switch (ini.key) {8074 switch (ini.key) {
8063 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,8075 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
8064 .reified => 2, // type_hash: PackedU648076 .reified => 2, // type_hash: PackedU64
8065 } +8077 } +
8066 // zig fmt: on8078 // zig fmt: on
...@@ -8069,7 +8081,10 @@ pub fn getUnionType(...@@ -8069,7 +8081,10 @@ pub fn getUnionType(
80698081
8070 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{8082 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8071 .flags = .{8083 .flags = .{
8072 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,8084 .any_captures = switch (ini.key) {
8085 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
8086 .reified => false,
8087 },
8073 .runtime_tag = ini.flags.runtime_tag,8088 .runtime_tag = ini.flags.runtime_tag,
8074 .any_aligned_fields = ini.flags.any_aligned_fields,8089 .any_aligned_fields = ini.flags.any_aligned_fields,
8075 .layout = ini.flags.layout,8090 .layout = ini.flags.layout,
...@@ -8078,7 +8093,10 @@ pub fn getUnionType(...@@ -8078,7 +8093,10 @@ pub fn getUnionType(
8078 .assumed_runtime_bits = ini.flags.assumed_runtime_bits,8093 .assumed_runtime_bits = ini.flags.assumed_runtime_bits,
8079 .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,8094 .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,
8080 .alignment = ini.flags.alignment,8095 .alignment = ini.flags.alignment,
8081 .is_reified = ini.key == .reified,8096 .is_reified = switch (ini.key) {
8097 .declared, .declared_owned_captures => false,
8098 .reified => true,
8099 },
8082 },8100 },
8083 .fields_len = ini.fields_len,8101 .fields_len = ini.fields_len,
8084 .size = std.math.maxInt(u32),8102 .size = std.math.maxInt(u32),
...@@ -8102,6 +8120,10 @@ pub fn getUnionType(...@@ -8102,6 +8120,10 @@ pub fn getUnionType(
8102 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8120 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8103 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8121 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8104 },8122 },
8123 .declared_owned_captures => |d| if (d.captures.len != 0) {
8124 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8125 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
8126 },
8105 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),8127 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8106 }8128 }
81078129
...@@ -8199,6 +8221,10 @@ pub const StructTypeInit = struct {...@@ -8199,6 +8221,10 @@ pub const StructTypeInit = struct {
8199 zir_index: TrackedInst.Index,8221 zir_index: TrackedInst.Index,
8200 captures: []const CaptureValue,8222 captures: []const CaptureValue,
8201 },8223 },
8224 declared_owned_captures: struct {
8225 zir_index: TrackedInst.Index,
8226 captures: CaptureValue.Slice,
8227 },
8202 reified: struct {8228 reified: struct {
8203 zir_index: TrackedInst.Index,8229 zir_index: TrackedInst.Index,
8204 type_hash: u64,8230 type_hash: u64,
...@@ -8220,6 +8246,10 @@ pub fn getStructType(...@@ -8220,6 +8246,10 @@ pub fn getStructType(
8220 .zir_index = d.zir_index,8246 .zir_index = d.zir_index,
8221 .captures = .{ .external = d.captures },8247 .captures = .{ .external = d.captures },
8222 } },8248 } },
8249 .declared_owned_captures => |d| .{ .declared = .{
8250 .zir_index = d.zir_index,
8251 .captures = .{ .owned = d.captures },
8252 } },
8223 .reified => |r| .{ .reified = .{8253 .reified => |r| .{ .reified = .{
8224 .zir_index = r.zir_index,8254 .zir_index = r.zir_index,
8225 .type_hash = r.type_hash,8255 .type_hash = r.type_hash,
...@@ -8251,7 +8281,7 @@ pub fn getStructType(...@@ -8251,7 +8281,7 @@ pub fn getStructType(
8251 // TODO: fmt bug8281 // TODO: fmt bug
8252 // zig fmt: off8282 // zig fmt: off
8253 switch (ini.key) {8283 switch (ini.key) {
8254 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,8284 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
8255 .reified => 2, // type_hash: PackedU648285 .reified => 2, // type_hash: PackedU64
8256 } +8286 } +
8257 // zig fmt: on8287 // zig fmt: on
...@@ -8267,10 +8297,16 @@ pub fn getStructType(...@@ -8267,10 +8297,16 @@ pub fn getStructType(
8267 .backing_int_ty = .none,8297 .backing_int_ty = .none,
8268 .names_map = names_map,8298 .names_map = names_map,
8269 .flags = .{8299 .flags = .{
8270 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,8300 .any_captures = switch (ini.key) {
8301 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
8302 .reified => false,
8303 },
8271 .field_inits_wip = false,8304 .field_inits_wip = false,
8272 .inits_resolved = ini.inits_resolved,8305 .inits_resolved = ini.inits_resolved,
8273 .is_reified = ini.key == .reified,8306 .is_reified = switch (ini.key) {
8307 .declared, .declared_owned_captures => false,
8308 .reified => true,
8309 },
8274 },8310 },
8275 });8311 });
8276 try items.append(.{8312 try items.append(.{
...@@ -8282,6 +8318,10 @@ pub fn getStructType(...@@ -8282,6 +8318,10 @@ pub fn getStructType(
8282 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8318 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8283 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8319 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8284 },8320 },
8321 .declared_owned_captures => |d| if (d.captures.len != 0) {
8322 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8323 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
8324 },
8285 .reified => |r| {8325 .reified => |r| {
8286 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));8326 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));
8287 },8327 },
...@@ -8309,7 +8349,7 @@ pub fn getStructType(...@@ -8309,7 +8349,7 @@ pub fn getStructType(
8309 // TODO: fmt bug8349 // TODO: fmt bug
8310 // zig fmt: off8350 // zig fmt: off
8311 switch (ini.key) {8351 switch (ini.key) {
8312 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,8352 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
8313 .reified => 2, // type_hash: PackedU648353 .reified => 2, // type_hash: PackedU64
8314 } +8354 } +
8315 // zig fmt: on8355 // zig fmt: on
...@@ -8324,7 +8364,10 @@ pub fn getStructType(...@@ -8324,7 +8364,10 @@ pub fn getStructType(
8324 .fields_len = ini.fields_len,8364 .fields_len = ini.fields_len,
8325 .size = std.math.maxInt(u32),8365 .size = std.math.maxInt(u32),
8326 .flags = .{8366 .flags = .{
8327 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,8367 .any_captures = switch (ini.key) {
8368 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
8369 .reified => false,
8370 },
8328 .is_extern = is_extern,8371 .is_extern = is_extern,
8329 .known_non_opv = ini.known_non_opv,8372 .known_non_opv = ini.known_non_opv,
8330 .requires_comptime = ini.requires_comptime,8373 .requires_comptime = ini.requires_comptime,
...@@ -8342,7 +8385,10 @@ pub fn getStructType(...@@ -8342,7 +8385,10 @@ pub fn getStructType(
8342 .field_inits_wip = false,8385 .field_inits_wip = false,
8343 .inits_resolved = ini.inits_resolved,8386 .inits_resolved = ini.inits_resolved,
8344 .fully_resolved = false,8387 .fully_resolved = false,
8345 .is_reified = ini.key == .reified,8388 .is_reified = switch (ini.key) {
8389 .declared, .declared_owned_captures => false,
8390 .reified => true,
8391 },
8346 },8392 },
8347 });8393 });
8348 try items.append(.{8394 try items.append(.{
...@@ -8354,6 +8400,10 @@ pub fn getStructType(...@@ -8354,6 +8400,10 @@ pub fn getStructType(
8354 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8400 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8355 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8401 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8356 },8402 },
8403 .declared_owned_captures => |d| if (d.captures.len != 0) {
8404 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8405 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
8406 },
8357 .reified => |r| {8407 .reified => |r| {
8358 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));8408 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));
8359 },8409 },
...@@ -9157,6 +9207,10 @@ pub const EnumTypeInit = struct {...@@ -9157,6 +9207,10 @@ pub const EnumTypeInit = struct {
9157 zir_index: TrackedInst.Index,9207 zir_index: TrackedInst.Index,
9158 captures: []const CaptureValue,9208 captures: []const CaptureValue,
9159 },9209 },
9210 declared_owned_captures: struct {
9211 zir_index: TrackedInst.Index,
9212 captures: CaptureValue.Slice,
9213 },
9160 reified: struct {9214 reified: struct {
9161 zir_index: TrackedInst.Index,9215 zir_index: TrackedInst.Index,
9162 type_hash: u64,9216 type_hash: u64,
...@@ -9261,6 +9315,10 @@ pub fn getEnumType(...@@ -9261,6 +9315,10 @@ pub fn getEnumType(
9261 .zir_index = d.zir_index,9315 .zir_index = d.zir_index,
9262 .captures = .{ .external = d.captures },9316 .captures = .{ .external = d.captures },
9263 } },9317 } },
9318 .declared_owned_captures => |d| .{ .declared = .{
9319 .zir_index = d.zir_index,
9320 .captures = .{ .owned = d.captures },
9321 } },
9264 .reified => |r| .{ .reified = .{9322 .reified => |r| .{ .reified = .{
9265 .zir_index = r.zir_index,9323 .zir_index = r.zir_index,
9266 .type_hash = r.type_hash,9324 .type_hash = r.type_hash,
...@@ -9288,7 +9346,7 @@ pub fn getEnumType(...@@ -9288,7 +9346,7 @@ pub fn getEnumType(
9288 // TODO: fmt bug9346 // TODO: fmt bug
9289 // zig fmt: off9347 // zig fmt: off
9290 switch (ini.key) {9348 switch (ini.key) {
9291 .declared => |d| d.captures.len,9349 inline .declared, .declared_owned_captures => |d| d.captures.len,
9292 .reified => 2, // type_hash: PackedU649350 .reified => 2, // type_hash: PackedU64
9293 } +9351 } +
9294 // zig fmt: on9352 // zig fmt: on
...@@ -9298,7 +9356,7 @@ pub fn getEnumType(...@@ -9298,7 +9356,7 @@ pub fn getEnumType(
9298 const extra_index = addExtraAssumeCapacity(extra, EnumAuto{9356 const extra_index = addExtraAssumeCapacity(extra, EnumAuto{
9299 .name = undefined, // set by `prepare`9357 .name = undefined, // set by `prepare`
9300 .captures_len = switch (ini.key) {9358 .captures_len = switch (ini.key) {
9301 .declared => |d| @intCast(d.captures.len),9359 inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
9302 .reified => std.math.maxInt(u32),9360 .reified => std.math.maxInt(u32),
9303 },9361 },
9304 .namespace = undefined, // set by `prepare`9362 .namespace = undefined, // set by `prepare`
...@@ -9317,6 +9375,7 @@ pub fn getEnumType(...@@ -9317,6 +9375,7 @@ pub fn getEnumType(
9317 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`9375 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
9318 switch (ini.key) {9376 switch (ini.key) {
9319 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),9377 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
9378 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
9320 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),9379 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
9321 }9380 }
9322 const names_start = extra.mutate.len;9381 const names_start = extra.mutate.len;
...@@ -9347,7 +9406,7 @@ pub fn getEnumType(...@@ -9347,7 +9406,7 @@ pub fn getEnumType(
9347 // TODO: fmt bug9406 // TODO: fmt bug
9348 // zig fmt: off9407 // zig fmt: off
9349 switch (ini.key) {9408 switch (ini.key) {
9350 .declared => |d| d.captures.len,9409 inline .declared, .declared_owned_captures => |d| d.captures.len,
9351 .reified => 2, // type_hash: PackedU649410 .reified => 2, // type_hash: PackedU64
9352 } +9411 } +
9353 // zig fmt: on9412 // zig fmt: on
...@@ -9358,7 +9417,7 @@ pub fn getEnumType(...@@ -9358,7 +9417,7 @@ pub fn getEnumType(
9358 const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{9417 const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{
9359 .name = undefined, // set by `prepare`9418 .name = undefined, // set by `prepare`
9360 .captures_len = switch (ini.key) {9419 .captures_len = switch (ini.key) {
9361 .declared => |d| @intCast(d.captures.len),9420 inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
9362 .reified => std.math.maxInt(u32),9421 .reified => std.math.maxInt(u32),
9363 },9422 },
9364 .namespace = undefined, // set by `prepare`9423 .namespace = undefined, // set by `prepare`
...@@ -9382,6 +9441,7 @@ pub fn getEnumType(...@@ -9382,6 +9441,7 @@ pub fn getEnumType(
9382 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`9441 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
9383 switch (ini.key) {9442 switch (ini.key) {
9384 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),9443 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
9444 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
9385 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),9445 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
9386 }9446 }
9387 const names_start = extra.mutate.len;9447 const names_start = extra.mutate.len;
...@@ -9445,10 +9505,12 @@ pub fn getGeneratedTagEnumType(...@@ -9445,10 +9505,12 @@ pub fn getGeneratedTagEnumType(
9445 .tid = tid,9505 .tid = tid,
9446 .index = items.mutate.len,9506 .index = items.mutate.len,
9447 }, ip);9507 }, ip);
9508 const parent_namespace = ip.namespacePtr(ini.parent_namespace);
9448 const namespace = try ip.createNamespace(gpa, tid, .{9509 const namespace = try ip.createNamespace(gpa, tid, .{
9449 .parent = ini.parent_namespace.toOptional(),9510 .parent = ini.parent_namespace.toOptional(),
9450 .owner_type = enum_index,9511 .owner_type = enum_index,
9451 .file_scope = ip.namespacePtr(ini.parent_namespace).file_scope,9512 .file_scope = parent_namespace.file_scope,
9513 .generation = parent_namespace.generation,
9452 });9514 });
9453 errdefer ip.destroyNamespace(tid, namespace);9515 errdefer ip.destroyNamespace(tid, namespace);
94549516
...@@ -11044,6 +11106,7 @@ pub fn destroyNamespace(...@@ -11044,6 +11106,7 @@ pub fn destroyNamespace(
11044 .parent = undefined,11106 .parent = undefined,
11045 .file_scope = undefined,11107 .file_scope = undefined,
11046 .owner_type = undefined,11108 .owner_type = undefined,
11109 .generation = undefined,
11047 };11110 };
11048 @field(namespace, Local.namespace_next_free_field) =11111 @field(namespace, Local.namespace_next_free_field) =
11049 @enumFromInt(local.mutate.namespaces.free_list);11112 @enumFromInt(local.mutate.namespaces.free_list);
src/Sema.zig+254-198
...@@ -2723,32 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) {...@@ -2723,32 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) {
2723 return new;2723 return new;
2724}2724}
27252725
2726/// Given a type just looked up in the `InternPool`, check whether it is
2727/// considered outdated on this update. If so, returns `true`, and the
2728/// caller must replace the outdated type with a fresh one.
2729fn checkOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
2730 const pt = sema.pt;
2731 const zcu = pt.zcu;
2732 const ip = &zcu.intern_pool;
2733
2734 if (!zcu.comp.incremental) return false;
2735
2736 const cau_index = switch (ip.indexToKey(ty)) {
2737 .struct_type => ip.loadStructType(ty).cau.unwrap().?,
2738 .union_type => ip.loadUnionType(ty).cau,
2739 .enum_type => ip.loadEnumType(ty).cau.unwrap().?,
2740 else => unreachable,
2741 };
2742 const cau_unit = AnalUnit.wrap(.{ .cau = cau_index });
2743 const was_outdated = zcu.outdated.swapRemove(cau_unit) or
2744 zcu.potentially_outdated.swapRemove(cau_unit);
2745 if (!was_outdated) return false;
2746 _ = zcu.outdated_ready.swapRemove(cau_unit);
2747 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, cau_unit);
2748 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
2749 return true;
2750}
2751
2752fn zirStructDecl(2726fn zirStructDecl(
2753 sema: *Sema,2727 sema: *Sema,
2754 block: *Block,2728 block: *Block,
...@@ -2815,13 +2789,16 @@ fn zirStructDecl(...@@ -2815,13 +2789,16 @@ fn zirStructDecl(
2815 } },2789 } },
2816 };2790 };
2817 const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) {2791 const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) {
2818 .existing => |ty| wip: {2792 .existing => |ty| {
2819 if (!try sema.checkOutdatedType(ty)) {2793 const new_ty = try pt.ensureTypeUpToDate(ty, false);
2820 try sema.declareDependency(.{ .interned = ty });2794
2821 try sema.addTypeReferenceEntry(src, ty);2795 // Make sure we update the namespace if the declaration is re-analyzed, to pick
2822 return Air.internedToRef(ty);2796 // up on e.g. changed comptime decls.
2823 }2797 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod));
2824 break :wip (try ip.getStructType(gpa, pt.tid, struct_init, true)).wip;2798
2799 try sema.declareDependency(.{ .interned = new_ty });
2800 try sema.addTypeReferenceEntry(src, new_ty);
2801 return Air.internedToRef(new_ty);
2825 },2802 },
2826 .wip => |wip| wip,2803 .wip => |wip| wip,
2827 });2804 });
...@@ -2839,6 +2816,7 @@ fn zirStructDecl(...@@ -2839,6 +2816,7 @@ fn zirStructDecl(
2839 .parent = block.namespace.toOptional(),2816 .parent = block.namespace.toOptional(),
2840 .owner_type = wip_ty.index,2817 .owner_type = wip_ty.index,
2841 .file_scope = block.getFileScopeIndex(mod),2818 .file_scope = block.getFileScopeIndex(mod),
2819 .generation = mod.generation,
2842 });2820 });
2843 errdefer pt.destroyNamespace(new_namespace_index);2821 errdefer pt.destroyNamespace(new_namespace_index);
28442822
...@@ -2977,7 +2955,6 @@ fn zirEnumDecl(...@@ -2977,7 +2955,6 @@ fn zirEnumDecl(
29772955
2978 const tracked_inst = try block.trackZir(inst);2956 const tracked_inst = try block.trackZir(inst);
2979 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };2957 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };
2980 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
29812958
2982 const tag_type_ref = if (small.has_tag_type) blk: {2959 const tag_type_ref = if (small.has_tag_type) blk: {
2983 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);2960 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
...@@ -3041,13 +3018,16 @@ fn zirEnumDecl(...@@ -3041,13 +3018,16 @@ fn zirEnumDecl(
3041 } },3018 } },
3042 };3019 };
3043 const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) {3020 const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) {
3044 .existing => |ty| wip: {3021 .existing => |ty| {
3045 if (!try sema.checkOutdatedType(ty)) {3022 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3046 try sema.declareDependency(.{ .interned = ty });3023
3047 try sema.addTypeReferenceEntry(src, ty);3024 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3048 return Air.internedToRef(ty);3025 // up on e.g. changed comptime decls.
3049 }3026 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod));
3050 break :wip (try ip.getEnumType(gpa, pt.tid, enum_init, true)).wip;3027
3028 try sema.declareDependency(.{ .interned = new_ty });
3029 try sema.addTypeReferenceEntry(src, new_ty);
3030 return Air.internedToRef(new_ty);
3051 },3031 },
3052 .wip => |wip| wip,3032 .wip => |wip| wip,
3053 });3033 });
...@@ -3071,19 +3051,12 @@ fn zirEnumDecl(...@@ -3071,19 +3051,12 @@ fn zirEnumDecl(
3071 .parent = block.namespace.toOptional(),3051 .parent = block.namespace.toOptional(),
3072 .owner_type = wip_ty.index,3052 .owner_type = wip_ty.index,
3073 .file_scope = block.getFileScopeIndex(mod),3053 .file_scope = block.getFileScopeIndex(mod),
3054 .generation = mod.generation,
3074 });3055 });
3075 errdefer if (!done) pt.destroyNamespace(new_namespace_index);3056 errdefer if (!done) pt.destroyNamespace(new_namespace_index);
30763057
3077 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);3058 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
30783059
3079 if (pt.zcu.comp.incremental) {
3080 try mod.intern_pool.addDependency(
3081 gpa,
3082 AnalUnit.wrap(.{ .cau = new_cau_index }),
3083 .{ .src_hash = try block.trackZir(inst) },
3084 );
3085 }
3086
3087 try pt.scanNamespace(new_namespace_index, decls);3060 try pt.scanNamespace(new_namespace_index, decls);
30883061
3089 try sema.declareDependency(.{ .interned = wip_ty.index });3062 try sema.declareDependency(.{ .interned = wip_ty.index });
...@@ -3094,144 +3067,22 @@ fn zirEnumDecl(...@@ -3094,144 +3067,22 @@ fn zirEnumDecl(
3094 wip_ty.prepare(ip, new_cau_index, new_namespace_index);3067 wip_ty.prepare(ip, new_cau_index, new_namespace_index);
3095 done = true;3068 done = true;
30963069
3097 const int_tag_ty = ty: {3070 try Sema.resolveDeclaredEnum(
3098 // We create a block for the field type instructions because they3071 pt,
3099 // may need to reference Decls from inside the enum namespace.3072 wip_ty,
3100 // Within the field type, default value, and alignment expressions, the owner should be the enum's `Cau`.3073 inst,
31013074 tracked_inst,
3102 const prev_owner = sema.owner;3075 new_namespace_index,
3103 sema.owner = AnalUnit.wrap(.{ .cau = new_cau_index });3076 type_name,
3104 defer sema.owner = prev_owner;3077 new_cau_index,
31053078 small,
3106 const prev_func_index = sema.func_index;3079 body,
3107 sema.func_index = .none;3080 tag_type_ref,
3108 defer sema.func_index = prev_func_index;3081 any_values,
31093082 fields_len,
3110 var enum_block: Block = .{3083 sema.code,
3111 .parent = null,3084 body_end,
3112 .sema = sema,3085 );
3113 .namespace = new_namespace_index,
3114 .instructions = .{},
3115 .inlining = null,
3116 .is_comptime = true,
3117 .src_base_inst = tracked_inst,
3118 .type_name_ctx = type_name,
3119 };
3120 defer enum_block.instructions.deinit(sema.gpa);
3121
3122 if (body.len != 0) {
3123 _ = try sema.analyzeInlineBody(&enum_block, body, inst);
3124 }
3125
3126 if (tag_type_ref != .none) {
3127 const ty = try sema.resolveType(&enum_block, tag_ty_src, tag_type_ref);
3128 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
3129 return sema.fail(&enum_block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)});
3130 }
3131 break :ty ty;
3132 } else if (fields_len == 0) {
3133 break :ty try pt.intType(.unsigned, 0);
3134 } else {
3135 const bits = std.math.log2_int_ceil(usize, fields_len);
3136 break :ty try pt.intType(.unsigned, bits);
3137 }
3138 };
3139
3140 wip_ty.setTagTy(ip, int_tag_ty.toIntern());
3141
3142 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
3143 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) {
3144 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
3145 }
3146 }
3147
3148 var bit_bag_index: usize = body_end;
3149 var cur_bit_bag: u32 = undefined;
3150 var field_i: u32 = 0;
3151 var last_tag_val: ?Value = null;
3152 while (field_i < fields_len) : (field_i += 1) {
3153 if (field_i % 32 == 0) {
3154 cur_bit_bag = sema.code.extra[bit_bag_index];
3155 bit_bag_index += 1;
3156 }
3157 const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
3158 cur_bit_bag >>= 1;
3159
3160 const field_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
3161 const field_name_zir = sema.code.nullTerminatedString(field_name_index);
3162 extra_index += 2; // field name, doc comment
3163
3164 const field_name = try mod.intern_pool.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls);
3165
3166 const value_src: LazySrcLoc = .{
3167 .base_node_inst = tracked_inst,
3168 .offset = .{ .container_field_value = field_i },
3169 };
3170
3171 const tag_overflow = if (has_tag_value) overflow: {
3172 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
3173 extra_index += 1;
3174 const tag_inst = try sema.resolveInst(tag_val_ref);
3175 last_tag_val = try sema.resolveConstDefinedValue(block, .{
3176 .base_node_inst = tracked_inst,
3177 .offset = .{ .container_field_name = field_i },
3178 }, tag_inst, .{
3179 .needed_comptime_reason = "enum tag value must be comptime-known",
3180 });
3181 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
3182 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
3183 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3184 assert(conflict.kind == .value); // AstGen validated names are unique
3185 const other_field_src: LazySrcLoc = .{
3186 .base_node_inst = tracked_inst,
3187 .offset = .{ .container_field_value = conflict.prev_field_idx },
3188 };
3189 const msg = msg: {
3190 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3191 errdefer msg.destroy(gpa);
3192 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3193 break :msg msg;
3194 };
3195 return sema.failWithOwnedErrorMsg(block, msg);
3196 }
3197 break :overflow false;
3198 } else if (any_values) overflow: {
3199 var overflow: ?usize = null;
3200 last_tag_val = if (last_tag_val) |val|
3201 try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow)
3202 else
3203 try pt.intValue(int_tag_ty, 0);
3204 if (overflow != null) break :overflow true;
3205 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3206 assert(conflict.kind == .value); // AstGen validated names are unique
3207 const other_field_src: LazySrcLoc = .{
3208 .base_node_inst = tracked_inst,
3209 .offset = .{ .container_field_value = conflict.prev_field_idx },
3210 };
3211 const msg = msg: {
3212 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3213 errdefer msg.destroy(gpa);
3214 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3215 break :msg msg;
3216 };
3217 return sema.failWithOwnedErrorMsg(block, msg);
3218 }
3219 break :overflow false;
3220 } else overflow: {
3221 assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null);
3222 last_tag_val = try pt.intValue(Type.comptime_int, field_i);
3223 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
3224 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
3225 break :overflow false;
3226 };
3227
3228 if (tag_overflow) {
3229 const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{
3230 last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt),
3231 });
3232 return sema.failWithOwnedErrorMsg(block, msg);
3233 }
3234 }
32353086
3236 codegen_type: {3087 codegen_type: {
3237 if (mod.comp.config.use_llvm) break :codegen_type;3088 if (mod.comp.config.use_llvm) break :codegen_type;
...@@ -3311,13 +3162,16 @@ fn zirUnionDecl(...@@ -3311,13 +3162,16 @@ fn zirUnionDecl(
3311 } },3162 } },
3312 };3163 };
3313 const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) {3164 const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) {
3314 .existing => |ty| wip: {3165 .existing => |ty| {
3315 if (!try sema.checkOutdatedType(ty)) {3166 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3316 try sema.declareDependency(.{ .interned = ty });3167
3317 try sema.addTypeReferenceEntry(src, ty);3168 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3318 return Air.internedToRef(ty);3169 // up on e.g. changed comptime decls.
3319 }3170 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod));
3320 break :wip (try ip.getUnionType(gpa, pt.tid, union_init, true)).wip;3171
3172 try sema.declareDependency(.{ .interned = new_ty });
3173 try sema.addTypeReferenceEntry(src, new_ty);
3174 return Air.internedToRef(new_ty);
3321 },3175 },
3322 .wip => |wip| wip,3176 .wip => |wip| wip,
3323 });3177 });
...@@ -3335,6 +3189,7 @@ fn zirUnionDecl(...@@ -3335,6 +3189,7 @@ fn zirUnionDecl(
3335 .parent = block.namespace.toOptional(),3189 .parent = block.namespace.toOptional(),
3336 .owner_type = wip_ty.index,3190 .owner_type = wip_ty.index,
3337 .file_scope = block.getFileScopeIndex(mod),3191 .file_scope = block.getFileScopeIndex(mod),
3192 .generation = mod.generation,
3338 });3193 });
3339 errdefer pt.destroyNamespace(new_namespace_index);3194 errdefer pt.destroyNamespace(new_namespace_index);
33403195
...@@ -3344,7 +3199,7 @@ fn zirUnionDecl(...@@ -3344,7 +3199,7 @@ fn zirUnionDecl(
3344 try mod.intern_pool.addDependency(3199 try mod.intern_pool.addDependency(
3345 gpa,3200 gpa,
3346 AnalUnit.wrap(.{ .cau = new_cau_index }),3201 AnalUnit.wrap(.{ .cau = new_cau_index }),
3347 .{ .src_hash = try block.trackZir(inst) },3202 .{ .src_hash = tracked_inst },
3348 );3203 );
3349 }3204 }
33503205
...@@ -3406,8 +3261,12 @@ fn zirOpaqueDecl(...@@ -3406,8 +3261,12 @@ fn zirOpaqueDecl(
3406 };3261 };
3407 // No `wrapWipTy` needed as no std.builtin types are opaque.3262 // No `wrapWipTy` needed as no std.builtin types are opaque.
3408 const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) {3263 const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) {
3409 // No `checkOutdatedType` as opaque types are never outdated.
3410 .existing => |ty| {3264 .existing => |ty| {
3265 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3266 // up on e.g. changed comptime decls.
3267 try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(mod));
3268
3269 try sema.declareDependency(.{ .interned = ty });
3411 try sema.addTypeReferenceEntry(src, ty);3270 try sema.addTypeReferenceEntry(src, ty);
3412 return Air.internedToRef(ty);3271 return Air.internedToRef(ty);
3413 },3272 },
...@@ -3427,6 +3286,7 @@ fn zirOpaqueDecl(...@@ -3427,6 +3286,7 @@ fn zirOpaqueDecl(
3427 .parent = block.namespace.toOptional(),3286 .parent = block.namespace.toOptional(),
3428 .owner_type = wip_ty.index,3287 .owner_type = wip_ty.index,
3429 .file_scope = block.getFileScopeIndex(mod),3288 .file_scope = block.getFileScopeIndex(mod),
3289 .generation = mod.generation,
3430 });3290 });
3431 errdefer pt.destroyNamespace(new_namespace_index);3291 errdefer pt.destroyNamespace(new_namespace_index);
34323292
...@@ -6072,6 +5932,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6072,6 +5932,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
6072 // trigger re-analysis later.5932 // trigger re-analysis later.
6073 try pt.ensureFileAnalyzed(result.file_index);5933 try pt.ensureFileAnalyzed(result.file_index);
6074 const ty = zcu.fileRootType(result.file_index);5934 const ty = zcu.fileRootType(result.file_index);
5935 try sema.declareDependency(.{ .interned = ty });
6075 try sema.addTypeReferenceEntry(src, ty);5936 try sema.addTypeReferenceEntry(src, ty);
6076 return Air.internedToRef(ty);5937 return Air.internedToRef(ty);
6077}5938}
...@@ -6821,6 +6682,8 @@ fn lookupInNamespace(...@@ -6821,6 +6682,8 @@ fn lookupInNamespace(
6821 const zcu = pt.zcu;6682 const zcu = pt.zcu;
6822 const ip = &zcu.intern_pool;6683 const ip = &zcu.intern_pool;
68236684
6685 try pt.ensureNamespaceUpToDate(namespace_index);
6686
6824 const namespace = zcu.namespacePtr(namespace_index);6687 const namespace = zcu.namespacePtr(namespace_index);
68256688
6826 const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu };6689 const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu };
...@@ -14038,6 +13901,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14038,6 +13901,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14038 // trigger re-analysis later.13901 // trigger re-analysis later.
14039 try pt.ensureFileAnalyzed(result.file_index);13902 try pt.ensureFileAnalyzed(result.file_index);
14040 const ty = zcu.fileRootType(result.file_index);13903 const ty = zcu.fileRootType(result.file_index);
13904 try sema.declareDependency(.{ .interned = ty });
14041 try sema.addTypeReferenceEntry(operand_src, ty);13905 try sema.addTypeReferenceEntry(operand_src, ty);
14042 return Air.internedToRef(ty);13906 return Air.internedToRef(ty);
14043}13907}
...@@ -17703,7 +17567,13 @@ fn zirThis(...@@ -17703,7 +17567,13 @@ fn zirThis(
17703 _ = extended;17567 _ = extended;
17704 const pt = sema.pt;17568 const pt = sema.pt;
17705 const namespace = pt.zcu.namespacePtr(block.namespace);17569 const namespace = pt.zcu.namespacePtr(block.namespace);
17706 return Air.internedToRef(namespace.owner_type);17570 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type, false);
17571 switch (pt.zcu.intern_pool.indexToKey(new_ty)) {
17572 .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }),
17573 .opaque_type => {},
17574 else => unreachable,
17575 }
17576 return Air.internedToRef(new_ty);
17707}17577}
1770817578
17709fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {17579fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
...@@ -19005,6 +18875,7 @@ fn typeInfoNamespaceDecls(...@@ -19005,6 +18875,7 @@ fn typeInfoNamespaceDecls(
19005 const ip = &zcu.intern_pool;18875 const ip = &zcu.intern_pool;
1900618876
19007 const namespace_index = opt_namespace_index.unwrap() orelse return;18877 const namespace_index = opt_namespace_index.unwrap() orelse return;
18878 try pt.ensureNamespaceUpToDate(namespace_index);
19008 const namespace = zcu.namespacePtr(namespace_index);18879 const namespace = zcu.namespacePtr(namespace_index);
1900918880
19010 const gop = try seen_namespaces.getOrPut(namespace);18881 const gop = try seen_namespaces.getOrPut(namespace);
...@@ -21871,6 +21742,7 @@ fn zirReify(...@@ -21871,6 +21742,7 @@ fn zirReify(
21871 .parent = block.namespace.toOptional(),21742 .parent = block.namespace.toOptional(),
21872 .owner_type = wip_ty.index,21743 .owner_type = wip_ty.index,
21873 .file_scope = block.getFileScopeIndex(mod),21744 .file_scope = block.getFileScopeIndex(mod),
21745 .generation = mod.generation,
21874 });21746 });
2187521747
21876 try sema.addTypeReferenceEntry(src, wip_ty.index);21748 try sema.addTypeReferenceEntry(src, wip_ty.index);
...@@ -22080,6 +21952,7 @@ fn reifyEnum(...@@ -22080,6 +21952,7 @@ fn reifyEnum(
22080 .parent = block.namespace.toOptional(),21952 .parent = block.namespace.toOptional(),
22081 .owner_type = wip_ty.index,21953 .owner_type = wip_ty.index,
22082 .file_scope = block.getFileScopeIndex(mod),21954 .file_scope = block.getFileScopeIndex(mod),
21955 .generation = mod.generation,
22083 });21956 });
2208421957
22085 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);21958 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
...@@ -22384,6 +22257,7 @@ fn reifyUnion(...@@ -22384,6 +22257,7 @@ fn reifyUnion(
22384 .parent = block.namespace.toOptional(),22257 .parent = block.namespace.toOptional(),
22385 .owner_type = wip_ty.index,22258 .owner_type = wip_ty.index,
22386 .file_scope = block.getFileScopeIndex(mod),22259 .file_scope = block.getFileScopeIndex(mod),
22260 .generation = mod.generation,
22387 });22261 });
2238822262
22389 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);22263 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
...@@ -22667,6 +22541,7 @@ fn reifyStruct(...@@ -22667,6 +22541,7 @@ fn reifyStruct(
22667 .parent = block.namespace.toOptional(),22541 .parent = block.namespace.toOptional(),
22668 .owner_type = wip_ty.index,22542 .owner_type = wip_ty.index,
22669 .file_scope = block.getFileScopeIndex(mod),22543 .file_scope = block.getFileScopeIndex(mod),
22544 .generation = mod.generation,
22670 });22545 });
2267122546
22672 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);22547 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
...@@ -35373,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {...@@ -35373,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
35373 if (struct_type.haveLayout(ip))35248 if (struct_type.haveLayout(ip))
35374 return;35249 return;
3537535250
35376 try ty.resolveFields(pt);35251 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
3537735252
35378 if (struct_type.layout == .@"packed") {35253 if (struct_type.layout == .@"packed") {
35379 semaBackingIntType(pt, struct_type) catch |err| switch (err) {35254 semaBackingIntType(pt, struct_type) catch |err| switch (err) {
...@@ -38499,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index {...@@ -38499,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index {
38499 return ip.getCau(cau).zir_index;38374 return ip.getCau(cau).zir_index;
38500}38375}
3850138376
38377/// Called as soon as a `declared` enum type is created.
38378/// Resolves the tag type and field inits.
38379/// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this.
38380pub fn resolveDeclaredEnum(
38381 pt: Zcu.PerThread,
38382 wip_ty: InternPool.WipEnumType,
38383 inst: Zir.Inst.Index,
38384 tracked_inst: InternPool.TrackedInst.Index,
38385 namespace: InternPool.NamespaceIndex,
38386 type_name: InternPool.NullTerminatedString,
38387 enum_cau: InternPool.Cau.Index,
38388 small: Zir.Inst.EnumDecl.Small,
38389 body: []const Zir.Inst.Index,
38390 tag_type_ref: Zir.Inst.Ref,
38391 any_values: bool,
38392 fields_len: u32,
38393 zir: Zir,
38394 body_end: usize,
38395) Zcu.CompileError!void {
38396 const zcu = pt.zcu;
38397 const gpa = zcu.gpa;
38398 const ip = &zcu.intern_pool;
38399
38400 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
38401
38402 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };
38403 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
38404
38405 const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau });
38406
38407 var arena = std.heap.ArenaAllocator.init(gpa);
38408 defer arena.deinit();
38409
38410 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
38411 defer comptime_err_ret_trace.deinit();
38412
38413 var sema: Sema = .{
38414 .pt = pt,
38415 .gpa = gpa,
38416 .arena = arena.allocator(),
38417 .code = zir,
38418 .owner = anal_unit,
38419 .func_index = .none,
38420 .func_is_naked = false,
38421 .fn_ret_ty = Type.void,
38422 .fn_ret_ty_ies = null,
38423 .comptime_err_ret_trace = &comptime_err_ret_trace,
38424 };
38425 defer sema.deinit();
38426
38427 try sema.declareDependency(.{ .src_hash = tracked_inst });
38428
38429 var block: Block = .{
38430 .parent = null,
38431 .sema = &sema,
38432 .namespace = namespace,
38433 .instructions = .{},
38434 .inlining = null,
38435 .is_comptime = true,
38436 .src_base_inst = tracked_inst,
38437 .type_name_ctx = type_name,
38438 };
38439 defer block.instructions.deinit(gpa);
38440
38441 const int_tag_ty = ty: {
38442 if (body.len != 0) {
38443 _ = try sema.analyzeInlineBody(&block, body, inst);
38444 }
38445
38446 if (tag_type_ref != .none) {
38447 const ty = try sema.resolveType(&block, tag_ty_src, tag_type_ref);
38448 if (ty.zigTypeTag(zcu) != .Int and ty.zigTypeTag(zcu) != .ComptimeInt) {
38449 return sema.fail(&block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)});
38450 }
38451 break :ty ty;
38452 } else if (fields_len == 0) {
38453 break :ty try pt.intType(.unsigned, 0);
38454 } else {
38455 const bits = std.math.log2_int_ceil(usize, fields_len);
38456 break :ty try pt.intType(.unsigned, bits);
38457 }
38458 };
38459
38460 wip_ty.setTagTy(ip, int_tag_ty.toIntern());
38461
38462 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
38463 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) {
38464 return sema.fail(&block, src, "non-exhaustive enum specifies every value", .{});
38465 }
38466 }
38467
38468 var extra_index = body_end + bit_bags_count;
38469 var bit_bag_index: usize = body_end;
38470 var cur_bit_bag: u32 = undefined;
38471 var last_tag_val: ?Value = null;
38472 for (0..fields_len) |field_i_usize| {
38473 const field_i: u32 = @intCast(field_i_usize);
38474 if (field_i % 32 == 0) {
38475 cur_bit_bag = zir.extra[bit_bag_index];
38476 bit_bag_index += 1;
38477 }
38478 const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
38479 cur_bit_bag >>= 1;
38480
38481 const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]);
38482 const field_name_zir = zir.nullTerminatedString(field_name_index);
38483 extra_index += 2; // field name, doc comment
38484
38485 const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls);
38486
38487 const value_src: LazySrcLoc = .{
38488 .base_node_inst = tracked_inst,
38489 .offset = .{ .container_field_value = field_i },
38490 };
38491
38492 const tag_overflow = if (has_tag_value) overflow: {
38493 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
38494 extra_index += 1;
38495 const tag_inst = try sema.resolveInst(tag_val_ref);
38496 last_tag_val = try sema.resolveConstDefinedValue(&block, .{
38497 .base_node_inst = tracked_inst,
38498 .offset = .{ .container_field_name = field_i },
38499 }, tag_inst, .{
38500 .needed_comptime_reason = "enum tag value must be comptime-known",
38501 });
38502 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
38503 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
38504 if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
38505 assert(conflict.kind == .value); // AstGen validated names are unique
38506 const other_field_src: LazySrcLoc = .{
38507 .base_node_inst = tracked_inst,
38508 .offset = .{ .container_field_value = conflict.prev_field_idx },
38509 };
38510 const msg = msg: {
38511 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)});
38512 errdefer msg.destroy(gpa);
38513 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
38514 break :msg msg;
38515 };
38516 return sema.failWithOwnedErrorMsg(&block, msg);
38517 }
38518 break :overflow false;
38519 } else if (any_values) overflow: {
38520 var overflow: ?usize = null;
38521 last_tag_val = if (last_tag_val) |val|
38522 try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow)
38523 else
38524 try pt.intValue(int_tag_ty, 0);
38525 if (overflow != null) break :overflow true;
38526 if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
38527 assert(conflict.kind == .value); // AstGen validated names are unique
38528 const other_field_src: LazySrcLoc = .{
38529 .base_node_inst = tracked_inst,
38530 .offset = .{ .container_field_value = conflict.prev_field_idx },
38531 };
38532 const msg = msg: {
38533 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)});
38534 errdefer msg.destroy(gpa);
38535 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
38536 break :msg msg;
38537 };
38538 return sema.failWithOwnedErrorMsg(&block, msg);
38539 }
38540 break :overflow false;
38541 } else overflow: {
38542 assert(wip_ty.nextField(ip, field_name, .none) == null);
38543 last_tag_val = try pt.intValue(Type.comptime_int, field_i);
38544 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
38545 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
38546 break :overflow false;
38547 };
38548
38549 if (tag_overflow) {
38550 const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{
38551 last_tag_val.?.fmtValueSema(pt, &sema), int_tag_ty.fmt(pt),
38552 });
38553 return sema.failWithOwnedErrorMsg(&block, msg);
38554 }
38555 }
38556}
38557
38502pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;38558pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
38503pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;38559pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
3850438560
src/Zcu.zig+34-27
...@@ -215,6 +215,8 @@ panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId...@@ -215,6 +215,8 @@ panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId
215panic_func_index: InternPool.Index = .none,215panic_func_index: InternPool.Index = .none,
216null_stack_trace: InternPool.Index = .none,216null_stack_trace: InternPool.Index = .none,
217217
218generation: u32 = 0,
219
218pub const PerThread = @import("Zcu/PerThread.zig");220pub const PerThread = @import("Zcu/PerThread.zig");
219221
220pub const PanicId = enum {222pub const PanicId = enum {
...@@ -332,6 +334,7 @@ pub const TypeReference = struct {...@@ -332,6 +334,7 @@ pub const TypeReference = struct {
332pub const Namespace = struct {334pub const Namespace = struct {
333 parent: OptionalIndex,335 parent: OptionalIndex,
334 file_scope: File.Index,336 file_scope: File.Index,
337 generation: u32,
335 /// Will be a struct, enum, union, or opaque.338 /// Will be a struct, enum, union, or opaque.
336 owner_type: InternPool.Index,339 owner_type: InternPool.Index,
337 /// Members of the namespace which are marked `pub`.340 /// Members of the namespace which are marked `pub`.
...@@ -2295,7 +2298,7 @@ pub fn markDependeeOutdated(...@@ -2295,7 +2298,7 @@ pub fn markDependeeOutdated(
2295 marked_po: enum { not_marked_po, marked_po },2298 marked_po: enum { not_marked_po, marked_po },
2296 dependee: InternPool.Dependee,2299 dependee: InternPool.Dependee,
2297) !void {2300) !void {
2298 log.debug("outdated dependee: {}", .{fmtDependee(dependee, zcu)});2301 log.debug("outdated dependee: {}", .{zcu.fmtDependee(dependee)});
2299 var it = zcu.intern_pool.dependencyIterator(dependee);2302 var it = zcu.intern_pool.dependencyIterator(dependee);
2300 while (it.next()) |depender| {2303 while (it.next()) |depender| {
2301 if (zcu.outdated.getPtr(depender)) |po_dep_count| {2304 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
...@@ -2303,9 +2306,9 @@ pub fn markDependeeOutdated(...@@ -2303,9 +2306,9 @@ pub fn markDependeeOutdated(
2303 .not_marked_po => {},2306 .not_marked_po => {},
2304 .marked_po => {2307 .marked_po => {
2305 po_dep_count.* -= 1;2308 po_dep_count.* -= 1;
2306 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), po_dep_count.* });2309 log.debug("outdated {} => already outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
2307 if (po_dep_count.* == 0) {2310 if (po_dep_count.* == 0) {
2308 log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)});2311 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
2309 try zcu.outdated_ready.put(zcu.gpa, depender, {});2312 try zcu.outdated_ready.put(zcu.gpa, depender, {});
2310 }2313 }
2311 },2314 },
...@@ -2316,20 +2319,19 @@ pub fn markDependeeOutdated(...@@ -2316,20 +2319,19 @@ pub fn markDependeeOutdated(
2316 const new_po_dep_count = switch (marked_po) {2319 const new_po_dep_count = switch (marked_po) {
2317 .not_marked_po => if (opt_po_entry) |e| e.value else 0,2320 .not_marked_po => if (opt_po_entry) |e| e.value else 0,
2318 .marked_po => if (opt_po_entry) |e| e.value - 1 else {2321 .marked_po => if (opt_po_entry) |e| e.value - 1 else {
2319 // This dependency has been registered during in-progress analysis, but the unit is2322 // This `AnalUnit` has already been re-analyzed this update, and registered a dependency
2320 // not in `potentially_outdated` because analysis is in-progress. Nothing to do.2323 // on this thing, but already has sufficiently up-to-date information. Nothing to do.
2321 continue;2324 continue;
2322 },2325 },
2323 };2326 };
2324 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), new_po_dep_count });
2325 try zcu.outdated.putNoClobber(2327 try zcu.outdated.putNoClobber(
2326 zcu.gpa,2328 zcu.gpa,
2327 depender,2329 depender,
2328 new_po_dep_count,2330 new_po_dep_count,
2329 );2331 );
2330 log.debug("outdated: {}", .{fmtAnalUnit(depender, zcu)});2332 log.debug("outdated {} => new outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
2331 if (new_po_dep_count == 0) {2333 if (new_po_dep_count == 0) {
2332 log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)});2334 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
2333 try zcu.outdated_ready.put(zcu.gpa, depender, {});2335 try zcu.outdated_ready.put(zcu.gpa, depender, {});
2334 }2336 }
2335 // If this is a Decl and was not previously PO, we must recursively2337 // If this is a Decl and was not previously PO, we must recursively
...@@ -2342,16 +2344,16 @@ pub fn markDependeeOutdated(...@@ -2342,16 +2344,16 @@ pub fn markDependeeOutdated(
2342}2344}
23432345
2344pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {2346pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2345 log.debug("up-to-date dependee: {}", .{fmtDependee(dependee, zcu)});2347 log.debug("up-to-date dependee: {}", .{zcu.fmtDependee(dependee)});
2346 var it = zcu.intern_pool.dependencyIterator(dependee);2348 var it = zcu.intern_pool.dependencyIterator(dependee);
2347 while (it.next()) |depender| {2349 while (it.next()) |depender| {
2348 if (zcu.outdated.getPtr(depender)) |po_dep_count| {2350 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
2349 // This depender is already outdated, but it now has one2351 // This depender is already outdated, but it now has one
2350 // less PO dependency!2352 // less PO dependency!
2351 po_dep_count.* -= 1;2353 po_dep_count.* -= 1;
2352 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), po_dep_count.* });2354 log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
2353 if (po_dep_count.* == 0) {2355 if (po_dep_count.* == 0) {
2354 log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)});2356 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
2355 try zcu.outdated_ready.put(zcu.gpa, depender, {});2357 try zcu.outdated_ready.put(zcu.gpa, depender, {});
2356 }2358 }
2357 continue;2359 continue;
...@@ -2365,11 +2367,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -2365,11 +2367,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2365 };2367 };
2366 if (ptr.* > 1) {2368 if (ptr.* > 1) {
2367 ptr.* -= 1;2369 ptr.* -= 1;
2368 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), ptr.* });2370 log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
2369 continue;2371 continue;
2370 }2372 }
23712373
2372 log.debug("up-to-date (po deps = 0): {}", .{fmtAnalUnit(depender, zcu)});2374 log.debug("up-to-date {} => {} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
23732375
2374 // This dependency is no longer PO, i.e. is known to be up-to-date.2376 // This dependency is no longer PO, i.e. is known to be up-to-date.
2375 assert(zcu.potentially_outdated.swapRemove(depender));2377 assert(zcu.potentially_outdated.swapRemove(depender));
...@@ -2398,7 +2400,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -2398,7 +2400,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
2398 },2400 },
2399 .func => |func_index| .{ .interned = func_index }, // IES2401 .func => |func_index| .{ .interned = func_index }, // IES
2400 };2402 };
2401 log.debug("marking dependee po: {}", .{fmtDependee(dependee, zcu)});2403 log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
2402 var it = ip.dependencyIterator(dependee);2404 var it = ip.dependencyIterator(dependee);
2403 while (it.next()) |po| {2405 while (it.next()) |po| {
2404 if (zcu.outdated.getPtr(po)) |po_dep_count| {2406 if (zcu.outdated.getPtr(po)) |po_dep_count| {
...@@ -2408,17 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -2408,17 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
2408 _ = zcu.outdated_ready.swapRemove(po);2410 _ = zcu.outdated_ready.swapRemove(po);
2409 }2411 }
2410 po_dep_count.* += 1;2412 po_dep_count.* += 1;
2411 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), po_dep_count.* });2413 log.debug("po {} => {} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
2412 continue;2414 continue;
2413 }2415 }
2414 if (zcu.potentially_outdated.getPtr(po)) |n| {2416 if (zcu.potentially_outdated.getPtr(po)) |n| {
2415 // There is now one more PO dependency.2417 // There is now one more PO dependency.
2416 n.* += 1;2418 n.* += 1;
2417 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), n.* });2419 log.debug("po {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
2418 continue;2420 continue;
2419 }2421 }
2420 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);2422 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
2421 log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), 1 });2423 log.debug("po {} => {} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
2422 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.2424 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
2423 try zcu.markTransitiveDependersPotentiallyOutdated(po);2425 try zcu.markTransitiveDependersPotentiallyOutdated(po);
2424 }2426 }
...@@ -2443,7 +2445,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {...@@ -2443,7 +2445,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
24432445
2444 if (zcu.outdated_ready.count() > 0) {2446 if (zcu.outdated_ready.count() > 0) {
2445 const unit = zcu.outdated_ready.keys()[0];2447 const unit = zcu.outdated_ready.keys()[0];
2446 log.debug("findOutdatedToAnalyze: trivial {}", .{fmtAnalUnit(unit, zcu)});2448 log.debug("findOutdatedToAnalyze: trivial {}", .{zcu.fmtAnalUnit(unit)});
2447 return unit;2449 return unit;
2448 }2450 }
24492451
...@@ -2498,10 +2500,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {...@@ -2498,10 +2500,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
2498 const nav = zcu.funcInfo(func).owner_nav;2500 const nav = zcu.funcInfo(func).owner_nav;
2499 std.io.getStdErr().writer().print("outdated: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {};2501 std.io.getStdErr().writer().print("outdated: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {};
2500 }2502 }
2503 for (zcu.potentially_outdated.keys(), zcu.potentially_outdated.values()) |o, opod| {
2504 const func = o.unwrap().func;
2505 const nav = zcu.funcInfo(func).owner_nav;
2506 std.io.getStdErr().writer().print("po: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {};
2507 }
2501 }2508 }
25022509
2503 log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{2510 log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{
2504 fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? }), zcu),2511 zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })),
2505 chosen_cau_dependers,2512 chosen_cau_dependers,
2506 });2513 });
25072514
...@@ -2744,7 +2751,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2744,7 +2751,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2744 const gpa = zcu.gpa;2751 const gpa = zcu.gpa;
27452752
2746 unit_refs: {2753 unit_refs: {
2747 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return;2754 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
2748 var idx = kv.value;2755 var idx = kv.value;
27492756
2750 while (idx != std.math.maxInt(u32)) {2757 while (idx != std.math.maxInt(u32)) {
...@@ -2758,7 +2765,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2758,7 +2765,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2758 }2765 }
27592766
2760 type_refs: {2767 type_refs: {
2761 const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse return;2768 const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse break :type_refs;
2762 var idx = kv.value;2769 var idx = kv.value;
27632770
2764 while (idx != std.math.maxInt(u32)) {2771 while (idx != std.math.maxInt(u32)) {
...@@ -3280,7 +3287,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve...@@ -3280,7 +3287,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve
3280 const unit = kv.key;3287 const unit = kv.key;
3281 try result.putNoClobber(gpa, unit, kv.value);3288 try result.putNoClobber(gpa, unit, kv.value);
32823289
3283 log.debug("handle unit '{}'", .{fmtAnalUnit(unit, zcu)});3290 log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});
32843291
3285 if (zcu.reference_table.get(unit)) |first_ref_idx| {3292 if (zcu.reference_table.get(unit)) |first_ref_idx| {
3286 assert(first_ref_idx != std.math.maxInt(u32));3293 assert(first_ref_idx != std.math.maxInt(u32));
...@@ -3289,8 +3296,8 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve...@@ -3289,8 +3296,8 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve
3289 const ref = zcu.all_references.items[ref_idx];3296 const ref = zcu.all_references.items[ref_idx];
3290 if (!result.contains(ref.referenced)) {3297 if (!result.contains(ref.referenced)) {
3291 log.debug("unit '{}': ref unit '{}'", .{3298 log.debug("unit '{}': ref unit '{}'", .{
3292 fmtAnalUnit(unit, zcu),3299 zcu.fmtAnalUnit(unit),
3293 fmtAnalUnit(ref.referenced, zcu),3300 zcu.fmtAnalUnit(ref.referenced),
3294 });3301 });
3295 try unit_queue.put(gpa, ref.referenced, .{3302 try unit_queue.put(gpa, ref.referenced, .{
3296 .referencer = unit,3303 .referencer = unit,
...@@ -3307,7 +3314,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve...@@ -3307,7 +3314,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve
3307 const ref = zcu.all_type_references.items[ref_idx];3314 const ref = zcu.all_type_references.items[ref_idx];
3308 if (!checked_types.contains(ref.referenced)) {3315 if (!checked_types.contains(ref.referenced)) {
3309 log.debug("unit '{}': ref type '{}'", .{3316 log.debug("unit '{}': ref type '{}'", .{
3310 fmtAnalUnit(unit, zcu),3317 zcu.fmtAnalUnit(unit),
3311 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),3318 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),
3312 });3319 });
3313 try type_queue.put(gpa, ref.referenced, .{3320 try type_queue.put(gpa, ref.referenced, .{
...@@ -3389,10 +3396,10 @@ pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {...@@ -3389,10 +3396,10 @@ pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
3389 return zcu.fileByIndex(file_index);3396 return zcu.fileByIndex(file_index);
3390}3397}
33913398
3392fn fmtAnalUnit(unit: AnalUnit, zcu: *Zcu) std.fmt.Formatter(formatAnalUnit) {3399pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) {
3393 return .{ .data = .{ .unit = unit, .zcu = zcu } };3400 return .{ .data = .{ .unit = unit, .zcu = zcu } };
3394}3401}
3395fn fmtDependee(d: InternPool.Dependee, zcu: *Zcu) std.fmt.Formatter(formatDependee) {3402pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDependee) {
3396 return .{ .data = .{ .dependee = d, .zcu = zcu } };3403 return .{ .data = .{ .dependee = d, .zcu = zcu } };
3397}3404}
33983405
src/Zcu/PerThread.zig+571-83
...@@ -485,10 +485,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -485,10 +485,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
485pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {485pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
486 const file_root_type = pt.zcu.fileRootType(file_index);486 const file_root_type = pt.zcu.fileRootType(file_index);
487 if (file_root_type != .none) {487 if (file_root_type != .none) {
488 // The namespace is already up-to-date thanks to the `updateFileNamespace` calls at the488 _ = try pt.ensureTypeUpToDate(file_root_type, false);
489 // start of this update. We just have to check whether the type itself is okay!
490 const file_root_type_cau = pt.zcu.intern_pool.loadStructType(file_root_type).cau.unwrap().?;
491 return pt.ensureCauAnalyzed(file_root_type_cau);
492 } else {489 } else {
493 return pt.semaFile(file_index);490 return pt.semaFile(file_index);
494 }491 }
...@@ -505,10 +502,10 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -505,10 +502,10 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
505 const gpa = zcu.gpa;502 const gpa = zcu.gpa;
506 const ip = &zcu.intern_pool;503 const ip = &zcu.intern_pool;
507504
508 const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index });505 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
509 const cau = ip.getCau(cau_index);506 const cau = ip.getCau(cau_index);
510507
511 //log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)});508 log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)});
512509
513 assert(!zcu.analysis_in_progress.contains(anal_unit));510 assert(!zcu.analysis_in_progress.contains(anal_unit));
514511
...@@ -552,10 +549,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -552,10 +549,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
552 // Since it does not, this must be a transitive failure.549 // Since it does not, this must be a transitive failure.
553 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});550 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
554 }551 }
555 // We treat errors as up-to-date, since those uses would just trigger a transitive error552 // We treat errors as up-to-date, since those uses would just trigger a transitive error.
553 // The exception is types, since type declarations may require re-analysis if the type, e.g. its captures, changed.
554 const outdated = cau.owner.unwrap() == .type;
556 break :res .{ .{555 break :res .{ .{
557 .invalidate_decl_val = false,556 .invalidate_decl_val = outdated,
558 .invalidate_decl_ref = false,557 .invalidate_decl_ref = outdated,
559 }, true };558 }, true };
560 },559 },
561 error.OutOfMemory => res: {560 error.OutOfMemory => res: {
...@@ -610,7 +609,7 @@ fn ensureCauAnalyzedInner(...@@ -610,7 +609,7 @@ fn ensureCauAnalyzedInner(
610 const ip = &zcu.intern_pool;609 const ip = &zcu.intern_pool;
611610
612 const cau = ip.getCau(cau_index);611 const cau = ip.getCau(cau_index);
613 const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index });612 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
614613
615 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;614 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
616615
...@@ -626,7 +625,6 @@ fn ensureCauAnalyzedInner(...@@ -626,7 +625,6 @@ fn ensureCauAnalyzedInner(
626 // * so, it uses the same `struct`625 // * so, it uses the same `struct`
627 // * but this doesn't stop it from updating the namespace!626 // * but this doesn't stop it from updating the namespace!
628 // * we basically do `scanDecls`, updating the namespace as needed627 // * we basically do `scanDecls`, updating the namespace as needed
629 // * TODO: optimize this to make sure we only do it once a generation i guess?
630 // * so everyone lived happily ever after628 // * so everyone lived happily ever after
631629
632 if (zcu.fileByIndex(inst_info.file).status != .success_zir) {630 if (zcu.fileByIndex(inst_info.file).status != .success_zir) {
...@@ -646,17 +644,6 @@ fn ensureCauAnalyzedInner(...@@ -646,17 +644,6 @@ fn ensureCauAnalyzedInner(
646 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);644 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
647 }645 }
648646
649 if (inst_info.inst == .main_struct_inst) {
650 // Note that this is definitely a *recreation* due to outdated, because
651 // this instruction indicates that `cau.owner` is a `type`, which only
652 // reaches here if `cau_outdated`.
653 try pt.recreateFileRoot(inst_info.file);
654 return .{
655 .invalidate_decl_val = true,
656 .invalidate_decl_ref = true,
657 };
658 }
659
660 const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) {647 const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) {
661 .nav => |nav| ip.getNav(nav).fqn.toSlice(ip),648 .nav => |nav| ip.getNav(nav).fqn.toSlice(ip),
662 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),649 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
...@@ -685,9 +672,9 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -685,9 +672,9 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
685672
686 const func = zcu.funcInfo(maybe_coerced_func_index);673 const func = zcu.funcInfo(maybe_coerced_func_index);
687674
688 //log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)});675 log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)});
689676
690 const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index });677 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
691 const func_outdated = zcu.outdated.swapRemove(anal_unit) or678 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
692 zcu.potentially_outdated.swapRemove(anal_unit);679 zcu.potentially_outdated.swapRemove(anal_unit);
693680
...@@ -742,7 +729,7 @@ fn ensureFuncBodyAnalyzedInner(...@@ -742,7 +729,7 @@ fn ensureFuncBodyAnalyzedInner(
742 const ip = &zcu.intern_pool;729 const ip = &zcu.intern_pool;
743730
744 const func = zcu.funcInfo(func_index);731 const func = zcu.funcInfo(func_index);
745 const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index });732 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
746733
747 // Here's an interesting question: is this function actually valid?734 // Here's an interesting question: is this function actually valid?
748 // Maybe the signature changed, so we'll end up creating a whole different `func`735 // Maybe the signature changed, so we'll end up creating a whole different `func`
...@@ -766,7 +753,7 @@ fn ensureFuncBodyAnalyzedInner(...@@ -766,7 +753,7 @@ fn ensureFuncBodyAnalyzedInner(
766 if (func_outdated) {753 if (func_outdated) {
767 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); // IES754 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); // IES
768 }755 }
769 ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));756 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
770 ip.remove(pt.tid, func_index);757 ip.remove(pt.tid, func_index);
771 @panic("TODO: remove orphaned function from binary");758 @panic("TODO: remove orphaned function from binary");
772 }759 }
...@@ -901,7 +888,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai...@@ -901,7 +888,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
901 "unable to codegen: {s}",888 "unable to codegen: {s}",
902 .{@errorName(err)},889 .{@errorName(err)},
903 ));890 ));
904 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));891 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
905 },892 },
906 };893 };
907 } else if (zcu.llvm_object) |llvm_object| {894 } else if (zcu.llvm_object) |llvm_object| {
...@@ -982,7 +969,7 @@ fn createFileRootStruct(...@@ -982,7 +969,7 @@ fn createFileRootStruct(
982 if (zcu.comp.incremental) {969 if (zcu.comp.incremental) {
983 try ip.addDependency(970 try ip.addDependency(
984 gpa,971 gpa,
985 InternPool.AnalUnit.wrap(.{ .cau = new_cau_index }),972 AnalUnit.wrap(.{ .cau = new_cau_index }),
986 .{ .src_hash = tracked_inst },973 .{ .src_hash = tracked_inst },
987 );974 );
988 }975 }
...@@ -998,35 +985,6 @@ fn createFileRootStruct(...@@ -998,35 +985,6 @@ fn createFileRootStruct(
998 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);985 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
999}986}
1000987
1001/// Recreate the root type of a file after it becomes outdated. A new struct type
1002/// is constructed at a new InternPool index, reusing the namespace for efficiency.
1003fn recreateFileRoot(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1004 const zcu = pt.zcu;
1005 const ip = &zcu.intern_pool;
1006 const file = zcu.fileByIndex(file_index);
1007 const file_root_type = zcu.fileRootType(file_index);
1008 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
1009
1010 assert(file_root_type != .none);
1011
1012 log.debug("recreateFileRoot mod={s} sub_file_path={s}", .{
1013 file.mod.fully_qualified_name,
1014 file.sub_file_path,
1015 });
1016
1017 if (file.status != .success_zir) {
1018 return error.AnalysisFail;
1019 }
1020
1021 // Invalidate the existing type, reusing its namespace.
1022 const file_root_type_cau = ip.loadStructType(file_root_type).cau.unwrap().?;
1023 ip.removeDependenciesForDepender(
1024 zcu.gpa,
1025 InternPool.AnalUnit.wrap(.{ .cau = file_root_type_cau }),
1026 );
1027 _ = try pt.createFileRootStruct(file_index, namespace_index, true);
1028}
1029
1030/// Re-scan the namespace of a file's root struct type on an incremental update.988/// Re-scan the namespace of a file's root struct type on an incremental update.
1031/// The file must have successfully populated ZIR.989/// The file must have successfully populated ZIR.
1032/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.990/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
...@@ -1060,6 +1018,7 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator....@@ -1060,6 +1018,7 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
1060 break :decls file.zir.bodySlice(extra_index, decls_len);1018 break :decls file.zir.bodySlice(extra_index, decls_len);
1061 };1019 };
1062 try pt.scanNamespace(namespace_index, decls);1020 try pt.scanNamespace(namespace_index, decls);
1021 zcu.namespacePtr(namespace_index).generation = zcu.generation;
1063}1022}
10641023
1065fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {1024fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
...@@ -1080,6 +1039,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -1080,6 +1039,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1080 .parent = .none,1039 .parent = .none,
1081 .owner_type = undefined, // set in `createFileRootStruct`1040 .owner_type = undefined, // set in `createFileRootStruct`
1082 .file_scope = file_index,1041 .file_scope = file_index,
1042 .generation = zcu.generation,
1083 });1043 });
1084 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);1044 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
1085 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);1045 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
...@@ -1131,7 +1091,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {...@@ -1131,7 +1091,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1131 const gpa = zcu.gpa;1091 const gpa = zcu.gpa;
1132 const ip = &zcu.intern_pool;1092 const ip = &zcu.intern_pool;
11331093
1134 const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index });1094 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
11351095
1136 const cau = ip.getCau(cau_index);1096 const cau = ip.getCau(cau_index);
1137 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;1097 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
...@@ -1151,10 +1111,12 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {...@@ -1151,10 +1111,12 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1151 // This declaration has no value so is definitely not a std.builtin type.1111 // This declaration has no value so is definitely not a std.builtin type.
1152 break :ip_index .none;1112 break :ip_index .none;
1153 },1113 },
1154 .type => {1114 .type => |ty| {
1155 // This is an incremental update, and this type is being re-analyzed because it is outdated.1115 // This is an incremental update, and this type is being re-analyzed because it is outdated.
1156 // The type must be recreated at a new `InternPool.Index`.1116 // Create a new type in its place, and mark the old one as outdated so that use sites will
1157 // Mark it outdated so that creation sites are re-analyzed.1117 // be re-analyzed and discover an up-to-date type.
1118 const new_ty = try pt.ensureTypeUpToDate(ty, true);
1119 assert(new_ty != ty);
1158 return .{1120 return .{
1159 .invalidate_decl_val = true,1121 .invalidate_decl_val = true,
1160 .invalidate_decl_ref = true,1122 .invalidate_decl_ref = true,
...@@ -2002,21 +1964,23 @@ const ScanDeclIter = struct {...@@ -2002,21 +1964,23 @@ const ScanDeclIter = struct {
20021964
2003 try namespace.other_decls.append(gpa, cau);1965 try namespace.other_decls.append(gpa, cau);
20041966
2005 // For a `comptime` declaration, whether to re-analyze is based solely on whether the1967 if (existing_cau == null) {
2006 // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already.1968 // For a `comptime` declaration, whether to analyze is based solely on whether the
2007 const unit = InternPool.AnalUnit.wrap(.{ .cau = cau });1969 // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already.
2008 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {1970 const unit = AnalUnit.wrap(.{ .cau = cau });
2009 try zcu.outdated.ensureUnusedCapacity(gpa, 1);1971 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
2010 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);1972 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2011 zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value);1973 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2012 if (kv.value == 0) { // no PO deps1974 zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value);
1975 if (kv.value == 0) { // no PO deps
1976 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
1977 }
1978 } else if (!zcu.outdated.contains(unit)) {
1979 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
1980 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
1981 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2013 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});1982 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2014 }1983 }
2015 } else if (!zcu.outdated.contains(unit)) {
2016 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2017 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2018 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2019 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2020 }1984 }
20211985
2022 break :cau .{ cau, true };1986 break :cau .{ cau, true };
...@@ -2027,9 +1991,6 @@ const ScanDeclIter = struct {...@@ -2027,9 +1991,6 @@ const ScanDeclIter = struct {
2027 const cau, const nav = if (existing_cau) |cau_index| cau_nav: {1991 const cau, const nav = if (existing_cau) |cau_index| cau_nav: {
2028 const nav_index = ip.getCau(cau_index).owner.unwrap().nav;1992 const nav_index = ip.getCau(cau_index).owner.unwrap().nav;
2029 const nav = ip.getNav(nav_index);1993 const nav = ip.getNav(nav_index);
2030 if (nav.name != name) {
2031 std.debug.panic("'{}' vs '{}'", .{ nav.name.fmt(ip), name.fmt(ip) });
2032 }
2033 assert(nav.name == name);1994 assert(nav.name == name);
2034 assert(nav.fqn == fqn);1995 assert(nav.fqn == fqn);
2035 break :cau_nav .{ cau_index, nav_index };1996 break :cau_nav .{ cau_index, nav_index };
...@@ -2078,7 +2039,7 @@ const ScanDeclIter = struct {...@@ -2078,7 +2039,7 @@ const ScanDeclIter = struct {
2078 },2039 },
2079 };2040 };
20802041
2081 if (want_analysis or declaration.flags.is_export) {2042 if (existing_cau == null and (want_analysis or declaration.flags.is_export)) {
2082 log.debug(2043 log.debug(
2083 "scanDecl queue analyze_cau file='{s}' cau_index={d}",2044 "scanDecl queue analyze_cau file='{s}' cau_index={d}",
2084 .{ namespace.fileScope(zcu).sub_file_path, cau },2045 .{ namespace.fileScope(zcu).sub_file_path, cau },
...@@ -2098,7 +2059,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!...@@ -2098,7 +2059,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
2098 const gpa = zcu.gpa;2059 const gpa = zcu.gpa;
2099 const ip = &zcu.intern_pool;2060 const ip = &zcu.intern_pool;
21002061
2101 const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index });2062 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
2102 const func = zcu.funcInfo(func_index);2063 const func = zcu.funcInfo(func_index);
2103 const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;2064 const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
2104 const file = zcu.fileByIndex(inst_info.file);2065 const file = zcu.fileByIndex(inst_info.file);
...@@ -2484,7 +2445,7 @@ fn processExportsInner(...@@ -2484,7 +2445,7 @@ fn processExportsInner(
2484 const nav = ip.getNav(nav_index);2445 const nav = ip.getNav(nav_index);
2485 if (zcu.failed_codegen.contains(nav_index)) break :failed true;2446 if (zcu.failed_codegen.contains(nav_index)) break :failed true;
2486 if (nav.analysis_owner.unwrap()) |cau| {2447 if (nav.analysis_owner.unwrap()) |cau| {
2487 const cau_unit = InternPool.AnalUnit.wrap(.{ .cau = cau });2448 const cau_unit = AnalUnit.wrap(.{ .cau = cau });
2488 if (zcu.failed_analysis.contains(cau_unit)) break :failed true;2449 if (zcu.failed_analysis.contains(cau_unit)) break :failed true;
2489 if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true;2450 if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true;
2490 }2451 }
...@@ -2494,7 +2455,7 @@ fn processExportsInner(...@@ -2494,7 +2455,7 @@ fn processExportsInner(
2494 };2455 };
2495 // If the value is a function, we also need to check if that function succeeded analysis.2456 // If the value is a function, we also need to check if that function succeeded analysis.
2496 if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) {2457 if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) {
2497 const func_unit = InternPool.AnalUnit.wrap(.{ .func = val.toIntern() });2458 const func_unit = AnalUnit.wrap(.{ .func = val.toIntern() });
2498 if (zcu.failed_analysis.contains(func_unit)) break :failed true;2459 if (zcu.failed_analysis.contains(func_unit)) break :failed true;
2499 if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true;2460 if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true;
2500 }2461 }
...@@ -2669,7 +2630,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void...@@ -2669,7 +2630,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void
2669 .{@errorName(err)},2630 .{@errorName(err)},
2670 ));2631 ));
2671 if (nav.analysis_owner.unwrap()) |cau| {2632 if (nav.analysis_owner.unwrap()) |cau| {
2672 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .cau = cau }));2633 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .cau = cau }));
2673 } else {2634 } else {
2674 // TODO: we don't have a way to indicate that this failure is retryable!2635 // TODO: we don't have a way to indicate that this failure is retryable!
2675 // Since these are really rare, we could as a cop-out retry the whole build next update.2636 // Since these are really rare, we could as a cop-out retry the whole build next update.
...@@ -2782,7 +2743,7 @@ pub fn reportRetryableFileError(...@@ -2782,7 +2743,7 @@ pub fn reportRetryableFileError(
2782 gop.value_ptr.* = err_msg;2743 gop.value_ptr.* = err_msg;
2783}2744}
27842745
2785/// Shortcut for calling `intern_pool.get`.2746///Shortcut for calling `intern_pool.get`.
2786pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index {2747pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index {
2787 return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key);2748 return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key);
2788}2749}
...@@ -3367,6 +3328,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo...@@ -3367,6 +3328,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo
3367 return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt);3328 return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt);
3368}3329}
33693330
3331/// Given a container type requiring resolution, ensures that it is up-to-date.
3332/// If not, the type is recreated at a new `InternPool.Index`.
3333/// The new index is returned. This is the same as the old index if the fields were up-to-date.
3334/// If `already_updating` is set, assumes the type is already outdated and undergoing re-analysis rather than checking `zcu.outdated`.
3335pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index {
3336 const zcu = pt.zcu;
3337 const ip = &zcu.intern_pool;
3338 switch (ip.indexToKey(ty)) {
3339 .struct_type => |key| {
3340 const struct_obj = ip.loadStructType(ty);
3341 const outdated = already_updating or o: {
3342 const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? });
3343 const o = zcu.outdated.swapRemove(anal_unit) or
3344 zcu.potentially_outdated.swapRemove(anal_unit);
3345 if (o) {
3346 _ = zcu.outdated_ready.swapRemove(anal_unit);
3347 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3348 }
3349 break :o o;
3350 };
3351 if (!outdated) return ty;
3352 return pt.recreateStructType(ty, key, struct_obj);
3353 },
3354 .union_type => |key| {
3355 const union_obj = ip.loadUnionType(ty);
3356 const outdated = already_updating or o: {
3357 const anal_unit = AnalUnit.wrap(.{ .cau = union_obj.cau });
3358 const o = zcu.outdated.swapRemove(anal_unit) or
3359 zcu.potentially_outdated.swapRemove(anal_unit);
3360 if (o) {
3361 _ = zcu.outdated_ready.swapRemove(anal_unit);
3362 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3363 }
3364 break :o o;
3365 };
3366 if (!outdated) return ty;
3367 return pt.recreateUnionType(ty, key, union_obj);
3368 },
3369 .enum_type => |key| {
3370 const enum_obj = ip.loadEnumType(ty);
3371 const outdated = already_updating or o: {
3372 const anal_unit = AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? });
3373 const o = zcu.outdated.swapRemove(anal_unit) or
3374 zcu.potentially_outdated.swapRemove(anal_unit);
3375 if (o) {
3376 _ = zcu.outdated_ready.swapRemove(anal_unit);
3377 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3378 }
3379 break :o o;
3380 };
3381 if (!outdated) return ty;
3382 return pt.recreateEnumType(ty, key, enum_obj);
3383 },
3384 .opaque_type => {
3385 assert(!already_updating);
3386 return ty;
3387 },
3388 else => unreachable,
3389 }
3390}
3391
3392fn recreateStructType(
3393 pt: Zcu.PerThread,
3394 ty: InternPool.Index,
3395 full_key: InternPool.Key.NamespaceType,
3396 struct_obj: InternPool.LoadedStructType,
3397) Zcu.SemaError!InternPool.Index {
3398 const zcu = pt.zcu;
3399 const gpa = zcu.gpa;
3400 const ip = &zcu.intern_pool;
3401
3402 const key = switch (full_key) {
3403 .reified => unreachable, // never outdated
3404 .empty_struct => unreachable, // never outdated
3405 .generated_tag => unreachable, // not a struct
3406 .declared => |d| d,
3407 };
3408
3409 if (@intFromEnum(ty) <= InternPool.static_len) {
3410 @panic("TODO: recreate resolved builtin type");
3411 }
3412
3413 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
3414 const file = zcu.fileByIndex(inst_info.file);
3415 if (file.status != .success_zir) return error.AnalysisFail;
3416 const zir = file.zir;
3417
3418 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3419 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
3420 assert(extended.opcode == .struct_decl);
3421 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3422 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
3423 var extra_index = extra.end;
3424
3425 const captures_len = if (small.has_captures_len) blk: {
3426 const captures_len = zir.extra[extra_index];
3427 extra_index += 1;
3428 break :blk captures_len;
3429 } else 0;
3430 const fields_len = if (small.has_fields_len) blk: {
3431 const fields_len = zir.extra[extra_index];
3432 extra_index += 1;
3433 break :blk fields_len;
3434 } else 0;
3435
3436 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
3437 if (fields_len != struct_obj.field_types.len) return error.AnalysisFail;
3438
3439 // The old type will be unused, so drop its dependency information.
3440 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? }));
3441
3442 const namespace_index = struct_obj.namespace.unwrap().?;
3443
3444 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
3445 .layout = small.layout,
3446 .fields_len = fields_len,
3447 .known_non_opv = small.known_non_opv,
3448 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
3449 .is_tuple = small.is_tuple,
3450 .any_comptime_fields = small.any_comptime_fields,
3451 .any_default_inits = small.any_default_inits,
3452 .inits_resolved = false,
3453 .any_aligned_fields = small.any_aligned_fields,
3454 .key = .{ .declared_owned_captures = .{
3455 .zir_index = key.zir_index,
3456 .captures = key.captures.owned,
3457 } },
3458 }, true)) {
3459 .wip => |wip| wip,
3460 .existing => unreachable, // we passed `replace_existing`
3461 };
3462 errdefer wip_ty.cancel(ip, pt.tid);
3463
3464 wip_ty.setName(ip, struct_obj.name);
3465 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
3466 try ip.addDependency(
3467 gpa,
3468 AnalUnit.wrap(.{ .cau = new_cau_index }),
3469 .{ .src_hash = key.zir_index },
3470 );
3471 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
3472 // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
3473 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3474
3475 const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
3476 if (inst_info.inst == .main_struct_inst) {
3477 // This is the root type of a file! Update the reference.
3478 zcu.setFileRootType(inst_info.file, new_ty);
3479 }
3480 return new_ty;
3481}
3482
3483fn recreateUnionType(
3484 pt: Zcu.PerThread,
3485 ty: InternPool.Index,
3486 full_key: InternPool.Key.NamespaceType,
3487 union_obj: InternPool.LoadedUnionType,
3488) Zcu.SemaError!InternPool.Index {
3489 const zcu = pt.zcu;
3490 const gpa = zcu.gpa;
3491 const ip = &zcu.intern_pool;
3492
3493 const key = switch (full_key) {
3494 .reified => unreachable, // never outdated
3495 .empty_struct => unreachable, // never outdated
3496 .generated_tag => unreachable, // not a union
3497 .declared => |d| d,
3498 };
3499
3500 if (@intFromEnum(ty) <= InternPool.static_len) {
3501 @panic("TODO: recreate resolved builtin type");
3502 }
3503
3504 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
3505 const file = zcu.fileByIndex(inst_info.file);
3506 if (file.status != .success_zir) return error.AnalysisFail;
3507 const zir = file.zir;
3508
3509 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3510 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
3511 assert(extended.opcode == .union_decl);
3512 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3513 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
3514 var extra_index = extra.end;
3515
3516 extra_index += @intFromBool(small.has_tag_type);
3517 const captures_len = if (small.has_captures_len) blk: {
3518 const captures_len = zir.extra[extra_index];
3519 extra_index += 1;
3520 break :blk captures_len;
3521 } else 0;
3522 extra_index += @intFromBool(small.has_body_len);
3523 const fields_len = if (small.has_fields_len) blk: {
3524 const fields_len = zir.extra[extra_index];
3525 extra_index += 1;
3526 break :blk fields_len;
3527 } else 0;
3528
3529 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
3530 if (fields_len != union_obj.field_types.len) return error.AnalysisFail;
3531
3532 // The old type will be unused, so drop its dependency information.
3533 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = union_obj.cau }));
3534
3535 const namespace_index = union_obj.namespace;
3536
3537 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{
3538 .flags = .{
3539 .layout = small.layout,
3540 .status = .none,
3541 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3542 .tagged
3543 else if (small.layout != .auto)
3544 .none
3545 else switch (true) { // TODO
3546 true => .safety,
3547 false => .none,
3548 },
3549 .any_aligned_fields = small.any_aligned_fields,
3550 .requires_comptime = .unknown,
3551 .assumed_runtime_bits = false,
3552 .assumed_pointer_aligned = false,
3553 .alignment = .none,
3554 },
3555 .fields_len = fields_len,
3556 .enum_tag_ty = .none, // set later
3557 .field_types = &.{}, // set later
3558 .field_aligns = &.{}, // set later
3559 .key = .{ .declared_owned_captures = .{
3560 .zir_index = key.zir_index,
3561 .captures = key.captures.owned,
3562 } },
3563 }, true)) {
3564 .wip => |wip| wip,
3565 .existing => unreachable, // we passed `replace_existing`
3566 };
3567 errdefer wip_ty.cancel(ip, pt.tid);
3568
3569 wip_ty.setName(ip, union_obj.name);
3570 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
3571 try ip.addDependency(
3572 gpa,
3573 AnalUnit.wrap(.{ .cau = new_cau_index }),
3574 .{ .src_hash = key.zir_index },
3575 );
3576 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
3577 // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive.
3578 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3579 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
3580}
3581
3582fn recreateEnumType(
3583 pt: Zcu.PerThread,
3584 ty: InternPool.Index,
3585 full_key: InternPool.Key.NamespaceType,
3586 enum_obj: InternPool.LoadedEnumType,
3587) Zcu.SemaError!InternPool.Index {
3588 const zcu = pt.zcu;
3589 const gpa = zcu.gpa;
3590 const ip = &zcu.intern_pool;
3591
3592 const key = switch (full_key) {
3593 .reified => unreachable, // never outdated
3594 .empty_struct => unreachable, // never outdated
3595 .generated_tag => unreachable, // never outdated
3596 .declared => |d| d,
3597 };
3598
3599 if (@intFromEnum(ty) <= InternPool.static_len) {
3600 @panic("TODO: recreate resolved builtin type");
3601 }
3602
3603 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
3604 const file = zcu.fileByIndex(inst_info.file);
3605 if (file.status != .success_zir) return error.AnalysisFail;
3606 const zir = file.zir;
3607
3608 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3609 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
3610 assert(extended.opcode == .enum_decl);
3611 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
3612 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
3613 var extra_index = extra.end;
3614
3615 const tag_type_ref = if (small.has_tag_type) blk: {
3616 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
3617 extra_index += 1;
3618 break :blk tag_type_ref;
3619 } else .none;
3620
3621 const captures_len = if (small.has_captures_len) blk: {
3622 const captures_len = zir.extra[extra_index];
3623 extra_index += 1;
3624 break :blk captures_len;
3625 } else 0;
3626
3627 const body_len = if (small.has_body_len) blk: {
3628 const body_len = zir.extra[extra_index];
3629 extra_index += 1;
3630 break :blk body_len;
3631 } else 0;
3632
3633 const fields_len = if (small.has_fields_len) blk: {
3634 const fields_len = zir.extra[extra_index];
3635 extra_index += 1;
3636 break :blk fields_len;
3637 } else 0;
3638
3639 const decls_len = if (small.has_decls_len) blk: {
3640 const decls_len = zir.extra[extra_index];
3641 extra_index += 1;
3642 break :blk decls_len;
3643 } else 0;
3644
3645 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
3646 if (fields_len != enum_obj.names.len) return error.AnalysisFail;
3647
3648 extra_index += captures_len;
3649 extra_index += decls_len;
3650
3651 const body = zir.bodySlice(extra_index, body_len);
3652 extra_index += body.len;
3653
3654 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
3655 const body_end = extra_index;
3656 extra_index += bit_bags_count;
3657
3658 const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| {
3659 if (bag != 0) break true;
3660 } else false;
3661
3662 // The old type will be unused, so drop its dependency information.
3663 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? }));
3664
3665 const namespace_index = enum_obj.namespace;
3666
3667 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
3668 .has_values = any_values,
3669 .tag_mode = if (small.nonexhaustive)
3670 .nonexhaustive
3671 else if (tag_type_ref == .none)
3672 .auto
3673 else
3674 .explicit,
3675 .fields_len = fields_len,
3676 .key = .{ .declared_owned_captures = .{
3677 .zir_index = key.zir_index,
3678 .captures = key.captures.owned,
3679 } },
3680 }, true)) {
3681 .wip => |wip| wip,
3682 .existing => unreachable, // we passed `replace_existing`
3683 };
3684 var done = true;
3685 errdefer if (!done) wip_ty.cancel(ip, pt.tid);
3686
3687 wip_ty.setName(ip, enum_obj.name);
3688
3689 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
3690
3691 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
3692 // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive.
3693
3694 wip_ty.prepare(ip, new_cau_index, namespace_index);
3695 done = true;
3696
3697 Sema.resolveDeclaredEnum(
3698 pt,
3699 wip_ty,
3700 inst_info.inst,
3701 key.zir_index,
3702 namespace_index,
3703 enum_obj.name,
3704 new_cau_index,
3705 small,
3706 body,
3707 tag_type_ref,
3708 any_values,
3709 fields_len,
3710 zir,
3711 body_end,
3712 ) catch |err| switch (err) {
3713 error.GenericPoison => unreachable,
3714 error.ComptimeBreak => unreachable,
3715 error.ComptimeReturn => unreachable,
3716 error.AnalysisFail, error.OutOfMemory => |e| return e,
3717 };
3718
3719 return wip_ty.index;
3720}
3721
3722/// Given a namespace, re-scan its declarations from the type definition if they have not
3723/// yet been re-scanned on this update.
3724/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.
3725/// This will effectively short-circuit the caller, which will be semantic analysis of a
3726/// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error.
3727pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void {
3728 const zcu = pt.zcu;
3729 const ip = &zcu.intern_pool;
3730 const namespace = zcu.namespacePtr(namespace_index);
3731
3732 if (namespace.generation == zcu.generation) return;
3733
3734 const Container = enum { @"struct", @"union", @"enum", @"opaque" };
3735 const container: Container, const full_key = switch (ip.indexToKey(namespace.owner_type)) {
3736 .struct_type => |k| .{ .@"struct", k },
3737 .union_type => |k| .{ .@"union", k },
3738 .enum_type => |k| .{ .@"enum", k },
3739 .opaque_type => |k| .{ .@"opaque", k },
3740 else => unreachable, // namespaces are owned by a container type
3741 };
3742
3743 const key = switch (full_key) {
3744 .reified, .empty_struct, .generated_tag => {
3745 // Namespace always empty, so up-to-date.
3746 namespace.generation = zcu.generation;
3747 return;
3748 },
3749 .declared => |d| d,
3750 };
3751
3752 // Namespace outdated -- re-scan the type if necessary.
3753
3754 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
3755 const file = zcu.fileByIndex(inst_info.file);
3756 if (file.status != .success_zir) return error.AnalysisFail;
3757 const zir = file.zir;
3758
3759 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3760 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
3761
3762 const decls = switch (container) {
3763 .@"struct" => decls: {
3764 assert(extended.opcode == .struct_decl);
3765 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3766 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
3767 var extra_index = extra.end;
3768 const captures_len = if (small.has_captures_len) blk: {
3769 const captures_len = zir.extra[extra_index];
3770 extra_index += 1;
3771 break :blk captures_len;
3772 } else 0;
3773 extra_index += @intFromBool(small.has_fields_len);
3774 const decls_len = if (small.has_decls_len) blk: {
3775 const decls_len = zir.extra[extra_index];
3776 extra_index += 1;
3777 break :blk decls_len;
3778 } else 0;
3779 extra_index += captures_len;
3780 if (small.has_backing_int) {
3781 const backing_int_body_len = zir.extra[extra_index];
3782 extra_index += 1; // backing_int_body_len
3783 if (backing_int_body_len == 0) {
3784 extra_index += 1; // backing_int_ref
3785 } else {
3786 extra_index += backing_int_body_len; // backing_int_body_inst
3787 }
3788 }
3789 break :decls zir.bodySlice(extra_index, decls_len);
3790 },
3791 .@"union" => decls: {
3792 assert(extended.opcode == .union_decl);
3793 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3794 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
3795 var extra_index = extra.end;
3796 extra_index += @intFromBool(small.has_tag_type);
3797 const captures_len = if (small.has_captures_len) blk: {
3798 const captures_len = zir.extra[extra_index];
3799 extra_index += 1;
3800 break :blk captures_len;
3801 } else 0;
3802 extra_index += @intFromBool(small.has_body_len);
3803 extra_index += @intFromBool(small.has_fields_len);
3804 const decls_len = if (small.has_decls_len) blk: {
3805 const decls_len = zir.extra[extra_index];
3806 extra_index += 1;
3807 break :blk decls_len;
3808 } else 0;
3809 extra_index += captures_len;
3810 break :decls zir.bodySlice(extra_index, decls_len);
3811 },
3812 .@"enum" => decls: {
3813 assert(extended.opcode == .enum_decl);
3814 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
3815 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
3816 var extra_index = extra.end;
3817 extra_index += @intFromBool(small.has_tag_type);
3818 const captures_len = if (small.has_captures_len) blk: {
3819 const captures_len = zir.extra[extra_index];
3820 extra_index += 1;
3821 break :blk captures_len;
3822 } else 0;
3823 extra_index += @intFromBool(small.has_body_len);
3824 extra_index += @intFromBool(small.has_fields_len);
3825 const decls_len = if (small.has_decls_len) blk: {
3826 const decls_len = zir.extra[extra_index];
3827 extra_index += 1;
3828 break :blk decls_len;
3829 } else 0;
3830 extra_index += captures_len;
3831 break :decls zir.bodySlice(extra_index, decls_len);
3832 },
3833 .@"opaque" => decls: {
3834 assert(extended.opcode == .opaque_decl);
3835 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
3836 const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
3837 var extra_index = extra.end;
3838 const captures_len = if (small.has_captures_len) blk: {
3839 const captures_len = zir.extra[extra_index];
3840 extra_index += 1;
3841 break :blk captures_len;
3842 } else 0;
3843 const decls_len = if (small.has_decls_len) blk: {
3844 const decls_len = zir.extra[extra_index];
3845 extra_index += 1;
3846 break :blk decls_len;
3847 } else 0;
3848 extra_index += captures_len;
3849 break :decls zir.bodySlice(extra_index, decls_len);
3850 },
3851 };
3852
3853 try pt.scanNamespace(namespace_index, decls);
3854 namespace.generation = zcu.generation;
3855}
3856
3370const Air = @import("../Air.zig");3857const Air = @import("../Air.zig");
3371const Allocator = std.mem.Allocator;3858const Allocator = std.mem.Allocator;
3372const assert = std.debug.assert;3859const assert = std.debug.assert;
...@@ -3379,6 +3866,7 @@ const builtin = @import("builtin");...@@ -3379,6 +3866,7 @@ const builtin = @import("builtin");
3379const Cache = std.Build.Cache;3866const Cache = std.Build.Cache;
3380const dev = @import("../dev.zig");3867const dev = @import("../dev.zig");
3381const InternPool = @import("../InternPool.zig");3868const InternPool = @import("../InternPool.zig");
3869const AnalUnit = InternPool.AnalUnit;
3382const isUpDir = @import("../introspect.zig").isUpDir;3870const isUpDir = @import("../introspect.zig").isUpDir;
3383const Liveness = @import("../Liveness.zig");3871const Liveness = @import("../Liveness.zig");
3384const log = std.log.scoped(.zcu);3872const log = std.log.scoped(.zcu);