| ... | @@ -7734,123 +7734,117 @@ fn analyzeCall( | ... | @@ -7734,123 +7734,117 @@ fn analyzeCall( |
| 7734 | } })); | 7734 | } })); |
| 7735 | } | 7735 | } |
| 7736 | | 7736 | |
| 7737 | // This `res2` is here instead of directly breaking from `res` due to a stage1 | 7737 | memoize: { |
| 7738 | // bug generating invalid LLVM IR. | 7738 | if (!should_memoize) break :memoize; |
| 7739 | const res2: Air.Inst.Ref = res2: { | 7739 | if (!is_comptime_call) break :memoize; |
| 7740 | memoize: { | 7740 | const memoized_call_index = ip.getIfExists(.{ |
| 7741 | if (!should_memoize) break :memoize; | 7741 | .memoized_call = .{ |
| 7742 | if (!is_comptime_call) break :memoize; | 7742 | .func = module_fn_index, |
| 7743 | const memoized_call_index = ip.getIfExists(.{ | 7743 | .arg_values = memoized_arg_values, |
| 7744 | .memoized_call = .{ | 7744 | .result = undefined, // ignored by hash+eql |
| 7745 | .func = module_fn_index, | 7745 | .branch_count = undefined, // ignored by hash+eql |
| 7746 | .arg_values = memoized_arg_values, | 7746 | }, |
| 7747 | .result = undefined, // ignored by hash+eql | 7747 | }) orelse break :memoize; |
| 7748 | .branch_count = undefined, // ignored by hash+eql | 7748 | const memoized_call = ip.indexToKey(memoized_call_index).memoized_call; |
| 7749 | }, | 7749 | if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) { |
| 7750 | }) orelse break :memoize; | 7750 | // Let the call play out se we get the correct source location for the |
| 7751 | const memoized_call = ip.indexToKey(memoized_call_index).memoized_call; | 7751 | // "evaluation exceeded X backwards branches" error. |
| 7752 | if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) { | 7752 | break :memoize; |
| 7753 | // Let the call play out se we get the correct source location for the | | |
| 7754 | // "evaluation exceeded X backwards branches" error. | | |
| 7755 | break :memoize; | | |
| 7756 | } | | |
| 7757 | sema.branch_count += memoized_call.branch_count; | | |
| 7758 | break :res2 Air.internedToRef(memoized_call.result); | | |
| 7759 | } | 7753 | } |
| | 7754 | sema.branch_count += memoized_call.branch_count; |
| | 7755 | break :res Air.internedToRef(memoized_call.result); |
| | 7756 | } |
| 7760 | | 7757 | |
| 7761 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); | 7758 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); |
| 7762 | if (!is_comptime_call and !block.is_typeof) { | 7759 | if (!is_comptime_call and !block.is_typeof) { |
| 7763 | const zir_tags = sema.code.instructions.items(.tag); | 7760 | const zir_tags = sema.code.instructions.items(.tag); |
| 7764 | for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { | 7761 | for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { |
| 7765 | .param, .param_comptime => { | 7762 | .param, .param_comptime => { |
| 7766 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok; | 7763 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok; |
| 7767 | const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); | 7764 | const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); |
| 7768 | const param_name = sema.code.nullTerminatedString(extra.data.name); | 7765 | const param_name = sema.code.nullTerminatedString(extra.data.name); |
| 7769 | const inst = sema.inst_map.get(param).?; | 7766 | const inst = sema.inst_map.get(param).?; |
| 7770 | | 7767 | |
| 7771 | try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); | 7768 | try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); |
| 7772 | }, | 7769 | }, |
| 7773 | .param_anytype, .param_anytype_comptime => { | 7770 | .param_anytype, .param_anytype_comptime => { |
| 7774 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok; | 7771 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok; |
| 7775 | const param_name = inst_data.get(sema.code); | 7772 | const param_name = inst_data.get(sema.code); |
| 7776 | const inst = sema.inst_map.get(param).?; | 7773 | const inst = sema.inst_map.get(param).?; |
| 7777 | | 7774 | |
| 7778 | try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); | 7775 | try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); |
| 7779 | }, | 7776 | }, |
| 7780 | else => continue, | 7777 | else => continue, |
| 7781 | }; | 7778 | }; |
| 7782 | } | 7779 | } |
| 7783 | | 7780 | |
| 7784 | if (is_comptime_call and ensure_result_used) { | 7781 | if (is_comptime_call and ensure_result_used) { |
| 7785 | try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src); | 7782 | try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src); |
| 7786 | } | 7783 | } |
| 7787 | | 7784 | |
| 7788 | if (is_comptime_call or block.is_typeof) { | 7785 | if (is_comptime_call or block.is_typeof) { |
| 7789 | // Save the error trace as our first action in the function | 7786 | // Save the error trace as our first action in the function |
| 7790 | // to match the behavior of runtime function calls. | 7787 | // to match the behavior of runtime function calls. |
| 7791 | const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block); | 7788 | const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block); |
| 7792 | sema.error_return_trace_index_on_fn_entry = error_return_trace_index; | 7789 | sema.error_return_trace_index_on_fn_entry = error_return_trace_index; |
| 7793 | child_block.error_return_trace_index = error_return_trace_index; | 7790 | child_block.error_return_trace_index = error_return_trace_index; |
| 7794 | } | 7791 | } |
| 7795 | | 7792 | |
| 7796 | // We temporarily set `allow_memoize` to `true` to track this comptime call. | 7793 | // We temporarily set `allow_memoize` to `true` to track this comptime call. |
| 7797 | // It is restored after this call finishes analysis, so that a caller may | 7794 | // It is restored after this call finishes analysis, so that a caller may |
| 7798 | // know whether an in-progress call (containing this call) may be memoized. | 7795 | // know whether an in-progress call (containing this call) may be memoized. |
| 7799 | const old_allow_memoize = sema.allow_memoize; | 7796 | const old_allow_memoize = sema.allow_memoize; |
| 7800 | defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize; | 7797 | defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize; |
| 7801 | sema.allow_memoize = true; | 7798 | sema.allow_memoize = true; |
| 7802 | | 7799 | |
| 7803 | // Store the current eval branch count so we can find out how many eval branches | 7800 | // Store the current eval branch count so we can find out how many eval branches |
| 7804 | // the comptime call caused. | 7801 | // the comptime call caused. |
| 7805 | const old_branch_count = sema.branch_count; | 7802 | const old_branch_count = sema.branch_count; |
| 7806 | | 7803 | |
| 7807 | const result = result: { | 7804 | const result = result: { |
| 7808 | sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { | 7805 | sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { |
| 7809 | error.ComptimeReturn => break :result inlining.comptime_result, | 7806 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 7810 | else => |e| return e, | 7807 | else => |e| return e, |
| 7811 | }; | | |
| 7812 | break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope); | | |
| 7813 | }; | 7808 | }; |
| | 7809 | break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope); |
| | 7810 | }; |
| 7814 | | 7811 | |
| 7815 | if (is_comptime_call) { | 7812 | if (is_comptime_call) { |
| 7816 | const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined); | 7813 | const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined); |
| 7817 | const result_interned = result_val.toIntern(); | 7814 | const result_interned = result_val.toIntern(); |
| 7818 | | 7815 | |
| 7819 | // Transform ad-hoc inferred error set types into concrete error sets. | 7816 | // Transform ad-hoc inferred error set types into concrete error sets. |
| 7820 | const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned); | 7817 | const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned); |
| 7821 | | 7818 | |
| 7822 | // If the result can mutate comptime vars, we must not memoize it, as it contains | 7819 | // If the result can mutate comptime vars, we must not memoize it, as it contains |
| 7823 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. | 7820 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. |
| 7824 | // TODO: check whether any external comptime memory was mutated by the | 7821 | // TODO: check whether any external comptime memory was mutated by the |
| 7825 | // comptime function call. If so, then do not memoize the call here. | 7822 | // comptime function call. If so, then do not memoize the call here. |
| 7826 | if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) { | 7823 | if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) { |
| 7827 | _ = try pt.intern(.{ .memoized_call = .{ | 7824 | _ = try pt.intern(.{ .memoized_call = .{ |
| 7828 | .func = module_fn_index, | 7825 | .func = module_fn_index, |
| 7829 | .arg_values = memoized_arg_values, | 7826 | .arg_values = memoized_arg_values, |
| 7830 | .result = result_transformed, | 7827 | .result = result_transformed, |
| 7831 | .branch_count = sema.branch_count - old_branch_count, | 7828 | .branch_count = sema.branch_count - old_branch_count, |
| 7832 | } }); | 7829 | } }); |
| 7833 | } | | |
| 7834 | | | |
| 7835 | break :res2 Air.internedToRef(result_transformed); | | |
| 7836 | } | 7830 | } |
| 7837 | | 7831 | |
| 7838 | if (try sema.resolveValue(result)) |result_val| { | 7832 | break :res Air.internedToRef(result_transformed); |
| 7839 | const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern()); | 7833 | } |
| 7840 | break :res2 Air.internedToRef(result_transformed); | | |
| 7841 | } | | |
| 7842 | | 7834 | |
| 7843 | const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern()); | 7835 | if (try sema.resolveValue(result)) |result_val| { |
| 7844 | if (new_ty != .none) { | 7836 | const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern()); |
| 7845 | // TODO: mutate in place the previous instruction if possible | 7837 | break :res Air.internedToRef(result_transformed); |
| 7846 | // rather than adding a bitcast instruction. | 7838 | } |
| 7847 | break :res2 try block.addBitCast(Type.fromInterned(new_ty), result); | | |
| 7848 | } | | |
| 7849 | | 7839 | |
| 7850 | break :res2 result; | 7840 | const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern()); |
| 7851 | }; | 7841 | if (new_ty != .none) { |
| | 7842 | // TODO: mutate in place the previous instruction if possible |
| | 7843 | // rather than adding a bitcast instruction. |
| | 7844 | break :res try block.addBitCast(Type.fromInterned(new_ty), result); |
| | 7845 | } |
| 7852 | | 7846 | |
| 7853 | break :res res2; | 7847 | break :res result; |
| 7854 | } else res: { | 7848 | } else res: { |
| 7855 | assert(!func_ty_info.is_generic); | 7849 | assert(!func_ty_info.is_generic); |
| 7856 | | 7850 | |