Skip to content

Commit 4b57b74

Browse files
committed
Scalarize Lua tuples through ordered bundles
1 parent ab2fda6 commit 4b57b74

8 files changed

Lines changed: 1351 additions & 322 deletions

File tree

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,20 @@ For config and run-pipeline changes, prefer these focused checks before broader
212212

213213
Recent fixes established additional rules for backend work. Follow these for all future changes:
214214

215+
### Compiler phase ownership and lowering invariants
216+
217+
* Fix malformed or underspecified IR in the phase which creates it. Do not add downstream recovery,
218+
name parsing, or backend-specific guessing for information an earlier phase discarded.
219+
* Semantic identity and specialization keys must use referenced AST/IM nodes plus structural type
220+
arguments, never generated names or string comparison.
221+
* Each lowering phase has one explicit input/output contract. After an abstraction is lowered,
222+
downstream phases consume the lowered representation and must not reconstruct its source meaning.
223+
* Prefer backend-appropriate, state-of-the-art lowering when semantics permit it. Jass limitations may
224+
require compatibility compromises; do not carry those compromises into Lua without evidence.
225+
* Behavioral correctness is the primary requirement. Runtime and allocation performance are the next
226+
requirement: common optimized paths must not retain avoidable compiler-introduced allocation,
227+
dispatch, copying, or bookkeeping overhead.
228+
215229
### Jass/Lua feature parity
216230

217231
* New language/compiler features must be validated for **both Jass and Lua** backends.

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/WurstCompilerJassImpl.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -874,12 +874,11 @@ public LuaCompilationUnit transformProgToLua() {
874874

875875
ImAttrType.setWurstClassType(null);
876876
int stage;
877-
if (containsGenericNewCall() || containsTypeClassDispatch()) {
878-
// Both operations need the concrete type argument, which erasure does not keep. Only
879-
// the paths reaching them are specialised: the full elimination used for Jass is
880-
// followed there by class elimination, and leaves state this backend cannot consume.
881-
beginPhase(2, "Specialize generics for generic construction and type class dispatch");
882-
new EliminateGenerics(getImTranslator(), getImProg()).transformGenericNewOnly();
877+
boolean specializeTupleValueTypes = containsTupleTypeArgument();
878+
if (containsGenericNewCall() || containsTypeClassDispatch() || specializeTupleValueTypes) {
879+
beginPhase(2, "Specialize generics for Lua-only concrete operations");
880+
new EliminateGenerics(getImTranslator(), getImProg())
881+
.transformGenericNewOnly(specializeTupleValueTypes);
883882
timeTaker.endPhase();
884883
}
885884
if (runArgs.isNoDebugMessages()) {
@@ -919,6 +918,12 @@ public LuaCompilationUnit transformProgToLua() {
919918
getImProg().flatten(imTranslator2);
920919
EliminateLocalTypes.eliminateLocalTypesProg(getImProg(), imTranslator2);
921920

921+
timeTaker.beginPhase("eliminate tuples");
922+
getImProg().flatten(imTranslator2);
923+
EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2);
924+
imTranslator2.assertProperties(AssertProperty.NOTUPLES);
925+
timeTaker.endPhase();
926+
922927
optimizer.removeGarbage();
923928
imProg.flatten(imTranslator);
924929
timeTaker.endPhase();
@@ -996,4 +1001,19 @@ public void visit(ImTypeVarDispatch dispatch) {
9961001
});
9971002
return found[0];
9981003
}
1004+
1005+
/** Tuple type arguments need monomorphisation before tuples can become scalar storage. */
1006+
private boolean containsTupleTypeArgument() {
1007+
boolean[] found = {false};
1008+
getImProg().accept(new de.peeeq.wurstscript.jassIm.Element.DefaultVisitor() {
1009+
@Override
1010+
public void visit(ImTypeArgument argument) {
1011+
if (TypesHelper.typeContainsTuples(argument.getType())) {
1012+
found[0] = true;
1013+
}
1014+
super.visit(argument);
1015+
}
1016+
});
1017+
return found[0];
1018+
}
9991019
}

0 commit comments

Comments
 (0)