authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-10 18:22:43+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-16 13:28:15+01:00
log429672705090f073adedb885057a4603eaf66c95
tree0776a0d58f9550258bbd3ebcc3232f61663b7764
parentd717c96877355090ea3a8e3662a2584eea02445c
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 26 insertions(+), 14 deletions(-)

src/Sema.zig+26-14
...@@ -444,13 +444,19 @@ pub const Block = struct {...@@ -444,13 +444,19 @@ pub const Block = struct {
444 pub const Inlining = struct {444 pub const Inlining = struct {
445 call_block: *Block,445 call_block: *Block,
446 call_src: LazySrcLoc,446 call_src: LazySrcLoc,
447 has_comptime_args: bool,
448 func: InternPool.Index,447 func: InternPool.Index,
449 comptime_result: Air.Inst.Ref,448
450 merges: Merges,
451 /// Populated lazily by `refFrame`.449 /// Populated lazily by `refFrame`.
452 ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none,450 ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none,
453451
452 /// If `true`, the following fields are `undefined`. This doesn't represent a true inline
453 /// call, but rather a generic call analyzing the instantiation's generic type bodies.
454 is_generic_instantiation: bool,
455
456 has_comptime_args: bool,
457 comptime_result: Air.Inst.Ref,
458 merges: Merges,
459
454 fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index {460 fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index {
455 if (inlining.ref_frame == .none) {461 if (inlining.ref_frame == .none) {
456 inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{462 inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{
...@@ -2604,12 +2610,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg...@@ -2604,12 +2610,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
2604 if (block) |start_block| {2610 if (block) |start_block| {
2605 var block_it = start_block;2611 var block_it = start_block;
2606 while (block_it.inlining) |inlining| {2612 while (block_it.inlining) |inlining| {
2607 try sema.errNote(2613 const note_str = note: {
2608 inlining.call_src,2614 if (inlining.is_generic_instantiation) break :note "generic function instantiated here";
2609 err_msg,2615 if (inlining.call_block.isComptime()) break :note "called at comptime here";
2610 "called from here",2616 break :note "called inline here";
2611 .{},2617 };
2612 );2618 try sema.errNote(inlining.call_src, err_msg, "{s}", .{note_str});
2613 block_it = inlining.call_block;2619 block_it = inlining.call_block;
2614 }2620 }
2615 }2621 }
...@@ -7736,9 +7742,10 @@ fn analyzeCall(...@@ -7736,9 +7742,10 @@ fn analyzeCall(
7736 .call_block = block,7742 .call_block = block,
7737 .call_src = call_src,7743 .call_src = call_src,
7738 .func = func_val.?.toIntern(),7744 .func = func_val.?.toIntern(),
7739 .has_comptime_args = false, // unused by error reporting7745 .is_generic_instantiation = true, // this allows the following fields to be `undefined`
7740 .comptime_result = .none, // unused by error reporting7746 .has_comptime_args = undefined,
7741 .merges = undefined, // unused because we'll never `return`7747 .comptime_result = undefined,
7748 .merges = undefined,
7742 } else undefined;7749 } else undefined;
77437750
7744 // This is the block in which we evaluate generic function components: that is, generic parameter7751 // This is the block in which we evaluate generic function components: that is, generic parameter
...@@ -8216,10 +8223,11 @@ fn analyzeCall(...@@ -8216,10 +8223,11 @@ fn analyzeCall(
8216 var inlining: Block.Inlining = .{8223 var inlining: Block.Inlining = .{
8217 .call_block = block,8224 .call_block = block,
8218 .call_src = call_src,8225 .call_src = call_src,
8226 .func = func_val.?.toIntern(),
8227 .is_generic_instantiation = false,
8219 .has_comptime_args = for (args) |a| {8228 .has_comptime_args = for (args) |a| {
8220 if (try sema.isComptimeKnown(a)) break true;8229 if (try sema.isComptimeKnown(a)) break true;
8221 } else false,8230 } else false,
8222 .func = func_val.?.toIntern(),
8223 .comptime_result = undefined,8231 .comptime_result = undefined,
8224 .merges = .{8232 .merges = .{
8225 .block_inst = block_inst,8233 .block_inst = block_inst,
...@@ -8250,7 +8258,10 @@ fn analyzeCall(...@@ -8250,7 +8258,10 @@ fn analyzeCall(
8250 if (!inlining.has_comptime_args) {8258 if (!inlining.has_comptime_args) {
8251 var block_it = block;8259 var block_it = block;
8252 while (block_it.inlining) |parent_inlining| {8260 while (block_it.inlining) |parent_inlining| {
8253 if (!parent_inlining.has_comptime_args and parent_inlining.func == func_val.?.toIntern()) {8261 if (!parent_inlining.is_generic_instantiation and
8262 !parent_inlining.has_comptime_args and
8263 parent_inlining.func == func_val.?.toIntern())
8264 {
8254 return sema.fail(block, call_src, "inline call is recursive", .{});8265 return sema.fail(block, call_src, "inline call is recursive", .{});
8255 }8266 }
8256 block_it = parent_inlining.call_block;8267 block_it = parent_inlining.call_block;
...@@ -19454,6 +19465,7 @@ fn analyzeRet(...@@ -19454,6 +19465,7 @@ fn analyzeRet(
19454 };19465 };
1945519466
19456 if (block.inlining) |inlining| {19467 if (block.inlining) |inlining| {
19468 assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr
19457 if (block.isComptime()) {19469 if (block.isComptime()) {
19458 const ret_val = try sema.resolveConstValue(block, operand_src, operand, null);19470 const ret_val = try sema.resolveConstValue(block, operand_src, operand, null);
19459 inlining.comptime_result = operand;19471 inlining.comptime_result = operand;