| ... | ... | @@ -29,6 +29,12 @@ owner_func: ?*Module.Fn, |
| 29 | 29 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 30 | 30 | /// an inline or comptime function call. |
| 31 | 31 | func: ?*Module.Fn, |
| 32 | /// When semantic analysis needs to know the return type of the function whose body |
| 33 | /// is being analyzed, this `Type` should be used instead of going through `func`. |
| 34 | /// This will correctly handle the case of a comptime/inline function call of a |
| 35 | /// generic function which uses a type expression for the return type. |
| 36 | /// The type will be `void` in the case that `func` is `null`. |
| 37 | fn_ret_ty: Type, |
| 32 | 38 | branch_quota: u32 = 1000, |
| 33 | 39 | branch_count: u32 = 0, |
| 34 | 40 | /// This field is updated when a new source location becomes active, so that |
| ... | ... | @@ -628,6 +634,7 @@ fn analyzeAsType( |
| 628 | 634 | |
| 629 | 635 | /// May return Value Tags: `variable`, `undef`. |
| 630 | 636 | /// See `resolveConstValue` for an alternative. |
| 637 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 631 | 638 | fn resolveValue( |
| 632 | 639 | sema: *Sema, |
| 633 | 640 | block: *Scope.Block, |
| ... | ... | @@ -679,6 +686,7 @@ fn resolveDefinedValue( |
| 679 | 686 | |
| 680 | 687 | /// Value Tag `variable` causes this function to return `null`. |
| 681 | 688 | /// Value Tag `undef` causes this function to return the Value. |
| 689 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 682 | 690 | fn resolveMaybeUndefVal( |
| 683 | 691 | sema: *Sema, |
| 684 | 692 | block: *Scope.Block, |
| ... | ... | @@ -686,10 +694,11 @@ fn resolveMaybeUndefVal( |
| 686 | 694 | inst: Air.Inst.Ref, |
| 687 | 695 | ) CompileError!?Value { |
| 688 | 696 | const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; |
| 689 | | if (val.tag() == .variable) { |
| 690 | | return null; |
| 697 | switch (val.tag()) { |
| 698 | .variable => return null, |
| 699 | .generic_poison => return error.GenericPoison, |
| 700 | else => return val, |
| 691 | 701 | } |
| 692 | | return val; |
| 693 | 702 | } |
| 694 | 703 | |
| 695 | 704 | /// Returns all Value tags including `variable` and `undef`. |
| ... | ... | @@ -1033,6 +1042,7 @@ fn zirEnumDecl( |
| 1033 | 1042 | .namespace = &enum_obj.namespace, |
| 1034 | 1043 | .owner_func = null, |
| 1035 | 1044 | .func = null, |
| 1045 | .fn_ret_ty = Type.initTag(.void), |
| 1036 | 1046 | .branch_quota = sema.branch_quota, |
| 1037 | 1047 | .branch_count = sema.branch_count, |
| 1038 | 1048 | }; |
| ... | ... | @@ -1238,9 +1248,7 @@ fn zirRetPtr( |
| 1238 | 1248 | |
| 1239 | 1249 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 1240 | 1250 | try sema.requireFunctionBlock(block, src); |
| 1241 | | const fn_ty = sema.func.?.owner_decl.ty; |
| 1242 | | const ret_type = fn_ty.fnReturnType(); |
| 1243 | | const ptr_type = try Module.simplePtrType(sema.arena, ret_type, true, .One); |
| 1251 | const ptr_type = try Module.simplePtrType(sema.arena, sema.fn_ret_ty, true, .One); |
| 1244 | 1252 | return block.addTy(.alloc, ptr_type); |
| 1245 | 1253 | } |
| 1246 | 1254 | |
| ... | ... | @@ -1263,9 +1271,7 @@ fn zirRetType( |
| 1263 | 1271 | |
| 1264 | 1272 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 1265 | 1273 | try sema.requireFunctionBlock(block, src); |
| 1266 | | const fn_ty = sema.func.?.owner_decl.ty; |
| 1267 | | const ret_type = fn_ty.fnReturnType(); |
| 1268 | | return sema.addType(ret_type); |
| 1274 | return sema.addType(sema.fn_ret_ty); |
| 1269 | 1275 | } |
| 1270 | 1276 | |
| 1271 | 1277 | fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -2364,7 +2370,7 @@ const GenericCallAdapter = struct { |
| 2364 | 2370 | generic_fn: *Module.Fn, |
| 2365 | 2371 | precomputed_hash: u64, |
| 2366 | 2372 | func_ty_info: Type.Payload.Function.Data, |
| 2367 | | comptime_vals: []const Value, |
| 2373 | comptime_tvs: []const TypedValue, |
| 2368 | 2374 | |
| 2369 | 2375 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { |
| 2370 | 2376 | _ = adapted_key; |
| ... | ... | @@ -2373,12 +2379,22 @@ const GenericCallAdapter = struct { |
| 2373 | 2379 | const generic_owner_decl = other_key.owner_decl.dependencies.keys()[0]; |
| 2374 | 2380 | if (ctx.generic_fn.owner_decl != generic_owner_decl) return false; |
| 2375 | 2381 | |
| 2376 | | // This logic must be kept in sync with the logic in `analyzeCall` that |
| 2377 | | // computes the hash. |
| 2378 | 2382 | const other_comptime_args = other_key.comptime_args.?; |
| 2379 | | for (ctx.func_ty_info.param_types) |param_ty, i| { |
| 2380 | | if (ctx.func_ty_info.paramIsComptime(i) and param_ty.tag() != .generic_poison) { |
| 2381 | | if (!ctx.comptime_vals[i].eql(other_comptime_args[i].val, param_ty)) { |
| 2383 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { |
| 2384 | if (other_arg.ty.tag() != .generic_poison) { |
| 2385 | // anytype parameter |
| 2386 | if (!other_arg.ty.eql(ctx.comptime_tvs[i].ty)) { |
| 2387 | return false; |
| 2388 | } |
| 2389 | } |
| 2390 | if (other_arg.val.tag() != .generic_poison) { |
| 2391 | // comptime parameter |
| 2392 | if (ctx.comptime_tvs[i].val.tag() == .generic_poison) { |
| 2393 | // No match because the instantiation has a comptime parameter |
| 2394 | // but the callsite does not. |
| 2395 | return false; |
| 2396 | } |
| 2397 | if (!other_arg.val.eql(ctx.comptime_tvs[i].val, other_arg.ty)) { |
| 2382 | 2398 | return false; |
| 2383 | 2399 | } |
| 2384 | 2400 | } |
| ... | ... | @@ -2394,6 +2410,22 @@ const GenericCallAdapter = struct { |
| 2394 | 2410 | } |
| 2395 | 2411 | }; |
| 2396 | 2412 | |
| 2413 | const GenericRemoveAdapter = struct { |
| 2414 | precomputed_hash: u64, |
| 2415 | |
| 2416 | pub fn eql(ctx: @This(), adapted_key: *Module.Fn, other_key: *Module.Fn) bool { |
| 2417 | _ = ctx; |
| 2418 | return adapted_key == other_key; |
| 2419 | } |
| 2420 | |
| 2421 | /// The implementation of the hash is in semantic analysis of function calls, so |
| 2422 | /// that any errors when computing the hash can be properly reported. |
| 2423 | pub fn hash(ctx: @This(), adapted_key: *Module.Fn) u64 { |
| 2424 | _ = adapted_key; |
| 2425 | return ctx.precomputed_hash; |
| 2426 | } |
| 2427 | }; |
| 2428 | |
| 2397 | 2429 | fn analyzeCall( |
| 2398 | 2430 | sema: *Sema, |
| 2399 | 2431 | block: *Scope.Block, |
| ... | ... | @@ -2466,14 +2498,6 @@ fn analyzeCall( |
| 2466 | 2498 | const is_inline_call = is_comptime_call or modifier == .always_inline or |
| 2467 | 2499 | func_ty_info.cc == .Inline; |
| 2468 | 2500 | const result: Air.Inst.Ref = if (is_inline_call) res: { |
| 2469 | | // TODO look into not allocating this args array |
| 2470 | | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); |
| 2471 | | for (uncasted_args) |uncasted_arg, i| { |
| 2472 | | const param_ty = func_ty.fnParamType(i); |
| 2473 | | const arg_src = call_src; // TODO: better source location |
| 2474 | | args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 2475 | | } |
| 2476 | | |
| 2477 | 2501 | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 2478 | 2502 | const module_fn = switch (func_val.tag()) { |
| 2479 | 2503 | .function => func_val.castTag(.function).?.data, |
| ... | ... | @@ -2544,19 +2568,62 @@ fn analyzeCall( |
| 2544 | 2568 | // This will have return instructions analyzed as break instructions to |
| 2545 | 2569 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| 2546 | 2570 | // for a function body, which means we must map the parameter ZIR instructions to |
| 2547 | | // the AIR instructions of the callsite. |
| 2571 | // the AIR instructions of the callsite. The callee could be a generic function |
| 2572 | // which means its parameter type expressions must be resolved in order and used |
| 2573 | // to successively coerce the arguments. |
| 2548 | 2574 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); |
| 2549 | 2575 | const zir_tags = sema.code.instructions.items(.tag); |
| 2550 | 2576 | var arg_i: usize = 0; |
| 2551 | | try sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, args.len)); |
| 2552 | | for (fn_info.param_body) |inst| { |
| 2553 | | switch (zir_tags[inst]) { |
| 2554 | | .param, .param_comptime, .param_anytype, .param_anytype_comptime => {}, |
| 2555 | | else => continue, |
| 2577 | for (fn_info.param_body) |inst| switch (zir_tags[inst]) { |
| 2578 | .param, .param_comptime => { |
| 2579 | // Evaluate the parameter type expression now that previous ones have |
| 2580 | // been mapped, and coerce the corresponding argument to it. |
| 2581 | const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; |
| 2582 | const param_src = pl_tok.src(); |
| 2583 | const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index); |
| 2584 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 2585 | const param_ty_inst = try sema.resolveBody(&child_block, param_body); |
| 2586 | const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst); |
| 2587 | const arg_src = call_src; // TODO: better source location |
| 2588 | const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src); |
| 2589 | try sema.inst_map.putNoClobber(gpa, inst, casted_arg); |
| 2590 | arg_i += 1; |
| 2591 | continue; |
| 2592 | }, |
| 2593 | .param_anytype, .param_anytype_comptime => { |
| 2594 | // No coercion needed. |
| 2595 | try sema.inst_map.putNoClobber(gpa, inst, uncasted_args[arg_i]); |
| 2596 | arg_i += 1; |
| 2597 | continue; |
| 2598 | }, |
| 2599 | else => continue, |
| 2600 | }; |
| 2601 | |
| 2602 | // In case it is a generic function with an expression for the return type that depends |
| 2603 | // on parameters, we must now do the same for the return type as we just did with |
| 2604 | // each of the parameters, resolving the return type and providing it to the child |
| 2605 | // `Sema` so that it can be used for the `ret_ptr` instruction. |
| 2606 | const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body); |
| 2607 | const ret_ty_src = func_src; // TODO better source location |
| 2608 | const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); |
| 2609 | // If the function has an inferred error set, `bare_return_type` is the payload type only. |
| 2610 | const fn_ret_ty = blk: { |
| 2611 | // TODO instead of reusing the function's inferred error set, this code should |
| 2612 | // create a temporary error set which is used for the comptime/inline function |
| 2613 | // call alone, independent from the runtime instantiation. |
| 2614 | if (func_ty_info.return_type.castTag(.error_union)) |payload| { |
| 2615 | const error_set_ty = payload.data.error_set; |
| 2616 | break :blk try Type.Tag.error_union.create(sema.arena, .{ |
| 2617 | .error_set = error_set_ty, |
| 2618 | .payload = bare_return_type, |
| 2619 | }); |
| 2556 | 2620 | } |
| 2557 | | sema.inst_map.putAssumeCapacityNoClobber(inst, args[arg_i]); |
| 2558 | | arg_i += 1; |
| 2559 | | } |
| 2621 | break :blk bare_return_type; |
| 2622 | }; |
| 2623 | const parent_fn_ret_ty = sema.fn_ret_ty; |
| 2624 | sema.fn_ret_ty = fn_ret_ty; |
| 2625 | defer sema.fn_ret_ty = parent_fn_ret_ty; |
| 2626 | |
| 2560 | 2627 | _ = try sema.analyzeBody(&child_block, fn_info.body); |
| 2561 | 2628 | break :res try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 2562 | 2629 | } else if (func_ty_info.is_generic) res: { |
| ... | ... | @@ -2569,57 +2636,74 @@ fn analyzeCall( |
| 2569 | 2636 | const fn_zir = namespace.file_scope.zir; |
| 2570 | 2637 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 2571 | 2638 | const zir_tags = fn_zir.instructions.items(.tag); |
| 2572 | | const new_module_func = new_func: { |
| 2573 | | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 2574 | | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 2575 | | // we know whether a parameter is elided from a monomorphed function, and can |
| 2576 | | // use it in the hash here. However, for parameter type expressions that are not |
| 2577 | | // explicitly marked comptime and rely on previous parameter comptime values, we |
| 2578 | | // don't find out until after generating a monomorphed function whether the parameter |
| 2579 | | // type ended up being a "must-be-comptime-known" type. |
| 2580 | | var hasher = std.hash.Wyhash.init(0); |
| 2581 | | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 2582 | | |
| 2583 | | const comptime_vals = try sema.arena.alloc(Value, func_ty_info.param_types.len); |
| 2584 | | |
| 2585 | | for (func_ty_info.param_types) |param_ty, i| { |
| 2586 | | const is_comptime = func_ty_info.paramIsComptime(i); |
| 2587 | | if (is_comptime and param_ty.tag() != .generic_poison) { |
| 2588 | | const arg_src = call_src; // TODO better source location |
| 2589 | | const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); |
| 2590 | | if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { |
| 2639 | |
| 2640 | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 2641 | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 2642 | // we know whether a parameter is elided from a monomorphed function, and can |
| 2643 | // use it in the hash here. However, for parameter type expressions that are not |
| 2644 | // explicitly marked comptime and rely on previous parameter comptime values, we |
| 2645 | // don't find out until after generating a monomorphed function whether the parameter |
| 2646 | // type ended up being a "must-be-comptime-known" type. |
| 2647 | var hasher = std.hash.Wyhash.init(0); |
| 2648 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 2649 | |
| 2650 | const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); |
| 2651 | |
| 2652 | for (func_ty_info.param_types) |param_ty, i| { |
| 2653 | const is_comptime = func_ty_info.paramIsComptime(i); |
| 2654 | if (is_comptime) { |
| 2655 | const arg_src = call_src; // TODO better source location |
| 2656 | const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); |
| 2657 | if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { |
| 2658 | if (param_ty.tag() != .generic_poison) { |
| 2591 | 2659 | arg_val.hash(param_ty, &hasher); |
| 2592 | | comptime_vals[i] = arg_val; |
| 2593 | | } else { |
| 2594 | | return sema.failWithNeededComptime(block, arg_src); |
| 2595 | 2660 | } |
| 2661 | comptime_tvs[i] = .{ |
| 2662 | // This will be different than `param_ty` in the case of `generic_poison`. |
| 2663 | .ty = sema.typeOf(casted_arg), |
| 2664 | .val = arg_val, |
| 2665 | }; |
| 2666 | } else { |
| 2667 | return sema.failWithNeededComptime(block, arg_src); |
| 2596 | 2668 | } |
| 2669 | } else { |
| 2670 | comptime_tvs[i] = .{ |
| 2671 | .ty = sema.typeOf(uncasted_args[i]), |
| 2672 | .val = Value.initTag(.generic_poison), |
| 2673 | }; |
| 2597 | 2674 | } |
| 2675 | } |
| 2598 | 2676 | |
| 2599 | | const adapter: GenericCallAdapter = .{ |
| 2600 | | .generic_fn = module_fn, |
| 2601 | | .precomputed_hash = hasher.final(), |
| 2602 | | .func_ty_info = func_ty_info, |
| 2603 | | .comptime_vals = comptime_vals, |
| 2604 | | }; |
| 2605 | | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); |
| 2606 | | if (gop.found_existing) { |
| 2607 | | const callee_func = gop.key_ptr.*; |
| 2608 | | break :res try sema.finishGenericCall( |
| 2609 | | block, |
| 2610 | | call_src, |
| 2611 | | callee_func, |
| 2612 | | func_src, |
| 2613 | | uncasted_args, |
| 2614 | | fn_info, |
| 2615 | | zir_tags, |
| 2616 | | ); |
| 2617 | | } |
| 2618 | | gop.key_ptr.* = try gpa.create(Module.Fn); |
| 2619 | | break :new_func gop.key_ptr.*; |
| 2620 | | }; |
| 2677 | const precomputed_hash = hasher.final(); |
| 2621 | 2678 | |
| 2679 | const adapter: GenericCallAdapter = .{ |
| 2680 | .generic_fn = module_fn, |
| 2681 | .precomputed_hash = precomputed_hash, |
| 2682 | .func_ty_info = func_ty_info, |
| 2683 | .comptime_tvs = comptime_tvs, |
| 2684 | }; |
| 2685 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); |
| 2686 | if (gop.found_existing) { |
| 2687 | const callee_func = gop.key_ptr.*; |
| 2688 | break :res try sema.finishGenericCall( |
| 2689 | block, |
| 2690 | call_src, |
| 2691 | callee_func, |
| 2692 | func_src, |
| 2693 | uncasted_args, |
| 2694 | fn_info, |
| 2695 | zir_tags, |
| 2696 | ); |
| 2697 | } |
| 2698 | const new_module_func = try gpa.create(Module.Fn); |
| 2699 | gop.key_ptr.* = new_module_func; |
| 2622 | 2700 | { |
| 2701 | errdefer gpa.destroy(new_module_func); |
| 2702 | const remove_adapter: GenericRemoveAdapter = .{ |
| 2703 | .precomputed_hash = precomputed_hash, |
| 2704 | }; |
| 2705 | errdefer assert(mod.monomorphed_funcs.removeAdapted(new_module_func, remove_adapter)); |
| 2706 | |
| 2623 | 2707 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 2624 | 2708 | |
| 2625 | 2709 | // Create a Decl for the new function. |
| ... | ... | @@ -2658,6 +2742,7 @@ fn analyzeCall( |
| 2658 | 2742 | .owner_decl = new_decl, |
| 2659 | 2743 | .namespace = namespace, |
| 2660 | 2744 | .func = null, |
| 2745 | .fn_ret_ty = Type.initTag(.void), |
| 2661 | 2746 | .owner_func = null, |
| 2662 | 2747 | .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len), |
| 2663 | 2748 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| ... | ... | @@ -2681,11 +2766,25 @@ fn analyzeCall( |
| 2681 | 2766 | try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); |
| 2682 | 2767 | var arg_i: usize = 0; |
| 2683 | 2768 | for (fn_info.param_body) |inst| { |
| 2684 | | const is_comptime = switch (zir_tags[inst]) { |
| 2685 | | .param_comptime, .param_anytype_comptime => true, |
| 2686 | | .param, .param_anytype => false, |
| 2769 | var is_comptime = false; |
| 2770 | var is_anytype = false; |
| 2771 | switch (zir_tags[inst]) { |
| 2772 | .param => { |
| 2773 | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 2774 | }, |
| 2775 | .param_comptime => { |
| 2776 | is_comptime = true; |
| 2777 | }, |
| 2778 | .param_anytype => { |
| 2779 | is_anytype = true; |
| 2780 | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 2781 | }, |
| 2782 | .param_anytype_comptime => { |
| 2783 | is_anytype = true; |
| 2784 | is_comptime = true; |
| 2785 | }, |
| 2687 | 2786 | else => continue, |
| 2688 | | } or func_ty_info.paramIsComptime(arg_i); |
| 2787 | } |
| 2689 | 2788 | const arg_src = call_src; // TODO: better source location |
| 2690 | 2789 | const arg = uncasted_args[arg_i]; |
| 2691 | 2790 | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { |
| ... | ... | @@ -2693,6 +2792,12 @@ fn analyzeCall( |
| 2693 | 2792 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 2694 | 2793 | } else if (is_comptime) { |
| 2695 | 2794 | return sema.failWithNeededComptime(block, arg_src); |
| 2795 | } else if (is_anytype) { |
| 2796 | const child_arg = try child_sema.addConstant( |
| 2797 | sema.typeOf(arg), |
| 2798 | Value.initTag(.generic_poison), |
| 2799 | ); |
| 2800 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 2696 | 2801 | } |
| 2697 | 2802 | arg_i += 1; |
| 2698 | 2803 | } |
| ... | ... | @@ -2710,17 +2815,10 @@ fn analyzeCall( |
| 2710 | 2815 | const arg = child_sema.inst_map.get(inst).?; |
| 2711 | 2816 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?; |
| 2712 | 2817 | |
| 2713 | | if (arg_val.tag() == .generic_poison) { |
| 2714 | | child_sema.comptime_args[arg_i] = .{ |
| 2715 | | .ty = Type.initTag(.noreturn), |
| 2716 | | .val = Value.initTag(.unreachable_value), |
| 2717 | | }; |
| 2718 | | } else { |
| 2719 | | child_sema.comptime_args[arg_i] = .{ |
| 2720 | | .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator), |
| 2721 | | .val = try arg_val.copy(&new_decl_arena.allocator), |
| 2722 | | }; |
| 2723 | | } |
| 2818 | child_sema.comptime_args[arg_i] = .{ |
| 2819 | .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator), |
| 2820 | .val = try arg_val.copy(&new_decl_arena.allocator), |
| 2821 | }; |
| 2724 | 2822 | |
| 2725 | 2823 | arg_i += 1; |
| 2726 | 2824 | } |
| ... | ... | @@ -2730,6 +2828,18 @@ fn analyzeCall( |
| 2730 | 2828 | new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func); |
| 2731 | 2829 | new_decl.analysis = .complete; |
| 2732 | 2830 | |
| 2831 | if (new_decl.ty.fnInfo().is_generic) { |
| 2832 | // TODO improve this error message. This can happen because of the parameter |
| 2833 | // type expression or return type expression depending on runtime-provided values. |
| 2834 | // The error message should be emitted in zirParam or funcCommon when it |
| 2835 | // is determined that we are trying to instantiate a generic function. |
| 2836 | return mod.fail(&block.base, call_src, "unable to monomorphize function", .{}); |
| 2837 | } |
| 2838 | |
| 2839 | log.debug("generic function '{s}' instantiated with type {}", .{ |
| 2840 | new_decl.name, new_decl.ty, |
| 2841 | }); |
| 2842 | |
| 2733 | 2843 | // The generic function Decl is guaranteed to be the first dependency |
| 2734 | 2844 | // of each of its instantiations. |
| 2735 | 2845 | assert(new_decl.dependencies.keys().len == 0); |
| ... | ... | @@ -2809,7 +2919,7 @@ fn finishGenericCall( |
| 2809 | 2919 | for (fn_info.param_body) |inst| { |
| 2810 | 2920 | switch (zir_tags[inst]) { |
| 2811 | 2921 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => { |
| 2812 | | if (comptime_args[arg_i].val.tag() == .unreachable_value) { |
| 2922 | if (comptime_args[arg_i].val.tag() == .generic_poison) { |
| 2813 | 2923 | count += 1; |
| 2814 | 2924 | } |
| 2815 | 2925 | arg_i += 1; |
| ... | ... | @@ -2829,7 +2939,7 @@ fn finishGenericCall( |
| 2829 | 2939 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, |
| 2830 | 2940 | else => continue, |
| 2831 | 2941 | } |
| 2832 | | const is_runtime = comptime_args[total_i].val.tag() == .unreachable_value; |
| 2942 | const is_runtime = comptime_args[total_i].val.tag() == .generic_poison; |
| 2833 | 2943 | if (is_runtime) { |
| 2834 | 2944 | const param_ty = new_fn_ty.fnParamType(runtime_i); |
| 2835 | 2945 | const arg_src = call_src; // TODO: better source location |
| ... | ... | @@ -6162,28 +6272,23 @@ fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr |
| 6162 | 6272 | fn analyzeRet( |
| 6163 | 6273 | sema: *Sema, |
| 6164 | 6274 | block: *Scope.Block, |
| 6165 | | operand: Air.Inst.Ref, |
| 6275 | uncasted_operand: Air.Inst.Ref, |
| 6166 | 6276 | src: LazySrcLoc, |
| 6167 | 6277 | need_coercion: bool, |
| 6168 | 6278 | ) CompileError!Zir.Inst.Index { |
| 6169 | | const casted_operand = if (!need_coercion) operand else op: { |
| 6170 | | const func = sema.func.?; |
| 6171 | | const fn_ty = func.owner_decl.ty; |
| 6172 | | // TODO: In the case of a comptime/inline function call of a generic function, |
| 6173 | | // this needs to be the resolved return type based on the function parameter type |
| 6174 | | // expressions being evaluated with comptime arguments passed in. Otherwise, this |
| 6175 | | // ends up being .generic_poison and failing the comptime/inline function call analysis. |
| 6176 | | const fn_ret_ty = fn_ty.fnReturnType(); |
| 6177 | | break :op try sema.coerce(block, fn_ret_ty, operand, src); |
| 6178 | | }; |
| 6279 | const operand = if (!need_coercion) |
| 6280 | uncasted_operand |
| 6281 | else |
| 6282 | try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src); |
| 6283 | |
| 6179 | 6284 | if (block.inlining) |inlining| { |
| 6180 | 6285 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 6181 | | try inlining.merges.results.append(sema.gpa, casted_operand); |
| 6182 | | _ = try block.addBr(inlining.merges.block_inst, casted_operand); |
| 6286 | try inlining.merges.results.append(sema.gpa, operand); |
| 6287 | _ = try block.addBr(inlining.merges.block_inst, operand); |
| 6183 | 6288 | return always_noreturn; |
| 6184 | 6289 | } |
| 6185 | 6290 | |
| 6186 | | _ = try block.addUnOp(.ret, casted_operand); |
| 6291 | _ = try block.addUnOp(.ret, operand); |
| 6187 | 6292 | return always_noreturn; |
| 6188 | 6293 | } |
| 6189 | 6294 | |