Skip to content

feat(laurel): paren-free field ++/--, and chained-field-access test coverage#1382

Merged
fabiomadge merged 2 commits into
reviewed-kbd-will-merge-to-mainfrom
feat/laurel-field-access-fixes
Jun 23, 2026
Merged

feat(laurel): paren-free field ++/--, and chained-field-access test coverage#1382
fabiomadge merged 2 commits into
reviewed-kbd-will-merge-to-mainfrom
feat/laurel-field-access-fixes

Conversation

@fabiomadge

@fabiomadge fabiomadge commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Two field-access improvements on the single fieldAccess grammar op, plus test coverage that closes out #1371.

Note: the chained-field-access capability (a#b#c parsing, resolution, and heap elimination) already landed via #1328. This PR adds the one missing ergonomic piece, hardens the chained-access machinery with the tests it was missing, and a small refactor.

Grammar — paren-free field ++/--. fieldAccess precedence is raised 90 → 95. At 90 it tied with the postfix ++/-- ops (also 90), forcing (c#n)++; at 95 it binds tighter, so c#n++ parses paren-free as (c#n)++. (leftassoc, already present from #1328, is unchanged.) Note the new precedence is shared with call (also 95, via its callee:89) — the two must stay equal or a#b(x) parsing shifts; documented at the op.

Resolution — refactor only. The duplicated type-scope field lookup in targetTypeName and incrDecrTargetType is factored into a shared fieldTypeInScope helper. No behavior change. (This helper is also a dependency of the stacked compound-assignment PR.)

Tests — fill the chained-access coverage gap. #1328 shipped chained access with only a read-side smoke test (no assertions). This adds:

  • T9_ChainedFieldAccess: chained write (o#inner#count := …), read-after-inner-assign, must-alias, depth-3 (a#mid#inner#count), chained reads on both sides of ==, and paren-free chained o#inner#count++ (the one test that exercises this PR's grammar change), plus three negative tests (unconstrained read, two-object may-alias, write isolation) that pin the encoding as non-vacuous and frame-sound.
  • T23b_IncrDecrField: paren-free single-level field ++/--.

Full lake build and lake test pass.

Chained field access (`a#b#c`) and paren-free field increment (`c#n++`)
were both blocked by the `fieldAccess` grammar op. Combine the fixes:

* Grammar: `fieldAccess` becomes `@[prec(95), leftassoc]`. prec(95) binds
  tighter than the postfix incr/decr ops (prec 90) so `c#n++` parses as
  `(c#n)++` without parens; `leftassoc` lets `a#b#c` left-recurse.

* Resolution: `targetTypeName` is generalized to resolve a chained
  `.Var (.Field tgt f)` target by recursing on `tgt` and looking the field
  up in the inner type's scope. The recursion is kept total via fuel
  (cf. `underlyingBaseType`), not `partial`. The shared type-scope field
  lookup is factored into `fieldTypeInScope`, which `incrDecrTargetType`
  now reuses instead of duplicating.

* Heap: the field-read arm recurses into its target so a nested
  `FieldSelect` is eliminated. This single line unblocks *both* chained
  reads and chained writes: the write arm already calls `recurseOne` on its
  target, but for a nested target that recursion bottoms out in the read
  arm, so neither path worked before. Without the fix, an un-eliminated
  `FieldSelect` hits a downstream guard and aborts with a `strata-bug`
  (confirmed by ablation).

Tests:
* T9_ChainedFieldAccess: chained read/write, read-after-inner-assign,
  must-alias, depth-3 (`a#mid#inner#count`), chained read on both sides of
  a comparison, paren-free chained incr/decr, plus three negative tests
  (unconstrained read, two-object may-alias, write isolation) pinning the
  encoding as non-vacuous and frame-sound.
* T23b_IncrDecrField: paren-free field `++`/`--`; header comment updated
  (parens are no longer required).

Implements #1371.
@fabiomadge fabiomadge force-pushed the feat/laurel-field-access-fixes branch from 4eb1238 to dea6bcc Compare June 20, 2026 14:53
@fabiomadge fabiomadge changed the title feat(laurel): chained field access and paren-free field increment feat(laurel): paren-free field ++/--, and chained-field-access test coverage Jun 20, 2026
@fabiomadge fabiomadge marked this pull request as ready for review June 20, 2026 15:09
@fabiomadge fabiomadge requested a review from a team as a code owner June 20, 2026 15:09

@keyboardDrummer keyboardDrummer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice! Thanks

kadirayk
kadirayk previously approved these changes Jun 23, 2026

@kadirayk kadirayk left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fieldAccess 90 → 95 bump enables paren-free c#n++ and keeps precedence equal to call, so a#b(x) still parses correctly. The fieldTypeInScope refactor is a clean, behavior-preserving dedup. Well-scoped change, negative test cases are very nice too. LGTM!

@fabiomadge fabiomadge added this pull request to the merge queue Jun 23, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Jun 23, 2026
@fabiomadge fabiomadge added this pull request to the merge queue Jun 23, 2026
Merged via the queue into reviewed-kbd-will-merge-to-main with commit 8d6aa98 Jun 23, 2026
18 checks passed
@fabiomadge fabiomadge deleted the feat/laurel-field-access-fixes branch June 23, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants