| ... | ... | @@ -5613,84 +5613,39 @@ fn analyzeCall( |
| 5613 | 5613 | // which means its parameter type expressions must be resolved in order and used |
| 5614 | 5614 | // to successively coerce the arguments. |
| 5615 | 5615 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); |
| 5616 | | const zir_tags = sema.code.instructions.items(.tag); |
| 5617 | 5616 | var arg_i: usize = 0; |
| 5618 | | for (fn_info.param_body) |inst| switch (zir_tags[inst]) { |
| 5619 | | .param, .param_comptime => { |
| 5620 | | // Evaluate the parameter type expression now that previous ones have |
| 5621 | | // been mapped, and coerce the corresponding argument to it. |
| 5622 | | const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; |
| 5623 | | const param_src = pl_tok.src(); |
| 5624 | | const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); |
| 5625 | | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 5626 | | const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst); |
| 5627 | | const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst); |
| 5628 | | new_fn_info.param_types[arg_i] = param_ty; |
| 5629 | | const arg_src = call_src; // TODO: better source location |
| 5630 | | const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src); |
| 5631 | | try sema.inst_map.putNoClobber(gpa, inst, casted_arg); |
| 5632 | | |
| 5633 | | if (is_comptime_call) { |
| 5634 | | // TODO explain why function is being called at comptime |
| 5635 | | const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known"); |
| 5636 | | switch (arg_val.tag()) { |
| 5637 | | .generic_poison, .generic_poison_type => { |
| 5638 | | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 5639 | | // parameter or return type. |
| 5640 | | return error.GenericPoison; |
| 5641 | | }, |
| 5642 | | else => { |
| 5643 | | // Needed so that lazy values do not trigger |
| 5644 | | // assertion due to type not being resolved |
| 5645 | | // when the hash function is called. |
| 5646 | | try sema.resolveLazyValue(&child_block, arg_src, arg_val); |
| 5647 | | }, |
| 5648 | | } |
| 5649 | | should_memoize = should_memoize and !arg_val.canMutateComptimeVarState(); |
| 5650 | | memoized_call_key.args[arg_i] = .{ |
| 5651 | | .ty = param_ty, |
| 5652 | | .val = arg_val, |
| 5653 | | }; |
| 5654 | | } |
| 5655 | | |
| 5656 | | arg_i += 1; |
| 5657 | | continue; |
| 5658 | | }, |
| 5659 | | .param_anytype, .param_anytype_comptime => { |
| 5660 | | // No coercion needed. |
| 5661 | | const uncasted_arg = uncasted_args[arg_i]; |
| 5662 | | new_fn_info.param_types[arg_i] = sema.typeOf(uncasted_arg); |
| 5663 | | try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg); |
| 5664 | | |
| 5665 | | if (is_comptime_call) { |
| 5666 | | const arg_src = call_src; // TODO: better source location |
| 5667 | | // TODO explain why function is being called at comptime |
| 5668 | | const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known"); |
| 5669 | | switch (arg_val.tag()) { |
| 5670 | | .generic_poison, .generic_poison_type => { |
| 5671 | | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 5672 | | // parameter or return type. |
| 5673 | | return error.GenericPoison; |
| 5674 | | }, |
| 5675 | | else => { |
| 5676 | | // Needed so that lazy values do not trigger |
| 5677 | | // assertion due to type not being resolved |
| 5678 | | // when the hash function is called. |
| 5679 | | try sema.resolveLazyValue(&child_block, arg_src, arg_val); |
| 5680 | | }, |
| 5681 | | } |
| 5682 | | should_memoize = should_memoize and !arg_val.canMutateComptimeVarState(); |
| 5683 | | memoized_call_key.args[arg_i] = .{ |
| 5684 | | .ty = sema.typeOf(uncasted_arg), |
| 5685 | | .val = arg_val, |
| 5686 | | }; |
| 5687 | | } |
| 5688 | | |
| 5689 | | arg_i += 1; |
| 5690 | | continue; |
| 5691 | | }, |
| 5692 | | else => continue, |
| 5693 | | }; |
| 5617 | for (fn_info.param_body) |inst| { |
| 5618 | sema.analyzeInlineCallArg( |
| 5619 | &child_block, |
| 5620 | .unneeded, |
| 5621 | inst, |
| 5622 | new_fn_info, |
| 5623 | &arg_i, |
| 5624 | uncasted_args, |
| 5625 | is_comptime_call, |
| 5626 | &should_memoize, |
| 5627 | memoized_call_key, |
| 5628 | ) catch |err| switch (err) { |
| 5629 | error.NeededSourceLocation => { |
| 5630 | const decl = sema.mod.declPtr(block.src_decl); |
| 5631 | try sema.analyzeInlineCallArg( |
| 5632 | // Intentionally use the wrong block here since we know it's |
| 5633 | // going to fail and `argSrc` is relative to `block.src_decl`. |
| 5634 | block, |
| 5635 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i), |
| 5636 | inst, |
| 5637 | new_fn_info, |
| 5638 | &arg_i, |
| 5639 | uncasted_args, |
| 5640 | is_comptime_call, |
| 5641 | &should_memoize, |
| 5642 | memoized_call_key, |
| 5643 | ); |
| 5644 | return error.AnalysisFail; |
| 5645 | }, |
| 5646 | else => |e| return e, |
| 5647 | }; |
| 5648 | } |
| 5694 | 5649 | |
| 5695 | 5650 | // In case it is a generic function with an expression for the return type that depends |
| 5696 | 5651 | // on parameters, we must now do the same for the return type as we just did with |
| ... | ... | @@ -5746,6 +5701,7 @@ fn analyzeCall( |
| 5746 | 5701 | if (!is_comptime_call) { |
| 5747 | 5702 | try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin); |
| 5748 | 5703 | |
| 5704 | const zir_tags = sema.code.instructions.items(.tag); |
| 5749 | 5705 | for (fn_info.param_body) |param| switch (zir_tags[param]) { |
| 5750 | 5706 | .param, .param_comptime => { |
| 5751 | 5707 | const inst_data = sema.code.instructions.items(.data)[param].pl_tok; |
| ... | ... | @@ -5826,11 +5782,26 @@ fn analyzeCall( |
| 5826 | 5782 | |
| 5827 | 5783 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); |
| 5828 | 5784 | for (uncasted_args) |uncasted_arg, i| { |
| 5829 | | const arg_src = call_src; // TODO: better source location |
| 5830 | 5785 | if (i < fn_params_len) { |
| 5831 | 5786 | const param_ty = func_ty.fnParamType(i); |
| 5832 | | try sema.resolveTypeFully(block, arg_src, param_ty); |
| 5833 | | args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 5787 | args[i] = sema.analyzeCallArg( |
| 5788 | block, |
| 5789 | .unneeded, |
| 5790 | param_ty, |
| 5791 | uncasted_arg, |
| 5792 | ) catch |err| switch (err) { |
| 5793 | error.NeededSourceLocation => { |
| 5794 | const decl = sema.mod.declPtr(block.src_decl); |
| 5795 | _ = try sema.analyzeCallArg( |
| 5796 | block, |
| 5797 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i), |
| 5798 | param_ty, |
| 5799 | uncasted_arg, |
| 5800 | ); |
| 5801 | return error.AnalysisFail; |
| 5802 | }, |
| 5803 | else => |e| return e, |
| 5804 | }; |
| 5834 | 5805 | } else { |
| 5835 | 5806 | args[i] = uncasted_arg; |
| 5836 | 5807 | } |
| ... | ... | @@ -5862,6 +5833,136 @@ fn analyzeCall( |
| 5862 | 5833 | return result; |
| 5863 | 5834 | } |
| 5864 | 5835 | |
| 5836 | fn analyzeInlineCallArg( |
| 5837 | sema: *Sema, |
| 5838 | block: *Block, |
| 5839 | arg_src: LazySrcLoc, |
| 5840 | inst: Zir.Inst.Index, |
| 5841 | new_fn_info: Type.Payload.Function.Data, |
| 5842 | arg_i: *usize, |
| 5843 | uncasted_args: []const Air.Inst.Ref, |
| 5844 | is_comptime_call: bool, |
| 5845 | should_memoize: *bool, |
| 5846 | memoized_call_key: Module.MemoizedCall.Key, |
| 5847 | ) !void { |
| 5848 | const zir_tags = sema.code.instructions.items(.tag); |
| 5849 | switch (zir_tags[inst]) { |
| 5850 | .param, .param_comptime => { |
| 5851 | // Evaluate the parameter type expression now that previous ones have |
| 5852 | // been mapped, and coerce the corresponding argument to it. |
| 5853 | const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; |
| 5854 | const param_src = pl_tok.src(); |
| 5855 | const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); |
| 5856 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 5857 | const param_ty_inst = try sema.resolveBody(block, param_body, inst); |
| 5858 | const param_ty = try sema.analyzeAsType(block, param_src, param_ty_inst); |
| 5859 | new_fn_info.param_types[arg_i.*] = param_ty; |
| 5860 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 5861 | if (try sema.typeRequiresComptime(block, arg_src, param_ty)) { |
| 5862 | _ = try sema.resolveConstMaybeUndefVal(block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known"); |
| 5863 | } |
| 5864 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 5865 | try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg); |
| 5866 | |
| 5867 | if (is_comptime_call) { |
| 5868 | // TODO explain why function is being called at comptime |
| 5869 | const arg_val = try sema.resolveConstMaybeUndefVal(block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known"); |
| 5870 | switch (arg_val.tag()) { |
| 5871 | .generic_poison, .generic_poison_type => { |
| 5872 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 5873 | // parameter or return type. |
| 5874 | return error.GenericPoison; |
| 5875 | }, |
| 5876 | else => { |
| 5877 | // Needed so that lazy values do not trigger |
| 5878 | // assertion due to type not being resolved |
| 5879 | // when the hash function is called. |
| 5880 | try sema.resolveLazyValue(block, arg_src, arg_val); |
| 5881 | }, |
| 5882 | } |
| 5883 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); |
| 5884 | memoized_call_key.args[arg_i.*] = .{ |
| 5885 | .ty = param_ty, |
| 5886 | .val = arg_val, |
| 5887 | }; |
| 5888 | } |
| 5889 | |
| 5890 | arg_i.* += 1; |
| 5891 | }, |
| 5892 | .param_anytype, .param_anytype_comptime => { |
| 5893 | // No coercion needed. |
| 5894 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 5895 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); |
| 5896 | try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg); |
| 5897 | |
| 5898 | if (is_comptime_call) { |
| 5899 | // TODO explain why function is being called at comptime |
| 5900 | const arg_val = try sema.resolveConstMaybeUndefVal(block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known"); |
| 5901 | switch (arg_val.tag()) { |
| 5902 | .generic_poison, .generic_poison_type => { |
| 5903 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 5904 | // parameter or return type. |
| 5905 | return error.GenericPoison; |
| 5906 | }, |
| 5907 | else => { |
| 5908 | // Needed so that lazy values do not trigger |
| 5909 | // assertion due to type not being resolved |
| 5910 | // when the hash function is called. |
| 5911 | try sema.resolveLazyValue(block, arg_src, arg_val); |
| 5912 | }, |
| 5913 | } |
| 5914 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); |
| 5915 | memoized_call_key.args[arg_i.*] = .{ |
| 5916 | .ty = sema.typeOf(uncasted_arg), |
| 5917 | .val = arg_val, |
| 5918 | }; |
| 5919 | } |
| 5920 | |
| 5921 | arg_i.* += 1; |
| 5922 | }, |
| 5923 | else => {}, |
| 5924 | } |
| 5925 | } |
| 5926 | |
| 5927 | fn analyzeCallArg( |
| 5928 | sema: *Sema, |
| 5929 | block: *Block, |
| 5930 | arg_src: LazySrcLoc, |
| 5931 | param_ty: Type, |
| 5932 | uncasted_arg: Air.Inst.Ref, |
| 5933 | ) !Air.Inst.Ref { |
| 5934 | try sema.resolveTypeFully(block, arg_src, param_ty); |
| 5935 | return sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 5936 | } |
| 5937 | |
| 5938 | fn analyzeGenericCallArg( |
| 5939 | sema: *Sema, |
| 5940 | block: *Block, |
| 5941 | arg_src: LazySrcLoc, |
| 5942 | uncasted_arg: Air.Inst.Ref, |
| 5943 | comptime_arg: TypedValue, |
| 5944 | runtime_args: []Air.Inst.Ref, |
| 5945 | new_fn_info: Type.Payload.Function.Data, |
| 5946 | runtime_i: *u32, |
| 5947 | ) !void { |
| 5948 | const is_runtime = comptime_arg.val.tag() == .generic_poison and |
| 5949 | comptime_arg.ty.hasRuntimeBits() and |
| 5950 | !(try sema.typeRequiresComptime(block, arg_src, comptime_arg.ty)); |
| 5951 | if (is_runtime) { |
| 5952 | const param_ty = new_fn_info.param_types[runtime_i.*]; |
| 5953 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 5954 | try sema.queueFullTypeResolution(param_ty); |
| 5955 | runtime_args[runtime_i.*] = casted_arg; |
| 5956 | runtime_i.* += 1; |
| 5957 | } |
| 5958 | } |
| 5959 | |
| 5960 | fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value { |
| 5961 | const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"); |
| 5962 | try sema.resolveLazyValue(block, arg_src, arg_val); |
| 5963 | return arg_val; |
| 5964 | } |
| 5965 | |
| 5865 | 5966 | fn instantiateGenericCall( |
| 5866 | 5967 | sema: *Sema, |
| 5867 | 5968 | block: *Block, |
| ... | ... | @@ -5927,10 +6028,16 @@ fn instantiateGenericCall( |
| 5927 | 6028 | } |
| 5928 | 6029 | |
| 5929 | 6030 | if (is_comptime) { |
| 5930 | | const arg_src = call_src; // TODO better source location |
| 5931 | 6031 | const arg_ty = sema.typeOf(uncasted_args[i]); |
| 5932 | | const arg_val = try sema.resolveValue(block, arg_src, uncasted_args[i], "parameter is comptime"); |
| 5933 | | try sema.resolveLazyValue(block, arg_src, arg_val); |
| 6032 | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { |
| 6033 | error.NeededSourceLocation => { |
| 6034 | const decl = sema.mod.declPtr(block.src_decl); |
| 6035 | const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i); |
| 6036 | _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); |
| 6037 | return error.AnalysisFail; |
| 6038 | }, |
| 6039 | else => |e| return e, |
| 6040 | }; |
| 5934 | 6041 | arg_val.hash(arg_ty, &hasher, mod); |
| 5935 | 6042 | if (is_anytype) { |
| 5936 | 6043 | arg_ty.hashWithHasher(&hasher, mod); |
| ... | ... | @@ -6086,19 +6193,18 @@ fn instantiateGenericCall( |
| 6086 | 6193 | }, |
| 6087 | 6194 | else => continue, |
| 6088 | 6195 | } |
| 6089 | | const arg_src = call_src; // TODO: better source location |
| 6090 | 6196 | const arg = uncasted_args[arg_i]; |
| 6091 | 6197 | if (is_comptime) { |
| 6092 | | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { |
| 6198 | if (try sema.resolveMaybeUndefVal(block, .unneeded, arg)) |arg_val| { |
| 6093 | 6199 | const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val); |
| 6094 | 6200 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 6095 | 6201 | } else { |
| 6096 | | return sema.failWithNeededComptime(block, arg_src, "parameter is comptime"); |
| 6202 | return sema.failWithNeededComptime(block, .unneeded, undefined); |
| 6097 | 6203 | } |
| 6098 | 6204 | } else if (is_anytype) { |
| 6099 | 6205 | const arg_ty = sema.typeOf(arg); |
| 6100 | | if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) { |
| 6101 | | const arg_val = try sema.resolveConstValue(block, arg_src, arg, "type of anytype parameter requires comptime"); |
| 6206 | if (try sema.typeRequiresComptime(block, .unneeded, arg_ty)) { |
| 6207 | const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined); |
| 6102 | 6208 | const child_arg = try child_sema.addConstant(arg_ty, arg_val); |
| 6103 | 6209 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 6104 | 6210 | } else { |
| ... | ... | @@ -6156,8 +6262,7 @@ fn instantiateGenericCall( |
| 6156 | 6262 | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); |
| 6157 | 6263 | anytype_args[arg_i] = is_anytype; |
| 6158 | 6264 | |
| 6159 | | const arg_src = call_src; // TODO: better source location |
| 6160 | | if (try sema.typeRequiresComptime(block, arg_src, copied_arg_ty)) { |
| 6265 | if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) { |
| 6161 | 6266 | is_comptime = true; |
| 6162 | 6267 | } |
| 6163 | 6268 | |
| ... | ... | @@ -6236,18 +6341,30 @@ fn instantiateGenericCall( |
| 6236 | 6341 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, |
| 6237 | 6342 | else => continue, |
| 6238 | 6343 | } |
| 6239 | | const arg_src = call_src; // TODO: better source location |
| 6240 | | const is_runtime = comptime_args[total_i].val.tag() == .generic_poison and |
| 6241 | | comptime_args[total_i].ty.hasRuntimeBits() and |
| 6242 | | !(try sema.typeRequiresComptime(block, arg_src, comptime_args[total_i].ty)); |
| 6243 | | if (is_runtime) { |
| 6244 | | const param_ty = new_fn_info.param_types[runtime_i]; |
| 6245 | | const uncasted_arg = uncasted_args[total_i]; |
| 6246 | | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 6247 | | try sema.queueFullTypeResolution(param_ty); |
| 6248 | | runtime_args[runtime_i] = casted_arg; |
| 6249 | | runtime_i += 1; |
| 6250 | | } |
| 6344 | sema.analyzeGenericCallArg( |
| 6345 | block, |
| 6346 | .unneeded, |
| 6347 | uncasted_args[total_i], |
| 6348 | comptime_args[total_i], |
| 6349 | runtime_args, |
| 6350 | new_fn_info, |
| 6351 | &runtime_i, |
| 6352 | ) catch |err| switch (err) { |
| 6353 | error.NeededSourceLocation => { |
| 6354 | const decl = sema.mod.declPtr(block.src_decl); |
| 6355 | _ = try sema.analyzeGenericCallArg( |
| 6356 | block, |
| 6357 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, total_i), |
| 6358 | uncasted_args[total_i], |
| 6359 | comptime_args[total_i], |
| 6360 | runtime_args, |
| 6361 | new_fn_info, |
| 6362 | &runtime_i, |
| 6363 | ); |
| 6364 | return error.AnalysisFail; |
| 6365 | }, |
| 6366 | else => |e| return e, |
| 6367 | }; |
| 6251 | 6368 | total_i += 1; |
| 6252 | 6369 | } |
| 6253 | 6370 | |