Skip to content

Commit fe87269

Browse files
committed
Retain nominal metadata for tuple specializations
1 parent 4b57b74 commit fe87269

3 files changed

Lines changed: 42 additions & 10 deletions

File tree

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,12 +1062,9 @@ private void initClassTables(ImClass c) {
10621062
));
10631063

10641064
// set typeid metadata:
1065-
ImClass typeIdClass = c;
1066-
ImTranslator.Specialisation specialization = imTr.specialisationOf(c);
1067-
if (specialization != null && specialization.original() instanceof ImClass original) {
1068-
// Targeted Lua specialization preserves the nominal identity of the erased class.
1069-
typeIdClass = original;
1070-
}
1065+
// Targeted Lua specialization changes storage, not nominal identity. Garbage reachability
1066+
// retains this canonical metadata dependency before emission.
1067+
ImClass typeIdClass = imTr.canonical(c);
10711068
deferMainInit(LuaAst.LuaAssignment(LuaAst.LuaExprFieldAccess(
10721069
LuaAst.LuaExprVarAccess(classVar),
10731070
ExprTranslation.TYPE_ID),
@@ -1486,11 +1483,11 @@ private void collectSuperClasses(LuaTableFields superClasses, ImClass c, Set<ImC
14861483
}
14871484
superClasses.add(LuaAst.LuaTableExprField(LuaAst.LuaExprVarAccess(luaClassVar.getFor(c)), LuaAst.LuaExprBoolVal(true)));
14881485
visited.add(c);
1489-
ImTranslator.Specialisation specialization = imTr.specialisationOf(c);
1490-
if (specialization != null && specialization.original() instanceof ImClass original) {
1486+
ImClass nominalClass = imTr.canonical(c);
1487+
if (nominalClass != c) {
14911488
// A targeted Lua specialization is a representation detail, not a new nominal type.
14921489
// Keep erased-class runtime checks true without inheriting its fields a second time.
1493-
collectSuperClasses(superClasses, original, visited);
1490+
collectSuperClasses(superClasses, nominalClass, visited);
14941491
}
14951492
for (ImClassType sc : c.getSuperClasses()) {
14961493
collectSuperClasses(superClasses, sc.getClassDef(), visited);

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,18 @@
1919
public class RemoveGarbage {
2020

2121
private static class Used {
22+
private final ImTranslator translator;
2223
private final Set<ImFunction> functions = new HashSet<>();
2324
private final Set<ImMethod> methods = new HashSet<>();
2425
// methods that will be added once the class is used:
2526
private final Multimap<ImClass, ImMethod> waitingMethods = HashMultimap.create();
2627
private final Set<ImClass> classes = new HashSet<>();
2728
private final Set<ImVar> vars = new HashSet<>();
2829

30+
private Used(ImTranslator translator) {
31+
this.translator = translator;
32+
}
33+
2934
public void addMethod(ImMethod m) {
3035
methods.add(m);
3136
}
@@ -65,6 +70,13 @@ public void addVar(ImVar var) {
6570

6671
public void addClass(ImClass c) {
6772
classes.add(c);
73+
ImClass nominalClass = translator.canonical(c);
74+
if (nominalClass != c) {
75+
// A targeted specialization has a distinct storage layout but keeps the source
76+
// class's nominal type id and instanceof identity. The canonical class is therefore
77+
// a real metadata dependency even when no source expression names it directly.
78+
visitClass(nominalClass, this);
79+
}
6880
Collection<ImMethod> imMethods = waitingMethods.get(c);
6981
Iterator<ImMethod> it = imMethods.iterator();
7082
while (it.hasNext()) {
@@ -76,7 +88,7 @@ public void addClass(ImClass c) {
7688
}
7789

7890
public static void removeGarbage(ImProg prog, ImTranslator translator) {
79-
Used used = new Used();
91+
Used used = new Used(translator);
8092
for (ImFunction f : ImHelper.calculateFunctionsOfProg(prog)) {
8193
if (f.getName().equals("main")
8294
|| f.getName().equals("config")) {

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,29 @@ public void tupleSpecializedClassPreservesRuntimeTypeOperations() throws IOExcep
451451
assertFalse(compiled.contains("tupleCopy"));
452452
}
453453

454+
@Test
455+
public void tupleSpecializedClassRetainsNominalMetadataWhenItIsTheOnlyReachableForm() throws IOException {
456+
test().testLua(true).executeProg().lines(
457+
"package Test",
458+
"native testSuccess()",
459+
"tuple pair(int x, int y)",
460+
"interface Marker",
461+
"class Box<T:> implements Marker",
462+
" T value",
463+
" construct(T initial)",
464+
" value = initial",
465+
"init",
466+
" Marker box = new Box<pair>(pair(6, 7))",
467+
" if box != null",
468+
" testSuccess()"
469+
);
470+
471+
String compiled = compiledLua(
472+
"tupleSpecializedClassRetainsNominalMetadataWhenItIsTheOnlyReachableForm");
473+
assertTrue(compiled.contains("Box_specialized"));
474+
assertFalse(compiled.contains("tupleCopy"));
475+
}
476+
454477
@Test
455478
public void tupleReturningCallsAreCapturedBeforeComparison() throws IOException {
456479
test().testLua(true).executeProg().lines(

0 commit comments

Comments
 (0)