block labels

This commit is contained in:
2026-06-28 08:51:01 +02:00
parent 3e54c6f9ad
commit eaa66511a0
7 changed files with 352 additions and 60 deletions
+23 -10
View File
@@ -2131,11 +2131,10 @@ yield_compiles_and_runs :: proc(t: ^testing.T) {
status := compiler_core.compile_package("examples/programs/yield", output)
testing.expect_value(t, status, 0)
state := run_executable(output)
// Value blocks (untyped/typed, defer-spill, reassignment), value if-statements
// (untyped/typed/reassign/else-if/defer, a branch that `return`s instead of yielding,
// and an unwrap-`if` as a value source), `orelse`, and value loops (a labeled `for`
// search yielding `?usize` on the found/not-found paths, a labeled `while`, and an
// untyped loop that yields `none` before any concrete value) together produce 42.
// Value blocks, value if-statements (incl. `return` branches and unwrap-`if`),
// `orelse`, value loops, labeled value blocks (`blk: { … yield :blk v }`, incl.
// defer-capture and `{T,none}` → optional), and outer-loop control (`yield :outer v`
// and `break :outer` from an inner loop) together produce 42.
testing.expect_value(t, state.exit_code, 42)
}
@@ -2180,9 +2179,10 @@ yield_misuse_is_diagnosed :: proc(t: ^testing.T) {
@(test)
yield_control_flow_is_diagnosed :: proc(t: ^testing.T) {
// Value if/loop misuse: an `if` value without an `else`; a branch that neither
// yields nor exits on every path (milestone 20.6); a value loop whose body lacks a
// trailing fall-through `yield`; and a `yield :label` with no matching value loop.
// Value if/loop/block misuse: an `if` value without an `else`; a branch that neither
// yields nor exits on every path (20.6); a value loop whose body lacks a trailing
// fall-through `yield`; a `yield :label` with no matching value loop; a labeled value
// block that does not yield on every path, and a `break :label` naming no loop (20.7).
text := `main :: func() i32 {
noelse :: if (true) {
yield 1
@@ -2198,7 +2198,14 @@ yield_control_flow_is_diagnosed :: proc(t: ^testing.T) {
for 0..10 |j| stray: {
yield :stray j
}
return noelse + badbranch + noloopyield
noblockyield :: blk: {
if (true) yield :blk 1
k2 :: 5
}
for 0..10 |m| {
break :nope
}
return noelse + badbranch + noloopyield + noblockyield
}
`
source_file := source.Source{path="test.bro", text=text}
@@ -2217,16 +2224,22 @@ yield_control_flow_is_diagnosed :: proc(t: ^testing.T) {
branch_no_yield := false
loop_no_yield := false
stray_label := false
block_no_yield := false
bad_break_label := false
for diagnostic in diagnostics.items {
no_else = no_else || strings.contains(diagnostic.message, "an 'if' used as a value must have an 'else'")
branch_no_yield = branch_no_yield || strings.contains(diagnostic.message, "a value branch must end with 'yield' or exit on every path")
loop_no_yield = loop_no_yield || strings.contains(diagnostic.message, "a value loop's body must end with a 'yield'")
stray_label = stray_label || strings.contains(diagnostic.message, "no enclosing value loop is labeled 'stray'")
stray_label = stray_label || strings.contains(diagnostic.message, "no enclosing value loop or block is labeled 'stray'")
block_no_yield = block_no_yield || strings.contains(diagnostic.message, "a labeled value block must 'yield' on every path")
bad_break_label = bad_break_label || strings.contains(diagnostic.message, "no enclosing loop is labeled 'nope'")
}
testing.expect(t, no_else)
testing.expect(t, branch_no_yield)
testing.expect(t, loop_no_yield)
testing.expect(t, stray_label)
testing.expect(t, block_no_yield)
testing.expect(t, bad_break_label)
}
@(test)