| 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,7 +4076,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 4076 | ref = refs.get(r.referencer).?; | 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,21 +286,34 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const |
| 286 | const referencer = (ref orelse break :ref "<analysis root>").referencer; | 286 | const referencer = (ref orelse break :ref "<analysis root>").referencer; |
| 287 | break :ref printAnalUnit(referencer, &ref_str_buf); | 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 | try w.print( | 289 | try w.print( |
| 295 | \\last update generation: {d} | 290 | \\last update generation: {d} |
| 296 | \\current referencer: {s} | 291 | \\current referencer: {s} |
| 297 | \\has error: {s} | ||
| 298 | \\ | 292 | \\ |
| 299 | , .{ | 293 | , .{ |
| 300 | unit_info.last_update_gen, | 294 | unit_info.last_update_gen, |
| 301 | ref_str, | 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 | } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) { | 317 | } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) { |
| 305 | const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); | 318 | const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); |
| 306 | const unit_info = zcu.incremental_debug_state.units.get(unit) orelse return w.writeAll("unknown anal unit"); | 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,7 +1472,7 @@ fn analyzeBodyInner( |
| 1472 | i += 1; | 1472 | i += 1; |
| 1473 | continue; | 1473 | continue; |
| 1474 | }, | 1474 | }, |
| 1475 | .astgen_error => return error.AnalysisFail, | 1475 | .astgen_error => return sema.failTransitive(.astgen_error), |
| 1476 | .float_op_result_ty => try sema.zirFloatOpResultType(block, extended), | 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,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 | @branchHint(.cold); | 2701 | @branchHint(.cold); |
| 2702 | const zcu = sema.pt.zcu; | 2702 | const zcu = sema.pt.zcu; |
| 2703 | const comp = zcu.comp; | 2703 | const comp = zcu.comp; |
| 2704 | const gpa = comp.gpa; | 2704 | const gpa = comp.gpa; |
| 2705 | const io = comp.io; | 2705 | const io = comp.io; |
| 2706 | 2706 | ||
| 2707 | assert(sema.err == null); | ||
| 2708 | |||
| 2707 | if (build_options.enable_debug_extensions and comp.debug_compile_errors) { | 2709 | if (build_options.enable_debug_extensions and comp.debug_compile_errors) { |
| 2708 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; | 2710 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2709 | wip_errors.init(gpa) catch @panic("out of memory"); | 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,17 +2731,11 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg |
| 2729 | 2731 | ||
| 2730 | err_msg.reference_trace_root = sema.owner.toOptional(); | 2732 | err_msg.reference_trace_root = sema.owner.toOptional(); |
| 2731 | 2733 | ||
| 2732 | const gop = try zcu.failed_analysis.getOrPut(gpa, sema.owner); | 2734 | try zcu.failed_analysis.putNoClobber(gpa, sema.owner, err_msg); |
| 2733 | if (gop.found_existing) { | 2735 | assert(!zcu.transitive_failed_analysis.contains(sema.owner)); |
| 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 | } | ||
| 2741 | 2736 | ||
| 2742 | return error.AnalysisFail; | 2737 | sema.err = err_msg; |
| 2738 | return error.AlreadyReported; | ||
| 2743 | } | 2739 | } |
| 2744 | 2740 | ||
| 2745 | /// Given an ErrorMsg, modify its message and source location to the given values, turning the | 2741 | /// Given an ErrorMsg, modify its message and source location to the given values, turning the |
| ... | @@ -4745,11 +4741,14 @@ fn failWithBadMemberAccess( | ... | @@ -4745,11 +4741,14 @@ fn failWithBadMemberAccess( |
| 4745 | .@"enum" => "enum", | 4741 | .@"enum" => "enum", |
| 4746 | else => unreachable, | 4742 | else => unreachable, |
| 4747 | }; | 4743 | }; |
| 4748 | if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) { | 4744 | if (agg_ty.typeDeclInst(zcu)) |inst| { |
| 4749 | return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ | 4745 | const inst_index = inst.resolve(ip) orelse return sema.failTransitive(.{ .lost_tracking = inst }); |
| 4750 | agg_ty.fmt(pt), field_name.fmt(ip), | 4746 | if (inst_index == .main_struct_inst) { |
| 4751 | }); | 4747 | return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ |
| 4752 | }; | 4748 | agg_ty.fmt(pt), field_name.fmt(ip), |
| 4749 | }); | ||
| 4750 | } | ||
| 4751 | } | ||
| 4753 | 4752 | ||
| 4754 | return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ | 4753 | return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ |
| 4755 | kw_name, agg_ty.fmt(pt), field_name.fmt(ip), | 4754 | kw_name, agg_ty.fmt(pt), field_name.fmt(ip), |
| ... | @@ -5997,7 +5996,14 @@ fn lookupInNamespace( | ... | @@ -5997,7 +5996,14 @@ fn lookupInNamespace( |
| 5997 | const pt = sema.pt; | 5996 | const pt = sema.pt; |
| 5998 | const zcu = pt.zcu; | 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 | const namespace = zcu.namespacePtr(namespace_index); | 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,7 +6068,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref |
| 6062 | const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace); | 6068 | const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace); |
| 6063 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); | 6069 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6064 | const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { | 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 | error.ComptimeReturn, error.ComptimeBreak => unreachable, | 6072 | error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6067 | error.OutOfMemory, error.Canceled => |e| return e, | 6073 | error.OutOfMemory, error.Canceled => |e| return e, |
| 6068 | }; | 6074 | }; |
| ... | @@ -6724,7 +6730,9 @@ fn analyzeCall( | ... | @@ -6724,7 +6730,9 @@ fn analyzeCall( |
| 6724 | 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: { | 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 | const info = ip.indexToKey(f.toIntern()).func; | 6731 | const info = ip.indexToKey(f.toIntern()).func; |
| 6726 | const nav = ip.getNav(info.owner_nav); | 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 | const file = zcu.fileByIndex(resolved_func_inst.file); | 6736 | const file = zcu.fileByIndex(resolved_func_inst.file); |
| 6729 | const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst); | 6737 | const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst); |
| 6730 | break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info }; | 6738 | break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info }; |
| ... | @@ -8355,7 +8363,10 @@ fn zirFunc( | ... | @@ -8355,7 +8363,10 @@ fn zirFunc( |
| 8355 | const cc: std.lang.CallingConvention = if (has_body) cc: { | 8363 | const cc: std.lang.CallingConvention = if (has_body) cc: { |
| 8356 | const func_decl_nav = sema.owner.unwrap().nav_val; | 8364 | const func_decl_nav = sema.owner.unwrap().nav_val; |
| 8357 | const fn_is_exported = exported: { | 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 | const zir_decl = sema.code.getDeclaration(decl_inst); | 8370 | const zir_decl = sema.code.getDeclaration(decl_inst); |
| 8360 | break :exported zir_decl.linkage == .@"export"; | 8371 | break :exported zir_decl.linkage == .@"export"; |
| 8361 | }; | 8372 | }; |
| ... | @@ -12289,10 +12300,11 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( | ... | @@ -12289,10 +12300,11 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( |
| 12289 | dummy_captures, | 12300 | dummy_captures, |
| 12290 | .{ .override = item_srcs }, | 12301 | .{ .override = item_srcs }, |
| 12291 | ) catch |err| switch (err) { | 12302 | ) catch |err| switch (err) { |
| 12292 | error.AnalysisFail => { | 12303 | error.AlreadyReported => |e| { |
| 12293 | const msg = sema.err orelse return error.AnalysisFail; | 12304 | if (sema.err) |msg| { |
| 12294 | try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); | 12305 | try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); |
| 12295 | return error.AnalysisFail; | 12306 | } |
| 12307 | return e; | ||
| 12296 | }, | 12308 | }, |
| 12297 | else => |e| return e, | 12309 | else => |e| return e, |
| 12298 | }; | 12310 | }; |
| ... | @@ -12328,11 +12340,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( | ... | @@ -12328,11 +12340,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( |
| 12328 | dummy_captures, | 12340 | dummy_captures, |
| 12329 | .{ .override = item_srcs }, | 12341 | .{ .override = item_srcs }, |
| 12330 | ) catch |err| switch (err) { | 12342 | ) catch |err| switch (err) { |
| 12331 | error.AnalysisFail => { | 12343 | error.AlreadyReported => |e| { |
| 12332 | const msg = sema.err orelse return error.AnalysisFail; | 12344 | if (sema.err) |msg| { |
| 12333 | try sema.errNote(capture_src, msg, "this coercion is only possible when capturing by value", .{}); | 12345 | 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", .{}); | 12346 | try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); |
| 12335 | return error.AnalysisFail; | 12347 | } |
| 12348 | return e; | ||
| 12336 | }, | 12349 | }, |
| 12337 | else => |e| return e, | 12350 | else => |e| return e, |
| 12338 | }; | 12351 | }; |
| ... | @@ -17207,7 +17220,14 @@ fn typeInfoNamespaceDecls( | ... | @@ -17207,7 +17220,14 @@ fn typeInfoNamespaceDecls( |
| 17207 | const ip = &zcu.intern_pool; | 17220 | const ip = &zcu.intern_pool; |
| 17208 | 17221 | ||
| 17209 | const namespace_index = opt_namespace_index.unwrap() orelse return; | 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 | const namespace = zcu.namespacePtr(namespace_index); | 17231 | const namespace = zcu.namespacePtr(namespace_index); |
| 17212 | 17232 | ||
| 17213 | const gop = try seen_namespaces.getOrPut(namespace); | 17233 | const gop = try seen_namespaces.getOrPut(namespace); |
| ... | @@ -17933,11 +17953,12 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -17933,11 +17953,12 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 17933 | } | 17953 | } |
| 17934 | // TODO Add compile error for @optimizeFor occurring too late in a scope. | 17954 | // TODO Add compile error for @optimizeFor occurring too late in a scope. |
| 17935 | sema.analyzeUnreachable(block, src, true) catch |err| switch (err) { | 17955 | sema.analyzeUnreachable(block, src, true) catch |err| switch (err) { |
| 17936 | error.AnalysisFail => { | 17956 | error.AlreadyReported => |e| { |
| 17937 | const msg = sema.err orelse return err; | 17957 | if (sema.err) |msg| { |
| 17938 | if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err; | 17958 | 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", .{}); | 17959 | try sema.errNote(src, msg, "the end of a naked function is implicitly unreachable", .{}); |
| 17940 | return err; | 17960 | } |
| 17961 | return e; | ||
| 17941 | }, | 17962 | }, |
| 17942 | else => |e| return e, | 17963 | else => |e| return e, |
| 17943 | }; | 17964 | }; |
| ... | @@ -18353,11 +18374,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18353,11 +18374,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18353 | 18374 | ||
| 18354 | const elem_ty = blk: { | 18375 | const elem_ty = blk: { |
| 18355 | const air_inst = sema.resolveInst(extra.data.elem_type); | 18376 | const air_inst = sema.resolveInst(extra.data.elem_type); |
| 18356 | const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| { | 18377 | const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| switch (err) { |
| 18357 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) { | 18378 | error.AlreadyReported => |e| { |
| 18358 | try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); | 18379 | if (sema.err) |msg| { |
| 18359 | } | 18380 | if (sema.typeOf(air_inst).isSinglePointer(zcu)) { |
| 18360 | return err; | 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 | assert(!ty.isGenericPoison()); | 18388 | assert(!ty.isGenericPoison()); |
| 18363 | break :blk ty; | 18389 | break :blk ty; |
| ... | @@ -24909,7 +24935,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -24909,7 +24935,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24909 | } else cc: { | 24935 | } else cc: { |
| 24910 | if (has_body) { | 24936 | if (has_body) { |
| 24911 | const func_decl_nav = sema.owner.unwrap().nav_val; | 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 | const zir_decl = sema.code.getDeclaration(func_decl_inst); | 24942 | const zir_decl = sema.code.getDeclaration(func_decl_inst); |
| 24914 | if (zir_decl.linkage == .@"export") { | 24943 | if (zir_decl.linkage == .@"export") { |
| 24915 | break :cc target.cCallingConvention() orelse { | 24944 | break :cc target.cCallingConvention() orelse { |
| ... | @@ -30642,7 +30671,10 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M | ... | @@ -30642,7 +30671,10 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M |
| 30642 | if (pt.zcu.analysis_in_progress.contains(unit)) { | 30671 | if (pt.zcu.analysis_in_progress.contains(unit)) { |
| 30643 | return sema.failWithDependencyLoop(unit, &reason); | 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 | pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { | 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,9 +30710,15 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: |
| 30678 | switch (kind) { | 30710 | switch (kind) { |
| 30679 | .type => { | 30711 | .type => { |
| 30680 | try zcu.ensureNavValAnalysisQueued(nav_index); | 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,7 +33781,10 @@ fn ensureFuncIesResolved( |
| 33743 | return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason); | 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 | pub fn resolveInferredErrorSetPtr( | 33790 | pub fn resolveInferredErrorSetPtr( |
| ... | @@ -34962,7 +35003,9 @@ pub fn setTypeName( | ... | @@ -34962,7 +35003,9 @@ pub fn setTypeName( |
| 34962 | }, | 35003 | }, |
| 34963 | .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), | 35004 | .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), |
| 34964 | .func => { | 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 | const zir_tags = sema.code.instructions.items(.tag); | 35009 | const zir_tags = sema.code.instructions.items(.tag); |
| 34967 | 35010 | ||
| 34968 | var aw: std.Io.Writer.Allocating = .init(gpa); | 35011 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| ... | @@ -35078,7 +35121,10 @@ fn zirStructDecl( | ... | @@ -35078,7 +35121,10 @@ fn zirStructDecl( |
| 35078 | }; | 35121 | }; |
| 35079 | 35122 | ||
| 35080 | try sema.addTypeReferenceEntry(src, ty); | 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 | return .fromType(ty); | 35129 | return .fromType(ty); |
| 35084 | } | 35130 | } |
| ... | @@ -35151,7 +35197,10 @@ fn zirUnionDecl( | ... | @@ -35151,7 +35197,10 @@ fn zirUnionDecl( |
| 35151 | }; | 35197 | }; |
| 35152 | 35198 | ||
| 35153 | try sema.addTypeReferenceEntry(src, ty); | 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 | return .fromType(ty); | 35205 | return .fromType(ty); |
| 35157 | } | 35206 | } |
| ... | @@ -35203,7 +35252,10 @@ fn zirEnumDecl( | ... | @@ -35203,7 +35252,10 @@ fn zirEnumDecl( |
| 35203 | }; | 35252 | }; |
| 35204 | 35253 | ||
| 35205 | try sema.addTypeReferenceEntry(src, ty); | 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 | return .fromType(ty); | 35260 | return .fromType(ty); |
| 35209 | } | 35261 | } |
| ... | @@ -35252,7 +35304,10 @@ fn zirOpaqueDecl( | ... | @@ -35252,7 +35304,10 @@ fn zirOpaqueDecl( |
| 35252 | }; | 35304 | }; |
| 35253 | 35305 | ||
| 35254 | try sema.addTypeReferenceEntry(src, ty); | 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 | return .fromType(ty); | 35312 | return .fromType(ty); |
| 35258 | } | 35313 | } |
| ... | @@ -35293,5 +35348,31 @@ pub fn failWithDependencyLoop( | ... | @@ -35293,5 +35348,31 @@ pub fn failWithDependencyLoop( |
| 35293 | } | 35348 | } |
| 35294 | 35349 | ||
| 35295 | // A dependency loop error will be reported. Mark us all as transitive failures. | 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,7 +320,7 @@ fn failUnsupportedResultType( |
| 320 | self: *LowerZon, | 320 | self: *LowerZon, |
| 321 | ty: Type, | 321 | ty: Type, |
| 322 | opt_note: ?[]const u8, | 322 | opt_note: ?[]const u8, |
| 323 | ) error{ AnalysisFail, OutOfMemory } { | 323 | ) Zcu.SemaError { |
| 324 | @branchHint(.cold); | 324 | @branchHint(.cold); |
| 325 | const sema = self.sema; | 325 | const sema = self.sema; |
| 326 | const gpa = sema.gpa; | 326 | const gpa = sema.gpa; |
| ... | @@ -338,7 +338,7 @@ fn fail( | ... | @@ -338,7 +338,7 @@ fn fail( |
| 338 | node: Zoir.Node.Index, | 338 | node: Zoir.Node.Index, |
| 339 | comptime format: []const u8, | 339 | comptime format: []const u8, |
| 340 | args: anytype, | 340 | args: anytype, |
| 341 | ) error{ AnalysisFail, OutOfMemory } { | 341 | ) Zcu.SemaError { |
| 342 | @branchHint(.cold); | 342 | @branchHint(.cold); |
| 343 | const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args); | 343 | const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args); |
| 344 | try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{}); | 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,7 +116,10 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons |
| 116 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { | 116 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { |
| 117 | return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason); | 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 | // values, not types | 125 | // values, not types |
| ... | @@ -166,7 +169,10 @@ pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) Sema | ... | @@ -166,7 +169,10 @@ pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) Sema |
| 166 | return sema.failWithDependencyLoop(.wrap(.{ .struct_defaults = ty.toIntern() }), &reason); | 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 | /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. | 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,7 +194,9 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 188 | 194 | ||
| 189 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | 195 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 190 | assert(struct_obj.want_layout); | 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 | var block: Block = .{ | 201 | var block: Block = .{ |
| 194 | .parent = null, | 202 | .parent = null, |
| ... | @@ -606,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -606,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 606 | struct_ty.assertHasLayout(zcu); | 614 | struct_ty.assertHasLayout(zcu); |
| 607 | const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() }); | 615 | const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() }); |
| 608 | if (zcu.failed_analysis.contains(layout_unit) or zcu.transitive_failed_analysis.contains(layout_unit)) { | 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 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | 620 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| ... | @@ -656,7 +664,9 @@ fn resolveStructDefaultsInner( | ... | @@ -656,7 +664,9 @@ fn resolveStructDefaultsInner( |
| 656 | assert(struct_obj.field_defaults.len > 0); | 664 | assert(struct_obj.field_defaults.len > 0); |
| 657 | 665 | ||
| 658 | // We'll need to map the struct decl instruction to provide result types | 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 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); | 670 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| 661 | 671 | ||
| 662 | const field_types = struct_obj.field_types.get(ip); | 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,7 +723,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 713 | 723 | ||
| 714 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | 724 | const union_obj = ip.loadUnionType(union_ty.toIntern()); |
| 715 | assert(union_obj.want_layout); | 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 | var block: Block = .{ | 730 | var block: Block = .{ |
| 719 | .parent = null, | 731 | .parent = null, |
| ... | @@ -1212,7 +1224,9 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -1212,7 +1224,9 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { |
| 1212 | }; | 1224 | }; |
| 1213 | 1225 | ||
| 1214 | const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; | 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 | var block: Block = .{ | 1231 | var block: Block = .{ |
| 1218 | .parent = null, | 1232 | .parent = null, |
src/Zcu.zig+18-3| ... | @@ -182,7 +182,10 @@ analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason | ... | @@ -182,7 +182,10 @@ analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason |
| 182 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | 182 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. |
| 183 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, | 183 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, |
| 184 | /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. | 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 | /// This `Nav` succeeded analysis, but failed codegen. | 189 | /// This `Nav` succeeded analysis, but failed codegen. |
| 187 | /// This may be a simple "value" `Nav`, or it may be a function. | 190 | /// This may be a simple "value" `Nav`, or it may be a function. |
| 188 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | 191 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. |
| ... | @@ -351,6 +354,18 @@ pub const DependencyReason = struct { | ... | @@ -351,6 +354,18 @@ pub const DependencyReason = struct { |
| 351 | type_layout_reason: Sema.type_resolution.LayoutResolveReason, | 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 | pub const IncrementalDebugState = struct { | 369 | pub const IncrementalDebugState = struct { |
| 355 | /// All container types in the ZCU, even dead ones. | 370 | /// All container types in the ZCU, even dead ones. |
| 356 | /// Value is the generation the type was created on. | 371 | /// Value is the generation the type was created on. |
| ... | @@ -2808,13 +2823,13 @@ pub const LazySrcLoc = struct { | ... | @@ -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 | pub const CompileError = error{ | 2827 | pub const CompileError = error{ |
| 2813 | OutOfMemory, | 2828 | OutOfMemory, |
| 2814 | /// The compilation update is no longer desired. | 2829 | /// The compilation update is no longer desired. |
| 2815 | Canceled, | 2830 | Canceled, |
| 2816 | /// When this is returned, the compile error for the failure has already been recorded. | 2831 | /// When this is returned, the compile error for the failure has already been recorded. |
| 2817 | AnalysisFail, | 2832 | AlreadyReported, |
| 2818 | /// In a comptime scope, a return instruction was encountered. This error is only seen when | 2833 | /// In a comptime scope, a return instruction was encountered. This error is only seen when |
| 2819 | /// doing a comptime function call. | 2834 | /// doing a comptime function call. |
| 2820 | ComptimeReturn, | 2835 | ComptimeReturn, |
src/Zcu/PerThread.zig+73-90| ... | @@ -320,7 +320,7 @@ pub fn update( | ... | @@ -320,7 +320,7 @@ pub fn update( |
| 320 | // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed, | 320 | // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed, |
| 321 | // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze. | 321 | // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze. |
| 322 | while (try zcu.findOutdatedToAnalyze()) |unit| { | 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 | .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), | 324 | .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), |
| 325 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null), | 325 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null), |
| 326 | .nav_val => |nav| pt.ensureNavValUpToDate(nav, null), | 326 | .nav_val => |nav| pt.ensureNavValUpToDate(nav, null), |
| ... | @@ -332,7 +332,7 @@ pub fn update( | ... | @@ -332,7 +332,7 @@ pub fn update( |
| 332 | error.Canceled, | 332 | error.Canceled, |
| 333 | => |e| return e, | 333 | => |e| return e, |
| 334 | 334 | ||
| 335 | error.AnalysisFail => {}, // already reported | 335 | error.AnalysisFail => {}, |
| 336 | }; | 336 | }; |
| 337 | break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null); | 337 | break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null); |
| 338 | }, | 338 | }, |
| ... | @@ -344,7 +344,7 @@ pub fn update( | ... | @@ -344,7 +344,7 @@ pub fn update( |
| 344 | error.Canceled, | 344 | error.Canceled, |
| 345 | => |e| return e, | 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,7 +455,7 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc |
| 455 | 455 | ||
| 456 | /// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs | 456 | /// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs |
| 457 | /// AstGen as needed. Also updates `file.status`. Does not assume that `file.mod` | 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 | pub fn updateFile( | 459 | pub fn updateFile( |
| 460 | pt: Zcu.PerThread, | 460 | pt: Zcu.PerThread, |
| 461 | file_index: Zcu.File.Index, | 461 | file_index: Zcu.File.Index, |
| ... | @@ -1036,6 +1036,11 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc | ... | @@ -1036,6 +1036,11 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc |
| 1036 | zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index)); | 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 | /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. | 1044 | /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. |
| 1040 | /// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore | 1045 | /// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore |
| 1041 | /// this, since the error is already registered, but it must not use the value of memoized fields. | 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,7 +1049,7 @@ pub fn ensureMemoizedStateUpToDate( |
| 1044 | stage: InternPool.MemoizedStateStage, | 1049 | stage: InternPool.MemoizedStateStage, |
| 1045 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 1050 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1046 | reason: ?*const Zcu.DependencyReason, | 1051 | reason: ?*const Zcu.DependencyReason, |
| 1047 | ) Zcu.SemaError!void { | 1052 | ) UpdateUnitError!void { |
| 1048 | const zcu = pt.zcu; | 1053 | const zcu = pt.zcu; |
| 1049 | const gpa = zcu.gpa; | 1054 | const gpa = zcu.gpa; |
| 1050 | 1055 | ||
| ... | @@ -1078,15 +1083,7 @@ pub fn ensureMemoizedStateUpToDate( | ... | @@ -1078,15 +1083,7 @@ pub fn ensureMemoizedStateUpToDate( |
| 1078 | const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed| | 1083 | const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed| |
| 1079 | .{ any_changed or prev_failed, false } | 1084 | .{ any_changed or prev_failed, false } |
| 1080 | else |err| switch (err) { | 1085 | else |err| switch (err) { |
| 1081 | error.AnalysisFail => res: { | 1086 | error.AlreadyReported => .{ !prev_failed, true }, |
| 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 | }, | ||
| 1090 | error.OutOfMemory => { | 1087 | error.OutOfMemory => { |
| 1091 | // TODO: same as for `ensureComptimeUnitUpToDate` etc | 1088 | // TODO: same as for `ensureComptimeUnitUpToDate` etc |
| 1092 | return error.OutOfMemory; | 1089 | return error.OutOfMemory; |
| ... | @@ -1154,7 +1151,7 @@ fn analyzeMemoizedState( | ... | @@ -1154,7 +1151,7 @@ fn analyzeMemoizedState( |
| 1154 | /// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis | 1151 | /// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis |
| 1155 | /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is | 1152 | /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is |
| 1156 | /// free to ignore this, since the error is already registered. | 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 | const zcu = pt.zcu; | 1155 | const zcu = pt.zcu; |
| 1159 | const gpa = zcu.gpa; | 1156 | const gpa = zcu.gpa; |
| 1160 | 1157 | ||
| ... | @@ -1195,15 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU | ... | @@ -1195,15 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 1195 | defer unit_tracking.end(zcu); | 1192 | defer unit_tracking.end(zcu); |
| 1196 | 1193 | ||
| 1197 | return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) { | 1194 | return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) { |
| 1198 | error.AnalysisFail => { | 1195 | error.AlreadyReported => return 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 | }, | ||
| 1207 | error.OutOfMemory => { | 1196 | error.OutOfMemory => { |
| 1208 | // TODO: it's unclear how to gracefully handle this. | 1197 | // TODO: it's unclear how to gracefully handle this. |
| 1209 | // To report the error cleanly, we need to add a message to `failed_analysis` and a | 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,8 +1210,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 1221 | 1210 | ||
| 1222 | /// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old | 1211 | /// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old |
| 1223 | /// side effects (exports/references/etc) have been dropped. If semantic analysis fails, this | 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 | 1213 | /// function will return `error.AlreadyReported`. |
| 1225 | /// to `transitive_failed_analysis` if necessary. | ||
| 1226 | fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void { | 1214 | fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void { |
| 1227 | const zcu = pt.zcu; | 1215 | const zcu = pt.zcu; |
| 1228 | const ip = &zcu.intern_pool; | 1216 | const ip = &zcu.intern_pool; |
| ... | @@ -1239,7 +1227,14 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu | ... | @@ -1239,7 +1227,14 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu |
| 1239 | defer tracy_trace.end(); | 1227 | defer tracy_trace.end(); |
| 1240 | tracy_trace.addTextFmt("cu_id={d}", .{cu_id}); | 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 | const file = zcu.fileByIndex(inst_resolved.file); | 1238 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1244 | const zir = file.zir.?; | 1239 | const zir = file.zir.?; |
| 1245 | 1240 | ||
| ... | @@ -1314,7 +1309,7 @@ pub fn ensureTypeLayoutUpToDate( | ... | @@ -1314,7 +1309,7 @@ pub fn ensureTypeLayoutUpToDate( |
| 1314 | ty: Type, | 1309 | ty: Type, |
| 1315 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 1310 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1316 | reason: ?*const Zcu.DependencyReason, | 1311 | reason: ?*const Zcu.DependencyReason, |
| 1317 | ) Zcu.SemaError!void { | 1312 | ) UpdateUnitError!void { |
| 1318 | const zcu = pt.zcu; | 1313 | const zcu = pt.zcu; |
| 1319 | const ip = &zcu.intern_pool; | 1314 | const ip = &zcu.intern_pool; |
| 1320 | const comp = zcu.comp; | 1315 | const comp = zcu.comp; |
| ... | @@ -1399,15 +1394,7 @@ pub fn ensureTypeLayoutUpToDate( | ... | @@ -1399,15 +1394,7 @@ pub fn ensureTypeLayoutUpToDate( |
| 1399 | const new_failed: bool = if (result) failed: { | 1394 | const new_failed: bool = if (result) failed: { |
| 1400 | break :failed false; | 1395 | break :failed false; |
| 1401 | } else |err| switch (err) { | 1396 | } else |err| switch (err) { |
| 1402 | error.AnalysisFail => failed: { | 1397 | error.AlreadyReported => true, |
| 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 | }, | ||
| 1411 | error.OutOfMemory, | 1398 | error.OutOfMemory, |
| 1412 | error.Canceled, | 1399 | error.Canceled, |
| 1413 | => |e| return e, | 1400 | => |e| return e, |
| ... | @@ -1442,7 +1429,7 @@ pub fn ensureStructDefaultsUpToDate( | ... | @@ -1442,7 +1429,7 @@ pub fn ensureStructDefaultsUpToDate( |
| 1442 | ty: Type, | 1429 | ty: Type, |
| 1443 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 1430 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1444 | reason: ?*const Zcu.DependencyReason, | 1431 | reason: ?*const Zcu.DependencyReason, |
| 1445 | ) Zcu.SemaError!void { | 1432 | ) UpdateUnitError!void { |
| 1446 | const zcu = pt.zcu; | 1433 | const zcu = pt.zcu; |
| 1447 | const ip = &zcu.intern_pool; | 1434 | const ip = &zcu.intern_pool; |
| 1448 | const comp = zcu.comp; | 1435 | const comp = zcu.comp; |
| ... | @@ -1513,15 +1500,7 @@ pub fn ensureStructDefaultsUpToDate( | ... | @@ -1513,15 +1500,7 @@ pub fn ensureStructDefaultsUpToDate( |
| 1513 | const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: { | 1500 | const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: { |
| 1514 | break :failed false; | 1501 | break :failed false; |
| 1515 | } else |err| switch (err) { | 1502 | } else |err| switch (err) { |
| 1516 | error.AnalysisFail => failed: { | 1503 | error.AlreadyReported => true, |
| 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 | }, | ||
| 1525 | error.OutOfMemory, | 1504 | error.OutOfMemory, |
| 1526 | error.Canceled, | 1505 | error.Canceled, |
| 1527 | => |e| return e, | 1506 | => |e| return e, |
| ... | @@ -1547,7 +1526,7 @@ pub fn ensureNavValUpToDate( | ... | @@ -1547,7 +1526,7 @@ pub fn ensureNavValUpToDate( |
| 1547 | nav_id: InternPool.Nav.Index, | 1526 | nav_id: InternPool.Nav.Index, |
| 1548 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 1527 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1549 | reason: ?*const Zcu.DependencyReason, | 1528 | reason: ?*const Zcu.DependencyReason, |
| 1550 | ) Zcu.SemaError!void { | 1529 | ) UpdateUnitError!void { |
| 1551 | const zcu = pt.zcu; | 1530 | const zcu = pt.zcu; |
| 1552 | const gpa = zcu.gpa; | 1531 | const gpa = zcu.gpa; |
| 1553 | const ip = &zcu.intern_pool; | 1532 | const ip = &zcu.intern_pool; |
| ... | @@ -1594,15 +1573,7 @@ pub fn ensureNavValUpToDate( | ... | @@ -1594,15 +1573,7 @@ pub fn ensureNavValUpToDate( |
| 1594 | false, | 1573 | false, |
| 1595 | }; | 1574 | }; |
| 1596 | } else |err| switch (err) { | 1575 | } else |err| switch (err) { |
| 1597 | error.AnalysisFail => res: { | 1576 | error.AlreadyReported => .{ !prev_failed, true }, |
| 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 | }, | ||
| 1606 | error.OutOfMemory => { | 1577 | error.OutOfMemory => { |
| 1607 | // TODO: it's unclear how to gracefully handle this. | 1578 | // TODO: it's unclear how to gracefully handle this. |
| 1608 | // To report the error cleanly, we need to add a message to `failed_analysis` and a | 1579 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | @@ -1655,7 +1626,14 @@ fn analyzeNavVal( | ... | @@ -1655,7 +1626,14 @@ fn analyzeNavVal( |
| 1655 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); | 1626 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); |
| 1656 | tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); | 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 | const file = zcu.fileByIndex(inst_resolved.file); | 1637 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1660 | const zir = file.zir.?; | 1638 | const zir = file.zir.?; |
| 1661 | const zir_decl = zir.getDeclaration(inst_resolved.inst); | 1639 | const zir_decl = zir.getDeclaration(inst_resolved.inst); |
| ... | @@ -1916,7 +1894,7 @@ pub fn ensureNavTypeUpToDate( | ... | @@ -1916,7 +1894,7 @@ pub fn ensureNavTypeUpToDate( |
| 1916 | nav_id: InternPool.Nav.Index, | 1894 | nav_id: InternPool.Nav.Index, |
| 1917 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 1895 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 1918 | reason: ?*const Zcu.DependencyReason, | 1896 | reason: ?*const Zcu.DependencyReason, |
| 1919 | ) Zcu.SemaError!void { | 1897 | ) UpdateUnitError!void { |
| 1920 | const zcu = pt.zcu; | 1898 | const zcu = pt.zcu; |
| 1921 | const gpa = zcu.gpa; | 1899 | const gpa = zcu.gpa; |
| 1922 | const ip = &zcu.intern_pool; | 1900 | const ip = &zcu.intern_pool; |
| ... | @@ -1963,15 +1941,7 @@ pub fn ensureNavTypeUpToDate( | ... | @@ -1963,15 +1941,7 @@ pub fn ensureNavTypeUpToDate( |
| 1963 | false, | 1941 | false, |
| 1964 | }; | 1942 | }; |
| 1965 | } else |err| switch (err) { | 1943 | } else |err| switch (err) { |
| 1966 | error.AnalysisFail => res: { | 1944 | error.AlreadyReported => .{ !prev_failed, true }, |
| 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 | }, | ||
| 1975 | error.OutOfMemory => { | 1945 | error.OutOfMemory => { |
| 1976 | // TODO: it's unclear how to gracefully handle this. | 1946 | // TODO: it's unclear how to gracefully handle this. |
| 1977 | // To report the error cleanly, we need to add a message to `failed_analysis` and a | 1947 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | @@ -2024,7 +1994,14 @@ fn analyzeNavType( | ... | @@ -2024,7 +1994,14 @@ fn analyzeNavType( |
| 2024 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); | 1994 | tracy_trace.addText(old_nav.fqn.toSlice(ip)); |
| 2025 | tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); | 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 | const file = zcu.fileByIndex(inst_resolved.file); | 2005 | const file = zcu.fileByIndex(inst_resolved.file); |
| 2029 | const zir = file.zir.?; | 2006 | const zir = file.zir.?; |
| 2030 | 2007 | ||
| ... | @@ -2160,7 +2137,7 @@ pub fn ensureFuncBodyUpToDate( | ... | @@ -2160,7 +2137,7 @@ pub fn ensureFuncBodyUpToDate( |
| 2160 | func_index: InternPool.Index, | 2137 | func_index: InternPool.Index, |
| 2161 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. | 2138 | /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. |
| 2162 | reason: ?*const Zcu.DependencyReason, | 2139 | reason: ?*const Zcu.DependencyReason, |
| 2163 | ) Zcu.SemaError!void { | 2140 | ) UpdateUnitError!void { |
| 2164 | dev.check(.sema); | 2141 | dev.check(.sema); |
| 2165 | 2142 | ||
| 2166 | const zcu = pt.zcu; | 2143 | const zcu = pt.zcu; |
| ... | @@ -2204,18 +2181,10 @@ pub fn ensureFuncBodyUpToDate( | ... | @@ -2204,18 +2181,10 @@ pub fn ensureFuncBodyUpToDate( |
| 2204 | const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result| | 2181 | const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result| |
| 2205 | .{ prev_failed or result.ies_outdated, false } | 2182 | .{ prev_failed or result.ies_outdated, false } |
| 2206 | else |err| switch (err) { | 2183 | else |err| switch (err) { |
| 2207 | error.AnalysisFail => res: { | 2184 | // We consider the IES to be outdated if the function previously succeeded analysis; in this case, |
| 2208 | if (!zcu.failed_analysis.contains(anal_unit)) { | 2185 | // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting |
| 2209 | // If this function caused the error, it would have an entry in `failed_analysis`. | 2186 | // a different error later (which may now be invalid). |
| 2210 | // Since it does not, this must be a transitive failure. | 2187 | error.AlreadyReported => .{ !prev_failed, true }, |
| 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 | }, | ||
| 2219 | error.OutOfMemory => { | 2188 | error.OutOfMemory => { |
| 2220 | // TODO: it's unclear how to gracefully handle this. | 2189 | // TODO: it's unclear how to gracefully handle this. |
| 2221 | // To report the error cleanly, we need to add a message to `failed_analysis` and a | 2190 | // To report the error cleanly, we need to add a message to `failed_analysis` and a |
| ... | @@ -3306,15 +3275,21 @@ fn analyzeFuncBodyInner( | ... | @@ -3306,15 +3275,21 @@ fn analyzeFuncBodyInner( |
| 3306 | // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary. | 3275 | // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary. |
| 3307 | 3276 | ||
| 3308 | if (func.generic_owner == .none) { | 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 | if (ip.getNav(func.owner_nav).resolved.?.value != func_index) { | 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 | } else { | 3285 | } else { |
| 3314 | const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; | 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 | if (ip.getNav(go_nav).resolved.?.value != func.generic_owner) { | 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,7 +3319,9 @@ fn analyzeFuncBodyInner( |
| 3344 | }; | 3319 | }; |
| 3345 | defer inner_block.instructions.deinit(gpa); | 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 | // Here we are performing "runtime semantic analysis" for a function body, which means | 3326 | // Here we are performing "runtime semantic analysis" for a function body, which means |
| 3350 | // we must map the parameter ZIR instructions to `arg` AIR instructions. | 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,12 +4355,18 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) (Io.Cancelable | |
| 4378 | return result.index; | 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 | /// Given a namespace, re-scan its declarations from the type definition if they have not | 4364 | /// Given a namespace, re-scan its declarations from the type definition if they have not |
| 4382 | /// yet been re-scanned on this update. | 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 | /// This will effectively short-circuit the caller, which will be semantic analysis of a | 4367 | /// This will effectively short-circuit the caller, which will be semantic analysis of a |
| 4385 | /// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error. | 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 | const zcu = pt.zcu; | 4370 | const zcu = pt.zcu; |
| 4388 | const ip = &zcu.intern_pool; | 4371 | const ip = &zcu.intern_pool; |
| 4389 | const namespace = zcu.namespacePtr(namespace_index); | 4372 | const namespace = zcu.namespacePtr(namespace_index); |
| ... | @@ -4410,7 +4393,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace | ... | @@ -4410,7 +4393,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4410 | 4393 | ||
| 4411 | // Namespace outdated -- re-scan the type if necessary. | 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 | const file = zcu.fileByIndex(inst_info.file); | 4397 | const file = zcu.fileByIndex(inst_info.file); |
| 4415 | const zir = &file.zir.?; | 4398 | const zir = &file.zir.?; |
| 4416 | 4399 |