Skip to content

Commit a5a4f2f

Browse files
committed
use traces for member identification
1 parent e562964 commit a5a4f2f

3 files changed

Lines changed: 119 additions & 20 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ProgramState.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,12 +613,12 @@ public void setVal(ImVar v, ILconst val) {
613613
if (inits != null && !inits.isEmpty()) {
614614
ILconst initVal = inits.get(inits.size() - 1).getRight().evaluate(this, EMPTY_LOCAL_STATE);
615615
genericStaticScalarVals.put(key, initVal);
616-
System.out.println("[GENSTATIC] get " + key + " -> (init) " + initVal);
616+
WLogger.trace("[GENSTATIC] get " + key + " -> (init) " + initVal);
617617
return initVal;
618618
}
619619

620620
// fallback: default semantics (if your interpreter expects “unset = null/0”)
621-
System.out.println("[GENSTATIC] get " + key + " -> (unset) null");
621+
WLogger.trace("[GENSTATIC] get " + key + " -> (unset) null");
622622
return null;
623623
}
624624

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

Lines changed: 95 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import com.google.common.collect.*;
44
import de.peeeq.wurstscript.WLogger;
5+
import de.peeeq.wurstscript.ast.ClassDef;
56
import de.peeeq.wurstscript.ast.PackageOrGlobal;
67
import de.peeeq.wurstscript.ast.WPackage;
78
import de.peeeq.wurstscript.attributes.CompileError;
89
import de.peeeq.wurstscript.jassIm.*;
910
import de.peeeq.wurstscript.translation.imtojass.ImAttrType;
1011
import de.peeeq.wurstscript.translation.imtojass.TypeRewriteMatcher;
12+
import de.peeeq.wurstscript.translation.lua.translation.RemoveGarbage;
1113
import org.eclipse.jdt.annotation.Nullable;
1214
import org.jetbrains.annotations.NotNull;
1315

@@ -81,6 +83,26 @@ public void transform() {
8183
dbg(summary("after removeGenericConstructs"));
8284

8385
dbg(checkDanglingMethodRefs("end"));
86+
87+
// TODO fix or remove this check
88+
// assertNoUnspecializedGenericGlobals();
89+
}
90+
91+
private void assertNoUnspecializedGenericGlobals() {
92+
prog.accept(new Element.DefaultVisitor() {
93+
@Override public void visit(ImVarAccess va) {
94+
super.visit(va);
95+
if (globalToClass.containsKey(va.getVar())) {
96+
throw new CompileError(va, "Unspecialized generic global still used: " + va.getVar().getName());
97+
}
98+
}
99+
@Override public void visit(ImVarArrayAccess vaa) {
100+
super.visit(vaa);
101+
if (globalToClass.containsKey(vaa.getVar())) {
102+
throw new CompileError(vaa, "Unspecialized generic global array still used: " + vaa.getVar().getName());
103+
}
104+
}
105+
});
84106
}
85107

