Skip to content

Unbox Ref/STRef operations in value positions (while-conditions, stored actions) #317

Description

@Unisay

Problem

The cell unboxing of #239 lowers a Ref/STRef operation only in run position — where the application carries the magic-do run marker, or is the body of a literal loop lambda the native-loop lowering runs per iteration. An operation used as a first-class value keeps the whole cell boxed. The most visible casualty is the while condition: map (_ > 0) (STRef.read value) is an ST action value built once and forced per iteration, so the cell it reads stays a {value = …} table even when everything else about it would unbox. From test/ps/output/Golden.NativeLoopsST.Test/golden.lua after #239steps (run positions only) unboxes while value (read inside the condition value) stays boxed:

local steps = 0
local value = Control_Monad_ST_Internal_new(start)()
do
  local _S_cond0 = Control_Monad_ST_Internal_map_(function(v)
    return v >= 0 and v ~= 0
  end)(Control_Monad_ST_Internal_read(value))
  while _S_cond0() do

Approach

Lower a recognised operation in value position to a nullary Lua closure over the unboxed local — function() return g(value) end for the condition above — which is semantically what the boxed foreign chain builds (the closure shares the local as an upvalue, so each forcing sees the current contents). The subtlety is evaluation timing: the boxed form evaluates the operation's non-reference arguments when the thunk is built, not when it is forced, so a non-atomic argument must be pre-bound outside the closure (or the analysis must require atomic arguments in value positions). The while-condition case can go further: when the condition's compiled run is a pure expression, the native-loop lowering can inline it as the while predicate directly instead of building the thunk at all.

Relations

Extends #239; the value-position restriction and this exact countDown shape are pinned by Golden.NativeLoopsST.Test. Independent of the Effect-side dictionary gap (filed separately).

Verification

countDown's value cell in Golden.NativeLoopsST.Test compiles with no {value = …} table and the loop condition reads the local; eval golden unchanged. A stored-action shape (let action = STRef.write 5 r re-run twice) unboxes with a fresh golden pinning it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    OptimisationA Compiler Optimisationarea: codegenLua code generation / printingenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions