Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,20 @@ For config and run-pipeline changes, prefer these focused checks before broader

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

### Compiler phase ownership and lowering invariants

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

### Jass/Lua feature parity

* New language/compiler features must be validated for **both Jass and Lua** backends.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -874,12 +874,14 @@ public LuaCompilationUnit transformProgToLua() {

ImAttrType.setWurstClassType(null);
int stage;
if (containsGenericNewCall() || containsTypeClassDispatch()) {
// Both operations need the concrete type argument, which erasure does not keep. Only
// the paths reaching them are specialised: the full elimination used for Jass is
// followed there by class elimination, and leaves state this backend cannot consume.
beginPhase(2, "Specialize generics for generic construction and type class dispatch");
new EliminateGenerics(getImTranslator(), getImProg()).transformGenericNewOnly();
boolean specializeTupleValueTypes = containsTupleTypeArgument();
if (containsGenericNewCall() || containsTypeClassDispatch() || specializeTupleValueTypes) {
beginPhase(2, "Specialize generics for Lua-only concrete operations");
new EliminateGenerics(getImTranslator(), getImProg())
.transformGenericNewOnly(specializeTupleValueTypes);
// Remove phantom erased initialization before optimization can preserve only its side
// effect. A specialized static owns its copied initializer unless the erased static is live.
RemoveGarbage.removePhantomGenericStaticInitializers(getImProg(), getImTranslator());
timeTaker.endPhase();
}
if (runArgs.isNoDebugMessages()) {
Expand Down Expand Up @@ -919,6 +921,12 @@ public LuaCompilationUnit transformProgToLua() {
getImProg().flatten(imTranslator2);
EliminateLocalTypes.eliminateLocalTypesProg(getImProg(), imTranslator2);

timeTaker.beginPhase("eliminate tuples");
getImProg().flatten(imTranslator2);
EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2);
Comment thread
Frotty marked this conversation as resolved.
imTranslator2.assertProperties(AssertProperty.NOTUPLES);
timeTaker.endPhase();

optimizer.removeGarbage();
imProg.flatten(imTranslator);
timeTaker.endPhase();
Expand Down Expand Up @@ -996,4 +1004,19 @@ public void visit(ImTypeVarDispatch dispatch) {
});
return found[0];
}

/** Tuple type arguments need monomorphisation before tuples can become scalar storage. */
private boolean containsTupleTypeArgument() {
boolean[] found = {false};
getImProg().accept(new de.peeeq.wurstscript.jassIm.Element.DefaultVisitor() {
@Override
public void visit(ImTypeArgument argument) {
if (TypesHelper.typeContainsTuples(argument.getType())) {
found[0] = true;
}
super.visit(argument);
}
});
return found[0];
}
}
Loading
Loading