| ... | ... | @@ -6679,78 +6679,6 @@ fn callBuiltin( |
| 6679 | 6679 | _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null); |
| 6680 | 6680 | } |
| 6681 | 6681 | |
| 6682 | | const GenericCallAdapter = struct { |
| 6683 | | generic_fn: *Module.Fn, |
| 6684 | | precomputed_hash: u64, |
| 6685 | | func_ty_info: InternPool.Key.FuncType, |
| 6686 | | args: []const Arg, |
| 6687 | | module: *Module, |
| 6688 | | |
| 6689 | | const Arg = struct { |
| 6690 | | ty: Type, |
| 6691 | | val: Value, |
| 6692 | | is_anytype: bool, |
| 6693 | | }; |
| 6694 | | |
| 6695 | | pub fn eql(ctx: @This(), adapted_key: void, other_key: Module.Fn.Index) bool { |
| 6696 | | _ = adapted_key; |
| 6697 | | const other_func = ctx.module.funcPtr(other_key); |
| 6698 | | |
| 6699 | | // Checking for equality may happen on an item that has been inserted |
| 6700 | | // into the map but is not yet fully initialized. In such case, the |
| 6701 | | // two initialized fields are `hash` and `generic_owner_decl`. |
| 6702 | | if (ctx.generic_fn.owner_decl != other_func.generic_owner_decl.unwrap().?) return false; |
| 6703 | | |
| 6704 | | const other_comptime_args = other_func.comptime_args.?; |
| 6705 | | for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| { |
| 6706 | | const this_arg = ctx.args[i]; |
| 6707 | | const this_is_comptime = !this_arg.val.isGenericPoison(); |
| 6708 | | const other_is_comptime = !other_arg.val.isGenericPoison(); |
| 6709 | | const this_is_anytype = this_arg.is_anytype; |
| 6710 | | const other_is_anytype = other_func.isAnytypeParam(ctx.module, @intCast(u32, i)); |
| 6711 | | |
| 6712 | | if (other_is_anytype != this_is_anytype) return false; |
| 6713 | | if (other_is_comptime != this_is_comptime) return false; |
| 6714 | | |
| 6715 | | if (this_is_anytype) { |
| 6716 | | // Both are anytype parameters. |
| 6717 | | if (!this_arg.ty.eql(other_arg.ty, ctx.module)) { |
| 6718 | | return false; |
| 6719 | | } |
| 6720 | | if (this_is_comptime) { |
| 6721 | | // Both are comptime and anytype parameters with matching types. |
| 6722 | | if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) { |
| 6723 | | return false; |
| 6724 | | } |
| 6725 | | } |
| 6726 | | } else if (this_is_comptime) { |
| 6727 | | // Both are comptime parameters but not anytype parameters. |
| 6728 | | // We assert no error is possible here because any lazy values must be resolved |
| 6729 | | // before inserting into the generic function hash map. |
| 6730 | | const is_eql = Value.eqlAdvanced( |
| 6731 | | this_arg.val, |
| 6732 | | this_arg.ty, |
| 6733 | | other_arg.val, |
| 6734 | | other_arg.ty, |
| 6735 | | ctx.module, |
| 6736 | | null, |
| 6737 | | ) catch unreachable; |
| 6738 | | if (!is_eql) { |
| 6739 | | return false; |
| 6740 | | } |
| 6741 | | } |
| 6742 | | } |
| 6743 | | return true; |
| 6744 | | } |
| 6745 | | |
| 6746 | | /// The implementation of the hash is in semantic analysis of function calls, so |
| 6747 | | /// that any errors when computing the hash can be properly reported. |
| 6748 | | pub fn hash(ctx: @This(), adapted_key: void) u64 { |
| 6749 | | _ = adapted_key; |
| 6750 | | return ctx.precomputed_hash; |
| 6751 | | } |
| 6752 | | }; |
| 6753 | | |
| 6754 | 6682 | fn analyzeCall( |
| 6755 | 6683 | sema: *Sema, |
| 6756 | 6684 | block: *Block, |
| ... | ... | @@ -7480,11 +7408,12 @@ fn instantiateGenericCall( |
| 7480 | 7408 | const ip = &mod.intern_pool; |
| 7481 | 7409 | |
| 7482 | 7410 | const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); |
| 7483 | | const module_fn = mod.funcPtr(switch (ip.indexToKey(func_val.toIntern())) { |
| 7411 | const module_fn_index = switch (ip.indexToKey(func_val.toIntern())) { |
| 7484 | 7412 | .func => |function| function.index, |
| 7485 | 7413 | .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, |
| 7486 | 7414 | else => unreachable, |
| 7487 | | }); |
| 7415 | }; |
| 7416 | const module_fn = mod.funcPtr(module_fn_index); |
| 7488 | 7417 | // Check the Module's generic function map with an adapted context, so that we |
| 7489 | 7418 | // can match against `uncasted_args` rather than doing the work below to create a |
| 7490 | 7419 | // generic Scope only to junk it if it matches an existing instantiation. |
| ... | ... | @@ -7495,32 +7424,24 @@ fn instantiateGenericCall( |
| 7495 | 7424 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7496 | 7425 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7497 | 7426 | |
| 7498 | | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 7499 | | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 7500 | | // we know whether a parameter is elided from a monomorphed function, and can |
| 7501 | | // use it in the hash here. However, for parameter type expressions that are not |
| 7502 | | // explicitly marked comptime and rely on previous parameter comptime values, we |
| 7503 | | // don't find out until after generating a monomorphed function whether the parameter |
| 7504 | | // type ended up being a "must-be-comptime-known" type. |
| 7505 | | var hasher = std.hash.Wyhash.init(0); |
| 7506 | | std.hash.autoHash(&hasher, module_fn.owner_decl); |
| 7507 | | |
| 7508 | | const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len); |
| 7509 | | { |
| 7510 | | var i: usize = 0; |
| 7427 | const generic_args = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); |
| 7428 | const callee_index = callee: { |
| 7429 | var arg_i: usize = 0; |
| 7430 | var generic_arg_i: u32 = 0; |
| 7431 | var known_unique = false; |
| 7511 | 7432 | for (fn_info.param_body) |inst| { |
| 7512 | 7433 | var is_comptime = false; |
| 7513 | 7434 | var is_anytype = false; |
| 7514 | 7435 | switch (zir_tags[inst]) { |
| 7515 | 7436 | .param => { |
| 7516 | | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i)); |
| 7437 | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7517 | 7438 | }, |
| 7518 | 7439 | .param_comptime => { |
| 7519 | 7440 | is_comptime = true; |
| 7520 | 7441 | }, |
| 7521 | 7442 | .param_anytype => { |
| 7522 | 7443 | is_anytype = true; |
| 7523 | | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, i)); |
| 7444 | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7524 | 7445 | }, |
| 7525 | 7446 | .param_anytype_comptime => { |
| 7526 | 7447 | is_anytype = true; |
| ... | ... | @@ -7529,7 +7450,15 @@ fn instantiateGenericCall( |
| 7529 | 7450 | else => continue, |
| 7530 | 7451 | } |
| 7531 | 7452 | |
| 7532 | | const arg_ty = sema.typeOf(uncasted_args[i]); |
| 7453 | defer arg_i += 1; |
| 7454 | if (known_unique) { |
| 7455 | if (is_comptime or is_anytype) { |
| 7456 | generic_arg_i += 1; |
| 7457 | } |
| 7458 | continue; |
| 7459 | } |
| 7460 | |
| 7461 | const arg_ty = sema.typeOf(uncasted_args[arg_i]); |
| 7533 | 7462 | if (is_comptime or is_anytype) { |
| 7534 | 7463 | // Tuple default values are a part of the type and need to be |
| 7535 | 7464 | // resolved to hash the type. |
| ... | ... | @@ -7537,69 +7466,72 @@ fn instantiateGenericCall( |
| 7537 | 7466 | } |
| 7538 | 7467 | |
| 7539 | 7468 | if (is_comptime) { |
| 7540 | | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { |
| 7469 | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[arg_i]) catch |err| switch (err) { |
| 7541 | 7470 | error.NeededSourceLocation => { |
| 7542 | 7471 | const decl = sema.mod.declPtr(block.src_decl); |
| 7543 | | const arg_src = mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src); |
| 7544 | | _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); |
| 7472 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); |
| 7473 | _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[arg_i]); |
| 7545 | 7474 | unreachable; |
| 7546 | 7475 | }, |
| 7547 | 7476 | else => |e| return e, |
| 7548 | 7477 | }; |
| 7549 | | arg_val.hashUncoerced(arg_ty, &hasher, mod); |
| 7478 | |
| 7550 | 7479 | if (is_anytype) { |
| 7551 | | std.hash.autoHash(&hasher, arg_ty.toIntern()); |
| 7552 | | generic_args[i] = .{ |
| 7553 | | .ty = arg_ty, |
| 7554 | | .val = arg_val, |
| 7555 | | .is_anytype = true, |
| 7556 | | }; |
| 7480 | generic_args[generic_arg_i] = arg_val.toIntern(); |
| 7557 | 7481 | } else { |
| 7558 | | generic_args[i] = .{ |
| 7559 | | .ty = arg_ty, |
| 7560 | | .val = arg_val, |
| 7561 | | .is_anytype = false, |
| 7482 | const final_arg_ty = mod.monomorphed_funcs.getAdapted( |
| 7483 | Module.MonomorphedFuncAdaptedKey{ |
| 7484 | .func = module_fn_index, |
| 7485 | .args = generic_args[0..generic_arg_i], |
| 7486 | }, |
| 7487 | Module.MonomorphedFuncsAdaptedContext{ .mod = mod }, |
| 7488 | ) orelse { |
| 7489 | known_unique = true; |
| 7490 | generic_arg_i += 1; |
| 7491 | continue; |
| 7492 | }; |
| 7493 | const casted_arg = sema.coerce(block, final_arg_ty.toType(), uncasted_args[arg_i], .unneeded) catch |err| switch (err) { |
| 7494 | error.NeededSourceLocation => { |
| 7495 | const decl = sema.mod.declPtr(block.src_decl); |
| 7496 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); |
| 7497 | _ = try sema.coerce(block, final_arg_ty.toType(), uncasted_args[arg_i], arg_src); |
| 7498 | unreachable; |
| 7499 | }, |
| 7500 | else => |e| return e, |
| 7562 | 7501 | }; |
| 7502 | const casted_arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, casted_arg) catch |err| switch (err) { |
| 7503 | error.NeededSourceLocation => { |
| 7504 | const decl = sema.mod.declPtr(block.src_decl); |
| 7505 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); |
| 7506 | _ = try sema.analyzeGenericCallArgVal(block, arg_src, casted_arg); |
| 7507 | unreachable; |
| 7508 | }, |
| 7509 | else => |e| return e, |
| 7510 | }; |
| 7511 | generic_args[generic_arg_i] = casted_arg_val.toIntern(); |
| 7563 | 7512 | } |
| 7513 | generic_arg_i += 1; |
| 7564 | 7514 | } else if (is_anytype) { |
| 7565 | | std.hash.autoHash(&hasher, arg_ty.toIntern()); |
| 7566 | | generic_args[i] = .{ |
| 7567 | | .ty = arg_ty, |
| 7568 | | .val = Value.generic_poison, |
| 7569 | | .is_anytype = true, |
| 7570 | | }; |
| 7571 | | } else { |
| 7572 | | generic_args[i] = .{ |
| 7573 | | .ty = arg_ty, |
| 7574 | | .val = Value.generic_poison, |
| 7575 | | .is_anytype = false, |
| 7576 | | }; |
| 7515 | generic_args[generic_arg_i] = arg_ty.toIntern(); |
| 7516 | generic_arg_i += 1; |
| 7577 | 7517 | } |
| 7578 | | |
| 7579 | | i += 1; |
| 7580 | 7518 | } |
| 7581 | | } |
| 7582 | 7519 | |
| 7583 | | const precomputed_hash = hasher.final(); |
| 7520 | if (!known_unique) { |
| 7521 | if (mod.monomorphed_funcs.getAdapted( |
| 7522 | Module.MonomorphedFuncAdaptedKey{ |
| 7523 | .func = module_fn_index, |
| 7524 | .args = generic_args[0..generic_arg_i], |
| 7525 | }, |
| 7526 | Module.MonomorphedFuncsAdaptedContext{ .mod = mod }, |
| 7527 | )) |callee_func| break :callee mod.intern_pool.indexToKey(callee_func).func.index; |
| 7528 | } |
| 7584 | 7529 | |
| 7585 | | const adapter: GenericCallAdapter = .{ |
| 7586 | | .generic_fn = module_fn, |
| 7587 | | .precomputed_hash = precomputed_hash, |
| 7588 | | .func_ty_info = func_ty_info, |
| 7589 | | .args = generic_args, |
| 7590 | | .module = mod, |
| 7591 | | }; |
| 7592 | | const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .mod = mod }); |
| 7593 | | const callee_index = if (!gop.found_existing) callee: { |
| 7594 | 7530 | const new_module_func_index = try mod.createFunc(undefined); |
| 7595 | 7531 | const new_module_func = mod.funcPtr(new_module_func_index); |
| 7596 | 7532 | |
| 7597 | | // This ensures that we can operate on the hash map before the Module.Fn |
| 7598 | | // struct is fully initialized. |
| 7599 | | new_module_func.hash = precomputed_hash; |
| 7600 | 7533 | new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); |
| 7601 | 7534 | new_module_func.comptime_args = null; |
| 7602 | | gop.key_ptr.* = new_module_func_index; |
| 7603 | 7535 | |
| 7604 | 7536 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 7605 | 7537 | |
| ... | ... | @@ -7641,7 +7573,8 @@ fn instantiateGenericCall( |
| 7641 | 7573 | new_decl, |
| 7642 | 7574 | new_decl_index, |
| 7643 | 7575 | uncasted_args, |
| 7644 | | module_fn, |
| 7576 | generic_arg_i, |
| 7577 | module_fn_index, |
| 7645 | 7578 | new_module_func_index, |
| 7646 | 7579 | namespace_index, |
| 7647 | 7580 | func_ty_info, |
| ... | ... | @@ -7657,12 +7590,10 @@ fn instantiateGenericCall( |
| 7657 | 7590 | } |
| 7658 | 7591 | assert(namespace.anon_decls.orderedRemove(new_decl_index)); |
| 7659 | 7592 | mod.destroyDecl(new_decl_index); |
| 7660 | | assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); |
| 7661 | 7593 | mod.destroyFunc(new_module_func_index); |
| 7662 | 7594 | return err; |
| 7663 | 7595 | }, |
| 7664 | 7596 | else => { |
| 7665 | | assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); |
| 7666 | 7597 | // TODO look up the compile error that happened here and attach a note to it |
| 7667 | 7598 | // pointing here, at the generic instantiation callsite. |
| 7668 | 7599 | if (sema.owner_func) |owner_func| { |
| ... | ... | @@ -7675,9 +7606,8 @@ fn instantiateGenericCall( |
| 7675 | 7606 | }; |
| 7676 | 7607 | |
| 7677 | 7608 | break :callee new_func; |
| 7678 | | } else gop.key_ptr.*; |
| 7609 | }; |
| 7679 | 7610 | const callee = mod.funcPtr(callee_index); |
| 7680 | | |
| 7681 | 7611 | callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); |
| 7682 | 7612 | |
| 7683 | 7613 | const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); |
| ... | ... | @@ -7752,7 +7682,7 @@ fn instantiateGenericCall( |
| 7752 | 7682 | if (call_tag == .call_always_tail) { |
| 7753 | 7683 | return sema.handleTailCall(block, call_src, func_ty, result); |
| 7754 | 7684 | } |
| 7755 | | if (new_fn_info.return_type == .noreturn_type) { |
| 7685 | if (func_ty.fnReturnType(mod).isNoReturn(mod)) { |
| 7756 | 7686 | _ = try block.addNoOp(.unreach); |
| 7757 | 7687 | return Air.Inst.Ref.unreachable_value; |
| 7758 | 7688 | } |
| ... | ... | @@ -7766,7 +7696,8 @@ fn resolveGenericInstantiationType( |
| 7766 | 7696 | new_decl: *Decl, |
| 7767 | 7697 | new_decl_index: Decl.Index, |
| 7768 | 7698 | uncasted_args: []const Air.Inst.Ref, |
| 7769 | | module_fn: *Module.Fn, |
| 7699 | generic_args_len: u32, |
| 7700 | module_fn_index: Module.Fn.Index, |
| 7770 | 7701 | new_module_func: Module.Fn.Index, |
| 7771 | 7702 | namespace: Namespace.Index, |
| 7772 | 7703 | func_ty_info: InternPool.Key.FuncType, |
| ... | ... | @@ -7777,6 +7708,7 @@ fn resolveGenericInstantiationType( |
| 7777 | 7708 | const gpa = sema.gpa; |
| 7778 | 7709 | |
| 7779 | 7710 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7711 | const module_fn = mod.funcPtr(module_fn_index); |
| 7780 | 7712 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7781 | 7713 | |
| 7782 | 7714 | // Re-run the block that creates the function, with the comptime parameters |
| ... | ... | @@ -7893,9 +7825,15 @@ fn resolveGenericInstantiationType( |
| 7893 | 7825 | const new_func = new_func_val.getFunctionIndex(mod).unwrap().?; |
| 7894 | 7826 | assert(new_func == new_module_func); |
| 7895 | 7827 | |
| 7828 | const generic_args_index = @intCast(u32, mod.monomorphed_func_keys.items.len); |
| 7829 | const generic_args = try mod.monomorphed_func_keys.addManyAsSlice(gpa, generic_args_len); |
| 7830 | var generic_arg_i: u32 = 0; |
| 7831 | try mod.monomorphed_funcs.ensureUnusedCapacityContext(gpa, generic_args_len + 1, .{ .mod = mod }); |
| 7832 | |
| 7896 | 7833 | arg_i = 0; |
| 7897 | 7834 | for (fn_info.param_body) |inst| { |
| 7898 | 7835 | var is_comptime = false; |
| 7836 | var is_anytype = false; |
| 7899 | 7837 | switch (zir_tags[inst]) { |
| 7900 | 7838 | .param => { |
| 7901 | 7839 | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| ... | ... | @@ -7904,9 +7842,11 @@ fn resolveGenericInstantiationType( |
| 7904 | 7842 | is_comptime = true; |
| 7905 | 7843 | }, |
| 7906 | 7844 | .param_anytype => { |
| 7845 | is_anytype = true; |
| 7907 | 7846 | is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7908 | 7847 | }, |
| 7909 | 7848 | .param_anytype_comptime => { |
| 7849 | is_anytype = true; |
| 7910 | 7850 | is_comptime = true; |
| 7911 | 7851 | }, |
| 7912 | 7852 | else => continue, |
| ... | ... | @@ -7924,11 +7864,24 @@ fn resolveGenericInstantiationType( |
| 7924 | 7864 | |
| 7925 | 7865 | if (is_comptime) { |
| 7926 | 7866 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; |
| 7867 | if (!is_anytype) { |
| 7868 | if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{ |
| 7869 | .func = module_fn_index, |
| 7870 | .args_index = generic_args_index, |
| 7871 | .args_len = generic_arg_i, |
| 7872 | }, arg_ty.toIntern(), .{ .mod = mod })) |kv| assert(kv.value == arg_ty.toIntern()); |
| 7873 | } |
| 7874 | generic_args[generic_arg_i] = arg_val.toIntern(); |
| 7875 | generic_arg_i += 1; |
| 7927 | 7876 | child_sema.comptime_args[arg_i] = .{ |
| 7928 | 7877 | .ty = arg_ty, |
| 7929 | 7878 | .val = (try arg_val.intern(arg_ty, mod)).toValue(), |
| 7930 | 7879 | }; |
| 7931 | 7880 | } else { |
| 7881 | if (is_anytype) { |
| 7882 | generic_args[generic_arg_i] = arg_ty.toIntern(); |
| 7883 | generic_arg_i += 1; |
| 7884 | } |
| 7932 | 7885 | child_sema.comptime_args[arg_i] = .{ |
| 7933 | 7886 | .ty = arg_ty, |
| 7934 | 7887 | .val = Value.generic_poison, |
| ... | ... | @@ -7963,6 +7916,12 @@ fn resolveGenericInstantiationType( |
| 7963 | 7916 | new_decl.owns_tv = true; |
| 7964 | 7917 | new_decl.analysis = .complete; |
| 7965 | 7918 | |
| 7919 | mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{ |
| 7920 | .func = module_fn_index, |
| 7921 | .args_index = generic_args_index, |
| 7922 | .args_len = generic_arg_i, |
| 7923 | }, new_decl.val.toIntern(), .{ .mod = mod }); |
| 7924 | |
| 7966 | 7925 | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field |
| 7967 | 7926 | // will be populated, ensuring it will have `analyzeBody` called with the ZIR |
| 7968 | 7927 | // parameters mapped appropriately. |