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(...@@ -3681,32 +3681,27 @@ pub fn addModuleErrorMsg(
3681 const ref = maybe_ref orelse break;3681 const ref = maybe_ref orelse break;
3682 const gop = try seen.getOrPut(gpa, ref.referencer);3682 const gop = try seen.getOrPut(gpa, ref.referencer);
3683 if (gop.found_existing) break;3683 if (gop.found_existing) break;
3684 if (ref_traces.items.len < max_references) skip: {3684 if (ref_traces.items.len < max_references) {
3685 const src = ref.src.upgrade(zcu);3685 var last_call_src = ref.src;
3686 const source = try src.file_scope.getSource(gpa);3686 var opt_inline_frame = ref.inline_frame;
3687 const span = try src.span(gpa);3687 while (opt_inline_frame.unwrap()) |inline_frame| {
3688 const loc = std.zig.findLineColumn(source.bytes, span.main);3688 const f = inline_frame.ptr(zcu).*;
3689 const rt_file_path = try src.file_scope.fullPath(gpa);3689 const func_nav = ip.indexToKey(f.callee).func.owner_nav;
3690 defer gpa.free(rt_file_path);3690 const func_name = ip.getNav(func_nav).name.toSlice(ip);
3691 const name = switch (ref.referencer.unwrap()) {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()) {
3692 .@"comptime" => "comptime",3696 .@"comptime" => "comptime",
3693 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),3697 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
3694 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),3698 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3695 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),3699 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
3696 .memoized_state => break :skip,3700 .memoized_state => null,
3697 };3701 };
3698 try ref_traces.append(gpa, .{3702 if (root_name) |n| {
3699 .decl_name = try eb.addString(name),3703 try addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false);
3700 .src_loc = try eb.addSourceLocation(.{3704 }
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 });
3710 }3705 }
3711 referenced_by = ref.referencer;3706 referenced_by = ref.referencer;
3712 }3707 }
...@@ -3786,6 +3781,35 @@ pub fn addModuleErrorMsg(...@@ -3786,6 +3781,35 @@ pub fn addModuleErrorMsg(
3786 }3781 }
3787}3782}
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
3789pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {3813pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3790 const gpa = eb.gpa;3814 const gpa = eb.gpa;
3791 const src_path = try file.fullPath(gpa);3815 const src_path = try file.fullPath(gpa);
src/Sema.zig+51-33
...@@ -448,6 +448,21 @@ pub const Block = struct {...@@ -448,6 +448,21 @@ pub const Block = struct {
448 func: InternPool.Index,448 func: InternPool.Index,
449 comptime_result: Air.Inst.Ref,449 comptime_result: Air.Inst.Ref,
450 merges: Merges,450 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 }
451 };466 };
452467
453 pub const Merges = struct {468 pub const Merges = struct {
...@@ -4287,7 +4302,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4287,7 +4302,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4287 if (zcu.intern_pool.isFuncBody(val)) {4302 if (zcu.intern_pool.isFuncBody(val)) {
4288 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));4303 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
4289 if (try ty.fnHasRuntimeBitsSema(pt)) {4304 if (try ty.fnHasRuntimeBitsSema(pt)) {
4290 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val }));4305 try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = val }));
4291 try zcu.ensureFuncBodyAnalysisQueued(val);4306 try zcu.ensureFuncBodyAnalysisQueued(val);
4292 }4307 }
4293 }4308 }
...@@ -6615,7 +6630,7 @@ pub fn analyzeExport(...@@ -6615,7 +6630,7 @@ pub fn analyzeExport(
6615 if (options.linkage == .internal)6630 if (options.linkage == .internal)
6616 return;6631 return;
66176632
6618 try sema.ensureNavResolved(src, orig_nav_index, .fully);6633 try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
66196634
6620 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {6635 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
6621 .variable => |v| v.owner_nav,6636 .variable => |v| v.owner_nav,
...@@ -6644,7 +6659,7 @@ pub fn analyzeExport(...@@ -6644,7 +6659,7 @@ pub fn analyzeExport(
6644 return sema.fail(block, src, "export target cannot be extern", .{});6659 return sema.fail(block, src, "export target cannot be extern", .{});
6645 }6660 }
66466661
6647 try sema.maybeQueueFuncBodyAnalysis(src, exported_nav_index);6662 try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index);
66486663
6649 try sema.exports.append(gpa, .{6664 try sema.exports.append(gpa, .{
6650 .opts = options,6665 .opts = options,
...@@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
6892 .no_embedded_nulls,6907 .no_embedded_nulls,
6893 );6908 );
6894 const nav_index = try sema.lookupIdentifier(block, src, decl_name);6909 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);
6896}6911}
68976912
6898fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6913fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -6988,7 +7003,7 @@ fn lookupInNamespace(...@@ -6988,7 +7003,7 @@ fn lookupInNamespace(
6988 }7003 }
69897004
6990 for (usingnamespaces.items) |sub_ns_nav| {7005 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);
6992 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);7007 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
6993 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));7008 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
6994 try checked_namespaces.put(gpa, sub_ns, {});7009 try checked_namespaces.put(gpa, sub_ns, {});
...@@ -7720,8 +7735,8 @@ fn analyzeCall(...@@ -7720,8 +7735,8 @@ fn analyzeCall(
7720 var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{7735 var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
7721 .call_block = block,7736 .call_block = block,
7722 .call_src = call_src,7737 .call_src = call_src,
7738 .func = func_val.?.toIntern(),
7723 .has_comptime_args = false, // unused by error reporting7739 .has_comptime_args = false, // unused by error reporting
7724 .func = .none, // unused by error reporting
7725 .comptime_result = .none, // unused by error reporting7740 .comptime_result = .none, // unused by error reporting
7726 .merges = undefined, // unused because we'll never `return`7741 .merges = undefined, // unused because we'll never `return`
7727 } else undefined;7742 } else undefined;
...@@ -7999,7 +8014,7 @@ fn analyzeCall(...@@ -7999,7 +8014,7 @@ fn analyzeCall(
7999 ref_func: {8014 ref_func: {
8000 const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;8015 const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;
8001 if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;8016 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() }));
8003 try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());8018 try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());
8004 }8019 }
80058020
...@@ -17254,7 +17269,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -17254,7 +17269,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
17254 .@"comptime" => |index| return Air.internedToRef(index),17269 .@"comptime" => |index| return Air.internedToRef(index),
17255 .runtime => |index| index,17270 .runtime => |index| index,
17256 .nav_val => |nav| return sema.analyzeNavVal(block, src, nav),17271 .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),
17258 };17273 };
1725917274
17260 // The comptime case is handled already above. Runtime case below.17275 // The comptime case is handled already above. Runtime case below.
...@@ -18407,7 +18422,7 @@ fn typeInfoNamespaceDecls(...@@ -18407,7 +18422,7 @@ fn typeInfoNamespaceDecls(
18407 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {18422 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
18408 continue;18423 continue;
18409 }18424 }
18410 try sema.ensureNavResolved(src, nav, .fully);18425 try sema.ensureNavResolved(block, src, nav, .fully);
18411 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);18426 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);
18412 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);18427 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
18413 }18428 }
...@@ -27932,7 +27947,7 @@ fn namespaceLookupRef(...@@ -27932,7 +27947,7 @@ fn namespaceLookupRef(
27932 decl_name: InternPool.NullTerminatedString,27947 decl_name: InternPool.NullTerminatedString,
27933) CompileError!?Air.Inst.Ref {27948) CompileError!?Air.Inst.Ref {
27934 const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null;27949 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);
27936}27951}
2793727952
27938fn namespaceLookupVal(27953fn namespaceLookupVal(
...@@ -29095,7 +29110,7 @@ fn coerceExtra(...@@ -29095,7 +29110,7 @@ fn coerceExtra(
29095 .@"extern" => |e| e.owner_nav,29110 .@"extern" => |e| e.owner_nav,
29096 else => unreachable,29111 else => unreachable,
29097 };29112 };
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);
29099 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);29114 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
29100 }29115 }
2910129116
...@@ -30748,7 +30763,7 @@ fn coerceVarArgParam(...@@ -30748,7 +30763,7 @@ fn coerceVarArgParam(
30748 .@"fn" => fn_ptr: {30763 .@"fn" => fn_ptr: {
30749 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);30764 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
30750 const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;30765 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);
30752 },30767 },
30753 .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),30768 .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
30754 .float => float: {30769 .float => float: {
...@@ -31758,12 +31773,13 @@ fn analyzeNavVal(...@@ -31758,12 +31773,13 @@ fn analyzeNavVal(
31758 src: LazySrcLoc,31773 src: LazySrcLoc,
31759 nav_index: InternPool.Nav.Index,31774 nav_index: InternPool.Nav.Index,
31760) CompileError!Air.Inst.Ref {31775) 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);
31762 return sema.analyzeLoad(block, src, ref, src);31777 return sema.analyzeLoad(block, src, ref, src);
31763}31778}
3176431779
31765fn addReferenceEntry(31780fn addReferenceEntry(
31766 sema: *Sema,31781 sema: *Sema,
31782 opt_block: ?*Block,
31767 src: LazySrcLoc,31783 src: LazySrcLoc,
31768 referenced_unit: AnalUnit,31784 referenced_unit: AnalUnit,
31769) !void {31785) !void {
...@@ -31771,10 +31787,12 @@ fn addReferenceEntry(...@@ -31771,10 +31787,12 @@ fn addReferenceEntry(
31771 if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;31787 if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;
31772 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);31788 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
31773 if (gop.found_existing) return;31789 if (gop.found_existing) return;
31774 // TODO: we need to figure out how to model inline calls here.31790 try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
31775 // They aren't references in the analysis sense, but ought to show up in the reference trace!31791 const block = opt_block orelse break :inline_frame .none;
31776 // Would representing inline calls in the reference table cause excessive memory usage?31792 const inlining = block.inlining orelse break :inline_frame .none;
31777 try zcu.addUnitReference(sema.owner, referenced_unit, src);31793 const frame = try inlining.refFrame(zcu);
31794 break :inline_frame frame.toOptional();
31795 });
31778}31796}
3177931797
31780pub fn addTypeReferenceEntry(31798pub fn addTypeReferenceEntry(
...@@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M...@@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
31793 const pt = sema.pt;31811 const pt = sema.pt;
3179431812
31795 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });31813 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
31796 try sema.addReferenceEntry(src, unit);31814 try sema.addReferenceEntry(null, src, unit);
31797 try sema.declareDependency(.{ .memoized_state = stage });31815 try sema.declareDependency(.{ .memoized_state = stage });
3179831816
31799 if (pt.zcu.analysis_in_progress.contains(unit)) {31817 if (pt.zcu.analysis_in_progress.contains(unit)) {
...@@ -31802,7 +31820,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M...@@ -31802,7 +31820,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
31802 try pt.ensureMemoizedStateUpToDate(stage);31820 try pt.ensureMemoizedStateUpToDate(stage);
31803}31821}
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 {
31806 const pt = sema.pt;31824 const pt = sema.pt;
31807 const zcu = pt.zcu;31825 const zcu = pt.zcu;
31808 const ip = &zcu.intern_pool;31826 const ip = &zcu.intern_pool;
...@@ -31825,7 +31843,7 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav...@@ -31825,7 +31843,7 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav
31825 .type => .{ .nav_ty = nav_index },31843 .type => .{ .nav_ty = nav_index },
31826 .fully => .{ .nav_val = nav_index },31844 .fully => .{ .nav_val = nav_index },
31827 });31845 });
31828 try sema.addReferenceEntry(src, anal_unit);31846 try sema.addReferenceEntry(block, src, anal_unit);
3182931847
31830 if (zcu.analysis_in_progress.contains(anal_unit)) {31848 if (zcu.analysis_in_progress.contains(anal_unit)) {
31831 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{31849 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
...@@ -31855,25 +31873,25 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {...@@ -31855,25 +31873,25 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
31855 } }));31873 } }));
31856}31874}
3185731875
31858fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {31876fn analyzeNavRef(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
31859 return sema.analyzeNavRefInner(src, nav_index, true);31877 return sema.analyzeNavRefInner(block, src, nav_index, true);
31860}31878}
3186131879
31862/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.31880/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
31863/// If this pointer will be used directly, `is_ref` must be `true`.31881/// If this pointer will be used directly, `is_ref` must be `true`.
31864/// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`.31882/// 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 {
31866 const pt = sema.pt;31884 const pt = sema.pt;
31867 const zcu = pt.zcu;31885 const zcu = pt.zcu;
31868 const ip = &zcu.intern_pool;31886 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
31872 const nav_index = nav: {31890 const nav_index = nav: {
31873 if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {31891 if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
31874 // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!31892 // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
31875 // We need to resolve the value to know for sure.31893 // 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);
31877 switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {31895 switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
31878 .func => |f| break :nav f.owner_nav,31896 .func => |f| break :nav f.owner_nav,
31879 .@"extern" => |e| break :nav e.owner_nav,31897 .@"extern" => |e| break :nav e.owner_nav,
...@@ -31897,7 +31915,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N...@@ -31897,7 +31915,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
31897 },31915 },
31898 });31916 });
31899 if (is_ref) {31917 if (is_ref) {
31900 try sema.maybeQueueFuncBodyAnalysis(src, nav_index);31918 try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
31901 }31919 }
31902 return Air.internedToRef((try pt.intern(.{ .ptr = .{31920 return Air.internedToRef((try pt.intern(.{ .ptr = .{
31903 .ty = ptr_ty.toIntern(),31921 .ty = ptr_ty.toIntern(),
...@@ -31906,7 +31924,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N...@@ -31906,7 +31924,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
31906 } })));31924 } })));
31907}31925}
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 {
31910 const pt = sema.pt;31928 const pt = sema.pt;
31911 const zcu = pt.zcu;31929 const zcu = pt.zcu;
31912 const ip = &zcu.intern_pool;31930 const ip = &zcu.intern_pool;
...@@ -31914,16 +31932,16 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPoo...@@ -31914,16 +31932,16 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPoo
31914 // To avoid forcing too much resolution, let's first resolve the type, and check if it's a function.31932 // To avoid forcing too much resolution, let's first resolve the type, and check if it's a function.
31915 // If it is, we can resolve the *value*, and queue analysis as needed.31933 // 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);
31918 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));31936 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
31919 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;31937 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
31920 if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;31938 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);
31923 const nav_val = zcu.navValue(nav_index);31941 const nav_val = zcu.navValue(nav_index);
31924 if (!ip.isFuncBody(nav_val.toIntern())) return;31942 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() }));
31927 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());31945 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
31928}31946}
3192931947
...@@ -31939,8 +31957,8 @@ fn analyzeRef(...@@ -31939,8 +31957,8 @@ fn analyzeRef(
3193931957
31940 if (try sema.resolveValue(operand)) |val| {31958 if (try sema.resolveValue(operand)) |val| {
31941 switch (zcu.intern_pool.indexToKey(val.toIntern())) {31959 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
31942 .@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav),31960 .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav),
31943 .func => |f| return sema.analyzeNavRef(src, f.owner_nav),31961 .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav),
31944 else => return uavRef(sema, val.toIntern()),31962 else => return uavRef(sema, val.toIntern()),
31945 }31963 }
31946 }31964 }
...@@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet(...@@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet(
35504 }35522 }
35505 // In this case we are dealing with the actual InferredErrorSet object that35523 // In this case we are dealing with the actual InferredErrorSet object that
35506 // corresponds to the function, not one created to track an inline/comptime call.35524 // 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 }));
35508 try pt.ensureFuncBodyUpToDate(func_index);35526 try pt.ensureFuncBodyUpToDate(func_index);
35509 }35527 }
3551035528
src/Sema/comptime_ptr_access.zig+1-1
...@@ -228,7 +228,7 @@ fn loadComptimePtrInner(...@@ -228,7 +228,7 @@ fn loadComptimePtrInner(
228228
229 const base_val: MutableValue = switch (ptr.base_addr) {229 const base_val: MutableValue = switch (ptr.base_addr) {
230 .nav => |nav| val: {230 .nav => |nav| val: {
231 try sema.ensureNavResolved(src, nav, .fully);231 try sema.ensureNavResolved(block, src, nav, .fully);
232 const val = ip.getNav(nav).status.fully_resolved.val;232 const val = ip.getNav(nav).status.fully_resolved.val;
233 switch (ip.indexToKey(val)) {233 switch (ip.indexToKey(val)) {
234 .variable => return .runtime_load,234 .variable => return .runtime_load,
src/Zcu.zig+78-2
...@@ -215,6 +215,9 @@ all_references: std.ArrayListUnmanaged(Reference) = .empty,...@@ -215,6 +215,9 @@ all_references: std.ArrayListUnmanaged(Reference) = .empty,
215/// Freelist of indices in `all_references`.215/// Freelist of indices in `all_references`.
216free_references: std.ArrayListUnmanaged(u32) = .empty,216free_references: std.ArrayListUnmanaged(u32) = .empty,
217217
218inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame) = .empty,
219free_inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame.Index) = .empty,
220
218/// Key is the `AnalUnit` *performing* the reference. This representation allows221/// Key is the `AnalUnit` *performing* the reference. This representation allows
219/// incremental updates to quickly delete references caused by a specific `AnalUnit`.222/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
220/// Value is index into `all_type_reference` of the first reference triggered by the unit.223/// Value is index into `all_type_reference` of the first reference triggered by the unit.
...@@ -583,6 +586,42 @@ pub const Reference = struct {...@@ -583,6 +586,42 @@ pub const Reference = struct {
583 next: u32,586 next: u32,
584 /// The source location of the reference.587 /// The source location of the reference.
585 src: LazySrcLoc,588 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 };
586};625};
587626
588pub const TypeReference = struct {627pub const TypeReference = struct {
...@@ -3440,12 +3479,28 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -3440,12 +3479,28 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
3440 var idx = kv.value;3479 var idx = kv.value;
34413480
3442 while (idx != std.math.maxInt(u32)) {3481 while (idx != std.math.maxInt(u32)) {
3482 const ref = zcu.all_references.items[idx];
3443 zcu.free_references.append(gpa, idx) catch {3483 zcu.free_references.append(gpa, idx) catch {
3444 // This space will be reused eventually, so we need not propagate this error.3484 // This space will be reused eventually, so we need not propagate this error.
3445 // Just leak it for now, and let GC reclaim it later on.3485 // Just leak it for now, and let GC reclaim it later on.
3446 break :unit_refs;3486 break :unit_refs;
3447 };3487 };
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 }
3449 }3504 }
3450 }3505 }
34513506
...@@ -3480,7 +3535,22 @@ pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -3480,7 +3535,22 @@ pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
3480 }3535 }
3481}3536}
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 {
3484 const gpa = zcu.gpa;3554 const gpa = zcu.gpa;
34853555
3486 zcu.clearCachedResolvedReferences();3556 zcu.clearCachedResolvedReferences();
...@@ -3500,6 +3570,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -3500,6 +3570,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
3500 .referenced = referenced_unit,3570 .referenced = referenced_unit,
3501 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),3571 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
3502 .src = ref_src,3572 .src = ref_src,
3573 .inline_frame = inline_frame,
3503 };3574 };
35043575
3505 gop.value_ptr.* = @intCast(ref_idx);3576 gop.value_ptr.* = @intCast(ref_idx);
...@@ -3828,7 +3899,10 @@ pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionT...@@ -3828,7 +3899,10 @@ pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionT
38283899
3829pub const ResolvedReference = struct {3900pub const ResolvedReference = struct {
3830 referencer: AnalUnit,3901 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`.
3831 src: LazySrcLoc,3904 src: LazySrcLoc,
3905 inline_frame: InlineReferenceFrame.Index.Optional,
3832};3906};
38333907
3834/// Returns a mapping from an `AnalUnit` to where it is referenced.3908/// Returns a mapping from an `AnalUnit` to where it is referenced.
...@@ -4037,6 +4111,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -4037,6 +4111,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
4037 try unit_queue.put(gpa, ref.referenced, .{4111 try unit_queue.put(gpa, ref.referenced, .{
4038 .referencer = unit,4112 .referencer = unit,
4039 .src = ref.src,4113 .src = ref.src,
4114 .inline_frame = ref.inline_frame,
4040 });4115 });
4041 }4116 }
4042 ref_idx = ref.next;4117 ref_idx = ref.next;
...@@ -4055,6 +4130,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -4055,6 +4130,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
4055 try type_queue.put(gpa, ref.referenced, .{4130 try type_queue.put(gpa, ref.referenced, .{
4056 .referencer = unit,4131 .referencer = unit,
4057 .src = ref.src,4132 .src = ref.src,
4133 .inline_frame = .none,
4058 });4134 });
4059 }4135 }
4060 ref_idx = ref.next;4136 ref_idx = ref.next;