| ... | ... | @@ -614,11 +614,16 @@ const CondKind = union(enum) { |
| 614 | 614 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); |
| 615 | 615 | return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result); |
| 616 | 616 | }, |
| 617 | | .err_union => unreachable, |
| 617 | .err_union => { |
| 618 | const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); |
| 619 | self.* = .{ .err_union = err_ptr }; |
| 620 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); |
| 621 | return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result); |
| 622 | }, |
| 618 | 623 | } |
| 619 | 624 | } |
| 620 | 625 | |
| 621 | | fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, payload_node: ?*ast.Node) !*Scope { |
| 626 | fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { |
| 622 | 627 | if (self == .bool) return &then_scope.base; |
| 623 | 628 | |
| 624 | 629 | const payload = payload_node.?.castTag(.PointerPayload).?; |
| ... | ... | @@ -633,6 +638,21 @@ const CondKind = union(enum) { |
| 633 | 638 | |
| 634 | 639 | return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{}); |
| 635 | 640 | } |
| 641 | |
| 642 | fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { |
| 643 | if (self != .err_union) return &else_scope.base; |
| 644 | |
| 645 | const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .unwrap_err_unsafe, self.err_union.?); |
| 646 | |
| 647 | const payload = payload_node.?.castTag(.Payload).?; |
| 648 | const ident_node = payload.error_symbol.castTag(.Identifier).?; |
| 649 | const ident_name = try identifierTokenString(mod, &else_scope.base, ident_node.token); |
| 650 | if (mem.eql(u8, ident_name, "_")) { |
| 651 | return &else_scope.base; |
| 652 | } |
| 653 | |
| 654 | return mod.failNode(&else_scope.base, payload.error_symbol, "TODO implement payload symbols", .{}); |
| 655 | } |
| 636 | 656 | }; |
| 637 | 657 | |
| 638 | 658 | fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { |
| ... | ... | @@ -643,7 +663,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 643 | 663 | if (cond_kind != .optional) { |
| 644 | 664 | return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{}); |
| 645 | 665 | } |
| 646 | | return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{}); |
| 666 | cond_kind = .{ .err_union = null }; |
| 647 | 667 | } |
| 648 | 668 | } |
| 649 | 669 | var block_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -667,6 +687,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 667 | 687 | const block = try addZIRInstBlock(mod, scope, if_src, .{ |
| 668 | 688 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 669 | 689 | }); |
| 690 | |
| 691 | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 670 | 692 | var then_scope: Scope.GenZIR = .{ |
| 671 | 693 | .parent = scope, |
| 672 | 694 | .decl = block_scope.decl, |
| ... | ... | @@ -676,7 +698,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 676 | 698 | defer then_scope.instructions.deinit(mod.gpa); |
| 677 | 699 | |
| 678 | 700 | // declare payload to the then_scope |
| 679 | | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, if_node.payload); |
| 701 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload); |
| 680 | 702 | |
| 681 | 703 | // Most result location types can be forwarded directly; however |
| 682 | 704 | // if we need to write to a pointer which has an inferred type, |
| ... | ... | @@ -689,7 +711,6 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 689 | 711 | |
| 690 | 712 | const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body); |
| 691 | 713 | if (!then_result.tag.isNoReturn()) { |
| 692 | | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 693 | 714 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| 694 | 715 | .block = block, |
| 695 | 716 | .operand = then_result, |
| ... | ... | @@ -708,10 +729,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 708 | 729 | defer else_scope.instructions.deinit(mod.gpa); |
| 709 | 730 | |
| 710 | 731 | if (if_node.@"else") |else_node| { |
| 711 | | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); |
| 732 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 733 | // declare payload to the then_scope |
| 734 | const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); |
| 735 | |
| 736 | const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body); |
| 712 | 737 | if (!else_result.tag.isNoReturn()) { |
| 713 | | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 714 | | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ |
| 738 | _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{ |
| 715 | 739 | .block = block, |
| 716 | 740 | .operand = else_result, |
| 717 | 741 | }, .{}); |
| ... | ... | @@ -739,7 +763,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 739 | 763 | if (cond_kind != .optional) { |
| 740 | 764 | return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{}); |
| 741 | 765 | } |
| 742 | | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{}); |
| 766 | cond_kind = .{ .err_union = null }; |
| 743 | 767 | } |
| 744 | 768 | } |
| 745 | 769 | |
| ... | ... | @@ -796,6 +820,8 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 796 | 820 | const while_block = try addZIRInstBlock(mod, scope, while_src, .{ |
| 797 | 821 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), |
| 798 | 822 | }); |
| 823 | |
| 824 | const then_src = tree.token_locs[while_node.body.lastToken()].start; |
| 799 | 825 | var then_scope: Scope.GenZIR = .{ |
| 800 | 826 | .parent = &continue_scope.base, |
| 801 | 827 | .decl = continue_scope.decl, |
| ... | ... | @@ -805,7 +831,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 805 | 831 | defer then_scope.instructions.deinit(mod.gpa); |
| 806 | 832 | |
| 807 | 833 | // declare payload to the then_scope |
| 808 | | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, while_node.payload); |
| 834 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload); |
| 809 | 835 | |
| 810 | 836 | // Most result location types can be forwarded directly; however |
| 811 | 837 | // if we need to write to a pointer which has an inferred type, |
| ... | ... | @@ -818,7 +844,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 818 | 844 | |
| 819 | 845 | const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body); |
| 820 | 846 | if (!then_result.tag.isNoReturn()) { |
| 821 | | const then_src = tree.token_locs[while_node.body.lastToken()].start; |
| 822 | 847 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| 823 | 848 | .block = cond_block, |
| 824 | 849 | .operand = then_result, |
| ... | ... | @@ -837,10 +862,13 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 837 | 862 | defer else_scope.instructions.deinit(mod.gpa); |
| 838 | 863 | |
| 839 | 864 | if (while_node.@"else") |else_node| { |
| 840 | | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); |
| 865 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 866 | // declare payload to the then_scope |
| 867 | const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); |
| 868 | |
| 869 | const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body); |
| 841 | 870 | if (!else_result.tag.isNoReturn()) { |
| 842 | | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 843 | | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ |
| 871 | _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{ |
| 844 | 872 | .block = while_block, |
| 845 | 873 | .operand = else_result, |
| 846 | 874 | }, .{}); |