From 429672705090f073adedb885057a4603eaf66c95 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sat, 10 May 2025 18:22:43 +0100 Subject: [PATCH] Sema: improve "called from here" notes To an average user, it may be unclear why these notes are not just in the reference trace; that's because they are more important, because they are inline calls through which comptime values may propagate. There are now 3 possible wordings for this note: * "called at comptime here" * "called inline here" * "generic function instantiated here" An alternative could be these wordings: * "while analyzing comptime call here" * "while analyzing inline call here" * "while analyzing generic instantiation here" I'm not sure which is better -- but this commit is certainly better than status quo. --- src/Sema.zig | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index d267dcdb473ec9f0565c70b29d8c57a93bb4eaed..41453d2bba3c01c85fec9ada4589e35e1f035c3c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -444,13 +444,19 @@ pub const Block = struct { pub const Inlining = struct { call_block: *Block, call_src: LazySrcLoc, - has_comptime_args: bool, func: InternPool.Index, - comptime_result: Air.Inst.Ref, - merges: Merges, + /// Populated lazily by `refFrame`. ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none, + /// If `true`, the following fields are `undefined`. This doesn't represent a true inline + /// call, but rather a generic call analyzing the instantiation's generic type bodies. + is_generic_instantiation: bool, + + has_comptime_args: bool, + comptime_result: Air.Inst.Ref, + merges: Merges, + fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index { if (inlining.ref_frame == .none) { inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{ @@ -2604,12 +2610,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg if (block) |start_block| { var block_it = start_block; while (block_it.inlining) |inlining| { - try sema.errNote( - inlining.call_src, - err_msg, - "called from here", - .{}, - ); + const note_str = note: { + if (inlining.is_generic_instantiation) break :note "generic function instantiated here"; + if (inlining.call_block.isComptime()) break :note "called at comptime here"; + break :note "called inline here"; + }; + try sema.errNote(inlining.call_src, err_msg, "{s}", .{note_str}); block_it = inlining.call_block; } } @@ -7736,9 +7742,10 @@ fn analyzeCall( .call_block = block, .call_src = call_src, .func = func_val.?.toIntern(), - .has_comptime_args = false, // unused by error reporting - .comptime_result = .none, // unused by error reporting - .merges = undefined, // unused because we'll never `return` + .is_generic_instantiation = true, // this allows the following fields to be `undefined` + .has_comptime_args = undefined, + .comptime_result = undefined, + .merges = undefined, } else undefined; // This is the block in which we evaluate generic function components: that is, generic parameter @@ -8216,10 +8223,11 @@ fn analyzeCall( var inlining: Block.Inlining = .{ .call_block = block, .call_src = call_src, + .func = func_val.?.toIntern(), + .is_generic_instantiation = false, .has_comptime_args = for (args) |a| { if (try sema.isComptimeKnown(a)) break true; } else false, - .func = func_val.?.toIntern(), .comptime_result = undefined, .merges = .{ .block_inst = block_inst, @@ -8250,7 +8258,10 @@ fn analyzeCall( if (!inlining.has_comptime_args) { var block_it = block; while (block_it.inlining) |parent_inlining| { - if (!parent_inlining.has_comptime_args and parent_inlining.func == func_val.?.toIntern()) { + if (!parent_inlining.is_generic_instantiation and + !parent_inlining.has_comptime_args and + parent_inlining.func == func_val.?.toIntern()) + { return sema.fail(block, call_src, "inline call is recursive", .{}); } block_it = parent_inlining.call_block; @@ -19454,6 +19465,7 @@ fn analyzeRet( }; if (block.inlining) |inlining| { + assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr if (block.isComptime()) { const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); inlining.comptime_result = operand; -- 2.54.0