86108
private void makeNullAssignmentsSafe() {
@@ -259,7 +281,12 @@ private String summary(String phase) {
259281
private void removeNonSpecializedGlobals() {
260282
for (ImVar imVar : specializedGlobals.rowKeySet()) {
261283
prog.getGlobals().remove(imVar);
262-
prog.getGlobalInits().remove(imVar);
284+
List<ImSet> inits = prog.getGlobalInits().remove(imVar);
285+
if (inits != null) {
286+
for (ImSet init : inits) {
287+
init.replaceBy(ImHelper.nullExpr());
288+
}
289+
}
263290
}
264291
}
265292

@@ -399,29 +426,79 @@ private void moveFunctionsOutOfClass(ImClass c) {
399426
* These are the "static" fields that need specialization
400427
*/
401428
private void identifyGenericGlobals() {
402-
// Build a map of class name to class for quick lookup
403-
Map<String, ImClass> classMap = new HashMap<>();
429+
// Only include "relevant" classes: new-generic or subclass of new-generic.
430+
Map<String, ImClass> relevantClassMap = buildRelevantClassMap();
431+
432+
for (ImVar global : prog.getGlobals()) {
433+
ImClass owner = resolveOwningClassFromTrace(global, relevantClassMap);
434+
if (owner == null) {
435+
continue; // not defined inside a class (package/global constant, etc.)
436+
}
437+
438+
// This global belongs to a relevant (new-generic or inheriting) class:
439+
globalToClass.put(global, owner);
440+
WLogger.trace("Identified generic static-field global: " + global.getName()
441+
+ " of type " + global.getType()
442+
+ " belonging to class " + owner.getName());
443+
}
444+
}
445+
446+
/**
447+
* Build a map of class-name -> ImClass, but only for "relevant" classes:
448+
* - the class is new-generic (has typeVariables)
449+
* - OR any of its superclasses is new-generic (transitively)
450+
*/
451+
private Map<String, ImClass> buildRelevantClassMap() {
452+
Map<String, ImClass> m = new HashMap<>();
453+
IdentityHashMap<ImClass, Boolean> memo = new IdentityHashMap<>();
454+
404455
for (ImClass c : prog.getClasses()) {
405-
classMap.put(c.getName(), c);
456+
if (isNewGenericOrExtendsNewGeneric(c, memo)) {
457+
m.put(c.getName(), c);
458+
}
406459
}
460+
return m;
461+
}
407462

408-
// Check each global variable to see if it belongs to a generic class
409-
for (ImVar global : prog.getGlobals()) {
410-
// Global variable names for static fields follow the pattern: ClassName_fieldName
411-
String varName = global.getName();
412-
int underscoreIdx = varName.indexOf('_');
413-
if (underscoreIdx > 0) {
414-
String potentialClassName = varName.substring(0, underscoreIdx);
415-
ImClass owningClass = classMap.get(potentialClassName);
416-
417-
if (owningClass != null && !owningClass.getTypeVariables().isEmpty()) {
418-
// This global belongs to a generic class
419-
globalToClass.put(global, owningClass);
420-
WLogger.trace("Identified generic global: " + varName + " of type " + global.getType() +
421-
" belonging to class " + owningClass.getName());
463+
private boolean isNewGenericOrExtendsNewGeneric(ImClass c, IdentityHashMap<ImClass, Boolean> memo) {
464+
Boolean cached = memo.get(c);
465+
if (cached != null) return cached;
466+
467+
boolean res = !c.getTypeVariables().isEmpty();
468+
if (!res) {
469+
for (ImClassType sc : c.getSuperClasses()) {
470+
ImClass sup = sc.getClassDef();
471+
if (sup != null && isNewGenericOrExtendsNewGeneric(sup, memo)) {
472+
res = true;
473+
break;
422474
}
423475
}
424476
}
477+
478+
memo.put(c, res);
479+
return res;
480+
}
481+
482+
/**
483+
* Resolve owning class for a global via trace:
484+
* - if the global's trace source is inside a class, return the matching ImClass (if relevant)
485+
* - otherwise return null
486+
*/
487+
private @Nullable ImClass resolveOwningClassFromTrace(ImVar global, Map<String, ImClass> relevantClassMap) {
488+
if (global.getTrace() == null) return null;
489+
490+
// This is the only assumption you may need to adapt if your ImTrace API differs:
491+
de.peeeq.wurstscript.ast.Element srcObj = global.getTrace(); // expected to be a wurst AST Element
492+
if (srcObj == null) return null;
493+
494+
@Nullable ClassDef classDef = srcObj.attrNearestClassDef();
495+
if (classDef == null) return null;
496+
497+
// Get the class name from the AST (no global-name parsing).
498+
String className = classDef.getNameId().getName();
499+
500+
// Only accept if it is one of the relevant classes (new-generic or inherits new-generic).
501+
return relevantClassMap.get(className);
425502
}
426503

427504
/**

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package tests.wurstscript.tests;
22

3+
import com.google.common.base.Charsets;
4+
import com.google.common.io.Files;
35
import org.testng.annotations.Ignore;
46
import org.testng.annotations.Test;
57

68
import java.io.File;
79
import java.io.IOException;
810

11+
import static org.testng.Assert.assertEquals;
12+
import static org.testng.Assert.assertFalse;
913
import static tests.wurstscript.tests.BugTests.TEST_DIR;
1014

1115
public class GenericsWithTypeclassesTests extends WurstScriptTest {
@@ -2021,6 +2025,24 @@ public void genericClassWithStaticMemberArray() {
20212025
@Test
20222026
public void fullArrayListTest() throws IOException {
20232027
test().withStdLib().executeProg().executeTests().file(new File(TEST_DIR + "arrayList.wurst"));
2028+
2029+
String compiled = Files.toString(new File("test-output/im 2_genericsEliminated.im"), Charsets.UTF_8);
2030+
// Count 2 occurences of integer ArrayList_MAX_ARRAY_SIZE
2031+
String target = "integer ArrayList_MAX_ARRAY_SIZE";
2032+
int count = 0;
2033+
int idx = 0;
2034+
while ((idx = compiled.indexOf(target, idx)) != -1) {
2035+
count++;
2036+
idx += target.length();
2037+
}
2038+
2039+
assertEquals(count, 2);
2040+
2041+
String compiled2 = Files.toString(new File("test-output/im 5_afterinline.im"), Charsets.UTF_8);
2042+
2043+
assertFalse(compiled2.contains("ArrayList_nextFreeIndex_"));
2044+
2045+
20242046
}
20252047

20262048
@Test

0 commit comments

Comments
 (0)