authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-15 13:18:08+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-16 13:28:15+01:00
logd717c96877355090ea3a8e3662a2584eea02445c
tree3f76da87b8b222f9f103344aaacec8370a8ee3d4
parent70040778fbde5d7fcbbfc26dbabc700024c538d5
signaturelock-open Commit is signed but in an unrecognized format.

compiler: include inline calls in the reference trace

Inline calls which happened in the erroring `AnalUnit` still show as error notes, because they tend to make very important context (e.g. to see how comptime values propagate through them). However, "earlier" inline calls are still useful to see to understand how something is being referenced, so we should include them in the reference trace.

4 files changed, 175 insertions(+), 57 deletions(-)

src/Compilation.zig+45-21
......@@ -3681,32 +3681,27 @@ pub fn addModuleErrorMsg(
36813681 const ref = maybe_ref orelse break;
36823682 const gop = try seen.getOrPut(gpa, ref.referencer);
36833683 if (gop.found_existing) break;
3684 if (ref_traces.items.len < max_references) skip: {
3685 const src = ref.src.upgrade(zcu);
3686 const source = try src.file_scope.getSource(gpa);
3687 const span = try src.span(gpa);
3688 const loc = std.zig.findLineColumn(source.bytes, span.main);
3689 const rt_file_path = try src.file_scope.fullPath(gpa);
3690 defer gpa.free(rt_file_path);
3691 const name = switch (ref.referencer.unwrap()) {
3684 if (ref_traces.items.len < max_references) {
3685 var last_call_src = ref.src;
3686 var opt_inline_frame = ref.inline_frame;
3687 while (opt_inline_frame.unwrap()) |inline_frame| {
3688 const f = inline_frame.ptr(zcu).*;
3689 const func_nav = ip.indexToKey(f.callee).func.owner_nav;
3690 const func_name = ip.getNav(func_nav).name.toSlice(ip);
3691 try addReferenceTraceFrame(zcu, eb, &ref_traces, func_name, last_call_src, true);
3692 last_call_src = f.call_src;
3693 opt_inline_frame = f.parent;
3694 }
3695 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
36923696 .@"comptime" => "comptime",
36933697 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
36943698 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
36953699 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
3696 .memoized_state => break :skip,
3700 .memoized_state => null,
36973701 };
3698 try ref_traces.append(gpa, .{
3699 .decl_name = try eb.addString(name),
3700 .src_loc = try eb.addSourceLocation(.{
3701 .src_path = try eb.addString(rt_file_path),
3702 .span_start = span.start,
3703 .span_main = span.main,
3704 .span_end = span.end,
3705 .line = @intCast(loc.line),
3706 .column = @intCast(loc.column),
3707 .source_line = 0,
3708 }),
3709 });
3702 if (root_name) |n| {
3703 try addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false);
3704 }
37103705 }
37113706 referenced_by = ref.referencer;
37123707 }
......@@ -3786,6 +3781,35 @@ pub fn addModuleErrorMsg(
37863781 }
37873782}
37883783
3784fn addReferenceTraceFrame(
3785 zcu: *Zcu,
3786 eb: *ErrorBundle.Wip,
3787 ref_traces: *std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace),
3788 name: []const u8,
3789 lazy_src: Zcu.LazySrcLoc,
3790 inlined: bool,
3791) !void {
3792 const gpa = zcu.gpa;
3793 const src = lazy_src.upgrade(zcu);
3794 const source = try src.file_scope.getSource(gpa);
3795 const span = try src.span(gpa);
3796 const loc = std.zig.findLineColumn(source.bytes, span.main);
3797 const rt_file_path = try src.file_scope.fullPath(gpa);
3798 defer gpa.free(rt_file_path);
3799 try ref_traces.append(gpa, .{
3800 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
3801 .src_loc = try eb.addSourceLocation(.{
3802 .src_path = try eb.addString(rt_file_path),
3803 .span_start = span.start,
3804 .span_main = span.main,
3805 .span_end = span.end,
3806 .line = @intCast(loc.line),
3807 .column = @intCast(loc.column),
3808 .source_line = 0,
3809 }),
3810 });
3811}
3812
37893813pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
37903814 const gpa = eb.gpa;
37913815 const src_path = try file.fullPath(gpa);
src/Sema.zig+51-33
......@@ -448,6 +448,21 @@ pub const Block = struct {
448448 func: InternPool.Index,
449449 comptime_result: Air.Inst.Ref,
450450 merges: Merges,
451 /// Populated lazily by `refFrame`.
452 ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none,
453
454 fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index {
455 if (inlining.ref_frame == .none) {
456 inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{
457 .callee = inlining.func,
458 .call_src = inlining.call_src,
459 .parent = if (inlining.call_block.inlining) |parent_inlining| p: {
460 break :p (try parent_inlining.refFrame(zcu)).toOptional();
461 } else .none,
462 })).toOptional();
463 }
464 return inlining.ref_frame.unwrap().?;
465 }
451466 };
452467
453468 pub const Merges = struct {
......@@ -4287,7 +4302,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42874302 if (zcu.intern_pool.isFuncBody(val)) {
42884303 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
42894304 if (try ty.fnHasRuntimeBitsSema(pt)) {
4290 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val }));
4305 try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = val }));
42914306 try zcu.ensureFuncBodyAnalysisQueued(val);
42924307 }
42934308 }
......@@ -6615,7 +6630,7 @@ pub fn analyzeExport(
66156630 if (options.linkage == .internal)
66166631 return;
66176632
6618 try sema.ensureNavResolved(src, orig_nav_index, .fully);
6633 try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
66196634
66206635 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
66216636 .variable => |v| v.owner_nav,
......@@ -6644,7 +6659,7 @@ pub fn analyzeExport(
66446659 return sema.fail(block, src, "export target cannot be extern", .{});
66456660 }
66466661
6647 try sema.maybeQueueFuncBodyAnalysis(src, exported_nav_index);
6662 try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index);
66486663
66496664 try sema.exports.append(gpa, .{
66506665 .opts = options,
......@@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
68926907 .no_embedded_nulls,
68936908 );
68946909 const nav_index = try sema.lookupIdentifier(block, src, decl_name);
6895 return sema.analyzeNavRef(src, nav_index);
6910 return sema.analyzeNavRef(block, src, nav_index);
68966911}
68976912
68986913fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -6988,7 +7003,7 @@ fn lookupInNamespace(
69887003 }
69897004
69907005 for (usingnamespaces.items) |sub_ns_nav| {
6991 try sema.ensureNavResolved(src, sub_ns_nav, .fully);
7006 try sema.ensureNavResolved(block, src, sub_ns_nav, .fully);
69927007 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
69937008 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
69947009 try checked_namespaces.put(gpa, sub_ns, {});
......@@ -7720,8 +7735,8 @@ fn analyzeCall(
77207735 var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
77217736 .call_block = block,
77227737 .call_src = call_src,
7738 .func = func_val.?.toIntern(),
77237739 .has_comptime_args = false, // unused by error reporting
7724 .func = .none, // unused by error reporting
77257740 .comptime_result = .none, // unused by error reporting
77267741 .merges = undefined, // unused because we'll never `return`
77277742 } else undefined;
......@@ -7999,7 +8014,7 @@ fn analyzeCall(
79998014 ref_func: {
80008015 const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;
80018016 if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;
8002 try sema.addReferenceEntry(call_src, .wrap(.{ .func = runtime_func_val.toIntern() }));
8017 try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = runtime_func_val.toIntern() }));
80038018 try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());
80048019 }
80058020
......@@ -17254,7 +17269,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1725417269 .@"comptime" => |index| return Air.internedToRef(index),
1725517270 .runtime => |index| index,
1725617271 .nav_val => |nav| return sema.analyzeNavVal(block, src, nav),
17257 .nav_ref => |nav| return sema.analyzeNavRef(src, nav),
17272 .nav_ref => |nav| return sema.analyzeNavRef(block, src, nav),
1725817273 };
1725917274
1726017275 // The comptime case is handled already above. Runtime case below.
......@@ -18407,7 +18422,7 @@ fn typeInfoNamespaceDecls(
1840718422 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
1840818423 continue;
1840918424 }
18410 try sema.ensureNavResolved(src, nav, .fully);
18425 try sema.ensureNavResolved(block, src, nav, .fully);
1841118426 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);
1841218427 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
1841318428 }
......@@ -27932,7 +27947,7 @@ fn namespaceLookupRef(
2793227947 decl_name: InternPool.NullTerminatedString,
2793327948) CompileError!?Air.Inst.Ref {
2793427949 const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null;
27935 return try sema.analyzeNavRef(src, nav);
27950 return try sema.analyzeNavRef(block, src, nav);
2793627951}
2793727952
2793827953fn namespaceLookupVal(
......@@ -29095,7 +29110,7 @@ fn coerceExtra(
2909529110 .@"extern" => |e| e.owner_nav,
2909629111 else => unreachable,
2909729112 };
29098 const inst_as_ptr = try sema.analyzeNavRef(inst_src, fn_nav);
29113 const inst_as_ptr = try sema.analyzeNavRef(block, inst_src, fn_nav);
2909929114 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
2910029115 }
2910129116
......@@ -30748,7 +30763,7 @@ fn coerceVarArgParam(
3074830763 .@"fn" => fn_ptr: {
3074930764 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
3075030765 const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;
30751 break :fn_ptr try sema.analyzeNavRef(inst_src, fn_nav);
30766 break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav);
3075230767 },
3075330768 .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
3075430769 .float => float: {
......@@ -31758,12 +31773,13 @@ fn analyzeNavVal(
3175831773 src: LazySrcLoc,
3175931774 nav_index: InternPool.Nav.Index,
3176031775) CompileError!Air.Inst.Ref {
31761 const ref = try sema.analyzeNavRefInner(src, nav_index, false);
31776 const ref = try sema.analyzeNavRefInner(block, src, nav_index, false);
3176231777 return sema.analyzeLoad(block, src, ref, src);
3176331778}
3176431779
3176531780fn addReferenceEntry(
3176631781 sema: *Sema,
31782 opt_block: ?*Block,
3176731783 src: LazySrcLoc,
3176831784 referenced_unit: AnalUnit,
3176931785) !void {
......@@ -31771,10 +31787,12 @@ fn addReferenceEntry(
3177131787 if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;
3177231788 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
3177331789 if (gop.found_existing) return;
31774 // TODO: we need to figure out how to model inline calls here.
31775 // They aren't references in the analysis sense, but ought to show up in the reference trace!
31776 // Would representing inline calls in the reference table cause excessive memory usage?
31777 try zcu.addUnitReference(sema.owner, referenced_unit, src);
31790 try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
31791 const block = opt_block orelse break :inline_frame .none;
31792 const inlining = block.inlining orelse break :inline_frame .none;
31793 const frame = try inlining.refFrame(zcu);
31794 break :inline_frame frame.toOptional();
31795 });
3177831796}
3177931797
3178031798pub fn addTypeReferenceEntry(
......@@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
3179331811 const pt = sema.pt;
3179431812
3179531813 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
31796 try sema.addReferenceEntry(src, unit);
31814 try sema.addReferenceEntry(null, src, unit);
3179731815 try sema.declareDependency(.{ .memoized_state = stage });
3179831816
3179931817 if (pt.zcu.analysis_in_progress.contains(unit)) {
......@@ -31802,7 +31820,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
3180231820 try pt.ensureMemoizedStateUpToDate(stage);
3180331821}
3180431822
31805pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
31823pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
3180631824 const pt = sema.pt;
3180731825 const zcu = pt.zcu;
3180831826 const ip = &zcu.intern_pool;
......@@ -31825,7 +31843,7 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav
3182531843 .type => .{ .nav_ty = nav_index },
3182631844 .fully => .{ .nav_val = nav_index },
3182731845 });
31828 try sema.addReferenceEntry(src, anal_unit);
31846 try sema.addReferenceEntry(block, src, anal_unit);
3182931847
3183031848 if (zcu.analysis_in_progress.contains(anal_unit)) {
3183131849 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
......@@ -31855,25 +31873,25 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
3185531873 } }));
3185631874}
3185731875
31858fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
31859 return sema.analyzeNavRefInner(src, nav_index, true);
31876fn analyzeNavRef(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
31877 return sema.analyzeNavRefInner(block, src, nav_index, true);
3186031878}
3186131879
3186231880/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
3186331881/// If this pointer will be used directly, `is_ref` must be `true`.
3186431882/// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`.
31865fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
31883fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
3186631884 const pt = sema.pt;
3186731885 const zcu = pt.zcu;
3186831886 const ip = &zcu.intern_pool;
3186931887
31870 try sema.ensureNavResolved(src, orig_nav_index, if (is_ref) .type else .fully);
31888 try sema.ensureNavResolved(block, src, orig_nav_index, if (is_ref) .type else .fully);
3187131889
3187231890 const nav_index = nav: {
3187331891 if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
3187431892 // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
3187531893 // We need to resolve the value to know for sure.
31876 if (is_ref) try sema.ensureNavResolved(src, orig_nav_index, .fully);
31894 if (is_ref) try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
3187731895 switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
3187831896 .func => |f| break :nav f.owner_nav,
3187931897 .@"extern" => |e| break :nav e.owner_nav,
......@@ -31897,7 +31915,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
3189731915 },
3189831916 });
3189931917 if (is_ref) {
31900 try sema.maybeQueueFuncBodyAnalysis(src, nav_index);
31918 try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
3190131919 }
3190231920 return Air.internedToRef((try pt.intern(.{ .ptr = .{
3190331921 .ty = ptr_ty.toIntern(),
......@@ -31906,7 +31924,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
3190631924 } })));
3190731925}
3190831926
31909fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
31927fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
3191031928 const pt = sema.pt;
3191131929 const zcu = pt.zcu;
3191231930 const ip = &zcu.intern_pool;
......@@ -31914,16 +31932,16 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPoo
3191431932 // To avoid forcing too much resolution, let's first resolve the type, and check if it's a function.
3191531933 // If it is, we can resolve the *value*, and queue analysis as needed.
3191631934
31917 try sema.ensureNavResolved(src, nav_index, .type);
31935 try sema.ensureNavResolved(block, src, nav_index, .type);
3191831936 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
3191931937 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
3192031938 if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;
3192131939
31922 try sema.ensureNavResolved(src, nav_index, .fully);
31940 try sema.ensureNavResolved(block, src, nav_index, .fully);
3192331941 const nav_val = zcu.navValue(nav_index);
3192431942 if (!ip.isFuncBody(nav_val.toIntern())) return;
3192531943
31926 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
31944 try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
3192731945 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
3192831946}
3192931947
......@@ -31939,8 +31957,8 @@ fn analyzeRef(
3193931957
3194031958 if (try sema.resolveValue(operand)) |val| {
3194131959 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
31942 .@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav),
31943 .func => |f| return sema.analyzeNavRef(src, f.owner_nav),
31960 .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav),
31961 .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav),
3194431962 else => return uavRef(sema, val.toIntern()),
3194531963 }
3194631964 }
......@@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet(
3550435522 }
3550535523 // In this case we are dealing with the actual InferredErrorSet object that
3550635524 // corresponds to the function, not one created to track an inline/comptime call.
35507 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index }));
35525 try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = func_index }));
3550835526 try pt.ensureFuncBodyUpToDate(func_index);
3550935527 }
3551035528
src/Sema/comptime_ptr_access.zig+1-1
......@@ -228,7 +228,7 @@ fn loadComptimePtrInner(
228228
229229 const base_val: MutableValue = switch (ptr.base_addr) {
230230 .nav => |nav| val: {
231 try sema.ensureNavResolved(src, nav, .fully);
231 try sema.ensureNavResolved(block, src, nav, .fully);
232232 const val = ip.getNav(nav).status.fully_resolved.val;
233233 switch (ip.indexToKey(val)) {
234234 .variable => return .runtime_load,
src/Zcu.zig+78-2
......@@ -215,6 +215,9 @@ all_references: std.ArrayListUnmanaged(Reference) = .empty,
215215/// Freelist of indices in `all_references`.
216216free_references: std.ArrayListUnmanaged(u32) = .empty,
217217
218inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame) = .empty,
219free_inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame.Index) = .empty,
220
218221/// Key is the `AnalUnit` *performing* the reference. This representation allows
219222/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
220223/// Value is index into `all_type_reference` of the first reference triggered by the unit.
......@@ -583,6 +586,42 @@ pub const Reference = struct {
583586 next: u32,
584587 /// The source location of the reference.
585588 src: LazySrcLoc,
589 /// If not `.none`, this is the index of the `InlineReferenceFrame` which should appear
590 /// between the referencer and `referenced` in the reference trace. These frames represent
591 /// inline calls, which do not create actual references (since they happen in the caller's
592 /// `AnalUnit`), but do show in the reference trace.
593 inline_frame: InlineReferenceFrame.Index.Optional,
594};
595
596pub const InlineReferenceFrame = struct {
597 /// The inline *callee*; that is, the function which was called inline.
598 /// The *caller* is either `parent`, or else the unit causing the original `Reference`.
599 callee: InternPool.Index,
600 /// The source location of the inline call, in the *caller*.
601 call_src: LazySrcLoc,
602 /// If not `.none`, a frame which should appear directly below this one.
603 /// This will be the "parent" inline call; this frame's `callee` is our caller.
604 parent: InlineReferenceFrame.Index.Optional,
605
606 pub const Index = enum(u32) {
607 _,
608 pub fn ptr(idx: Index, zcu: *Zcu) *InlineReferenceFrame {
609 return &zcu.inline_reference_frames.items[@intFromEnum(idx)];
610 }
611 pub fn toOptional(idx: Index) Optional {
612 return @enumFromInt(@intFromEnum(idx));
613 }
614 pub const Optional = enum(u32) {
615 none = std.math.maxInt(u32),
616 _,
617 pub fn unwrap(opt: Optional) ?Index {
618 return switch (opt) {
619 .none => null,
620 _ => @enumFromInt(@intFromEnum(opt)),
621 };
622 }
623 };
624 };
586625};
587626
588627pub const TypeReference = struct {
......@@ -3440,12 +3479,28 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
34403479 var idx = kv.value;
34413480
34423481 while (idx != std.math.maxInt(u32)) {
3482 const ref = zcu.all_references.items[idx];
34433483 zcu.free_references.append(gpa, idx) catch {
34443484 // This space will be reused eventually, so we need not propagate this error.
34453485 // Just leak it for now, and let GC reclaim it later on.
34463486 break :unit_refs;
34473487 };
3448 idx = zcu.all_references.items[idx].next;
3488 idx = ref.next;
3489
3490 var opt_inline_frame = ref.inline_frame;
3491 while (opt_inline_frame.unwrap()) |inline_frame| {
3492 // The same inline frame could be used multiple times by one unit. We need to
3493 // detect this case to avoid adding it to `free_inline_reference_frames` more
3494 // than once. We do that by setting `parent` to itself as a marker.
3495 if (inline_frame.ptr(zcu).parent == inline_frame.toOptional()) break;
3496 zcu.free_inline_reference_frames.append(gpa, inline_frame) catch {
3497 // This space will be reused eventually, so we need not propagate this error.
3498 // Just leak it for now, and let GC reclaim it later on.
3499 break :unit_refs;
3500 };
3501 opt_inline_frame = inline_frame.ptr(zcu).parent;
3502 inline_frame.ptr(zcu).parent = inline_frame.toOptional(); // signal to code above
3503 }
34493504 }
34503505 }
34513506
......@@ -3480,7 +3535,22 @@ pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
34803535 }
34813536}
34823537
3483pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
3538pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index {
3539 const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: {
3540 _ = try zcu.inline_reference_frames.addOne(zcu.gpa);
3541 break :idx @enumFromInt(zcu.inline_reference_frames.items.len - 1);
3542 };
3543 frame_idx.ptr(zcu).* = frame;
3544 return frame_idx;
3545}
3546
3547pub fn addUnitReference(
3548 zcu: *Zcu,
3549 src_unit: AnalUnit,
3550 referenced_unit: AnalUnit,
3551 ref_src: LazySrcLoc,
3552 inline_frame: InlineReferenceFrame.Index.Optional,
3553) Allocator.Error!void {
34843554 const gpa = zcu.gpa;
34853555
34863556 zcu.clearCachedResolvedReferences();
......@@ -3500,6 +3570,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
35003570 .referenced = referenced_unit,
35013571 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
35023572 .src = ref_src,
3573 .inline_frame = inline_frame,
35033574 };
35043575
35053576 gop.value_ptr.* = @intCast(ref_idx);
......@@ -3828,7 +3899,10 @@ pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionT
38283899
38293900pub const ResolvedReference = struct {
38303901 referencer: AnalUnit,
3902 /// If `inline_frame` is not `.none`, this is the *deepest* source location in the chain of
3903 /// inline calls. For source locations further up the inline call stack, consult `inline_frame`.
38313904 src: LazySrcLoc,
3905 inline_frame: InlineReferenceFrame.Index.Optional,
38323906};
38333907
38343908/// Returns a mapping from an `AnalUnit` to where it is referenced.
......@@ -4037,6 +4111,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
40374111 try unit_queue.put(gpa, ref.referenced, .{
40384112 .referencer = unit,
40394113 .src = ref.src,
4114 .inline_frame = ref.inline_frame,
40404115 });
40414116 }
40424117 ref_idx = ref.next;
......@@ -4055,6 +4130,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
40554130 try type_queue.put(gpa, ref.referenced, .{
40564131 .referencer = unit,
40574132 .src = ref.src,
4133 .inline_frame = .none,
40584134 });
40594135 }
40604136 ref_idx = ref.next;