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.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.jetbrains.jet.lang.types.Variance;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
@@ -101,6 +97,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
interfaces.toArray(new String[interfaces.size()])
|
||||
);
|
||||
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() {
|
||||
|
||||
@@ -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 java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -12,6 +14,8 @@ import java.util.Arrays;
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
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<Short> SHORT_TYPE_INFO = getTypeInfo(Short.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);
|
||||
|
||||
private TypeInfo<?> typeInfo;
|
||||
private final Class<T> theClass;
|
||||
private final Signature signature;
|
||||
private final boolean nullable;
|
||||
private final TypeInfoProjection[] projections;
|
||||
|
||||
private TypeInfo(Class<T> theClass, boolean nullable) {
|
||||
this.theClass = theClass;
|
||||
this.nullable = nullable;
|
||||
this.projections = null;
|
||||
this(theClass, nullable, EMPTY);
|
||||
}
|
||||
|
||||
private TypeInfo(Class<T> theClass, boolean nullable, TypeInfoProjection[] projections) {
|
||||
this.theClass = theClass;
|
||||
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 static <T> TypeInfoProjection invariantProjection(final TypeInfo<T> typeInfo) {
|
||||
@@ -85,7 +89,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
|
||||
public final Object getClassObject() {
|
||||
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");
|
||||
return classobj.get(null);
|
||||
} catch (Exception e) {
|
||||
@@ -100,25 +104,23 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
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) {
|
||||
if (nullable && !superType.nullable) {
|
||||
return false;
|
||||
}
|
||||
if (!superType.theClass.isAssignableFrom(theClass)) {
|
||||
if (!superType.signature.klazz.isAssignableFrom(signature.klazz)) {
|
||||
return false;
|
||||
}
|
||||
if (projections != null) {
|
||||
if (superType.projections == null || superType.projections.length != projections.length) {
|
||||
throw new IllegalArgumentException("inconsistent type infos for the same class");
|
||||
}
|
||||
for (int i = 0; i < projections.length; i++) {
|
||||
// TODO handle variance here
|
||||
if (!projections[i].equals(superType.projections[i])) {
|
||||
return false;
|
||||
}
|
||||
if (superType.projections == null || superType.projections.length != projections.length) {
|
||||
throw new IllegalArgumentException("inconsistent type infos for the same class");
|
||||
}
|
||||
for (int i = 0; i < projections.length; i++) {
|
||||
// TODO handle variance here
|
||||
if (!projections[i].equals(superType.projections[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -148,7 +150,7 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
|
||||
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 (!Arrays.equals(projections, typeInfo.projections)) return false;
|
||||
|
||||
@@ -157,13 +159,13 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return 31 * theClass.hashCode() + (projections != null ? Arrays.hashCode(projections) : 0);
|
||||
return 31 * signature.klazz.hashCode() + Arrays.hashCode(projections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder sb = new StringBuilder().append(theClass.getName());
|
||||
if (projections != null && projections.length != 0) {
|
||||
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(",");
|
||||
@@ -196,4 +198,261 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
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
|
||||
*/
|
||||
public interface TypeInfoProjection {
|
||||
TypeInfoProjection[] EMPTY_ARRAY = new TypeInfoProjection[0];
|
||||
|
||||
TypeInfoVariance getVariance();
|
||||
|
||||
TypeInfo getType();
|
||||
|
||||
Reference in New Issue
Block a user