frontend: removed resolved IES data for outdated functions

Without this, incremental updates which would change inferred error sets
fail, since they assume the IES is resolved and equals the old set,
resulting in false positive compile errors when e.g. coercing to an IES.
This commit is contained in:
mlugg 2024-08-18 13:35:35 +01:00
parent 1045537141
commit 93a5bd262d
No known key found for this signature in database
GPG Key ID: 3F5B7DCCBF4AF02E
4 changed files with 41 additions and 3 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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));