Skip to content

fix(parser): recv-define select arms unparseable in second-or-later position - #1429

Open
lilyliiphone2026-collab wants to merge 1 commit into
limitlessprojects:mainfrom
lilyliiphone2026-collab:fix/select-recv-define-arm-lookahead
Open

lilyliiphone2026-collab wants to merge 1 commit into
limitlessprojects:mainfrom
lilyliiphone2026-collab:fix/select-recv-define-arm-lookahead

Conversation

@lilyliiphone2026-collab

Copy link
Copy Markdown

Bug

Any select whose second or later arm was a named recv-define arm failed to parse:

fn main() {
    a := make(chan int, 1)
    b := make(chan int, 1)
    select {
        v := <-a: fmt.println(v)
        w := <-b: fmt.println(w)   // "expected expression, found ':'" (at this colon)
    }
}

Comma-ok arms (w, ok := <-b:) failed identically in second position.
One named arm alone parsed fine, which is why the corpus missed it:
24-shadow-scope-map-reject.hy pairs one named arm with a bare arm, and every example uses send/default arms only.

Root cause (two bugs, same lookahead)

looks_like_select_arm_head — the arm-body terminator inside parse_select — recognized:

  • send arms: cur = Ident, nth(1) = "<-"
  • bare recv arms: cur = "<-"
  • comma-ok recv-define arms: the comma walk — but its final check was off by one (demanded an Ident at nth(k) where the walk already lands k on ":=")

and had no branch at all for the single-name recv-define head Ident ":=" "<-".

So the previous arm's body loop swallowed the arm head as a local declaration, hit the trailing colon, and parse_stmt failed with expected expression, found ':'. The arm-kind detector itself (first-iteration path) always handled both shapes correctly — only the terminator lookahead was broken, which is exactly why first arms worked and later arms didn't.

Fix

  1. add the missing Tok::Punct(":=") => matches!(self.nth(2), Tok::Punct("<-")) branch for single-name recv-define heads
  2. correct the comma walk's final check to nth(k) == ":=" && nth(k+1) == "<-"

Verification

  • new parser regression test second_recv_define_select_arm_parses (three shapes: named+named, comma-ok+comma-ok, named+comma-ok) — passes
  • new corpus program select-two-recv-define-arms-accept.hy (ACCEPT, end-to-end: check → emit → go build → run outputs 2) — passes with the fix, failed to parse before
  • cargo test --workspace: all green (173 + 112 parser + rest, 0 failures)
  • tools/differential_loop.py: reject-side 86/86, accept-side 38/40 — the two accept-side disagreements are the pre-existing cgo: gcc not found Windows-env failures in corpus 12/13, reproduced identically on an unpatched baseline build

Bounty

Submitted under the BOUNTY.md Track 2 — useful improvements ladder (2026-11-01 cycle): diagnostic-adjacent tooling fix with regression coverage. The issue-creation guidance in BOUNTY.md covers bugs and wildcards; this is a fix PR, so it goes straight to the ladder per "Improvements: a normal issue or a PR".

The arm-body terminator looks_like_select_arm_head recognized send arms
(ch <- v:), bare recv arms (<-ch:), and comma-ok recv-define arms
(v, ok := <-ch:) — but not the single-name recv-define arm (v := <-ch:).
Any select whose second or later arm was a named recv-define therefore
died with "expected expression, found ':'": the body loop swallowed the
arm head as a local declaration and choked on the trailing colon.

While fixing it, the comma-ok branch's final token check turned out to
be off by one: after the name walk k lands on ':=', but the check
demanded an Ident there — so comma-ok arms in second position failed
the same way. Both shapes are now recognized.

- add the missing ':=' branch to the single-name lookahead
- fix the comma-walk's final check (nth(k) is ':=', not an Ident)
- regression test: second_recv_define_select_arm_parses (3 shapes)
- corpus program select-two-recv-define-arms-accept.hy (ACCEPT; the
  pre-fix parser rejected this shape outright)

The gap had zero coverage: corpus 24 pairs one named arm with a bare
arm, examples use send/default arms only.
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