Skip to content

parser: reject reserved stmt keywords as fn decl starts#235

Merged
danieljohnmorris merged 2 commits into
mainfrom
fix/wh-gt-return-type-trap
May 13, 2026
Merged

parser: reject reserved stmt keywords as fn decl starts#235
danieljohnmorris merged 2 commits into
mainfrom
fix/wh-gt-return-type-trap

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

Both gis-analyst and routing-tsp personas hit the same parser trap on v0.11.1: wh >cond{...} mid-body gets re-parsed as a new function declaration named wh returning cond, surfacing as a misleading ILO-T008 return type mismatch: expected n, got _ plus a cascade of "undefined variable" errors in function wh. Same root cause as the v0.10 wh >len xs 0{...} friction entry — it was never len-specific, just wh > ... in any position.

Manifesto framing: the workaround (cnd=>v 0;wh cnd{...;cnd=>v 0}) adds two extra statements per loop, exactly the kind of recurring token tax the language exists to avoid. The fix dissolves the friction at the parser layer; the corrected wh >v 0{...} form is 1 token cheaper per loop than any workaround.

Repro

Before:

$ ilo run 'foo s:n>n;v=+s 0;wh >v 0{v=- v 1};+v 0' foo 5
error[ILO-T008]: return type mismatch: expected n, got _
error[ILO-T004]: undefined variable 'v' (in function 'wh')
error[ILO-T004]: undefined variable 'v' (in function 'wh')

After:

$ ilo run 'foo s:n>n;v=+s 0;wh >v 0{v=- v 1};+v 0' foo 5
0

What's in the diff

Commit 1 — parser: reject reserved stmt keywords as fn decl starts. is_fn_decl_start previously accepted any Ident Greater ... sequence as a zero-param fn header. After the first ; of an outer body, parse_body_with's top-level boundary heuristic fires on wh >v 0{...} and treats wh as a fresh fn decl. Short-circuit is_fn_decl_start to false when the leading ident is one of the four reserved statement-keyword identifiers (wh/ret/brk/cnt) that parse_stmt intercepts as control-flow forms. Mirrors the existing ILO-P011 reserved-keyword precedent in parse_decl.

Commit 2 — test: cross-engine coverage for wh >cond parser trap. New tests/regression_wh_gt_trap.rs covers four shapes across tree, vm, and cranelift:

  • wh >v 0{...} after a let binding (the gis-analyst repro)
  • wh >cond{...} followed by a sibling fn decl (boundary heuristic must still find the real boundary)
  • wh >=v 1{...} (GreaterEq prefix, same family)
  • a zero-param fn sanity check (legitimate name>return;body still parses)

examples/wh-gt-condition.ilo demonstrates the now-correct shape and rides through tests/examples_engines.rs as an extra cross-engine regression layer.

Test plan

  • cargo test --release --features cranelift — 4253 passed, 0 failed
  • All 12 new regression_wh_gt_trap tests pass on tree/vm/cranelift
  • examples_engines picks up wh-gt-condition.ilo and runs it across all engines
  • cargo fmt --check clean
  • cargo clippy --release --features cranelift --all-targets -- -D warnings clean
  • Headline repro foo s:n>n;v=+s 0;wh >v 0{v=- v 1};+v 0 returns 0 for foo 5 under all three engines

is_fn_decl_start treated any Ident followed by > as a zero-param fn
header, which mis-fires on wh >cond{...} mid-body: parse_body_with's
top-level boundary heuristic terminates the outer body at wh and
parses wh >v 0{v=- v 1} as a fresh fn decl named wh returning v.
Symptom is ILO-T008 "return type mismatch: expected n, got _" plus a
cascade of undefined-variable errors in function 'wh'. Hit by both
gis-analyst and routing-tsp persona reruns against v0.11.1.

wh, ret, brk, and cnt are intercepted by parse_stmt as control-flow
forms and can never start a fn decl. Short-circuit is_fn_decl_start
to false for these four names. Mirrors the existing ILO-P011
reserved-keyword precedent in parse_decl.
Regression test covering the gis-analyst repro (wh >v 0 mid-body),
wh >cond followed by a sibling fn decl, the GreaterEq variant, and a
zero-param fn sanity check. All four shapes exercised across tree,
vm, and cranelift.

examples/wh-gt-condition.ilo demonstrates the now-correct shape and
flows through tests/examples_engines.rs as an extra cross-engine
regression layer.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@danieljohnmorris danieljohnmorris merged commit 41046b2 into main May 13, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/wh-gt-return-type-trap branch May 13, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant