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 {