authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-01 23:34:55+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-01 23:34:55+02:00
log4af8a35ca91578615f1a6c7a3dc8c82cfd48fea3
tree0ac66d9f4ab22e2265e7b67b7c263944935c2ca5
parent6ee0ef96fea84f66ad3e7e987a07a5b89ab41308
parent804c284d2a4ece85aec64d25c241a48b4e8b11ad

Merge pull request 'incremental: fix incorrect dependency in generic instances' (#36363) from mlugg/incremental-generic-instance-owner-dep into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36363

8 files changed, 323 insertions(+), 164 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+75-92
......@@ -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
......@@ -3293,9 +3262,7 @@ fn analyzeFuncBodyInner(
32933262 defer sema.deinit();
32943263
32953264 // Every runtime function has a dependency on the source of the Decl it originates from.
3296 // It also depends on the value of its owner Decl.
32973265 try sema.declareDependency(.{ .src_hash = decl_analysis.zir_index });
3298 try sema.declareDependency(.{ .nav_val = func.owner_nav });
32993266
33003267 // Make sure that the declaration `Nav` still refers to this function (or its generic owner).
33013268 // This will not be the case if the incremental update has changed a function type or turned a
......@@ -3306,15 +3273,23 @@ fn analyzeFuncBodyInner(
33063273 // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary.
33073274
33083275 if (func.generic_owner == .none) {
3309 try pt.ensureNavValUpToDate(func.owner_nav, reason);
3276 try sema.declareDependency(.{ .nav_val = func.owner_nav });
3277 pt.ensureNavValUpToDate(func.owner_nav, reason) catch |err| switch (err) {
3278 error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .nav_val = func.owner_nav }) }),
3279 else => |e| return e,
3280 };
33103281 if (ip.getNav(func.owner_nav).resolved.?.value != func_index) {
3311 return error.AnalysisFail;
3282 return sema.failTransitive(.{ .func_nav_val_changed = func_index });
33123283 }
33133284 } else {
33143285 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
3315 try pt.ensureNavValUpToDate(go_nav, reason);
3286 try sema.declareDependency(.{ .nav_val = go_nav });
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
test/incremental/temporary_analysis_error_in_generic_signature created+46
......@@ -0,0 +1,46 @@
1#update=initial version
2#file=main.zig
3//! The original repro here depends on re-analysis order, which depends on
4//! declaration order, so this exact declaration order must be used.
5const Foo = struct { x: u8 };
6pub fn main(init: std.process.Init) !void {
7 const c = bar('Z').x;
8 try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' });
9}
10fn bar(comptime x: u8) @This().Foo {
11 return .{ .x = x };
12}
13const std = @import("std");
14#expect_stdout="Z\n"
15
16#update=change generic signature to use non-existent member
17#file=main.zig
18//! The original repro here depends on re-analysis order, which depends on
19//! declaration order, so this exact declaration order must be used.
20const Foo = struct { x: u8 };
21pub fn main(init: std.process.Init) !void {
22 const c = bar('Z').x;
23 try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' });
24}
25fn bar(comptime x: u8) @This().FooAlias {
26 return .{ .x = x };
27}
28const std = @import("std");
29#expect_error=main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'
30#expect_error=main.zig:1:1: note: struct declared here
31
32#update=add that member, fixing the error
33#file=main.zig
34//! The original repro here depends on re-analysis order, which depends on
35//! declaration order, so this exact declaration order must be used.
36const Foo = struct { x: u8 };
37const FooAlias = Foo;
38pub fn main(init: std.process.Init) !void {
39 const c = bar('Z').x;
40 try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' });
41}
42fn bar(comptime x: u8) @This().FooAlias {
43 return .{ .x = x };
44}
45const std = @import("std");
46#expect_stdout="Z\n"