| ... | @@ -594,12 +594,55 @@ fn simpleBinOp( | ... | @@ -594,12 +594,55 @@ fn simpleBinOp( |
| 594 | return rlWrap(mod, scope, rl, result); | 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 { | 597 | const CondKind = union(enum) { |
| 598 | if (if_node.payload) |payload| { | 598 | bool, |
| 599 | return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{}); | 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 | if (if_node.@"else") |else_node| { | 641 | if (if_node.@"else") |else_node| { |
| 602 | if (else_node.payload) |payload| { | 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 | return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{}); | 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,11 +656,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 613 | | 656 | |
| 614 | const tree = scope.tree(); | 657 | const tree = scope.tree(); |
| 615 | const if_src = tree.token_locs[if_node.if_token].start; | 658 | const if_src = tree.token_locs[if_node.if_token].start; |
| 616 | const bool_type = try addZIRInstConst(mod, scope, if_src, .{ | 659 | const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition); |
| 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); | | |
| 621 | | 660 | |
| 622 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{ | 661 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{ |
| 623 | .condition = cond, | 662 | .condition = cond, |
| ... | @@ -636,6 +675,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -636,6 +675,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 636 | }; | 675 | }; |
| 637 | defer then_scope.instructions.deinit(mod.gpa); | 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 | // Most result location types can be forwarded directly; however | 681 | // Most result location types can be forwarded directly; however |
| 640 | // if we need to write to a pointer which has an inferred type, | 682 | // if we need to write to a pointer which has an inferred type, |
| 641 | // proper type inference requires peer type resolution on the if's | 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,10 +687,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 645 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | 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 | if (!then_result.tag.isNoReturn()) { | 691 | if (!then_result.tag.isNoReturn()) { |
| 650 | const then_src = tree.token_locs[if_node.body.lastToken()].start; | 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 | .block = block, | 694 | .block = block, |
| 653 | .operand = then_result, | 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,11 +732,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 690 | } | 732 | } |
| 691 | | 733 | |
| 692 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { | 734 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { |
| 693 | if (while_node.payload) |payload| { | 735 | var cond_kind: CondKind = .bool; |
| 694 | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{}); | 736 | if (while_node.payload) |_| cond_kind = .{ .optional = null }; |
| 695 | } | | |
| 696 | if (while_node.@"else") |else_node| { | 737 | if (while_node.@"else") |else_node| { |
| 697 | if (else_node.payload) |payload| { | 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 | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{}); | 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,15 +769,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 725 | | 769 | |
| 726 | const tree = scope.tree(); | 770 | const tree = scope.tree(); |
| 727 | const while_src = tree.token_locs[while_node.while_token].start; | 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 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ | 772 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ |
| 733 | .ty = Type.initTag(.type), | 773 | .ty = Type.initTag(.type), |
| 734 | .val = Value.initTag(.void_type), | 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 | const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ | 778 | const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ |
| 739 | .condition = cond, | 779 | .condition = cond, |
| ... | @@ -764,6 +804,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -764,6 +804,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 764 | }; | 804 | }; |
| 765 | defer then_scope.instructions.deinit(mod.gpa); | 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 | // Most result location types can be forwarded directly; however | 810 | // Most result location types can be forwarded directly; however |
| 768 | // if we need to write to a pointer which has an inferred type, | 811 | // if we need to write to a pointer which has an inferred type, |
| 769 | // proper type inference requires peer type resolution on the while's | 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,10 +816,10 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 773 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, | 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 | if (!then_result.tag.isNoReturn()) { | 820 | if (!then_result.tag.isNoReturn()) { |
| 778 | const then_src = tree.token_locs[while_node.body.lastToken()].start; | 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 | .block = cond_block, | 823 | .block = cond_block, |
| 781 | .operand = then_result, | 824 | .operand = then_result, |
| 782 | }, .{}); | 825 | }, .{}); |