Commit 93a5bd262d
Changed files (4)
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));
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 {
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;
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);
+ }
+}