Skip to content

feat: represent application as an n-ary AppN call node (#179) - #199

Merged
Unisay merged 1 commit into
mainfrom
issue-179/nary-appn
Jul 7, 2026
Merged

feat: represent application as an n-ary AppN call node (#179)#199
Unisay merged 1 commit into
mainfrom
issue-179/nary-appn

Conversation

@Unisay

@Unisay Unisay commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Implements the representational half of #179: the IR gains an n-ary application node, the groundwork for lifting the uncurried *.Uncurried wrappers to direct calls.

What changed

  • App ann f a becomes the singleton case of AppN ann f (args), one Lua call passing every argument. App stays as a bidirectional pattern synonym, so every unary rewrite rule (beta, magicDo, flattenDeepBinds) compiles unchanged. Currying stays expressed by nesting: AppN f [a, b] (one call f(a, b)) and AppN (AppN f [a]) [b] (two calls f(a)(b)) are different programs, because Lua drops surplus arguments and nils missing ones.
  • Total traversals move to AppN: getAnn, setAnn, subexpressions (visits every argument), and alphaEq (compares arity, then pairs arguments positionally).
  • The Lua backend emits a single n-ary call for a multi-argument AppN, keeping the lone Prim.undefined elision for the nullary case.
  • A new linter invariant, WellApplied, rejects applying a literal lambda to more than one argument in one call. A lambda compiles to a one-parameter Lua function, so a well-formed multi-argument AppN always has a non-lambda head (a reference to an n-ary foreign). The check is wired into the pass pipeline, dormant until a pass introduces multi-argument nodes.

Scope

This is the node only. Nothing produces a multi-argument AppN yet, so generated code is unchanged. Lifting the *.Uncurried wrappers (the perf-bearing half of the original #179) needs the source-derived lifter from #178 and is tracked in #198.

Closes #179.

Verification

  • cabal test all: 557 examples, 0 failures, including 16 new tests (n-ary codegen, the WellApplied invariant, alphaEq arity sensitivity).
  • golden.ir churns mechanically with the AppN Show shape. golden.lua and eval/golden.txt are untouched: the emitted Lua and its runtime output stay byte-identical.
  • fourmolu and hlint clean.

Replace the IR's unary `App ann f a` with `AppN ann f (args :| ...)`, one
Lua call passing every argument. `App` stays as a bidirectional pattern
synonym for the singleton, so existing unary rewrite rules compile
unchanged and currying keeps being expressed by nesting.

- Total case analyses (getAnn, setAnn, subexpressions, alphaEq) move to
  AppN; alphaEq compares arity and pairs arguments positionally.
- The Lua backend emits a single n-ary call for a multi-argument AppN,
  preserving the lone Prim.undefined elision for the nullary case.
- A new linter invariant (WellApplied) rejects a literal lambda applied
  to more than one argument in one call, since a lambda is a
  one-parameter Lua function.

Representational groundwork for lifting the *.Uncurried wrappers to
direct calls. On its own it leaves generated code unchanged: golden.lua
and eval goldens are untouched; golden.ir churns mechanically with the
AppN Show shape.
@Unisay Unisay self-assigned this Jul 7, 2026
@Unisay
Unisay requested a review from Copilot July 7, 2026 14:14
@Unisay
Unisay marked this pull request as ready for review July 7, 2026 14:14

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 updates the compiler IR to represent function application as an n-ary call node (AppN) while preserving the existing unary App API via a bidirectional pattern synonym. This lays the groundwork for future optimization work that can collapse uncurried wrapper spines into single Lua calls.

Changes:

  • Replaced the unary IR constructor App with AppN ann f (NonEmpty args) and reintroduced App as a bidirectional pattern synonym for the singleton case.
  • Updated core traversals/comparisons (getAnn, setAnn, subexpressions, alphaEq) and Lua codegen to support emitting a single n-ary Lua call for multi-argument AppN.
  • Added a new IR linter invariant (WellApplied) plus unit tests to prevent miscompiling multi-argument calls where the callee is a literal lambda.

Reviewed changes

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

Show a summary per file
File Description
lib/Language/PureScript/Backend/IR/Types.hs Introduces AppN, documents semantics, adds App pattern synonym, updates traversals and alphaEq.
lib/Language/PureScript/Backend/Lua.hs Emits n-ary Lua calls from AppN (including Prim.undefined elision for nullary calls).
lib/Language/PureScript/Backend/IR/Linter.hs Adds WellApplied invariant and detection of over-applied literal lambdas under AppN.
lib/Language/PureScript/Backend/IR/Pass.hs Wires WellApplied into the checked pass runner as a new invariant option.
lib/Language/PureScript/Backend/IR/Optimizer.hs Updates imports to use the App pattern synonym where needed.
lib/Language/PureScript/Backend/IR/MagicDo.hs Updates imports to use the App pattern synonym where needed.
lib/Language/PureScript/Backend/IR/FlattenDeepBinds.hs Updates imports to use the App pattern synonym where needed.
test/Language/PureScript/Backend/Lua/Spec.hs Adds coverage asserting AppN with multiple args lowers to a single Lua call.
test/Language/PureScript/Backend/IR/Types/Spec.hs Adds alphaEq tests covering AppN arity sensitivity and matching.
test/Language/PureScript/Backend/IR/Linter/Spec.hs Adds tests for WellApplied (including descent into nested call arguments).
test/Language/PureScript/Backend/IR/FlattenDeepBinds/Spec.hs Updates imports to use the App pattern synonym.
changelog.d/20260707_160000_unisay_nary_appn.md Changelog entry describing the IR change and new invariant.
test/ps/output/Golden.Unbinding.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.TailRecM2Shadow.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.StringEscapes.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.RecursiveBindings.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.RecGroupOrder.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.RecDataDefs.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.ProfunctorDictLens.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.PatternMatching.Test2/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Nested.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.NameShadowing.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.MaybeChainModule.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.MaybeChain.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Issue37.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Inline.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.HelloPrelude.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.ForeignSharing.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.FloatIn.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Fibonacci.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.DerivedFunctor.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Currying.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.CharLiterals.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.CaseStatements.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.BugListGenericEq.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.ArrayPatternMatch.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.ArrayOfUnits.Test/golden.ir Golden IR updated for AppN shape.
test/ps/output/Golden.Annotations.M2/golden.ir Golden IR updated for AppN shape.

@Unisay
Unisay merged commit d9d2d58 into main Jul 7, 2026
3 checks passed
@Unisay
Unisay deleted the issue-179/nary-appn branch July 7, 2026 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce the n-ary AppN call node (replace unary App)

2 participants