merge Alex' work with mine, move internal classes to internal subpackage
This commit is contained in:
@@ -52,6 +52,7 @@ public class BothSignatureWriter {
|
|||||||
|
|
||||||
private JetSignatureWriter jetSignatureWriter;
|
private JetSignatureWriter jetSignatureWriter;
|
||||||
|
|
||||||
|
private String kotlinClassParameters;
|
||||||
private String kotlinClassSignature;
|
private String kotlinClassSignature;
|
||||||
|
|
||||||
private List<String> kotlinParameterTypes = new ArrayList<String>();
|
private List<String> kotlinParameterTypes = new ArrayList<String>();
|
||||||
@@ -207,7 +208,16 @@ public class BothSignatureWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeFormalTypeParametersEnd() {
|
public void writeFormalTypeParametersEnd() {
|
||||||
|
jetSignatureWriter.visitSuperclass(); // just to call endFormals
|
||||||
|
|
||||||
|
kotlinClassParameters = jetSignatureWriter.toString();
|
||||||
|
|
||||||
jetSignatureWriter = null;
|
jetSignatureWriter = null;
|
||||||
|
|
||||||
|
if (DEBUG_SIGNATURE_WRITER) {
|
||||||
|
new JetSignatureReader(kotlinClassParameters).acceptFormalTypeParametersOnly(new JetSignatureAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
checkState(State.TYPE_PARAMETERS);
|
checkState(State.TYPE_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,6 +295,11 @@ public class BothSignatureWriter {
|
|||||||
public void writeSupersEnd() {
|
public void writeSupersEnd() {
|
||||||
kotlinClassSignature = jetSignatureWriter.toString();
|
kotlinClassSignature = jetSignatureWriter.toString();
|
||||||
jetSignatureWriter = null;
|
jetSignatureWriter = null;
|
||||||
|
|
||||||
|
if (DEBUG_SIGNATURE_WRITER) {
|
||||||
|
new JetSignatureReader(kotlinClassSignature).accept(new JetSignatureAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
transitionState(State.SUPERS, State.CLASS_END);
|
transitionState(State.SUPERS, State.CLASS_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +359,13 @@ public class BothSignatureWriter {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public String makeKotlinClassSignature() {
|
public String makeKotlinClassSignature() {
|
||||||
checkState(State.CLASS_END);
|
checkState(State.CLASS_END);
|
||||||
return kotlinClassSignature;
|
if (kotlinClassParameters == null) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
if (kotlinClassSignature == null) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return kotlinClassParameters + kotlinClassSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
v.visitOuterClass(typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null);
|
v.visitOuterClass(typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(myClass instanceof JetClass) {
|
if(myClass instanceof JetClass && signature.getKotlinGenericSignature() != null) {
|
||||||
AnnotationVisitor annotationVisitor = v.newAnnotation(myClass, "Ljet/typeinfo/JetSignature;", true);
|
AnnotationVisitor annotationVisitor = v.newAnnotation(myClass, "Ljet/typeinfo/JetSignature;", true);
|
||||||
annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, bindingContext, typeMapper));
|
//annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, bindingContext, typeMapper));
|
||||||
|
annotationVisitor.visit("value", signature.getKotlinGenericSignature());
|
||||||
annotationVisitor.visitEnd();
|
annotationVisitor.visitEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
|
||||||
|
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetClass;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeParameter;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeReference;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
|
||||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
|
||||||
import org.jetbrains.jet.lang.types.Variance;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author alex.tkachman
|
|
||||||
*/
|
|
||||||
public class SignatureUtil {
|
|
||||||
private SignatureUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String classToSignature(JetClass type, BindingContext bindingContext, JetTypeMapper typeMapper) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
genTypeParams(type, sb);
|
|
||||||
List<JetDelegationSpecifier> delegationSpecifiers = type.getDelegationSpecifiers();
|
|
||||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
|
||||||
JetTypeReference typeReference = specifier.getTypeReference();
|
|
||||||
JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
|
|
||||||
genJetType(sb, jetType, typeMapper);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void genJetType(StringBuilder sb, JetType jetType, JetTypeMapper typeMapper) {
|
|
||||||
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
|
|
||||||
if(descriptor instanceof ClassDescriptor) {
|
|
||||||
JetType defaultType = ((ClassDescriptor) descriptor).getDefaultType();
|
|
||||||
Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION);
|
|
||||||
if(JetTypeMapper.isPrimitive(type)) {
|
|
||||||
type = JetTypeMapper.boxType(type);
|
|
||||||
}
|
|
||||||
sb.append(type.getDescriptor());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sb.append("T");
|
|
||||||
JetType defaultType = ((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType();
|
|
||||||
Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION);
|
|
||||||
sb.append(type.getDescriptor());
|
|
||||||
sb.append(descriptor.getName());
|
|
||||||
sb.append(";");
|
|
||||||
}
|
|
||||||
if(!jetType.getArguments().isEmpty()) {
|
|
||||||
sb.append("<");
|
|
||||||
for (TypeProjection typeProjection : jetType.getArguments()) {
|
|
||||||
if(typeProjection.getProjectionKind() == Variance.IN_VARIANCE)
|
|
||||||
sb.append("in ");
|
|
||||||
if(typeProjection.getProjectionKind() == Variance.OUT_VARIANCE)
|
|
||||||
sb.append("out ");
|
|
||||||
genJetType(sb, typeProjection.getType(), typeMapper);
|
|
||||||
}
|
|
||||||
sb.append(">");
|
|
||||||
}
|
|
||||||
if(jetType.isNullable())
|
|
||||||
sb.append("?");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void genTypeParams(JetClass type, StringBuilder sb) {
|
|
||||||
List<JetTypeParameter> parameters = type.getTypeParameterList().getParameters();
|
|
||||||
if (parameters.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sb.append('<');
|
|
||||||
for(JetTypeParameter param : parameters) {
|
|
||||||
Variance variance = param.getVariance();
|
|
||||||
if(variance == Variance.IN_VARIANCE)
|
|
||||||
sb.append("in ");
|
|
||||||
else if(variance == Variance.OUT_VARIANCE)
|
|
||||||
sb.append("out ");
|
|
||||||
sb.append(param.getName());
|
|
||||||
sb.append(";");
|
|
||||||
}
|
|
||||||
sb.append('>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-62
@@ -1,6 +1,8 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java;
|
package org.jetbrains.jet.lang.resolve.java;
|
||||||
|
|
||||||
import jet.typeinfo.TypeInfoVariance;
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
import jet.typeinfo.internal.signature.JetSignatureAdapter;
|
||||||
|
import jet.typeinfo.internal.signature.JetSignatureExceptionsAdapter;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
@@ -20,7 +22,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @author Stepan Koltsov
|
* @author Stepan Koltsov
|
||||||
*/
|
*/
|
||||||
public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor {
|
public abstract class JetTypeJetSignatureReader extends JetSignatureExceptionsAdapter {
|
||||||
|
|
||||||
private final JavaDescriptorResolver javaDescriptorResolver;
|
private final JavaDescriptorResolver javaDescriptorResolver;
|
||||||
private final JetStandardLibrary jetStandardLibrary;
|
private final JetStandardLibrary jetStandardLibrary;
|
||||||
@@ -31,47 +33,6 @@ public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitFormalTypeParameter(String name, TypeInfoVariance variance) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitClassBound() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitInterfaceBound() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitSuperclass() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitInterface() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitParameterType() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitReturnType() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitExceptionType() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private JetType getPrimitiveType(char descriptor, boolean nullable) {
|
private JetType getPrimitiveType(char descriptor, boolean nullable) {
|
||||||
if (!nullable) {
|
if (!nullable) {
|
||||||
switch (descriptor) {
|
switch (descriptor) {
|
||||||
@@ -124,16 +85,6 @@ public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor {
|
|||||||
done(getPrimitiveType(descriptor, nullable));
|
done(getPrimitiveType(descriptor, nullable));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitTypeVariable(String name, boolean nullable) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetSignatureVisitor visitArrayType(boolean nullable) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ClassDescriptor classDescriptor;
|
private ClassDescriptor classDescriptor;
|
||||||
private boolean nullable;
|
private boolean nullable;
|
||||||
@@ -150,16 +101,6 @@ public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor {
|
|||||||
this.typeArguments = new ArrayList<TypeProjection>();
|
this.typeArguments = new ArrayList<TypeProjection>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitInnerClassType(String name, boolean nullable) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitTypeArgument() {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Variance parseVariance(char wildcard) {
|
private static Variance parseVariance(char wildcard) {
|
||||||
switch (wildcard) {
|
switch (wildcard) {
|
||||||
case '=': return Variance.INVARIANT;
|
case '=': return Variance.INVARIANT;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.*;
|
|||||||
* @url http://confluence.jetbrains.net/display/JET/Jet+Signatures
|
* @url http://confluence.jetbrains.net/display/JET/Jet+Signatures
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@interface JetSignature {
|
public @interface JetSignature {
|
||||||
String value();
|
String value();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,8 @@ package jet.typeinfo;
|
|||||||
|
|
||||||
import jet.JetObject;
|
import jet.JetObject;
|
||||||
import jet.Tuple0;
|
import jet.Tuple0;
|
||||||
|
import jet.typeinfo.internal.TypeInfoImpl;
|
||||||
import java.lang.reflect.Array;
|
import jet.typeinfo.internal.TypeInfoProjectionImpl;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.TypeVariable;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -15,7 +11,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
* @author alex.tkachman
|
* @author alex.tkachman
|
||||||
*/
|
*/
|
||||||
public abstract class TypeInfo<T> implements JetObject {
|
public abstract class TypeInfo<T> implements JetObject {
|
||||||
private final static TypeInfoProjection[] EMPTY = new TypeInfoProjection[0];
|
|
||||||
|
|
||||||
public static final TypeInfo<Byte> BYTE_TYPE_INFO = getTypeInfo(Byte.class, false);
|
public static final TypeInfo<Byte> BYTE_TYPE_INFO = getTypeInfo(Byte.class, false);
|
||||||
public static final TypeInfo<Short> SHORT_TYPE_INFO = getTypeInfo(Short.class, false);
|
public static final TypeInfo<Short> SHORT_TYPE_INFO = getTypeInfo(Short.class, false);
|
||||||
@@ -56,7 +51,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TypeInfoProjection inProjection(TypeInfo<T> typeInfo) {
|
public static <T> TypeInfoProjection inProjection(TypeInfo<T> typeInfo) {
|
||||||
return new TypeInfoProjection.TypeInfoProjectionImpl(typeInfo) {
|
return new TypeInfoProjectionImpl(typeInfo) {
|
||||||
// @NotNull
|
// @NotNull
|
||||||
@Override
|
@Override
|
||||||
public TypeInfoVariance getVariance() {
|
public TypeInfoVariance getVariance() {
|
||||||
@@ -66,7 +61,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TypeInfoProjection outProjection(TypeInfo<T> typeInfo) {
|
public static <T> TypeInfoProjection outProjection(TypeInfo<T> typeInfo) {
|
||||||
return new TypeInfoProjection.TypeInfoProjectionImpl(typeInfo) {
|
return new TypeInfoProjectionImpl(typeInfo) {
|
||||||
// @NotNull
|
// @NotNull
|
||||||
@Override
|
@Override
|
||||||
public TypeInfoVariance getVariance() {
|
public TypeInfoVariance getVariance() {
|
||||||
@@ -75,6 +70,15 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> TypeInfoProjection projection(TypeInfo<T> typeInfo, TypeInfoVariance variance) {
|
||||||
|
switch (variance) {
|
||||||
|
case IN: return inProjection(typeInfo);
|
||||||
|
case OUT: return outProjection(typeInfo);
|
||||||
|
case INVARIANT: return invariantProjection(typeInfo);
|
||||||
|
default: throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> TypeInfo<T> getTypeInfo(Class<T> klazz, boolean nullable) {
|
public static <T> TypeInfo<T> getTypeInfo(Class<T> klazz, boolean nullable) {
|
||||||
return new TypeInfoImpl<T>(klazz, nullable);
|
return new TypeInfoImpl<T>(klazz, nullable);
|
||||||
}
|
}
|
||||||
@@ -95,625 +99,4 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
|
|
||||||
public abstract TypeInfo getArgumentType(Class klass, int index);
|
public abstract TypeInfo getArgumentType(Class klass, int index);
|
||||||
|
|
||||||
protected abstract TypeInfo substitute(List<TypeInfo> myVars);
|
|
||||||
|
|
||||||
protected abstract TypeInfo substitute(TypeInfoProjection[] projections);
|
|
||||||
|
|
||||||
private static class TypeInfoVar<T> extends TypeInfo<T> {
|
|
||||||
final int varIndex;
|
|
||||||
final Signature signature;
|
|
||||||
final boolean nullable;
|
|
||||||
|
|
||||||
private TypeInfoVar(Signature signature, Integer varIndex) {
|
|
||||||
this.signature = signature;
|
|
||||||
this.varIndex = varIndex;
|
|
||||||
nullable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeInfoVar(Signature signature, boolean nullable, int varIndex) {
|
|
||||||
this.signature = signature;
|
|
||||||
this.nullable = nullable;
|
|
||||||
this.varIndex = varIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] newArray(int length) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<T> getJavaClass() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getClassObject() {
|
|
||||||
throw new UnsupportedOperationException("Abstract TypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInstance(Object obj) {
|
|
||||||
throw new UnsupportedOperationException("Abstract TypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getProjectionCount() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfoProjection getProjection(int index) {
|
|
||||||
throw new UnsupportedOperationException("Abstract TypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getArgumentType(Class klass, int index) {
|
|
||||||
throw new UnsupportedOperationException("Abstract TypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo substitute(List<TypeInfo> myVars) {
|
|
||||||
return myVars.get(varIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TypeInfo substitute(TypeInfoProjection[] projections) {
|
|
||||||
return projections[varIndex].getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo<?> getTypeInfo() {
|
|
||||||
throw new UnsupportedOperationException("Abstract TypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetObject getOuterObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "T:" + signature.klazz.getName() + ":" + varIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TypeInfoImpl<T> extends TypeInfo<T> implements TypeInfoProjection {
|
|
||||||
private TypeInfo<?> typeInfo;
|
|
||||||
private final Signature signature;
|
|
||||||
private final boolean nullable;
|
|
||||||
private final TypeInfoProjection[] projections;
|
|
||||||
|
|
||||||
private TypeInfoImpl(Class<T> theClass, boolean nullable) {
|
|
||||||
this(theClass, nullable, EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfoImpl(Class<T> theClass, boolean nullable, TypeInfoProjection[] projections) {
|
|
||||||
this.signature = Parser.parse(theClass);
|
|
||||||
this.nullable = nullable;
|
|
||||||
this.projections = projections;
|
|
||||||
if(signature.variables.size() != projections.length)
|
|
||||||
throw new IllegalStateException("Wrong signature " + theClass.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final TypeInfoProjection getProjection(int index) {
|
|
||||||
return projections[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] newArray(int length) {
|
|
||||||
return (Object[]) Array.newInstance(signature.klazz, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<T> getJavaClass() {
|
|
||||||
return signature.klazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Object getClassObject() {
|
|
||||||
try {
|
|
||||||
final Class implClass = signature.klazz.getClassLoader().loadClass(signature.klazz.getCanonicalName());
|
|
||||||
final Field classobj = implClass.getField("$classobj");
|
|
||||||
return classobj.get(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeInfo getSuperTypeInfo(Class klass) {
|
|
||||||
return signature.superSignatures.get(klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final TypeInfo getArgumentType(Class klass, int index) {
|
|
||||||
if(klass == this.signature.klazz)
|
|
||||||
return projections[index].getType();
|
|
||||||
else {
|
|
||||||
return getSuperTypeInfo(klass).substitute(projections).getArgumentType(klass, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo substitute(final List<TypeInfo> myVars) {
|
|
||||||
if(projections.length == 0)
|
|
||||||
return new TypeInfoImpl(this.signature.klazz, nullable, EMPTY);
|
|
||||||
else {
|
|
||||||
TypeInfoProjection [] proj = new TypeInfoProjection[projections.length];
|
|
||||||
for(int i = 0; i != proj.length; ++i) {
|
|
||||||
final int finalI = i;
|
|
||||||
final TypeInfo substitute = projections[finalI].getType().substitute(myVars);
|
|
||||||
proj[i] = new TypeInfoProjection(){
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return projections[finalI].getVariance();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return substitute;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getVariance().toString() + " " + substitute;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return new TypeInfoImpl(this.signature.klazz, nullable, proj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TypeInfo substitute(TypeInfoProjection[] prj) {
|
|
||||||
if(projections.length == 0)
|
|
||||||
return new TypeInfoImpl(signature.klazz, nullable, EMPTY);
|
|
||||||
else {
|
|
||||||
TypeInfoProjection [] proj = new TypeInfoProjection[projections.length];
|
|
||||||
for(int i = 0; i != proj.length; ++i) {
|
|
||||||
final int finalI = i;
|
|
||||||
final TypeInfo substitute = projections[finalI].getType().substitute(prj);
|
|
||||||
proj[i] = new TypeInfoProjection(){
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return projections[finalI].getVariance();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return substitute;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getVariance().toString() + " " + substitute;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return new TypeInfoImpl(signature.klazz, nullable, proj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
|
|
||||||
TypeInfoImpl typeInfo = (TypeInfoImpl) o;
|
|
||||||
|
|
||||||
if (!signature.klazz.equals(typeInfo.signature.klazz)) return false;
|
|
||||||
if (nullable != typeInfo.nullable) return false;
|
|
||||||
if (!Arrays.equals(projections, typeInfo.projections)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @NotNull
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return TypeInfoVariance.INVARIANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @NotNull
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
return 31 * signature.klazz.hashCode() + Arrays.hashCode(projections);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isInstance(Object obj) {
|
|
||||||
if (obj == null) return nullable;
|
|
||||||
|
|
||||||
if (obj instanceof JetObject) {
|
|
||||||
return ((TypeInfoImpl)((JetObject) obj).getTypeInfo()).isSubtypeOf(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return signature.klazz.isAssignableFrom(obj.getClass()); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getProjectionCount() {
|
|
||||||
return projections.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder().append(signature.klazz.getName());
|
|
||||||
if (projections.length != 0) {
|
|
||||||
sb.append("<");
|
|
||||||
for (int i = 0; i != projections.length - 1; ++i) {
|
|
||||||
sb.append(projections[i].toString()).append(",");
|
|
||||||
}
|
|
||||||
sb.append(projections[projections.length - 1].toString()).append(">");
|
|
||||||
}
|
|
||||||
if (nullable)
|
|
||||||
sb.append("?");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final TypeInfo<?> getTypeInfo() {
|
|
||||||
if (typeInfo == null) {
|
|
||||||
// TODO: Implementation must be lazy, otherwise the result would be of an infinite size
|
|
||||||
throw new UnsupportedOperationException(); // TODO
|
|
||||||
}
|
|
||||||
return typeInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetObject getOuterObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isSubtypeOf(TypeInfoImpl<?> superType) {
|
|
||||||
if (nullable && !superType.nullable) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!superType.signature.klazz.isAssignableFrom(signature.klazz)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (superType.projections == null || superType.projections.length != projections.length) {
|
|
||||||
throw new IllegalArgumentException("inconsistent type info for the same class");
|
|
||||||
}
|
|
||||||
for (int i = 0; i < projections.length; i++) {
|
|
||||||
// TODO handle variance here
|
|
||||||
if (!projections[i].getType().equals(superType.projections[i].getType())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Signature {
|
|
||||||
final Class klazz;
|
|
||||||
|
|
||||||
List<TypeInfoProjection> variables;
|
|
||||||
Map<String,Integer> varNames;
|
|
||||||
List<TypeInfo> superTypes;
|
|
||||||
|
|
||||||
final HashMap<Class,TypeInfo> superSignatures = new HashMap<Class,TypeInfo>();
|
|
||||||
|
|
||||||
public Signature(Class klazz) {
|
|
||||||
this.klazz = klazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void afterParse() {
|
|
||||||
List<TypeInfo> myVars = variables == null ? Collections.<TypeInfo>emptyList() : new LinkedList<TypeInfo>();
|
|
||||||
if(variables != null)
|
|
||||||
for(int i = 0; i != variables.size(); ++i)
|
|
||||||
myVars.add(new TypeInfoVar(this, false, i));
|
|
||||||
|
|
||||||
for(TypeInfo superType : superTypes) {
|
|
||||||
if(superType instanceof TypeInfoImpl) {
|
|
||||||
TypeInfoImpl type = (TypeInfoImpl) superType;
|
|
||||||
Signature superSignature = Parser.parse(type.signature.klazz);
|
|
||||||
|
|
||||||
TypeInfo substituted = type.substitute(myVars);
|
|
||||||
superSignatures.put(type.signature.klazz, substituted);
|
|
||||||
|
|
||||||
List<TypeInfo> vars = Collections.emptyList();
|
|
||||||
if(superType.getProjectionCount() != 0) {
|
|
||||||
vars = new LinkedList<TypeInfo>();
|
|
||||||
for(int i=0; i != superType.getProjectionCount(); ++i) {
|
|
||||||
TypeInfo substitute = superType.getProjection(i).getType().substitute(myVars);
|
|
||||||
vars.add(substitute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Map.Entry<Class,TypeInfo> entry : superSignature.superSignatures.entrySet()) {
|
|
||||||
superSignatures.put(entry.getKey(), entry.getValue().substitute(vars));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Parser {
|
|
||||||
static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
|
||||||
static final WeakHashMap<Class,Signature> map = new WeakHashMap<Class,Signature>();
|
|
||||||
|
|
||||||
int cur;
|
|
||||||
final char [] string;
|
|
||||||
|
|
||||||
final ClassLoader classLoader;
|
|
||||||
|
|
||||||
Parser(String string, ClassLoader classLoader) {
|
|
||||||
this.classLoader = classLoader;
|
|
||||||
this.string = string.toCharArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Signature parse(Class klass) {
|
|
||||||
if(klass == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// lock.readLock().lock();
|
|
||||||
Signature sig = map.get(klass);
|
|
||||||
// lock.readLock().unlock();
|
|
||||||
if (sig == null) {
|
|
||||||
// lock.writeLock().lock();
|
|
||||||
|
|
||||||
sig = map.get(klass);
|
|
||||||
if (sig == null) {
|
|
||||||
sig = internalParse(klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Signature internalParse(Class klass) {
|
|
||||||
if(klass.isArray() && !klass.getComponentType().isPrimitive()) {
|
|
||||||
Signature signature = new ArraySignature(klass);
|
|
||||||
map.put(klass, signature);
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
JetSignature annotation = (JetSignature) klass.getAnnotation(JetSignature.class);
|
|
||||||
if(annotation != null) {
|
|
||||||
String value = annotation.value();
|
|
||||||
if(value != null) {
|
|
||||||
Parser parser = new Parser(value, klass.getClassLoader());
|
|
||||||
Class enclosingClass = klass.getEnclosingClass();
|
|
||||||
Signature signature = new Signature(klass);
|
|
||||||
map.put(klass, signature);
|
|
||||||
parser.parseVars(signature);
|
|
||||||
parser.parseTypes(signature);
|
|
||||||
signature.afterParse();
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getGenericSignature(klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Signature getGenericSignature(Class klass) {
|
|
||||||
// todo complete impl
|
|
||||||
|
|
||||||
java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass();
|
|
||||||
Signature signature = new Signature(klass);
|
|
||||||
|
|
||||||
TypeVariable[] typeParameters = klass.getTypeParameters();
|
|
||||||
if(typeParameters == null || typeParameters.length == 0) {
|
|
||||||
signature.varNames = Collections.emptyMap();
|
|
||||||
signature.variables = Collections.emptyList();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
signature.varNames = new HashMap<String, Integer>();
|
|
||||||
signature.variables = new LinkedList<TypeInfoProjection>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeParameters != null && typeParameters.length != 0) {
|
|
||||||
for (int i = 0; i < typeParameters.length; i++) {
|
|
||||||
TypeVariable typeParameter = typeParameters[i];
|
|
||||||
signature.varNames.put(typeParameter.getName(), i);
|
|
||||||
final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, false, i);
|
|
||||||
signature.variables.add(new TypeInfoProjection(){
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return TypeInfoVariance.INVARIANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return typeInfoVar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return typeInfoVar.toString();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseVars(Signature signature) {
|
|
||||||
if (cur < string.length && string[cur] == '<') {
|
|
||||||
cur++;
|
|
||||||
while(cur < string.length && string[cur] != '>') {
|
|
||||||
if(signature.variables == null) {
|
|
||||||
signature.variables = new LinkedList<TypeInfoProjection>();
|
|
||||||
signature.varNames = new HashMap<String, Integer>();
|
|
||||||
}
|
|
||||||
signature.variables.add(parseVar(signature));
|
|
||||||
}
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
signature.variables = signature.variables == null ? Collections.<TypeInfoProjection>emptyList() : signature.variables;
|
|
||||||
signature.varNames = signature.varNames == null ? Collections.<String,Integer>emptyMap() : signature.varNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfoProjection parseVar(Signature signature) {
|
|
||||||
final TypeInfoVariance variance = parseVariance();
|
|
||||||
String name = parseName();
|
|
||||||
final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, signature.variables.size());
|
|
||||||
signature.varNames.put(name, signature.variables.size());
|
|
||||||
return new TypeInfoProjection(){
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return variance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return typeInfoVar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return typeInfoVar.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseName() {
|
|
||||||
int c = cur;
|
|
||||||
while (string[c] != ';') {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
String name = new String(string, cur, c - cur);
|
|
||||||
cur = c+1;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfoVariance parseVariance() {
|
|
||||||
if(string[cur] == 'i' && string[cur+1] == 'n' && string[cur+2] == ' ' ) {
|
|
||||||
cur += 3;
|
|
||||||
return TypeInfoVariance.IN;
|
|
||||||
}
|
|
||||||
else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+3] == ' ') {
|
|
||||||
cur += 4;
|
|
||||||
return TypeInfoVariance.OUT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return TypeInfoVariance.INVARIANT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseTypes(Signature signature) {
|
|
||||||
List<TypeInfo> types = null;
|
|
||||||
while(cur != string.length) {
|
|
||||||
if(types == null) {
|
|
||||||
types = new LinkedList<TypeInfo>();
|
|
||||||
}
|
|
||||||
types.add(parseType(signature));
|
|
||||||
}
|
|
||||||
signature.superTypes = types == null ? Collections.<TypeInfo>emptyList() : types;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfo parseType(Signature signature) {
|
|
||||||
switch (string[cur]) {
|
|
||||||
case 'L':
|
|
||||||
cur++;
|
|
||||||
String name = parseName();
|
|
||||||
Class<?> aClass;
|
|
||||||
try {
|
|
||||||
aClass = classLoader.loadClass(name.replace('/','.'));
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
List<TypeInfoProjection> proj = null;
|
|
||||||
boolean nullable = false;
|
|
||||||
if(cur != string.length && string[cur] == '<') {
|
|
||||||
cur++;
|
|
||||||
while(string[cur] != '>') {
|
|
||||||
if(proj == null)
|
|
||||||
proj = new LinkedList<TypeInfoProjection>();
|
|
||||||
proj.add(parseProjection(signature));
|
|
||||||
}
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
if(cur != string.length && string[cur] == '?') {
|
|
||||||
cur++;
|
|
||||||
nullable = true;
|
|
||||||
}
|
|
||||||
if(proj == null)
|
|
||||||
proj = Collections.emptyList();
|
|
||||||
return new TypeInfoImpl(aClass, nullable,proj.toArray(new TypeInfoProjection[proj.size()]));
|
|
||||||
|
|
||||||
case 'T':
|
|
||||||
cur++;
|
|
||||||
return parseTypeVar(signature);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException(new String(string));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfo parseTypeVar(Signature signature) {
|
|
||||||
TypeInfoVariance variance = parseVariance();
|
|
||||||
assert string[cur] == 'L';
|
|
||||||
cur++;
|
|
||||||
String klazz = parseName().replace('/','.');
|
|
||||||
String name = parseName();
|
|
||||||
boolean nullable = false;
|
|
||||||
if(string[cur] == '?') {
|
|
||||||
nullable = true;
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(klazz.equals(signature.klazz.getName()))
|
|
||||||
return new TypeInfoVar(signature, nullable, signature.varNames.get(name));
|
|
||||||
else {
|
|
||||||
// Signature sig = signature;
|
|
||||||
// while(!klazz.equals(sig.klazz.getName())) {
|
|
||||||
// sig = sig.outer;
|
|
||||||
// if(sig == null)
|
|
||||||
// throw new IllegalStateException();
|
|
||||||
// }
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("outer type info does not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInfoProjection parseProjection(Signature signature) {
|
|
||||||
final TypeInfoVariance variance = parseVariance();
|
|
||||||
final TypeInfo type = parseType(signature);
|
|
||||||
return new TypeInfoProjection(){
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return variance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return type.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ArraySignature extends Signature {
|
|
||||||
public ArraySignature(Class klass) {
|
|
||||||
super(klass);
|
|
||||||
variables = new LinkedList<TypeInfoProjection>();
|
|
||||||
varNames = new HashMap<String, Integer>();
|
|
||||||
varNames.put("T", 0);
|
|
||||||
final TypeInfoVar typeInfoVar = new TypeInfoVar(this, 0);
|
|
||||||
variables.add(new TypeInfoProjection(){
|
|
||||||
@Override
|
|
||||||
public TypeInfoVariance getVariance() {
|
|
||||||
return TypeInfoVariance.INVARIANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeInfo getType() {
|
|
||||||
return typeInfoVar;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,38 +12,4 @@ public interface TypeInfoProjection {
|
|||||||
|
|
||||||
TypeInfo getType();
|
TypeInfo getType();
|
||||||
|
|
||||||
abstract class TypeInfoProjectionImpl implements TypeInfoProjection {
|
|
||||||
private final TypeInfo type;
|
|
||||||
|
|
||||||
TypeInfoProjectionImpl(TypeInfo typeInfo) {
|
|
||||||
this.type = typeInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final TypeInfo getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
|
|
||||||
TypeInfoProjectionImpl that = (TypeInfoProjectionImpl) o;
|
|
||||||
// no need to compare variance as we compared classes already
|
|
||||||
return type.equals(that.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
int result = type.hashCode();
|
|
||||||
result = 31 * result + (getVariance().hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return (getVariance() == TypeInfoVariance.INVARIANT ? "" : getVariance().toString() + " ") + type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
class Signature {
|
||||||
|
|
||||||
|
// TODO: make all these fields private
|
||||||
|
|
||||||
|
final Class klazz;
|
||||||
|
|
||||||
|
List<TypeInfoProjection> variables;
|
||||||
|
Map<String,Integer> varNames;
|
||||||
|
List<TypeInfo> superTypes;
|
||||||
|
|
||||||
|
HashMap<Class,TypeInfo> superSignatures = new HashMap<Class,TypeInfo>();
|
||||||
|
|
||||||
|
Signature(Class klazz) {
|
||||||
|
this.klazz = klazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afterParse() {
|
||||||
|
List<TypeInfo> myVars = variables == null ? Collections.<TypeInfo>emptyList() : new LinkedList<TypeInfo>();
|
||||||
|
if(variables != null)
|
||||||
|
for(int i = 0; i != variables.size(); ++i)
|
||||||
|
myVars.add(new TypeInfoVar(this, false, i));
|
||||||
|
|
||||||
|
for(TypeInfo superType : superTypes) {
|
||||||
|
if(superType instanceof TypeInfoImpl) {
|
||||||
|
TypeInfoImpl type = (TypeInfoImpl) superType;
|
||||||
|
Signature superSignature = TypeInfoParser.parse(type.signature.klazz);
|
||||||
|
|
||||||
|
TypeInfo substituted = TypeInfoUtils.substitute(type, myVars);
|
||||||
|
superSignatures.put(type.signature.klazz, substituted);
|
||||||
|
|
||||||
|
List<TypeInfo> vars = Collections.emptyList();
|
||||||
|
if(superType.getProjectionCount() != 0) {
|
||||||
|
vars = new LinkedList<TypeInfo>();
|
||||||
|
for(int i=0; i != superType.getProjectionCount(); ++i) {
|
||||||
|
TypeInfo substitute = TypeInfoUtils.substitute(superType.getProjection(i).getType(), myVars);
|
||||||
|
vars.add(substitute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Map.Entry<Class,TypeInfo> entry : superSignature.superSignatures.entrySet()) {
|
||||||
|
superSignatures.put(entry.getKey(), TypeInfoUtils.substitute(entry.getValue(), vars));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.JetObject;
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
* @author yole
|
||||||
|
* @author alex.tkachman
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
public class TypeInfoImpl<T> extends TypeInfo<T> implements TypeInfoProjection {
|
||||||
|
private final static TypeInfoProjection[] EMPTY = new TypeInfoProjection[0];
|
||||||
|
|
||||||
|
private TypeInfo<?> typeInfo;
|
||||||
|
public final Signature signature;
|
||||||
|
private final boolean nullable;
|
||||||
|
private final TypeInfoProjection[] projections;
|
||||||
|
|
||||||
|
public TypeInfoImpl(Class<T> theClass, boolean nullable) {
|
||||||
|
this(theClass, nullable, EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfoImpl(Class<T> theClass, boolean nullable, TypeInfoProjection[] projections) {
|
||||||
|
this.signature = TypeInfoParser.parse(theClass);
|
||||||
|
this.nullable = nullable;
|
||||||
|
this.projections = projections;
|
||||||
|
if(signature.variables.size() != projections.length)
|
||||||
|
throw new IllegalStateException("Wrong signature " + theClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final TypeInfoProjection getProjection(int index) {
|
||||||
|
return projections[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] newArray(int length) {
|
||||||
|
return (Object[]) Array.newInstance(signature.klazz, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getJavaClass() {
|
||||||
|
return signature.klazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Object getClassObject() {
|
||||||
|
try {
|
||||||
|
final Class implClass = signature.klazz.getClassLoader().loadClass(signature.klazz.getCanonicalName());
|
||||||
|
final Field classobj = implClass.getField("$classobj");
|
||||||
|
return classobj.get(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo getSuperTypeInfo(Class klass) {
|
||||||
|
return signature.superSignatures.get(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final TypeInfo getArgumentType(Class klass, int index) {
|
||||||
|
if(klass == this.signature.klazz)
|
||||||
|
return projections[index].getType();
|
||||||
|
else {
|
||||||
|
return TypeInfoUtils.substitute(getSuperTypeInfo(klass), projections).getArgumentType(klass, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo substitute(final List<TypeInfo> myVars) {
|
||||||
|
if(projections.length == 0)
|
||||||
|
return new TypeInfoImpl(this.signature.klazz, nullable, EMPTY);
|
||||||
|
else {
|
||||||
|
TypeInfoProjection [] proj = new TypeInfoProjection[projections.length];
|
||||||
|
for(int i = 0; i != proj.length; ++i) {
|
||||||
|
final int finalI = i;
|
||||||
|
final TypeInfo substitute = TypeInfoUtils.substitute(projections[finalI].getType(), myVars);
|
||||||
|
proj[i] = new TypeInfoProjection(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return projections[finalI].getVariance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return substitute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getVariance().toString() + " " + substitute;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new TypeInfoImpl(this.signature.klazz, nullable, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo substitute(TypeInfoProjection[] prj) {
|
||||||
|
if(projections.length == 0)
|
||||||
|
return new TypeInfoImpl(signature.klazz, nullable, EMPTY);
|
||||||
|
else {
|
||||||
|
TypeInfoProjection [] proj = new TypeInfoProjection[projections.length];
|
||||||
|
for(int i = 0; i != proj.length; ++i) {
|
||||||
|
final int finalI = i;
|
||||||
|
final TypeInfo substitute = TypeInfoUtils.substitute(projections[finalI].getType(), prj);
|
||||||
|
proj[i] = new TypeInfoProjection(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return projections[finalI].getVariance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return substitute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getVariance().toString() + " " + substitute;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new TypeInfoImpl(signature.klazz, nullable, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
TypeInfoImpl typeInfo = (TypeInfoImpl) o;
|
||||||
|
|
||||||
|
if (!signature.klazz.equals(typeInfo.signature.klazz)) return false;
|
||||||
|
if (nullable != typeInfo.nullable) return false;
|
||||||
|
if (!Arrays.equals(projections, typeInfo.projections)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @NotNull
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return TypeInfoVariance.INVARIANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @NotNull
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return 31 * signature.klazz.hashCode() + Arrays.hashCode(projections);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isInstance(Object obj) {
|
||||||
|
if (obj == null) return nullable;
|
||||||
|
|
||||||
|
if (obj instanceof JetObject) {
|
||||||
|
return ((TypeInfoImpl)((JetObject) obj).getTypeInfo()).isSubtypeOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature.klazz.isAssignableFrom(obj.getClass()); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProjectionCount() {
|
||||||
|
return projections.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder().append(signature.klazz.getName());
|
||||||
|
if (projections.length != 0) {
|
||||||
|
sb.append("<");
|
||||||
|
for (int i = 0; i != projections.length - 1; ++i) {
|
||||||
|
sb.append(projections[i].toString()).append(",");
|
||||||
|
}
|
||||||
|
sb.append(projections[projections.length - 1].toString()).append(">");
|
||||||
|
}
|
||||||
|
if (nullable)
|
||||||
|
sb.append("?");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final TypeInfo<?> getTypeInfo() {
|
||||||
|
if (typeInfo == null) {
|
||||||
|
// TODO: Implementation must be lazy, otherwise the result would be of an infinite size
|
||||||
|
throw new UnsupportedOperationException(); // TODO
|
||||||
|
}
|
||||||
|
return typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetObject getOuterObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSubtypeOf(TypeInfoImpl<?> superType) {
|
||||||
|
if (nullable && !superType.nullable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!superType.signature.klazz.isAssignableFrom(signature.klazz)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (superType.projections == null || superType.projections.length != projections.length) {
|
||||||
|
throw new IllegalArgumentException("inconsistent type info for the same class");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < projections.length; i++) {
|
||||||
|
// TODO handle variance here
|
||||||
|
if (!projections[i].getType().equals(superType.projections[i].getType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.typeinfo.JetSignature;
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
import jet.typeinfo.internal.signature.JetSignatureExceptionsAdapter;
|
||||||
|
import jet.typeinfo.internal.signature.JetSignatureReader;
|
||||||
|
import jet.typeinfo.internal.signature.JetSignatureVisitor;
|
||||||
|
|
||||||
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
class TypeInfoParser {
|
||||||
|
static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
static final WeakHashMap<Class,Signature> map = new WeakHashMap<Class,Signature>();
|
||||||
|
|
||||||
|
public static Signature parse(Class klass) {
|
||||||
|
if(klass == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// lock.readLock().lock();
|
||||||
|
Signature sig = map.get(klass);
|
||||||
|
// lock.readLock().unlock();
|
||||||
|
if (sig == null) {
|
||||||
|
// lock.writeLock().lock();
|
||||||
|
|
||||||
|
sig = map.get(klass);
|
||||||
|
if (sig == null) {
|
||||||
|
sig = internalParse(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Signature internalParse(Class klass) {
|
||||||
|
if(klass.isArray() && !klass.getComponentType().isPrimitive()) {
|
||||||
|
Signature signature = new ArraySignature(klass);
|
||||||
|
map.put(klass, signature);
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
JetSignature annotation = (JetSignature) klass.getAnnotation(JetSignature.class);
|
||||||
|
if(annotation != null) {
|
||||||
|
String value = annotation.value();
|
||||||
|
if(value != null) {
|
||||||
|
Class enclosingClass = klass.getEnclosingClass();
|
||||||
|
Signature signature = new Signature(klass);
|
||||||
|
map.put(klass, signature);
|
||||||
|
parse(value, signature);
|
||||||
|
signature.afterParse();
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getGenericSignature(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parse(String annotationValue, final Signature signature) {
|
||||||
|
signature.variables = new ArrayList<TypeInfoProjection>();
|
||||||
|
signature.varNames = new HashMap<String, Integer>();
|
||||||
|
signature.superTypes = new ArrayList<TypeInfo>();
|
||||||
|
new JetSignatureReader(annotationValue).accept(new JetSignatureExceptionsAdapter() {
|
||||||
|
int varIndex = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitFormalTypeParameter(String name, final TypeInfoVariance variance) {
|
||||||
|
|
||||||
|
final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, signature.variables.size());
|
||||||
|
|
||||||
|
signature.varNames.put(name, signature.variables.size());
|
||||||
|
TypeInfoProjection typeInfoProjection = new TypeInfoProjection() {
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return variance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return typeInfoVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return typeInfoVar.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
signature.variables.add(typeInfoProjection);
|
||||||
|
// TODO: supers
|
||||||
|
// TODO: nullability
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitClassBound() {
|
||||||
|
return new SignatureParserJetSignatureAdapter(signature.klazz.getClassLoader(), signature) {
|
||||||
|
@Override
|
||||||
|
protected void done(TypeInfo typeInfo) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitInterfaceBound() {
|
||||||
|
return new SignatureParserJetSignatureAdapter(signature.klazz.getClassLoader(), signature) {
|
||||||
|
@Override
|
||||||
|
protected void done(TypeInfo typeInfo) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitSuperclass() {
|
||||||
|
return new SignatureParserJetSignatureAdapter(signature.klazz.getClassLoader(), signature) {
|
||||||
|
@Override
|
||||||
|
protected void done(TypeInfo typeInfo) {
|
||||||
|
signature.superTypes.add(typeInfo);
|
||||||
|
signature.superSignatures.put(typeInfo.getJavaClass(), typeInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitInterface() {
|
||||||
|
return new SignatureParserJetSignatureAdapter(signature.klazz.getClassLoader(), signature) {
|
||||||
|
@Override
|
||||||
|
protected void done(TypeInfo typeInfo) {
|
||||||
|
signature.superTypes.add(typeInfo);
|
||||||
|
signature.superSignatures.put(typeInfo.getJavaClass(), typeInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static abstract class SignatureParserJetSignatureAdapter extends JetSignatureExceptionsAdapter {
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
private final Signature signature;
|
||||||
|
|
||||||
|
protected SignatureParserJetSignatureAdapter(ClassLoader classLoader, Signature signature) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void done(TypeInfo typeInfo);
|
||||||
|
|
||||||
|
private Class<?> klass;
|
||||||
|
private boolean nullable;
|
||||||
|
private List<TypeInfoProjection> projections;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitClassType(String name, boolean nullable) {
|
||||||
|
try {
|
||||||
|
klass = classLoader.loadClass(name.replace('/', '.'));
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
this.nullable = nullable;
|
||||||
|
this.projections = new ArrayList<TypeInfoProjection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeInfoVariance parseVariance(char wildcard) {
|
||||||
|
switch (wildcard) {
|
||||||
|
case '=': return TypeInfoVariance.INVARIANT;
|
||||||
|
case '+': return TypeInfoVariance.OUT;
|
||||||
|
case '-': return TypeInfoVariance.IN;
|
||||||
|
default: throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitTypeArgument(final char wildcard) {
|
||||||
|
final TypeInfoVariance variance = parseVariance(wildcard);
|
||||||
|
return new SignatureParserJetSignatureAdapter(classLoader, signature) {
|
||||||
|
@Override
|
||||||
|
protected void done(TypeInfo typeInfo) {
|
||||||
|
projections.add(new TypeInfoProjectionImpl(typeInfo) {
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return variance;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeVariable(String name, boolean nullable) {
|
||||||
|
Integer varIndex = signature.varNames.get(name);
|
||||||
|
if (varIndex == null) {
|
||||||
|
throw new IllegalStateException("unresolved type variable: " + name);
|
||||||
|
}
|
||||||
|
TypeInfoVar typeInfo = new TypeInfoVar(signature, nullable, varIndex);
|
||||||
|
done(typeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
done(new TypeInfoImpl(klass, nullable, projections.toArray(new TypeInfoProjection[0])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Signature getGenericSignature(Class klass) {
|
||||||
|
// todo complete impl
|
||||||
|
|
||||||
|
java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass();
|
||||||
|
Signature signature = new Signature(klass);
|
||||||
|
|
||||||
|
TypeVariable[] typeParameters = klass.getTypeParameters();
|
||||||
|
if(typeParameters == null || typeParameters.length == 0) {
|
||||||
|
signature.varNames = Collections.emptyMap();
|
||||||
|
signature.variables = Collections.emptyList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
signature.varNames = new HashMap<String, Integer>();
|
||||||
|
signature.variables = new LinkedList<TypeInfoProjection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeParameters != null && typeParameters.length != 0) {
|
||||||
|
for (int i = 0; i < typeParameters.length; i++) {
|
||||||
|
TypeVariable typeParameter = typeParameters[i];
|
||||||
|
signature.varNames.put(typeParameter.getName(), i);
|
||||||
|
final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, false, i);
|
||||||
|
signature.variables.add(new TypeInfoProjection(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return TypeInfoVariance.INVARIANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return typeInfoVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return typeInfoVar.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ArraySignature extends Signature {
|
||||||
|
public ArraySignature(Class klass) {
|
||||||
|
super(klass);
|
||||||
|
variables = new LinkedList<TypeInfoProjection>();
|
||||||
|
varNames = new HashMap<String, Integer>();
|
||||||
|
varNames.put("T", 0);
|
||||||
|
final TypeInfoVar typeInfoVar = new TypeInfoVar(this, 0);
|
||||||
|
variables.add(new TypeInfoProjection() {
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return TypeInfoVariance.INVARIANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return typeInfoVar;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
* @author yole
|
||||||
|
* @author alex.tkachman
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
public abstract class TypeInfoProjectionImpl implements TypeInfoProjection {
|
||||||
|
private final TypeInfo type;
|
||||||
|
|
||||||
|
public TypeInfoProjectionImpl(TypeInfo typeInfo) {
|
||||||
|
this.type = typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final TypeInfo getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
jet.typeinfo.internal.TypeInfoProjectionImpl that = (jet.typeinfo.internal.TypeInfoProjectionImpl) o;
|
||||||
|
// no need to compare variance as we compared classes already
|
||||||
|
return type.equals(that.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
int result = type.hashCode();
|
||||||
|
result = 31 * result + (getVariance().hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return (getVariance() == TypeInfoVariance.INVARIANT ? "" : getVariance().toString() + " ") + type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
* @author yole
|
||||||
|
* @author alex.tkachman
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
class TypeInfoUtils {
|
||||||
|
|
||||||
|
static TypeInfo<?> substitute(TypeInfo<?> typeInfo, TypeInfoProjection[] projections) {
|
||||||
|
if (typeInfo instanceof TypeInfoImpl<?>) {
|
||||||
|
TypeInfoImpl<?> typeInfoImpl = (TypeInfoImpl<?>) typeInfo;
|
||||||
|
return typeInfoImpl.substitute(projections);
|
||||||
|
} else if (typeInfo instanceof TypeInfoVar<?>) {
|
||||||
|
TypeInfoVar<?> typeInfoVar = (TypeInfoVar<?>) typeInfo;
|
||||||
|
return typeInfoVar.substitute(projections);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeInfo<?> substitute(TypeInfo<?> typeInfo, List<TypeInfo> myVars) {
|
||||||
|
if (typeInfo instanceof TypeInfoImpl<?>) {
|
||||||
|
TypeInfoImpl<?> typeInfoImpl = (TypeInfoImpl<?>) typeInfo;
|
||||||
|
return typeInfoImpl.substitute(myVars);
|
||||||
|
} else if (typeInfo instanceof TypeInfoVar<?>) {
|
||||||
|
TypeInfoVar<?> typeInfoVar = (TypeInfoVar<?>) typeInfo;
|
||||||
|
return typeInfoVar.substitute(myVars);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package jet.typeinfo.internal;
|
||||||
|
|
||||||
|
import jet.JetObject;
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
import jet.typeinfo.TypeInfoProjection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
* @author yole
|
||||||
|
* @author alex.tkachman
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
class TypeInfoVar<T> extends TypeInfo<T> {
|
||||||
|
final int varIndex;
|
||||||
|
final Signature signature;
|
||||||
|
final boolean nullable;
|
||||||
|
|
||||||
|
public TypeInfoVar(Signature signature, Integer varIndex) {
|
||||||
|
this.signature = signature;
|
||||||
|
this.varIndex = varIndex;
|
||||||
|
nullable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfoVar(Signature signature, boolean nullable, int varIndex) {
|
||||||
|
this.signature = signature;
|
||||||
|
this.nullable = nullable;
|
||||||
|
this.varIndex = varIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] newArray(int length) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getJavaClass() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getClassObject() {
|
||||||
|
throw new UnsupportedOperationException("Abstract TypeInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInstance(Object obj) {
|
||||||
|
throw new UnsupportedOperationException("Abstract TypeInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProjectionCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfoProjection getProjection(int index) {
|
||||||
|
throw new UnsupportedOperationException("Abstract TypeInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getArgumentType(Class klass, int index) {
|
||||||
|
throw new UnsupportedOperationException("Abstract TypeInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo substitute(List<TypeInfo> myVars) {
|
||||||
|
return myVars.get(varIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo substitute(TypeInfoProjection[] projections) {
|
||||||
|
return projections[varIndex].getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo<?> getTypeInfo() {
|
||||||
|
throw new UnsupportedOperationException("Abstract TypeInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetObject getOuterObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "T:" + signature.klazz.getName() + ":" + varIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package jet.typeinfo.internal.signature;
|
||||||
|
|
||||||
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
public class JetSignatureExceptionsAdapter implements JetSignatureVisitor {
|
||||||
|
@Override
|
||||||
|
public void visitFormalTypeParameter(String name, TypeInfoVariance variance) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitClassBound() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitInterfaceBound() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitSuperclass() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitInterface() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitParameterType() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitReturnType() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitExceptionType() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBaseType(char descriptor, boolean nullable) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeVariable(String name, boolean nullable) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitArrayType(boolean nullable) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitClassType(String name, boolean nullable) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInnerClassType(String name, boolean nullable) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeArgument() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetSignatureVisitor visitTypeArgument(char wildcard) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,39 +19,7 @@ public class JetSignatureReader {
|
|||||||
public void accept(final JetSignatureVisitor v) {
|
public void accept(final JetSignatureVisitor v) {
|
||||||
String signature = this.signature;
|
String signature = this.signature;
|
||||||
int len = signature.length();
|
int len = signature.length();
|
||||||
int pos;
|
int pos = acceptFormalTypeParameters(v);
|
||||||
char c;
|
|
||||||
|
|
||||||
if (signature.charAt(0) == '<') {
|
|
||||||
pos = 2;
|
|
||||||
do {
|
|
||||||
TypeInfoVariance variance;
|
|
||||||
if (signature.substring(pos).startsWith("in ")) {
|
|
||||||
variance = TypeInfoVariance.IN;
|
|
||||||
pos += "in ".length();
|
|
||||||
} else if (signature.substring(pos).startsWith("out ")) {
|
|
||||||
variance = TypeInfoVariance.OUT;
|
|
||||||
pos += "out ".length();
|
|
||||||
} else {
|
|
||||||
variance = TypeInfoVariance.INVARIANT;
|
|
||||||
pos += "".length();
|
|
||||||
}
|
|
||||||
int end = signature.indexOf(':', pos);
|
|
||||||
v.visitFormalTypeParameter(signature.substring(pos - 1, end), variance);
|
|
||||||
pos = end + 1;
|
|
||||||
|
|
||||||
c = signature.charAt(pos);
|
|
||||||
if (c == 'L' || c == '[' || c == 'T') {
|
|
||||||
pos = parseType(signature, pos, v.visitClassBound());
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((c = signature.charAt(pos++)) == ':') {
|
|
||||||
pos = parseType(signature, pos, v.visitInterfaceBound());
|
|
||||||
}
|
|
||||||
} while (c != '>');
|
|
||||||
} else {
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signature.charAt(pos) == '(') {
|
if (signature.charAt(pos) == '(') {
|
||||||
pos++;
|
pos++;
|
||||||
@@ -70,6 +38,52 @@ public class JetSignatureReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int acceptFormalTypeParameters(JetSignatureVisitor v) {
|
||||||
|
int pos;
|
||||||
|
char c;
|
||||||
|
if (signature.length() > 0 && signature.charAt(0) == '<') {
|
||||||
|
pos = 1;
|
||||||
|
do {
|
||||||
|
TypeInfoVariance variance;
|
||||||
|
if (signature.substring(pos).startsWith("in ")) {
|
||||||
|
variance = TypeInfoVariance.IN;
|
||||||
|
pos += "in ".length();
|
||||||
|
} else if (signature.substring(pos).startsWith("out ")) {
|
||||||
|
variance = TypeInfoVariance.OUT;
|
||||||
|
pos += "out ".length();
|
||||||
|
} else {
|
||||||
|
variance = TypeInfoVariance.INVARIANT;
|
||||||
|
pos += "".length();
|
||||||
|
}
|
||||||
|
int end = signature.indexOf(':', pos);
|
||||||
|
if (end < 0) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
v.visitFormalTypeParameter(signature.substring(pos, end), variance);
|
||||||
|
pos = end + 1;
|
||||||
|
|
||||||
|
c = signature.charAt(pos);
|
||||||
|
if (c == 'L' || c == '[' || c == 'T' || c == '?') {
|
||||||
|
pos = parseType(signature, pos, v.visitClassBound());
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = signature.charAt(pos++)) == ':') {
|
||||||
|
pos = parseType(signature, pos, v.visitInterfaceBound());
|
||||||
|
}
|
||||||
|
} while (c != '>');
|
||||||
|
} else {
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptFormalTypeParametersOnly(JetSignatureVisitor v) {
|
||||||
|
int r = acceptFormalTypeParameters(v);
|
||||||
|
if (r != signature.length()) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int acceptType(JetSignatureVisitor v) {
|
public int acceptType(JetSignatureVisitor v) {
|
||||||
return parseType(this.signature, 0, v);
|
return parseType(this.signature, 0, v);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user