| author | |
| committer | |
| log | f134f4345cf8484b82c46278074eb45af0efaf2e |
| tree | 6d4e30800a3017b2b57d96b342f719add4d4379d |
| parent | f6c5f8b79908d6c1550fe535ceb26d1d8944c197 |
| signature |
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 { |
| 4076 | 4076 | ref = refs.get(r.referencer).?; |
| 4077 | 4077 | } |
| 4078 | 4078 | } |
| 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 | } | |
| 4080 | 4087 | } |
| 4081 | 4088 | }; |
| 4082 | 4089 |
src/IncrementalDebugServer.zig+20-7| ... | ... | @@ -286,21 +286,34 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const |
| 286 | 286 | const referencer = (ref orelse break :ref "<analysis root>").referencer; |
| 287 | 287 | break :ref printAnalUnit(referencer, &ref_str_buf); |
| 288 | 288 | }; |
| 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 | }; | |
| 294 | 289 | try w.print( |
| 295 | 290 | \\last update generation: {d} |
| 296 | 291 | \\current referencer: {s} |
| 297 | \\has error: {s} | |
| 298 | 292 | \\ |
| 299 | 293 | , .{ |
| 300 | 294 | unit_info.last_update_gen, |
| 301 | 295 | ref_str, |
| 302 | has_err, | |
| 303 | 296 | }); |
| 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 | } | |
| 304 | 317 | } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) { |
| 305 | 318 | const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); |
| 306 | 319 | 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( |
| 1472 | 1472 | i += 1; |
| 1473 | 1473 | continue; |
| 1474 | 1474 | }, |
| 1475 | .astgen_error => return error.AnalysisFail, | |
| 1475 | .astgen_error => return sema.failTransitive(.astgen_error), | |
| 1476 | 1476 | .float_op_result_ty => try sema.zirFloatOpResultType(block, extended), |
| 1477 | 1477 | }; |
| 1478 | 1478 | }, |
| ... | ... | @@ -2697,13 +2697,15 @@ fn failWithTypeMismatch(sema: *Sema, block: *Block, src: LazySrcLoc, expected: T |
| 2697 | 2697 | }); |
| 2698 | 2698 | } |
| 2699 | 2699 | |
| 2700 | pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) error{ AnalysisFail, OutOfMemory } { | |
| 2700 | pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) SemaError { | |
| 2701 | 2701 | @branchHint(.cold); |
| 2702 | 2702 | const zcu = sema.pt.zcu; |
| 2703 | 2703 | const comp = zcu.comp; |
| 2704 | 2704 | const gpa = comp.gpa; |
| 2705 | 2705 | const io = comp.io; |
| 2706 | 2706 | |
| 2707 | assert(sema.err == null); | |
| 2708 | ||
| 2707 | 2709 | if (build_options.enable_debug_extensions and comp.debug_compile_errors) { |
| 2708 | 2710 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2709 | 2711 | wip_errors.init(gpa) catch @panic("out of memory"); |
| ... | ... | @@ -2729,17 +2731,11 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg |
| 2729 | 2731 | |
| 2730 | 2732 | err_msg.reference_trace_root = sema.owner.toOptional(); |
| 2731 | 2733 | |
| 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)); | |
| 2741 | 2736 | |
| 2742 | return error.AnalysisFail; | |
| 2737 | sema.err = err_msg; | |
| 2738 | return error.AlreadyReported; | |
| 2743 | 2739 | } |
| 2744 | 2740 | |
| 2745 | 2741 | /// Given an ErrorMsg, modify its message and source location to the given values, turning the |
| ... | ... | @@ -4745,11 +4741,14 @@ fn failWithBadMemberAccess( |
| 4745 | 4741 | .@"enum" => "enum", |
| 4746 | 4742 | else => unreachable, |
| 4747 | 4743 | }; |
| 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 | } | |
| 4753 | 4752 | |
| 4754 | 4753 | return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ |
| 4755 | 4754 | kw_name, agg_ty.fmt(pt), field_name.fmt(ip), |
| ... | ... | @@ -5997,7 +5996,14 @@ fn lookupInNamespace( |
| 5997 | 5996 | const pt = sema.pt; |
| 5998 | 5997 | const zcu = pt.zcu; |
| 5999 | 5998 | |
| 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 | }; | |
| 6001 | 6007 | |
| 6002 | 6008 | const namespace = zcu.namespacePtr(namespace_index); |
| 6003 | 6009 | |
| ... | ... | @@ -6062,7 +6068,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref |
| 6062 | 6068 | const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace); |
| 6063 | 6069 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6064 | 6070 | 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"), | |
| 6066 | 6072 | error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6067 | 6073 | error.OutOfMemory, error.Canceled => |e| return e, |
| 6068 | 6074 | }; |
| ... | ... | @@ -6724,7 +6730,9 @@ fn analyzeCall( |
| 6724 | 6730 | 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: { |
| 6725 | 6731 | const info = ip.indexToKey(f.toIntern()).func; |
| 6726 | 6732 | 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 | }; | |
| 6728 | 6736 | const file = zcu.fileByIndex(resolved_func_inst.file); |
| 6729 | 6737 | const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst); |
| 6730 | 6738 | break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info }; |
| ... | ... | @@ -8355,7 +8363,10 @@ fn zirFunc( |
| 8355 | 8363 | const cc: std.lang.CallingConvention = if (has_body) cc: { |
| 8356 | 8364 | const func_decl_nav = sema.owner.unwrap().nav_val; |
| 8357 | 8365 | 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 | }; | |
| 8359 | 8370 | const zir_decl = sema.code.getDeclaration(decl_inst); |
| 8360 | 8371 | break :exported zir_decl.linkage == .@"export"; |
| 8361 | 8372 | }; |
| ... | ... | @@ -12289,10 +12300,11 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( |
| 12289 | 12300 | dummy_captures, |
| 12290 | 12301 | .{ .override = item_srcs }, |
| 12291 | 12302 | ) 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; | |
| 12296 | 12308 | }, |
| 12297 | 12309 | else => |e| return e, |
| 12298 | 12310 | }; |
| ... | ... | @@ -12328,11 +12340,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( |
| 12328 | 12340 | dummy_captures, |
| 12329 | 12341 | .{ .override = item_srcs }, |
| 12330 | 12342 | ) 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; | |
| 12336 | 12349 | }, |
| 12337 | 12350 | else => |e| return e, |
| 12338 | 12351 | }; |
| ... | ... | @@ -17207,7 +17220,14 @@ fn typeInfoNamespaceDecls( |
| 17207 | 17220 | const ip = &zcu.intern_pool; |
| 17208 | 17221 | |
| 17209 | 17222 | 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 | }; | |
| 17211 | 17231 | const namespace = zcu.namespacePtr(namespace_index); |
| 17212 | 17232 | |
| 17213 | 17233 | const gop = try seen_namespaces.getOrPut(namespace); |
| ... | ... | @@ -17933,11 +17953,12 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 17933 | 17953 | } |
| 17934 | 17954 | // TODO Add compile error for @optimizeFor occurring too late in a scope. |
| 17935 | 17955 | 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; | |
| 17941 | 17962 | }, |
| 17942 | 17963 | else => |e| return e, |
| 17943 | 17964 | }; |
| ... | ... | @@ -18353,11 +18374,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18353 | 18374 | |
| 18354 | 18375 | const elem_ty = blk: { |
| 18355 | 18376 | 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, | |
| 18361 | 18387 | }; |
| 18362 | 18388 | assert(!ty.isGenericPoison()); |
| 18363 | 18389 | break :blk ty; |
| ... | ... | @@ -24909,7 +24935,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24909 | 24935 | } else cc: { |
| 24910 | 24936 | if (has_body) { |
| 24911 | 24937 | 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 | }; | |
| 24913 | 24942 | const zir_decl = sema.code.getDeclaration(func_decl_inst); |
| 24914 | 24943 | if (zir_decl.linkage == .@"export") { |
| 24915 | 24944 | break :cc target.cCallingConvention() orelse { |
| ... | ... | @@ -30642,7 +30671,10 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M |
| 30642 | 30671 | if (pt.zcu.analysis_in_progress.contains(unit)) { |
| 30643 | 30672 | return sema.failWithDependencyLoop(unit, &reason); |
| 30644 | 30673 | } |
| 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 | }; | |
| 30646 | 30678 | } |
| 30647 | 30679 | |
| 30648 | 30680 | pub 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: |
| 30678 | 30710 | switch (kind) { |
| 30679 | 30711 | .type => { |
| 30680 | 30712 | 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, | |
| 30682 | 30721 | }, |
| 30683 | .fully => return pt.ensureNavValUpToDate(nav_index, &reason), | |
| 30684 | 30722 | } |
| 30685 | 30723 | } |
| 30686 | 30724 | |
| ... | ... | @@ -33743,7 +33781,10 @@ fn ensureFuncIesResolved( |
| 33743 | 33781 | return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason); |
| 33744 | 33782 | } |
| 33745 | 33783 | |
| 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 | }; | |
| 33747 | 33788 | } |
| 33748 | 33789 | |
| 33749 | 33790 | pub fn resolveInferredErrorSetPtr( |
| ... | ... | @@ -34962,7 +35003,9 @@ pub fn setTypeName( |
| 34962 | 35003 | }, |
| 34963 | 35004 | .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), |
| 34964 | 35005 | .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 | }); | |
| 34966 | 35009 | const zir_tags = sema.code.instructions.items(.tag); |
| 34967 | 35010 | |
| 34968 | 35011 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| ... | ... | @@ -35078,7 +35121,10 @@ fn zirStructDecl( |
| 35078 | 35121 | }; |
| 35079 | 35122 | |
| 35080 | 35123 | 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 | }; | |
| 35082 | 35128 | |
| 35083 | 35129 | return .fromType(ty); |
| 35084 | 35130 | } |
| ... | ... | @@ -35151,7 +35197,10 @@ fn zirUnionDecl( |
| 35151 | 35197 | }; |
| 35152 | 35198 | |
| 35153 | 35199 | 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 | }; | |
| 35155 | 35204 | |
| 35156 | 35205 | return .fromType(ty); |
| 35157 | 35206 | } |
| ... | ... | @@ -35203,7 +35252,10 @@ fn zirEnumDecl( |
| 35203 | 35252 | }; |
| 35204 | 35253 | |
| 35205 | 35254 | 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 | }; | |
| 35207 | 35259 | |
| 35208 | 35260 | return .fromType(ty); |
| 35209 | 35261 | } |
| ... | ... | @@ -35252,7 +35304,10 @@ fn zirOpaqueDecl( |
| 35252 | 35304 | }; |
| 35253 | 35305 | |
| 35254 | 35306 | 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 | }; | |
| 35256 | 35311 | |
| 35257 | 35312 | return .fromType(ty); |
| 35258 | 35313 | } |
| ... | ... | @@ -35293,5 +35348,31 @@ pub fn failWithDependencyLoop( |
| 35293 | 35348 | } |
| 35294 | 35349 | |
| 35295 | 35350 | // 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. | |
| 35363 | pub 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; | |
| 35297 | 35378 | } |
src/Sema/LowerZon.zig+2-2| ... | ... | @@ -320,7 +320,7 @@ fn failUnsupportedResultType( |
| 320 | 320 | self: *LowerZon, |
| 321 | 321 | ty: Type, |
| 322 | 322 | opt_note: ?[]const u8, |
| 323 | ) error{ AnalysisFail, OutOfMemory } { | |
| 323 | ) Zcu.SemaError { | |
| 324 | 324 | @branchHint(.cold); |
| 325 | 325 | const sema = self.sema; |
| 326 | 326 | const gpa = sema.gpa; |
| ... | ... | @@ -338,7 +338,7 @@ fn fail( |
| 338 | 338 | node: Zoir.Node.Index, |
| 339 | 339 | comptime format: []const u8, |
| 340 | 340 | args: anytype, |
| 341 | ) error{ AnalysisFail, OutOfMemory } { | |
| 341 | ) Zcu.SemaError { | |
| 342 | 342 | @branchHint(.cold); |
| 343 | 343 | const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args); |
| 344 | 344 | 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 |
| 116 | 116 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { |
| 117 | 117 | return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason); |
| 118 | 118 | } |
| 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 | }; | |
| 120 | 123 | }, |
| 121 | 124 | |
| 122 | 125 | // values, not types |
| ... | ... | @@ -166,7 +169,10 @@ pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) Sema |
| 166 | 169 | return sema.failWithDependencyLoop(.wrap(.{ .struct_defaults = ty.toIntern() }), &reason); |
| 167 | 170 | } |
| 168 | 171 | |
| 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 | }; | |
| 170 | 176 | } |
| 171 | 177 | |
| 172 | 178 | /// 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 { |
| 188 | 194 | |
| 189 | 195 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 190 | 196 | 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 | }; | |
| 192 | 200 | |
| 193 | 201 | var block: Block = .{ |
| 194 | 202 | .parent = null, |
| ... | ... | @@ -606,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 606 | 614 | struct_ty.assertHasLayout(zcu); |
| 607 | 615 | const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() }); |
| 608 | 616 | 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 }); | |
| 610 | 618 | } |
| 611 | 619 | |
| 612 | 620 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| ... | ... | @@ -656,7 +664,9 @@ fn resolveStructDefaultsInner( |
| 656 | 664 | assert(struct_obj.field_defaults.len > 0); |
| 657 | 665 | |
| 658 | 666 | // 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 | }; | |
| 660 | 670 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| 661 | 671 | |
| 662 | 672 | const field_types = struct_obj.field_types.get(ip); |
| ... | ... | @@ -713,7 +723,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 713 | 723 | |
| 714 | 724 | const union_obj = ip.loadUnionType(union_ty.toIntern()); |
| 715 | 725 | 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 | }; | |
| 717 | 729 | |
| 718 | 730 | var block: Block = .{ |
| 719 | 731 | .parent = null, |
| ... | ... | @@ -1212,7 +1224,9 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { |
| 1212 | 1224 | }; |
| 1213 | 1225 | |
| 1214 | 1226 | 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 | }; | |
| 1216 | 1230 | |
| 1217 | 1231 | var block: Block = .{ |
| 1218 | 1232 | .parent = null, |
src/Zcu.zig+18-3| ... | ... | @@ -182,7 +182,10 @@ analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason |
| 182 | 182 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. |
| 183 | 183 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, |
| 184 | 184 | /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. |
| 185 | transitive_failed_analysis: std.array_hash_map.Auto(AnalUnit, void) = .empty, | |
| 185 | transitive_failed_analysis: std.array_hash_map.Auto( | |
| 186 | AnalUnit, | |
| 187 | if (build_options.enable_debug_extensions) TransitiveFailureReason else void, | |
| 188 | ) = .empty, | |
| 186 | 189 | /// This `Nav` succeeded analysis, but failed codegen. |
| 187 | 190 | /// This may be a simple "value" `Nav`, or it may be a function. |
| 188 | 191 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. |
| ... | ... | @@ -351,6 +354,18 @@ pub const DependencyReason = struct { |
| 351 | 354 | type_layout_reason: Sema.type_resolution.LayoutResolveReason, |
| 352 | 355 | }; |
| 353 | 356 | |
| 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. | |
| 361 | pub 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 | ||
| 354 | 369 | pub const IncrementalDebugState = struct { |
| 355 | 370 | /// All container types in the ZCU, even dead ones. |
| 356 | 371 | /// Value is the generation the type was created on. |
| ... | ... | @@ -2808,13 +2823,13 @@ pub const LazySrcLoc = struct { |
| 2808 | 2823 | } |
| 2809 | 2824 | }; |
| 2810 | 2825 | |
| 2811 | pub const SemaError = error{ OutOfMemory, Canceled, AnalysisFail }; | |
| 2826 | pub const SemaError = error{ OutOfMemory, Canceled, AlreadyReported }; | |
| 2812 | 2827 | pub const CompileError = error{ |
| 2813 | 2828 | OutOfMemory, |
| 2814 | 2829 | /// The compilation update is no longer desired. |
| 2815 | 2830 | Canceled, |
| 2816 | 2831 | /// When this is returned, the compile error for the failure has already been recorded. |
| 2817 | AnalysisFail, | |
| 2832 | AlreadyReported, | |
| 2818 | 2833 | /// In a comptime scope, a return instruction was encountered. This error is only seen when |
| 2819 | 2834 | /// doing a comptime function call. |
| 2820 | 2835 | ComptimeReturn, |
src/Zcu/PerThread.zig+73-90| ... | ... | @@ -320,7 +320,7 @@ pub fn update( |
| 320 | 320 | // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed, |
| 321 | 321 | // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze. |
| 322 | 322 | while (try zcu.findOutdatedToAnalyze()) |unit| { |
| 323 | const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) { | |
| 323 | const maybe_err: UpdateUnitError!void = switch (unit.unwrap()) { | |
| 324 | 324 | .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), |
| 325 | 325 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null), |
| 326 | 326 | .nav_val => |nav| pt.ensureNavValUpToDate(nav, null), |
| ... | ... | @@ -332,7 +332,7 @@ pub fn update( |
| 332 | 332 | error.Canceled, |
| 333 | 333 | => |e| return e, |
| 334 | 334 | |
| 335 | error.AnalysisFail => {}, // already reported | |
| 335 | error.AnalysisFail => {}, | |
| 336 | 336 | }; |
| 337 | 337 | break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null); |
| 338 | 338 | }, |
| ... | ... | @@ -344,7 +344,7 @@ pub fn update( |
| 344 | 344 | error.Canceled, |
| 345 | 345 | => |e| return e, |
| 346 | 346 | |
| 347 | error.AnalysisFail => {}, // already reported | |
| 347 | error.AnalysisFail => {}, | |
| 348 | 348 | }; |
| 349 | 349 | } |
| 350 | 350 | } |
| ... | ... | @@ -455,7 +455,7 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc |
| 455 | 455 | |
| 456 | 456 | /// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs |
| 457 | 457 | /// 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. | |
| 459 | 459 | pub fn updateFile( |
| 460 | 460 | pt: Zcu.PerThread, |
| 461 | 461 | file_index: Zcu.File.Index, |
| ... | ... | @@ -1036,6 +1036,11 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc |
| 1036 | 1036 | zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index)); |
| 1037 | 1037 | } |
| 1038 | 1038 | |
| 1039 | const UpdateUnitError = Allocator.Error || Io.Cancelable || error{ | |
| 1040 | /// Semantic analysis of this `AnalUnit` failed. | |
| 1041 | AnalysisFail, | |
| 1042 | }; | |
| 1043 | ||
| 1039 | 1044 | /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. |
| 1040 | 1045 | /// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore |
| 1041 | 1046 | /// this, since the error is already registered, but it must not use the value of memoized fields. |
| ... | ... | @@ -1044,7 +1049,7 @@ pub fn ensureMemoizedStateUpToDate( |
| 1044 | 1049 | stage: InternPool.MemoizedStateStage, |
| 1045 | 1050 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1046 | 1051 | reason: ?*const Zcu.DependencyReason, |
| 1047 | ) Zcu.SemaError!void { | |
| 1052 | ) UpdateUnitError!void { | |
| 1048 | 1053 | const zcu = pt.zcu; |
| 1049 | 1054 | const gpa = zcu.gpa; |
| 1050 | 1055 | |
| ... | ... | @@ -1078,15 +1083,7 @@ pub fn ensureMemoizedStateUpToDate( |
| 1078 | 1083 | const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed| |
| 1079 | 1084 | .{ any_changed or prev_failed, false } |
| 1080 | 1085 | 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 }, | |
| 1090 | 1087 | error.OutOfMemory => { |
| 1091 | 1088 | // TODO: same as for `ensureComptimeUnitUpToDate` etc |
| 1092 | 1089 | return error.OutOfMemory; |
| ... | ... | @@ -1154,7 +1151,7 @@ fn analyzeMemoizedState( |
| 1154 | 1151 | /// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis |
| 1155 | 1152 | /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is |
| 1156 | 1153 | /// free to ignore this, since the error is already registered. |
| 1157 | pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void { | |
| 1154 | pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) UpdateUnitError!void { | |
| 1158 | 1155 | const zcu = pt.zcu; |
| 1159 | 1156 | const gpa = zcu.gpa; |
| 1160 | 1157 | |
| ... | ... | @@ -1195,15 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 1195 | 1192 | defer unit_tracking.end(zcu); |
| 1196 | 1193 | |
| 1197 | 1194 | 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, | |
| 1207 | 1196 | error.OutOfMemory => { |
| 1208 | 1197 | // TODO: it's unclear how to gracefully handle this. |
| 1209 | 1198 | // 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 |
| 1221 | 1210 | |
| 1222 | 1211 | /// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old |
| 1223 | 1212 | /// 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`. | |
| 1226 | 1214 | fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void { |
| 1227 | 1215 | const zcu = pt.zcu; |
| 1228 | 1216 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -1239,7 +1227,14 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu |
| 1239 | 1227 | defer tracy_trace.end(); |
| 1240 | 1228 | tracy_trace.addTextFmt("cu_id={d}", .{cu_id}); |
| 1241 | 1229 | |
| 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 | }; | |
| 1243 | 1238 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1244 | 1239 | const zir = file.zir.?; |
| 1245 | 1240 | |
| ... | ... | @@ -1314,7 +1309,7 @@ pub fn ensureTypeLayoutUpToDate( |
| 1314 | 1309 | ty: Type, |
| 1315 | 1310 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1316 | 1311 | reason: ?*const Zcu.DependencyReason, |
| 1317 | ) Zcu.SemaError!void { | |
| 1312 | ) UpdateUnitError!void { | |
| 1318 | 1313 | const zcu = pt.zcu; |
| 1319 | 1314 | const ip = &zcu.intern_pool; |
| 1320 | 1315 | const comp = zcu.comp; |
| ... | ... | @@ -1399,15 +1394,7 @@ pub fn ensureTypeLayoutUpToDate( |
| 1399 | 1394 | const new_failed: bool = if (result) failed: { |
| 1400 | 1395 | break :failed false; |
| 1401 | 1396 | } 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, | |
| 1411 | 1398 | error.OutOfMemory, |
| 1412 | 1399 | error.Canceled, |
| 1413 | 1400 | => |e| return e, |
| ... | ... | @@ -1442,7 +1429,7 @@ pub fn ensureStructDefaultsUpToDate( |
| 1442 | 1429 | ty: Type, |
| 1443 | 1430 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1444 | 1431 | reason: ?*const Zcu.DependencyReason, |
| 1445 | ) Zcu.SemaError!void { | |
| 1432 | ) UpdateUnitError!void { | |
| 1446 | 1433 | const zcu = pt.zcu; |
| 1447 | 1434 | const ip = &zcu.intern_pool; |
| 1448 | 1435 | const comp = zcu.comp; |
| ... | ... | @@ -1513,15 +1500,7 @@ pub fn ensureStructDefaultsUpToDate( |
| 1513 | 1500 | const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: { |
| 1514 | 1501 | break :failed false; |
| 1515 | 1502 | } 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, | |
| 1525 | 1504 | error.OutOfMemory, |
| 1526 | 1505 | error.Canceled, |
| 1527 | 1506 | => |e| return e, |
| ... | ... | @@ -1547,7 +1526,7 @@ pub fn ensureNavValUpToDate( |
| 1547 | 1526 | nav_id: InternPool.Nav.Index, |
| 1548 | 1527 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1549 | 1528 | reason: ?*const Zcu.DependencyReason, |
| 1550 | ) Zcu.SemaError!void { | |
| 1529 | ) UpdateUnitError!void { | |
| 1551 | 1530 | const zcu = pt.zcu; |
| 1552 | 1531 | const gpa = zcu.gpa; |
| 1553 | 1532 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -1594,15 +1573,7 @@ pub fn ensureNavValUpToDate( |
| 1594 | 1573 | false, |
| 1595 | 1574 | }; |
| 1596 | 1575 | } 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 }, | |
| 1606 | 1577 | error.OutOfMemory => { |
| 1607 | 1578 | // TODO: it's unclear how to gracefully handle this. |
| 1608 | 1579 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | ... | @@ -1655,7 +1626,14 @@ fn analyzeNavVal( |
| 1655 | 1626 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); |
| 1656 | 1627 | tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); |
| 1657 | 1628 | |
| 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 | }; | |
| 1659 | 1637 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1660 | 1638 | const zir = file.zir.?; |
| 1661 | 1639 | const zir_decl = zir.getDeclaration(inst_resolved.inst); |
| ... | ... | @@ -1916,7 +1894,7 @@ pub fn ensureNavTypeUpToDate( |
| 1916 | 1894 | nav_id: InternPool.Nav.Index, |
| 1917 | 1895 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1918 | 1896 | reason: ?*const Zcu.DependencyReason, |
| 1919 | ) Zcu.SemaError!void { | |
| 1897 | ) UpdateUnitError!void { | |
| 1920 | 1898 | const zcu = pt.zcu; |
| 1921 | 1899 | const gpa = zcu.gpa; |
| 1922 | 1900 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -1963,15 +1941,7 @@ pub fn ensureNavTypeUpToDate( |
| 1963 | 1941 | false, |
| 1964 | 1942 | }; |
| 1965 | 1943 | } 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 }, | |
| 1975 | 1945 | error.OutOfMemory => { |
| 1976 | 1946 | // TODO: it's unclear how to gracefully handle this. |
| 1977 | 1947 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | ... | @@ -2024,7 +1994,14 @@ fn analyzeNavType( |
| 2024 | 1994 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); |
| 2025 | 1995 | tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); |
| 2026 | 1996 | |
| 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 | }; | |
| 2028 | 2005 | const file = zcu.fileByIndex(inst_resolved.file); |
| 2029 | 2006 | const zir = file.zir.?; |
| 2030 | 2007 | |
| ... | ... | @@ -2160,7 +2137,7 @@ pub fn ensureFuncBodyUpToDate( |
| 2160 | 2137 | func_index: InternPool.Index, |
| 2161 | 2138 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 2162 | 2139 | reason: ?*const Zcu.DependencyReason, |
| 2163 | ) Zcu.SemaError!void { | |
| 2140 | ) UpdateUnitError!void { | |
| 2164 | 2141 | dev.check(.sema); |
| 2165 | 2142 | |
| 2166 | 2143 | const zcu = pt.zcu; |
| ... | ... | @@ -2204,18 +2181,10 @@ pub fn ensureFuncBodyUpToDate( |
| 2204 | 2181 | const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result| |
| 2205 | 2182 | .{ prev_failed or result.ies_outdated, false } |
| 2206 | 2183 | 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 }, | |
| 2219 | 2188 | error.OutOfMemory => { |
| 2220 | 2189 | // TODO: it's unclear how to gracefully handle this. |
| 2221 | 2190 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | ... | @@ -3306,15 +3275,21 @@ fn analyzeFuncBodyInner( |
| 3306 | 3275 | // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary. |
| 3307 | 3276 | |
| 3308 | 3277 | 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 | }; | |
| 3310 | 3282 | if (ip.getNav(func.owner_nav).resolved.?.value != func_index) { |
| 3311 | return error.AnalysisFail; | |
| 3283 | return sema.failTransitive(.{ .func_nav_val_changed = func_index }); | |
| 3312 | 3284 | } |
| 3313 | 3285 | } else { |
| 3314 | 3286 | 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 | }; | |
| 3316 | 3291 | 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 }); | |
| 3318 | 3293 | } |
| 3319 | 3294 | } |
| 3320 | 3295 | |
| ... | ... | @@ -3344,7 +3319,9 @@ fn analyzeFuncBodyInner( |
| 3344 | 3319 | }; |
| 3345 | 3320 | defer inner_block.instructions.deinit(gpa); |
| 3346 | 3321 | |
| 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 | }); | |
| 3348 | 3325 | |
| 3349 | 3326 | // Here we are performing "runtime semantic analysis" for a function body, which means |
| 3350 | 3327 | // 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 | |
| 4378 | 4355 | return result.index; |
| 4379 | 4356 | } |
| 4380 | 4357 | |
| 4358 | const 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 | ||
| 4381 | 4364 | /// Given a namespace, re-scan its declarations from the type definition if they have not |
| 4382 | 4365 | /// 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`. | |
| 4384 | 4367 | /// This will effectively short-circuit the caller, which will be semantic analysis of a |
| 4385 | 4368 | /// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error. |
| 4386 | pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void { | |
| 4369 | pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) UpdateNamespaceError!void { | |
| 4387 | 4370 | const zcu = pt.zcu; |
| 4388 | 4371 | const ip = &zcu.intern_pool; |
| 4389 | 4372 | const namespace = zcu.namespacePtr(namespace_index); |
| ... | ... | @@ -4410,7 +4393,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4410 | 4393 | |
| 4411 | 4394 | // Namespace outdated -- re-scan the type if necessary. |
| 4412 | 4395 | |
| 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; | |
| 4414 | 4397 | const file = zcu.fileByIndex(inst_info.file); |
| 4415 | 4398 | const zir = &file.zir.?; |
| 4416 | 4399 |