| ... | ... | @@ -277,10 +277,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 277 | 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 278 | 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 279 | 279 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), |
| 280 | .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), |
| 280 | 281 | |
| 281 | 282 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 282 | 283 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| 283 | | .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}), |
| 284 | 284 | .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), |
| 285 | 285 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), |
| 286 | 286 | .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| ... | ... | @@ -790,13 +790,31 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!* |
| 790 | 790 | } |
| 791 | 791 | |
| 792 | 792 | fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { |
| 793 | return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .iserr, .unwrap_err_unsafe, node.rhs, node.payload); |
| 794 | } |
| 795 | |
| 796 | fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { |
| 797 | return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .isnull, .unwrap_optional_unsafe, node.rhs, null); |
| 798 | } |
| 799 | |
| 800 | fn orelseCatchExpr( |
| 801 | mod: *Module, |
| 802 | scope: *Scope, |
| 803 | rl: ResultLoc, |
| 804 | lhs: *ast.Node, |
| 805 | op_token: ast.TokenIndex, |
| 806 | cond_op: zir.Inst.Tag, |
| 807 | unwrap_op: zir.Inst.Tag, |
| 808 | rhs: *ast.Node, |
| 809 | payload_node: ?*ast.Node, |
| 810 | ) InnerError!*zir.Inst { |
| 793 | 811 | const tree = scope.tree(); |
| 794 | | const src = tree.token_locs[node.op_token].start; |
| 812 | const src = tree.token_locs[op_token].start; |
| 795 | 813 | |
| 796 | | const err_union_ptr = try expr(mod, scope, .ref, node.lhs); |
| 797 | | // TODO we could avoid an unnecessary copy if .iserr took a pointer |
| 798 | | const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr); |
| 799 | | const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union); |
| 814 | const operand_ptr = try expr(mod, scope, .ref, lhs); |
| 815 | // TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer |
| 816 | const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr); |
| 817 | const cond = try addZIRUnOp(mod, scope, src, cond_op, err_union); |
| 800 | 818 | |
| 801 | 819 | var block_scope: Scope.GenZIR = .{ |
| 802 | 820 | .parent = scope, |
| ... | ... | @@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 825 | 843 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 826 | 844 | }; |
| 827 | 845 | |
| 828 | | var err_scope: Scope.GenZIR = .{ |
| 846 | var then_scope: Scope.GenZIR = .{ |
| 829 | 847 | .parent = scope, |
| 830 | 848 | .decl = block_scope.decl, |
| 831 | 849 | .arena = block_scope.arena, |
| 832 | 850 | .instructions = .{}, |
| 833 | 851 | }; |
| 834 | | defer err_scope.instructions.deinit(mod.gpa); |
| 852 | defer then_scope.instructions.deinit(mod.gpa); |
| 835 | 853 | |
| 836 | 854 | var err_val_scope: Scope.LocalVal = undefined; |
| 837 | | const err_sub_scope = blk: { |
| 838 | | const payload = node.payload orelse |
| 839 | | break :blk &err_scope.base; |
| 855 | const then_sub_scope = blk: { |
| 856 | const payload = payload_node orelse |
| 857 | break :blk &then_scope.base; |
| 840 | 858 | |
| 841 | 859 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 842 | 860 | if (mem.eql(u8, err_name, "_")) |
| 843 | | break :blk &err_scope.base; |
| 861 | break :blk &then_scope.base; |
| 844 | 862 | |
| 845 | | const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr); |
| 863 | const unwrapped_err_ptr = try addZIRUnOp(mod, &then_scope.base, src, .unwrap_err_code, operand_ptr); |
| 846 | 864 | err_val_scope = .{ |
| 847 | | .parent = &err_scope.base, |
| 848 | | .gen_zir = &err_scope, |
| 865 | .parent = &then_scope.base, |
| 866 | .gen_zir = &then_scope, |
| 849 | 867 | .name = err_name, |
| 850 | | .inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr), |
| 868 | .inst = try addZIRUnOp(mod, &then_scope.base, src, .deref, unwrapped_err_ptr), |
| 851 | 869 | }; |
| 852 | 870 | break :blk &err_val_scope.base; |
| 853 | 871 | }; |
| 854 | 872 | |
| 855 | | _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{ |
| 873 | _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ |
| 856 | 874 | .block = block, |
| 857 | | .operand = try expr(mod, err_sub_scope, branch_rl, node.rhs), |
| 875 | .operand = try expr(mod, then_sub_scope, branch_rl, rhs), |
| 858 | 876 | }, .{}); |
| 859 | 877 | |
| 860 | | var not_err_scope: Scope.GenZIR = .{ |
| 878 | var else_scope: Scope.GenZIR = .{ |
| 861 | 879 | .parent = scope, |
| 862 | 880 | .decl = block_scope.decl, |
| 863 | 881 | .arena = block_scope.arena, |
| 864 | 882 | .instructions = .{}, |
| 865 | 883 | }; |
| 866 | | defer not_err_scope.instructions.deinit(mod.gpa); |
| 884 | defer else_scope.instructions.deinit(mod.gpa); |
| 867 | 885 | |
| 868 | | const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr); |
| 869 | | _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{ |
| 886 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand_ptr); |
| 887 | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ |
| 870 | 888 | .block = block, |
| 871 | 889 | .operand = unwrapped_payload, |
| 872 | 890 | }, .{}); |
| 873 | 891 | |
| 874 | | condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) }; |
| 875 | | condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) }; |
| 876 | | return rlWrap(mod, scope, rl, &block.base); |
| 892 | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; |
| 893 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; |
| 894 | return rlWrapPtr(mod, scope, rl, &block.base); |
| 877 | 895 | } |
| 878 | 896 | |
| 879 | 897 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. |