Skip to content

fix chained nil-coalesce mis-parse on arity-aware calls#233

Merged
danieljohnmorris merged 2 commits into
mainfrom
fix/chained-nilcoalesce
May 13, 2026
Merged

fix chained nil-coalesce mis-parse on arity-aware calls#233
danieljohnmorris merged 2 commits into
mainfrom
fix/chained-nilcoalesce

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

Chained mget m "a" ?? mget m "b" ?? 99 failed at the verifier with ILO-T006 arity mismatch: 'mget' expects 2 args, got 3. Single mget m k ?? d was fine; only chains broke.

Root cause is in parse_call_or_atom's post-arg break. After each collected argument, the loop checks for an infix operator to stop on, but allows the prefix-binary lookahead (looks_like_prefix_binary) to override that break. ?? is registered as a prefix-binary candidate (so g ??c 7 can pass a prefix-?? sub-expression to g), and ?? mget m "b" has 3 tail atoms which the scanner happily reads as a prefix nil-coalesce. So the first mget kept absorbing ?? mget m as its third arg, then "b" ?? 99 as its fourth, producing the bogus 3-arg verifier error.

Fix: once at least one argument has been collected for a call, ?? is unambiguously the infix nil-coalesce on the call result. Don't let the prefix-binary scanner pull it back into call-arg territory. The first-token case is left alone so prefix ??c 7 in a call-arg position still works.

Repro

f>n;m=mset (mmap) "a" 1;mget m "a" ?? mget m "b" ?? 99

Before:

ILO-T006 arity mismatch: 'mget' expects 2 args, got 3

After:

1

What's in the diff

  • src/parser/mod.rs: in the post-arg infix check in parse_call_or_atom, treat Token::NilCoalesce as always-infix. One condition, one comment block explaining why.
  • tests/regression_mget_default.rs: extend the existing cross-engine harness with chained mget m k1 ?? mget m k2 ?? d in first-hit, second-hit, both-miss and no-default shapes. Add an at-based pair to confirm the fix isn't mget-specific. Drop the stale comment that said chained ?? didn't parse.
  • examples/chained-nilcoalesce.ilo: in-context learning example exercised across every engine by tests/examples_engines.rs.

Test plan

  • Repro program returns the expected value across --run-tree, --run-vm, --run-cranelift.
  • Existing regression_prefix_nil_coalesce (covers g ??c 7) still passes — prefix-?? in call-arg position is unaffected.
  • Existing regression_mget_default single-mget cases still pass.
  • examples/chained-nilcoalesce.ilo runs clean under the examples harness.
  • Full suite green: cargo test --release --features cranelift.
  • cargo fmt --check, cargo clippy --all-targets --release --features cranelift clean.

Follow-ups

None. The post-arg infix check was the only place this leaked.

The post-arg break in parse_call_or_atom allowed ?? through when
looks_like_prefix_binary matched, since ?? is included in the
prefix-binary scanner. With a 2+ atom tail (??ident ident ...) the
scanner happily treated the chain as a prefix nil-coalesce, and the
first call kept absorbing it as another argument. Chained
'mget m "a" ?? mget m "b" ?? 99' then failed verification with
ILO-T006 arity mismatch.

Once at least one argument has been collected, ?? is unambiguously
the infix nil-coalesce on the call result. The first-token case is
left alone so 'g ??c 7' still passes a prefix-?? sub-expression as g's
arg.
Extends regression_mget_default with chained 'mget m k1 ?? mget m k2 ?? d'
across the first-hit, second-hit, both-miss, and no-default shapes, plus
an 'at'-based pair to confirm the fix isn't mget-specific. Also drops
the stale comment noting the chained form didn't parse.

examples/chained-nilcoalesce.ilo demonstrates the now-correct behaviour
for in-context learning and acts as a higher-level regression via
tests/examples_engines.rs.
@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 e4542aa into main May 13, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/chained-nilcoalesce branch May 13, 2026 14:20
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