authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-09 11:53:06+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-14 07:40:07+00:00
log1421d329a3bbe4891eda8f234139be787fefcd2f
tree3439ccd40fe2b59801410d792ab9ad3f62f397bc
parent7ba8641d19b719c11c0f6177fb28fa098a769e1f
signaturelock-open Commit is signed but in an unrecognized format.

compiler: progress towards incremental

Most basic re-analysis logic is now in place. Trivial updates are hitting linker assertions.

3 files changed, 175 insertions(+), 56 deletions(-)

src/InternPool.zig+2-2
...@@ -7103,7 +7103,7 @@ pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTa...@@ -7103,7 +7103,7 @@ pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTa
7103 return @enumFromInt(gop.index);7103 return @enumFromInt(gop.index);
7104}7104}
71057105
7106pub const OpaqueTypeIni = struct {7106pub const OpaqueTypeInit = struct {
7107 has_namespace: bool,7107 has_namespace: bool,
7108 key: union(enum) {7108 key: union(enum) {
7109 declared: struct {7109 declared: struct {
...@@ -7117,7 +7117,7 @@ pub const OpaqueTypeIni = struct {...@@ -7117,7 +7117,7 @@ pub const OpaqueTypeIni = struct {
7117 },7117 },
7118};7118};
71197119
7120pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!WipNamespaceType.Result {7120pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeInit) Allocator.Error!WipNamespaceType.Result {
7121 const adapter: KeyAdapter = .{ .intern_pool = ip };7121 const adapter: KeyAdapter = .{ .intern_pool = ip };
7122 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {7122 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
7123 .declared => |d| .{ .declared = .{7123 .declared => |d| .{ .declared = .{
src/Module.zig+101-21
...@@ -762,14 +762,14 @@ pub const Namespace = struct {...@@ -762,14 +762,14 @@ pub const Namespace = struct {
762 zcu: *Zcu,762 zcu: *Zcu,
763763
764 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {764 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
765 const decl = ctx.module.declPtr(decl_index);765 const decl = ctx.zcu.declPtr(decl_index);
766 return std.hash.uint32(@intFromEnum(decl.name));766 return std.hash.uint32(@intFromEnum(decl.name));
767 }767 }
768768
769 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {769 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
770 _ = b_index;770 _ = b_index;
771 const a_decl = ctx.module.declPtr(a_decl_index);771 const a_decl = ctx.zcu.declPtr(a_decl_index);
772 const b_decl = ctx.module.declPtr(b_decl_index);772 const b_decl = ctx.zcu.declPtr(b_decl_index);
773 return a_decl.name == b_decl.name;773 return a_decl.name == b_decl.name;
774 }774 }
775 };775 };
...@@ -2655,7 +2655,7 @@ pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -2655,7 +2655,7 @@ pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2655 if (opt_po_entry) |e| e.value else 0,2655 if (opt_po_entry) |e| e.value else 0,
2656 );2656 );
2657 log.debug("outdated: {}", .{depender});2657 log.debug("outdated: {}", .{depender});
2658 if (opt_po_entry != null) {2658 if (opt_po_entry == null) {
2659 // This is a new entry with no PO dependencies.2659 // This is a new entry with no PO dependencies.
2660 try zcu.outdated_ready.put(zcu.gpa, depender, {});2660 try zcu.outdated_ready.put(zcu.gpa, depender, {});
2661 }2661 }
...@@ -2989,10 +2989,10 @@ pub fn mapOldZirToNew(...@@ -2989,10 +2989,10 @@ pub fn mapOldZirToNew(
29892989
2990/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.2990/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.
2991pub fn ensureFileAnalyzed(zcu: *Zcu, file: *File) SemaError!void {2991pub fn ensureFileAnalyzed(zcu: *Zcu, file: *File) SemaError!void {
2992 if (file.root_decl == .none) {2992 if (file.root_decl.unwrap()) |existing_root| {
2993 return zcu.semaFile(file);2993 return zcu.ensureDeclAnalyzed(existing_root);
2994 } else {2994 } else {
2995 return zcu.ensureDeclAnalyzed(file.root_decl);2995 return zcu.semaFile(file);
2996 }2996 }
2997}2997}
29982998
...@@ -3006,6 +3006,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3006,6 +3006,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
30063006
3007 const decl = mod.declPtr(decl_index);3007 const decl = mod.declPtr(decl_index);
30083008
3009 log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{
3010 @intFromEnum(decl_index),
3011 decl.name.fmt(&mod.intern_pool),
3012 });
3013
3009 // Determine whether or not this Decl is outdated, i.e. requires re-analysis3014 // Determine whether or not this Decl is outdated, i.e. requires re-analysis
3010 // even if `complete`. If a Decl is PO, we pessismistically assume that it3015 // even if `complete`. If a Decl is PO, we pessismistically assume that it
3011 // *does* require re-analysis, to ensure that the Decl is definitely3016 // *does* require re-analysis, to ensure that the Decl is definitely
...@@ -3099,11 +3104,13 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3099,11 +3104,13 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3099 // TODO: we do not yet have separate dependencies for decl values vs types.3104 // TODO: we do not yet have separate dependencies for decl values vs types.
3100 if (decl_was_outdated) {3105 if (decl_was_outdated) {
3101 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {3106 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
3107 log.debug("Decl tv invalidated ('{d}')", .{@intFromEnum(decl_index)});
3102 // This dependency was marked as PO, meaning dependees were waiting3108 // This dependency was marked as PO, meaning dependees were waiting
3103 // on its analysis result, and it has turned out to be outdated.3109 // on its analysis result, and it has turned out to be outdated.
3104 // Update dependees accordingly.3110 // Update dependees accordingly.
3105 try mod.markDependeeOutdated(.{ .decl_val = decl_index });3111 try mod.markDependeeOutdated(.{ .decl_val = decl_index });
3106 } else {3112 } else {
3113 log.debug("Decl tv up-to-date ('{d}')", .{@intFromEnum(decl_index)});
3107 // This dependency was previously PO, but turned out to be up-to-date.3114 // This dependency was previously PO, but turned out to be up-to-date.
3108 // We do not need to queue successive analysis.3115 // We do not need to queue successive analysis.
3109 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });3116 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });
...@@ -3115,11 +3122,31 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3115,11 +3122,31 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3115 const tracy = trace(@src());3122 const tracy = trace(@src());
3116 defer tracy.end();3123 defer tracy.end();
31173124
3125 const gpa = zcu.gpa;
3118 const ip = &zcu.intern_pool;3126 const ip = &zcu.intern_pool;
3119 const func = zcu.funcInfo(func_index);3127 const func = zcu.funcInfo(func_index);
3120 const decl_index = func.owner_decl;3128 const decl_index = func.owner_decl;
3121 const decl = zcu.declPtr(decl_index);3129 const decl = zcu.declPtr(decl_index);
31223130
3131 log.debug("ensureFuncBodyAnalyzed '{d}' (instance of '{}')", .{
3132 @intFromEnum(func_index),
3133 decl.name.fmt(ip),
3134 });
3135
3136 // First, our owner decl must be up-to-date. This will always be the case
3137 // during the first update, but may not on successive updates if we happen
3138 // to get analyzed before our parent decl.
3139 try zcu.ensureDeclAnalyzed(decl_index);
3140
3141 // On an update, it's possible this function changed such that our owner
3142 // decl now refers to a different function, making this one orphaned. If
3143 // that's the case, we should remove this function from the binary.
3144 if (decl.val.ip_index != func_index) {
3145 ip.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
3146 ip.remove(func_index);
3147 @panic("TODO: remove orphaned function from binary");
3148 }
3149
3123 switch (decl.analysis) {3150 switch (decl.analysis) {
3124 .unreferenced => unreachable,3151 .unreferenced => unreachable,
3125 .in_progress => unreachable,3152 .in_progress => unreachable,
...@@ -3143,7 +3170,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3143,7 +3170,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3143 }3170 }
31443171
3145 switch (func.analysis(ip).state) {3172 switch (func.analysis(ip).state) {
3146 .success,3173 .success => if (!was_outdated) return,
3147 .sema_failure,3174 .sema_failure,
3148 .dependency_failure,3175 .dependency_failure,
3149 .codegen_failure,3176 .codegen_failure,
...@@ -3153,7 +3180,10 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3153,7 +3180,10 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3153 .inline_only => unreachable, // don't queue work for this3180 .inline_only => unreachable, // don't queue work for this
3154 }3181 }
31553182
3156 const gpa = zcu.gpa;3183 log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{
3184 @intFromEnum(func_index),
3185 if (was_outdated) "outdated" else "never analyzed",
3186 });
31573187
3158 var tmp_arena = std.heap.ArenaAllocator.init(gpa);3188 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
3159 defer tmp_arena.deinit();3189 defer tmp_arena.deinit();
...@@ -3311,7 +3341,9 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)...@@ -3311,7 +3341,9 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
3311/// https://github.com/ziglang/zig/issues/143073341/// https://github.com/ziglang/zig/issues/14307
3312pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {3342pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
3313 const file = (try mod.importPkg(pkg)).file;3343 const file = (try mod.importPkg(pkg)).file;
3314 return mod.semaFile(file);3344 if (file.root_decl == .none) {
3345 return mod.semaFile(file);
3346 }
3315}3347}
33163348
3317fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {3349fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {
...@@ -3383,9 +3415,13 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa...@@ -3383,9 +3415,13 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
3383/// reconstructed at a new InternPool index. Otherwise, the namespace is just3415/// reconstructed at a new InternPool index. Otherwise, the namespace is just
3384/// re-analyzed. Returns whether the decl's tyval was invalidated.3416/// re-analyzed. Returns whether the decl's tyval was invalidated.
3385fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {3417fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
3386 assert(file.root_decl != .none);3418 const decl = zcu.declPtr(file.root_decl.unwrap().?);
33873419
3388 const decl = zcu.declPtr(file.root_decl);3420 log.debug("semaFileUpdate mod={s} sub_file_path={s} type_outdated={}", .{
3421 file.mod.fully_qualified_name,
3422 file.sub_file_path,
3423 type_outdated,
3424 });
33893425
3390 if (file.status != .success_zir) {3426 if (file.status != .success_zir) {
3391 if (decl.analysis == .file_failure) {3427 if (decl.analysis == .file_failure) {
...@@ -3398,7 +3434,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {...@@ -3398,7 +3434,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
33983434
3399 if (decl.analysis == .file_failure) {3435 if (decl.analysis == .file_failure) {
3400 // No struct type currently exists. Create one!3436 // No struct type currently exists. Create one!
3401 _ = try zcu.getFileRootStruct(file.root_decl, decl.src_namespace, file);3437 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
3402 return true;3438 return true;
3403 }3439 }
34043440
...@@ -3407,9 +3443,10 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {...@@ -3407,9 +3443,10 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
34073443
3408 if (type_outdated) {3444 if (type_outdated) {
3409 // Invalidate the existing type, reusing the decl and namespace.3445 // Invalidate the existing type, reusing the decl and namespace.
3410 try zcu.intern_pool.remove(decl.val.toIntern());3446 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = file.root_decl.unwrap().? }));
3447 zcu.intern_pool.remove(decl.val.toIntern());
3411 decl.val = undefined;3448 decl.val = undefined;
3412 _ = try zcu.getFileRootStruct(file.root_decl, decl.src_namespace, file);3449 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
3413 return true;3450 return true;
3414 }3451 }
34153452
...@@ -3420,7 +3457,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {...@@ -3420,7 +3457,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
3420 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);3457 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
34213458
3422 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;3459 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3423 extra_index += @intFromEnum(small.has_fields_len);3460 extra_index += @intFromBool(small.has_fields_len);
3424 const decls_len = if (small.has_decls_len) blk: {3461 const decls_len = if (small.has_decls_len) blk: {
3425 const decls_len = file.zir.extra[extra_index];3462 const decls_len = file.zir.extra[extra_index];
3426 extra_index += 1;3463 extra_index += 1;
...@@ -3530,11 +3567,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3530,11 +3567,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
35303567
3531 assert(!mod.declIsRoot(decl_index));3568 assert(!mod.declIsRoot(decl_index));
35323569
3533 if (decl.owns_tv) {3570 if (decl.zir_decl_index == .none and decl.owns_tv) {
3534 // We are re-analyzing an owner Decl (for a function or a namespace type).3571 // We are re-analyzing an anonymous owner Decl (for a function or a namespace type).
3535 @panic("TODO: update owner Decl");3572 return mod.semaAnonOwnerDecl(decl_index);
3536 }3573 }
35373574
3575 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
3576
3538 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);3577 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
35393578
3540 const gpa = mod.gpa;3579 const gpa = mod.gpa;
...@@ -3827,6 +3866,42 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3827,6 +3866,42 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3827 return result;3866 return result;
3828}3867}
38293868
3869fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
3870 const decl = zcu.declPtr(decl_index);
3871
3872 assert(decl.has_tv);
3873 assert(decl.owns_tv);
3874
3875 log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)});
3876
3877 switch (decl.ty.zigTypeTag(zcu)) {
3878 .Fn => @panic("TODO: update fn instance"),
3879 .Type => {},
3880 else => unreachable,
3881 }
3882
3883 // We are the owner Decl of a type, and we were marked as outdated. That means the *structure*
3884 // of this type changed; not just its namespace. Therefore, we need a new InternPool index.
3885 //
3886 // However, as soon as we make that, the context that created us will require re-analysis anyway
3887 // (as it depends on this Decl's value), meaning the `struct_decl` (or equivalent) instruction
3888 // will be analyzed again. Since Sema already needs to be able to reconstruct types like this,
3889 // why should we bother implementing it here too when the Sema logic will be hit right after?
3890 //
3891 // So instead, let's just mark this Decl as failed - so that any remaining Decls which genuinely
3892 // reference it (via `@This`) end up silently erroring too - and we'll let Sema make a new type
3893 // with a new Decl.
3894 //
3895 // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
3896 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3897 zcu.intern_pool.remove(decl.val.toIntern());
3898 decl.analysis = .dependency_failure;
3899 return .{
3900 .invalidate_decl_val = true,
3901 .invalidate_decl_ref = true,
3902 };
3903}
3904
3830pub const ImportFileResult = struct {3905pub const ImportFileResult = struct {
3831 file: *File,3906 file: *File,
3832 is_new: bool,3907 is_new: bool,
...@@ -4152,7 +4227,7 @@ pub fn scanNamespace(...@@ -4152,7 +4227,7 @@ pub fn scanNamespace(
4152 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index) = .{};4227 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index) = .{};
4153 defer existing_by_inst.deinit(gpa);4228 defer existing_by_inst.deinit(gpa);
41544229
4155 try existing_by_inst.ensureTotalCapacity(namespace.decls.count());4230 try existing_by_inst.ensureTotalCapacity(gpa, @intCast(namespace.decls.count()));
41564231
4157 for (namespace.decls.keys()) |decl_index| {4232 for (namespace.decls.keys()) |decl_index| {
4158 const decl = zcu.declPtr(decl_index);4233 const decl = zcu.declPtr(decl_index);
...@@ -4357,7 +4432,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void...@@ -4357,7 +4432,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
4357 .anon => unreachable,4432 .anon => unreachable,
4358 .@"comptime" => true,4433 .@"comptime" => true,
4359 .@"usingnamespace" => a: {4434 .@"usingnamespace" => a: {
4360 namespace.usingnamespace_set.putNoClobber(decl_index, declaration.flags.is_pub);4435 namespace.usingnamespace_set.putAssumeCapacityNoClobber(decl_index, declaration.flags.is_pub);
4361 break :a true;4436 break :a true;
4362 },4437 },
4363 .named => false,4438 .named => false,
...@@ -4533,6 +4608,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4533,6 +4608,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4533 };4608 };
4534 defer sema.deinit();4609 defer sema.deinit();
45354610
4611 // Every runtime function has a dependency on the source of the Decl it originates from.
4612 // It also depends on the value of its owner Decl.
4613 try sema.declareDependency(.{ .src_hash = decl.zir_decl_index.unwrap().? });
4614 try sema.declareDependency(.{ .decl_val = decl_index });
4615
4536 if (func.analysis(ip).inferred_error_set) {4616 if (func.analysis(ip).inferred_error_set) {
4537 const ies = try arena.create(Sema.InferredErrorSet);4617 const ies = try arena.create(Sema.InferredErrorSet);
4538 ies.* = .{ .func = func_index };4618 ies.* = .{ .func = func_index };
src/Sema.zig+72-33
...@@ -2705,6 +2705,37 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32...@@ -2705,6 +2705,37 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32
2705 return captures;2705 return captures;
2706}2706}
27072707
2708/// Given an `InternPool.WipNamespaceType` or `InternPool.WipEnumType`, apply
2709/// `sema.builtin_type_target_index` to it if necessary.
2710fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) {
2711 if (sema.builtin_type_target_index == .none) return wip_ty;
2712 var new = wip_ty;
2713 new.index = sema.builtin_type_target_index;
2714 sema.mod.intern_pool.resolveBuiltinType(new.index, wip_ty.index);
2715 return new;
2716}
2717
2718/// Given a type just looked up in the `InternPool`, check whether it is
2719/// considered outdated on this update. If so, remove it from the pool
2720/// and return `true`.
2721fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
2722 const zcu = sema.mod;
2723
2724 if (!zcu.comp.debug_incremental) return false;
2725
2726 const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
2727 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
2728 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
2729 zcu.potentially_outdated.swapRemove(decl_as_depender);
2730 if (!was_outdated) return false;
2731 _ = zcu.outdated_ready.swapRemove(decl_as_depender);
2732 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
2733 zcu.intern_pool.remove(ty);
2734 zcu.declPtr(decl_index).analysis = .dependency_failure;
2735 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
2736 return true;
2737}
2738
2708fn zirStructDecl(2739fn zirStructDecl(
2709 sema: *Sema,2740 sema: *Sema,
2710 block: *Block,2741 block: *Block,
...@@ -2748,7 +2779,7 @@ fn zirStructDecl(...@@ -2748,7 +2779,7 @@ fn zirStructDecl(
2748 }2779 }
2749 }2780 }
27502781
2751 const wip_ty = switch (try ip.getStructType(gpa, .{2782 const struct_init: InternPool.StructTypeInit = .{
2752 .layout = small.layout,2783 .layout = small.layout,
2753 .fields_len = fields_len,2784 .fields_len = fields_len,
2754 .known_non_opv = small.known_non_opv,2785 .known_non_opv = small.known_non_opv,
...@@ -2763,16 +2794,14 @@ fn zirStructDecl(...@@ -2763,16 +2794,14 @@ fn zirStructDecl(
2763 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),2794 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
2764 .captures = captures,2795 .captures = captures,
2765 } },2796 } },
2766 })) {
2767 .existing => |ty| return Air.internedToRef(ty),
2768 .wip => |wip| wip: {
2769 if (sema.builtin_type_target_index == .none) break :wip wip;
2770 var new = wip;
2771 new.index = sema.builtin_type_target_index;
2772 ip.resolveBuiltinType(new.index, wip.index);
2773 break :wip new;
2774 },
2775 };2797 };
2798 const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, struct_init)) {
2799 .existing => |ty| wip: {
2800 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
2801 break :wip (try ip.getStructType(gpa, struct_init)).wip;
2802 },
2803 .wip => |wip| wip,
2804 });
2776 errdefer wip_ty.cancel(ip);2805 errdefer wip_ty.cancel(ip);
27772806
2778 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{2807 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
...@@ -2969,7 +2998,7 @@ fn zirEnumDecl(...@@ -2969,7 +2998,7 @@ fn zirEnumDecl(
2969 if (bag != 0) break true;2998 if (bag != 0) break true;
2970 } else false;2999 } else false;
29713000
2972 const wip_ty = switch (try ip.getEnumType(gpa, .{3001 const enum_init: InternPool.EnumTypeInit = .{
2973 .has_namespace = true or decls_len > 0, // TODO: see below3002 .has_namespace = true or decls_len > 0, // TODO: see below
2974 .has_values = any_values,3003 .has_values = any_values,
2975 .tag_mode = if (small.nonexhaustive)3004 .tag_mode = if (small.nonexhaustive)
...@@ -2983,16 +3012,14 @@ fn zirEnumDecl(...@@ -2983,16 +3012,14 @@ fn zirEnumDecl(
2983 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),3012 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
2984 .captures = captures,3013 .captures = captures,
2985 } },3014 } },
2986 })) {
2987 .wip => |wip| wip: {
2988 if (sema.builtin_type_target_index == .none) break :wip wip;
2989 var new = wip;
2990 new.index = sema.builtin_type_target_index;
2991 ip.resolveBuiltinType(new.index, wip.index);
2992 break :wip new;
2993 },
2994 .existing => |ty| return Air.internedToRef(ty),
2995 };3015 };
3016 const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, enum_init)) {
3017 .existing => |ty| wip: {
3018 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3019 break :wip (try ip.getEnumType(gpa, enum_init)).wip;
3020 },
3021 .wip => |wip| wip,
3022 });
29963023
2997 // Once this is `true`, we will not delete the decl or type even upon failure, since we3024 // Once this is `true`, we will not delete the decl or type even upon failure, since we
2998 // have finished constructing the type and are in the process of analyzing it.3025 // have finished constructing the type and are in the process of analyzing it.
...@@ -3230,7 +3257,7 @@ fn zirUnionDecl(...@@ -3230,7 +3257,7 @@ fn zirUnionDecl(
3230 const captures = try sema.getCaptures(block, extra_index, captures_len);3257 const captures = try sema.getCaptures(block, extra_index, captures_len);
3231 extra_index += captures_len;3258 extra_index += captures_len;
32323259
3233 const wip_ty = switch (try ip.getUnionType(gpa, .{3260 const union_init: InternPool.UnionTypeInit = .{
3234 .flags = .{3261 .flags = .{
3235 .layout = small.layout,3262 .layout = small.layout,
3236 .status = .none,3263 .status = .none,
...@@ -3257,16 +3284,14 @@ fn zirUnionDecl(...@@ -3257,16 +3284,14 @@ fn zirUnionDecl(
3257 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),3284 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3258 .captures = captures,3285 .captures = captures,
3259 } },3286 } },
3260 })) {
3261 .wip => |wip| wip: {
3262 if (sema.builtin_type_target_index == .none) break :wip wip;
3263 var new = wip;
3264 new.index = sema.builtin_type_target_index;
3265 ip.resolveBuiltinType(new.index, wip.index);
3266 break :wip new;
3267 },
3268 .existing => |ty| return Air.internedToRef(ty),
3269 };3287 };
3288 const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, union_init)) {
3289 .existing => |ty| wip: {
3290 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3291 break :wip (try ip.getUnionType(gpa, union_init)).wip;
3292 },
3293 .wip => |wip| wip,
3294 });
3270 errdefer wip_ty.cancel(ip);3295 errdefer wip_ty.cancel(ip);
32713296
3272 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3297 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
...@@ -3336,15 +3361,20 @@ fn zirOpaqueDecl(...@@ -3336,15 +3361,20 @@ fn zirOpaqueDecl(
3336 const captures = try sema.getCaptures(block, extra_index, captures_len);3361 const captures = try sema.getCaptures(block, extra_index, captures_len);
3337 extra_index += captures_len;3362 extra_index += captures_len;
33383363
3339 const wip_ty = switch (try ip.getOpaqueType(gpa, .{3364 const opaque_init: InternPool.OpaqueTypeInit = .{
3340 .has_namespace = decls_len != 0,3365 .has_namespace = decls_len != 0,
3341 .key = .{ .declared = .{3366 .key = .{ .declared = .{
3342 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),3367 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3343 .captures = captures,3368 .captures = captures,
3344 } },3369 } },
3345 })) {3370 };
3371 // No `wrapWipTy` needed as no std.builtin types are opaque.
3372 const wip_ty = switch (try ip.getOpaqueType(gpa, opaque_init)) {
3373 .existing => |ty| wip: {
3374 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3375 break :wip (try ip.getOpaqueType(gpa, opaque_init)).wip;
3376 },
3346 .wip => |wip| wip,3377 .wip => |wip| wip,
3347 .existing => |ty| return Air.internedToRef(ty),
3348 };3378 };
3349 errdefer wip_ty.cancel(ip);3379 errdefer wip_ty.cancel(ip);
33503380
...@@ -39052,6 +39082,15 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {...@@ -39052,6 +39082,15 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
3905239082
39053pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {39083pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
39054 if (!sema.mod.comp.debug_incremental) return;39084 if (!sema.mod.comp.debug_incremental) return;
39085
39086 // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields
39087 // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
39088 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
39089 // the loop.
39090 if (sema.owner_func_index == .none and dependee == .decl_val and dependee.decl_val == sema.owner_decl_index) {
39091 return;
39092 }
39093
39055 const depender = InternPool.Depender.wrap(39094 const depender = InternPool.Depender.wrap(
39056 if (sema.owner_func_index != .none)39095 if (sema.owner_func_index != .none)
39057 .{ .func = sema.owner_func_index }39096 .{ .func = sema.owner_func_index }