A braceless test body that opens with var or const is silently emptied. Every assertion in it is discarded, and gen_test_block emits the empty test with no marker.
test opens_with_var
var x : i32 = 1;
assert g(x) == 999 ← never reaches any backend
The same body works if any clause precedes the var:
test opens_with_given
given pad = 0
var x : i32 = 1;
assert g(x) == 999 ← lowered
Why
parse_bdd_clauses gates its statement arm on first_clause_col, which is set after the first clause is lowered. A body opening with var/const has no earlier clause, so the column is None, the arm is skipped, and the block falls back to the wholesale discard.
I wrote the fix, measured it, and did not ship it
Seeding the column from the opening statement recovers 1,914 discarded tokens across the corpus (35,224 → 33,310, and one spec leaves the discarding set entirely).
It also regresses specs/memory/notebooklm.t27 from parsing to not parsing.
The mechanism, isolated by disabling one edit at a time rather than by reading the code: seeding the column lets an earlier clause take the statement arm, and the parser then arrives at
const (notebook, err) = notebook_find_by_name(client, "nonexistent");
— a tuple destructure the arm cannot handle — in a state where the old path would have fallen back for the whole block. Instead it dies with Expected identifier after 'const', got LParen.
Narrowing the guard to peek == Ident does not help, because the failure is not at the seeded clause: it is downstream, at a const ( several clauses later.
parse_bdd_clauses carries an explicit contract in its own doc comment:
Safety contract: this may only ADD assertions, never break a file.
That version breaks one, so it stayed out. The trailing-semicolon half of the same family shipped separately — regression-free, 154 tokens.
What the real fix probably needs
Containment rather than a better guard: the statement arm's failure should restore the block-level fallback instead of propagating a hard parse error out of the caller. Then seeding the column is safe, because the worst case returns to today's behaviour for that block rather than failing the file.
That is a change to how parse_bdd_clauses reports failure, not to when it fires, and it is worth doing on its own terms — the 1,914 tokens are the reward, and the same containment would make every future widening of this arm safe by construction.
Refs #2161
A braceless test body that opens with
varorconstis silently emptied. Every assertion in it is discarded, andgen_test_blockemits the empty test with no marker.The same body works if any clause precedes the
var:Why
parse_bdd_clausesgates its statement arm onfirst_clause_col, which is set after the first clause is lowered. A body opening withvar/consthas no earlier clause, so the column isNone, the arm is skipped, and the block falls back to the wholesale discard.I wrote the fix, measured it, and did not ship it
Seeding the column from the opening statement recovers 1,914 discarded tokens across the corpus (35,224 → 33,310, and one spec leaves the discarding set entirely).
It also regresses
specs/memory/notebooklm.t27from parsing to not parsing.The mechanism, isolated by disabling one edit at a time rather than by reading the code: seeding the column lets an earlier clause take the statement arm, and the parser then arrives at
— a tuple destructure the arm cannot handle — in a state where the old path would have fallen back for the whole block. Instead it dies with
Expected identifier after 'const', got LParen.Narrowing the guard to
peek == Identdoes not help, because the failure is not at the seeded clause: it is downstream, at aconst (several clauses later.parse_bdd_clausescarries an explicit contract in its own doc comment:That version breaks one, so it stayed out. The trailing-semicolon half of the same family shipped separately — regression-free, 154 tokens.
What the real fix probably needs
Containment rather than a better guard: the statement arm's failure should restore the block-level fallback instead of propagating a hard parse error out of the caller. Then seeding the column is safe, because the worst case returns to today's behaviour for that block rather than failing the file.
That is a change to how
parse_bdd_clausesreports failure, not to when it fires, and it is worth doing on its own terms — the 1,914 tokens are the reward, and the same containment would make every future widening of this arm safe by construction.Refs #2161