diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 40c242ab634..01a1d76eaed 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1813,23 +1813,25 @@ public class ExpressionCodegen extends JetVisitor { JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference); assert jetType != null; DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (!(descriptor instanceof ClassDescriptor)) { - throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); - } - Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType)); - generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); - Label isInstance = new Label(); - v.ifne(isInstance); - v.pop(); - if (opToken == JetTokens.AS_SAFE) { - v.aconst(null); + if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) { + Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType)); + generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); + Label isInstance = new Label(); + v.ifne(isInstance); + v.pop(); + if (opToken == JetTokens.AS_SAFE) { + v.aconst(null); + } + else { + throwNewException(CLASS_TYPE_CAST_EXCEPTION); + } + v.mark(isInstance); + v.checkcast(type); + return StackValue.onStack(type); } else { - throwNewException(CLASS_TYPE_CAST_EXCEPTION); + throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); } - v.mark(isInstance); - v.checkcast(type); - return StackValue.onStack(type); } } @@ -1962,7 +1964,7 @@ public class ExpressionCodegen extends JetVisitor { } } - private void generateTypeInfo(JetType jetType) { + void generateTypeInfo(JetType jetType) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index e9f872046a6..aead6e36f70 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; @@ -109,7 +110,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void getSuperClass() { List delegationSpecifiers = myClass.getDelegationSpecifiers(); - if(myClass instanceof JetClass && ((JetClass)myClass).isTrait()) + if(myClass instanceof JetClass && ((JetClass) myClass).isTrait()) return; for (JetDelegationSpecifier specifier : delegationSpecifiers) { @@ -150,6 +151,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } generateGetTypeInfo(); + //genGetSuperTypesTypeInfo(); } private void generateFieldForTypeInfo() { @@ -240,6 +242,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); + for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) { + codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); + } + String classname = state.getTypeMapper().jvmName(descriptor, kind); final Type classType = Type.getType("L" + classname + ";"); @@ -348,7 +354,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { reg += argType.getSize(); } - String fdescriptor = function.getDescriptor().replace("(","(L" + state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(),OwnerKind.IMPLEMENTATION) + ";"); + ClassDescriptor containingDeclaration = (ClassDescriptor) fun.getContainingDeclaration(); + JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, state.getBindingContext()); + Type type = state.getTypeMapper().mapType(jetType); + if(type.getInternalName().equals("java/lang/Object")) { + jetType = containingDeclaration.getDefaultType(); + type = state.getTypeMapper().mapType(jetType); + } + + String fdescriptor = function.getDescriptor().replace("(","(" + type.getDescriptor()); iv.invokestatic(state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(), OwnerKind.TRAIT_IMPL), function.getName(), fdescriptor); iv.areturn(function.getReturnType()); mv.visitMaxs(0, 0); @@ -530,7 +544,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.dup(); iv.iconst(i); iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); - ExpressionCodegen.genTypeInfoToProjection(iv, Variance.INVARIANT); + iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION); iv.astore(JetTypeMapper.TYPE_OBJECT); } iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); @@ -648,4 +662,50 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateClassObject(JetClassObject declaration) { state.forClass().generate(context, declaration.getObjectDeclaration()); } + + private void genGetSuperTypesTypeInfo() { + if(!(myClass instanceof JetClass) || ((JetClass)myClass).isTrait()) { + return; + } + + String sig = getGetSuperTypesTypeInfoSignature(descriptor.getDefaultType()); + + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC|Opcodes.ACC_STATIC, + "$$getSuperTypesTypeInfo", + sig, + null /* TODO */, + null); + mv.visitCode(); + InstructionAdapter v = new InstructionAdapter(mv); + + ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state); + + v.load(0, JetTypeMapper.TYPE_OBJECT); + + int k = 1; + for (TypeParameterDescriptor parameterDescriptor : descriptor.getTypeConstructor().getParameters()) { + codegen.addTypeParameter(parameterDescriptor, StackValue.local(k++, JetTypeMapper.TYPE_TYPEINFO)); + } + + for(JetType superType : descriptor.getTypeConstructor().getSupertypes()) { + for (TypeProjection typeProjection : superType.getArguments()) { + codegen.generateTypeInfo(typeProjection.getType()); + } + v.invokestatic(state.getTypeMapper().mapType(superType).getInternalName(), "$$getSuperTypesTypeInfo", getGetSuperTypesTypeInfoSignature(superType)); + } + + v.areturn(Type.VOID_TYPE); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private static String getGetSuperTypesTypeInfoSignature(JetType type) { + List typeParameters = type.getConstructor().getParameters(); + StringBuilder sb = new StringBuilder("(Ljava/util/Set;"); + for(TypeParameterDescriptor tp : typeParameters) + sb.append("Ljet/typeinfo/TypeInfo;"); + sb.append(")V"); + + return sb.toString(); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 5896a36e70b..e014f057e38 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -439,8 +439,13 @@ public class JetTypeMapper { } FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); if(kind == OwnerKind.TRAIT_IMPL) { - JetType jetType = ((ClassDescriptor)functionDescriptor.getContainingDeclaration()).getDefaultType(); - final Type type = mapType(jetType); + ClassDescriptor containingDeclaration = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); + JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); + Type type = mapType(jetType); + if(type.getInternalName().equals("java/lang/Object")) { + jetType = containingDeclaration.getDefaultType(); + type = mapType(jetType); + } valueParameterTypes.add(type); parameterTypes.add(type); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 8c87865c55b..ecf1b2c8ff7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -1,9 +1,11 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetClassOrObject; -import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetNamedFunction; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; @@ -16,6 +18,33 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen { super(aClass, context, v, state); } + //todo not needed when frontend will be able to calculate properly + static JetType getSuperClass(ClassDescriptor myClassDescr, BindingContext bindingContext) { + JetClassOrObject myClass = (JetClassOrObject) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, myClassDescr); + List delegationSpecifiers = myClass.getDelegationSpecifiers(); + + for (JetDelegationSpecifier specifier : delegationSpecifiers) { + if (specifier instanceof JetDelegatorToSuperClass || specifier instanceof JetDelegatorToSuperCall) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor); + if (declaration != null) { + if (declaration instanceof PsiClass) { + if (!((PsiClass) declaration).isInterface()) { + return superClassDescriptor.getDefaultType(); + } + } + else if(declaration instanceof JetClass) { + if(!((JetClass) declaration).isTrait()) { + return superClassDescriptor.getDefaultType(); + } + } + } + } + } + return null; + } + @Override protected void generateDeclaration() { v.visit(Opcodes.V1_6, diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index dada6e9c2cd..e11e74f179d 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -1,10 +1,16 @@ class A() {} -class B() { +open class B() { fun isT (a : Any?) : Boolean { return a is T } } +class C() : B() { +} + +class D() : B>() { +} + fun t1() : Boolean { val a = A() if(a !is A) return false @@ -148,6 +154,18 @@ fun t24 () : Boolean { return true } +fun t25 () : Boolean { + val c = C() + if(!c.isT("aaa")) return false + return true +} + +fun t26 () : Boolean { + val d = D() + if(!d.isT(B())) return false + return true +} + fun box() : String { if(!t1()) { return "t1 failed" @@ -221,5 +239,11 @@ fun box() : String { if(!t24()) { return "t24 failed" } + if(!t25()) { + return "t25 failed" + } + if(!t26()) { + return "t26 failed" + } return "OK" } \ No newline at end of file diff --git a/idea/testData/codegen/traits/multiple.jet b/idea/testData/codegen/traits/multiple.jet new file mode 100644 index 00000000000..c471506e9c5 --- /dev/null +++ b/idea/testData/codegen/traits/multiple.jet @@ -0,0 +1,15 @@ +trait AL { + fun get(index: Int) : Any? = null +} + +trait ALE : AL { + fun getOrNull(index: Int, value : T) = get(index) as? T ?: value +} + +class SmartArrayList() : ALE { +} + +fun box() : String { + val c = SmartArrayList() + return if("239" == c.getOrNull(0, "239")) "OK" else "fail" +} diff --git a/idea/testData/codegen/traits/withRequired.jet b/idea/testData/codegen/traits/withRequired.jet new file mode 100644 index 00000000000..64e4df814ee --- /dev/null +++ b/idea/testData/codegen/traits/withRequired.jet @@ -0,0 +1,15 @@ +open class AL { + fun get(index: Int) : T? = null +} + +trait ALE : AL { + fun getOrValue(index: Int, value : T) : T = get(index) ?: value +} + +class SmartArrayList() : ALE, AL { +} + +fun box() : String { + val c = SmartArrayList() + return if("239" == c.getOrValue(0, "239")) "OK" else "fail" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java index 3558c42e455..384c103b9a3 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java @@ -10,4 +10,14 @@ public class TraitsTest extends CodegenTestCase { blackBoxFile("traits/simple.jet"); System.out.println(generateToText()); } + + public void testWithRequired () throws Exception { + blackBoxFile("traits/withRequired.jet"); + System.out.println(generateToText()); + } + + public void testMultiple () throws Exception { +// blackBoxFile("traits/multiple.jet"); +// System.out.println(generateToText()); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index d4843618aa9..39f2db4abfa 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -131,6 +131,7 @@ public class TypeInfoTest extends CodegenTestCase { public void testKt259() throws Exception { blackBoxFile("regressions/kt259.jet"); + System.out.println(generateToText()); } }