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) {...@@ -2160,6 +2160,14 @@ pub const Key = union(enum) {
2160 pub fn resolvedErrorSetUnordered(func: Func, ip: *const InternPool) Index {2160 pub fn resolvedErrorSetUnordered(func: Func, ip: *const InternPool) Index {
2161 return @atomicLoad(Index, func.resolvedErrorSetPtr(@constCast(ip)), .unordered);2161 return @atomicLoad(Index, func.resolvedErrorSetPtr(@constCast(ip)), .unordered);
2162 }2162 }
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 }
2163 };2171 };
21642172
2165 pub const Int = struct {2173 pub const Int = struct {
src/Sema.zig+3-2
...@@ -32527,6 +32527,7 @@ fn analyzeIsNonErrComptimeOnly(...@@ -32527,6 +32527,7 @@ fn analyzeIsNonErrComptimeOnly(
32527 // If the error set is empty, we must return a comptime true or false.32527 // If the error set is empty, we must return a comptime true or false.
32528 // However we want to avoid unnecessarily resolving an inferred error set32528 // However we want to avoid unnecessarily resolving an inferred error set
32529 // in case it is already non-empty.32529 // in case it is already non-empty.
32530 try mod.maybeUnresolveIes(func_index);
32530 switch (ip.funcIesResolvedUnordered(func_index)) {32531 switch (ip.funcIesResolvedUnordered(func_index)) {
32531 .anyerror_type => break :blk,32532 .anyerror_type => break :blk,
32532 .none => {},32533 .none => {},
...@@ -33596,6 +33597,7 @@ fn wrapErrorUnionSet(...@@ -33596,6 +33597,7 @@ fn wrapErrorUnionSet(
33596 .inferred_error_set_type => |func_index| ok: {33597 .inferred_error_set_type => |func_index| ok: {
33597 // We carefully do this in an order that avoids unnecessarily33598 // We carefully do this in an order that avoids unnecessarily
33598 // resolving the destination error set type.33599 // resolving the destination error set type.
33600 try mod.maybeUnresolveIes(func_index);
33599 switch (ip.funcIesResolvedUnordered(func_index)) {33601 switch (ip.funcIesResolvedUnordered(func_index)) {
33600 .anyerror_type => break :ok,33602 .anyerror_type => break :ok,
33601 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {33603 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
...@@ -35853,8 +35855,7 @@ fn resolveInferredErrorSet(...@@ -35853,8 +35855,7 @@ fn resolveInferredErrorSet(
3585335855
35854 try sema.declareDependency(.{ .interned = func_index }); // resolved IES35856 try sema.declareDependency(.{ .interned = func_index }); // resolved IES
3585535857
35856 // TODO: during an incremental update this might not be `.none`, but the35858 try zcu.maybeUnresolveIes(func_index);
35857 // function might be out-of-date!
35858 const resolved_ty = func.resolvedErrorSetUnordered(ip);35859 const resolved_ty = func.resolvedErrorSetUnordered(ip);
35859 if (resolved_ty != .none) return resolved_ty;35860 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...@@ -3468,3 +3468,29 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3468 },3468 },
3469 }3469 }
3470}3470}
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!...@@ -2072,6 +2072,9 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
2072 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);2072 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
20732073
2074 func.setAnalysisState(ip, .analyzed);2074 func.setAnalysisState(ip, .analyzed);
2075 if (func.analysisUnordered(ip).inferred_error_set) {
2076 func.setResolvedErrorSet(ip, .none);
2077 }
20752078
2076 // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from.2079 // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
2077 const decl_cau = ip.getCau(cau: {2080 const decl_cau = ip.getCau(cau: {
...@@ -2278,7 +2281,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!...@@ -2278,7 +2281,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
2278 else => |e| return e,2281 else => |e| return e,
2279 };2282 };
2280 assert(ies.resolved != .none);2283 assert(ies.resolved != .none);
2281 ip.funcSetIesResolved(func_index, ies.resolved);2284 func.setResolvedErrorSet(ip, ies.resolved);
2282 }2285 }
22832286
2284 assert(zcu.analysis_in_progress.swapRemove(anal_unit));2287 assert(zcu.analysis_in_progress.swapRemove(anal_unit));