Skip to content

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

Description

@Unisay

Status

Scoped to the n-ary AppN node (Option 1 of the original issue). Delivered in #199. The *.Uncurried lifting half, which carries the performance win and depends on the #178 lifter, moved to #198.

Problem

pslua has no way to express a single Lua call that passes several arguments. Every application is unary, so a saturated uncurried FFI call such as runSTFn2(pushImpl)(x)(arr)() compiles to a curried onion (two closure allocations plus a thunk per call), and the optimizer cannot collapse it because the IR cannot represent pushImpl(x, arr). The node added here is the representation the collapse needs; the collapse itself is #198.

Approach

AppN replaces App. The IR's unary App ann f a becomes AppN ann f (NonEmpty args), where the argument list is one Lua call with those arguments. The unary case is the singleton, and a bidirectional pattern synonym pattern App ann f a = AppN ann f (a :| []) keeps every existing unary rule (betaReduce, magicDo matching, flattenDeepBinds) compiling unchanged; multi-argument cases are added only where meaningful.

The list is not a flattened spine: 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 fills missing ones with nil. Currying stays expressed by nesting. A lint invariant (WellApplied) forbids applying a literal lambda to more arguments than it binds; since a lambda compiles to a one-parameter Lua function, a well-formed multi-argument AppN always has a non-lambda head.

n-ary abstraction (AbsN) is deliberately out of scope: n-ary callees already exist (FFI functions are n-ary in Lua source), while n-ary definitions only arise with full uncurrying (#24). This makes AppN the first installment of #24's infrastructure, with the arity given by types instead of analysis. For the same reason mkFnN (whose body is an n-ary function literal) defers to #24.

Prerequisites / Relations

The node depends only on #173 (done). It is the first installment of #24's infrastructure and, by giving #24 its n-ary call node, in turn unblocks #181. Lifting the *.Uncurried wrappers to direct AppN calls is #198, which additionally needs the #178 lifter.

Verification

On its own the node changes no generated code: golden.lua and the eval goldens stay byte-identical, while golden.ir churns mechanically with the AppN Show shape. New tests cover the n-ary codegen path, the WellApplied invariant, and alphaEq arity sensitivity. The performance measurement lives with the lifting work in #198.

Metadata

Metadata

Assignees

Labels

OptimisationA Compiler Optimisationarea: irIR / optimizer / DCE / inliner

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions