| ... | ... | @@ -594,12 +594,55 @@ fn simpleBinOp( |
| 594 | 594 | return rlWrap(mod, scope, rl, result); |
| 595 | 595 | } |
| 596 | 596 | |
| 597 | | fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { |
| 598 | | if (if_node.payload) |payload| { |
| 599 | | return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{}); |
| 597 | const CondKind = union(enum) { |
| 598 | bool, |
| 599 | optional: ?*zir.Inst, |
| 600 | err_union: ?*zir.Inst, |
| 601 | |
| 602 | fn cond(self: *CondKind, mod: *Module, block_scope: *Scope.GenZIR, src: usize, cond_node: *ast.Node) !*zir.Inst { |
| 603 | switch (self.*) { |
| 604 | .bool => { |
| 605 | const bool_type = try addZIRInstConst(mod, &block_scope.base, src, .{ |
| 606 | .ty = Type.initTag(.type), |
| 607 | .val = Value.initTag(.bool_type), |
| 608 | }); |
| 609 | return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node); |
| 610 | }, |
| 611 | .optional => { |
| 612 | const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); |
| 613 | self.* = .{ .optional = cond_ptr }; |
| 614 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); |
| 615 | return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result); |
| 616 | }, |
| 617 | .err_union => unreachable, |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, payload_node: ?*ast.Node) !*Scope { |
| 622 | if (self == .bool) return &then_scope.base; |
| 623 | |
| 624 | const payload = payload_node.?.castTag(.PointerPayload).?; |
| 625 | const is_ptr = payload.ptr_token != null; |
| 626 | const ident_node = payload.value_symbol.castTag(.Identifier).?; |
| 627 | const ident_name = try identifierTokenString(mod, &then_scope.base, ident_node.token); |
| 628 | if (mem.eql(u8, ident_name, "_")) { |
| 629 | if (is_ptr) |
| 630 | return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| 631 | return &then_scope.base; |
| 632 | } |
| 633 | |
| 634 | return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{}); |
| 600 | 635 | } |
| 636 | }; |
| 637 | |
| 638 | fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { |
| 639 | var cond_kind: CondKind = .bool; |
| 640 | if (if_node.payload) |_| cond_kind = .{ .optional = null }; |
| 601 | 641 | if (if_node.@"else") |else_node| { |
| 602 | 642 | if (else_node.payload) |payload| { |
| 643 | if (cond_kind != .optional) { |
| 644 | return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{}); |
| 645 | } |
| 603 | 646 | return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{}); |
| 604 | 647 | } |
| 605 | 648 | } |
| ... | ... | @@ -613,11 +656,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 613 | 656 | |
| 614 | 657 | const tree = scope.tree(); |
| 615 | 658 | const if_src = tree.token_locs[if_node.if_token].start; |
| 616 | | const bool_type = try addZIRInstConst(mod, scope, if_src, .{ |
| 617 | | .ty = Type.initTag(.type), |
| 618 | | .val = Value.initTag(.bool_type), |
| 619 | | }); |
| 620 | | const cond = try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_node.condition); |
| 659 | const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition); |
| 621 | 660 | |
| 622 | 661 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{ |
| 623 | 662 | .condition = cond, |
| ... | ... | @@ -636,6 +675,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 636 | 675 | }; |
| 637 | 676 | defer then_scope.instructions.deinit(mod.gpa); |
| 638 | 677 | |
| 678 | // declare payload to the then_scope |
| 679 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, if_node.payload); |
| 680 | |
| 639 | 681 | // Most result location types can be forwarded directly; however |
| 640 | 682 | // if we need to write to a pointer which has an inferred type, |
| 641 | 683 | // proper type inference requires peer type resolution on the if's |
| ... | ... | @@ -645,10 +687,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 645 | 687 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 646 | 688 | }; |
| 647 | 689 | |
| 648 | | const then_result = try expr(mod, &then_scope.base, branch_rl, if_node.body); |
| 690 | const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body); |
| 649 | 691 | if (!then_result.tag.isNoReturn()) { |
| 650 | 692 | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 651 | | _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{ |
| 693 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| 652 | 694 | .block = block, |
| 653 | 695 | .operand = then_result, |
| 654 | 696 | }, .{}); |
| ... | ... | @@ -690,11 +732,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 690 | 732 | } |
| 691 | 733 | |
| 692 | 734 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { |
| 693 | | if (while_node.payload) |payload| { |
| 694 | | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{}); |
| 695 | | } |
| 735 | var cond_kind: CondKind = .bool; |
| 736 | if (while_node.payload) |_| cond_kind = .{ .optional = null }; |
| 696 | 737 | if (while_node.@"else") |else_node| { |
| 697 | 738 | if (else_node.payload) |payload| { |
| 739 | if (cond_kind != .optional) { |
| 740 | return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{}); |
| 741 | } |
| 698 | 742 | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{}); |
| 699 | 743 | } |
| 700 | 744 | } |
| ... | ... | @@ -725,15 +769,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 725 | 769 | |
| 726 | 770 | const tree = scope.tree(); |
| 727 | 771 | const while_src = tree.token_locs[while_node.while_token].start; |
| 728 | | const bool_type = try addZIRInstConst(mod, scope, while_src, .{ |
| 729 | | .ty = Type.initTag(.type), |
| 730 | | .val = Value.initTag(.bool_type), |
| 731 | | }); |
| 732 | 772 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ |
| 733 | 773 | .ty = Type.initTag(.type), |
| 734 | 774 | .val = Value.initTag(.void_type), |
| 735 | 775 | }); |
| 736 | | const cond = try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_node.condition); |
| 776 | const cond = try cond_kind.cond(mod, &continue_scope, while_src, while_node.condition); |
| 737 | 777 | |
| 738 | 778 | const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ |
| 739 | 779 | .condition = cond, |
| ... | ... | @@ -764,6 +804,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 764 | 804 | }; |
| 765 | 805 | defer then_scope.instructions.deinit(mod.gpa); |
| 766 | 806 | |
| 807 | // declare payload to the then_scope |
| 808 | const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, while_node.payload); |
| 809 | |
| 767 | 810 | // Most result location types can be forwarded directly; however |
| 768 | 811 | // if we need to write to a pointer which has an inferred type, |
| 769 | 812 | // proper type inference requires peer type resolution on the while's |
| ... | ... | @@ -773,10 +816,10 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 773 | 816 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, |
| 774 | 817 | }; |
| 775 | 818 | |
| 776 | | const then_result = try expr(mod, &then_scope.base, branch_rl, while_node.body); |
| 819 | const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body); |
| 777 | 820 | if (!then_result.tag.isNoReturn()) { |
| 778 | 821 | const then_src = tree.token_locs[while_node.body.lastToken()].start; |
| 779 | | _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{ |
| 822 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| 780 | 823 | .block = cond_block, |
| 781 | 824 | .operand = then_result, |
| 782 | 825 | }, .{}); |