value if/loop follow-ups

This commit is contained in:
2026-06-27 23:24:36 +02:00
parent 61293a23e7
commit 3e54c6f9ad
4 changed files with 282 additions and 26 deletions
+33 -6
View File
@@ -358,17 +358,44 @@
loop body without a trailing fall-through `yield`; a `yield :blk` with no matching value
loop. The TODO "BAD" loops (unlabeled yield from inside an `if`, an unbound labeled loop)
fall out of these naturally
- deferred to a later pass (`// ponytail:`): a value-if/loop nested as the *trailing*
statement of a value block (first pass is the direct `x :: if …`/`for …` form); a branch
that early-`return`s instead of yielding; unwrap-`if` (`if v |x| { yield … }`) as a value
source; `yield none` before any concrete yield in an untyped loop (annotate instead);
`yield :blk` to an outer (non-innermost) loop
- follow-ups: a branch that early-`return`s instead of yielding, unwrap-`if` as a value
source, and `none`-before-concrete typing in untyped loops are done in 20.6; labeled value
blocks and `yield`/`break` to an outer loop are 20.7 (need labels in the IR)
20.6 value if/loop follow-ups (implemented; checker-only)
- a value-if branch may end in `yield` **or** exit on every path (`return`/`break`/
`continue`) — `r :: if (ok) { yield x } else { return -1 }`. A non-terminating, non-yielding
branch is rejected ("a value branch must end with 'yield' or exit on every path"). Checked
via `all_paths_exit` on the built branch in `emit_value_branch`
- unwrap-`if` as a value source: `name :: if opt |v| { yield v * 2 } else { yield d }`.
`emit_value_if` gained an unwrap path mirroring the build-pass `.If` unwrap arm (captures +
guard), each branch assigning the slot; the HIR `.If` carries the unwraps, which the existing
lowering already handles. (The simple "unwrap or fallback" case is just `orelse` —
`name :: opt orelse d` — already a plain expression.)
- untyped value loops pre-type their element from the first concrete (non-`none`) yield
regardless of source order (a capture-scoped probe build, `value_loop_element_type`), so a
`none` yielded before any concrete value still resolves the result to `?T`
- still checker-only; no HIR/lowering change
20.7 labeled value blocks + `yield`/`break` to an outer loop (introduces labels in the IR)
- `x :: blk: { …; yield :blk v }` — a labeled value *block* (the disambiguated form of "an
if/loop at the end of a block"; an unlabeled trailing if/loop stays ambiguous and is not a
value source). `yield :blk v` exits the block with a value
- `yield :outer v` / labeled `break` to a non-innermost loop
- both need exit targets to carry a label: add `label` to HIR `.While`/`.For`/`.Break` and a
labeled `.Block`; generalize the lowering's `Loop_Ctx`/`State.loops` into an exit-target
stack keyed by label (plain `break`/`continue` stay innermost-only; a labeled `.Break`
searches by label; a labeled block pushes a non-loop target + an exit label after its body).
First lowering change in the `yield` line
21. unions and tagged unions
22. match statements with tagged unions payload unwrapping
23. dynamic heap allocation
23. error types
- brolang should feature errors as values
24. dynamic heap allocation
- see below for direction
- notes below are too big in scope for a first pass and the language is not mature enough to support it yet
- this first pass should focus on just basic heap allocation, so we have something to work with