aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-05-15 13:18:08 +0100
committermlugg <mlugg@mlugg.co.uk>2025-05-16 13:28:15 +0100
commitd717c96877355090ea3a8e3662a2584eea02445c (patch)
tree3f76da87b8b222f9f103344aaacec8370a8ee3d4 /src/Sema.zig
parent70040778fbde5d7fcbbfc26dbabc700024c538d5 (diff)
downloadzig-d717c96877355090ea3a8e3662a2584eea02445c.tar.gz
zig-d717c96877355090ea3a8e3662a2584eea02445c.zip
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.
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig84
1 files changed, 51 insertions, 33 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index e13aba3349..d267dcdb47 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -448,6 +448,21 @@ pub const Block = struct {
func: InternPool.Index,
comptime_result: Air.Inst.Ref,
merges: Merges,
+ /// Populated lazily by `refFrame`.
+ ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none,
+
+ fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index {
+ if (inlining.ref_frame == .none) {
+ inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{
+ .callee = inlining.func,
+ .call_src = inlining.call_src,
+ .parent = if (inlining.call_block.inlining) |parent_inlining| p: {
+ break :p (try parent_inlining.refFrame(zcu)).toOptional();
+ } else .none,
+ })).toOptional();
+ }
+ return inlining.ref_frame.unwrap().?;
+ }
};
pub const Merges = struct {
@@ -4287,7 +4302,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
if (zcu.intern_pool.isFuncBody(val)) {
const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
if (try ty.fnHasRuntimeBitsSema(pt)) {
- try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val }));
+ try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = val }));
try zcu.ensureFuncBodyAnalysisQueued(val);
}
}
@@ -6615,7 +6630,7 @@ pub fn analyzeExport(
if (options.linkage == .internal)
return;
- try sema.ensureNavResolved(src, orig_nav_index, .fully);
+ try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
.variable => |v| v.owner_nav,
@@ -6644,7 +6659,7 @@ pub fn analyzeExport(
return sema.fail(block, src, "export target cannot be extern", .{});
}
- try sema.maybeQueueFuncBodyAnalysis(src, exported_nav_index);
+ try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index);
try sema.exports.append(gpa, .{
.opts = options,
@@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.no_embedded_nulls,
);
const nav_index = try sema.lookupIdentifier(block, src, decl_name);
- return sema.analyzeNavRef(src, nav_index);
+ return sema.analyzeNavRef(block, src, nav_index);
}
fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -6988,7 +7003,7 @@ fn lookupInNamespace(
}
for (usingnamespaces.items) |sub_ns_nav| {
- try sema.ensureNavResolved(src, sub_ns_nav, .fully);
+ try sema.ensureNavResolved(block, src, sub_ns_nav, .fully);
const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
try checked_namespaces.put(gpa, sub_ns, {});
@@ -7720,8 +7735,8 @@ fn analyzeCall(
var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
.call_block = block,
.call_src = call_src,
+ .func = func_val.?.toIntern(),
.has_comptime_args = false, // unused by error reporting
- .func = .none, // unused by error reporting
.comptime_result = .none, // unused by error reporting
.merges = undefined, // unused because we'll never `return`
} else undefined;
@@ -7999,7 +8014,7 @@ fn analyzeCall(
ref_func: {
const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;
if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;
- try sema.addReferenceEntry(call_src, .wrap(.{ .func = runtime_func_val.toIntern() }));
+ try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = runtime_func_val.toIntern() }));
try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());
}
@@ -17254,7 +17269,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
.@"comptime" => |index| return Air.internedToRef(index),
.runtime => |index| index,
.nav_val => |nav| return sema.analyzeNavVal(block, src, nav),
- .nav_ref => |nav| return sema.analyzeNavRef(src, nav),
+ .nav_ref => |nav| return sema.analyzeNavRef(block, src, nav),
};
// The comptime case is handled already above. Runtime case below.
@@ -18407,7 +18422,7 @@ fn typeInfoNamespaceDecls(
if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
continue;
}
- try sema.ensureNavResolved(src, nav, .fully);
+ try sema.ensureNavResolved(block, src, nav, .fully);
const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);
try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
}
@@ -27932,7 +27947,7 @@ fn namespaceLookupRef(
decl_name: InternPool.NullTerminatedString,
) CompileError!?Air.Inst.Ref {
const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null;
- return try sema.analyzeNavRef(src, nav);
+ return try sema.analyzeNavRef(block, src, nav);
}
fn namespaceLookupVal(
@@ -29095,7 +29110,7 @@ fn coerceExtra(
.@"extern" => |e| e.owner_nav,
else => unreachable,
};
- const inst_as_ptr = try sema.analyzeNavRef(inst_src, fn_nav);
+ const inst_as_ptr = try sema.analyzeNavRef(block, inst_src, fn_nav);
return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
}
@@ -30748,7 +30763,7 @@ fn coerceVarArgParam(
.@"fn" => fn_ptr: {
const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;
- break :fn_ptr try sema.analyzeNavRef(inst_src, fn_nav);
+ break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav);
},
.array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
.float => float: {
@@ -31758,12 +31773,13 @@ fn analyzeNavVal(
src: LazySrcLoc,
nav_index: InternPool.Nav.Index,
) CompileError!Air.Inst.Ref {
- const ref = try sema.analyzeNavRefInner(src, nav_index, false);
+ const ref = try sema.analyzeNavRefInner(block, src, nav_index, false);
return sema.analyzeLoad(block, src, ref, src);
}
fn addReferenceEntry(
sema: *Sema,
+ opt_block: ?*Block,
src: LazySrcLoc,
referenced_unit: AnalUnit,
) !void {
@@ -31771,10 +31787,12 @@ fn addReferenceEntry(
if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;
const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
if (gop.found_existing) return;
- // TODO: we need to figure out how to model inline calls here.
- // They aren't references in the analysis sense, but ought to show up in the reference trace!
- // Would representing inline calls in the reference table cause excessive memory usage?
- try zcu.addUnitReference(sema.owner, referenced_unit, src);
+ try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
+ const block = opt_block orelse break :inline_frame .none;
+ const inlining = block.inlining orelse break :inline_frame .none;
+ const frame = try inlining.refFrame(zcu);
+ break :inline_frame frame.toOptional();
+ });
}
pub fn addTypeReferenceEntry(
@@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
const pt = sema.pt;
const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
- try sema.addReferenceEntry(src, unit);
+ try sema.addReferenceEntry(null, src, unit);
try sema.declareDependency(.{ .memoized_state = stage });
if (pt.zcu.analysis_in_progress.contains(unit)) {
@@ -31802,7 +31820,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
try pt.ensureMemoizedStateUpToDate(stage);
}
-pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
+pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -31825,7 +31843,7 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav
.type => .{ .nav_ty = nav_index },
.fully => .{ .nav_val = nav_index },
});
- try sema.addReferenceEntry(src, anal_unit);
+ try sema.addReferenceEntry(block, src, anal_unit);
if (zcu.analysis_in_progress.contains(anal_unit)) {
return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
@@ -31855,25 +31873,25 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
} }));
}
-fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
- return sema.analyzeNavRefInner(src, nav_index, true);
+fn analyzeNavRef(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
+ return sema.analyzeNavRefInner(block, src, nav_index, true);
}
/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
/// If this pointer will be used directly, `is_ref` must be `true`.
/// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`.
-fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
+fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- try sema.ensureNavResolved(src, orig_nav_index, if (is_ref) .type else .fully);
+ try sema.ensureNavResolved(block, src, orig_nav_index, if (is_ref) .type else .fully);
const nav_index = nav: {
if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
// Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
// We need to resolve the value to know for sure.
- if (is_ref) try sema.ensureNavResolved(src, orig_nav_index, .fully);
+ if (is_ref) try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
.func => |f| break :nav f.owner_nav,
.@"extern" => |e| break :nav e.owner_nav,
@@ -31897,7 +31915,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
},
});
if (is_ref) {
- try sema.maybeQueueFuncBodyAnalysis(src, nav_index);
+ try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
}
return Air.internedToRef((try pt.intern(.{ .ptr = .{
.ty = ptr_ty.toIntern(),
@@ -31906,7 +31924,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
} })));
}
-fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
+fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -31914,16 +31932,16 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPoo
// To avoid forcing too much resolution, let's first resolve the type, and check if it's a function.
// If it is, we can resolve the *value*, and queue analysis as needed.
- try sema.ensureNavResolved(src, nav_index, .type);
+ try sema.ensureNavResolved(block, src, nav_index, .type);
const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;
- try sema.ensureNavResolved(src, nav_index, .fully);
+ try sema.ensureNavResolved(block, src, nav_index, .fully);
const nav_val = zcu.navValue(nav_index);
if (!ip.isFuncBody(nav_val.toIntern())) return;
- try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
+ try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
}
@@ -31939,8 +31957,8 @@ fn analyzeRef(
if (try sema.resolveValue(operand)) |val| {
switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav),
- .func => |f| return sema.analyzeNavRef(src, f.owner_nav),
+ .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav),
+ .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav),
else => return uavRef(sema, val.toIntern()),
}
}
@@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet(
}
// In this case we are dealing with the actual InferredErrorSet object that
// corresponds to the function, not one created to track an inline/comptime call.
- try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index }));
+ try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = func_index }));
try pt.ensureFuncBodyUpToDate(func_index);
}