ADR-151: break Carries No Value, and the Refusal Names the Two Shapes That Do

Status: Superseded by ADR-276 — its D1 is D13, its D2-D3 are D14-D15 there Date: September 19, 2026 Target Version: Nikaia 0.0.31 Related: ADR-138 §4 (which left this open), ADR-084 D3 (NK1133, and what it was written for), ADR-070 (there is no unconditional loop keyword), Part I 3.1 (an if is an expression always), Part I 3.3

1. Context

ADR-138 §4 left it open: Rust’s break x hands a value out of a loop, this language has no unconditional loop (ADR-070), so while true { … break x } would be the only home for it — and NK1133 refuses it today, because a statement after a break in the same block is not reached.

The refusal is right and its message is where this record lands. It says bind it before the break, which is one of the two shapes and not the one a reader usually wants.

2. Decisions

D1 — A loop is a statement, and break carries nothing.

while hands back unit. One construct that is sometimes a value and sometimes not is exactly the ambiguity if was spared by being an expression always (Part I 3.1), and adding it to the loop would buy one shape at the cost of that.

D2 — The message names the two shapes that carry a value out of a loop.

error[NK1133]: nothing after a `break` in the same block is reached
  = `break` takes no value: a loop is a statement here and hands back
    nothing, so `break x` is two statements rather than one (Part I, 3.3)
  help: a value that outlives the loop is a `let` before it that the loop
        assigns - or a `return`, where the function has nothing left to do

Two shapes, both already in the language, and the return one is what a search loop is usually written as.

D3 — It stays additive.

break x can be admitted later without breaking a program, because every program that would use it is refused today. The refusal costs nothing but a message — which is the argument for keeping it while no program is waiting.

3. Consequences

4. What this does not decide

5. What is built

All of it, which is one help text — and writing it down is most of the value: the refusal already existed and the decision behind it did not, so ADR-138 §4 could reasonably have been read as undecided by whoever touched the loop next.

The help said delete it - or, where a value was meant, bind it before the break. It says both shapes now, and names the return one second because that is the one a search loop is written as.

The test that was already there is what pins it: NK1133’s own fixture in crates/nikaia/tests/jumps.rs asserts the code and the message, and it gained the two shapes.

This site is open source. Improve this page.