Skip to content

Commit d3d5327

Browse files
committed
maybe working version?
1 parent 9fd68e1 commit d3d5327

24 files changed

Lines changed: 1147 additions & 292 deletions

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFunctionSignature.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package de.peeeq.wurstscript.attributes;
22

3+
import de.peeeq.wurstscript.WLogger;
34
import de.peeeq.wurstscript.ast.*;
45
import de.peeeq.wurstscript.types.FunctionSignature;
56
import de.peeeq.wurstscript.types.VariableBinding;
@@ -17,7 +18,23 @@ public class AttrFunctionSignature {
1718

1819
public static FunctionSignature calculate(StmtCall fc) {
1920
Collection<FunctionSignature> sigs = fc.attrPossibleFunctionSignatures();
20-
FunctionSignature sig = filterSigs(sigs, argTypes(fc), fc);
21+
List<WurstType> at = argTypes(fc);
22+
23+
FunctionSignature sig = filterSigs(sigs, at, fc);
24+
25+
// ---- DEBUG: what did we pick, and what did we bind? ----
26+
if (fc instanceof FunctionCall) {
27+
WLogger.trace("[IMPLCONV] call=" + name(fc) + " args=" + at);
28+
// WLogger.trace("[IMPLCONV] pickedSig=" + sig);
29+
WLogger.trace("[IMPLCONV] mapping=" + sig.getMapping()
30+
+ " unbound=" + sig.getMapping().printUnboundTypeVars());
31+
if (fc instanceof ExprMemberMethodDot emmd) {
32+
WLogger.trace("[IMPLCONV] receiver=" + emmd.getLeft().attrTyp()
33+
+ " raw=" + emmd.getLeft().attrTypRaw()
34+
+ " member=" + emmd.getFuncName());
35+
}
36+
}
37+
// --------------------------------------------------------
2138

2239
VariableBinding mapping = sig.getMapping();
2340
for (CompileError error : mapping.getErrors()) {
@@ -48,6 +65,12 @@ private static FunctionSignature filterSigs(
4865
List<WurstType> argTypes, StmtCall location) {
4966
if (sigs.isEmpty()) {
5067
if (!isInitTrigFunc(location)) {
68+
if (location instanceof ExprMemberMethodDot) {
69+
ExprMemberMethodDot emmd = (ExprMemberMethodDot) location;
70+
WLogger.trace("[IMPLCONV] receiver typRaw=" + emmd.getLeft().attrTypRaw()
71+
+ " typ=" + emmd.getLeft().attrTyp()
72+
+ " for call ." + emmd.getFuncName());
73+
}
5174
location.addError("Could not find " + name(location) + ".");
5275
}
5376
return FunctionSignature.empty;
@@ -119,12 +142,21 @@ private static List<FunctionSignature> filterPreferNonAbstract(List<FunctionSign
119142
}
120143

121144
@NotNull
122-
private static List<FunctionSignature> filterByArgumentTypes(Collection<FunctionSignature> sigs, List<WurstType> argTypes, StmtCall location) {
145+
private static List<FunctionSignature> filterByArgumentTypes(
146+
Collection<FunctionSignature> sigs, List<WurstType> argTypes, StmtCall location) {
147+
123148
List<FunctionSignature> candidates = new ArrayList<>();
124149
for (FunctionSignature sig : sigs) {
125-
sig = sig.matchAgainstArgs(argTypes, location);
126-
if (sig != null) {
127-
candidates.add(sig);
150+
WLogger.trace("[IMPLCONV] trySig=" + sig + " argTypes=" + argTypes);
151+
152+
FunctionSignature matched = sig.matchAgainstArgs(argTypes, location);
153+
154+
if (matched != null) {
155+
WLogger.trace("[IMPLCONV] -> matched, mapping=" + matched.getMapping()
156+
+ " unbound=" + matched.getMapping().printUnboundTypeVars());
157+
candidates.add(matched);
158+
} else {
159+
WLogger.trace("[IMPLCONV] -> no match");
128160
}
129161
}
130162
return candidates;

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrPossibleFunctionSignatures.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.ImmutableCollection;
44
import com.google.common.collect.ImmutableList;
55
import com.google.common.collect.Lists;
6+
import de.peeeq.wurstscript.WLogger;
67
import de.peeeq.wurstscript.ast.*;
78
import de.peeeq.wurstscript.attributes.names.FuncLink;
89
import de.peeeq.wurstscript.attributes.names.NameResolution;
@@ -139,6 +140,19 @@ public static ImmutableCollection<FunctionSignature> calculate(ExprMemberMethod
139140
final ImmutableCollection<FuncLink> raw =
140141
mm.lookupMemberFuncs(leftType, name, /*showErrors*/ false);
141142

143+
WLogger.trace("[IMPLCONV] lookupMemberFuncs name=" + name
144+
+ " leftType=" + leftType
145+
+ " leftRaw=" + left.attrTypRaw()
146+
+ " raw.size=" + raw.size());
147+
148+
for (FuncLink f : raw) {
149+
WLogger.trace("[IMPLCONV] rawLink name=" + f.getName()
150+
+ " def=" + f.getDef()
151+
+ " recv=" + f.getReceiverType()
152+
+ " typeParams=" + f.getTypeParams()
153+
+ " binding=" + f.getVariableBinding());
154+
}
155+
142156
if (raw.isEmpty()) {
143157
// Let downstream handle "not found"
144158
return ImmutableList.of();
@@ -174,6 +188,10 @@ public static ImmutableCollection<FunctionSignature> calculate(ExprMemberMethod
174188
for (FuncLink f : visible) {
175189
FunctionSignature sig = FunctionSignature.fromNameLink(f);
176190

191+
WLogger.trace("[IMPLCONV] fromNameLink -> sig=" + sig
192+
+ " sig.recv=" + sig.getReceiverType()
193+
+ " sig.map=" + sig.getMapping());
194+
177195
// Bind type variables using the actual receiver
178196
WurstType recv = sig.getReceiverType();
179197
if (recv != null) {
@@ -184,7 +202,22 @@ public static ImmutableCollection<FunctionSignature> calculate(ExprMemberMethod
184202
// For members injected via `use module`, the receiver can be a synthetic/module `thistype`
185203
// that is not directly comparable here (especially during incremental builds).
186204
// Do NOT drop the candidate if binding fails; keep it and let arg matching rank it later.
187-
if (m != null) {
205+
if (m == null) {
206+
// Keep only if this is the "synthetic receiver" situation (use-module / thistype).
207+
// Otherwise it's almost certainly a stale specialized FuncLink (exactly what your log shows).
208+
String rs = String.valueOf(recv);
209+
boolean synthetic = rs.contains("thistype") || rs.contains("module"); // refine later if you have a proper predicate
210+
if (!synthetic) {
211+
WLogger.trace("[IMPLCONV] drop candidate: receiver mismatch left=" + leftType + " recv=" + recv
212+
+ " def=" + f.getDef() + " linkBinding=" + f.getVariableBinding());
213+
WLogger.trace("[IMPLCONV] receiver mismatch: leftType=" + leftType
214+
+ " recv=" + recv
215+
+ " func=" + f.getName()
216+
+ " def=" + f.getDef()
217+
+ " linkBinding=" + f.getVariableBinding());
218+
continue;
219+
}
220+
} else {
188221
sig = sig.setTypeArgs(mm, m);
189222
}
190223
}

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/names/DefLink.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,10 @@ protected static Stream<TypeParamDef> typeParams(Element scope) {
5252
return Stream.of();
5353
}
5454

55-
56-
57-
5855
public @Nullable WurstType getReceiverType() {
5956
return receiverType;
6057
}
6158

62-
6359
public DefLink hidingPrivate() {
6460
return (DefLink) super.hidingPrivate();
6561
}
@@ -84,21 +80,15 @@ public boolean receiverCompatibleWith(WurstType receiverType, Element location)
8480
*/
8581
public @Nullable DefLink adaptToReceiverType(WurstType receiverType) {
8682
if (this.receiverType == null) {
87-
if (receiverType == null) {
88-
return this;
89-
} else {
90-
return null;
91-
}
83+
return receiverType == null ? this : null;
9284
}
9385
NameDef def = getDef();
94-
VariableBinding match = this.receiverType.matchAgainstSupertype(receiverType, def, VariableBinding.emptyMapping().withTypeVariables(typeParams), VariablePosition.LEFT);
95-
if (match == null) {
96-
return null;
97-
}
86+
VariableBinding seed = VariableBinding.emptyMapping().withTypeVariables(typeParams);
87+
VariableBinding match = receiverType.matchAgainstSupertype(this.receiverType, def, seed, VariablePosition.RIGHT);
88+
if (match == null) return null;
9889
return withTypeArgBinding(def, match);
9990
}
10091

101-
10292
@Override
10393
public abstract DefLink withTypeArgBinding(Element context, VariableBinding binding);
10494

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/names/FuncLink.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,51 @@ public FuncLink(Visibility visibility, WScope definedIn, List<TypeParamDef> type
3232
}
3333

3434
public static FuncLink create(FunctionDefinition func, WScope definedIn) {
35-
Visibility visibiliy = calcVisibility(definedIn, func);
36-
List<TypeParamDef> typeParams = typeParams(func).collect(Collectors.toList());
37-
List<String> lParameterNames = new ArrayList<>();
38-
for (WParameter wParameter : func.getParameters()) {
39-
String name = wParameter.getName();
40-
lParameterNames.add(name);
35+
Visibility visibility = calcVisibility(definedIn, func);
36+
37+
// Collect all type params visible at this function:
38+
// 1) function's own type params
39+
// 2) enclosing/owning structure type params (class/module/inner class chain)
40+
java.util.ArrayList<TypeParamDef> typeParams = new java.util.ArrayList<>();
41+
typeParams.addAll(typeParams(func).collect(Collectors.toList()));
42+
43+
Element cur = definedIn;
44+
while (cur != null) {
45+
if (cur instanceof AstElementWithTypeParameters) {
46+
typeParams.addAll(((AstElementWithTypeParameters) cur).getTypeParameters());
47+
}
48+
if (cur instanceof WPackage || cur instanceof CompilationUnit) {
49+
break;
50+
}
51+
cur = cur.getParent();
4152
}
42-
List<WurstType> lParameterTypes = new ArrayList<>();
43-
for (WParameter wParameter : func.getParameters()) {
44-
WurstType attrTyp = wParameter.attrTyp();
45-
lParameterTypes.add(attrTyp);
53+
54+
// De-dup by identity (same TypeParamDef object may appear more than once)
55+
java.util.Set<TypeParamDef> seen = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>());
56+
typeParams.removeIf(tp -> !seen.add(tp));
57+
58+
// Parameter names/types
59+
java.util.ArrayList<String> paramNames = new java.util.ArrayList<>();
60+
for (WParameter p : func.getParameters()) {
61+
paramNames.add(p.getName());
4662
}
47-
WurstType lreturnType = func.attrReturnTyp();
48-
WurstType lreceiverType = calcReceiverType(definedIn, func);
49-
VariableBinding mapping = VariableBinding.emptyMapping();
50-
if (func instanceof AstElementWithTypeParameters) {
51-
mapping = mapping.withTypeVariables(((AstElementWithTypeParameters) func).getTypeParameters());
63+
64+
java.util.ArrayList<WurstType> paramTypes = new java.util.ArrayList<>();
65+
for (WParameter p : func.getParameters()) {
66+
paramTypes.add(p.attrTyp());
5267
}
53-
return new FuncLink(visibiliy, definedIn, typeParams, lreceiverType, func, lParameterNames, lParameterTypes, lreturnType, mapping);
68+
69+
WurstType returnType = func.attrReturnTyp();
70+
WurstType receiverType = calcReceiverType(definedIn, func);
71+
72+
// Seed mapping with ALL visible type vars (not just the function's)
73+
VariableBinding mapping = VariableBinding.emptyMapping().withTypeVariables(typeParams);
74+
75+
return new FuncLink(visibility, definedIn, typeParams, receiverType, func, paramNames, paramTypes, returnType, mapping);
5476
}
5577

5678

79+
5780
private static @Nullable WurstType calcReceiverType(WScope definedIn, NameDef nameDef) {
5881
if (nameDef instanceof ExtensionFuncDef) {
5982
ExtensionFuncDef exF = (ExtensionFuncDef) nameDef;

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/names/NameResolution.java

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.ImmutableCollection;
44
import com.google.common.collect.ImmutableList;
5+
import de.peeeq.wurstscript.WLogger;
56
import de.peeeq.wurstscript.ast.*;
67
import de.peeeq.wurstscript.types.*;
78
import de.peeeq.wurstscript.utils.Utils;
@@ -11,6 +12,13 @@
1112
import java.util.*;
1213

1314
public class NameResolution {
15+
private static String memberFuncCacheName(String name, WurstType receiverType) {
16+
return name
17+
+ "@"
18+
+ receiverType
19+
+ "#"
20+
+ System.identityHashCode(receiverType);
21+
}
1422

1523
public static ImmutableCollection<FuncLink> lookupFuncsNoConfig(Element node, String name, boolean showErrors) {
1624
if (!showErrors) {
@@ -117,16 +125,41 @@ private static <T extends NameLink> ImmutableCollection<T> removeDuplicates(List
117125

118126
public static ImmutableCollection<FuncLink> lookupMemberFuncs(Element node, WurstType receiverType, String name, boolean showErrors) {
119127
if (!showErrors) {
120-
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, name + "@" + receiverType, GlobalCaches.LookupType.MEMBER_FUNC);
128+
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, memberFuncCacheName(name, receiverType), GlobalCaches.LookupType.MEMBER_FUNC);
121129
@SuppressWarnings("unchecked")
122130
ImmutableCollection<FuncLink> cached = (ImmutableCollection<FuncLink>) GlobalCaches.lookupCache.get(key);
123131
if (cached != null) {
132+
WLogger.trace("[LOOKUPCACHE] HIT MEMBER_FUNC node=" + System.identityHashCode(node)
133+
+ " name=" + name
134+
+ " recv=" + receiverType
135+
+ " recvId=" + System.identityHashCode(receiverType)
136+
+ " size=" + cached.size());
124137
return cached;
125138
}
126139
}
127140

128141
List<FuncLink> result = new ArrayList<>(4);
129-
addMemberMethods(node, receiverType, name, result);
142+
WLogger.trace("[LMF] addMemberMethods recv=" + receiverType
143+
+ " recvId=" + System.identityHashCode(receiverType)
144+
+ " name=" + name
145+
+ " node=" + System.identityHashCode(node));
146+
// Collect from the type first, but *validate/adapt* each candidate to the actual receiverType.
147+
List<FuncLink> fromType = new ArrayList<>(4);
148+
addMemberMethods(node, receiverType, name, fromType);
149+
for (FuncLink cand : fromType) {
150+
DefLink m = matchDefLinkReceiver(cand, receiverType, node, showErrors);
151+
if (m instanceof FuncLink) {
152+
result.add((FuncLink) m);
153+
}
154+
}
155+
156+
for (FuncLink f : result) {
157+
WLogger.trace("[LMF] addMemberMethods -> " + f
158+
+ " recv=" + f.getReceiverType()
159+
+ " recvId=" + System.identityHashCode(f.getReceiverType())
160+
+ " linkVB=" + f.getVariableBinding()
161+
+ " linkTypeParams=" + f.getTypeParams());
162+
}
130163

131164
WScope scope = node.attrNearestScope();
132165

@@ -155,7 +188,12 @@ public static ImmutableCollection<FuncLink> lookupMemberFuncs(Element node, Wurs
155188
ImmutableCollection<FuncLink> immutableResult = removeDuplicates(result);
156189

157190
if (!showErrors) {
158-
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, name + "@" + receiverType, GlobalCaches.LookupType.MEMBER_FUNC);
191+
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, memberFuncCacheName(name, receiverType), GlobalCaches.LookupType.MEMBER_FUNC);
192+
WLogger.trace("[LOOKUPCACHE] PUT MEMBER_FUNC node=" + System.identityHashCode(node)
193+
+ " name=" + name
194+
+ " recv=" + receiverType
195+
+ " recvId=" + System.identityHashCode(receiverType)
196+
+ " size=" + immutableResult.size());
159197
GlobalCaches.lookupCache.put(key, immutableResult);
160198
}
161199

@@ -252,7 +290,7 @@ public static NameLink lookupVarNoConfig(Element node, String name, boolean show
252290

253291
public static NameLink lookupMemberVar(Element node, WurstType receiverType, String name, boolean showErrors) {
254292
if (!showErrors) {
255-
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, name + "@" + receiverType, GlobalCaches.LookupType.MEMBER_VAR);
293+
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, memberFuncCacheName(name, receiverType), GlobalCaches.LookupType.MEMBER_VAR);
256294
NameLink cached = (NameLink) GlobalCaches.lookupCache.get(key);
257295
if (cached != null) {
258296
return cached;
@@ -286,7 +324,11 @@ public static NameLink lookupMemberVar(Element node, WurstType receiverType, Str
286324

287325
if (bestMatch != null) {
288326
if (!showErrors) {
289-
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, name + "@" + receiverType, GlobalCaches.LookupType.MEMBER_VAR);
327+
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, memberFuncCacheName(name, receiverType), GlobalCaches.LookupType.MEMBER_VAR);
328+
WLogger.trace("[LOOKUPCACHE] PUT MEMBER_FUNC node=" + System.identityHashCode(node)
329+
+ " name=" + name
330+
+ " recv=" + receiverType
331+
+ " recvId=" + System.identityHashCode(receiverType));
290332
GlobalCaches.lookupCache.put(key, bestMatch.link);
291333
}
292334
return bestMatch.link;
@@ -412,24 +454,43 @@ private DefLinkMatch(DefLink link, int distance) {
412454
}
413455

414456
public static DefLink matchDefLinkReceiver(DefLink n, WurstType receiverType, Element node, boolean showErrors) {
415-
WurstType n_receiverType = n.getReceiverType();
416-
if (n_receiverType == null) {
417-
return null;
418-
}
419-
VariableBinding mapping = receiverType.matchAgainstSupertype(n_receiverType, node, VariableBinding.emptyMapping().withTypeVariables(n.getTypeParams()), VariablePosition.RIGHT);
420-
if (mapping == null) {
421-
return null;
422-
}
457+
WurstType candRecv = n.getReceiverType();
458+
if (candRecv == null) return null;
459+
460+
VariableBinding seed = VariableBinding.emptyMapping().withTypeVariables(n.getTypeParams());
461+
VariableBinding mapping = receiverType.matchAgainstSupertype(candRecv, node, seed, VariablePosition.RIGHT);
462+
if (mapping == null) return null;
463+
464+
WLogger.trace("[MATCHRECV] def=" + ((n instanceof FuncLink) ? ((FuncLink) n).getDef().getName() : n.getDef().getName())
465+
+ " left=" + receiverType
466+
+ " candRecv=" + candRecv
467+
+ " linkTypeParams=" + n.getTypeParams()
468+
+ (n instanceof FuncLink ? (" linkVB=" + ((FuncLink) n).getVariableBinding()) : ""));
469+
423470
if (showErrors) {
424471
if (n.getVisibility() == Visibility.PRIVATE_OTHER) {
425472
node.addError(Utils.printElement(n.getDef()) + " is private and cannot be used here.");
426-
} else if (n.getVisibility() == Visibility.PROTECTED_OTHER && !receiverType.isSubtypeOf(n_receiverType, node)) {
473+
} else if (n.getVisibility() == Visibility.PROTECTED_OTHER && !receiverType.isSubtypeOf(candRecv, node)) {
427474
node.addError(Utils.printElement(n.getDef()) + " is protected and cannot be used here.");
428475
}
429476
}
477+
430478
return n.withTypeArgBinding(node, mapping);
431479
}
432480

481+
private static Iterable<TypeParamDef> typeParamsOfReceiverType(WurstType t) {
482+
if (t instanceof WurstTypeClassOrInterface) {
483+
return ((WurstTypeClassOrInterface) t).getDef().getTypeParameters();
484+
}
485+
if (t instanceof WurstTypeClass) {
486+
return ((WurstTypeClass) t).getClassDef().getTypeParameters();
487+
}
488+
if (t instanceof WurstTypeInterface) {
489+
return ((WurstTypeInterface) t).getInterfaceDef().getTypeParameters();
490+
}
491+
return java.util.Collections.emptyList();
492+
}
493+
433494
public static @Nullable TypeDef lookupType(Element node, String name, boolean showErrors) {
434495
if (!showErrors) {
435496
GlobalCaches.CacheKey key = new GlobalCaches.CacheKey(node, name, GlobalCaches.LookupType.TYPE);

0 commit comments

Comments
 (0)