mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 10:28:48 +00:00
70894d5c2f
The main problem was that the loop body was treated as an expression that was one of the peer result values of a loop, when in reality the loop body is noreturn and only the `break` operands are the result values of loops. This was solved by introducing an override that prevents rvalue() from emitting a store to result location instruction for loop bodies. An orthogonal change also included in this commit is switching `elem_val` index expressions to using `coerced_ty` and doing the coercion to `usize` inside `Sema`, resulting in smaller ZIR (since the cast becomes implied). I also changed the break operand expression to use `reachableExpr`, introducing a new compile error for double break. This makes a few more behavior tests pass for `while` and `for` loops.
136 lines
3.1 KiB
Zig
136 lines
3.1 KiB
Zig
const std = @import("std");
|
|
const expect = std.testing.expect;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const mem = std.mem;
|
|
|
|
test "continue in for loop" {
|
|
const array = [_]i32{ 1, 2, 3, 4, 5 };
|
|
var sum: i32 = 0;
|
|
for (array) |x| {
|
|
sum += x;
|
|
if (x < 3) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (sum != 6) unreachable;
|
|
}
|
|
|
|
test "break from outer for loop" {
|
|
try testBreakOuter();
|
|
comptime try testBreakOuter();
|
|
}
|
|
|
|
fn testBreakOuter() !void {
|
|
var array = "aoeu";
|
|
var count: usize = 0;
|
|
outer: for (array) |_| {
|
|
for (array) |_| {
|
|
count += 1;
|
|
break :outer;
|
|
}
|
|
}
|
|
try expect(count == 1);
|
|
}
|
|
|
|
test "continue outer for loop" {
|
|
try testContinueOuter();
|
|
comptime try testContinueOuter();
|
|
}
|
|
|
|
fn testContinueOuter() !void {
|
|
var array = "aoeu";
|
|
var counter: usize = 0;
|
|
outer: for (array) |_| {
|
|
for (array) |_| {
|
|
counter += 1;
|
|
continue :outer;
|
|
}
|
|
}
|
|
try expect(counter == array.len);
|
|
}
|
|
|
|
test "ignore lval with underscore (for loop)" {
|
|
for ([_]void{}) |_, i| {
|
|
_ = i;
|
|
for ([_]void{}) |_, j| {
|
|
_ = j;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
test "basic for loop" {
|
|
const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
|
|
|
|
var buffer: [expected_result.len]u8 = undefined;
|
|
var buf_index: usize = 0;
|
|
|
|
const array = [_]u8{ 9, 8, 7, 6 };
|
|
for (array) |item| {
|
|
buffer[buf_index] = item;
|
|
buf_index += 1;
|
|
}
|
|
for (array) |item, index| {
|
|
_ = item;
|
|
buffer[buf_index] = @intCast(u8, index);
|
|
buf_index += 1;
|
|
}
|
|
const array_ptr = &array;
|
|
for (array_ptr) |item| {
|
|
buffer[buf_index] = item;
|
|
buf_index += 1;
|
|
}
|
|
for (array_ptr) |item, index| {
|
|
_ = item;
|
|
buffer[buf_index] = @intCast(u8, index);
|
|
buf_index += 1;
|
|
}
|
|
const unknown_size: []const u8 = &array;
|
|
for (unknown_size) |item| {
|
|
buffer[buf_index] = item;
|
|
buf_index += 1;
|
|
}
|
|
for (unknown_size) |_, index| {
|
|
buffer[buf_index] = @intCast(u8, index);
|
|
buf_index += 1;
|
|
}
|
|
|
|
try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
|
|
}
|
|
|
|
test "for with null and T peer types and inferred result location type" {
|
|
const S = struct {
|
|
fn doTheTest(slice: []const u8) !void {
|
|
if (for (slice) |item| {
|
|
if (item == 10) {
|
|
break item;
|
|
}
|
|
} else null) |v| {
|
|
_ = v;
|
|
@panic("fail");
|
|
}
|
|
}
|
|
};
|
|
try S.doTheTest(&[_]u8{ 1, 2 });
|
|
comptime try S.doTheTest(&[_]u8{ 1, 2 });
|
|
}
|
|
|
|
test "2 break statements and an else" {
|
|
const S = struct {
|
|
fn entry(t: bool, f: bool) !void {
|
|
var buf: [10]u8 = undefined;
|
|
var ok = false;
|
|
ok = for (buf) |item| {
|
|
_ = item;
|
|
if (f) break false;
|
|
if (t) break true;
|
|
} else false;
|
|
try expect(ok);
|
|
}
|
|
};
|
|
try S.entry(true, false);
|
|
comptime try S.entry(true, false);
|
|
}
|