Skip to content

Commit 899a2c3

Browse files
committed
add arraylist test suite
1 parent 7f2107d commit 899a2c3

3 files changed

Lines changed: 811 additions & 44 deletions

File tree

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

Lines changed: 90 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,50 @@ private String checkDanglingMethodRefs(String phase) {
152152
final int[] dangling = {0};
153153

154154
prog.accept(new Element.DefaultVisitor() {
155-
@Override public void visit(ImMethodCall mc) {
155+
@Override
156+
public void visit(ImMethodCall mc) {
157+
super.visit(mc);
158+
156159
ImMethod m = mc.getMethod();
157-
if (m != null && !inProg.containsKey(m)) {
158-
dangling[0]++;
159-
dbg("DANGLING methodCall: method=" + m.getName() + " " + id(m)
160+
if (m == null) return;
161+
162+
boolean methodIsGeneric = m.getImplementation() != null && !m.getImplementation().getTypeVariables().isEmpty();
163+
164+
// If method is generic but call carries no type args, try to infer from receiver type and patch them in.
165+
if (methodIsGeneric && mc.getTypeArguments().isEmpty()) {
166+
ImClass owning = m.attrClass();
167+
ImType rt = mc.getReceiver().attrTyp();
168+
if (owning != null && rt instanceof ImClassType) {
169+
ImClassType adapted = adaptToSuperclass((ImClassType) rt, owning);
170+
if (adapted != null && !adapted.getTypeArguments().isEmpty()) {
171+
List<ImTypeArgument> copied = new ArrayList<>(adapted.getTypeArguments().size());
172+
for (ImTypeArgument ta : adapted.getTypeArguments()) copied.add(ta.copy());
173+
mc.getTypeArguments().addAll(0, copied);
174+
175+
dbg("Backfilled missing methodCall typeArgs: method=" + m.getName() + " " + id(m)
176+
+ " owning=" + owning.getName()
177+
+ " recvType=" + rt
178+
+ " inferredTA=" + shortTypeArgs(mc.getTypeArguments()));
179+
} else {
180+
dbg("MISSING methodCall typeArgs (cannot infer): method=" + m.getName() + " " + id(m)
181+
+ " owning=" + (owning == null ? "null" : owning.getName())
182+
+ " recvType=" + rt);
183+
}
184+
} else {
185+
dbg("MISSING methodCall typeArgs (no owning/receiverClassType): method=" + m.getName() + " " + id(m)
186+
+ " owning=" + (owning == null ? "null" : owning.getName())
187+
+ " recvType=" + shortType(rt));
188+
}
189+
}
190+
191+
if (!mc.getTypeArguments().isEmpty()) {
192+
dbg("COLLECT GenericMethodCall: method=" + m.getName() + " " + id(m)
160193
+ " impl=" + (m.getImplementation() == null ? "null" : (m.getImplementation().getName() + " " + id(m.getImplementation())))
161194
+ " owningClass=" + (m.attrClass() == null ? "null" : (m.attrClass().getName() + " " + id(m.attrClass())))
162-
+ " receiverType=" + shortType(mc.getReceiver().attrTyp())
163-
+ " callTypeArgs=" + shortTypeArgs(mc.getTypeArguments()));
195+
+ " recvType=" + shortType(mc.getReceiver().attrTyp())
196+
+ " callTA=" + shortTypeArgs(mc.getTypeArguments()));
197+
genericsUses.add(new GenericMethodCall(mc));
164198
}
165-
super.visit(mc);
166199
}
167200
});
168201

@@ -503,10 +536,10 @@ private ImFunction specializeFunction(ImFunction f, GenericTypes generics) {
503536
*/
504537
private ImMethod specializeMethod(ImMethod m, GenericTypes generics) {
505538

506-
dbg("specializeMethod ENTER: " + m.getName() + " " + id(m)
507-
+ " impl=" + (m.getImplementation() == null ? "null" : (m.getImplementation().getName() + " " + id(m.getImplementation())))
508-
+ " methodClass=" + m.getMethodClass()
509-
+ " generics=" + generics);
539+
// dbg("specializeMethod ENTER: " + m.getName() + " " + id(m)
540+
// + " impl=" + (m.getImplementation() == null ? "null" : (m.getImplementation().getName() + " " + id(m.getImplementation())))
541+
// + " methodClass=" + m.getMethodClass()
542+
// + " generics=" + generics);
510543

511544
ImMethod specialized = specializedMethods.get(m, generics);
512545
if (specialized != null) {
@@ -836,11 +869,11 @@ public void visit(ImFunctionCall f) {
836869
public void visit(ImMethodCall mc) {
837870
super.visit(mc);
838871
if (!mc.getTypeArguments().isEmpty()) {
839-
dbg("COLLECT GenericMethodCall: method=" + mc.getMethod().getName() + " " + id(mc.getMethod())
840-
+ " impl=" + (mc.getMethod().getImplementation() == null ? "null" : (mc.getMethod().getImplementation().getName() + " " + id(mc.getMethod().getImplementation())))
841-
+ " owningClass=" + (mc.getMethod().attrClass() == null ? "null" : (mc.getMethod().attrClass().getName() + " " + id(mc.getMethod().attrClass())))
842-
+ " recvType=" + shortType(mc.getReceiver().attrTyp())
843-
+ " callTA=" + shortTypeArgs(mc.getTypeArguments()));
872+
// dbg("COLLECT GenericMethodCall: method=" + mc.getMethod().getName() + " " + id(mc.getMethod())
873+
// + " impl=" + (mc.getMethod().getImplementation() == null ? "null" : (mc.getMethod().getImplementation().getName() + " " + id(mc.getMethod().getImplementation())))
874+
// + " owningClass=" + (mc.getMethod().attrClass() == null ? "null" : (mc.getMethod().attrClass().getName() + " " + id(mc.getMethod().attrClass())))
875+
// + " recvType=" + shortType(mc.getReceiver().attrTyp())
876+
// + " callTA=" + shortTypeArgs(mc.getTypeArguments()));
844877
genericsUses.add(new GenericMethodCall(mc));
845878
}
846879
}
@@ -1114,17 +1147,17 @@ public void eliminate() {
11141147
ImMethod f = mc.getMethod();
11151148
GenericTypes generics = new GenericTypes(specializeTypeArgs(mc.getTypeArguments()));
11161149

1117-
dbg("ELIM GenericMethodCall: method=" + f.getName() + " " + id(f)
1118-
+ " impl=" + (f.getImplementation() == null ? "null" : (f.getImplementation().getName() + " " + id(f.getImplementation())))
1119-
+ " owningClass=" + (f.attrClass() == null ? "null" : (f.attrClass().getName() + " " + id(f.attrClass())))
1120-
+ " callTA=" + shortTypeArgs(mc.getTypeArguments())
1121-
+ " concrete=" + generics);
1150+
// dbg("ELIM GenericMethodCall: method=" + f.getName() + " " + id(f)
1151+
// + " impl=" + (f.getImplementation() == null ? "null" : (f.getImplementation().getName() + " " + id(f.getImplementation())))
1152+
// + " owningClass=" + (f.attrClass() == null ? "null" : (f.attrClass().getName() + " " + id(f.attrClass())))
1153+
// + " callTA=" + shortTypeArgs(mc.getTypeArguments())
1154+
// + " concrete=" + generics);
11221155

11231156
ImMethod specializedMethod = specializeMethod(f, generics);
11241157

1125-
dbg("ELIM -> specializedMethod=" + specializedMethod.getName() + " " + id(specializedMethod)
1126-
+ " impl=" + (specializedMethod.getImplementation() == null ? "null" : (specializedMethod.getImplementation().getName() + " " + id(specializedMethod.getImplementation())))
1127-
+ " methodClass=" + specializedMethod.getMethodClass());
1158+
// dbg("ELIM -> specializedMethod=" + specializedMethod.getName() + " " + id(specializedMethod)
1159+
// + " impl=" + (specializedMethod.getImplementation() == null ? "null" : (specializedMethod.getImplementation().getName() + " " + id(specializedMethod.getImplementation())))
1160+
// + " methodClass=" + specializedMethod.getMethodClass());
11281161

11291162
mc.setMethod(specializedMethod);
11301163
mc.getTypeArguments().removeAll();
@@ -1169,6 +1202,9 @@ public void eliminate() {
11691202
}
11701203

11711204
private ImVar ensureSpecializedGlobal(ImVar originalGlobal, ImClass owningClass, GenericTypes concreteGenerics) {
1205+
concreteGenerics = normalizeToClassArity(concreteGenerics, owningClass, "ensureSpecializedGlobal:" + originalGlobal.getName());
1206+
if (concreteGenerics == null) return null;
1207+
11721208
String key = gKey(concreteGenerics);
11731209
ImVar sg = specializedGlobals.get(originalGlobal, key);
11741210
if (sg != null) return sg;
@@ -1229,6 +1265,29 @@ class GenericGlobalArrayAccess implements GenericUse {
12291265
}
12301266
}
12311267

1268+
private @Nullable GenericTypes normalizeToClassArity(GenericTypes g, ImClass owningClass, String why) {
1269+
int need = owningClass.getTypeVariables().size();
1270+
int have = g.getTypeArguments().size();
1271+
1272+
if (have == need) return g;
1273+
1274+
if (have < need) {
1275+
dbg("GEN-ARITY FAIL (" + why + "): class=" + owningClass.getName()
1276+
+ " need=" + need + " have=" + have + " g=" + g);
1277+
return null;
1278+
}
1279+
1280+
// have > need: take the prefix; this is the common case when the function-context has extra type args.
1281+
List<ImTypeArgument> cut = new ArrayList<>(need);
1282+
for (int i = 0; i < need; i++) {
1283+
cut.add(g.getTypeArguments().get(i).copy());
1284+
}
1285+
GenericTypes r = new GenericTypes(cut);
1286+
dbg("GEN-ARITY TRUNC (" + why + "): class=" + owningClass.getName()
1287+
+ " need=" + need + " have=" + have + " g=" + g + " -> " + r);
1288+
return r;
1289+
}
1290+
12321291
/**
12331292
* NEW: Infer generic types from the enclosing function context
12341293
* For specialized functions, the name contains the type information
@@ -1241,18 +1300,15 @@ private GenericTypes inferGenericsFromFunction(Element element, ImClass owningCl
12411300

12421301
GenericTypes specialized = specializedFunctionGenerics.get(func);
12431302
if (specialized != null) {
1244-
return specialized;
1303+
return normalizeToClassArity(specialized, owningClass, "specializedFunctionGenerics:" + func.getName());
12451304
}
12461305

1247-
// If function is still generic, we can't decide yet.
12481306
if (!func.getTypeVariables().isEmpty()) {
12491307
return null;
12501308
}
12511309

12521310
if (!func.getParameters().isEmpty()) {
1253-
ImVar receiver = func.getParameters().get(0);
1254-
ImType rt = receiver.getType();
1255-
1311+
ImType rt = func.getParameters().get(0).getType();
12561312
if (rt instanceof ImClassType) {
12571313
ImClassType ct = (ImClassType) rt;
12581314
ImClass raw = ct.getClassDef();
@@ -1263,27 +1319,26 @@ private GenericTypes inferGenericsFromFunction(Element element, ImClass owningCl
12631319
raw.isSubclassOf(owningClass);
12641320

12651321
if (matches) {
1266-
// PRIMARY: use actual type args if present
12671322
if (!ct.getTypeArguments().isEmpty()) {
12681323
List<ImTypeArgument> copied = new ArrayList<>(ct.getTypeArguments().size());
12691324
for (ImTypeArgument ta : ct.getTypeArguments()) {
12701325
copied.add(JassIm.ImTypeArgument(ta.getType().copy(), ta.getTypeClassBinding()));
12711326
}
1272-
return new GenericTypes(copied);
1327+
return normalizeToClassArity(new GenericTypes(copied), owningClass, "receiverTypeArgs:" + func.getName());
12731328
}
12741329

1275-
// FALLBACK: parse from specialized class name: Box⟪...⟫
12761330
GenericTypes fromName = extractGenericsFromClassName(raw.getName());
12771331
if (fromName != null && !fromName.getTypeArguments().isEmpty()) {
1278-
return fromName;
1332+
return normalizeToClassArity(fromName, owningClass, "className:" + raw.getName());
12791333
}
12801334
}
12811335
}
12821336
}
12831337

12841338
Map<GenericTypes, ImClass> specs = specializedClasses.row(owningClass);
12851339
if (specs.size() == 1) {
1286-
return specs.keySet().iterator().next();
1340+
GenericTypes only = specs.keySet().iterator().next();
1341+
return normalizeToClassArity(only, owningClass, "singleSpecializationFallback");
12871342
}
12881343

12891344
return null;
@@ -1294,6 +1349,7 @@ private GenericTypes inferGenericsFromFunction(Element element, ImClass owningCl
12941349
}
12951350

12961351

1352+
12971353
/**
12981354
* NEW: Extract generic types from a specialized class name like "Box⟪integer⟫"
12991355
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2020,7 +2020,7 @@ public void genericClassWithStaticMemberArray() {
20202020

20212021
@Test
20222022
public void fullArrayListTest() throws IOException {
2023-
testAssertOkFileWithStdLib(new File(TEST_DIR + "arrayList.wurst"), true);
2023+
test().withStdLib().executeProg().executeTests().file(new File(TEST_DIR + "arrayList.wurst"));
20242024
}
20252025

20262026
@Test

0 commit comments

Comments
 (0)