diff --git a/src/InternPool.zig b/src/InternPool.zig index d0dc16c47d..99f937cacf 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -2160,6 +2160,14 @@ pub const Key = union(enum) { pub fn resolvedErrorSetUnordered(func: Func, ip: *const InternPool) Index { return @atomicLoad(Index, func.resolvedErrorSetPtr(@constCast(ip)), .unordered); } + + pub fn setResolvedErrorSet(func: Func, ip: *InternPool, ies: Index) void { + const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; + extra_mutex.lock(); + defer extra_mutex.unlock(); + + @atomicStore(Index, func.resolvedErrorSetPtr(ip), ies, .release); + } }; pub const Int = struct { diff --git a/src/Sema.zig b/src/Sema.zig index 7930c8f080..756e0ac9ca 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -32527,6 +32527,7 @@ fn analyzeIsNonErrComptimeOnly( // If the error set is empty, we must return a comptime true or false. // However we want to avoid unnecessarily resolving an inferred error set // in case it is already non-empty. + try mod.maybeUnresolveIes(func_index); switch (ip.funcIesResolvedUnordered(func_index)) { .anyerror_type => break :blk, .none => {}, @@ -33596,6 +33597,7 @@ fn wrapErrorUnionSet( .inferred_error_set_type => |func_index| ok: { // We carefully do this in an order that avoids unnecessarily // resolving the destination error set type. + try mod.maybeUnresolveIes(func_index); switch (ip.funcIesResolvedUnordered(func_index)) { .anyerror_type => break :ok, .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { @@ -35853,8 +35855,7 @@ fn resolveInferredErrorSet( try sema.declareDependency(.{ .interned = func_index }); // resolved IES - // TODO: during an incremental update this might not be `.none`, but the - // function might be out-of-date! + try zcu.maybeUnresolveIes(func_index); const resolved_ty = func.resolvedErrorSetUnordered(ip); if (resolved_ty != .none) return resolved_ty; diff --git a/src/Zcu.zig b/src/Zcu.zig index a47979bf60..53ad80444e 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -3468,3 +3468,29 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com }, } } + +/// Given the `InternPool.Index` of a function, set its resolved IES to `.none` if it +/// may be outdated. `Sema` should do this before ever loading a resolved IES. +pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void { + const unit = AnalUnit.wrap(.{ .func = func_index }); + if (zcu.outdated.contains(unit) or zcu.potentially_outdated.contains(unit)) { + // We're consulting the resolved IES now, but the function is outdated, so its + // IES may have changed. We have to assume the IES is outdated and set the resolved + // set back to `.none`. + // + // This will cause `PerThread.analyzeFnBody` to mark the IES as outdated when it's + // eventually hit. + // + // Since the IES needs to be resolved, the function body will now definitely need + // re-analysis (even if the IES turns out to be the same!), so mark it as + // definitely-outdated if it's only PO. + if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| { + const gpa = zcu.gpa; + try zcu.outdated.putNoClobber(gpa, unit, kv.value); + if (kv.value == 0) { + try zcu.outdated_ready.put(gpa, unit, {}); + } + } + zcu.intern_pool.funcSetIesResolved(func_index, .none); + } +} diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 700d8708b1..88bc318b3c 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -2072,6 +2072,9 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); func.setAnalysisState(ip, .analyzed); + if (func.analysisUnordered(ip).inferred_error_set) { + func.setResolvedErrorSet(ip, .none); + } // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from. const decl_cau = ip.getCau(cau: { @@ -2278,7 +2281,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! else => |e| return e, }; assert(ies.resolved != .none); - ip.funcSetIesResolved(func_index, ies.resolved); + func.setResolvedErrorSet(ip, ies.resolved); } assert(zcu.analysis_in_progress.swapRemove(anal_unit));