mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 22:04:21 +00:00
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.
This commit is contained in:
parent
70040778fb
commit
d717c96877
4 changed files with 175 additions and 57 deletions
|
|
@ -3681,32 +3681,27 @@ pub fn addModuleErrorMsg(
|
||||||
const ref = maybe_ref orelse break;
|
const ref = maybe_ref orelse break;
|
||||||
const gop = try seen.getOrPut(gpa, ref.referencer);
|
const gop = try seen.getOrPut(gpa, ref.referencer);
|
||||||
if (gop.found_existing) break;
|
if (gop.found_existing) break;
|
||||||
if (ref_traces.items.len < max_references) skip: {
|
if (ref_traces.items.len < max_references) {
|
||||||
const src = ref.src.upgrade(zcu);
|
var last_call_src = ref.src;
|
||||||
const source = try src.file_scope.getSource(gpa);
|
var opt_inline_frame = ref.inline_frame;
|
||||||
const span = try src.span(gpa);
|
while (opt_inline_frame.unwrap()) |inline_frame| {
|
||||||
const loc = std.zig.findLineColumn(source.bytes, span.main);
|
const f = inline_frame.ptr(zcu).*;
|
||||||
const rt_file_path = try src.file_scope.fullPath(gpa);
|
const func_nav = ip.indexToKey(f.callee).func.owner_nav;
|
||||||
defer gpa.free(rt_file_path);
|
const func_name = ip.getNav(func_nav).name.toSlice(ip);
|
||||||
const name = switch (ref.referencer.unwrap()) {
|
try addReferenceTraceFrame(zcu, eb, &ref_traces, func_name, last_call_src, true);
|
||||||
|
last_call_src = f.call_src;
|
||||||
|
opt_inline_frame = f.parent;
|
||||||
|
}
|
||||||
|
const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
|
||||||
.@"comptime" => "comptime",
|
.@"comptime" => "comptime",
|
||||||
.nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
|
.nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
|
||||||
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
|
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
|
||||||
.func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
|
.func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
|
||||||
.memoized_state => break :skip,
|
.memoized_state => null,
|
||||||
};
|
};
|
||||||
try ref_traces.append(gpa, .{
|
if (root_name) |n| {
|
||||||
.decl_name = try eb.addString(name),
|
try addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false);
|
||||||
.src_loc = try eb.addSourceLocation(.{
|
}
|
||||||
.src_path = try eb.addString(rt_file_path),
|
|
||||||
.span_start = span.start,
|
|
||||||
.span_main = span.main,
|
|
||||||
.span_end = span.end,
|
|
||||||
.line = @intCast(loc.line),
|
|
||||||
.column = @intCast(loc.column),
|
|
||||||
.source_line = 0,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
referenced_by = ref.referencer;
|
referenced_by = ref.referencer;
|
||||||
}
|
}
|
||||||
|
|
@ -3786,6 +3781,35 @@ pub fn addModuleErrorMsg(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addReferenceTraceFrame(
|
||||||
|
zcu: *Zcu,
|
||||||
|
eb: *ErrorBundle.Wip,
|
||||||
|
ref_traces: *std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace),
|
||||||
|
name: []const u8,
|
||||||
|
lazy_src: Zcu.LazySrcLoc,
|
||||||
|
inlined: bool,
|
||||||
|
) !void {
|
||||||
|
const gpa = zcu.gpa;
|
||||||
|
const src = lazy_src.upgrade(zcu);
|
||||||
|
const source = try src.file_scope.getSource(gpa);
|
||||||
|
const span = try src.span(gpa);
|
||||||
|
const loc = std.zig.findLineColumn(source.bytes, span.main);
|
||||||
|
const rt_file_path = try src.file_scope.fullPath(gpa);
|
||||||
|
defer gpa.free(rt_file_path);
|
||||||
|
try ref_traces.append(gpa, .{
|
||||||
|
.decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
|
||||||
|
.src_loc = try eb.addSourceLocation(.{
|
||||||
|
.src_path = try eb.addString(rt_file_path),
|
||||||
|
.span_start = span.start,
|
||||||
|
.span_main = span.main,
|
||||||
|
.span_end = span.end,
|
||||||
|
.line = @intCast(loc.line),
|
||||||
|
.column = @intCast(loc.column),
|
||||||
|
.source_line = 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
||||||
const gpa = eb.gpa;
|
const gpa = eb.gpa;
|
||||||
const src_path = try file.fullPath(gpa);
|
const src_path = try file.fullPath(gpa);
|
||||||
|
|
|
||||||
84
src/Sema.zig
84
src/Sema.zig
|
|
@ -448,6 +448,21 @@ pub const Block = struct {
|
||||||
func: InternPool.Index,
|
func: InternPool.Index,
|
||||||
comptime_result: Air.Inst.Ref,
|
comptime_result: Air.Inst.Ref,
|
||||||
merges: Merges,
|
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 {
|
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)) {
|
if (zcu.intern_pool.isFuncBody(val)) {
|
||||||
const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
|
const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
|
||||||
if (try ty.fnHasRuntimeBitsSema(pt)) {
|
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);
|
try zcu.ensureFuncBodyAnalysisQueued(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6615,7 +6630,7 @@ pub fn analyzeExport(
|
||||||
if (options.linkage == .internal)
|
if (options.linkage == .internal)
|
||||||
return;
|
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)) {
|
const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
|
||||||
.variable => |v| v.owner_nav,
|
.variable => |v| v.owner_nav,
|
||||||
|
|
@ -6644,7 +6659,7 @@ pub fn analyzeExport(
|
||||||
return sema.fail(block, src, "export target cannot be extern", .{});
|
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, .{
|
try sema.exports.append(gpa, .{
|
||||||
.opts = options,
|
.opts = options,
|
||||||
|
|
@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||||
.no_embedded_nulls,
|
.no_embedded_nulls,
|
||||||
);
|
);
|
||||||
const nav_index = try sema.lookupIdentifier(block, src, decl_name);
|
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 {
|
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| {
|
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_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
|
||||||
const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
|
const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
|
||||||
try checked_namespaces.put(gpa, sub_ns, {});
|
try checked_namespaces.put(gpa, sub_ns, {});
|
||||||
|
|
@ -7720,8 +7735,8 @@ fn analyzeCall(
|
||||||
var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
|
var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
|
||||||
.call_block = block,
|
.call_block = block,
|
||||||
.call_src = call_src,
|
.call_src = call_src,
|
||||||
|
.func = func_val.?.toIntern(),
|
||||||
.has_comptime_args = false, // unused by error reporting
|
.has_comptime_args = false, // unused by error reporting
|
||||||
.func = .none, // unused by error reporting
|
|
||||||
.comptime_result = .none, // unused by error reporting
|
.comptime_result = .none, // unused by error reporting
|
||||||
.merges = undefined, // unused because we'll never `return`
|
.merges = undefined, // unused because we'll never `return`
|
||||||
} else undefined;
|
} else undefined;
|
||||||
|
|
@ -7999,7 +8014,7 @@ fn analyzeCall(
|
||||||
ref_func: {
|
ref_func: {
|
||||||
const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :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;
|
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());
|
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),
|
.@"comptime" => |index| return Air.internedToRef(index),
|
||||||
.runtime => |index| index,
|
.runtime => |index| index,
|
||||||
.nav_val => |nav| return sema.analyzeNavVal(block, src, nav),
|
.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.
|
// 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 }))) {
|
if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
|
||||||
continue;
|
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);
|
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);
|
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,
|
decl_name: InternPool.NullTerminatedString,
|
||||||
) CompileError!?Air.Inst.Ref {
|
) CompileError!?Air.Inst.Ref {
|
||||||
const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null;
|
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(
|
fn namespaceLookupVal(
|
||||||
|
|
@ -29095,7 +29110,7 @@ fn coerceExtra(
|
||||||
.@"extern" => |e| e.owner_nav,
|
.@"extern" => |e| e.owner_nav,
|
||||||
else => unreachable,
|
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);
|
return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30748,7 +30763,7 @@ fn coerceVarArgParam(
|
||||||
.@"fn" => fn_ptr: {
|
.@"fn" => fn_ptr: {
|
||||||
const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
|
const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
|
||||||
const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;
|
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", .{}),
|
.array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
|
||||||
.float => float: {
|
.float => float: {
|
||||||
|
|
@ -31758,12 +31773,13 @@ fn analyzeNavVal(
|
||||||
src: LazySrcLoc,
|
src: LazySrcLoc,
|
||||||
nav_index: InternPool.Nav.Index,
|
nav_index: InternPool.Nav.Index,
|
||||||
) CompileError!Air.Inst.Ref {
|
) 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);
|
return sema.analyzeLoad(block, src, ref, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addReferenceEntry(
|
fn addReferenceEntry(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
|
opt_block: ?*Block,
|
||||||
src: LazySrcLoc,
|
src: LazySrcLoc,
|
||||||
referenced_unit: AnalUnit,
|
referenced_unit: AnalUnit,
|
||||||
) !void {
|
) !void {
|
||||||
|
|
@ -31771,10 +31787,12 @@ fn addReferenceEntry(
|
||||||
if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;
|
if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;
|
||||||
const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
|
const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
|
||||||
if (gop.found_existing) return;
|
if (gop.found_existing) return;
|
||||||
// TODO: we need to figure out how to model inline calls here.
|
try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
|
||||||
// They aren't references in the analysis sense, but ought to show up in the reference trace!
|
const block = opt_block orelse break :inline_frame .none;
|
||||||
// Would representing inline calls in the reference table cause excessive memory usage?
|
const inlining = block.inlining orelse break :inline_frame .none;
|
||||||
try zcu.addUnitReference(sema.owner, referenced_unit, src);
|
const frame = try inlining.refFrame(zcu);
|
||||||
|
break :inline_frame frame.toOptional();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addTypeReferenceEntry(
|
pub fn addTypeReferenceEntry(
|
||||||
|
|
@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
|
|
||||||
const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
|
const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
|
||||||
try sema.addReferenceEntry(src, unit);
|
try sema.addReferenceEntry(null, src, unit);
|
||||||
try sema.declareDependency(.{ .memoized_state = stage });
|
try sema.declareDependency(.{ .memoized_state = stage });
|
||||||
|
|
||||||
if (pt.zcu.analysis_in_progress.contains(unit)) {
|
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);
|
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 pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
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 },
|
.type => .{ .nav_ty = nav_index },
|
||||||
.fully => .{ .nav_val = 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)) {
|
if (zcu.analysis_in_progress.contains(anal_unit)) {
|
||||||
return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
|
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 {
|
fn analyzeNavRef(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref {
|
||||||
return sema.analyzeNavRefInner(src, nav_index, true);
|
return sema.analyzeNavRefInner(block, src, nav_index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
|
/// 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 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`.
|
/// 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 pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
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: {
|
const nav_index = nav: {
|
||||||
if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
|
if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
|
||||||
// Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
|
// 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.
|
// 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)) {
|
switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
|
||||||
.func => |f| break :nav f.owner_nav,
|
.func => |f| break :nav f.owner_nav,
|
||||||
.@"extern" => |e| break :nav e.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) {
|
if (is_ref) {
|
||||||
try sema.maybeQueueFuncBodyAnalysis(src, nav_index);
|
try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
|
||||||
}
|
}
|
||||||
return Air.internedToRef((try pt.intern(.{ .ptr = .{
|
return Air.internedToRef((try pt.intern(.{ .ptr = .{
|
||||||
.ty = ptr_ty.toIntern(),
|
.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 pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
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.
|
// 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.
|
// 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));
|
const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
|
||||||
if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
|
if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
|
||||||
if (!try nav_ty.fnHasRuntimeBitsSema(pt)) 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);
|
const nav_val = zcu.navValue(nav_index);
|
||||||
if (!ip.isFuncBody(nav_val.toIntern())) return;
|
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());
|
try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31939,8 +31957,8 @@ fn analyzeRef(
|
||||||
|
|
||||||
if (try sema.resolveValue(operand)) |val| {
|
if (try sema.resolveValue(operand)) |val| {
|
||||||
switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||||
.@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav),
|
.@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav),
|
||||||
.func => |f| return sema.analyzeNavRef(src, f.owner_nav),
|
.func => |f| return sema.analyzeNavRef(block, src, f.owner_nav),
|
||||||
else => return uavRef(sema, val.toIntern()),
|
else => return uavRef(sema, val.toIntern()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet(
|
||||||
}
|
}
|
||||||
// In this case we are dealing with the actual InferredErrorSet object that
|
// 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.
|
// 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);
|
try pt.ensureFuncBodyUpToDate(func_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ fn loadComptimePtrInner(
|
||||||
|
|
||||||
const base_val: MutableValue = switch (ptr.base_addr) {
|
const base_val: MutableValue = switch (ptr.base_addr) {
|
||||||
.nav => |nav| val: {
|
.nav => |nav| val: {
|
||||||
try sema.ensureNavResolved(src, nav, .fully);
|
try sema.ensureNavResolved(block, src, nav, .fully);
|
||||||
const val = ip.getNav(nav).status.fully_resolved.val;
|
const val = ip.getNav(nav).status.fully_resolved.val;
|
||||||
switch (ip.indexToKey(val)) {
|
switch (ip.indexToKey(val)) {
|
||||||
.variable => return .runtime_load,
|
.variable => return .runtime_load,
|
||||||
|
|
|
||||||
80
src/Zcu.zig
80
src/Zcu.zig
|
|
@ -215,6 +215,9 @@ all_references: std.ArrayListUnmanaged(Reference) = .empty,
|
||||||
/// Freelist of indices in `all_references`.
|
/// Freelist of indices in `all_references`.
|
||||||
free_references: std.ArrayListUnmanaged(u32) = .empty,
|
free_references: std.ArrayListUnmanaged(u32) = .empty,
|
||||||
|
|
||||||
|
inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame) = .empty,
|
||||||
|
free_inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame.Index) = .empty,
|
||||||
|
|
||||||
/// Key is the `AnalUnit` *performing* the reference. This representation allows
|
/// Key is the `AnalUnit` *performing* the reference. This representation allows
|
||||||
/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
|
/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
|
||||||
/// Value is index into `all_type_reference` of the first reference triggered by the unit.
|
/// Value is index into `all_type_reference` of the first reference triggered by the unit.
|
||||||
|
|
@ -583,6 +586,42 @@ pub const Reference = struct {
|
||||||
next: u32,
|
next: u32,
|
||||||
/// The source location of the reference.
|
/// The source location of the reference.
|
||||||
src: LazySrcLoc,
|
src: LazySrcLoc,
|
||||||
|
/// If not `.none`, this is the index of the `InlineReferenceFrame` which should appear
|
||||||
|
/// between the referencer and `referenced` in the reference trace. These frames represent
|
||||||
|
/// inline calls, which do not create actual references (since they happen in the caller's
|
||||||
|
/// `AnalUnit`), but do show in the reference trace.
|
||||||
|
inline_frame: InlineReferenceFrame.Index.Optional,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const InlineReferenceFrame = struct {
|
||||||
|
/// The inline *callee*; that is, the function which was called inline.
|
||||||
|
/// The *caller* is either `parent`, or else the unit causing the original `Reference`.
|
||||||
|
callee: InternPool.Index,
|
||||||
|
/// The source location of the inline call, in the *caller*.
|
||||||
|
call_src: LazySrcLoc,
|
||||||
|
/// If not `.none`, a frame which should appear directly below this one.
|
||||||
|
/// This will be the "parent" inline call; this frame's `callee` is our caller.
|
||||||
|
parent: InlineReferenceFrame.Index.Optional,
|
||||||
|
|
||||||
|
pub const Index = enum(u32) {
|
||||||
|
_,
|
||||||
|
pub fn ptr(idx: Index, zcu: *Zcu) *InlineReferenceFrame {
|
||||||
|
return &zcu.inline_reference_frames.items[@intFromEnum(idx)];
|
||||||
|
}
|
||||||
|
pub fn toOptional(idx: Index) Optional {
|
||||||
|
return @enumFromInt(@intFromEnum(idx));
|
||||||
|
}
|
||||||
|
pub const Optional = enum(u32) {
|
||||||
|
none = std.math.maxInt(u32),
|
||||||
|
_,
|
||||||
|
pub fn unwrap(opt: Optional) ?Index {
|
||||||
|
return switch (opt) {
|
||||||
|
.none => null,
|
||||||
|
_ => @enumFromInt(@intFromEnum(opt)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const TypeReference = struct {
|
pub const TypeReference = struct {
|
||||||
|
|
@ -3440,12 +3479,28 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||||
var idx = kv.value;
|
var idx = kv.value;
|
||||||
|
|
||||||
while (idx != std.math.maxInt(u32)) {
|
while (idx != std.math.maxInt(u32)) {
|
||||||
|
const ref = zcu.all_references.items[idx];
|
||||||
zcu.free_references.append(gpa, idx) catch {
|
zcu.free_references.append(gpa, idx) catch {
|
||||||
// This space will be reused eventually, so we need not propagate this error.
|
// This space will be reused eventually, so we need not propagate this error.
|
||||||
// Just leak it for now, and let GC reclaim it later on.
|
// Just leak it for now, and let GC reclaim it later on.
|
||||||
break :unit_refs;
|
break :unit_refs;
|
||||||
};
|
};
|
||||||
idx = zcu.all_references.items[idx].next;
|
idx = ref.next;
|
||||||
|
|
||||||
|
var opt_inline_frame = ref.inline_frame;
|
||||||
|
while (opt_inline_frame.unwrap()) |inline_frame| {
|
||||||
|
// The same inline frame could be used multiple times by one unit. We need to
|
||||||
|
// detect this case to avoid adding it to `free_inline_reference_frames` more
|
||||||
|
// than once. We do that by setting `parent` to itself as a marker.
|
||||||
|
if (inline_frame.ptr(zcu).parent == inline_frame.toOptional()) break;
|
||||||
|
zcu.free_inline_reference_frames.append(gpa, inline_frame) catch {
|
||||||
|
// This space will be reused eventually, so we need not propagate this error.
|
||||||
|
// Just leak it for now, and let GC reclaim it later on.
|
||||||
|
break :unit_refs;
|
||||||
|
};
|
||||||
|
opt_inline_frame = inline_frame.ptr(zcu).parent;
|
||||||
|
inline_frame.ptr(zcu).parent = inline_frame.toOptional(); // signal to code above
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3480,7 +3535,22 @@ pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
|
pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index {
|
||||||
|
const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: {
|
||||||
|
_ = try zcu.inline_reference_frames.addOne(zcu.gpa);
|
||||||
|
break :idx @enumFromInt(zcu.inline_reference_frames.items.len - 1);
|
||||||
|
};
|
||||||
|
frame_idx.ptr(zcu).* = frame;
|
||||||
|
return frame_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addUnitReference(
|
||||||
|
zcu: *Zcu,
|
||||||
|
src_unit: AnalUnit,
|
||||||
|
referenced_unit: AnalUnit,
|
||||||
|
ref_src: LazySrcLoc,
|
||||||
|
inline_frame: InlineReferenceFrame.Index.Optional,
|
||||||
|
) Allocator.Error!void {
|
||||||
const gpa = zcu.gpa;
|
const gpa = zcu.gpa;
|
||||||
|
|
||||||
zcu.clearCachedResolvedReferences();
|
zcu.clearCachedResolvedReferences();
|
||||||
|
|
@ -3500,6 +3570,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
|
||||||
.referenced = referenced_unit,
|
.referenced = referenced_unit,
|
||||||
.next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
|
.next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
|
||||||
.src = ref_src,
|
.src = ref_src,
|
||||||
|
.inline_frame = inline_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
gop.value_ptr.* = @intCast(ref_idx);
|
gop.value_ptr.* = @intCast(ref_idx);
|
||||||
|
|
@ -3828,7 +3899,10 @@ pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionT
|
||||||
|
|
||||||
pub const ResolvedReference = struct {
|
pub const ResolvedReference = struct {
|
||||||
referencer: AnalUnit,
|
referencer: AnalUnit,
|
||||||
|
/// If `inline_frame` is not `.none`, this is the *deepest* source location in the chain of
|
||||||
|
/// inline calls. For source locations further up the inline call stack, consult `inline_frame`.
|
||||||
src: LazySrcLoc,
|
src: LazySrcLoc,
|
||||||
|
inline_frame: InlineReferenceFrame.Index.Optional,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns a mapping from an `AnalUnit` to where it is referenced.
|
/// Returns a mapping from an `AnalUnit` to where it is referenced.
|
||||||
|
|
@ -4037,6 +4111,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||||
try unit_queue.put(gpa, ref.referenced, .{
|
try unit_queue.put(gpa, ref.referenced, .{
|
||||||
.referencer = unit,
|
.referencer = unit,
|
||||||
.src = ref.src,
|
.src = ref.src,
|
||||||
|
.inline_frame = ref.inline_frame,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ref_idx = ref.next;
|
ref_idx = ref.next;
|
||||||
|
|
@ -4055,6 +4130,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||||
try type_queue.put(gpa, ref.referenced, .{
|
try type_queue.put(gpa, ref.referenced, .{
|
||||||
.referencer = unit,
|
.referencer = unit,
|
||||||
.src = ref.src,
|
.src = ref.src,
|
||||||
|
.inline_frame = .none,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ref_idx = ref.next;
|
ref_idx = ref.next;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue