@@ -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 */
0 commit comments