| ... | ... | @@ -682,28 +682,77 @@ fn varDecl( |
| 682 | 682 | return &sub_scope.base; |
| 683 | 683 | } |
| 684 | 684 | |
| 685 | // Detect whether the initialization expression actually uses the |
| 686 | // result location pointer. |
| 687 | var init_scope: Scope.GenZIR = .{ |
| 688 | .parent = scope, |
| 689 | .decl = scope.ownerDecl().?, |
| 690 | .arena = scope.arena(), |
| 691 | .instructions = .{}, |
| 692 | }; |
| 693 | defer init_scope.instructions.deinit(mod.gpa); |
| 694 | |
| 685 | 695 | var resolve_inferred_alloc: ?*zir.Inst = null; |
| 686 | | const result_loc = r: { |
| 687 | | if (node.getTypeNode()) |type_node| { |
| 688 | | const type_inst = try typeExpr(mod, scope, type_node); |
| 689 | | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); |
| 690 | | break :r ResultLoc{ .ptr = alloc }; |
| 691 | | } else { |
| 692 | | const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred); |
| 693 | | resolve_inferred_alloc = &alloc.base; |
| 694 | | break :r ResultLoc{ .inferred_ptr = alloc }; |
| 696 | if (node.getTypeNode()) |type_node| { |
| 697 | const type_inst = try typeExpr(mod, &init_scope.base, type_node); |
| 698 | const alloc = try addZIRUnOp(mod, &init_scope.base, name_src, .alloc, type_inst); |
| 699 | init_scope.rl_ptr = alloc; |
| 700 | } else { |
| 701 | const alloc = try addZIRNoOpT(mod, &init_scope.base, name_src, .alloc_inferred); |
| 702 | resolve_inferred_alloc = &alloc.base; |
| 703 | init_scope.rl_ptr = &alloc.base; |
| 704 | } |
| 705 | const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; |
| 706 | const init_inst = try expr(mod, &init_scope.base, init_result_loc, init_node); |
| 707 | const parent_zir = &scope.getGenZIR().instructions; |
| 708 | if (init_scope.rvalue_rl_count == 1) { |
| 709 | // Result location pointer not used. We don't need an alloc for this |
| 710 | // const local, and type inference becomes trivial. |
| 711 | // Move the init_scope instructions into the parent scope, eliding |
| 712 | // the alloc instruction and the store_to_block_ptr instruction. |
| 713 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2; |
| 714 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 715 | for (init_scope.instructions.items) |src_inst| { |
| 716 | if (src_inst == init_scope.rl_ptr.?) continue; |
| 717 | if (src_inst.castTag(.store_to_block_ptr)) |store| { |
| 718 | if (store.positionals.lhs == init_scope.rl_ptr.?) continue; |
| 719 | } |
| 720 | parent_zir.appendAssumeCapacity(src_inst); |
| 695 | 721 | } |
| 696 | | }; |
| 697 | | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 722 | assert(parent_zir.items.len == expected_len); |
| 723 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 724 | sub_scope.* = .{ |
| 725 | .parent = scope, |
| 726 | .gen_zir = scope.getGenZIR(), |
| 727 | .name = ident_name, |
| 728 | .inst = init_inst, |
| 729 | }; |
| 730 | return &sub_scope.base; |
| 731 | } |
| 732 | // The initialization expression took advantage of the result location |
| 733 | // of the const local. In this case we will create an alloc and a LocalPtr for it. |
| 734 | // Move the init_scope instructions into the parent scope, swapping |
| 735 | // store_to_block_ptr for store_to_inferred_ptr. |
| 736 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; |
| 737 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 738 | for (init_scope.instructions.items) |src_inst| { |
| 739 | if (src_inst.castTag(.store_to_block_ptr)) |store| { |
| 740 | if (store.positionals.lhs == init_scope.rl_ptr.?) { |
| 741 | src_inst.tag = .store_to_inferred_ptr; |
| 742 | } |
| 743 | } |
| 744 | parent_zir.appendAssumeCapacity(src_inst); |
| 745 | } |
| 746 | assert(parent_zir.items.len == expected_len); |
| 698 | 747 | if (resolve_inferred_alloc) |inst| { |
| 699 | 748 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); |
| 700 | 749 | } |
| 701 | | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 750 | const sub_scope = try block_arena.create(Scope.LocalPtr); |
| 702 | 751 | sub_scope.* = .{ |
| 703 | 752 | .parent = scope, |
| 704 | 753 | .gen_zir = scope.getGenZIR(), |
| 705 | 754 | .name = ident_name, |
| 706 | | .inst = init_inst, |
| 755 | .ptr = init_scope.rl_ptr.?, |
| 707 | 756 | }; |
| 708 | 757 | return &sub_scope.base; |
| 709 | 758 | }, |
| ... | ... | @@ -2810,13 +2859,15 @@ fn asRlPtr( |
| 2810 | 2859 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; |
| 2811 | 2860 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 2812 | 2861 | for (as_scope.instructions.items) |src_inst| { |
| 2813 | | switch (src_inst.tag) { |
| 2814 | | .store_to_block_ptr, .coerce_result_ptr => continue, |
| 2815 | | else => parent_zir.appendAssumeCapacity(src_inst), |
| 2862 | if (src_inst == as_scope.rl_ptr.?) continue; |
| 2863 | if (src_inst.castTag(.store_to_block_ptr)) |store| { |
| 2864 | if (store.positionals.lhs == as_scope.rl_ptr.?) continue; |
| 2816 | 2865 | } |
| 2866 | parent_zir.appendAssumeCapacity(src_inst); |
| 2817 | 2867 | } |
| 2818 | 2868 | assert(parent_zir.items.len == expected_len); |
| 2819 | | return rvalue(mod, scope, rl, result); |
| 2869 | const casted_result = try addZIRBinOp(mod, scope, result.src, .as, dest_type, result); |
| 2870 | return rvalue(mod, scope, rl, casted_result); |
| 2820 | 2871 | } else { |
| 2821 | 2872 | try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); |
| 2822 | 2873 | return result; |