Commit 3e53f1d
## Summary
Closes #547. The slash-effect-row form `fn(...) -> T / { E1, E2 }` (and
its single-effect short form `fn(...) -> T / E`) parses today only in
fn-decl signatures (`return_type`, lines 271-282); it parse-errors in
record-field and type-alias positions, forcing every effectful
function-typed record field to fall back to the older `-{E}->` arrow
form.
This is a parser asymmetry, not a language-design question. Surfaced
during the post-#228 idaptik port batch in
[`hyperpolymath/idaptik#153`](https://github.com/hyperpolymath/idaptik/pull/153).
## Surface-grammar diff
```
type_expr_arrow:
| T -> R (already)
| T -{E}-> R (already)
+ | T -> R / { E1, E2, ... } (this PR)
+ | T -> R / E (this PR)
type_expr_primary (FN form, fn-as-type):
| fn(A, ...) -> R (already)
| fn(A, ...) -{E}-> R (already)
+ | fn(A, ...) -> R / { E1, ... } (this PR)
+ | fn(A, ...) -> R / E (this PR)
```
Both spellings remain accepted. `-{E}->` semantics are unchanged.
## Verification
- `dune build bin/main.exe` — clean
- `dune runtest` — **376/376 PASS** (368 baseline + 8 new)
- **Conflict count unchanged** (21 s/r, 1 r/r — same as pre-PR)
- Headline probes (all `Type checking passed`):
```
pub type AsyncCall = fn(Int) -> Int / { Async };
pub type H = { call: fn(Int) -> Int / { Async } }
pub type H = { call: fn(Int) -> Int / Async } // single short
pub type Multi = fn(Int, String) -> Bool / { IO, Async };
pub type R = Int -> Int / { Mut }; // arrow-as-type
pub type R = fn() -> () / { IO }; // zero-arg
```
## Semantic note (which arrow the effect attaches to)
- In `type_expr_arrow` (no `fn(...)` wrapper), the slash effect attaches
to the **outermost** arrow — the position of the slash itself. This is
the natural reading of `A -> B / { E }`.
- In the FN-form (`fn(A, B) -> R / { E }`), the effect attaches to the
**innermost** arrow (the call site), matching the established prefix-row
`-{E}->` FN-form precedent (lines 555-582). This is what consumers
expect when porting `fn(A, B) -{E}-> R`.
For users who want inner-arrow effect attachment in arrow-as-type
positions, the existing `-{E}->` form continues to express that.
## Refs
- Closes #547
- Refs #228 (sibling parser-asymmetry gap, closed in #241 / #447 / #523)
- Refs #229 (estate-wide ReScript-surface elimination)
- Refs #548 (sibling gap from the same port batch — module-level mutable
bindings, PR #549)
- Refs hyperpolymath/idaptik#153 (the port batch that surfaced this)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3608ff9 commit 3e53f1d
3 files changed
Lines changed: 141 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | | - | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
505 | 505 | | |
506 | 506 | | |
507 | 507 | | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
508 | 524 | | |
509 | 525 | | |
510 | 526 | | |
| |||
566 | 582 | | |
567 | 583 | | |
568 | 584 | | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
569 | 618 | | |
570 | 619 | | |
571 | 620 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
0 commit comments