| ... | ... | @@ -663,11 +663,27 @@ fn varDecl( |
| 663 | 663 | |
| 664 | 664 | switch (tree.token_ids[node.mut_token]) { |
| 665 | 665 | .Keyword_const => { |
| 666 | | var resolve_inferred_alloc: ?*zir.Inst = null; |
| 667 | 666 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 668 | 667 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 669 | 668 | // the variable, no memory location needed. |
| 670 | | const result_loc = if (nodeMayNeedMemoryLocation(init_node, scope)) r: { |
| 669 | if (!nodeMayNeedMemoryLocation(init_node, scope)) { |
| 670 | const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| |
| 671 | .{ .ty = try typeExpr(mod, scope, type_node) } |
| 672 | else |
| 673 | .none; |
| 674 | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 675 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 676 | sub_scope.* = .{ |
| 677 | .parent = scope, |
| 678 | .gen_zir = scope.getGenZIR(), |
| 679 | .name = ident_name, |
| 680 | .inst = init_inst, |
| 681 | }; |
| 682 | return &sub_scope.base; |
| 683 | } |
| 684 | |
| 685 | var resolve_inferred_alloc: ?*zir.Inst = null; |
| 686 | const result_loc = r: { |
| 671 | 687 | if (node.getTypeNode()) |type_node| { |
| 672 | 688 | const type_inst = try typeExpr(mod, scope, type_node); |
| 673 | 689 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); |
| ... | ... | @@ -677,11 +693,6 @@ fn varDecl( |
| 677 | 693 | resolve_inferred_alloc = &alloc.base; |
| 678 | 694 | break :r ResultLoc{ .inferred_ptr = alloc }; |
| 679 | 695 | } |
| 680 | | } else r: { |
| 681 | | if (node.getTypeNode()) |type_node| |
| 682 | | break :r ResultLoc{ .ty = try typeExpr(mod, scope, type_node) } |
| 683 | | else |
| 684 | | break :r .none; |
| 685 | 696 | }; |
| 686 | 697 | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 687 | 698 | if (resolve_inferred_alloc) |inst| { |
| ... | ... | @@ -1718,14 +1729,20 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1718 | 1729 | switch (strategy) { |
| 1719 | 1730 | .break_void => { |
| 1720 | 1731 | if (!then_result.tag.isNoReturn()) { |
| 1721 | | _ = try addZIRNoOp(mod, then_sub_scope, then_src, .break_void); |
| 1732 | _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ |
| 1733 | .block = block, |
| 1734 | }); |
| 1722 | 1735 | } |
| 1723 | 1736 | if (else_result) |inst| { |
| 1724 | 1737 | if (!inst.tag.isNoReturn()) { |
| 1725 | | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); |
| 1738 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1739 | .block = block, |
| 1740 | }); |
| 1726 | 1741 | } |
| 1727 | 1742 | } else { |
| 1728 | | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); |
| 1743 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1744 | .block = block, |
| 1745 | }); |
| 1729 | 1746 | } |
| 1730 | 1747 | assert(!elide_store_to_block_ptr_instructions); |
| 1731 | 1748 | try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); |
| ... | ... | @@ -1747,7 +1764,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1747 | 1764 | }); |
| 1748 | 1765 | } |
| 1749 | 1766 | } else { |
| 1750 | | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); |
| 1767 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1768 | .block = block, |
| 1769 | }); |
| 1751 | 1770 | } |
| 1752 | 1771 | if (elide_store_to_block_ptr_instructions) { |
| 1753 | 1772 | try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); |
| ... | ... | @@ -2728,31 +2747,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError |
| 2728 | 2747 | return addZIRUnOp(mod, scope, src, .ptrtoint, operand); |
| 2729 | 2748 | } |
| 2730 | 2749 | |
| 2731 | | fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 2750 | fn as( |
| 2751 | mod: *Module, |
| 2752 | scope: *Scope, |
| 2753 | rl: ResultLoc, |
| 2754 | call: *ast.Node.BuiltinCall, |
| 2755 | ) InnerError!*zir.Inst { |
| 2732 | 2756 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 2733 | 2757 | const tree = scope.tree(); |
| 2734 | 2758 | const src = tree.token_locs[call.builtin_token].start; |
| 2735 | 2759 | const params = call.params(); |
| 2736 | 2760 | const dest_type = try typeExpr(mod, scope, params[0]); |
| 2737 | 2761 | switch (rl) { |
| 2738 | | .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]), |
| 2739 | | .discard => { |
| 2762 | .none, .discard, .ref, .ty => { |
| 2740 | 2763 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 2741 | | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 2742 | | return result; |
| 2743 | | }, |
| 2744 | | .ref => { |
| 2745 | | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 2746 | | return addZIRUnOp(mod, scope, result.src, .ref, result); |
| 2747 | | }, |
| 2748 | | .ty => |result_ty| { |
| 2749 | | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 2750 | | return addZIRBinOp(mod, scope, src, .as, result_ty, result); |
| 2764 | return rvalue(mod, scope, rl, result); |
| 2751 | 2765 | }, |
| 2766 | |
| 2752 | 2767 | .ptr => |result_ptr| { |
| 2753 | | const casted_result_ptr = try addZIRBinOp(mod, scope, src, .coerce_result_ptr, dest_type, result_ptr); |
| 2754 | | return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]); |
| 2768 | return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type); |
| 2755 | 2769 | }, |
| 2770 | .block_ptr => |block_scope| { |
| 2771 | return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type); |
| 2772 | }, |
| 2773 | |
| 2756 | 2774 | .bitcasted_ptr => |bitcasted_ptr| { |
| 2757 | 2775 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2758 | 2776 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); |
| ... | ... | @@ -2761,13 +2779,47 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I |
| 2761 | 2779 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2762 | 2780 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); |
| 2763 | 2781 | }, |
| 2764 | | .block_ptr => |block_scope| { |
| 2765 | | const casted_block_ptr = try addZirInstTag(mod, scope, src, .coerce_result_block_ptr, .{ |
| 2766 | | .dest_type = dest_type, |
| 2767 | | .block_ptr = block_scope.rl_ptr.?, |
| 2768 | | }); |
| 2769 | | return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]); |
| 2770 | | }, |
| 2782 | } |
| 2783 | } |
| 2784 | |
| 2785 | fn asRlPtr( |
| 2786 | mod: *Module, |
| 2787 | scope: *Scope, |
| 2788 | rl: ResultLoc, |
| 2789 | src: usize, |
| 2790 | result_ptr: *zir.Inst, |
| 2791 | operand_node: *ast.Node, |
| 2792 | dest_type: *zir.Inst, |
| 2793 | ) InnerError!*zir.Inst { |
| 2794 | // Detect whether this expr() call goes into rvalue() to store the result into the |
| 2795 | // result location. If it does, elide the coerce_result_ptr instruction |
| 2796 | // as well as the store instruction, instead passing the result as an rvalue. |
| 2797 | var as_scope: Scope.GenZIR = .{ |
| 2798 | .parent = scope, |
| 2799 | .decl = scope.ownerDecl().?, |
| 2800 | .arena = scope.arena(), |
| 2801 | .instructions = .{}, |
| 2802 | }; |
| 2803 | defer as_scope.instructions.deinit(mod.gpa); |
| 2804 | |
| 2805 | as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); |
| 2806 | const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); |
| 2807 | const parent_zir = &scope.getGenZIR().instructions; |
| 2808 | if (as_scope.rvalue_rl_count == 1) { |
| 2809 | // Busted! This expression didn't actually need a pointer. |
| 2810 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; |
| 2811 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 2812 | 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), |
| 2816 | } |
| 2817 | } |
| 2818 | assert(parent_zir.items.len == expected_len); |
| 2819 | return rvalue(mod, scope, rl, result); |
| 2820 | } else { |
| 2821 | try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); |
| 2822 | return result; |
| 2771 | 2823 | } |
| 2772 | 2824 | } |
| 2773 | 2825 | |