authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-18 13:35:35+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-18 18:10:59+01:00
log93a5bd262defe4c09a617a4ecc68340e20a2b20b
tree1f369ba5818e47ffc6ac4f0a68ff274568e591bf
parent10455371416a37da201b6f968d47ffae597ea7ce
signaturelock-open Commit is signed but in an unrecognized format.

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.

4 files changed, 41 insertions(+), 3 deletions(-)

src/InternPool.zig+8
......@@ -2160,6 +2160,14 @@ pub const Key = union(enum) {
21602160 pub fn resolvedErrorSetUnordered(func: Func, ip: *const InternPool) Index {
21612161 return @atomicLoad(Index, func.resolvedErrorSetPtr(@constCast(ip)), .unordered);
21622162 }
2163
2164 pub fn setResolvedErrorSet(func: Func, ip: *InternPool, ies: Index) void {
2165 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2166 extra_mutex.lock();
2167 defer extra_mutex.unlock();
2168
2169 @atomicStore(Index, func.resolvedErrorSetPtr(ip), ies, .release);
2170 }
21632171 };
21642172
21652173 pub const Int = struct {
src/Sema.zig+3-2
......@@ -32527,6 +32527,7 @@ fn analyzeIsNonErrComptimeOnly(
3252732527 // If the error set is empty, we must return a comptime true or false.
3252832528 // However we want to avoid unnecessarily resolving an inferred error set
3252932529 // in case it is already non-empty.
32530 try mod.maybeUnresolveIes(func_index);
3253032531 switch (ip.funcIesResolvedUnordered(func_index)) {
3253132532 .anyerror_type => break :blk,
3253232533 .none => {},
......@@ -33596,6 +33597,7 @@ fn wrapErrorUnionSet(
3359633597 .inferred_error_set_type => |func_index| ok: {
3359733598 // We carefully do this in an order that avoids unnecessarily
3359833599 // resolving the destination error set type.
33600 try mod.maybeUnresolveIes(func_index);
3359933601 switch (ip.funcIesResolvedUnordered(func_index)) {
3360033602 .anyerror_type => break :ok,
3360133603 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
......@@ -35853,8 +35855,7 @@ fn resolveInferredErrorSet(
3585335855
3585435856 try sema.declareDependency(.{ .interned = func_index }); // resolved IES
3585535857
35856 // TODO: during an incremental update this might not be `.none`, but the
35857 // function might be out-of-date!
35858 try zcu.maybeUnresolveIes(func_index);
3585835859 const resolved_ty = func.resolvedErrorSetUnordered(ip);
3585935860 if (resolved_ty != .none) return resolved_ty;
3586035861
src/Zcu.zig+26
......@@ -3468,3 +3468,29 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
34683468 },
34693469 }
34703470}
3471
3472/// Given the `InternPool.Index` of a function, set its resolved IES to `.none` if it
3473/// may be outdated. `Sema` should do this before ever loading a resolved IES.
3474pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {
3475 const unit = AnalUnit.wrap(.{ .func = func_index });
3476 if (zcu.outdated.contains(unit) or zcu.potentially_outdated.contains(unit)) {
3477 // We're consulting the resolved IES now, but the function is outdated, so its
3478 // IES may have changed. We have to assume the IES is outdated and set the resolved
3479 // set back to `.none`.
3480 //
3481 // This will cause `PerThread.analyzeFnBody` to mark the IES as outdated when it's
3482 // eventually hit.
3483 //
3484 // Since the IES needs to be resolved, the function body will now definitely need
3485 // re-analysis (even if the IES turns out to be the same!), so mark it as
3486 // definitely-outdated if it's only PO.
3487 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
3488 const gpa = zcu.gpa;
3489 try zcu.outdated.putNoClobber(gpa, unit, kv.value);
3490 if (kv.value == 0) {
3491 try zcu.outdated_ready.put(gpa, unit, {});
3492 }
3493 }
3494 zcu.intern_pool.funcSetIesResolved(func_index, .none);
3495 }
3496}
src/Zcu/PerThread.zig+4-1
......@@ -2072,6 +2072,9 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
20722072 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
20732073
20742074 func.setAnalysisState(ip, .analyzed);
2075 if (func.analysisUnordered(ip).inferred_error_set) {
2076 func.setResolvedErrorSet(ip, .none);
2077 }
20752078
20762079 // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
20772080 const decl_cau = ip.getCau(cau: {
......@@ -2278,7 +2281,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
22782281 else => |e| return e,
22792282 };
22802283 assert(ies.resolved != .none);
2281 ip.funcSetIesResolved(func_index, ies.resolved);
2284 func.setResolvedErrorSet(ip, ies.resolved);
22822285 }
22832286
22842287 assert(zcu.analysis_in_progress.swapRemove(anal_unit));