Skip to content

Fold ObjectProp field reads over known constructors (#213)#215

Merged
Unisay merged 1 commit into
mainfrom
issue-213/objectprop-ctor-fold
Jul 9, 2026
Merged

Fold ObjectProp field reads over known constructors (#213)#215
Unisay merged 1 commit into
mainfrom
issue-213/objectprop-ctor-fold

Conversation

@Unisay

@Unisay Unisay commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Closes #213.

What

Constructor field access reaches the IR as an ObjectProp record projection, ObjectProp (Ref v) (PropName "value0"), not as DataArgumentByIndex. That is the shape the generated bind/map/maybe workers actually contain. Nothing folded it: reduceObjectProp handles record literals and updates only (#153), and the case-of-known-constructor folds of #177 cover the DataArgumentByIndex field-read form. So (Just 7).value0 was left standing even with the constructor syntactically in place.

How

This adds one case to reduceKnownConstructor: ObjectProp (K a₁ … aₙ) "valueᵢ" over a saturated constructor application folds to aᵢ. The projection label maps to its positional argument through the constructor's declared field names (value0, value1, …, the row keys the Lua backend emits for a Ctor), so a label that is not one of them is declined rather than guessed. It reuses the discipline already established for the DataArgumentByIndex fold: discarded arguments are dropped rather than evaluated or duplicated, and the folded value carries the read node's own annotation, not the field's (the leak care behind reduceObjectProp).

Why now

This is a prerequisite for #180 (budgeted dictionary-method inlining). Once a method is inlined and its constructor argument is in place, the payload reads it through exactly this ObjectProp shape; without this fold the inliner would inline but the projection would not collapse. #214 (case-of-known-constructor through a let) stacks on this branch, and #180 stacks on #214.

Verification

New optimizer specs mirror the #177 coverage for the projection form: saturated sum and product reads, the sibling-rule cascade, the partial-application and absent-label declines, the discarded-argument drop, and the two annotation-leak guards. A randomized property stresses the discard semantics across arbitrary arity, algebraic type, and argument content.

Full suite green (cabal test all): 695 examples, 0 failures. No structural golden moved and no eval oracle moved, which matches the near-zero standalone impact the issue predicts, since the shape barely occurs before method inlining lands. fourmolu and hlint are clean and the build is warning-free.

Extend case-of-known-constructor (reduceKnownConstructor) to the
record-projection field read the pattern matcher actually emits:
`ObjectProp (K a₁ … aₙ) "valueᵢ"` over a saturated constructor
application folds to `aᵢ`. The label maps to its position through the
constructor's declared field names, so a projection whose label is not
one of them is declined.

This is the ObjectProp twin of the DataArgumentByIndex fold from #177
and the algebraic-data companion of the record-literal fold from #153.
Discarded arguments are dropped rather than evaluated or duplicated, and
the folded value takes the read node's own annotation, not the field's,
matching the existing discard/annotation discipline.

Standalone impact is near zero; the shape appears once dictionary-method
inlining (#180) folds a constructor into a projection, so this lands as
a prerequisite that issue builds on.
@Unisay Unisay added area: ir IR / optimizer / DCE / inliner Optimisation A Compiler Optimisation labels Jul 9, 2026
@Unisay Unisay requested a review from Copilot July 9, 2026 09:10
@Unisay Unisay self-assigned this Jul 9, 2026
@Unisay Unisay marked this pull request as ready for review July 9, 2026 09:13

Copilot AI 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.

Pull request overview

This PR extends the IR optimizer’s “case-of-known-constructor” folding so it can eliminate constructor payload reads that appear as ObjectProp … (PropName "value<i>"), matching the projection shape produced by the pattern matcher and unblocking downstream dictionary-method inlining work.

Changes:

  • Add a reduceKnownConstructor rewrite for ObjectProp (Ctor … a₁ … aₙ) "valueᵢ" to fold to aᵢ when the constructor application is saturated and the label matches a declared field.
  • Add Hspec + Hedgehog coverage mirroring the existing DataArgumentByIndex folding tests, including annotation preservation and randomized discard-semantics stress.
  • Add a changelog fragment documenting the new optimizer behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
lib/Language/PureScript/Backend/IR/Optimizer.hs Adds the ObjectProp-over-saturated-Ctor folding case to reduceKnownConstructor, using field-name/prop-name matching and preserving the projection node’s annotation.
test/Language/PureScript/Backend/IR/Optimizer/Spec.hs Adds targeted unit/property tests covering success/decline cases, sibling-rule cascade, discard semantics, and annotation leak guards for the new fold.
changelog.d/20260709_110442_unisay_objectprop_ctor_fold.md Documents the new optimizer rule and its intended discipline/impact.

@Unisay Unisay merged commit 9c4e805 into main Jul 9, 2026
3 checks passed
@Unisay Unisay deleted the issue-213/objectprop-ctor-fold branch July 9, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ir IR / optimizer / DCE / inliner Optimisation A Compiler Optimisation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fold ObjectProp field reads over known constructor applications

2 participants