From c0dfe933c6e0eb4d1482b9f72a02cb0ab788bb42 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 6 Sep 2011 16:30:48 +0200 Subject: [PATCH 1/2] half way to KT-4 --- .../jetbrains/jet/codegen/ClassContext.java | 19 +++ .../jet/codegen/ExpressionCodegen.java | 28 ++-- .../codegen/ImplementationBodyCodegen.java | 2 +- .../jet/codegen/InstructionAdapterEx.java | 42 ++---- .../jetbrains/jet/codegen/JetTypeMapper.java | 124 ++++++++++++++---- .../jet/codegen/NamespaceCodegen.java | 21 ++- .../org/jetbrains/jet/codegen/StackValue.java | 4 +- .../jet/lang/types/JetStandardLibrary.java | 68 ++++++++++ .../jetbrains/jet/lang/types/TypeUtils.java | 13 ++ .../JetStructureViewElement.java | 5 + stdlib/src/jet/typeinfo/TypeInfo.java | 14 ++ 11 files changed, 267 insertions(+), 73 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassContext.java b/idea/src/org/jetbrains/jet/codegen/ClassContext.java index d553ca2774e..3ad0f4da7ca 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassContext.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassContext.java @@ -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 typeInfoConstants; public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, ClosureCodegen closureCodegen) { this.contextType = contextType; @@ -164,4 +168,19 @@ public class ClassContext { final ClassContext parent = getParentContext(); return parent != null ? parent.enclosingClassType(mapper) : null; } + + public int getTypeInfoConstantIndex(JetType type) { + if(parentContext != STATIC) + parentContext.getTypeInfoConstantIndex(type); + + if(typeInfoConstants == null) + typeInfoConstants = new HashMap(); + + Integer index = typeInfoConstants.get(type); + if(index == null) { + index = Integer.valueOf(typeInfoConstants.size()); + typeInfoConstants.put(type, index); + } + return index; + } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 521ae9e361a..95588c972c3 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -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 { } 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("", Type.VOID_TYPE, new Type[0]); @@ -1500,7 +1497,7 @@ public class ExpressionCodegen extends JetVisitor { } 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,6 +1935,12 @@ public class ExpressionCodegen extends JetVisitor { } 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); @@ -1945,10 +1948,17 @@ public class ExpressionCodegen extends JetVisitor { } 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) { + context.getTypeInfoConstantIndex(jetType); + } v.aconst(jvmType); v.iconst(jetType.isNullable()?1:0); @@ -1974,7 +1984,7 @@ public class ExpressionCodegen extends JetVisitor { 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) diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 8f1be52b429..ec4c31d888b 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -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() { diff --git a/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java index 48c9c163486..f78095819d2 100644 --- a/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java +++ b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java @@ -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: diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index d48c8eec52e..745074db43f 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -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(ExpressionCodegen.CLASS_STRING_BUILDER); 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; + } } diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 1b8ee6b5429..7f0b3c961a0 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -4,12 +4,18 @@ import com.intellij.psi.PsiFile; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetType; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + /** * @author max */ @@ -42,10 +48,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,9 +67,18 @@ public class NamespaceCodegen { state.forNamespace(childNamespace).generate(childNamespace); } } + +// System.out.println("-----------"); +// for(Map.Entry e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.emptyMap()).entrySet()) { +// System.out.println(e.getKey() + " -> " + e.getValue()); +// } + + if (hasNonConstantPropertyInitializers(namespace)) { + generateStaticInitializers(namespace, context); + } } - private void generateStaticInitializers(JetNamespace namespace) { + private void generateStaticInitializers(JetNamespace namespace, ClassContext context) { MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "", "()V", null, null); mv.visitCode(); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 6ff96e485c3..b657161eb12 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -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); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 220ea250226..bb642d8df68 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -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; + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java index 10215de1dec..75ed47acf37 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -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; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java index fb7d05ede1e..1cb819b2154 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java @@ -70,6 +70,11 @@ public class JetStructureViewElement implements StructureViewTreeElement { : null; } + @Override + public TextAttributesKey getTextAttributesKey() { + return null; + } + }; } diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 6a531d7695f..e8c7f5e36d2 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -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 implements JetObject { public static final TypeInfo BOOL_TYPE_INFO = getTypeInfo(Boolean.class, false); public static final TypeInfo FLOAT_TYPE_INFO = getTypeInfo(Float.class, false); public static final TypeInfo DOUBLE_TYPE_INFO = getTypeInfo(Double.class, false); + public static final TypeInfo STRING_TYPE_INFO = getTypeInfo(String.class, false); + public static final TypeInfo TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, false); + + public static final TypeInfo NULLABLE_BYTE_TYPE_INFO = getTypeInfo(Byte.class, true); + public static final TypeInfo NULLABLE_SHORT_TYPE_INFO = getTypeInfo(Short.class, true); + public static final TypeInfo NULLABLE_INT_TYPE_INFO = getTypeInfo(Integer.class, true); + public static final TypeInfo NULLABLE_LONG_TYPE_INFO = getTypeInfo(Long.class, true); + public static final TypeInfo NULLABLE_CHAR_TYPE_INFO = getTypeInfo(Character.class, true); + public static final TypeInfo NULLABLE_BOOL_TYPE_INFO = getTypeInfo(Boolean.class, true); + public static final TypeInfo NULLABLE_FLOAT_TYPE_INFO = getTypeInfo(Float.class, true); + public static final TypeInfo NULLABLE_DOUBLE_TYPE_INFO = getTypeInfo(Double.class, true); + public static final TypeInfo NULLABLE_STRING_TYPE_INFO = getTypeInfo(String.class, true); + public static final TypeInfo NULLABLE_TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, true); private TypeInfo typeInfo; private final Class theClass; From 6898ff5665d2f518f399542317791e4a2d8663ca Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 6 Sep 2011 23:45:04 +0200 Subject: [PATCH 2/2] KT-4 fixed --- .../jetbrains/jet/codegen/ClassContext.java | 9 +- .../jet/codegen/ExpressionCodegen.java | 8 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 2 +- .../jet/codegen/NamespaceCodegen.java | 109 +++++++-- .../jetbrains/jet/lang/types/JetTypeImpl.java | 2 +- idea/testData/codegen/regressions/kt259.jet | 212 +++++++++++++++--- .../jet/codegen/PatternMatchingTest.java | 2 +- 7 files changed, 289 insertions(+), 55 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassContext.java b/idea/src/org/jetbrains/jet/codegen/ClassContext.java index 3ad0f4da7ca..da21e7e8501 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassContext.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassContext.java @@ -36,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; } @@ -171,7 +178,7 @@ public class ClassContext { public int getTypeInfoConstantIndex(JetType type) { if(parentContext != STATIC) - parentContext.getTypeInfoConstantIndex(type); + return parentContext.getTypeInfoConstantIndex(type); if(typeInfoConstants == null) typeInfoConstants = new HashMap(); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 95588c972c3..d07d89a63d5 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1947,8 +1947,6 @@ public class ExpressionCodegen extends JetVisitor { return; } - final Type jvmType = typeMapper.mapType(jetType, OwnerKind.INTERFACE); - 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;"); @@ -1957,9 +1955,13 @@ public class ExpressionCodegen extends JetVisitor { boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType); if(!hasUnsubstituted) { - context.getTypeInfoConstantIndex(jetType); + 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 arguments = jetType.getArguments(); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 745074db43f..8666e7cd8ba 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -37,7 +37,7 @@ public class JetTypeMapper { 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(ExpressionCodegen.CLASS_STRING_BUILDER); + public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder"); private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 7f0b3c961a0..b5e599721b4 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -1,20 +1,21 @@ 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.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.types.JetType; -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.types.TypeProjection; +import org.jetbrains.jet.lang.types.TypeUtils; +import org.objectweb.asm.*; import org.objectweb.asm.commons.InstructionAdapter; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.util.*; + +import static org.objectweb.asm.Opcodes.*; /** * @author max @@ -27,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", @@ -68,18 +69,15 @@ public class NamespaceCodegen { } } -// System.out.println("-----------"); -// for(Map.Entry e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.emptyMap()).entrySet()) { -// System.out.println(e.getKey() + " -> " + e.getValue()); -// } - - if (hasNonConstantPropertyInitializers(namespace)) { + if (hasNonConstantPropertyInitializers(namespace, context)) { generateStaticInitializers(namespace, context); } + + generateTypeInfoFields(namespace, context); } private void generateStaticInitializers(JetNamespace namespace, ClassContext context) { - MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, + MethodVisitor mv = v.visitMethod(ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); mv.visitCode(); @@ -96,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 e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.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 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(); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java index 4d7945db4c4..c5371ba11bb 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java @@ -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; diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index bf6ac4b0fe1..dada6e9c2cd 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -8,52 +8,143 @@ class B() { 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() if(b !is B) return false + return true +} + +fun t5 () : Boolean { + val b = B() if(b !is B?) return false + return true +} + +fun t6 () : Boolean { if(null !is B?) return false + return true +} - val v = b as B //ok - val u = b as B? //TypeCastException +fun t7 () : Boolean { + val b = B() + if(!b.isT("aaa")) return false + return true +} +fun t8 () : Boolean { + val b = B() + if(b.isT(10)) return false + return true +} + +fun t9 () : Boolean { + val b = B() + if(b.isT(null)) return false + return true +} + +fun t10 () : Boolean { + val d = B() + if(!d.isT("aaa")) return false + return true +} +fun t11 () : Boolean { + val d = B() + if(d.isT(10)) return false + return true +} + +fun t12 () : Boolean { + val d = B() + if(!d.isT(null)) return false + return true +} + +fun t13 () : Boolean { + val f = B() + if(!f.isT("aaa")) return false + return true +} + +fun t14 () : Boolean { + val f = B() + if(f.isT(10)) return false + return true +} + +fun t15 () : Boolean { + val f = B() + if(!f.isT(null)) return false + return true +} + +fun t16 () : Boolean { + val c = B() + if(c.isT("aaa")) return false + return true +} + +fun t17 () : Boolean { + val c = B() + if(!c.isT(10)) return false + return true +} + +fun t18 () : Boolean { + val c = B() + if(c.isT(null)) return false + return true +} + +fun t19 () : Boolean { + val e = B() + if(e.isT("aaa")) return false + return true +} + +fun t20 () : Boolean { + val e = B() + if(!e.isT(10)) return false + return true +} + +fun t21 () : Boolean { + val e = B() + if(!e.isT(null)) return false + return true +} + +fun t22 () : Boolean { + val b = B() val w : B? = b as B //ok val x = w as B? //TypeCastException return true } -fun t3 () : Boolean { +fun t23 () : Boolean { val b = B() - if(!b.isT("aaa")) return false - - if(b.isT(10)) return false - if(b.isT(null)) return false - - val d = B() - if(!d.isT("aaa")) return false - if(d.isT(10)) return false - if(!d.isT(null)) return false - - val f = B() - if(!f.isT("aaa")) return false - if(f.isT(10)) return false - if(!f.isT(null)) return false - - val c = B() - if(c.isT("aaa")) return false - if(!c.isT(10)) return false - if(c.isT(null)) return false - - val e = B() - if(e.isT("aaa")) return false - if(!e.isT(10)) return false - if(!e.isT(null)) return false + val v = b as B //ok + return true +} +fun t24 () : Boolean { + val b = B() + val u = b as B? //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" } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index c82f9a4847d..60337ed4ff2 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -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 {