11package de .peeeq .wurstscript .intermediatelang .interpreter ;
22
3- import com .google .common .base .Objects ;
4- import com .google .common .collect .ImmutableList ;
53import com .google .common .collect .Lists ;
64import de .peeeq .wurstio .jassinterpreter .InterpreterException ;
75import de .peeeq .wurstscript .ast .Element ;
108import de .peeeq .wurstscript .intermediatelang .*;
119import de .peeeq .wurstscript .jassIm .*;
1210import de .peeeq .wurstscript .parser .WPos ;
13- import de .peeeq .wurstscript .translation .imtranslation . ImPrinter ;
11+ import de .peeeq .wurstscript .translation .imtojass . ImAttrType ;
1412import de .peeeq .wurstscript .utils .LineOffsets ;
1513import de .peeeq .wurstscript .utils .Utils ;
1614import it .unimi .dsi .fastutil .ints .Int2ObjectOpenHashMap ;
@@ -35,11 +33,40 @@ public class ProgramState extends State {
3533 private final Deque <de .peeeq .wurstscript .jassIm .Element > lastStatements = new ArrayDeque <>();
3634 private final boolean isCompiletime ;
3735
36+ private final Map <ImVar , ImClass > genericStaticOwner = new HashMap <>();
37+
38+ private final Object2ObjectOpenHashMap <String , ILconst > genericStaticVals = new Object2ObjectOpenHashMap <>();
39+ private final Object2ObjectOpenHashMap <String , ILconstArray > genericStaticArrays = new Object2ObjectOpenHashMap <>();
40+
3841
3942 public ProgramState (WurstGui gui , ImProg prog , boolean isCompiletime ) {
4043 this .gui = gui ;
4144 this .prog = prog ;
4245 this .isCompiletime = isCompiletime ;
46+
47+ identifyGenericStaticGlobals ();
48+ }
49+
50+ private void identifyGenericStaticGlobals () {
51+ Map <String , ImClass > classMap = new HashMap <>();
52+ for (ImClass c : prog .getClasses ()) {
53+ classMap .put (c .getName (), c );
54+ }
55+
56+ for (ImVar global : prog .getGlobals ()) {
57+ String n = global .getName ();
58+ int underscore = n .indexOf ('_' );
59+ if (underscore <= 0 ) continue ;
60+
61+ String className = n .substring (0 , underscore );
62+ ImClass owner = classMap .get (className );
63+ if (owner == null ) continue ;
64+
65+ // Only generic classes need per-instantiation statics:
66+ if (owner .getTypeVariables ().isEmpty ()) continue ;
67+
68+ genericStaticOwner .put (global , owner );
69+ }
4370 }
4471
4572 public void setLastStatement (ImStmt s ) {
@@ -162,9 +189,51 @@ public void pushStackframeWithTypes(ImFunction f, @Nullable ILconstObject receiv
162189 lastStatements .push (stmt );
163190 }
164191
192+ private @ Nullable String genericStaticKey (ImVar v ) {
193+ ImClass owner = genericStaticOwner .get (v );
194+ if (owner == null ) return null ;
195+
196+ ImClassType inst = currentReceiverInstantiationFor (owner );
197+ if (inst == null ) {
198+ // Happens if accessed without a receiver context (static-only code path).
199+ // You can refine later; for now keep a stable bucket.
200+ return v .getName () + "|<no-receiver>" ;
201+ }
202+ return v .getName () + "|" + instantiationKey (inst );
203+ }
204+
205+ private @ Nullable ImClassType currentReceiverInstantiationFor (ImClass owner ) {
206+ ILStackFrame top = stackFrames .peek ();
207+ if (top == null || top .receiver == null ) return null ;
208+
209+ ImClassType rt = top .receiver .getType ();
210+ // resolve possible type vars inside type args
211+ ImType resolved = resolveType (rt );
212+ if (resolved instanceof ImClassType ) {
213+ rt = (ImClassType ) resolved ;
214+ }
215+
216+ ImClassType adapted = adaptToSuperclass (rt , owner );
217+ return adapted != null ? adapted : rt ;
218+ }
219+
220+ private @ Nullable ImClassType adaptToSuperclass (ImClassType ct , ImClass owner ) {
221+ if (ct .getClassDef () == owner ) return ct ;
165222
166- // NEW: Resolve a generic type using current stack frame's type substitutions
167- // Replace both resolveType(...) and substituteTypeVars(...) with this:
223+ // Walk super types, substituting this ct's type args into the superclass types
224+ List <ImTypeVar > tvs = ct .getClassDef ().getTypeVariables ();
225+ ImTypeArguments tas = ct .getTypeArguments ();
226+
227+ for (ImClassType scRaw : ct .getClassDef ().getSuperClasses ()) {
228+ ImType scSubst = ImAttrType .substituteType (scRaw , tas , tvs );
229+ scSubst = resolveType (scSubst );
230+ if (scSubst instanceof ImClassType ) {
231+ ImClassType r = adaptToSuperclass ((ImClassType ) scSubst , owner );
232+ if (r != null ) return r ;
233+ }
234+ }
235+ return null ;
236+ }
168237
169238 public ImType resolveType (ImType t ) {
170239 return resolveTypeDeep (t , 32 ); // small budget to avoid cycles
@@ -404,9 +473,6 @@ public ILStackFrame next() {
404473 }
405474 }
406475
407- private final Object2ObjectOpenHashMap <String , ILconst > genericStaticVals = new Object2ObjectOpenHashMap <>();
408-
409-
410476 public String instantiationKey (ImClassType ct ) {
411477 StringBuilder sb = new StringBuilder ();
412478 sb .append (ct .getClassDef ().getName ());
@@ -425,33 +491,32 @@ public String instantiationKey(ImClassType ct) {
425491
426492 @ Override
427493 public void setVal (ImVar v , ILconst val ) {
428- if (v .isGlobal () && v .getType () instanceof ImTypeVarRef ) {
429- ILStackFrame top = stackFrames .peek ();
430- if (top != null && top .receiver != null ) {
431- ImTypeArguments tas = top .receiver .getType ().getTypeArguments ();
432- ImType resolved = resolveType (tas .get (0 ).getType ()); // <<< resolve
433- String s = v .getName () + resolved ;
434- genericStaticVals .put (s , val );
435- return ;
436- }
494+ String key = genericStaticKey (v );
495+ if (key != null ) {
496+ genericStaticVals .put (key , val );
497+ return ;
437498 }
438499 super .setVal (v , val );
439500 }
440501
502+ @ Override
441503 public @ Nullable ILconst getVal (ImVar v ) {
442- if (v .isGlobal () && v .getType () instanceof ImTypeVarRef ) {
443- System .out .println ("looking for generic static var " + v );
444- ILStackFrame top = stackFrames .peek ();
445- if (top != null && top .receiver != null ) {
446- ImTypeArguments tas = top .receiver .getType ().getTypeArguments ();
447- ImType resolved = resolveType (tas .get (0 ).getType ()); // <<< resolve
448- String s = v .getName () + resolved ;
449- return genericStaticVals .get (s );
504+ String key = genericStaticKey (v );
505+ if (key != null ) {
506+ ILconst existing = genericStaticVals .get (key );
507+ if (existing != null ) return existing ;
508+
509+ // Initialize from the normal global init machinery once, then copy into this instantiation bucket:
510+ ILconst init = super .getVal (v );
511+ if (init != null ) {
512+ genericStaticVals .put (key , init );
450513 }
514+ return init ;
451515 }
452516 return super .getVal (v );
453517 }
454518
519+
455520 public boolean isCompiletime () {
456521 return isCompiletime ;
457522 }
@@ -461,17 +526,35 @@ public boolean isCompiletime() {
461526
462527 @ Override
463528 protected ILconstArray getArray (ImVar v ) {
529+ String key = genericStaticKey (v );
530+ if (key != null ) {
531+ ILconstArray arr = genericStaticArrays .get (key );
532+ if (arr != null ) return arr ;
533+
534+ ILconstArray r = createArrayConstantFromType (v .getType ());
535+ genericStaticArrays .put (key , r );
536+
537+ List <ImSet > inits = prog .getGlobalInits ().get (v );
538+ if (inits != null && !inits .isEmpty ()) {
539+ final LocalState ls = EMPTY_LOCAL_STATE ;
540+ for (int i = 0 ; i < inits .size (); i ++) {
541+ ILconst val = inits .get (i ).getRight ().evaluate (this , ls );
542+ r .set (i , val );
543+ }
544+ }
545+ return r ;
546+ }
547+
548+ // non-generic case = your existing logic
464549 Object2ObjectOpenHashMap <ImVar , ILconstArray > arrayValues = ensureArrayValues ();
465550 ILconstArray r = arrayValues .get (v );
466551 if (r != null ) return r ;
467552
468553 r = createArrayConstantFromType (v .getType ());
469554 arrayValues .put (v , r );
470555
471- // Initialize from globalInits only once
472556 List <ImSet > inits = prog .getGlobalInits ().get (v );
473557 if (inits != null && !inits .isEmpty ()) {
474- // evaluate with a reusable local state to avoid per-init allocations
475558 final LocalState ls = EMPTY_LOCAL_STATE ;
476559 for (int i = 0 ; i < inits .size (); i ++) {
477560 ILconst val = inits .get (i ).getRight ().evaluate (this , ls );
0 commit comments