Magic-do recognises Effect/ST do-chains by name: it matches the bindE/pureE dictionary methods, flattens the chain into do-chunks, and marks each statement's run with the synthetic EffectRunArg application. The downstream passes are already built around the marker rather than the names: DCE keeps a result-unused effect statement via isEffectRun, betaReduce refuses to reduce an effect-run redex, and codegen erases the marker back to a plain call (and, since #226, sheds the literal thunk under it).
The name recognition is the fragile half. Anything that renames, inlines, or lifts the Effect core before magic-do runs blinds it. #227 makes this concrete: once the foreign lifter handles multi-parameter literals, bindE and pureE become technically liftable (their bodies are pure return trees), and allowlisting them would dissolve the bind chains in the optimizer fixpoint before magic-do ever sees them. That loses the flat do-chunks and with them the handling of Lua's nesting and locals limits (#19). Today the only protection is a warning comment next to the allowlist, and the broader-allowlist work (#187) keeps raising the exposure.
The direction is to invert the dependency. Normalise every effect run to the EffectRunArg marker before magic-do, and let magic-do build do-chunks from the marker semantics (an application of the marker is the run of a suspended action) instead of recognising dictionary names. Lifting or inlining the Effect core then stops being dangerous by construction, and the guardrail comment becomes obsolete.
This is a redesign of magic-do's recognition and of the chunk-boundary strategy that keeps generated functions within Lua's parser-nesting and locals caps (#19), so it needs its own design pass. Split out of the future-direction note in #227.
Magic-do recognises
Effect/STdo-chains by name: it matches thebindE/pureEdictionary methods, flattens the chain into do-chunks, and marks each statement's run with the syntheticEffectRunArgapplication. The downstream passes are already built around the marker rather than the names: DCE keeps a result-unused effect statement viaisEffectRun,betaReducerefuses to reduce an effect-run redex, and codegen erases the marker back to a plain call (and, since #226, sheds the literal thunk under it).The name recognition is the fragile half. Anything that renames, inlines, or lifts the Effect core before magic-do runs blinds it. #227 makes this concrete: once the foreign lifter handles multi-parameter literals,
bindEandpureEbecome technically liftable (their bodies are pure return trees), and allowlisting them would dissolve the bind chains in the optimizer fixpoint before magic-do ever sees them. That loses the flat do-chunks and with them the handling of Lua's nesting and locals limits (#19). Today the only protection is a warning comment next to the allowlist, and the broader-allowlist work (#187) keeps raising the exposure.The direction is to invert the dependency. Normalise every effect run to the
EffectRunArgmarker before magic-do, and let magic-do build do-chunks from the marker semantics (an application of the marker is the run of a suspended action) instead of recognising dictionary names. Lifting or inlining the Effect core then stops being dangerous by construction, and the guardrail comment becomes obsolete.This is a redesign of magic-do's recognition and of the chunk-boundary strategy that keeps generated functions within Lua's parser-nesting and locals caps (#19), so it needs its own design pass. Split out of the future-direction note in #227.