| ... | @@ -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, |
| 453 | | 451 | |
| | 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 reporting | 7745 | .is_generic_instantiation = true, // this allows the following fields to be `undefined` |
| 7740 | .comptime_result = .none, // unused by error reporting | 7746 | .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; |
| 7743 | | 7750 | |
| 7744 | // This is the block in which we evaluate generic function components: that is, generic parameter | 7751 | // 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 | }; |
| 19455 | | 19466 | |
| 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; |