Skip to content

Commit 22bdaaa

Browse files
hyperpolymathclaude
andcommitted
fix(parser): braced /{E1, E2} return-position effect row (Refs #59)
The effects-migration-stance guide uses /{IO} and /{IO, Async} verbatim, but only the bare single-term `-> T / E` and prefix `-{ E1 + E2 }->` forms parsed; migrators could not write the documented syntax. Adds `ARROW type_expr SLASH LBRACE sep_nonempty_list(COMMA, effect_term) RBRACE`, folded into EffUnion via effect_union_of_list. The SLASH LBRACE prefix is unambiguous (bare form continues on IDENT; prefix row uses MINUS LBRACE; `{` cannot open a division operand in type position). Conflict STATES unchanged (25 s/r, 5 r/r — the documented ADR-008/009 permissive class); the 35->36 r/r item is exactly what the ADR-008 note predicts for any SLASH production. dune test 253/253, zero regression. Verified: /{IO} and /{IO, Async} parse+typecheck, /{IO, Bogus} still rejected via the PR-1 registry, bare /IO unregressed. Refs #59 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e1c1591 commit 22bdaaa

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

lib/parser.mly

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ let trait_ref_of_type_expr (t : type_expr) : trait_ref =
3232
| TyApp (id, args) -> { tr_name = id; tr_args = args }
3333
| _ -> failwith "impl: trait reference must be a named type"
3434

35+
(* Fold a non-empty comma-separated braced effect row `{E1, E2, ...}`
36+
into the binary EffUnion AST. Right-associated; union is
37+
order-insensitive downstream so association is immaterial. *)
38+
let rec effect_union_of_list = function
39+
| [] -> assert false (* separated_nonempty_list guarantees >= 1 *)
40+
| [e] -> e
41+
| e :: rest -> EffUnion (e, effect_union_of_list rest)
42+
3543
%}
3644

3745
/* Tokens with values */
@@ -209,6 +217,18 @@ return_type:
209217
`a / b`, `-{ E }->`, and braced `effect E {}` are all unaffected,
210218
full suite green. ADR-008 mandates this syntax; it is not sugar. */
211219
| ARROW ty = type_expr SLASH eff = effect_term { (Some ty, Some eff) }
220+
/* `-> T / {E1, E2, ...}` — braced comma-separated effect row. This is
221+
the surface the effects-migration-stance guide uses verbatim
222+
(`/{IO}`, `/{IO, Async}`); previously only the bare single-term
223+
`-> T / E` and the prefix `-{ E1 + E2 }->` forms parsed, so migrators
224+
could not write the documented syntax. The `SLASH LBRACE` prefix is
225+
unambiguous: bare `-> T / E` continues on IDENT, the prefix row uses
226+
`MINUS LBRACE`, and `{` cannot open a division operand in type
227+
position — so this adds no new reduce/reduce item beyond the existing
228+
ADR-008/ADR-009 permissive-ambiguity class (verified by conflict
229+
count + full suite). */
230+
| ARROW ty = type_expr SLASH LBRACE effs = separated_nonempty_list(COMMA, effect_term) RBRACE
231+
{ (Some ty, Some (effect_union_of_list effs)) }
212232
213233
fn_body:
214234
| blk = block { FnBlock blk }

0 commit comments

Comments
 (0)