authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-31 13:39:16+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-01 11:27:38+01:00
logf134f4345cf8484b82c46278074eb45af0efaf2e
tree6d4e30800a3017b2b57d96b342f719add4d4379d
parentf6c5f8b79908d6c1550fe535ceb26d1d8944c197
signaturelock-open Commit is signed but in an unrecognized format.

compiler: improve tracking of transitive analysis errors

This is an internal refactor to mark transitive semantic analysis errors as soon as they occur rather than relying on the root "update" function to do so. This is simpler to understand and slightly more efficient. The error surfaced in this case is renamed from `error.AnalysisFail` to `error.AlreadyReported` for consistency with the rest of the compiler. `error.AnalysisFail` is returned from the "ensure up to date" functions in `Zcu.PerThread` to indicate that the unit which was requested has failed analysis---using a different error name here is useful because it prevents `Sema` from accidentally introducing a bug by `try`ing. Alongside the above, I have also begun to store some useful debugging information (the reason for the transitive analysis error) with transitive analysis errors in compilers built with debug extensions. This information is surfaced by the incremental debug server, and was invaluable in tracking down an incremental compilation bug---details of that in the next commit.

7 files changed, 275 insertions(+), 162 deletions(-)

src/Compilation.zig+8-1
......@@ -4076,7 +4076,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
40764076 ref = refs.get(r.referencer).?;
40774077 }
40784078 }
4079 @panic("referenced transitive analysis errors, but none actually emitted");
4079 if (comp.debugIncremental()) {
4080 std.debug.print("skipping compiler panic to allow incremental debug server usage", .{});
4081 try bundle.addRootErrorMessage(.{
4082 .msg = try bundle.addString("compiler bug: referenced transitive analysis errors, but none actually emitted"),
4083 });
4084 } else {
4085 @panic("referenced transitive analysis errors, but none actually emitted");
4086 }
40804087 }
40814088 };
40824089
src/IncrementalDebugServer.zig+20-7
......@@ -286,21 +286,34 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
286286 const referencer = (ref orelse break :ref "<analysis root>").referencer;
287287 break :ref printAnalUnit(referencer, &ref_str_buf);
288288 };
289 const has_err: []const u8 = err: {
290 if (zcu.failed_analysis.contains(unit)) break :err "true";
291 if (zcu.transitive_failed_analysis.contains(unit)) break :err "true (transitive)";
292 break :err "false";
293 };
294289 try w.print(
295290 \\last update generation: {d}
296291 \\current referencer: {s}
297 \\has error: {s}
298292 \\
299293 , .{
300294 unit_info.last_update_gen,
301295 ref_str,
302 has_err,
303296 });
297 if (zcu.failed_analysis.get(unit)) |err_msg| {
298 try w.print("analysis result: failure ({q})\n", .{err_msg.msg});
299 } else if (zcu.transitive_failed_analysis.get(unit)) |reason| {
300 switch (reason) {
301 .astgen_error => try w.writeAll("analysis result: transitive failure (astgen error)\n"),
302 .dependency_loop => try w.writeAll("analysis result: transitive failure (dependency loop)\n"),
303 .lost_tracking => try w.writeAll("analysis result: transitive failure (lost tracking for zir inst)\n"),
304 .failed_unit => |other_unit| {
305 var buf: [32]u8 = undefined;
306 try w.print("analysis result: transitive failure (failed unit: {s})\n", .{printAnalUnit(other_unit, &buf)});
307 },
308 .func_nav_val_changed => |func_index| try w.print("analysis result: transitive failure (owner nav of func '{d}' changed value)\n", .{@backingInt(func_index)}),
309 }
310 } else {
311 try w.writeAll("analysis result: success\n");
312 }
313 if (unit.unwrap() == .func) {
314 const nav_id = zcu.intern_pool.indexToKey(unit.unwrap().func).func.owner_nav;
315 try w.print("owner nav: {d}\n", .{@backingInt(nav_id)});
316 }
304317 } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) {
305318 const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit");
306319 const unit_info = zcu.incremental_debug_state.units.get(unit) orelse return w.writeAll("unknown anal unit");
src/Sema.zig+133-52
......@@ -1472,7 +1472,7 @@ fn analyzeBodyInner(
14721472 i += 1;
14731473 continue;
14741474 },
1475 .astgen_error => return error.AnalysisFail,
1475 .astgen_error => return sema.failTransitive(.astgen_error),
14761476 .float_op_result_ty => try sema.zirFloatOpResultType(block, extended),
14771477 };
14781478 },
......@@ -2697,13 +2697,15 @@ fn failWithTypeMismatch(sema: *Sema, block: *Block, src: LazySrcLoc, expected: T
26972697 });
26982698}
26992699
2700pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) error{ AnalysisFail, OutOfMemory } {
2700pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) SemaError {
27012701 @branchHint(.cold);
27022702 const zcu = sema.pt.zcu;
27032703 const comp = zcu.comp;
27042704 const gpa = comp.gpa;
27052705 const io = comp.io;
27062706
2707 assert(sema.err == null);
2708
27072709 if (build_options.enable_debug_extensions and comp.debug_compile_errors) {
27082710 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
27092711 wip_errors.init(gpa) catch @panic("out of memory");
......@@ -2729,17 +2731,11 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
27292731
27302732 err_msg.reference_trace_root = sema.owner.toOptional();
27312733
2732 const gop = try zcu.failed_analysis.getOrPut(gpa, sema.owner);
2733 if (gop.found_existing) {
2734 // If there are multiple errors for the same Decl, prefer the first one added.
2735 sema.err = null;
2736 err_msg.destroy(gpa);
2737 } else {
2738 sema.err = err_msg;
2739 gop.value_ptr.* = err_msg;
2740 }
2734 try zcu.failed_analysis.putNoClobber(gpa, sema.owner, err_msg);
2735 assert(!zcu.transitive_failed_analysis.contains(sema.owner));
27412736
2742 return error.AnalysisFail;
2737 sema.err = err_msg;
2738 return error.AlreadyReported;
27432739}
27442740
27452741/// Given an ErrorMsg, modify its message and source location to the given values, turning the
......@@ -4745,11 +4741,14 @@ fn failWithBadMemberAccess(
47454741 .@"enum" => "enum",
47464742 else => unreachable,
47474743 };
4748 if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) {
4749 return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{
4750 agg_ty.fmt(pt), field_name.fmt(ip),
4751 });
4752 };
4744 if (agg_ty.typeDeclInst(zcu)) |inst| {
4745 const inst_index = inst.resolve(ip) orelse return sema.failTransitive(.{ .lost_tracking = inst });
4746 if (inst_index == .main_struct_inst) {
4747 return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{
4748 agg_ty.fmt(pt), field_name.fmt(ip),
4749 });
4750 }
4751 }
47534752
47544753 return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{
47554754 kw_name, agg_ty.fmt(pt), field_name.fmt(ip),
......@@ -5997,7 +5996,14 @@ fn lookupInNamespace(
59975996 const pt = sema.pt;
59985997 const zcu = pt.zcu;
59995998
6000 try pt.ensureNamespaceUpToDate(namespace_index);
5999 pt.ensureNamespaceUpToDate(namespace_index) catch |err| switch (err) {
6000 error.LostZirContainerDecl => {
6001 const namespace = zcu.namespacePtr(namespace_index);
6002 const ns_ty: Type = .fromInterned(namespace.owner_type);
6003 return sema.failTransitive(.{ .lost_tracking = ns_ty.typeDeclInstAllowGeneratedTag(zcu).? });
6004 },
6005 else => |e| return e,
6006 };
60016007
60026008 const namespace = zcu.namespacePtr(namespace_index);
60036009
......@@ -6062,7 +6068,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
60626068 const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace);
60636069 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
60646070 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
6065 error.AnalysisFail => @panic("std.lang.StackTrace is corrupt"),
6071 error.AlreadyReported => @panic("std.lang.StackTrace is corrupt"),
60666072 error.ComptimeReturn, error.ComptimeBreak => unreachable,
60676073 error.OutOfMemory, error.Canceled => |e| return e,
60686074 };
......@@ -6724,7 +6730,9 @@ fn analyzeCall(
67246730 const fn_nav: InternPool.Nav, const fn_zir: Zir, const fn_tracked_inst: InternPool.TrackedInst.Index, const fn_zir_inst: Zir.Inst.Index, const fn_zir_info: Zir.FnInfo = if (func_val) |f| b: {
67256731 const info = ip.indexToKey(f.toIntern()).func;
67266732 const nav = ip.getNav(info.owner_nav);
6727 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
6733 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse {
6734 return sema.failTransitive(.{ .lost_tracking = info.zir_body_inst });
6735 };
67286736 const file = zcu.fileByIndex(resolved_func_inst.file);
67296737 const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst);
67306738 break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info };
......@@ -8355,7 +8363,10 @@ fn zirFunc(
83558363 const cc: std.lang.CallingConvention = if (has_body) cc: {
83568364 const func_decl_nav = sema.owner.unwrap().nav_val;
83578365 const fn_is_exported = exported: {
8358 const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail;
8366 const decl_ti = ip.getNav(func_decl_nav).analysis.?.zir_index;
8367 const decl_inst = decl_ti.resolve(ip) orelse {
8368 return sema.failTransitive(.{ .lost_tracking = decl_ti });
8369 };
83598370 const zir_decl = sema.code.getDeclaration(decl_inst);
83608371 break :exported zir_decl.linkage == .@"export";
83618372 };
......@@ -12289,10 +12300,11 @@ fn analyzeSwitchPayloadCaptureTaggedUnion(
1228912300 dummy_captures,
1229012301 .{ .override = item_srcs },
1229112302 ) catch |err| switch (err) {
12292 error.AnalysisFail => {
12293 const msg = sema.err orelse return error.AnalysisFail;
12294 try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{});
12295 return error.AnalysisFail;
12303 error.AlreadyReported => |e| {
12304 if (sema.err) |msg| {
12305 try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{});
12306 }
12307 return e;
1229612308 },
1229712309 else => |e| return e,
1229812310 };
......@@ -12328,11 +12340,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion(
1232812340 dummy_captures,
1232912341 .{ .override = item_srcs },
1233012342 ) catch |err| switch (err) {
12331 error.AnalysisFail => {
12332 const msg = sema.err orelse return error.AnalysisFail;
12333 try sema.errNote(capture_src, msg, "this coercion is only possible when capturing by value", .{});
12334 try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{});
12335 return error.AnalysisFail;
12343 error.AlreadyReported => |e| {
12344 if (sema.err) |msg| {
12345 try sema.errNote(capture_src, msg, "this coercion is only possible when capturing by value", .{});
12346 try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{});
12347 }
12348 return e;
1233612349 },
1233712350 else => |e| return e,
1233812351 };
......@@ -17207,7 +17220,14 @@ fn typeInfoNamespaceDecls(
1720717220 const ip = &zcu.intern_pool;
1720817221
1720917222 const namespace_index = opt_namespace_index.unwrap() orelse return;
17210 try pt.ensureNamespaceUpToDate(namespace_index);
17223 pt.ensureNamespaceUpToDate(namespace_index) catch |err| switch (err) {
17224 error.LostZirContainerDecl => {
17225 const namespace = zcu.namespacePtr(namespace_index);
17226 const ns_ty: Type = .fromInterned(namespace.owner_type);
17227 return sema.failTransitive(.{ .lost_tracking = ns_ty.typeDeclInstAllowGeneratedTag(zcu).? });
17228 },
17229 else => |e| return e,
17230 };
1721117231 const namespace = zcu.namespacePtr(namespace_index);
1721217232
1721317233 const gop = try seen_namespaces.getOrPut(namespace);
......@@ -17933,11 +17953,12 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1793317953 }
1793417954 // TODO Add compile error for @optimizeFor occurring too late in a scope.
1793517955 sema.analyzeUnreachable(block, src, true) catch |err| switch (err) {
17936 error.AnalysisFail => {
17937 const msg = sema.err orelse return err;
17938 if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err;
17939 try sema.errNote(src, msg, "the end of a naked function is implicitly unreachable", .{});
17940 return err;
17956 error.AlreadyReported => |e| {
17957 if (sema.err) |msg| {
17958 if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err;
17959 try sema.errNote(src, msg, "the end of a naked function is implicitly unreachable", .{});
17960 }
17961 return e;
1794117962 },
1794217963 else => |e| return e,
1794317964 };
......@@ -18353,11 +18374,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1835318374
1835418375 const elem_ty = blk: {
1835518376 const air_inst = sema.resolveInst(extra.data.elem_type);
18356 const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| {
18357 if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) {
18358 try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
18359 }
18360 return err;
18377 const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| switch (err) {
18378 error.AlreadyReported => |e| {
18379 if (sema.err) |msg| {
18380 if (sema.typeOf(air_inst).isSinglePointer(zcu)) {
18381 try sema.errNote(elem_ty_src, msg, "use '.*' to dereference pointer", .{});
18382 }
18383 }
18384 return e;
18385 },
18386 else => |e| return e,
1836118387 };
1836218388 assert(!ty.isGenericPoison());
1836318389 break :blk ty;
......@@ -24909,7 +24935,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2490924935 } else cc: {
2491024936 if (has_body) {
2491124937 const func_decl_nav = sema.owner.unwrap().nav_val;
24912 const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail;
24938 const func_decl_ti = ip.getNav(func_decl_nav).analysis.?.zir_index;
24939 const func_decl_inst = func_decl_ti.resolve(&zcu.intern_pool) orelse {
24940 return sema.failTransitive(.{ .lost_tracking = func_decl_ti });
24941 };
2491324942 const zir_decl = sema.code.getDeclaration(func_decl_inst);
2491424943 if (zir_decl.linkage == .@"export") {
2491524944 break :cc target.cCallingConvention() orelse {
......@@ -30642,7 +30671,10 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
3064230671 if (pt.zcu.analysis_in_progress.contains(unit)) {
3064330672 return sema.failWithDependencyLoop(unit, &reason);
3064430673 }
30645 try pt.ensureMemoizedStateUpToDate(stage, &reason);
30674 pt.ensureMemoizedStateUpToDate(stage, &reason) catch |err| switch (err) {
30675 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = unit }),
30676 else => |e| return e,
30677 };
3064630678}
3064730679
3064830680pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
......@@ -30678,9 +30710,15 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
3067830710 switch (kind) {
3067930711 .type => {
3068030712 try zcu.ensureNavValAnalysisQueued(nav_index);
30681 return pt.ensureNavTypeUpToDate(nav_index, &reason);
30713 return pt.ensureNavTypeUpToDate(nav_index, &reason) catch |err| switch (err) {
30714 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = anal_unit }),
30715 else => |e| return e,
30716 };
30717 },
30718 .fully => return pt.ensureNavValUpToDate(nav_index, &reason) catch |err| switch (err) {
30719 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = anal_unit }),
30720 else => |e| return e,
3068230721 },
30683 .fully => return pt.ensureNavValUpToDate(nav_index, &reason),
3068430722 }
3068530723}
3068630724
......@@ -33743,7 +33781,10 @@ fn ensureFuncIesResolved(
3374333781 return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason);
3374433782 }
3374533783
33746 try pt.ensureFuncBodyUpToDate(func_index, &reason);
33784 pt.ensureFuncBodyUpToDate(func_index, &reason) catch |err| switch (err) {
33785 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .func = func_index }) }),
33786 else => |e| return e,
33787 };
3374733788}
3374833789
3374933790pub fn resolveInferredErrorSetPtr(
......@@ -34962,7 +35003,9 @@ pub fn setTypeName(
3496235003 },
3496335004 .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()),
3496435005 .func => {
34965 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
35006 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse {
35007 return sema.failTransitive(.{ .lost_tracking = ip.funcZirBodyInst(sema.func_index) });
35008 });
3496635009 const zir_tags = sema.code.instructions.items(.tag);
3496735010
3496835011 var aw: std.Io.Writer.Allocating = .init(gpa);
......@@ -35078,7 +35121,10 @@ fn zirStructDecl(
3507835121 };
3507935122
3508035123 try sema.addTypeReferenceEntry(src, ty);
35081 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35124 pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) {
35125 error.LostZirContainerDecl => unreachable, // we literally just tracked it
35126 else => |e| return e,
35127 };
3508235128
3508335129 return .fromType(ty);
3508435130}
......@@ -35151,7 +35197,10 @@ fn zirUnionDecl(
3515135197 };
3515235198
3515335199 try sema.addTypeReferenceEntry(src, ty);
35154 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35200 pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) {
35201 error.LostZirContainerDecl => unreachable, // we literally just tracked it
35202 else => |e| return e,
35203 };
3515535204
3515635205 return .fromType(ty);
3515735206}
......@@ -35203,7 +35252,10 @@ fn zirEnumDecl(
3520335252 };
3520435253
3520535254 try sema.addTypeReferenceEntry(src, ty);
35206 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35255 pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) {
35256 error.LostZirContainerDecl => unreachable, // we literally just tracked it
35257 else => |e| return e,
35258 };
3520735259
3520835260 return .fromType(ty);
3520935261}
......@@ -35252,7 +35304,10 @@ fn zirOpaqueDecl(
3525235304 };
3525335305
3525435306 try sema.addTypeReferenceEntry(src, ty);
35255 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35307 pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) {
35308 error.LostZirContainerDecl => unreachable, // we literally just tracked it
35309 else => |e| return e,
35310 };
3525635311
3525735312 return .fromType(ty);
3525835313}
......@@ -35293,5 +35348,31 @@ pub fn failWithDependencyLoop(
3529335348 }
3529435349
3529535350 // A dependency loop error will be reported. Mark us all as transitive failures.
35296 return error.AnalysisFail;
35351 return sema.failTransitive(.dependency_loop);
35352}
35353
35354/// Marks the owner of `sema` as having failed semantic failed *without* an error message, and
35355/// returns failure. This function is suitable to call when any one of the following is true:
35356///
35357/// * `sema.owner` is guaranteed to be unreferenced on this update, for instance because it uses a
35358/// dead `InternPool.TrackedInst`.
35359///
35360/// * There is guaranteed to be a compile error if this unit is referenced. In practice, this means
35361/// that either there is an error elsewhere in the pipeline (e.g. AstGen), or we depend on another
35362/// `AnalUnit` which has itself failed.
35363pub fn failTransitive(sema: *Sema, reason: Zcu.TransitiveFailureReason) SemaError {
35364 assert(sema.err == null);
35365 const zcu = sema.pt.zcu;
35366 const unit = sema.owner;
35367
35368 log.debug("transitive failure analyzing '{f}' ({t})", .{ zcu.fmtAnalUnit(unit), reason });
35369
35370 assert(!zcu.failed_analysis.contains(unit));
35371 try zcu.transitive_failed_analysis.putNoClobber(
35372 zcu.comp.gpa,
35373 unit,
35374 if (build_options.enable_debug_extensions) reason,
35375 );
35376
35377 return error.AlreadyReported;
3529735378}
src/Sema/LowerZon.zig+2-2
......@@ -320,7 +320,7 @@ fn failUnsupportedResultType(
320320 self: *LowerZon,
321321 ty: Type,
322322 opt_note: ?[]const u8,
323) error{ AnalysisFail, OutOfMemory } {
323) Zcu.SemaError {
324324 @branchHint(.cold);
325325 const sema = self.sema;
326326 const gpa = sema.gpa;
......@@ -338,7 +338,7 @@ fn fail(
338338 node: Zoir.Node.Index,
339339 comptime format: []const u8,
340340 args: anytype,
341) error{ AnalysisFail, OutOfMemory } {
341) Zcu.SemaError {
342342 @branchHint(.cold);
343343 const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args);
344344 try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{});
src/Sema/type_resolution.zig+21-7
......@@ -116,7 +116,10 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons
116116 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
117117 return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason);
118118 }
119 try pt.ensureTypeLayoutUpToDate(ty, reason);
119 pt.ensureTypeLayoutUpToDate(ty, reason) catch |err| switch (err) {
120 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .type_layout = ty.toIntern() }) }),
121 else => |e| return e,
122 };
120123 },
121124
122125 // values, not types
......@@ -166,7 +169,10 @@ pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) Sema
166169 return sema.failWithDependencyLoop(.wrap(.{ .struct_defaults = ty.toIntern() }), &reason);
167170 }
168171
169 try pt.ensureStructDefaultsUpToDate(ty, &reason);
172 pt.ensureStructDefaultsUpToDate(ty, &reason) catch |err| switch (err) {
173 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .struct_defaults = ty.toIntern() }) }),
174 else => |e| return e,
175 };
170176}
171177
172178/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.
......@@ -188,7 +194,9 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
188194
189195 const struct_obj = ip.loadStructType(struct_ty.toIntern());
190196 assert(struct_obj.want_layout);
191 const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
197 const zir_index = struct_obj.zir_index.resolve(ip) orelse {
198 return sema.failTransitive(.{ .lost_tracking = struct_obj.zir_index });
199 };
192200
193201 var block: Block = .{
194202 .parent = null,
......@@ -606,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
606614 struct_ty.assertHasLayout(zcu);
607615 const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() });
608616 if (zcu.failed_analysis.contains(layout_unit) or zcu.transitive_failed_analysis.contains(layout_unit)) {
609 return error.AnalysisFail;
617 return sema.failTransitive(.{ .failed_unit = layout_unit });
610618 }
611619
612620 const struct_obj = ip.loadStructType(struct_ty.toIntern());
......@@ -656,7 +664,9 @@ fn resolveStructDefaultsInner(
656664 assert(struct_obj.field_defaults.len > 0);
657665
658666 // We'll need to map the struct decl instruction to provide result types
659 const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
667 const zir_index = struct_obj.zir_index.resolve(ip) orelse {
668 return sema.failTransitive(.{ .lost_tracking = struct_obj.zir_index });
669 };
660670 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
661671
662672 const field_types = struct_obj.field_types.get(ip);
......@@ -713,7 +723,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
713723
714724 const union_obj = ip.loadUnionType(union_ty.toIntern());
715725 assert(union_obj.want_layout);
716 const zir_index = union_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
726 const zir_index = union_obj.zir_index.resolve(ip) orelse {
727 return sema.failTransitive(.{ .lost_tracking = union_obj.zir_index });
728 };
717729
718730 var block: Block = .{
719731 .parent = null,
......@@ -1212,7 +1224,9 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
12121224 };
12131225
12141226 const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index;
1215 const zir_index = tracked_inst.resolve(ip) orelse return error.AnalysisFail;
1227 const zir_index = tracked_inst.resolve(ip) orelse {
1228 return sema.failTransitive(.{ .lost_tracking = tracked_inst });
1229 };
12161230
12171231 var block: Block = .{
12181232 .parent = null,
src/Zcu.zig+18-3
......@@ -182,7 +182,10 @@ analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason
182182/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
183183failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty,
184184/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
185transitive_failed_analysis: std.array_hash_map.Auto(AnalUnit, void) = .empty,
185transitive_failed_analysis: std.array_hash_map.Auto(
186 AnalUnit,
187 if (build_options.enable_debug_extensions) TransitiveFailureReason else void,
188) = .empty,
186189/// This `Nav` succeeded analysis, but failed codegen.
187190/// This may be a simple "value" `Nav`, or it may be a function.
188191/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
......@@ -351,6 +354,18 @@ pub const DependencyReason = struct {
351354 type_layout_reason: Sema.type_resolution.LayoutResolveReason,
352355};
353356
357/// These are not required for anything, but when the compiler is built with debug extensions, we
358/// store these in `Zcu.transitive_failed_analysis` and surface them in the incremental debug server
359/// (see `src/IncrementalDebugServer.zig`) because they are a useful debugging aid for bugs in
360/// incremental compilation.
361pub const TransitiveFailureReason = union(enum) {
362 astgen_error,
363 dependency_loop,
364 lost_tracking: InternPool.TrackedInst.Index,
365 failed_unit: AnalUnit,
366 func_nav_val_changed: InternPool.Index,
367};
368
354369pub const IncrementalDebugState = struct {
355370 /// All container types in the ZCU, even dead ones.
356371 /// Value is the generation the type was created on.
......@@ -2808,13 +2823,13 @@ pub const LazySrcLoc = struct {
28082823 }
28092824};
28102825
2811pub const SemaError = error{ OutOfMemory, Canceled, AnalysisFail };
2826pub const SemaError = error{ OutOfMemory, Canceled, AlreadyReported };
28122827pub const CompileError = error{
28132828 OutOfMemory,
28142829 /// The compilation update is no longer desired.
28152830 Canceled,
28162831 /// When this is returned, the compile error for the failure has already been recorded.
2817 AnalysisFail,
2832 AlreadyReported,
28182833 /// In a comptime scope, a return instruction was encountered. This error is only seen when
28192834 /// doing a comptime function call.
28202835 ComptimeReturn,
src/Zcu/PerThread.zig+73-90
......@@ -320,7 +320,7 @@ pub fn update(
320320 // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed,
321321 // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze.
322322 while (try zcu.findOutdatedToAnalyze()) |unit| {
323 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
323 const maybe_err: UpdateUnitError!void = switch (unit.unwrap()) {
324324 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
325325 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null),
326326 .nav_val => |nav| pt.ensureNavValUpToDate(nav, null),
......@@ -332,7 +332,7 @@ pub fn update(
332332 error.Canceled,
333333 => |e| return e,
334334
335 error.AnalysisFail => {}, // already reported
335 error.AnalysisFail => {},
336336 };
337337 break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null);
338338 },
......@@ -344,7 +344,7 @@ pub fn update(
344344 error.Canceled,
345345 => |e| return e,
346346
347 error.AnalysisFail => {}, // already reported
347 error.AnalysisFail => {},
348348 };
349349 }
350350}
......@@ -455,7 +455,7 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc
455455
456456/// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs
457457/// AstGen as needed. Also updates `file.status`. Does not assume that `file.mod`
458/// is populated. Does not return `error.AnalysisFail` on AstGen failures.
458/// is populated. Returns success even if the file has AstGen errors.
459459pub fn updateFile(
460460 pt: Zcu.PerThread,
461461 file_index: Zcu.File.Index,
......@@ -1036,6 +1036,11 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc
10361036 zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index));
10371037}
10381038
1039const UpdateUnitError = Allocator.Error || Io.Cancelable || error{
1040 /// Semantic analysis of this `AnalUnit` failed.
1041 AnalysisFail,
1042};
1043
10391044/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.
10401045/// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore
10411046/// this, since the error is already registered, but it must not use the value of memoized fields.
......@@ -1044,7 +1049,7 @@ pub fn ensureMemoizedStateUpToDate(
10441049 stage: InternPool.MemoizedStateStage,
10451050 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
10461051 reason: ?*const Zcu.DependencyReason,
1047) Zcu.SemaError!void {
1052) UpdateUnitError!void {
10481053 const zcu = pt.zcu;
10491054 const gpa = zcu.gpa;
10501055
......@@ -1078,15 +1083,7 @@ pub fn ensureMemoizedStateUpToDate(
10781083 const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed|
10791084 .{ any_changed or prev_failed, false }
10801085 else |err| switch (err) {
1081 error.AnalysisFail => res: {
1082 if (!zcu.failed_analysis.contains(unit)) {
1083 // If this unit caused the error, it would have an entry in `failed_analysis`.
1084 // Since it does not, this must be a transitive failure.
1085 try zcu.transitive_failed_analysis.put(gpa, unit, {});
1086 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(unit)});
1087 }
1088 break :res .{ !prev_failed, true };
1089 },
1086 error.AlreadyReported => .{ !prev_failed, true },
10901087 error.OutOfMemory => {
10911088 // TODO: same as for `ensureComptimeUnitUpToDate` etc
10921089 return error.OutOfMemory;
......@@ -1154,7 +1151,7 @@ fn analyzeMemoizedState(
11541151/// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis
11551152/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
11561153/// free to ignore this, since the error is already registered.
1157pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void {
1154pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) UpdateUnitError!void {
11581155 const zcu = pt.zcu;
11591156 const gpa = zcu.gpa;
11601157
......@@ -1195,15 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
11951192 defer unit_tracking.end(zcu);
11961193
11971194 return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) {
1198 error.AnalysisFail => {
1199 if (!zcu.failed_analysis.contains(anal_unit)) {
1200 // If this unit caused the error, it would have an entry in `failed_analysis`.
1201 // Since it does not, this must be a transitive failure.
1202 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1203 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1204 }
1205 return error.AnalysisFail;
1206 },
1195 error.AlreadyReported => return error.AnalysisFail,
12071196 error.OutOfMemory => {
12081197 // TODO: it's unclear how to gracefully handle this.
12091198 // To report the error cleanly, we need to add a message to `failed_analysis` and a
......@@ -1221,8 +1210,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
12211210
12221211/// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old
12231212/// side effects (exports/references/etc) have been dropped. If semantic analysis fails, this
1224/// function will return `error.AnalysisFail`, and it is the caller's reponsibility to add an entry
1225/// to `transitive_failed_analysis` if necessary.
1213/// function will return `error.AlreadyReported`.
12261214fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void {
12271215 const zcu = pt.zcu;
12281216 const ip = &zcu.intern_pool;
......@@ -1239,7 +1227,14 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
12391227 defer tracy_trace.end();
12401228 tracy_trace.addTextFmt("cu_id={d}", .{cu_id});
12411229
1242 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1230 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse {
1231 try zcu.transitive_failed_analysis.putNoClobber(
1232 gpa,
1233 anal_unit,
1234 if (build_options.enable_debug_extensions) .{ .lost_tracking = comptime_unit.zir_index },
1235 );
1236 return error.AlreadyReported;
1237 };
12431238 const file = zcu.fileByIndex(inst_resolved.file);
12441239 const zir = file.zir.?;
12451240
......@@ -1314,7 +1309,7 @@ pub fn ensureTypeLayoutUpToDate(
13141309 ty: Type,
13151310 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
13161311 reason: ?*const Zcu.DependencyReason,
1317) Zcu.SemaError!void {
1312) UpdateUnitError!void {
13181313 const zcu = pt.zcu;
13191314 const ip = &zcu.intern_pool;
13201315 const comp = zcu.comp;
......@@ -1399,15 +1394,7 @@ pub fn ensureTypeLayoutUpToDate(
13991394 const new_failed: bool = if (result) failed: {
14001395 break :failed false;
14011396 } else |err| switch (err) {
1402 error.AnalysisFail => failed: {
1403 if (!zcu.failed_analysis.contains(anal_unit)) {
1404 // If this unit caused the error, it would have an entry in `failed_analysis`.
1405 // Since it does not, this must be a transitive failure.
1406 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1407 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1408 }
1409 break :failed true;
1410 },
1397 error.AlreadyReported => true,
14111398 error.OutOfMemory,
14121399 error.Canceled,
14131400 => |e| return e,
......@@ -1442,7 +1429,7 @@ pub fn ensureStructDefaultsUpToDate(
14421429 ty: Type,
14431430 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
14441431 reason: ?*const Zcu.DependencyReason,
1445) Zcu.SemaError!void {
1432) UpdateUnitError!void {
14461433 const zcu = pt.zcu;
14471434 const ip = &zcu.intern_pool;
14481435 const comp = zcu.comp;
......@@ -1513,15 +1500,7 @@ pub fn ensureStructDefaultsUpToDate(
15131500 const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: {
15141501 break :failed false;
15151502 } else |err| switch (err) {
1516 error.AnalysisFail => failed: {
1517 if (!zcu.failed_analysis.contains(anal_unit)) {
1518 // If this unit caused the error, it would have an entry in `failed_analysis`.
1519 // Since it does not, this must be a transitive failure.
1520 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1521 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1522 }
1523 break :failed true;
1524 },
1503 error.AlreadyReported => true,
15251504 error.OutOfMemory,
15261505 error.Canceled,
15271506 => |e| return e,
......@@ -1547,7 +1526,7 @@ pub fn ensureNavValUpToDate(
15471526 nav_id: InternPool.Nav.Index,
15481527 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
15491528 reason: ?*const Zcu.DependencyReason,
1550) Zcu.SemaError!void {
1529) UpdateUnitError!void {
15511530 const zcu = pt.zcu;
15521531 const gpa = zcu.gpa;
15531532 const ip = &zcu.intern_pool;
......@@ -1594,15 +1573,7 @@ pub fn ensureNavValUpToDate(
15941573 false,
15951574 };
15961575 } else |err| switch (err) {
1597 error.AnalysisFail => res: {
1598 if (!zcu.failed_analysis.contains(anal_unit)) {
1599 // If this unit caused the error, it would have an entry in `failed_analysis`.
1600 // Since it does not, this must be a transitive failure.
1601 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1602 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1603 }
1604 break :res .{ !prev_failed, true };
1605 },
1576 error.AlreadyReported => .{ !prev_failed, true },
16061577 error.OutOfMemory => {
16071578 // TODO: it's unclear how to gracefully handle this.
16081579 // To report the error cleanly, we need to add a message to `failed_analysis` and a
......@@ -1655,7 +1626,14 @@ fn analyzeNavVal(
16551626 tracy_trace.addText(old_nav.fqn.toSlice(ip));
16561627 tracy_trace.addTextFmt("nav_id={d}", .{nav_id});
16571628
1658 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1629 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse {
1630 try zcu.transitive_failed_analysis.putNoClobber(
1631 gpa,
1632 anal_unit,
1633 if (build_options.enable_debug_extensions) .{ .lost_tracking = old_nav.analysis.?.zir_index },
1634 );
1635 return error.AlreadyReported;
1636 };
16591637 const file = zcu.fileByIndex(inst_resolved.file);
16601638 const zir = file.zir.?;
16611639 const zir_decl = zir.getDeclaration(inst_resolved.inst);
......@@ -1916,7 +1894,7 @@ pub fn ensureNavTypeUpToDate(
19161894 nav_id: InternPool.Nav.Index,
19171895 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
19181896 reason: ?*const Zcu.DependencyReason,
1919) Zcu.SemaError!void {
1897) UpdateUnitError!void {
19201898 const zcu = pt.zcu;
19211899 const gpa = zcu.gpa;
19221900 const ip = &zcu.intern_pool;
......@@ -1963,15 +1941,7 @@ pub fn ensureNavTypeUpToDate(
19631941 false,
19641942 };
19651943 } else |err| switch (err) {
1966 error.AnalysisFail => res: {
1967 if (!zcu.failed_analysis.contains(anal_unit)) {
1968 // If this unit caused the error, it would have an entry in `failed_analysis`.
1969 // Since it does not, this must be a transitive failure.
1970 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1971 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1972 }
1973 break :res .{ !prev_failed, true };
1974 },
1944 error.AlreadyReported => .{ !prev_failed, true },
19751945 error.OutOfMemory => {
19761946 // TODO: it's unclear how to gracefully handle this.
19771947 // To report the error cleanly, we need to add a message to `failed_analysis` and a
......@@ -2024,7 +1994,14 @@ fn analyzeNavType(
20241994 tracy_trace.addText(old_nav.fqn.toSlice(ip));
20251995 tracy_trace.addTextFmt("nav_id={d}", .{nav_id});
20261996
2027 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1997 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse {
1998 try zcu.transitive_failed_analysis.putNoClobber(
1999 gpa,
2000 anal_unit,
2001 if (build_options.enable_debug_extensions) .{ .lost_tracking = old_nav.analysis.?.zir_index },
2002 );
2003 return error.AlreadyReported;
2004 };
20282005 const file = zcu.fileByIndex(inst_resolved.file);
20292006 const zir = file.zir.?;
20302007
......@@ -2160,7 +2137,7 @@ pub fn ensureFuncBodyUpToDate(
21602137 func_index: InternPool.Index,
21612138 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
21622139 reason: ?*const Zcu.DependencyReason,
2163) Zcu.SemaError!void {
2140) UpdateUnitError!void {
21642141 dev.check(.sema);
21652142
21662143 const zcu = pt.zcu;
......@@ -2204,18 +2181,10 @@ pub fn ensureFuncBodyUpToDate(
22042181 const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result|
22052182 .{ prev_failed or result.ies_outdated, false }
22062183 else |err| switch (err) {
2207 error.AnalysisFail => res: {
2208 if (!zcu.failed_analysis.contains(anal_unit)) {
2209 // If this function caused the error, it would have an entry in `failed_analysis`.
2210 // Since it does not, this must be a transitive failure.
2211 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
2212 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
2213 }
2214 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
2215 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
2216 // a different error later (which may now be invalid).
2217 break :res .{ !prev_failed, true };
2218 },
2184 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
2185 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
2186 // a different error later (which may now be invalid).
2187 error.AlreadyReported => .{ !prev_failed, true },
22192188 error.OutOfMemory => {
22202189 // TODO: it's unclear how to gracefully handle this.
22212190 // To report the error cleanly, we need to add a message to `failed_analysis` and a
......@@ -3306,15 +3275,21 @@ fn analyzeFuncBodyInner(
33063275 // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary.
33073276
33083277 if (func.generic_owner == .none) {
3309 try pt.ensureNavValUpToDate(func.owner_nav, reason);
3278 pt.ensureNavValUpToDate(func.owner_nav, reason) catch |err| switch (err) {
3279 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .nav_val = func.owner_nav }) }),
3280 else => |e| return e,
3281 };
33103282 if (ip.getNav(func.owner_nav).resolved.?.value != func_index) {
3311 return error.AnalysisFail;
3283 return sema.failTransitive(.{ .func_nav_val_changed = func_index });
33123284 }
33133285 } else {
33143286 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
3315 try pt.ensureNavValUpToDate(go_nav, reason);
3287 pt.ensureNavValUpToDate(go_nav, reason) catch |err| switch (err) {
3288 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .nav_val = go_nav }) }),
3289 else => |e| return e,
3290 };
33163291 if (ip.getNav(go_nav).resolved.?.value != func.generic_owner) {
3317 return error.AnalysisFail;
3292 return sema.failTransitive(.{ .func_nav_val_changed = func.generic_owner });
33183293 }
33193294 }
33203295
......@@ -3344,7 +3319,9 @@ fn analyzeFuncBodyInner(
33443319 };
33453320 defer inner_block.instructions.deinit(gpa);
33463321
3347 const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse return error.AnalysisFail);
3322 const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse {
3323 return sema.failTransitive(.{ .lost_tracking = func.zirBodyInstUnordered(ip) });
3324 });
33483325
33493326 // Here we are performing "runtime semantic analysis" for a function body, which means
33503327 // we must map the parameter ZIR instructions to `arg` AIR instructions.
......@@ -4378,12 +4355,18 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) (Io.Cancelable |
43784355 return result.index;
43794356}
43804357
4358const UpdateNamespaceError = Allocator.Error || Io.Cancelable || error{
4359 /// This namespace refers to a ZIR container declaration which no longer exists, so any code
4360 /// referencing it is guaranteed to be unreferenced on this update.
4361 LostZirContainerDecl,
4362};
4363
43814364/// Given a namespace, re-scan its declarations from the type definition if they have not
43824365/// yet been re-scanned on this update.
4383/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.
4366/// If the type declaration instruction has been lost, returns `error.LostZirContainerDecl`.
43844367/// This will effectively short-circuit the caller, which will be semantic analysis of a
43854368/// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error.
4386pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void {
4369pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) UpdateNamespaceError!void {
43874370 const zcu = pt.zcu;
43884371 const ip = &zcu.intern_pool;
43894372 const namespace = zcu.namespacePtr(namespace_index);
......@@ -4410,7 +4393,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
44104393
44114394 // Namespace outdated -- re-scan the type if necessary.
44124395
4413 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
4396 const inst_info = key.zir_index.resolveFull(ip) orelse return error.LostZirContainerDecl;
44144397 const file = zcu.fileByIndex(inst_info.file);
44154398 const zir = &file.zir.?;
44164399