|
3 | 3 | import de.peeeq.wurstscript.ast.*; |
4 | 4 | import de.peeeq.wurstscript.attributes.names.FuncLink; |
5 | 5 | import de.peeeq.wurstscript.attributes.names.NameLink; |
| 6 | +import de.peeeq.wurstscript.attributes.names.OtherLink; |
| 7 | +import de.peeeq.wurstscript.attributes.names.Visibility; |
6 | 8 | import de.peeeq.wurstscript.types.WurstType; |
| 9 | +import de.peeeq.wurstscript.types.WurstTypeClassOrInterface; |
| 10 | +import de.peeeq.wurstscript.types.WurstTypeUnknown; |
7 | 11 | import de.peeeq.wurstscript.types.WurstTypeEnum; |
8 | 12 | import de.peeeq.wurstscript.types.WurstTypeModule; |
9 | 13 | import org.eclipse.jdt.annotation.Nullable; |
@@ -74,8 +78,52 @@ public static NameLink calculate(ExprMemberVar term) { |
74 | 78 |
|
75 | 79 | protected static NameLink searchNameInScope(String varName, NameRef node) { |
76 | 80 | boolean showErrors = !varName.startsWith("gg_"); |
77 | | - NameLink result = node.lookupVar(varName, showErrors); |
78 | | - return result; |
| 81 | + if (!"it".equals(varName)) { |
| 82 | + return node.lookupVar(varName, showErrors); |
| 83 | + } |
| 84 | + |
| 85 | + // Normal lexical lookup wins, so user-defined names can shadow implicit closure-self. |
| 86 | + NameLink result = node.lookupVar(varName, false); |
| 87 | + if (result != null) { |
| 88 | + return result; |
| 89 | + } |
| 90 | + |
| 91 | + NameLink implicitClosureSelf = lookupImplicitClosureSelf(node, showErrors); |
| 92 | + if (implicitClosureSelf != null) { |
| 93 | + return implicitClosureSelf; |
| 94 | + } |
| 95 | + if (node.attrNearestExprClosure() != null) { |
| 96 | + // keep diagnostics focused on closure typing instead of "unknown variable it" |
| 97 | + return null; |
| 98 | + } |
| 99 | + |
| 100 | + if (!showErrors) { |
| 101 | + return null; |
| 102 | + } |
| 103 | + |
| 104 | + // Fallback to default diagnostics when no implicit closure-self is available. |
| 105 | + return node.lookupVar(varName, true); |
| 106 | + } |
| 107 | + |
| 108 | + private static @Nullable NameLink lookupImplicitClosureSelf(NameRef node, boolean showErrors) { |
| 109 | + ExprClosure closure = node.attrNearestExprClosure(); |
| 110 | + if (closure == null) { |
| 111 | + return null; |
| 112 | + } |
| 113 | + WurstType expectedTyp = closure.attrExpectedTypAfterOverloading(); |
| 114 | + if (!(expectedTyp instanceof WurstTypeClassOrInterface)) { |
| 115 | + if (showErrors && (expectedTyp instanceof WurstTypeUnknown)) { |
| 116 | + node.addError("Cannot use implicit closure self 'it' because the closure target type is unknown."); |
| 117 | + } |
| 118 | + return null; |
| 119 | + } |
| 120 | + |
| 121 | + return new OtherLink(Visibility.LOCAL, "it", expectedTyp) { |
| 122 | + @Override |
| 123 | + public de.peeeq.wurstscript.jassIm.ImExpr translate(NameRef e, de.peeeq.wurstscript.translation.imtranslation.ImTranslator t, de.peeeq.wurstscript.jassIm.ImFunction f) { |
| 124 | + return de.peeeq.wurstscript.jassIm.JassIm.ImVarAccess(t.getThisVar(closure)); |
| 125 | + } |
| 126 | + }; |
79 | 127 | } |
80 | 128 |
|
81 | 129 | private static boolean isWriteAccess(final NameRef node) { |
@@ -110,7 +158,7 @@ private static boolean isWriteAccess(final NameRef node) { |
110 | 158 |
|
111 | 159 | public static @Nullable NameDef tryGetNameDef(NameRef e) { |
112 | 160 | NameLink link = e.attrNameLink(); |
113 | | - if (link == null) { |
| 161 | + if (link == null || link instanceof OtherLink) { |
114 | 162 | return null; |
115 | 163 | } |
116 | 164 | return link.getDef(); |
@@ -139,6 +187,9 @@ private static boolean isWriteAccess(final NameRef node) { |
139 | 187 |
|
140 | 188 | public static NameDef calculateDef(NameRef nameRef) { |
141 | 189 | NameLink l = nameRef.attrNameLink(); |
| 190 | + if (l instanceof OtherLink) { |
| 191 | + return null; |
| 192 | + } |
142 | 193 | return l == null ? null : l.getDef(); |
143 | 194 | } |
144 | 195 | } |
0 commit comments