Merge remote branch 'origin/master'
This commit is contained in:
@@ -11,6 +11,8 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ClassContext {
|
||||
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null, null);
|
||||
private final DeclarationDescriptor contextType;
|
||||
@@ -19,6 +21,8 @@ public class ClassContext {
|
||||
private final ClassContext parentContext;
|
||||
private final ClosureCodegen closure;
|
||||
private boolean thisWasUsed = false;
|
||||
|
||||
HashMap<JetType,Integer> typeInfoConstants;
|
||||
|
||||
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, ClosureCodegen closureCodegen) {
|
||||
this.contextType = contextType;
|
||||
@@ -32,6 +36,13 @@ public class ClassContext {
|
||||
return contextType;
|
||||
}
|
||||
|
||||
public String getNamespaceClassName() {
|
||||
if(parentContext != STATIC)
|
||||
return parentContext.getNamespaceClassName();
|
||||
|
||||
return NamespaceCodegen.getJVMClassName(contextType.getName());
|
||||
}
|
||||
|
||||
public OwnerKind getContextKind() {
|
||||
return contextKind;
|
||||
}
|
||||
@@ -164,4 +175,19 @@ public class ClassContext {
|
||||
final ClassContext parent = getParentContext();
|
||||
return parent != null ? parent.enclosingClassType(mapper) : null;
|
||||
}
|
||||
|
||||
public int getTypeInfoConstantIndex(JetType type) {
|
||||
if(parentContext != STATIC)
|
||||
return parentContext.getTypeInfoConstantIndex(type);
|
||||
|
||||
if(typeInfoConstants == null)
|
||||
typeInfoConstants = new HashMap<JetType, Integer>();
|
||||
|
||||
Integer index = typeInfoConstants.get(type);
|
||||
if(index == null) {
|
||||
index = Integer.valueOf(typeInfoConstants.size());
|
||||
typeInfoConstants.put(type, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
|
||||
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.lang.types.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
@@ -1478,7 +1475,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
|
||||
public void generateStringBuilderConstructor() {
|
||||
Type type = Type.getObjectType(CLASS_STRING_BUILDER);
|
||||
Type type = JetTypeMapper.JL_STRING_BUILDER;
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
||||
@@ -1500,7 +1497,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
|
||||
public void invokeAppendMethod(Type exprType) {
|
||||
Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
|
||||
Method appendDescriptor = new Method("append", JetTypeMapper.JL_STRING_BUILDER,
|
||||
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
|
||||
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
|
||||
}
|
||||
@@ -1938,17 +1935,32 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
|
||||
private void generateTypeInfo(JetType jetType) {
|
||||
String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
|
||||
if(knownTypeInfo != null) {
|
||||
v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||
loadTypeParameterTypeInfo((TypeParameterDescriptor) declarationDescriptor);
|
||||
return;
|
||||
}
|
||||
|
||||
final Type jvmType = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
|
||||
if (jvmType.getSort() <= Type.DOUBLE) {
|
||||
v.getstatic("jet/typeinfo/TypeInfo", PRIMITIVE_TYPE_INFO_FIELDS[jvmType.getSort()], "Ljet/typeinfo/TypeInfo;");
|
||||
if(jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) {
|
||||
// TODO: we need some better checks here
|
||||
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType);
|
||||
if(!hasUnsubstituted) {
|
||||
int typeInfoConstantIndex = context.getTypeInfoConstantIndex(jetType);
|
||||
v.invokestatic(context.getNamespaceClassName(), "$getCachedTypeInfo$" + typeInfoConstantIndex, "()Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
final Type jvmType = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
|
||||
|
||||
v.aconst(jvmType);
|
||||
v.iconst(jetType.isNullable()?1:0);
|
||||
@@ -1974,7 +1986,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
public static void genTypeInfoToProjection(InstructionAdapter v, Variance variance) {
|
||||
if(variance == Variance.INVARIANT)
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "invariantProjection", "(Ljet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfoProjection;");
|
||||
v.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
|
||||
else if(variance == Variance.IN_VARIANCE)
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "inProjection", "(Ljet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfoProjection;");
|
||||
else if(variance == Variance.OUT_VARIANCE)
|
||||
|
||||
@@ -94,7 +94,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
private void generateFieldForTypeInfo() {
|
||||
final boolean typeInfoIsStatic = descriptor.getTypeConstructor().getParameters().size() == 0;
|
||||
v.visitField(Opcodes.ACC_PRIVATE | (typeInfoIsStatic ? Opcodes.ACC_STATIC : 0), "$typeInfo",
|
||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | (typeInfoIsStatic ? Opcodes.ACC_STATIC : 0), "$typeInfo",
|
||||
"Ljet/typeinfo/TypeInfo;", null, null);
|
||||
if (typeInfoIsStatic) {
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
|
||||
@@ -7,26 +7,6 @@ import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
public class InstructionAdapterEx extends InstructionAdapter {
|
||||
private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
|
||||
|
||||
private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
|
||||
|
||||
private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
|
||||
|
||||
private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
|
||||
|
||||
private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
|
||||
|
||||
private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
|
||||
|
||||
private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
|
||||
|
||||
private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
|
||||
|
||||
private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
|
||||
|
||||
private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
|
||||
|
||||
private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
|
||||
|
||||
private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
|
||||
@@ -46,21 +26,21 @@ public class InstructionAdapterEx extends InstructionAdapter {
|
||||
private static Type getBoxedType(final Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.BYTE:
|
||||
return BYTE_TYPE;
|
||||
return JetTypeMapper.JL_BYTE_TYPE;
|
||||
case Type.BOOLEAN:
|
||||
return BOOLEAN_TYPE;
|
||||
return JetTypeMapper.JL_BOOLEAN_TYPE;
|
||||
case Type.SHORT:
|
||||
return SHORT_TYPE;
|
||||
return JetTypeMapper.JL_SHORT_TYPE;
|
||||
case Type.CHAR:
|
||||
return CHARACTER_TYPE;
|
||||
return JetTypeMapper.JL_CHAR_TYPE;
|
||||
case Type.INT:
|
||||
return INTEGER_TYPE;
|
||||
return JetTypeMapper.JL_INTEGER_TYPE;
|
||||
case Type.FLOAT:
|
||||
return FLOAT_TYPE;
|
||||
return JetTypeMapper.JL_FLOAT_TYPE;
|
||||
case Type.LONG:
|
||||
return LONG_TYPE;
|
||||
return JetTypeMapper.JL_LONG_TYPE;
|
||||
case Type.DOUBLE:
|
||||
return DOUBLE_TYPE;
|
||||
return JetTypeMapper.JL_DOUBLE_TYPE;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -78,17 +58,17 @@ public class InstructionAdapterEx extends InstructionAdapter {
|
||||
}
|
||||
|
||||
public void unbox(final Type type) {
|
||||
Type t = NUMBER_TYPE;
|
||||
Type t = JetTypeMapper.JL_NUMBER_TYPE;
|
||||
Method sig = null;
|
||||
switch (type.getSort()) {
|
||||
case Type.VOID:
|
||||
return;
|
||||
case Type.CHAR:
|
||||
t = CHARACTER_TYPE;
|
||||
t = JetTypeMapper.JL_CHAR_TYPE;
|
||||
sig = CHAR_VALUE;
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
t = BOOLEAN_TYPE;
|
||||
t = JetTypeMapper.JL_BOOLEAN_TYPE;
|
||||
sig = BOOLEAN_VALUE;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
|
||||
@@ -28,6 +28,16 @@ public class JetTypeMapper {
|
||||
public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class);
|
||||
public static final Type TYPE_CLASS = Type.getType(Class.class);
|
||||
public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing");
|
||||
public static final Type JL_INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
|
||||
public static final Type JL_LONG_TYPE = Type.getObjectType("java/lang/Long");
|
||||
public static final Type JL_SHORT_TYPE = Type.getObjectType("java/lang/Short");
|
||||
public static final Type JL_BYTE_TYPE = Type.getObjectType("java/lang/Byte");
|
||||
public static final Type JL_CHAR_TYPE = Type.getObjectType("java/lang/Character");
|
||||
public static final Type JL_FLOAT_TYPE = Type.getObjectType("java/lang/Float");
|
||||
public static final Type JL_DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
|
||||
public static final Type JL_BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
|
||||
public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number");
|
||||
public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder");
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final BindingContext bindingContext;
|
||||
@@ -298,50 +308,50 @@ public class JetTypeMapper {
|
||||
if (jetType.equals(standardLibrary.getIntType())) {
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getIntType()))) {
|
||||
return Type.getObjectType("java/lang/Integer");
|
||||
if (jetType.equals(standardLibrary.getNullableIntType())) {
|
||||
return JL_INTEGER_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getLongType())) {
|
||||
return Type.LONG_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getLongType()))) {
|
||||
return Type.getObjectType("java/lang/Long");
|
||||
if (jetType.equals(standardLibrary.getNullableLongType())) {
|
||||
return JL_LONG_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getShortType())) {
|
||||
return Type.SHORT_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getShortType()))) {
|
||||
return Type.getObjectType("java/lang/Short");
|
||||
if (jetType.equals(standardLibrary.getNullableShortType())) {
|
||||
return JL_SHORT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getByteType())) {
|
||||
return Type.BYTE_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getByteType()))) {
|
||||
return Type.getObjectType("java/lang/Byte");
|
||||
if (jetType.equals(standardLibrary.getNullableByteType())) {
|
||||
return JL_BYTE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getCharType())) {
|
||||
return Type.CHAR_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getCharType()))) {
|
||||
return Type.getObjectType("java/lang/Char");
|
||||
if (jetType.equals(standardLibrary.getNullableCharType())) {
|
||||
return JL_CHAR_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getFloatType())) {
|
||||
return Type.FLOAT_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getFloatType()))) {
|
||||
return Type.getObjectType("java/lang/Float");
|
||||
if (jetType.equals(standardLibrary.getNullableFloatType())) {
|
||||
return JL_FLOAT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getDoubleType())) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getDoubleType()))) {
|
||||
return Type.getObjectType("java/lang/Double");
|
||||
if (jetType.equals(standardLibrary.getNullableDoubleType())) {
|
||||
return JL_DOUBLE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getBooleanType())) {
|
||||
return Type.BOOLEAN_TYPE;
|
||||
}
|
||||
if (jetType.equals(TypeUtils.makeNullable(standardLibrary.getBooleanType()))) {
|
||||
return Type.getObjectType("java/lang/Boolean");
|
||||
if (jetType.equals(standardLibrary.getNullableBooleanType())) {
|
||||
return JL_BOOLEAN_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
|
||||
return Type.getType(String.class);
|
||||
@@ -374,23 +384,23 @@ public class JetTypeMapper {
|
||||
public Type boxType(Type asmType) {
|
||||
switch (asmType.getSort()) {
|
||||
case Type.VOID:
|
||||
return Type.getObjectType("java/lang/Void");
|
||||
return Type.VOID_TYPE;
|
||||
case Type.BYTE:
|
||||
return Type.getObjectType("java/lang/Byte");
|
||||
return JL_BYTE_TYPE;
|
||||
case Type.BOOLEAN:
|
||||
return Type.getObjectType("java/lang/Boolean");
|
||||
return JL_BOOLEAN_TYPE;
|
||||
case Type.SHORT:
|
||||
return Type.getObjectType("java/lang.Short");
|
||||
return JL_SHORT_TYPE;
|
||||
case Type.CHAR:
|
||||
return Type.getObjectType("java/lang/Character");
|
||||
return JL_CHAR_TYPE;
|
||||
case Type.INT:
|
||||
return Type.getObjectType("java/lang/Integer");
|
||||
return JL_INTEGER_TYPE;
|
||||
case Type.FLOAT:
|
||||
return Type.getObjectType("java/lang/Float");
|
||||
return JL_FLOAT_TYPE;
|
||||
case Type.LONG:
|
||||
return Type.getObjectType("java/lang/Long");
|
||||
return JL_LONG_TYPE;
|
||||
case Type.DOUBLE:
|
||||
return Type.getObjectType("java/lang/Double");
|
||||
return JL_DOUBLE_TYPE;
|
||||
}
|
||||
|
||||
return asmType;
|
||||
@@ -618,4 +628,68 @@ public class JetTypeMapper {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String isKnownTypeInfo(JetType jetType) {
|
||||
if (jetType.equals(standardLibrary.getIntType())) {
|
||||
return "INT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableIntType())) {
|
||||
return "NULLABLE_INT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getLongType())) {
|
||||
return "LONG_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableLongType())) {
|
||||
return "NULLABLE_LONG_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getShortType())) {
|
||||
return "SHORT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableShortType())) {
|
||||
return "NULLABLE_SHORT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getByteType())) {
|
||||
return "BYTE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableByteType())) {
|
||||
return "NULLABLE_BYTE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getCharType())) {
|
||||
return "CHAR_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableCharType())) {
|
||||
return "NULLABLE_CHAR_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getFloatType())) {
|
||||
return "FLOAT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableFloatType())) {
|
||||
return "NULLABLE_FLOAT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getDoubleType())) {
|
||||
return "DOUBLE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableDoubleType())) {
|
||||
return "NULLABLE_DOUBLE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getBooleanType())) {
|
||||
return "BOOLEAN_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableBooleanType())) {
|
||||
return "NULLABLE_BOOLEAN_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getStringType())) {
|
||||
return "STRING_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableStringType())) {
|
||||
return "NULLABLE_STRING_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getTuple0Type())) {
|
||||
return "TUPLE0_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableTuple0Type())) {
|
||||
return "NULLABLE_TUPLE0_TYPE_INFO";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
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.TypeUtils;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
@@ -21,8 +28,8 @@ public class NamespaceCodegen {
|
||||
this.v = v;
|
||||
this.state = state;
|
||||
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
v.visit(V1_6,
|
||||
ACC_PUBLIC,
|
||||
getJVMClassName(fqName),
|
||||
null,
|
||||
//"jet/lang/Namespace",
|
||||
@@ -42,10 +49,6 @@ public class NamespaceCodegen {
|
||||
|
||||
GenerationState.prepareAnonymousClasses(namespace, state.getTypeMapper());
|
||||
|
||||
if (hasNonConstantPropertyInitializers(namespace)) {
|
||||
generateStaticInitializers(namespace);
|
||||
}
|
||||
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration);
|
||||
@@ -65,10 +68,16 @@ public class NamespaceCodegen {
|
||||
state.forNamespace(childNamespace).generate(childNamespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNonConstantPropertyInitializers(namespace, context)) {
|
||||
generateStaticInitializers(namespace, context);
|
||||
}
|
||||
|
||||
generateTypeInfoFields(namespace, context);
|
||||
}
|
||||
|
||||
private void generateStaticInitializers(JetNamespace namespace) {
|
||||
MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||
private void generateStaticInitializers(JetNamespace namespace, ClassContext context) {
|
||||
MethodVisitor mv = v.visitMethod(ACC_PUBLIC | ACC_STATIC,
|
||||
"<clinit>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
@@ -85,12 +94,85 @@ public class NamespaceCodegen {
|
||||
}
|
||||
}
|
||||
}
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static boolean hasNonConstantPropertyInitializers(JetNamespace namespace) {
|
||||
private void generateTypeInfoFields(JetNamespace namespace, ClassContext context) {
|
||||
if(context.typeInfoConstants != null) {
|
||||
String jvmClassName = getJVMClassName(namespace.getName());
|
||||
for(Map.Entry<JetType,Integer> e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.<JetType,Integer>emptyMap()).entrySet()) {
|
||||
String fieldName = "$typeInfoCache$" + e.getValue();
|
||||
v.visitField(ACC_PRIVATE|ACC_STATIC|ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null);
|
||||
|
||||
MethodVisitor mmv = v.visitMethod(ACC_PUBLIC|ACC_STATIC|ACC_SYNTHETIC, "$getCachedTypeInfo$" + e.getValue(), "()Ljet/typeinfo/TypeInfo;", null, null);
|
||||
InstructionAdapterEx v = new InstructionAdapterEx(mmv);
|
||||
v.visitFieldInsn(GETSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
|
||||
v.visitInsn(DUP);
|
||||
Label end = new Label();
|
||||
v.visitJumpInsn(IFNONNULL, end);
|
||||
|
||||
v.pop();
|
||||
generateTypeInfo(context, v, e.getKey(), state.getTypeMapper(), e.getKey());
|
||||
v.dup();
|
||||
|
||||
v.visitFieldInsn(PUTSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
|
||||
v.visitLabel(end);
|
||||
v.visitInsn(ARETURN);
|
||||
v.visitMaxs(0, 0);
|
||||
v.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateTypeInfo(ClassContext context, InstructionAdapterEx v, JetType jetType, JetTypeMapper typeMapper, JetType root) {
|
||||
String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
|
||||
if(knownTypeInfo != null) {
|
||||
v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) {
|
||||
// TODO: we need some better checks here
|
||||
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType);
|
||||
if(!jetType.equals(root) && !hasUnsubstituted) {
|
||||
int typeInfoConstantIndex = context.getTypeInfoConstantIndex(jetType);
|
||||
v.invokestatic(context.getNamespaceClassName(), "$getCachedTypeInfo$" + typeInfoConstantIndex, "()Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
final Type jvmType = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
|
||||
|
||||
v.aconst(jvmType);
|
||||
v.iconst(jetType.isNullable() ? 1 : 0);
|
||||
List<TypeProjection> arguments = jetType.getArguments();
|
||||
if (arguments.size() > 0) {
|
||||
v.iconst(arguments.size());
|
||||
v.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
|
||||
|
||||
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
|
||||
TypeProjection argument = arguments.get(i);
|
||||
v.dup();
|
||||
v.iconst(i);
|
||||
generateTypeInfo(context, v, argument.getType(), typeMapper, root);
|
||||
ExpressionCodegen.genTypeInfoToProjection(v, argument.getProjectionKind());
|
||||
v.astore(JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
else {
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasNonConstantPropertyInitializers(JetNamespace namespace, ClassContext context) {
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||
|
||||
@@ -183,10 +183,10 @@ public abstract class StackValue {
|
||||
else if (this.type.getSort() == Type.OBJECT && type.getSort() <= Type.DOUBLE) {
|
||||
if (this.type.equals(JetTypeMapper.TYPE_OBJECT)) {
|
||||
if (type.getSort() == Type.BOOLEAN) {
|
||||
v.checkcast(Type.getObjectType("java/lang/Boolean"));
|
||||
v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE);
|
||||
}
|
||||
else {
|
||||
v.checkcast(Type.getObjectType("java/lang/Number"));
|
||||
v.checkcast(JetTypeMapper.JL_NUMBER_TYPE);
|
||||
}
|
||||
}
|
||||
unbox(type, v);
|
||||
|
||||
@@ -56,16 +56,32 @@ public class JetStandardLibrary {
|
||||
private final ClassDescriptor arrayClass;
|
||||
private final ClassDescriptor iterableClass;
|
||||
private final ClassDescriptor typeInfoClass;
|
||||
private final ClassDescriptor tuple0Class;
|
||||
|
||||
private final JetType byteType;
|
||||
private final JetType nullableByteType;
|
||||
private final JetType charType;
|
||||
private final JetType nullableCharType;
|
||||
private final JetType shortType;
|
||||
private final JetType nullableShortType;
|
||||
private final JetType intType;
|
||||
private final JetType nullableIntType;
|
||||
private final JetType longType;
|
||||
private final JetType nullableLongType;
|
||||
private final JetType floatType;
|
||||
private final JetType nullableFloatType;
|
||||
private final JetType doubleType;
|
||||
private final JetType nullableDoubleType;
|
||||
private final JetType booleanType;
|
||||
private final JetType nullableBooleanType;
|
||||
private final JetType stringType;
|
||||
private final JetType nullableTuple0Type;
|
||||
|
||||
public JetType getTuple0Type() {
|
||||
return tuple0Type;
|
||||
}
|
||||
|
||||
private final JetType tuple0Type;
|
||||
private final JetType nullableStringType;
|
||||
|
||||
private final NamespaceDescriptor typeInfoNamespace;
|
||||
@@ -100,6 +116,7 @@ public class JetStandardLibrary {
|
||||
this.stringClass = (ClassDescriptor) libraryScope.getClassifier("String");
|
||||
this.arrayClass = (ClassDescriptor) libraryScope.getClassifier("Array");
|
||||
this.iterableClass = (ClassDescriptor) libraryScope.getClassifier("Iterable");
|
||||
this.tuple0Class = (ClassDescriptor) libraryScope.getClassifier("Tuple0");
|
||||
typeInfoNamespace = libraryScope.getNamespace("typeinfo");
|
||||
this.typeInfoClass = (ClassDescriptor) typeInfoNamespace.getMemberScope().getClassifier("TypeInfo");
|
||||
typeInfoFunction = typeInfoNamespace.getMemberScope().getFunctionGroup("typeinfo");
|
||||
@@ -113,7 +130,18 @@ public class JetStandardLibrary {
|
||||
this.doubleType = new JetTypeImpl(getDouble());
|
||||
this.booleanType = new JetTypeImpl(getBoolean());
|
||||
this.stringType = new JetTypeImpl(getString());
|
||||
this.tuple0Type = new JetTypeImpl(getTuple0());
|
||||
|
||||
this.nullableByteType = TypeUtils.makeNullable(byteType);
|
||||
this.nullableCharType = TypeUtils.makeNullable(charType);
|
||||
this.nullableShortType = TypeUtils.makeNullable(shortType);
|
||||
this.nullableIntType = TypeUtils.makeNullable(intType);
|
||||
this.nullableLongType = TypeUtils.makeNullable(longType);
|
||||
this.nullableFloatType = TypeUtils.makeNullable(floatType);
|
||||
this.nullableDoubleType = TypeUtils.makeNullable(doubleType);
|
||||
this.nullableBooleanType = TypeUtils.makeNullable(booleanType);
|
||||
this.nullableStringType = TypeUtils.makeNullable(stringType);
|
||||
this.nullableTuple0Type = TypeUtils.makeNullable(tuple0Type);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
@@ -178,6 +206,10 @@ public class JetStandardLibrary {
|
||||
return iterableClass;
|
||||
}
|
||||
|
||||
public ClassDescriptor getTuple0() {
|
||||
return tuple0Class;
|
||||
}
|
||||
|
||||
public NamespaceDescriptor getTypeInfoNamespace() {
|
||||
return typeInfoNamespace;
|
||||
}
|
||||
@@ -275,4 +307,40 @@ public class JetStandardLibrary {
|
||||
public JetType getNullableStringType() {
|
||||
return nullableStringType;
|
||||
}
|
||||
|
||||
public JetType getNullableByteType() {
|
||||
return nullableByteType;
|
||||
}
|
||||
|
||||
public JetType getNullableCharType() {
|
||||
return nullableCharType;
|
||||
}
|
||||
|
||||
public JetType getNullableShortType() {
|
||||
return nullableShortType;
|
||||
}
|
||||
|
||||
public JetType getNullableIntType() {
|
||||
return nullableIntType;
|
||||
}
|
||||
|
||||
public JetType getNullableLongType() {
|
||||
return nullableLongType;
|
||||
}
|
||||
|
||||
public JetType getNullableFloatType() {
|
||||
return nullableFloatType;
|
||||
}
|
||||
|
||||
public JetType getNullableDoubleType() {
|
||||
return nullableDoubleType;
|
||||
}
|
||||
|
||||
public JetType getNullableBooleanType() {
|
||||
return nullableBooleanType;
|
||||
}
|
||||
|
||||
public JetType getNullableTuple0Type() {
|
||||
return nullableTuple0Type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType {
|
||||
JetTypeImpl type = (JetTypeImpl) o;
|
||||
|
||||
// TODO
|
||||
return equalTypes(this, type, EMPTY_AXIOMS);
|
||||
return nullable == type.nullable && equalTypes(this, type, EMPTY_AXIOMS);
|
||||
// if (nullable != type.nullable) return false;
|
||||
// if (arguments != null ? !arguments.equals(type.arguments) : type.arguments != null) return false;
|
||||
// if (constructor != null ? !constructor.equals(type.constructor) : type.constructor != null) return false;
|
||||
|
||||
@@ -320,4 +320,17 @@ public class TypeUtils {
|
||||
if (declarationDescriptor2 == null) return false; // Class of type1 is not null
|
||||
return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
|
||||
}
|
||||
|
||||
public static boolean hasUnsubstitutedTypeParameters(JetType type) {
|
||||
if(type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor)
|
||||
return true;
|
||||
|
||||
for(TypeProjection proj : type.getArguments()) {
|
||||
if(hasUnsubstitutedTypeParameters(proj.getType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,11 @@ public class JetStructureViewElement implements StructureViewTreeElement {
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextAttributesKey getTextAttributesKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,52 +8,143 @@ class B<T>() {
|
||||
fun t1() : Boolean {
|
||||
val a = A()
|
||||
if(a !is A) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t2() : Boolean {
|
||||
val a = A()
|
||||
if(a !is A?) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t3() : Boolean {
|
||||
val a = A()
|
||||
if(null !is A?) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t2 () : Boolean {
|
||||
fun t4 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(b !is B<String>) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t5 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(b !is B<String>?) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t6 () : Boolean {
|
||||
if(null !is B<String>?) return false
|
||||
return true
|
||||
}
|
||||
|
||||
val v = b as B<String> //ok
|
||||
val u = b as B<String>? //TypeCastException
|
||||
fun t7 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(!b.isT("aaa")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t8 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(b.isT(10)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t9 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(b.isT(null)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t10 () : Boolean {
|
||||
val d = B<String?>()
|
||||
if(!d.isT("aaa")) return false
|
||||
return true
|
||||
}
|
||||
fun t11 () : Boolean {
|
||||
val d = B<String?>()
|
||||
if(d.isT(10)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t12 () : Boolean {
|
||||
val d = B<String?>()
|
||||
if(!d.isT(null)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t13 () : Boolean {
|
||||
val f = B<java.lang.String?>()
|
||||
if(!f.isT("aaa")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t14 () : Boolean {
|
||||
val f = B<java.lang.String?>()
|
||||
if(f.isT(10)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t15 () : Boolean {
|
||||
val f = B<java.lang.String?>()
|
||||
if(!f.isT(null)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t16 () : Boolean {
|
||||
val c = B<Int>()
|
||||
if(c.isT("aaa")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t17 () : Boolean {
|
||||
val c = B<Int>()
|
||||
if(!c.isT(10)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t18 () : Boolean {
|
||||
val c = B<Int>()
|
||||
if(c.isT(null)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t19 () : Boolean {
|
||||
val e = B<Int?>()
|
||||
if(e.isT("aaa")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t20 () : Boolean {
|
||||
val e = B<Int?>()
|
||||
if(!e.isT(10)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t21 () : Boolean {
|
||||
val e = B<Int?>()
|
||||
if(!e.isT(null)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun t22 () : Boolean {
|
||||
val b = B<String>()
|
||||
val w : B<String>? = b as B<String> //ok
|
||||
val x = w as B<String>? //TypeCastException
|
||||
return true
|
||||
}
|
||||
|
||||
fun t3 () : Boolean {
|
||||
fun t23 () : Boolean {
|
||||
val b = B<String>()
|
||||
if(!b.isT("aaa")) return false
|
||||
|
||||
if(b.isT(10)) return false
|
||||
if(b.isT(null)) return false
|
||||
|
||||
val d = B<String?>()
|
||||
if(!d.isT("aaa")) return false
|
||||
if(d.isT(10)) return false
|
||||
if(!d.isT(null)) return false
|
||||
|
||||
val f = B<java.lang.String?>()
|
||||
if(!f.isT("aaa")) return false
|
||||
if(f.isT(10)) return false
|
||||
if(!f.isT(null)) return false
|
||||
|
||||
val c = B<Int>()
|
||||
if(c.isT("aaa")) return false
|
||||
if(!c.isT(10)) return false
|
||||
if(c.isT(null)) return false
|
||||
|
||||
val e = B<Int?>()
|
||||
if(e.isT("aaa")) return false
|
||||
if(!e.isT(10)) return false
|
||||
if(!e.isT(null)) return false
|
||||
val v = b as B<String> //ok
|
||||
return true
|
||||
}
|
||||
|
||||
fun t24 () : Boolean {
|
||||
val b = B<String>()
|
||||
val u = b as B<String>? //TypeCastException
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -67,5 +158,68 @@ fun box() : String {
|
||||
if(!t3()) {
|
||||
return "t3 failed"
|
||||
}
|
||||
return "OK"
|
||||
if(!t4()) {
|
||||
return "t4 failed"
|
||||
}
|
||||
if(!t5()) {
|
||||
return "t5 failed"
|
||||
}
|
||||
if(!t6()) {
|
||||
return "t6 failed"
|
||||
}
|
||||
if(!t7()) {
|
||||
return "t7 failed"
|
||||
}
|
||||
if(!t8()) {
|
||||
return "t8 failed"
|
||||
}
|
||||
if(!t9()) {
|
||||
return "t9 failed"
|
||||
}
|
||||
if(!t10()) {
|
||||
return "t10 failed"
|
||||
}
|
||||
if(!t11()) {
|
||||
return "t11 failed"
|
||||
}
|
||||
if(!t12()) {
|
||||
return "t12 failed"
|
||||
}
|
||||
if(!t13()) {
|
||||
return "t13 failed"
|
||||
}
|
||||
if(!t14()) {
|
||||
return "t14 failed"
|
||||
}
|
||||
if(!t15()) {
|
||||
return "t15 failed"
|
||||
}
|
||||
if(!t16()) {
|
||||
return "t16 failed"
|
||||
}
|
||||
if(!t17()) {
|
||||
return "t17 failed"
|
||||
}
|
||||
if(!t18()) {
|
||||
return "t18 failed"
|
||||
}
|
||||
if(!t19()) {
|
||||
return "t19 failed"
|
||||
}
|
||||
if(!t20()) {
|
||||
return "t10 failed"
|
||||
}
|
||||
if(!t21()) {
|
||||
return "t21 failed"
|
||||
}
|
||||
if(!t22()) {
|
||||
return "t22 failed"
|
||||
}
|
||||
if(!t23()) {
|
||||
return "t23 failed"
|
||||
}
|
||||
if(!t24()) {
|
||||
return "t24 failed"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
@@ -49,8 +49,8 @@ public class PatternMatchingTest extends CodegenTestCase {
|
||||
|
||||
public void testIs() throws Exception {
|
||||
loadFile();
|
||||
blackBox();
|
||||
System.out.println(generateToText());
|
||||
blackBox();
|
||||
}
|
||||
|
||||
public void testRange() throws Exception {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jet.typeinfo;
|
||||
|
||||
import jet.JetObject;
|
||||
import jet.Tuple0;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
@@ -19,6 +20,19 @@ public abstract class TypeInfo<T> implements JetObject {
|
||||
public static final TypeInfo<Boolean> BOOL_TYPE_INFO = getTypeInfo(Boolean.class, false);
|
||||
public static final TypeInfo<Float> FLOAT_TYPE_INFO = getTypeInfo(Float.class, false);
|
||||
public static final TypeInfo<Double> DOUBLE_TYPE_INFO = getTypeInfo(Double.class, false);
|
||||
public static final TypeInfo<String> STRING_TYPE_INFO = getTypeInfo(String.class, false);
|
||||
public static final TypeInfo<Tuple0> TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, false);
|
||||
|
||||
public static final TypeInfo<Byte> NULLABLE_BYTE_TYPE_INFO = getTypeInfo(Byte.class, true);
|
||||
public static final TypeInfo<Short> NULLABLE_SHORT_TYPE_INFO = getTypeInfo(Short.class, true);
|
||||
public static final TypeInfo<Integer> NULLABLE_INT_TYPE_INFO = getTypeInfo(Integer.class, true);
|
||||
public static final TypeInfo<Long> NULLABLE_LONG_TYPE_INFO = getTypeInfo(Long.class, true);
|
||||
public static final TypeInfo<Character> NULLABLE_CHAR_TYPE_INFO = getTypeInfo(Character.class, true);
|
||||
public static final TypeInfo<Boolean> NULLABLE_BOOL_TYPE_INFO = getTypeInfo(Boolean.class, true);
|
||||
public static final TypeInfo<Float> NULLABLE_FLOAT_TYPE_INFO = getTypeInfo(Float.class, true);
|
||||
public static final TypeInfo<Double> NULLABLE_DOUBLE_TYPE_INFO = getTypeInfo(Double.class, true);
|
||||
public static final TypeInfo<String> NULLABLE_STRING_TYPE_INFO = getTypeInfo(String.class, true);
|
||||
public static final TypeInfo<Tuple0> NULLABLE_TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, true);
|
||||
|
||||
private TypeInfo<?> typeInfo;
|
||||
private final Class<T> theClass;
|
||||
|
||||
Reference in New Issue
Block a user