authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 10:18:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 10:28:00-04:00
log20b1491e6bd87b10e822282c5867604d634973a1
tree0ca98f3cbac3ca3dd9f5a755e059964e374eea0a
parent698829b772fe39c4311a75b20324256b8d7392b1

implement while for nullables and error unions

See #357

6 files changed, 330 insertions(+), 84 deletions(-)

src/ast_render.cpp+13-2
...@@ -725,12 +725,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -725,12 +725,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
725 const char *inline_str = node->data.while_expr.is_inline ? "inline " : "";725 const char *inline_str = node->data.while_expr.is_inline ? "inline " : "";
726 fprintf(ar->f, "%swhile (", inline_str);726 fprintf(ar->f, "%swhile (", inline_str);
727 render_node_grouped(ar, node->data.while_expr.condition);727 render_node_grouped(ar, node->data.while_expr.condition);
728 fprintf(ar->f, ") ");
729 if (node->data.while_expr.var_symbol) {
730 fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.var_symbol));
731 }
728 if (node->data.while_expr.continue_expr) {732 if (node->data.while_expr.continue_expr) {
729 fprintf(ar->f, "; ");733 fprintf(ar->f, ": (");
730 render_node_grouped(ar, node->data.while_expr.continue_expr);734 render_node_grouped(ar, node->data.while_expr.continue_expr);
735 fprintf(ar->f, ") ");
731 }736 }
732 fprintf(ar->f, ") ");
733 render_node_grouped(ar, node->data.while_expr.body);737 render_node_grouped(ar, node->data.while_expr.body);
738 if (node->data.while_expr.else_node) {
739 fprintf(ar->f, " else ");
740 if (node->data.while_expr.err_symbol) {
741 fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.err_symbol));
742 }
743 render_node_grouped(ar, node->data.while_expr.else_node);
744 }
734 break;745 break;
735 }746 }
736 case NodeTypeThisLiteral:747 case NodeTypeThisLiteral:
src/ir.cpp+175-29
...@@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4658 assert(node->type == NodeTypeWhileExpr);4658 assert(node->type == NodeTypeWhileExpr);
46594659
4660 AstNode *continue_expr_node = node->data.while_expr.continue_expr;4660 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
4661 AstNode *else_node = node->data.while_expr.else_node;
46614662
4662 IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond");4663 IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond");
4663 IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody");4664 IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody");
4664 IrBasicBlock *continue_block = continue_expr_node ?4665 IrBasicBlock *continue_block = continue_expr_node ?
4665 ir_build_basic_block(irb, scope, "WhileContinue") : cond_block;4666 ir_build_basic_block(irb, scope, "WhileContinue") : cond_block;
4666 IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd");4667 IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd");
4668 IrBasicBlock *else_block = else_node ?
4669 ir_build_basic_block(irb, scope, "WhileElse") : end_block;
46674670
4668 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,4671 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,
4669 ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);4672 ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);
4670 ir_build_br(irb, scope, node, cond_block, is_comptime);4673 ir_build_br(irb, scope, node, cond_block, is_comptime);
46714674
4672 if (continue_expr_node) {4675 Buf *var_symbol = node->data.while_expr.var_symbol;
4673 ir_set_cursor_at_end(irb, continue_block);4676 Buf *err_symbol = node->data.while_expr.err_symbol;
4674 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope);4677 if (err_symbol != nullptr) {
4675 if (expr_result == irb->codegen->invalid_instruction)4678 ir_set_cursor_at_end(irb, cond_block);
4676 return expr_result;4679
4677 if (!instr_is_unreachable(expr_result))4680 Scope *payload_scope;
4678 ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime));4681 AstNode *symbol_node = node; // TODO make more accurate
4679 }4682 VariableTableEntry *payload_var;
4683 if (var_symbol) {
4684 // TODO make it an error to write to payload variable
4685 payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,
4686 true, false, false, is_comptime);
4687 payload_scope = payload_var->child_scope;
4688 } else {
4689 payload_scope = scope;
4690 }
4691 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
4692 if (err_val_ptr == irb->codegen->invalid_instruction)
4693 return err_val_ptr;
4694 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
4695 IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
4696 if (!instr_is_unreachable(is_err)) {
4697 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
4698 else_block, body_block, is_comptime));
4699 }
4700
4701 ir_set_cursor_at_end(irb, body_block);
4702 if (var_symbol) {
4703 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
4704 err_val_ptr, false);
4705 IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
4706 var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
4707 ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value);
4708 }
4709 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4710 loop_stack_item->break_block = end_block;
4711 loop_stack_item->continue_block = continue_block;
4712 loop_stack_item->is_comptime = is_comptime;
4713 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope);
4714 if (body_result == irb->codegen->invalid_instruction)
4715 return body_result;
4716 irb->loop_stack.pop();
4717
4718 if (!instr_is_unreachable(body_result))
4719 ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime));
4720
4721 if (continue_expr_node) {
4722 ir_set_cursor_at_end(irb, continue_block);
4723 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope);
4724 if (expr_result == irb->codegen->invalid_instruction)
4725 return expr_result;
4726 if (!instr_is_unreachable(expr_result))
4727 ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));
4728 }
4729
4730 if (else_node) {
4731 ir_set_cursor_at_end(irb, else_block);
46804732
4681 ir_set_cursor_at_end(irb, cond_block);4733 // TODO make it an error to write to error variable
4682 IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);4734 AstNode *err_symbol_node = else_node; // TODO make more accurate
4683 if (cond_val == irb->codegen->invalid_instruction)4735 VariableTableEntry *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
4684 return cond_val;4736 true, false, false, is_comptime);
4685 if (!instr_is_unreachable(cond_val)) {4737 Scope *err_scope = err_var->child_scope;
4686 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,4738 IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
4687 body_block, end_block, is_comptime));4739 ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value);
4688 }4740
4741 IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
4742 if (else_result == irb->codegen->invalid_instruction)
4743 return else_result;
4744 if (!instr_is_unreachable(else_result))
4745 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4746 }
4747
4748 ir_set_cursor_at_end(irb, end_block);
4749 return ir_build_const_void(irb, scope, node);
4750 } else if (var_symbol != nullptr) {
4751 ir_set_cursor_at_end(irb, cond_block);
4752 // TODO make it an error to write to payload variable
4753 AstNode *symbol_node = node; // TODO make more accurate
4754 VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,
4755 true, false, false, is_comptime);
4756 Scope *child_scope = payload_var->child_scope;
4757 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
4758 if (maybe_val_ptr == irb->codegen->invalid_instruction)
4759 return maybe_val_ptr;
4760 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
4761 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
4762 if (!instr_is_unreachable(is_non_null)) {
4763 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
4764 body_block, else_block, is_comptime));
4765 }
4766
4767 ir_set_cursor_at_end(irb, body_block);
4768 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
4769 IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
4770 var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
4771 ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value);
4772 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4773 loop_stack_item->break_block = end_block;
4774 loop_stack_item->continue_block = continue_block;
4775 loop_stack_item->is_comptime = is_comptime;
4776 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope);
4777 if (body_result == irb->codegen->invalid_instruction)
4778 return body_result;
4779 irb->loop_stack.pop();
4780
4781 if (!instr_is_unreachable(body_result))
4782 ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
4783
4784 if (continue_expr_node) {
4785 ir_set_cursor_at_end(irb, continue_block);
4786 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope);
4787 if (expr_result == irb->codegen->invalid_instruction)
4788 return expr_result;
4789 if (!instr_is_unreachable(expr_result))
4790 ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));
4791 }
4792
4793 if (else_node) {
4794 ir_set_cursor_at_end(irb, else_block);
46894795
4690 ir_set_cursor_at_end(irb, body_block);4796 IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4797 if (else_result == irb->codegen->invalid_instruction)
4798 return else_result;
4799 if (!instr_is_unreachable(else_result))
4800 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4801 }
46914802
4692 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();4803 ir_set_cursor_at_end(irb, end_block);
4693 loop_stack_item->break_block = end_block;4804 return ir_build_const_void(irb, scope, node);
4694 loop_stack_item->continue_block = continue_block;4805 } else {
4695 loop_stack_item->is_comptime = is_comptime;4806 if (continue_expr_node) {
4696 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);4807 ir_set_cursor_at_end(irb, continue_block);
4697 if (body_result == irb->codegen->invalid_instruction)4808 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope);
4698 return body_result;4809 if (expr_result == irb->codegen->invalid_instruction)
4699 irb->loop_stack.pop();4810 return expr_result;
4811 if (!instr_is_unreachable(expr_result))
4812 ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime));
4813 }
4814
4815 ir_set_cursor_at_end(irb, cond_block);
4816 IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
4817 if (cond_val == irb->codegen->invalid_instruction)
4818 return cond_val;
4819 if (!instr_is_unreachable(cond_val)) {
4820 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
4821 body_block, else_block, is_comptime));
4822 }
4823
4824 ir_set_cursor_at_end(irb, body_block);
4825
4826 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4827 loop_stack_item->break_block = end_block;
4828 loop_stack_item->continue_block = continue_block;
4829 loop_stack_item->is_comptime = is_comptime;
4830 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);
4831 if (body_result == irb->codegen->invalid_instruction)
4832 return body_result;
4833 irb->loop_stack.pop();
4834
4835 if (!instr_is_unreachable(body_result))
4836 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
4837
4838 if (else_node) {
4839 ir_set_cursor_at_end(irb, else_block);
47004840
4701 if (!instr_is_unreachable(body_result))4841 IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4702 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));4842 if (else_result == irb->codegen->invalid_instruction)
4703 ir_set_cursor_at_end(irb, end_block);4843 return else_result;
4844 if (!instr_is_unreachable(else_result))
4845 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4846 }
47044847
4705 return ir_build_const_void(irb, scope, node);4848 ir_set_cursor_at_end(irb, end_block);
4849
4850 return ir_build_const_void(irb, scope, node);
4851 }
4706}4852}
47074853
4708static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {4854static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
src/parser.cpp+1-1
...@@ -1654,7 +1654,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool...@@ -1654,7 +1654,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool
1654 ast_eat_token(pc, token_index, TokenIdBinOr);1654 ast_eat_token(pc, token_index, TokenIdBinOr);
1655 }1655 }
16561656
1657 node->data.while_expr.body = ast_parse_block_or_expression(pc, token_index, true);1657 node->data.while_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
1658 }1658 }
16591659
1660 return node;1660 return node;
std/linked_list.zig+18-47
...@@ -187,43 +187,6 @@ pub fn LinkedList(comptime T: type) -> type {...@@ -187,43 +187,6 @@ pub fn LinkedList(comptime T: type) -> type {
187 };187 };
188 return node;188 return node;
189 }189 }
190
191 /// Iterate through the elements of the list.
192 ///
193 /// Returns:
194 /// A list iterator with a next() method.
195 pub fn iterate(list: &List) -> List.Iterator(false) {
196 List.Iterator(false) {
197 .node = list.first,
198 }
199 }
200
201 /// Iterate through the elements of the list backwards.
202 ///
203 /// Returns:
204 /// A list iterator with a next() method.
205 pub fn iterateBackwards(list: &List) -> List.Iterator(true) {
206 List.Iterator(true) {
207 .node = list.last,
208 }
209 }
210
211 /// Abstract iteration over a linked list.
212 pub fn Iterator(comptime backwards: bool) -> type {
213 struct {
214 const It = this;
215
216 node: ?&Node,
217
218 /// Return the next element of the list, until the end.
219 /// When no more elements are available, return null.
220 pub fn next(it: &It) -> ?&Node {
221 const current = it.node ?? return null;
222 it.node = if (backwards) current.prev else current.next;
223 return current;
224 }
225 }
226 }
227 }190 }
228}191}
229192
...@@ -249,16 +212,24 @@ test "basic linked list test" {...@@ -249,16 +212,24 @@ test "basic linked list test" {
249 list.insertBefore(five, four); // {1, 2, 4, 5}212 list.insertBefore(five, four); // {1, 2, 4, 5}
250 list.insertAfter(two, three); // {1, 2, 3, 4, 5}213 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
251214
252 // Traverse the list forwards and backwards.215 // traverse forwards
253 var it = list.iterate();216 {
254 var it_reverse = list.iterateBackwards();217 var it = list.first;
255 var index: u32 = 1;218 var index: u32 = 1;
256 while (true) {219 while (it) |node| : (it = node.next) {
257 const node = it.next() ?? break;220 assert(node.data == index);
258 const node_reverse = it_reverse.next() ?? break;221 index += 1;
259 assert (node.data == index);222 }
260 assert (node_reverse.data == (6 - index));223 }
261 index += 1;224
225 // traverse backwards
226 {
227 var it = list.last;
228 var index: u32 = 1;
229 while (it) |node| : (it = node.prev) {
230 assert(node.data == (6 - index));
231 index += 1;
232 }
262 }233 }
263234
264 var first = list.popFirst(); // {2, 3, 4, 5}235 var first = list.popFirst(); // {2, 3, 4, 5}
test/cases/while.zig+75-5
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
22
3test "whileLoop" {3test "while loop" {
4 var i : i32 = 0;4 var i : i32 = 0;
5 while (i < 4) {5 while (i < 4) {
6 i += 1;6 i += 1;
...@@ -16,7 +16,7 @@ fn whileLoop2() -> i32 {...@@ -16,7 +16,7 @@ fn whileLoop2() -> i32 {
16 return 1;16 return 1;
17 }17 }
18}18}
19test "staticEvalWhile" {19test "static eval while" {
20 assert(static_eval_while_number == 1);20 assert(static_eval_while_number == 1);
21}21}
22const static_eval_while_number = staticWhileLoop1();22const static_eval_while_number = staticWhileLoop1();
...@@ -29,7 +29,7 @@ fn staticWhileLoop2() -> i32 {...@@ -29,7 +29,7 @@ fn staticWhileLoop2() -> i32 {
29 }29 }
30}30}
3131
32test "continueAndBreak" {32test "continue and break" {
33 runContinueAndBreakTest();33 runContinueAndBreakTest();
34 assert(continue_and_break_counter == 8);34 assert(continue_and_break_counter == 8);
35}35}
...@@ -47,7 +47,7 @@ fn runContinueAndBreakTest() {...@@ -47,7 +47,7 @@ fn runContinueAndBreakTest() {
47 assert(i == 4);47 assert(i == 4);
48}48}
4949
50test "returnWithImplicitCastFromWhileLoop" {50test "return with implicit cast from while loop" {
51 %%returnWithImplicitCastFromWhileLoopTest();51 %%returnWithImplicitCastFromWhileLoopTest();
52}52}
53fn returnWithImplicitCastFromWhileLoopTest() -> %void {53fn returnWithImplicitCastFromWhileLoopTest() -> %void {
...@@ -56,7 +56,7 @@ fn returnWithImplicitCastFromWhileLoopTest() -> %void {...@@ -56,7 +56,7 @@ fn returnWithImplicitCastFromWhileLoopTest() -> %void {
56 }56 }
57}57}
5858
59test "whileWithContinueExpr" {59test "while with continue expression" {
60 var sum: i32 = 0;60 var sum: i32 = 0;
61 {var i: i32 = 0; while (i < 10) : (i += 1) {61 {var i: i32 = 0; while (i < 10) : (i += 1) {
62 if (i == 5) continue;62 if (i == 5) continue;
...@@ -64,3 +64,73 @@ test "whileWithContinueExpr" {...@@ -64,3 +64,73 @@ test "whileWithContinueExpr" {
64 }}64 }}
65 assert(sum == 40);65 assert(sum == 40);
66}66}
67
68test "while with else" {
69 var sum: i32 = 0;
70 var i: i32 = 0;
71 var got_else: i32 = 0;
72 while (i < 10) : (i += 1) {
73 sum += 1;
74 } else {
75 got_else += 1;
76 }
77 assert(sum == 10);
78 assert(got_else == 1);
79}
80
81test "while with nullable as condition" {
82 numbers_left = 10;
83 var sum: i32 = 0;
84 while (getNumberOrNull()) |value| {
85 sum += value;
86 }
87 assert(sum == 45);
88}
89
90test "while with nullable as condition with else" {
91 numbers_left = 10;
92 var sum: i32 = 0;
93 var got_else: i32 = 0;
94 while (getNumberOrNull()) |value| {
95 sum += value;
96 assert(got_else == 0);
97 } else {
98 got_else += 1;
99 }
100 assert(sum == 45);
101 assert(got_else == 1);
102}
103
104test "while with error union condition" {
105 numbers_left = 10;
106 var sum: i32 = 0;
107 var got_else: i32 = 0;
108 while (getNumberOrErr()) |value| {
109 sum += value;
110 } else |err| {
111 assert(err == error.OutOfNumbers);
112 got_else += 1;
113 }
114 assert(sum == 45);
115 assert(got_else == 1);
116}
117
118var numbers_left: i32 = undefined;
119error OutOfNumbers;
120fn getNumberOrErr() -> %i32 {
121 return if (numbers_left == 0) {
122 error.OutOfNumbers
123 } else {
124 numbers_left -= 1;
125 numbers_left
126 };
127}
128fn getNumberOrNull() -> ?i32 {
129 return if (numbers_left == 0) {
130 null
131 } else {
132 numbers_left -= 1;
133 numbers_left
134 };
135}
136
test/compile_errors.zig+48
...@@ -1636,4 +1636,52 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1636,4 +1636,52 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1636 ,1636 ,
1637 ".tmp_source.zig:9:17: error: redefinition of 'Self'",1637 ".tmp_source.zig:9:17: error: redefinition of 'Self'",
1638 ".tmp_source.zig:5:9: note: previous definition is here");1638 ".tmp_source.zig:5:9: note: previous definition is here");
1639
1640 cases.add("while expected bool, got nullable",
1641 \\export fn foo() {
1642 \\ while (bar()) {}
1643 \\}
1644 \\fn bar() -> ?i32 { 1 }
1645 ,
1646 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'");
1647
1648 cases.add("while expected bool, got error union",
1649 \\export fn foo() {
1650 \\ while (bar()) {}
1651 \\}
1652 \\fn bar() -> %i32 { 1 }
1653 ,
1654 ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'");
1655
1656 cases.add("while expected nullable, got bool",
1657 \\export fn foo() {
1658 \\ while (bar()) |x| {}
1659 \\}
1660 \\fn bar() -> bool { true }
1661 ,
1662 ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'");
1663
1664 cases.add("while expected nullable, got error union",
1665 \\export fn foo() {
1666 \\ while (bar()) |x| {}
1667 \\}
1668 \\fn bar() -> %i32 { 1 }
1669 ,
1670 ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'");
1671
1672 cases.add("while expected error union, got bool",
1673 \\export fn foo() {
1674 \\ while (bar()) |x| {} else |err| {}
1675 \\}
1676 \\fn bar() -> bool { true }
1677 ,
1678 ".tmp_source.zig:2:15: error: expected error union type, found 'bool'");
1679
1680 cases.add("while expected error union, got nullable",
1681 \\export fn foo() {
1682 \\ while (bar()) |x| {} else |err| {}
1683 \\}
1684 \\fn bar() -> ?i32 { 1 }
1685 ,
1686 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");
1639}1687}