Skip to content

Fold ctor/array through-let unpacking across trailing sibling groupings, as the record rules do #323

Description

@Unisay

Problem

The three through-a-let unpacking families now disagree on where they look for the binder's uses. The record rules of #240 (propagateKnownObjectThroughLet, propagateObjectUpdateThroughLet) fold occurrences across the trailing sibling groupings of the same Let as well as its body — Let groupings scope sequentially, so a later binding's right-hand side legitimately reads an earlier binder. The constructor rule (propagateKnownCtorThroughLet, #214) and the array rule (propagateKnownArrayThroughLet, #225) instead decline outright when any sibling grouping references the binder:

, all ((== 0) . countFreeRefGrouping name) (before <> after)

For records the sibling reach was load-bearing (the defaults pattern let opts = {…}; chosen = opts { … } in … puts the update use in a sibling), but the same multi-binding shape exists for the other aggregates — e.g. a let-bound array consumed by a later sibling binding's length/element reads, or a constructor scrutinized by a sibling — and today those decline even though every use is a foldable eliminating read:

let xs = [10, 20]
    total = xs !! 0 + xs !! 1   -- sibling grouping reads xs: rule declines
in f total total

Approach

Port the #240 mechanics to the two older rules: split with the shared findStandaloneBinding, take targets = body : (groupingExprs =<< after) (both helpers already live in Language.PureScript.Backend.IR.Optimizer), run the existing census over targets, fold with fmap (fmap (fmap foldReads)) after alongside the body, and keep declining on any before-grouping reference (impossible under globally-unique-counters scoping, but optimizedExpression also runs on generated input). The field/element-binders already take the consumed binding's position, so they scope over the trailing siblings unchanged.

Prerequisites / Relations

No open blockers. Builds on #240 (closed), which introduced the sibling-reach mechanics and the shared findStandaloneBinding/groupingExprs helpers; touches the rules introduced by #214 and #225 (both closed).

Verification

A unit spec per rule with the use in a trailing sibling grouping (mirroring the #240 spec "unpacks a literal used from a later sibling binding") goes from decline to fold; existing suites and goldens stay green, with any structural golden movement reviewed as legitimate extra folding.

Metadata

Metadata

Assignees

No one assigned

    Labels

    OptimisationA Compiler Optimisationarea: irIR / optimizer / DCE / inlinerenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions