| ... | @@ -6487,8 +6487,7 @@ fn forExpr( | ... | @@ -6487,8 +6487,7 @@ fn forExpr( |
| 6487 | | 6487 | |
| 6488 | { | 6488 | { |
| 6489 | var capture_token = for_full.payload_token; | 6489 | var capture_token = for_full.payload_token; |
| 6490 | for (for_full.ast.inputs, 0..) |input, i_usize| { | 6490 | for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_ref| { |
| 6491 | const i = @as(u32, @intCast(i_usize)); | | |
| 6492 | const capture_is_ref = token_tags[capture_token] == .asterisk; | 6491 | const capture_is_ref = token_tags[capture_token] == .asterisk; |
| 6493 | const ident_tok = capture_token + @intFromBool(capture_is_ref); | 6492 | const ident_tok = capture_token + @intFromBool(capture_is_ref); |
| 6494 | const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_"); | 6493 | const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_"); |
| ... | @@ -6527,14 +6526,14 @@ fn forExpr( | ... | @@ -6527,14 +6526,14 @@ fn forExpr( |
| 6527 | }); | 6526 | }); |
| 6528 | | 6527 | |
| 6529 | any_len_checks = any_len_checks or range_len != .none; | 6528 | any_len_checks = any_len_checks or range_len != .none; |
| 6530 | indexables[i] = if (start_is_zero) .none else start_val; | 6529 | indexable_ref.* = if (start_is_zero) .none else start_val; |
| 6531 | lens[i] = range_len; | 6530 | len_ref.* = range_len; |
| 6532 | } else { | 6531 | } else { |
| 6533 | const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input); | 6532 | const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input); |
| 6534 | | 6533 | |
| 6535 | any_len_checks = true; | 6534 | any_len_checks = true; |
| 6536 | indexables[i] = indexable; | 6535 | indexable_ref.* = indexable; |
| 6537 | lens[i] = indexable; | 6536 | len_ref.* = indexable; |
| 6538 | } | 6537 | } |
| 6539 | } | 6538 | } |
| 6540 | } | 6539 | } |
| ... | @@ -6546,7 +6545,7 @@ fn forExpr( | ... | @@ -6546,7 +6545,7 @@ fn forExpr( |
| 6546 | // We use a dedicated ZIR instruction to assert the lengths to assist with | 6545 | // We use a dedicated ZIR instruction to assert the lengths to assist with |
| 6547 | // nicer error reporting as well as fewer ZIR bytes emitted. | 6546 | // nicer error reporting as well as fewer ZIR bytes emitted. |
| 6548 | const len: Zir.Inst.Ref = len: { | 6547 | const len: Zir.Inst.Ref = len: { |
| 6549 | const lens_len = @as(u32, @intCast(lens.len)); | 6548 | const lens_len: u32 = @intCast(lens.len); |
| 6550 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.MultiOp).Struct.fields.len + lens_len); | 6549 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.MultiOp).Struct.fields.len + lens_len); |
| 6551 | const len = try parent_gz.addPlNode(.for_len, node, Zir.Inst.MultiOp{ | 6550 | const len = try parent_gz.addPlNode(.for_len, node, Zir.Inst.MultiOp{ |
| 6552 | .operands_len = lens_len, | 6551 | .operands_len = lens_len, |
| ... | @@ -6565,7 +6564,10 @@ fn forExpr( | ... | @@ -6565,7 +6564,10 @@ fn forExpr( |
| 6565 | defer loop_scope.unstack(); | 6564 | defer loop_scope.unstack(); |
| 6566 | defer loop_scope.labeled_breaks.deinit(gpa); | 6565 | defer loop_scope.labeled_breaks.deinit(gpa); |
| 6567 | | 6566 | |
| | 6567 | // We need to finish loop_scope later once we have the deferred refs from then_scope. However, the |
| | 6568 | // load must be removed from instructions in the meantime or it appears to be part of parent_gz. |
| 6568 | const index = try loop_scope.addUnNode(.load, index_ptr, node); | 6569 | const index = try loop_scope.addUnNode(.load, index_ptr, node); |
| | 6570 | _ = loop_scope.instructions.pop(); |
| 6569 | | 6571 | |
| 6570 | var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); | 6572 | var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); |
| 6571 | defer cond_scope.unstack(); | 6573 | defer cond_scope.unstack(); |
| ... | @@ -6581,26 +6583,14 @@ fn forExpr( | ... | @@ -6581,26 +6583,14 @@ fn forExpr( |
| 6581 | const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; | 6583 | const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; |
| 6582 | const cond_block = try loop_scope.makeBlockInst(block_tag, node); | 6584 | const cond_block = try loop_scope.makeBlockInst(block_tag, node); |
| 6583 | try cond_scope.setBlockBody(cond_block); | 6585 | try cond_scope.setBlockBody(cond_block); |
| 6584 | // cond_block unstacked now, can add new instructions to loop_scope | | |
| 6585 | try loop_scope.instructions.append(gpa, cond_block); | | |
| 6586 | | 6586 | |
| 6587 | // Increment the index variable. | | |
| 6588 | const index_plus_one = try loop_scope.addPlNode(.add_unsafe, node, Zir.Inst.Bin{ | | |
| 6589 | .lhs = index, | | |
| 6590 | .rhs = .one_usize, | | |
| 6591 | }); | | |
| 6592 | _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); | | |
| 6593 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | | |
| 6594 | _ = try loop_scope.addNode(repeat_tag, node); | | |
| 6595 | | | |
| 6596 | try loop_scope.setBlockBody(loop_block); | | |
| 6597 | loop_scope.break_block = loop_block; | 6587 | loop_scope.break_block = loop_block; |
| 6598 | loop_scope.continue_block = cond_block; | 6588 | loop_scope.continue_block = cond_block; |
| 6599 | if (for_full.label_token) |label_token| { | 6589 | if (for_full.label_token) |label_token| { |
| 6600 | loop_scope.label = @as(?GenZir.Label, GenZir.Label{ | 6590 | loop_scope.label = .{ |
| 6601 | .token = label_token, | 6591 | .token = label_token, |
| 6602 | .block_inst = loop_block, | 6592 | .block_inst = loop_block, |
| 6603 | }); | 6593 | }; |
| 6604 | } | 6594 | } |
| 6605 | | 6595 | |
| 6606 | var then_node = for_full.ast.then_expr; | 6596 | var then_node = for_full.ast.then_expr; |
| ... | @@ -6615,8 +6605,7 @@ fn forExpr( | ... | @@ -6615,8 +6605,7 @@ fn forExpr( |
| 6615 | const then_sub_scope = blk: { | 6605 | const then_sub_scope = blk: { |
| 6616 | var capture_token = for_full.payload_token; | 6606 | var capture_token = for_full.payload_token; |
| 6617 | var capture_sub_scope: *Scope = &then_scope.base; | 6607 | var capture_sub_scope: *Scope = &then_scope.base; |
| 6618 | for (for_full.ast.inputs, 0..) |input, i_usize| { | 6608 | for (for_full.ast.inputs, indexables, capture_scopes) |input, indexable_ref, *capture_scope| { |
| 6619 | const i = @as(u32, @intCast(i_usize)); | | |
| 6620 | const capture_is_ref = token_tags[capture_token] == .asterisk; | 6609 | const capture_is_ref = token_tags[capture_token] == .asterisk; |
| 6621 | const ident_tok = capture_token + @intFromBool(capture_is_ref); | 6610 | const ident_tok = capture_token + @intFromBool(capture_is_ref); |
| 6622 | const capture_name = tree.tokenSlice(ident_tok); | 6611 | const capture_name = tree.tokenSlice(ident_tok); |
| ... | @@ -6631,7 +6620,7 @@ fn forExpr( | ... | @@ -6631,7 +6620,7 @@ fn forExpr( |
| 6631 | const capture_inst = inst: { | 6620 | const capture_inst = inst: { |
| 6632 | const is_counter = node_tags[input] == .for_range; | 6621 | const is_counter = node_tags[input] == .for_range; |
| 6633 | | 6622 | |
| 6634 | if (indexables[i] == .none) { | 6623 | if (indexable_ref == .none) { |
| 6635 | // Special case: the main index can be used directly. | 6624 | // Special case: the main index can be used directly. |
| 6636 | assert(is_counter); | 6625 | assert(is_counter); |
| 6637 | assert(!capture_is_ref); | 6626 | assert(!capture_is_ref); |
| ... | @@ -6650,12 +6639,12 @@ fn forExpr( | ... | @@ -6650,12 +6639,12 @@ fn forExpr( |
| 6650 | 0b11 => unreachable, // compile error emitted already | 6639 | 0b11 => unreachable, // compile error emitted already |
| 6651 | }; | 6640 | }; |
| 6652 | break :inst try then_scope.addPlNode(tag, input, Zir.Inst.Bin{ | 6641 | break :inst try then_scope.addPlNode(tag, input, Zir.Inst.Bin{ |
| 6653 | .lhs = indexables[i], | 6642 | .lhs = indexable_ref, |
| 6654 | .rhs = index, | 6643 | .rhs = index, |
| 6655 | }); | 6644 | }); |
| 6656 | }; | 6645 | }; |
| 6657 | | 6646 | |
| 6658 | capture_scopes[i] = .{ | 6647 | capture_scope.* = .{ |
| 6659 | .parent = capture_sub_scope, | 6648 | .parent = capture_sub_scope, |
| 6660 | .gen_zir = &then_scope, | 6649 | .gen_zir = &then_scope, |
| 6661 | .name = name_str_index, | 6650 | .name = name_str_index, |
| ... | @@ -6665,7 +6654,7 @@ fn forExpr( | ... | @@ -6665,7 +6654,7 @@ fn forExpr( |
| 6665 | }; | 6654 | }; |
| 6666 | | 6655 | |
| 6667 | try then_scope.addDbgVar(.dbg_var_val, name_str_index, capture_inst); | 6656 | try then_scope.addDbgVar(.dbg_var_val, name_str_index, capture_inst); |
| 6668 | capture_sub_scope = &capture_scopes[i].base; | 6657 | capture_sub_scope = &capture_scope.base; |
| 6669 | } | 6658 | } |
| 6670 | | 6659 | |
| 6671 | break :blk capture_sub_scope; | 6660 | break :blk capture_sub_scope; |
| ... | @@ -6730,6 +6719,24 @@ fn forExpr( | ... | @@ -6730,6 +6719,24 @@ fn forExpr( |
| 6730 | cond_block, | 6719 | cond_block, |
| 6731 | break_tag, | 6720 | break_tag, |
| 6732 | ); | 6721 | ); |
| | 6722 | |
| | 6723 | // then_block and else_block unstacked now, can resurrect loop_scope to finally finish it |
| | 6724 | { |
| | 6725 | loop_scope.instructions_top = loop_scope.instructions.items.len; |
| | 6726 | try loop_scope.instructions.appendSlice(gpa, &.{ Zir.refToIndex(index).?, cond_block }); |
| | 6727 | |
| | 6728 | // Increment the index variable. |
| | 6729 | const index_plus_one = try loop_scope.addPlNode(.add_unsafe, node, Zir.Inst.Bin{ |
| | 6730 | .lhs = index, |
| | 6731 | .rhs = .one_usize, |
| | 6732 | }); |
| | 6733 | _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); |
| | 6734 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; |
| | 6735 | _ = try loop_scope.addNode(repeat_tag, node); |
| | 6736 | |
| | 6737 | try loop_scope.setBlockBody(loop_block); |
| | 6738 | } |
| | 6739 | |
| 6733 | if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) { | 6740 | if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) { |
| 6734 | _ = try rvalue(parent_gz, ri, .void_value, node); | 6741 | _ = try rvalue(parent_gz, ri, .void_value, node); |
| 6735 | } | 6742 | } |