mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 05:27:37 +00:00
Proper TypeInfo.typeParam overload that is much needed + IntersectionTypeInfo for type parameter <T extends X & Interface1 & Interface2<T>>
This commit is contained in:
1 parent
eae5a08932
commit
3b7798338f
4 files changed
+229
-19
No files matched your search
@@ -4343,14 +4343,7 @@ public class ScriptDocument {
|
||||
// Check if the name is a declared type parameter on this class (e.g., E in class Box<E>)
|
||||
TypeParamInfo typeParam = enclosing.getDeclaredTypeParam(baseTypeName);
|
||||
if (typeParam != null) {
|
||||
TypeInfo boundType = typeParam.getBoundTypeInfo();
|
||||
if (boundType == null) {
|
||||
typeParam.resolveBoundType();
|
||||
boundType = typeParam.getBoundTypeInfo();
|
||||
}
|
||||
TypeInfo result = (boundType != null && boundType.isResolved())
|
||||
? TypeInfo.typeParameter(baseTypeName, boundType)
|
||||
: TypeInfo.typeParameter(baseTypeName);
|
||||
TypeInfo result = TypeInfo.typeParameter(baseTypeName, typeParam);
|
||||
for (int i = 0; i < arrayDims; i++) result = TypeInfo.arrayOf(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
+6
-11
@@ -73,8 +73,9 @@ public final class GenericContext {
|
||||
if (declared == null) continue;
|
||||
String name = declared.getName();
|
||||
if (name == null || name.isEmpty()) continue;
|
||||
TypeInfo bound = declared.getBoundTypeInfo();
|
||||
bounds.put(name, (bound != null && bound.isResolved()) ? bound : TypeInfo.OBJECT);
|
||||
TypeInfo tp = TypeInfo.typeParameter(name, declared);
|
||||
TypeInfo effectiveBound = tp.getBoundType();
|
||||
bounds.put(name, effectiveBound != null ? effectiveBound : TypeInfo.OBJECT);
|
||||
}
|
||||
|
||||
return new GenericContext(applied, bounds);
|
||||
@@ -125,15 +126,9 @@ public final class GenericContext {
|
||||
if (declared == null) continue;
|
||||
String name = declared.getName();
|
||||
if (name == null || name.isEmpty()) continue;
|
||||
TypeInfo bound = declared.getBoundTypeInfo();
|
||||
TypeInfo effectiveBound = (bound != null && bound.isResolved()) ? bound : TypeInfo.OBJECT;
|
||||
|
||||
// TODO: Goatee not sure what this was for
|
||||
// List<TypeInfo> additionalBounds = declared.getAdditionalBoundTypes();
|
||||
// if (additionalBounds != null && !additionalBounds.isEmpty()) {
|
||||
// effectiveBound = IntersectionTypeInfo.of(effectiveBound, additionalBounds);
|
||||
// }
|
||||
bounds.put(name, effectiveBound);
|
||||
TypeInfo tp = TypeInfo.typeParameter(name, declared);
|
||||
TypeInfo effectiveBound = tp.getBoundType();
|
||||
bounds.put(name, effectiveBound != null ? effectiveBound : TypeInfo.OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package noppes.npcs.client.gui.util.script.interpreter.type;
|
||||
|
||||
import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo;
|
||||
import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents an intersection type from multiple bounds on a type parameter.
|
||||
* For example, {@code <T extends Number & Comparable<T>>} creates an intersection
|
||||
* of Number and Comparable.
|
||||
*
|
||||
* <p>The primary bound determines the display name and main type identity.
|
||||
* Member lookup (hasMethod, getMethodInfo, hasField, getFieldInfo, getAllMethodOverloads)
|
||||
* delegates to ALL constituent types, so methods from any bound are accessible.</p>
|
||||
*
|
||||
* <p>This is used by {@link GenericContext} when building bound fallbacks for type
|
||||
* parameters with additional interface bounds.</p>
|
||||
*/
|
||||
public class IntersectionTypeInfo extends TypeInfo {
|
||||
|
||||
/** The primary (first) bound type — used for display and as the "main" type. */
|
||||
private final TypeInfo primaryBound;
|
||||
|
||||
/** Additional interface bounds (everything after {@code &}). */
|
||||
private final List<TypeInfo> additionalBounds;
|
||||
|
||||
private IntersectionTypeInfo(TypeInfo primaryBound, List<TypeInfo> additionalBounds) {
|
||||
super(primaryBound.getSimpleName(), primaryBound.getFullName(), "",
|
||||
primaryBound.getKind(), primaryBound.getJavaClass(), true, null, true);
|
||||
this.primaryBound = primaryBound;
|
||||
this.additionalBounds = additionalBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an intersection type from a primary bound and additional interface bounds.
|
||||
* If there are no additional bounds, returns the primary bound directly (no wrapper).
|
||||
*
|
||||
* @param primary the primary (first) bound type
|
||||
* @param additional the additional interface bounds (may be empty)
|
||||
* @return an IntersectionTypeInfo if there are additional bounds, otherwise the primary itself
|
||||
*/
|
||||
public static TypeInfo of(TypeInfo primary, List<TypeInfo> additional) {
|
||||
if (additional == null || additional.isEmpty()) {
|
||||
return primary;
|
||||
}
|
||||
return new IntersectionTypeInfo(primary, new ArrayList<>(additional));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMethod(String methodName) {
|
||||
if (primaryBound.hasMethod(methodName)) return true;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
if (bound.hasMethod(methodName)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMethod(String methodName, int paramCount) {
|
||||
if (primaryBound.hasMethod(methodName, paramCount)) return true;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
if (bound.hasMethod(methodName, paramCount)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodInfo getMethodInfo(String methodName) {
|
||||
MethodInfo m = primaryBound.getMethodInfo(methodName);
|
||||
if (m != null) return m;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
m = bound.getMethodInfo(methodName);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MethodInfo> getAllMethodOverloads(String methodName) {
|
||||
Set<MethodInfo> seen = new LinkedHashSet<>();
|
||||
seen.addAll(primaryBound.getAllMethodOverloads(methodName));
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
seen.addAll(bound.getAllMethodOverloads(methodName));
|
||||
}
|
||||
return new ArrayList<>(seen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodInfo getBestMethodOverload(String methodName, TypeInfo[] argTypes) {
|
||||
MethodInfo m = primaryBound.getBestMethodOverload(methodName, argTypes);
|
||||
if (m != null) return m;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
m = bound.getBestMethodOverload(methodName, argTypes);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodInfo getBestMethodOverload(String methodName, TypeInfo expectedReturnType) {
|
||||
MethodInfo m = primaryBound.getBestMethodOverload(methodName, expectedReturnType);
|
||||
if (m != null) return m;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
m = bound.getBestMethodOverload(methodName, expectedReturnType);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(String fieldName) {
|
||||
if (primaryBound.hasField(fieldName)) return true;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
if (bound.hasField(fieldName)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInfo getFieldInfo(String fieldName) {
|
||||
FieldInfo f = primaryBound.getFieldInfo(fieldName);
|
||||
if (f != null) return f;
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
f = bound.getFieldInfo(fieldName);
|
||||
if (f != null) return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeInfo getPrimaryBound() {
|
||||
return primaryBound;
|
||||
}
|
||||
|
||||
public List<TypeInfo> getAdditionalBounds() {
|
||||
return new ArrayList<>(additionalBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
StringBuilder sb = new StringBuilder(primaryBound.getDisplayName());
|
||||
for (TypeInfo bound : additionalBounds) {
|
||||
sb.append(" & ").append(bound.getDisplayName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResolved() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntersectionTypeInfo{" + getDisplayName() + "}";
|
||||
}
|
||||
}
|
||||
@@ -194,12 +194,74 @@ public class TypeInfo {
|
||||
public static TypeInfo typeParameter(String paramName, TypeInfo boundType) {
|
||||
Class<?> javaClass = (boundType != null && boundType.javaClass != null) ? boundType.javaClass : Object.class;
|
||||
Kind kind = (boundType != null) ? boundType.kind : Kind.CLASS;
|
||||
|
||||
if (boundType instanceof IntersectionTypeInfo) {
|
||||
final IntersectionTypeInfo intersection = (IntersectionTypeInfo) boundType;
|
||||
TypeInfo ti = new TypeInfo(paramName, paramName, "", kind, javaClass, true, null) {
|
||||
@Override
|
||||
public List<MethodInfo> getAllMethods() {
|
||||
List<MethodInfo> result = new ArrayList<>(super.getAllMethods());
|
||||
for (TypeInfo bound : intersection.getAdditionalBounds())
|
||||
result.addAll(bound.getAllMethods());
|
||||
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public List<FieldInfo> getAllFields() {
|
||||
List<FieldInfo> result = new ArrayList<>(super.getAllFields());
|
||||
for (TypeInfo bound : intersection.getAdditionalBounds())
|
||||
result.addAll(bound.getAllFields());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
ti.typeParameterName = paramName;
|
||||
ti.boundType = boundType;
|
||||
return ti;
|
||||
}
|
||||
|
||||
TypeInfo ti = new TypeInfo(paramName, paramName, "", kind, javaClass, true, null);
|
||||
ti.typeParameterName = paramName;
|
||||
ti.boundType = boundType;
|
||||
return ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TypeInfo representing a bounded type parameter from a {@link TypeParamInfo}.
|
||||
* This is the single point of control for creating type parameter TypeInfos with bound handling.
|
||||
*
|
||||
* <p>If the TypeParamInfo has additional bounds (e.g., {@code T extends Number & Comparable<T>}),
|
||||
* an {@link IntersectionTypeInfo} is created internally to represent the combined bound.
|
||||
* This centralizes intersection creation so no caller needs to call {@code IntersectionTypeInfo.of()} directly.</p>
|
||||
*
|
||||
* @param paramName the type parameter name (e.g., "T")
|
||||
* @param typeParam the TypeParamInfo containing bound information
|
||||
* @return a TypeInfo tagged as a type parameter with the effective bound
|
||||
*/
|
||||
public static TypeInfo typeParameter(String paramName, TypeParamInfo typeParam) {
|
||||
if (typeParam == null) {
|
||||
return typeParameter(paramName);
|
||||
}
|
||||
TypeInfo primaryBound = typeParam.getBoundTypeInfo();
|
||||
if (primaryBound == null) {
|
||||
typeParam.resolveBoundType();
|
||||
primaryBound = typeParam.getBoundTypeInfo();
|
||||
}
|
||||
|
||||
TypeInfo effectiveBound;
|
||||
if (primaryBound != null && primaryBound.isResolved()) {
|
||||
List<TypeInfo> additionalBounds = typeParam.getAdditionalBoundTypes();
|
||||
if (additionalBounds != null && !additionalBounds.isEmpty()) {
|
||||
effectiveBound = IntersectionTypeInfo.of(primaryBound, additionalBounds);
|
||||
} else {
|
||||
effectiveBound = primaryBound;
|
||||
}
|
||||
} else {
|
||||
effectiveBound = null;
|
||||
}
|
||||
return typeParameter(paramName, effectiveBound);
|
||||
}
|
||||
|
||||
public boolean isTypeParameter() {
|
||||
return typeParameterName != null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user