Skip to content

Commit 6c8d205

Browse files
committed
Preserve tuple specialization class identity
1 parent 7904f0b commit 6c8d205

3 files changed

Lines changed: 97 additions & 2 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,43 @@ public void visit(ImMemberAccess memberAccess) {
281281
super.visit(memberAccess);
282282
collectGenericNewUse(memberAccess);
283283
}
284+
285+
@Override
286+
public void visit(ImDealloc dealloc) {
287+
super.visit(dealloc);
288+
collectGenericNewUse(dealloc);
289+
}
290+
291+
@Override
292+
public void visit(ImInstanceof instanceOf) {
293+
super.visit(instanceOf);
294+
collectGenericNewUse(instanceOf);
295+
}
296+
297+
@Override
298+
public void visit(ImTypeIdOfObj typeId) {
299+
super.visit(typeId);
300+
collectGenericNewUse(typeId);
301+
}
302+
303+
@Override
304+
public void visit(ImTypeIdOfClass typeId) {
305+
super.visit(typeId);
306+
collectGenericNewUse(typeId);
307+
}
284308
});
285309
}
286310

311+
private void collectGenericNewUse(ImClassRelatedExprWithClass expression) {
312+
ImClassType clazz = expression.getClazz();
313+
if (clazz.getTypeArguments().isEmpty()
314+
|| typeArgumentsContainTypeVariable(clazz.getTypeArguments())
315+
|| !shouldSpecializeTupleArguments(clazz.getTypeArguments())) {
316+
return;
317+
}
318+
genericsUses.add(new GenericClazzUse(expression));
319+
}
320+
287321
private void collectGenericNewUses(Element element) {
288322
element.accept(new Element.DefaultVisitor() {
289323
@Override
@@ -1796,7 +1830,8 @@ private ImClass specializeClass(ImClass c, GenericTypes generics) {
17961830
// NEW: Create specialized global variables for this class instantiation
17971831
createSpecializedGlobals(c, generics, typeVars);
17981832

1799-
if (genericNewOnly && isConstructionOnlyInstantiation(c)) {
1833+
if (genericNewOnly && (isConstructionOnlyInstantiation(c)
1834+
|| (specializeTupleValueTypes && genericTypesContainTuple(generics)))) {
18001835
attachSpecializedClassMethods(c, newC, generics);
18011836
}
18021837

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/LuaTranslator.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,10 +892,16 @@ private void initClassTables(ImClass c) {
892892
));
893893

894894
// set typeid metadata:
895+
ImClass typeIdClass = c;
896+
ImTranslator.Specialisation specialization = imTr.specialisationOf(c);
897+
if (specialization != null && specialization.original() instanceof ImClass original) {
898+
// Targeted Lua specialization preserves the nominal identity of the erased class.
899+
typeIdClass = original;
900+
}
895901
deferMainInit(LuaAst.LuaAssignment(LuaAst.LuaExprFieldAccess(
896902
LuaAst.LuaExprVarAccess(classVar),
897903
ExprTranslation.TYPE_ID),
898-
LuaAst.LuaExprIntVal("" + prog.attrTypeId().get(c))
904+
LuaAst.LuaExprIntVal("" + prog.attrTypeId().get(typeIdClass))
899905
));
900906

901907

@@ -1310,6 +1316,12 @@ private void collectSuperClasses(LuaTableFields superClasses, ImClass c, Set<ImC
13101316
}
13111317
superClasses.add(LuaAst.LuaTableExprField(LuaAst.LuaExprVarAccess(luaClassVar.getFor(c)), LuaAst.LuaExprBoolVal(true)));
13121318
visited.add(c);
1319+
ImTranslator.Specialisation specialization = imTr.specialisationOf(c);
1320+
if (specialization != null && specialization.original() instanceof ImClass original) {
1321+
// A targeted Lua specialization is a representation detail, not a new nominal type.
1322+
// Keep erased-class runtime checks true without inheriting its fields a second time.
1323+
collectSuperClasses(superClasses, original, visited);
1324+
}
13131325
for (ImClassType sc : c.getSuperClasses()) {
13141326
collectSuperClasses(superClasses, sc.getClassDef(), visited);
13151327
}

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaBackendAuditTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,54 @@ public void tupleReturnSlotsAreSharedAcrossMultipleInterfaceRoots() throws IOExc
264264
assertFalse(compiled.contains("tupleEquals"));
265265
}
266266

267+
@Test
268+
public void tupleSpecializedClassBindsNongenericInterfaceDispatch() throws IOException {
269+
test().testLua(true).executeProg().lines(
270+
"package Test",
271+
"native testSuccess()",
272+
"tuple pair(int x, int y)",
273+
"interface Producer",
274+
" function produce() returns pair",
275+
"class GenericProducer<T:> implements Producer",
276+
" pair stored",
277+
" construct(pair value)",
278+
" stored = value",
279+
" function produce() returns pair",
280+
" return stored",
281+
"init",
282+
" Producer producer = new GenericProducer<pair>(pair(4, 5))",
283+
" if producer.produce() == pair(4, 5)",
284+
" testSuccess()"
285+
);
286+
287+
String compiled = compiledLua("tupleSpecializedClassBindsNongenericInterfaceDispatch");
288+
assertTrue(compiled.contains("GenericProducer_specialized"));
289+
assertFalse(compiled.contains("tupleCopy"));
290+
}
291+
292+
@Test
293+
public void tupleSpecializedClassPreservesRuntimeTypeOperations() throws IOException {
294+
test().testLua(true).executeProg().lines(
295+
"package Test",
296+
"native testSuccess()",
297+
"tuple pair(int x, int y)",
298+
"interface Marker",
299+
"class Box<T:> implements Marker",
300+
" T value",
301+
" construct(T initial)",
302+
" value = initial",
303+
"init",
304+
" Marker box = new Box<pair>(pair(6, 7))",
305+
" Marker plain = new Box<int>(1)",
306+
" if box instanceof Box and box.typeId == plain.typeId",
307+
" testSuccess()"
308+
);
309+
310+
String compiled = compiledLua("tupleSpecializedClassPreservesRuntimeTypeOperations");
311+
assertTrue(compiled.contains("Box_specialized"));
312+
assertFalse(compiled.contains("tupleCopy"));
313+
}
314+
267315
@Test
268316
public void tupleReturningCallsAreCapturedBeforeComparison() throws IOException {
269317
test().testLua(true).executeProg().lines(

0 commit comments

Comments
 (0)