| ... | @@ -29,6 +29,12 @@ owner_func: ?*Module.Fn, | ... | @@ -29,6 +29,12 @@ owner_func: ?*Module.Fn, |
| 29 | /// This starts out the same as `owner_func` and then diverges in the case of | 29 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 30 | /// an inline or comptime function call. | 30 | /// an inline or comptime function call. |
| 31 | func: ?*Module.Fn, | 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 | branch_quota: u32 = 1000, | 38 | branch_quota: u32 = 1000, |
| 33 | branch_count: u32 = 0, | 39 | branch_count: u32 = 0, |
| 34 | /// This field is updated when a new source location becomes active, so that | 40 | /// This field is updated when a new source location becomes active, so that |
| ... | @@ -628,6 +634,7 @@ fn analyzeAsType( | ... | @@ -628,6 +634,7 @@ fn analyzeAsType( |
| 628 | | 634 | |
| 629 | /// May return Value Tags: `variable`, `undef`. | 635 | /// May return Value Tags: `variable`, `undef`. |
| 630 | /// See `resolveConstValue` for an alternative. | 636 | /// See `resolveConstValue` for an alternative. |
| | 637 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 631 | fn resolveValue( | 638 | fn resolveValue( |
| 632 | sema: *Sema, | 639 | sema: *Sema, |
| 633 | block: *Scope.Block, | 640 | block: *Scope.Block, |
| ... | @@ -679,6 +686,7 @@ fn resolveDefinedValue( | ... | @@ -679,6 +686,7 @@ fn resolveDefinedValue( |
| 679 | | 686 | |
| 680 | /// Value Tag `variable` causes this function to return `null`. | 687 | /// Value Tag `variable` causes this function to return `null`. |
| 681 | /// Value Tag `undef` causes this function to return the Value. | 688 | /// Value Tag `undef` causes this function to return the Value. |
| | 689 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 682 | fn resolveMaybeUndefVal( | 690 | fn resolveMaybeUndefVal( |
| 683 | sema: *Sema, | 691 | sema: *Sema, |
| 684 | block: *Scope.Block, | 692 | block: *Scope.Block, |
| ... | @@ -686,10 +694,11 @@ fn resolveMaybeUndefVal( | ... | @@ -686,10 +694,11 @@ fn resolveMaybeUndefVal( |
| 686 | inst: Air.Inst.Ref, | 694 | inst: Air.Inst.Ref, |
| 687 | ) CompileError!?Value { | 695 | ) CompileError!?Value { |
| 688 | const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; | 696 | const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; |
| 689 | if (val.tag() == .variable) { | 697 | switch (val.tag()) { |
| 690 | return null; | 698 | .variable => return null, |
| | 699 | .generic_poison => return error.GenericPoison, |
| | 700 | else => return val, |
| 691 | } | 701 | } |
| 692 | return val; | | |
| 693 | } | 702 | } |
| 694 | | 703 | |
| 695 | /// Returns all Value tags including `variable` and `undef`. | 704 | /// Returns all Value tags including `variable` and `undef`. |
| ... | @@ -1033,6 +1042,7 @@ fn zirEnumDecl( | ... | @@ -1033,6 +1042,7 @@ fn zirEnumDecl( |
| 1033 | .namespace = &enum_obj.namespace, | 1042 | .namespace = &enum_obj.namespace, |
| 1034 | .owner_func = null, | 1043 | .owner_func = null, |
| 1035 | .func = null, | 1044 | .func = null, |
| | 1045 | .fn_ret_ty = Type.initTag(.void), |
| 1036 | .branch_quota = sema.branch_quota, | 1046 | .branch_quota = sema.branch_quota, |
| 1037 | .branch_count = sema.branch_count, | 1047 | .branch_count = sema.branch_count, |
| 1038 | }; | 1048 | }; |
| ... | @@ -1238,9 +1248,7 @@ fn zirRetPtr( | ... | @@ -1238,9 +1248,7 @@ fn zirRetPtr( |
| 1238 | | 1248 | |
| 1239 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | 1249 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 1240 | try sema.requireFunctionBlock(block, src); | 1250 | try sema.requireFunctionBlock(block, src); |
| 1241 | const fn_ty = sema.func.?.owner_decl.ty; | 1251 | const ptr_type = try Module.simplePtrType(sema.arena, sema.fn_ret_ty, true, .One); |
| 1242 | const ret_type = fn_ty.fnReturnType(); | | |
| 1243 | const ptr_type = try Module.simplePtrType(sema.arena, ret_type, true, .One); | | |
| 1244 | return block.addTy(.alloc, ptr_type); | 1252 | return block.addTy(.alloc, ptr_type); |
| 1245 | } | 1253 | } |
| 1246 | | 1254 | |
| ... | @@ -1263,9 +1271,7 @@ fn zirRetType( | ... | @@ -1263,9 +1271,7 @@ fn zirRetType( |
| 1263 | | 1271 | |
| 1264 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | 1272 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 1265 | try sema.requireFunctionBlock(block, src); | 1273 | try sema.requireFunctionBlock(block, src); |
| 1266 | const fn_ty = sema.func.?.owner_decl.ty; | 1274 | return sema.addType(sema.fn_ret_ty); |
| 1267 | const ret_type = fn_ty.fnReturnType(); | | |
| 1268 | return sema.addType(ret_type); | | |
| 1269 | } | 1275 | } |
| 1270 | | 1276 | |
| 1271 | fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { | 1277 | fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | @@ -2364,7 +2370,7 @@ const GenericCallAdapter = struct { | ... | @@ -2364,7 +2370,7 @@ const GenericCallAdapter = struct { |
| 2364 | generic_fn: *Module.Fn, | 2370 | generic_fn: *Module.Fn, |
| 2365 | precomputed_hash: u64, | 2371 | precomputed_hash: u64, |
| 2366 | func_ty_info: Type.Payload.Function.Data, | 2372 | func_ty_info: Type.Payload.Function.Data, |
| 2367 | comptime_vals: []const Value, | 2373 | comptime_tvs: []const TypedValue, |
| 2368 | | 2374 | |
| 2369 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { | 2375 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { |
| 2370 | _ = adapted_key; | 2376 | _ = adapted_key; |
| ... | @@ -2373,12 +2379,22 @@ const GenericCallAdapter = struct { | ... | @@ -2373,12 +2379,22 @@ const GenericCallAdapter = struct { |
| 2373 | const generic_owner_decl = other_key.owner_decl.dependencies.keys()[0]; | 2379 | const generic_owner_decl = other_key.owner_decl.dependencies.keys()[0]; |
| 2374 | if (ctx.generic_fn.owner_decl != generic_owner_decl) return false; | 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 | const other_comptime_args = other_key.comptime_args.?; | 2382 | const other_comptime_args = other_key.comptime_args.?; |
| 2379 | for (ctx.func_ty_info.param_types) |param_ty, i| { | 2383 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { |
| 2380 | if (ctx.func_ty_info.paramIsComptime(i) and param_ty.tag() != .generic_poison) { | 2384 | if (other_arg.ty.tag() != .generic_poison) { |
| 2381 | if (!ctx.comptime_vals[i].eql(other_comptime_args[i].val, param_ty)) { | 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 | return false; | 2398 | return false; |
| 2383 | } | 2399 | } |
| 2384 | } | 2400 | } |
| ... | @@ -2394,6 +2410,22 @@ const GenericCallAdapter = struct { | ... | @@ -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 | fn analyzeCall( | 2429 | fn analyzeCall( |
| 2398 | sema: *Sema, | 2430 | sema: *Sema, |
| 2399 | block: *Scope.Block, | 2431 | block: *Scope.Block, |
| ... | @@ -2466,14 +2498,6 @@ fn analyzeCall( | ... | @@ -2466,14 +2498,6 @@ fn analyzeCall( |
| 2466 | const is_inline_call = is_comptime_call or modifier == .always_inline or | 2498 | const is_inline_call = is_comptime_call or modifier == .always_inline or |
| 2467 | func_ty_info.cc == .Inline; | 2499 | func_ty_info.cc == .Inline; |
| 2468 | const result: Air.Inst.Ref = if (is_inline_call) res: { | 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 | const func_val = try sema.resolveConstValue(block, func_src, func); | 2501 | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 2478 | const module_fn = switch (func_val.tag()) { | 2502 | const module_fn = switch (func_val.tag()) { |
| 2479 | .function => func_val.castTag(.function).?.data, | 2503 | .function => func_val.castTag(.function).?.data, |
| ... | @@ -2544,19 +2568,62 @@ fn analyzeCall( | ... | @@ -2544,19 +2568,62 @@ fn analyzeCall( |
| 2544 | // This will have return instructions analyzed as break instructions to | 2568 | // This will have return instructions analyzed as break instructions to |
| 2545 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" | 2569 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| 2546 | // for a function body, which means we must map the parameter ZIR instructions to | 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 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); | 2574 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); |
| 2549 | const zir_tags = sema.code.instructions.items(.tag); | 2575 | const zir_tags = sema.code.instructions.items(.tag); |
| 2550 | var arg_i: usize = 0; | 2576 | var arg_i: usize = 0; |
| 2551 | try sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, args.len)); | 2577 | for (fn_info.param_body) |inst| switch (zir_tags[inst]) { |
| 2552 | for (fn_info.param_body) |inst| { | 2578 | .param, .param_comptime => { |
| 2553 | switch (zir_tags[inst]) { | 2579 | // Evaluate the parameter type expression now that previous ones have |
| 2554 | .param, .param_comptime, .param_anytype, .param_anytype_comptime => {}, | 2580 | // been mapped, and coerce the corresponding argument to it. |
| 2555 | else => continue, | 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]); | 2621 | break :blk bare_return_type; |
| 2558 | arg_i += 1; | 2622 | }; |
| 2559 | } | 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 | _ = try sema.analyzeBody(&child_block, fn_info.body); | 2627 | _ = try sema.analyzeBody(&child_block, fn_info.body); |
| 2561 | break :res try sema.analyzeBlockBody(block, call_src, &child_block, merges); | 2628 | break :res try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 2562 | } else if (func_ty_info.is_generic) res: { | 2629 | } else if (func_ty_info.is_generic) res: { |
| ... | @@ -2569,57 +2636,74 @@ fn analyzeCall( | ... | @@ -2569,57 +2636,74 @@ fn analyzeCall( |
| 2569 | const fn_zir = namespace.file_scope.zir; | 2636 | const fn_zir = namespace.file_scope.zir; |
| 2570 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); | 2637 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 2571 | const zir_tags = fn_zir.instructions.items(.tag); | 2638 | const zir_tags = fn_zir.instructions.items(.tag); |
| 2572 | const new_module_func = new_func: { | 2639 | |
| 2573 | // This hash must match `Module.MonomorphedFuncsContext.hash`. | 2640 | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 2574 | // For parameters explicitly marked comptime and simple parameter type expressions, | 2641 | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 2575 | // we know whether a parameter is elided from a monomorphed function, and can | 2642 | // 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 | 2643 | // 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 | 2644 | // 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 | 2645 | // don't find out until after generating a monomorphed function whether the parameter |
| 2579 | // type ended up being a "must-be-comptime-known" type. | 2646 | // type ended up being a "must-be-comptime-known" type. |
| 2580 | var hasher = std.hash.Wyhash.init(0); | 2647 | var hasher = std.hash.Wyhash.init(0); |
| 2581 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); | 2648 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 2582 | | 2649 | |
| 2583 | const comptime_vals = try sema.arena.alloc(Value, func_ty_info.param_types.len); | 2650 | const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); |
| 2584 | | 2651 | |
| 2585 | for (func_ty_info.param_types) |param_ty, i| { | 2652 | for (func_ty_info.param_types) |param_ty, i| { |
| 2586 | const is_comptime = func_ty_info.paramIsComptime(i); | 2653 | const is_comptime = func_ty_info.paramIsComptime(i); |
| 2587 | if (is_comptime and param_ty.tag() != .generic_poison) { | 2654 | if (is_comptime) { |
| 2588 | const arg_src = call_src; // TODO better source location | 2655 | const arg_src = call_src; // TODO better source location |
| 2589 | const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); | 2656 | 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| { | 2657 | if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { |
| | 2658 | if (param_ty.tag() != .generic_poison) { |
| 2591 | arg_val.hash(param_ty, &hasher); | 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 = .{ | 2677 | const precomputed_hash = hasher.final(); |
| 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 | }; | | |
| 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 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); | 2707 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 2624 | | 2708 | |
| 2625 | // Create a Decl for the new function. | 2709 | // Create a Decl for the new function. |
| ... | @@ -2658,6 +2742,7 @@ fn analyzeCall( | ... | @@ -2658,6 +2742,7 @@ fn analyzeCall( |
| 2658 | .owner_decl = new_decl, | 2742 | .owner_decl = new_decl, |
| 2659 | .namespace = namespace, | 2743 | .namespace = namespace, |
| 2660 | .func = null, | 2744 | .func = null, |
| | 2745 | .fn_ret_ty = Type.initTag(.void), |
| 2661 | .owner_func = null, | 2746 | .owner_func = null, |
| 2662 | .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len), | 2747 | .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len), |
| 2663 | .comptime_args_fn_inst = module_fn.zir_body_inst, | 2748 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| ... | @@ -2681,11 +2766,25 @@ fn analyzeCall( | ... | @@ -2681,11 +2766,25 @@ fn analyzeCall( |
| 2681 | try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); | 2766 | try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); |
| 2682 | var arg_i: usize = 0; | 2767 | var arg_i: usize = 0; |
| 2683 | for (fn_info.param_body) |inst| { | 2768 | for (fn_info.param_body) |inst| { |
| 2684 | const is_comptime = switch (zir_tags[inst]) { | 2769 | var is_comptime = false; |
| 2685 | .param_comptime, .param_anytype_comptime => true, | 2770 | var is_anytype = false; |
| 2686 | .param, .param_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 | else => continue, | 2786 | else => continue, |
| 2688 | } or func_ty_info.paramIsComptime(arg_i); | 2787 | } |
| 2689 | const arg_src = call_src; // TODO: better source location | 2788 | const arg_src = call_src; // TODO: better source location |
| 2690 | const arg = uncasted_args[arg_i]; | 2789 | const arg = uncasted_args[arg_i]; |
| 2691 | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { | 2790 | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { |
| ... | @@ -2693,6 +2792,12 @@ fn analyzeCall( | ... | @@ -2693,6 +2792,12 @@ fn analyzeCall( |
| 2693 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); | 2792 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 2694 | } else if (is_comptime) { | 2793 | } else if (is_comptime) { |
| 2695 | return sema.failWithNeededComptime(block, arg_src); | 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 | arg_i += 1; | 2802 | arg_i += 1; |
| 2698 | } | 2803 | } |
| ... | @@ -2710,17 +2815,10 @@ fn analyzeCall( | ... | @@ -2710,17 +2815,10 @@ fn analyzeCall( |
| 2710 | const arg = child_sema.inst_map.get(inst).?; | 2815 | const arg = child_sema.inst_map.get(inst).?; |
| 2711 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?; | 2816 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?; |
| 2712 | | 2817 | |
| 2713 | if (arg_val.tag() == .generic_poison) { | 2818 | child_sema.comptime_args[arg_i] = .{ |
| 2714 | child_sema.comptime_args[arg_i] = .{ | 2819 | .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator), |
| 2715 | .ty = Type.initTag(.noreturn), | 2820 | .val = try arg_val.copy(&new_decl_arena.allocator), |
| 2716 | .val = Value.initTag(.unreachable_value), | 2821 | }; |
| 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 | } | | |
| 2724 | | 2822 | |
| 2725 | arg_i += 1; | 2823 | arg_i += 1; |
| 2726 | } | 2824 | } |
| ... | @@ -2730,6 +2828,18 @@ fn analyzeCall( | ... | @@ -2730,6 +2828,18 @@ fn analyzeCall( |
| 2730 | new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func); | 2828 | new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func); |
| 2731 | new_decl.analysis = .complete; | 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 | // The generic function Decl is guaranteed to be the first dependency | 2843 | // The generic function Decl is guaranteed to be the first dependency |
| 2734 | // of each of its instantiations. | 2844 | // of each of its instantiations. |
| 2735 | assert(new_decl.dependencies.keys().len == 0); | 2845 | assert(new_decl.dependencies.keys().len == 0); |
| ... | @@ -2809,7 +2919,7 @@ fn finishGenericCall( | ... | @@ -2809,7 +2919,7 @@ fn finishGenericCall( |
| 2809 | for (fn_info.param_body) |inst| { | 2919 | for (fn_info.param_body) |inst| { |
| 2810 | switch (zir_tags[inst]) { | 2920 | switch (zir_tags[inst]) { |
| 2811 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => { | 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 | count += 1; | 2923 | count += 1; |
| 2814 | } | 2924 | } |
| 2815 | arg_i += 1; | 2925 | arg_i += 1; |
| ... | @@ -2829,7 +2939,7 @@ fn finishGenericCall( | ... | @@ -2829,7 +2939,7 @@ fn finishGenericCall( |
| 2829 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, | 2939 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, |
| 2830 | else => continue, | 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 | if (is_runtime) { | 2943 | if (is_runtime) { |
| 2834 | const param_ty = new_fn_ty.fnParamType(runtime_i); | 2944 | const param_ty = new_fn_ty.fnParamType(runtime_i); |
| 2835 | const arg_src = call_src; // TODO: better source location | 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,28 +6272,23 @@ fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr |
| 6162 | fn analyzeRet( | 6272 | fn analyzeRet( |
| 6163 | sema: *Sema, | 6273 | sema: *Sema, |
| 6164 | block: *Scope.Block, | 6274 | block: *Scope.Block, |
| 6165 | operand: Air.Inst.Ref, | 6275 | uncasted_operand: Air.Inst.Ref, |
| 6166 | src: LazySrcLoc, | 6276 | src: LazySrcLoc, |
| 6167 | need_coercion: bool, | 6277 | need_coercion: bool, |
| 6168 | ) CompileError!Zir.Inst.Index { | 6278 | ) CompileError!Zir.Inst.Index { |
| 6169 | const casted_operand = if (!need_coercion) operand else op: { | 6279 | const operand = if (!need_coercion) |
| 6170 | const func = sema.func.?; | 6280 | uncasted_operand |
| 6171 | const fn_ty = func.owner_decl.ty; | 6281 | else |
| 6172 | // TODO: In the case of a comptime/inline function call of a generic function, | 6282 | try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src); |
| 6173 | // this needs to be the resolved return type based on the function parameter type | 6283 | |
| 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 | }; | | |
| 6179 | if (block.inlining) |inlining| { | 6284 | if (block.inlining) |inlining| { |
| 6180 | // We are inlining a function call; rewrite the `ret` as a `break`. | 6285 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 6181 | try inlining.merges.results.append(sema.gpa, casted_operand); | 6286 | try inlining.merges.results.append(sema.gpa, operand); |
| 6182 | _ = try block.addBr(inlining.merges.block_inst, casted_operand); | 6287 | _ = try block.addBr(inlining.merges.block_inst, operand); |
| 6183 | return always_noreturn; | 6288 | return always_noreturn; |
| 6184 | } | 6289 | } |
| 6185 | | 6290 | |
| 6186 | _ = try block.addUnOp(.ret, casted_operand); | 6291 | _ = try block.addUnOp(.ret, operand); |
| 6187 | return always_noreturn; | 6292 | return always_noreturn; |
| 6188 | } | 6293 | } |
| 6189 | | 6294 | |