1414import de .peeeq .wurstscript .translation .imtojass .ImAttrType ;
1515import de .peeeq .wurstscript .translation .imtojass .TypeRewriteMatcher ;
1616import de .peeeq .wurstscript .translation .lua .translation .RemoveGarbage ;
17+ import de .peeeq .wurstscript .types .TypesHelper ;
1718import io .vavr .control .Either ;
1819import org .eclipse .jdt .annotation .Nullable ;
1920import org .jetbrains .annotations .NotNull ;
@@ -29,6 +30,7 @@ public class EliminateGenerics {
2930 private final ImTranslator translator ;
3031 private final ImProg prog ;
3132 private boolean genericNewOnly ;
33+ private boolean specializeTupleValueTypes ;
3234 private final Deque <GenericUse > genericsUses = new ArrayDeque <>();
3335 /**
3436 * Call sites already rewritten to a specialisation.
@@ -112,12 +114,21 @@ public void transform() {
112114 }
113115
114116 /**
115- * Lua normally erases new generics. Generic construction is the one operation which needs the
116- * concrete type, so only specialize functions on paths leading to {@code wurstNewInstance}. All other
117- * generic calls and classes keep the Lua backend's normal erased representation.
117+ * Lua normally erases generics. Generic construction and scalar storage for tuple type arguments
118+ * are the operations which need the concrete type, so only specialize paths leading to those
119+ * operations. All other generic calls and classes keep the Lua backend's erased representation.
118120 */
119121 public void transformGenericNewOnly () {
122+ transformGenericNewOnly (false );
123+ }
124+
125+ public void transformGenericNewOnly (boolean specializeTupleValueTypes ) {
120126 genericNewOnly = true ;
127+ this .specializeTupleValueTypes = specializeTupleValueTypes ;
128+ if (specializeTupleValueTypes ) {
129+ addMemberTypeArguments ();
130+ identifyGenericGlobals ();
131+ }
121132 collectUnspecializedGenericClassMethods ();
122133 // Specialising a constructor makes its result type concrete, which is what lets a method
123134 // call on that result resolve. Repeat until a pass finds nothing new; collection is
@@ -133,6 +144,14 @@ public void transformGenericNewOnly() {
133144 assertNoReachableGenericNewMarkers ();
134145 bindSpecialisedMethodsToTheAllocatedClass ();
135146 settleRemainingDispatches ();
147+ if (specializeTupleValueTypes ) {
148+ for (Map .Entry <ImFunction , GenericTypes > entry :
149+ new ArrayList <>(specializedFunctionGenerics .entrySet ())) {
150+ if (genericTypesContainTuple (entry .getValue ())) {
151+ rewriteGenericGlobals (entry .getKey (), entry .getValue ());
152+ }
153+ }
154+ }
136155 }
137156
138157 /**
@@ -290,6 +309,26 @@ public void visit(ImMemberAccess memberAccess) {
290309 super .visit (memberAccess );
291310 collectGenericNewUse (memberAccess );
292311 }
312+
313+ @ Override
314+ public void visit (ImVarAccess access ) {
315+ super .visit (access );
316+ if (specializedContextContainsTuple (access )
317+ && globalToClass .containsKey (access .getVar ())) {
318+ recordGenericGlobalUse (access , access .getVar ());
319+ genericsUses .add (new GenericGlobalAccess (access ));
320+ }
321+ }
322+
323+ @ Override
324+ public void visit (ImVarArrayAccess access ) {
325+ super .visit (access );
326+ if (specializedContextContainsTuple (access )
327+ && globalToClass .containsKey (access .getVar ())) {
328+ recordGenericGlobalUse (access , access .getVar ());
329+ genericsUses .add (new GenericGlobalArrayAccess (access ));
330+ }
331+ }
293332 });
294333 }
295334
@@ -304,7 +343,8 @@ private void collectGenericNewUse(ImFunctionCall call) {
304343 return ;
305344 }
306345 if (!call .getTypeArguments ().isEmpty ()
307- && functionNeedsSpecialization (call .getFunc (), Collections .newSetFromMap (new IdentityHashMap <>()))) {
346+ && (shouldSpecializeTupleArguments (call .getTypeArguments ())
347+ || functionNeedsSpecialization (call .getFunc (), Collections .newSetFromMap (new IdentityHashMap <>())))) {
308348 if (!typeArgumentsContainTypeVariable (call .getTypeArguments ())) {
309349 genericsUses .add (new GenericImFunctionCall (call ));
310350 }
@@ -347,8 +387,9 @@ private void collectCallThroughGenericReceiver(ImFunctionCall call) {
347387 || typeArgumentsContainTypeVariable (classType .getTypeArguments ())) {
348388 return ;
349389 }
350- if (!functionNeedsSpecialization (call .getFunc (),
351- Collections .newSetFromMap (new IdentityHashMap <>()))) {
390+ if (!shouldSpecializeTupleArguments (classType .getTypeArguments ())
391+ && !functionNeedsSpecialization (call .getFunc (),
392+ Collections .newSetFromMap (new IdentityHashMap <>()))) {
352393 return ;
353394 }
354395 genericsUses .add (new GenericClassFunctionCall (call , owningClass ,
@@ -393,7 +434,8 @@ private void collectGenericNewUse(ImAlloc alloc) {
393434 ImClassType clazz = alloc .getClazz ();
394435 if (clazz .getTypeArguments ().isEmpty ()
395436 || typeArgumentsContainTypeVariable (clazz .getTypeArguments ())
396- || !isConstructionOnlyInstantiation (clazz .getClassDef ())) {
437+ || (!shouldSpecializeTupleArguments (clazz .getTypeArguments ())
438+ && !isConstructionOnlyInstantiation (clazz .getClassDef ()))) {
397439 return ;
398440 }
399441 genericsUses .add (new GenericClazzUse (alloc ));
@@ -468,7 +510,7 @@ private void collectGenericNewUse(ImMemberAccess memberAccess) {
468510 // A class that has already been specialised has nothing left to select, and asking the
469511 // receiver to adapt to it fails outright: the receiver is still typed by the generic class
470512 // the specialised one was copied from, which is not a superclass of it.
471- if (owningClass .getTypeVariables ().isEmpty () || ! isConstructionOnlyInstantiation ( owningClass ) ) {
513+ if (owningClass .getTypeVariables ().isEmpty ()) {
472514 return ;
473515 }
474516 if (memberAccess .getTypeArguments ().isEmpty ()) {
@@ -479,6 +521,10 @@ private void collectGenericNewUse(ImMemberAccess memberAccess) {
479521 || typeArgumentsContainTypeVariable (memberAccess .getTypeArguments ())) {
480522 return ;
481523 }
524+ if (!shouldSpecializeTupleArguments (memberAccess .getTypeArguments ())
525+ && !isConstructionOnlyInstantiation (owningClass )) {
526+ return ;
527+ }
482528 genericsUses .add (new GenericMemberAccess (memberAccess ));
483529 }
484530
@@ -487,7 +533,8 @@ private void collectGenericNewUse(ImMethodCall call) {
487533 return ;
488534 }
489535 ImMethod method = call .getMethod ();
490- if (!methodNeedsSpecialization (method ,
536+ if (!shouldSpecializeTupleArguments (call .getTypeArguments ())
537+ && !methodNeedsSpecialization (method ,
491538 Collections .newSetFromMap (new IdentityHashMap <>()),
492539 Collections .newSetFromMap (new IdentityHashMap <>()))) {
493540 return ;
@@ -550,6 +597,29 @@ private boolean typeArgumentsContainTypeVariable(ImTypeArguments typeArguments)
550597 return false ;
551598 }
552599
600+ private boolean typeArgumentsContainTuple (Iterable <ImTypeArgument > typeArguments ) {
601+ for (ImTypeArgument typeArgument : typeArguments ) {
602+ if (TypesHelper .typeContainsTuples (typeArgument .getType ())) {
603+ return true ;
604+ }
605+ }
606+ return false ;
607+ }
608+
609+ private boolean shouldSpecializeTupleArguments (ImTypeArguments typeArguments ) {
610+ return specializeTupleValueTypes && typeArgumentsContainTuple (typeArguments );
611+ }
612+
613+ private boolean genericTypesContainTuple (GenericTypes generics ) {
614+ return typeArgumentsContainTuple (generics .getTypeArguments ());
615+ }
616+
617+ private boolean specializedContextContainsTuple (Element element ) {
618+ ImFunction function = enclosingFunction (element );
619+ GenericTypes generics = function == null ? null : specializedFunctionGenerics .get (function );
620+ return specializeTupleValueTypes && generics != null && genericTypesContainTuple (generics );
621+ }
622+
553623 private boolean functionNeedsSpecialization (ImFunction function , Set <ImFunction > visited ) {
554624 return functionNeedsSpecialization (function , visited ,
555625 Collections .newSetFromMap (new IdentityHashMap <>()));
@@ -1307,6 +1377,10 @@ private ImFunction specializeFunction(ImFunction f, GenericTypes generics) {
13071377 rewriteGenerics (newF , generics , typeVars );
13081378 }
13091379
1380+ if (genericNewOnly && specializeTupleValueTypes && genericTypesContainTuple (generics )) {
1381+ rewriteGenericGlobals (newF , generics );
1382+ }
1383+
13101384 // Fix calls inside this specialized function so they also point to specialized callees
13111385 if (genericNewOnly ) {
13121386 collectGenericNewUses (newF );
@@ -1320,6 +1394,36 @@ private ImFunction specializeFunction(ImFunction f, GenericTypes generics) {
13201394 return newF ;
13211395 }
13221396
1397+ private void rewriteGenericGlobals (ImFunction function , GenericTypes generics ) {
1398+ function .accept (new Element .DefaultVisitor () {
1399+ @ Override
1400+ public void visit (ImVarAccess access ) {
1401+ super .visit (access );
1402+ access .setVar (specializedGlobal (access .getVar ()));
1403+ }
1404+
1405+ @ Override
1406+ public void visit (ImVarArrayAccess access ) {
1407+ super .visit (access );
1408+ access .setVar (specializedGlobal (access .getVar ()));
1409+ }
1410+
1411+ private ImVar specializedGlobal (ImVar original ) {
1412+ ImClass owner = globalToClass .get (original );
1413+ if (owner == null ) {
1414+ return original ;
1415+ }
1416+ GenericTypes concrete = normalizeToClassArity (generics , owner ,
1417+ "specialized function " + function .getName ());
1418+ if (concrete == null || concrete .containsTypeVariable ()) {
1419+ return original ;
1420+ }
1421+ ImVar result = ensureSpecializedGlobal (original , owner , concrete );
1422+ return result == null ? original : result ;
1423+ }
1424+ });
1425+ }
1426+
13231427 /**
13241428 * creates a specialized version of this method
13251429 */
@@ -1398,6 +1502,9 @@ private ImFunction specializeClassFunction(ImFunction function, ImClass owningCl
13981502 newImplementation .getTypeVariables ().removeAll ();
13991503 newImplementation .setName (function .getName () + "_specialized" );
14001504 rewriteGenerics (newImplementation , generics , typeVariables );
1505+ if (specializeTupleValueTypes && genericTypesContainTuple (generics )) {
1506+ rewriteGenericGlobals (newImplementation , generics );
1507+ }
14011508 collectGenericNewUses (newImplementation );
14021509 return newImplementation ;
14031510 }
0 commit comments