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