work in progress on type info
This commit is contained in:
@@ -10,12 +10,8 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
|||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||||
import org.jetbrains.jet.lang.types.Variance;
|
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.*;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
import org.objectweb.asm.commons.InstructionAdapter;
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
import org.objectweb.asm.commons.Method;
|
import org.objectweb.asm.commons.Method;
|
||||||
|
|
||||||
@@ -101,6 +97,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
interfaces.toArray(new String[interfaces.size()])
|
interfaces.toArray(new String[interfaces.size()])
|
||||||
);
|
);
|
||||||
v.visitSource(myClass.getContainingFile().getName(), null);
|
v.visitSource(myClass.getContainingFile().getName(), null);
|
||||||
|
|
||||||
|
if(myClass instanceof JetClass) {
|
||||||
|
AnnotationVisitor annotationVisitor = v.visitAnnotation("Ljet/typeinfo/JetSignature;", true);
|
||||||
|
annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, state.getBindingContext(), state.getTypeMapper()));
|
||||||
|
annotationVisitor.visitEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String jvmName() {
|
private String jvmName() {
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import jet.typeinfo.TypeInfoVariance;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
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.resolve.java.JavaClassDescriptor;
|
||||||
|
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 {
|
||||||
|
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();
|
||||||
|
org.objectweb.asm.Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION);
|
||||||
|
if(JetTypeMapper.isPrimitive(type)) {
|
||||||
|
type = JetTypeMapper.boxType(type);
|
||||||
|
}
|
||||||
|
sb.append(type.getDescriptor());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.append("T").append(descriptor.getName()).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();
|
||||||
|
for(JetTypeParameter param : parameters) {
|
||||||
|
sb.append("T");
|
||||||
|
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(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package jet.typeinfo;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alex.tkachman
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface JetSignature {
|
||||||
|
String value();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@ import jet.JetObject;
|
|||||||
import jet.Tuple0;
|
import jet.Tuple0;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -12,6 +14,8 @@ import java.util.Arrays;
|
|||||||
* @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);
|
||||||
public static final TypeInfo<Integer> INT_TYPE_INFO = getTypeInfo(Integer.class, false);
|
public static final TypeInfo<Integer> INT_TYPE_INFO = getTypeInfo(Integer.class, false);
|
||||||
@@ -35,20 +39,20 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
public static final TypeInfo<Tuple0> NULLABLE_TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, true);
|
public static final TypeInfo<Tuple0> NULLABLE_TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, true);
|
||||||
|
|
||||||
private TypeInfo<?> typeInfo;
|
private TypeInfo<?> typeInfo;
|
||||||
private final Class<T> theClass;
|
private final Signature signature;
|
||||||
private final boolean nullable;
|
private final boolean nullable;
|
||||||
private final TypeInfoProjection[] projections;
|
private final TypeInfoProjection[] projections;
|
||||||
|
|
||||||
private TypeInfo(Class<T> theClass, boolean nullable) {
|
private TypeInfo(Class<T> theClass, boolean nullable) {
|
||||||
this.theClass = theClass;
|
this(theClass, nullable, EMPTY);
|
||||||
this.nullable = nullable;
|
|
||||||
this.projections = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeInfo(Class<T> theClass, boolean nullable, TypeInfoProjection[] projections) {
|
private TypeInfo(Class<T> theClass, boolean nullable, TypeInfoProjection[] projections) {
|
||||||
this.theClass = theClass;
|
this.signature = Parser.parse(theClass);
|
||||||
this.nullable = nullable;
|
this.nullable = nullable;
|
||||||
this.projections = projections;
|
this.projections = projections;
|
||||||
|
if(signature.variables.size() != projections.length)
|
||||||
|
throw new IllegalStateException("Wrong signature " + theClass.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TypeInfoProjection invariantProjection(final TypeInfo<T> typeInfo) {
|
public static <T> TypeInfoProjection invariantProjection(final TypeInfo<T> typeInfo) {
|
||||||
@@ -85,7 +89,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
|
|
||||||
public final Object getClassObject() {
|
public final Object getClassObject() {
|
||||||
try {
|
try {
|
||||||
final Class implClass = theClass.getClassLoader().loadClass(theClass.getCanonicalName());
|
final Class implClass = signature.klazz.getClassLoader().loadClass(signature.klazz.getCanonicalName());
|
||||||
final Field classobj = implClass.getField("$classobj");
|
final Field classobj = implClass.getField("$classobj");
|
||||||
return classobj.get(null);
|
return classobj.get(null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -100,25 +104,23 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
return ((JetObject) obj).getTypeInfo().isSubtypeOf(this);
|
return ((JetObject) obj).getTypeInfo().isSubtypeOf(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return theClass.isAssignableFrom(obj.getClass()); // TODO
|
return signature.klazz.isAssignableFrom(obj.getClass()); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isSubtypeOf(TypeInfo<?> superType) {
|
public final boolean isSubtypeOf(TypeInfo<?> superType) {
|
||||||
if (nullable && !superType.nullable) {
|
if (nullable && !superType.nullable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!superType.theClass.isAssignableFrom(theClass)) {
|
if (!superType.signature.klazz.isAssignableFrom(signature.klazz)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (projections != null) {
|
if (superType.projections == null || superType.projections.length != projections.length) {
|
||||||
if (superType.projections == null || superType.projections.length != projections.length) {
|
throw new IllegalArgumentException("inconsistent type infos for the same class");
|
||||||
throw new IllegalArgumentException("inconsistent type infos for the same class");
|
}
|
||||||
}
|
for (int i = 0; i < projections.length; i++) {
|
||||||
for (int i = 0; i < projections.length; i++) {
|
// TODO handle variance here
|
||||||
// TODO handle variance here
|
if (!projections[i].equals(superType.projections[i])) {
|
||||||
if (!projections[i].equals(superType.projections[i])) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -148,7 +150,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
|
|
||||||
TypeInfo typeInfo = (TypeInfo) o;
|
TypeInfo typeInfo = (TypeInfo) o;
|
||||||
|
|
||||||
if (!theClass.equals(typeInfo.theClass)) return false;
|
if (!signature.klazz.equals(typeInfo.signature.klazz)) return false;
|
||||||
if (nullable != typeInfo.nullable) return false;
|
if (nullable != typeInfo.nullable) return false;
|
||||||
if (!Arrays.equals(projections, typeInfo.projections)) return false;
|
if (!Arrays.equals(projections, typeInfo.projections)) return false;
|
||||||
|
|
||||||
@@ -157,13 +159,13 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int hashCode() {
|
public final int hashCode() {
|
||||||
return 31 * theClass.hashCode() + (projections != null ? Arrays.hashCode(projections) : 0);
|
return 31 * signature.klazz.hashCode() + Arrays.hashCode(projections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
StringBuilder sb = new StringBuilder().append(theClass.getName());
|
StringBuilder sb = new StringBuilder().append(signature.klazz.getName());
|
||||||
if (projections != null && projections.length != 0) {
|
if (projections.length != 0) {
|
||||||
sb.append("<");
|
sb.append("<");
|
||||||
for (int i = 0; i != projections.length - 1; ++i) {
|
for (int i = 0; i != projections.length - 1; ++i) {
|
||||||
sb.append(projections[i].toString()).append(",");
|
sb.append(projections[i].toString()).append(",");
|
||||||
@@ -196,4 +198,261 @@ public abstract class TypeInfo<T> implements JetObject {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Signature {
|
||||||
|
final Class klazz;
|
||||||
|
final List<Var> variables;
|
||||||
|
final List<Type> superTypes;
|
||||||
|
|
||||||
|
final HashMap<Class,Signature> superSignatures = new HashMap<Class,Signature>();
|
||||||
|
|
||||||
|
public Signature(Class klazz, List<Var> variables, List<Type> superTypes) {
|
||||||
|
this.klazz = klazz;
|
||||||
|
this.superTypes = superTypes;
|
||||||
|
this.variables = variables;
|
||||||
|
|
||||||
|
for(Type superType : superTypes) {
|
||||||
|
if(superType instanceof TypeReal) {
|
||||||
|
TypeReal type = (TypeReal) superType;
|
||||||
|
Signature parse = Parser.parse(type.klazz);
|
||||||
|
superSignatures.put(type.klazz, parse);
|
||||||
|
for(Map.Entry<Class,Signature> entry : parse.superSignatures.entrySet()) {
|
||||||
|
superSignatures.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Var {
|
||||||
|
final String name;
|
||||||
|
final TypeInfoVariance variance;
|
||||||
|
|
||||||
|
public Var(String name, TypeInfoVariance variance) {
|
||||||
|
this.name = name;
|
||||||
|
this.variance = variance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class Type{
|
||||||
|
final boolean nullable;
|
||||||
|
|
||||||
|
protected Type(boolean nullable) {
|
||||||
|
this.nullable = nullable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TypeVar extends Type {
|
||||||
|
final int varIndex;
|
||||||
|
|
||||||
|
public TypeVar(boolean nullable, int varIndex) {
|
||||||
|
super(nullable);
|
||||||
|
this.varIndex = varIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TypeProj {
|
||||||
|
public final TypeInfoVariance variance;
|
||||||
|
public final Type type;
|
||||||
|
|
||||||
|
public TypeProj(TypeInfoVariance variance, Type type) {
|
||||||
|
this.variance = variance;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TypeReal extends Type {
|
||||||
|
public final Class klazz;
|
||||||
|
public final List<TypeProj> params;
|
||||||
|
|
||||||
|
public TypeReal(Class klazz, boolean nullable, List<TypeProj> params) {
|
||||||
|
super(nullable);
|
||||||
|
this.params = params;
|
||||||
|
this.klazz = klazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Map<String,Integer> variables;
|
||||||
|
|
||||||
|
final ClassLoader classLoader;
|
||||||
|
|
||||||
|
Parser(String string, ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
this.string = string.toCharArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Signature parse(Class klass) {
|
||||||
|
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);
|
||||||
|
map.put(klass, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Signature internalParse(Class klass) {
|
||||||
|
JetSignature annotation = (JetSignature) klass.getAnnotation(JetSignature.class);
|
||||||
|
if(annotation != null) {
|
||||||
|
String value = annotation.value();
|
||||||
|
if(value != null) {
|
||||||
|
Parser parser = new Parser(value, klass.getClassLoader());
|
||||||
|
return new Signature(klass, parser.parseVars(), parser.parseTypes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getGenericSignature(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Signature getGenericSignature(Class klass) {
|
||||||
|
// todo complete impl
|
||||||
|
|
||||||
|
TypeVariable[] typeParameters = klass.getTypeParameters();
|
||||||
|
Map<String,Integer> variables;
|
||||||
|
List<Var> vars;
|
||||||
|
if(typeParameters == null || typeParameters.length == 0) {
|
||||||
|
variables = Collections.emptyMap();
|
||||||
|
vars = Collections.emptyList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
variables = new HashMap<String, Integer>();
|
||||||
|
vars = new LinkedList<Var>();
|
||||||
|
for (int i = 0; i < typeParameters.length; i++) {
|
||||||
|
TypeVariable typeParameter = typeParameters[i];
|
||||||
|
variables.put(typeParameter.getName(), i);
|
||||||
|
vars.add(new Var(typeParameter.getName(), TypeInfoVariance.INVARIANT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Type> types = new LinkedList<Type>();
|
||||||
|
java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass();
|
||||||
|
return new Signature(klass, vars, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Var> parseVars() {
|
||||||
|
List<Var> list = null;
|
||||||
|
while(cur != string.length && string[cur] == 'T') {
|
||||||
|
if(list == null)
|
||||||
|
list = new LinkedList<Var>();
|
||||||
|
list.add(parseVar());
|
||||||
|
}
|
||||||
|
List<Var> vars = list == null ? Collections.<Var>emptyList() : list;
|
||||||
|
if(vars.isEmpty())
|
||||||
|
variables = Collections.emptyMap();
|
||||||
|
else {
|
||||||
|
variables = new HashMap<String, Integer>();
|
||||||
|
for(int i=0; i != list.size(); ++i) {
|
||||||
|
variables.put(list.get(i).name, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Var parseVar() {
|
||||||
|
TypeInfoVariance variance = parseVariance();
|
||||||
|
String name = parseName();
|
||||||
|
return new Var(name, variance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseName() {
|
||||||
|
int c = ++cur; // skip 'T'
|
||||||
|
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_VARIANCE;
|
||||||
|
}
|
||||||
|
else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+2] == ' ') {
|
||||||
|
cur += 4;
|
||||||
|
return TypeInfoVariance.OUT_VARIANCE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return TypeInfoVariance.INVARIANT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Type> parseTypes() {
|
||||||
|
List<Type> types = null;
|
||||||
|
while(cur != string.length) {
|
||||||
|
if(types == null) {
|
||||||
|
types = new LinkedList<Type>();
|
||||||
|
}
|
||||||
|
types.add(parseType());
|
||||||
|
}
|
||||||
|
return types == null ? Collections.<Type>emptyList() : types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type parseType() {
|
||||||
|
switch (string[cur]) {
|
||||||
|
case 'L':
|
||||||
|
String name = parseName();
|
||||||
|
Class<?> aClass;
|
||||||
|
try {
|
||||||
|
aClass = classLoader.loadClass(name.replace('/','.'));
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
List<TypeProj> proj = null;
|
||||||
|
boolean nullable = false;
|
||||||
|
if(cur != string.length && string[cur] == '<') {
|
||||||
|
cur++;
|
||||||
|
while(string[cur] != '>') {
|
||||||
|
if(proj == null)
|
||||||
|
proj = new LinkedList<TypeProj>();
|
||||||
|
proj.add(parseProjection());
|
||||||
|
}
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
if(cur != string.length && string[cur] == '?') {
|
||||||
|
cur++;
|
||||||
|
nullable = true;
|
||||||
|
}
|
||||||
|
return new TypeReal(aClass, nullable, proj == null ? Collections.<TypeProj>emptyList() : proj);
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
return parseTypeVar();
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(new String(string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type parseTypeVar() {
|
||||||
|
String name = parseName();
|
||||||
|
boolean nullable = false;
|
||||||
|
if(string[cur] == '?') {
|
||||||
|
nullable = true;
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TypeVar(nullable, variables.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeProj parseProjection() {
|
||||||
|
TypeInfoVariance variance = parseVariance();
|
||||||
|
Type type = parseType();
|
||||||
|
return new TypeProj(variance, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package jet.typeinfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents how type info of super class should be matched against type parameters of subclass.
|
||||||
|
*
|
||||||
|
* For each subclass we create such pattern for subclass itself and all it super classes either during
|
||||||
|
* static initialization(or maybe when needed).
|
||||||
|
*
|
||||||
|
* For each instance of parametrized type we keep it type info, which can be understood as binding of type parameter variables.
|
||||||
|
*
|
||||||
|
* @author alex.tkachman
|
||||||
|
*/
|
||||||
|
public interface TypeInfoPattern {
|
||||||
|
TypeInfo substitute(TypeInfo[] variables);
|
||||||
|
|
||||||
|
class Var implements TypeInfoPattern {
|
||||||
|
public final int index;
|
||||||
|
|
||||||
|
public Var(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo substitute(TypeInfo[] variables) {
|
||||||
|
return variables[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Const implements TypeInfoPattern {
|
||||||
|
private final TypeInfo typeInfo;
|
||||||
|
|
||||||
|
public Const(TypeInfo typeInfo) {
|
||||||
|
this.typeInfo = typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo substitute(TypeInfo[] variables) {
|
||||||
|
return typeInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Pattern implements TypeInfoPattern {
|
||||||
|
public static final TypeInfoPatternProjection[] EMPTY = new TypeInfoPatternProjection[0];
|
||||||
|
public final Class klazz;
|
||||||
|
public final boolean nullable;
|
||||||
|
public final TypeInfoPatternProjection [] patterns;
|
||||||
|
|
||||||
|
public Pattern(Class klazz, boolean nullable, TypeInfoPatternProjection[] patterns) {
|
||||||
|
this.klazz = klazz;
|
||||||
|
this.nullable = nullable;
|
||||||
|
this.patterns = patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pattern(Class klazz, boolean nullable) {
|
||||||
|
this.klazz = klazz;
|
||||||
|
this.nullable = nullable;
|
||||||
|
this.patterns = EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo substitute(TypeInfo[] variables) {
|
||||||
|
return TypeInfo.getTypeInfo(klazz, nullable, TypeInfoPatternProjection.substitute(patterns, variables));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeInfoPatternProjection {
|
||||||
|
public final TypeInfoVariance variance;
|
||||||
|
|
||||||
|
public final TypeInfoPattern pattern;
|
||||||
|
|
||||||
|
public TypeInfoPatternProjection(TypeInfoVariance variance, TypeInfoPattern pattern) {
|
||||||
|
this.variance = variance;
|
||||||
|
this.pattern = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfoProjection substitute(final TypeInfo[] variables) {
|
||||||
|
return new TypeInfoProjection() {
|
||||||
|
@Override
|
||||||
|
public TypeInfoVariance getVariance() {
|
||||||
|
return variance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeInfo getType() {
|
||||||
|
return pattern.substitute(variables);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TypeInfoProjection[] substitute(TypeInfoPatternProjection[] patterns, TypeInfo[] variables) {
|
||||||
|
if(patterns.length == 0)
|
||||||
|
return TypeInfoProjection.EMPTY_ARRAY;
|
||||||
|
TypeInfoProjection [] projections = new TypeInfoProjection[patterns.length];
|
||||||
|
for (int i = 0; i < projections.length; i++) {
|
||||||
|
projections[i] = patterns[i].substitute(variables);
|
||||||
|
}
|
||||||
|
return projections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ package jet.typeinfo;
|
|||||||
* @author alex.tkachman
|
* @author alex.tkachman
|
||||||
*/
|
*/
|
||||||
public interface TypeInfoProjection {
|
public interface TypeInfoProjection {
|
||||||
|
TypeInfoProjection[] EMPTY_ARRAY = new TypeInfoProjection[0];
|
||||||
|
|
||||||
TypeInfoVariance getVariance();
|
TypeInfoVariance getVariance();
|
||||||
|
|
||||||
TypeInfo getType();
|
TypeInfo getType();
|
||||||
|
|||||||
Reference in New Issue
Block a user