Expanded scope of "this." resolution to account for JS script types and inner scopes too. (compat for new ObjectLiterals & not implemented yet but soonTM JS prototypes)

This commit is contained in:
bigguy345 committed 2026-03-08 16:17:21 +02:00
1 parent 86c3277075
commit c0d5bf3acc
3 files changed
+35 -13

No files matched your search

@@ -188,7 +188,10 @@ public class FieldChainMarker {
if (ctx.firstIsThis) {
// 'this' - resolve to enclosing class/global fields
ctx.currentType = ctx.enclosingType;
ctx.currentType = document.resolveThisType(chainStart);
if (ctx.currentType == null) {
ctx.currentType = ctx.enclosingType;
}
} else if (ctx.firstIsSuper) {
// 'super' - resolve to parent class
if (ctx.enclosingType != null && ctx.enclosingType.hasSuperClass()) {
@@ -228,7 +231,7 @@ public class FieldChainMarker {
// Case 2: this.field
if (index == 1 && ctx.firstIsThis) {
return resolveThisFieldMark(ctx);
return resolveThisFieldMark(ctx);
}
// Case 3: super.field
@@ -286,17 +289,18 @@ public class FieldChainMarker {
boolean found = false;
FieldInfo fieldInfo = null;
// First check enclosing script type fields
if (ctx.enclosingType != null && ctx.enclosingType.hasField(segment)) {
TypeInfo thisType = ctx.currentType != null ? ctx.currentType : ctx.enclosingType;
if (thisType != null && thisType.hasField(segment)) {
found = true;
fieldInfo = ctx.enclosingType.getFieldInfo(segment);
fieldInfo = thisType.getFieldInfo(segment);
} else if (document.getGlobalFields().containsKey(segment)) {
found = true;
fieldInfo = document.getGlobalFields().get(segment);
}
if (found) {
FieldAccessInfo accessInfo = document.createFieldAccessInfo(segment, pos[0], pos[1], ctx.enclosingType,
FieldAccessInfo accessInfo = document.createFieldAccessInfo(segment, pos[0], pos[1], thisType,
fieldInfo, isLast, false);
return new MarkResult(new ScriptLine.Mark(pos[0], pos[1], getFieldTokenType(fieldInfo), accessInfo),
@@ -29,6 +29,7 @@ public class InnerCallableScope {
private final Map<String, FieldInfo> locals = new HashMap<>();
private InnerCallableScope parentScope; // Enclosing inner scope (for nested lambdas)
private TypeInfo expectedType; // The expected functional interface type (set during resolution)
private TypeInfo containingObjectType; // For object-literal methods, the synthetic object-literal type
public InnerCallableScope(Kind kind, int headerStart, int headerEnd, int bodyStart, int bodyEnd) {
this.kind = kind;
@@ -48,10 +49,12 @@ public class InnerCallableScope {
public Map<String, FieldInfo> getLocals() { return locals; }
public InnerCallableScope getParentScope() { return parentScope; }
public TypeInfo getExpectedType() { return expectedType; }
public TypeInfo getContainingObjectType() { return containingObjectType; }
// Setters
public void setParentScope(InnerCallableScope parent) { this.parentScope = parent; }
public void setExpectedType(TypeInfo type) { this.expectedType = type; }
public void setContainingObjectType(TypeInfo type) { this.containingObjectType = type; }
public void addParameter(FieldInfo param) {
parameters.add(param);
@@ -5394,7 +5394,7 @@ public class ScriptDocument {
// "this" keyword
if (expr.equals("this")) {
return findEnclosingScriptType(position);
return resolveThisType(position);
}
if (expr.startsWith("new ")) {
@@ -5430,7 +5430,7 @@ public class ScriptDocument {
TypeInfo currentType = null;
if (first.name.equals("this")) {
currentType = findEnclosingScriptType(position);
currentType = resolveThisType(position);
// Handle this.field where we don't have a script type
if (currentType == null && segments.size() > 1 && !segments.get(1).isMethodCall) {
String fieldName = segments.get(1).name;
@@ -5909,8 +5909,23 @@ public class ScriptDocument {
}
return null;
}
/**
* Resolve the type of "this" at a given position by finding the innermost scope and checking for containing object types.
* For both Java and JavaScript, this will correctly resolve to the appropriate type based on the current context (e.g., enclosing class, script type, or synthetic type).
* @param position
* @return
*/
TypeInfo resolveThisType(int position) {
Object innermostScope = findInnermostScopeAt(position);
if (innermostScope instanceof InnerCallableScope) {
TypeInfo objectType = ((InnerCallableScope) innermostScope).getContainingObjectType();
if (objectType != null && objectType.isResolved()) {
return objectType;
}
}
return findEnclosingScriptType(position);
}
// ==================== OPERATOR EXPRESSION RESOLUTION ====================
@@ -6099,7 +6114,7 @@ public class ScriptDocument {
@Override
public TypeInfo resolveIdentifier(String name) {
if ("this".equals(name)) {
return findEnclosingScriptType(position);
return resolveThisType(position);
}
if ("super".equals(name)) {
// Resolve super to parent class type
@@ -6257,7 +6272,7 @@ public class ScriptDocument {
// "this" keyword
if (expr.equals("this")) {
return findEnclosingScriptType(position);
return resolveThisType(position);
}
// "new Type()" expressions
@@ -6289,7 +6304,7 @@ public class ScriptDocument {
TypeInfo currentType = null;
if (first.name.equals("this")) {
currentType = findEnclosingScriptType(position);
currentType = resolveThisType(position);
} else {
// Check if first segment is a type name
TypeInfo typeCheck = resolveType(first.name);
@@ -8228,7 +8243,7 @@ public class ScriptDocument {
// First check inner callable scopes (most specific)
InnerCallableScope innermost = null;
for (InnerCallableScope scope : innerScopes) {
if (scope.containsPosition(position)) {
if (scope.containsPosition(position) || scope.containsHeaderPosition(position)) {
if (innermost == null || scope.getBodyStart() > innermost.getBodyStart()) {
innermost = scope;
}