diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 4508ca0a291..ce5a8a0aa1b 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -6,7 +6,8 @@ import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -14,6 +15,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -210,6 +212,14 @@ public class ClassCodegen { iv.invokespecial(superClass, "", /* TODO super constructor descriptor */"()V"); } + HashSet overriden = new HashSet(); + for (JetDeclaration declaration : aClass.getDeclarations()) { + if (declaration instanceof JetFunction) { + overriden.addAll(bindingContext.getFunctionDescriptor((JetFunction) declaration).getOverriddenFunctions()); + } + } + + int n = 0; for (JetDelegationSpecifier specifier : specifiers) { boolean delegateOnStack = specifier instanceof JetDelegatorToSuperCall && n > 0 || @@ -267,7 +277,7 @@ public class ClassCodegen { JetClass superClass = (JetClass) bindingContext.getDeclarationPsiElement(superClassDescriptor); generateDelegates(aClass, superClass, v, new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), - JetTypeMapper.jvmNameForInterface(superClassDescriptor))); + JetTypeMapper.jvmNameForInterface(superClassDescriptor)), overriden); } n++; @@ -364,7 +374,7 @@ public class ClassCodegen { } } - private void generateDelegates(JetClass inClass, JetClass toClass, ClassVisitor v, OwnerKind kind) { + private void generateDelegates(JetClass inClass, JetClass toClass, ClassVisitor v, OwnerKind kind, Set overriden) { final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, standardLibrary, bindingContext); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); @@ -374,7 +384,9 @@ public class ClassCodegen { propertyCodegen.gen((JetProperty) declaration, kind); } else if (declaration instanceof JetFunction) { - functionCodegen.gen((JetFunction) declaration, kind); + if (!overriden.contains(bindingContext.getFunctionDescriptor((JetFunction) declaration))) { + functionCodegen.gen((JetFunction) declaration, kind); + } } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 94cb05ea079..2a1e5c8f2d2 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1268,9 +1268,6 @@ public class ExpressionCodegen extends JetVisitor { else { JetTypeReference typeReference = expression.getRight(); JetType jetType = bindingContext.resolveTypeReference(typeReference); - if (jetType.getArguments().size() > 0) { - throw new UnsupportedOperationException("don't know how to handle type arguments in as/as?"); - } DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); if (!(descriptor instanceof ClassDescriptor)) { throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); @@ -1278,8 +1275,7 @@ public class ExpressionCodegen extends JetVisitor { Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); gen(expression.getLeft(), OBJECT_TYPE); if (opToken == JetTokens.AS_SAFE) { - v.dup(); - v.instanceOf(type); + generateInstanceOf(expression.getLeft(), jetType, true); Label isInstance = new Label(); v.ifne(isInstance); v.pop(); @@ -1288,7 +1284,7 @@ public class ExpressionCodegen extends JetVisitor { myStack.push(StackValue.onStack(type)); } else { - throw new UnsupportedOperationException("as not yet implemented"); + throw new UnsupportedOperationException("'as' not yet implemented"); } } } @@ -1307,22 +1303,32 @@ public class ExpressionCodegen extends JetVisitor { } JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference(); JetType jetType = bindingContext.resolveTypeReference(typeReference); + generateInstanceOf(expression.getLeftHandSide(), jetType, false); + StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); + myStack.push(expression.isNot() ? StackValue.not(value) : value); + } + + private void generateInstanceOf(JetExpression expression, JetType jetType, boolean leaveExpressionOnStack) { DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); if (!(descriptor instanceof ClassDescriptor)) { - throw new UnsupportedOperationException("don't know how to handle non-class types in is"); + throw new UnsupportedOperationException("don't know how to handle non-class types"); } if (jetType.getArguments().size() > 0) { generateTypeInfo(jetType); - gen(expression.getLeftHandSide(), OBJECT_TYPE); + gen(expression, OBJECT_TYPE); + if (leaveExpressionOnStack) { + v.dupX1(); + } v.invokevirtual("jet/typeinfo/TypeInfo", "isInstance", "(Ljava/lang/Object;)Z"); } else { - gen(expression.getLeftHandSide(), OBJECT_TYPE); + gen(expression, OBJECT_TYPE); + if (leaveExpressionOnStack) { + v.dup(); + } Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); v.instanceOf(type); } - StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); - myStack.push(expression.isNot() ? StackValue.not(value) : value); } private void generateTypeInfo(JetType jetType) { @@ -1330,9 +1336,8 @@ public class ExpressionCodegen extends JetVisitor { if (declarationDescriptor instanceof TypeParameterDescriptor) { DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration(); if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) { - int index = indexOfTypeParameter((ClassDescriptor) contextType, (TypeParameterDescriptor) declarationDescriptor); loadTypeInfo((ClassDescriptor) contextType, v); - v.iconst(index); + v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex()); v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;"); return; } @@ -1361,15 +1366,6 @@ public class ExpressionCodegen extends JetVisitor { } } - private int indexOfTypeParameter(ClassDescriptor classDescriptor, TypeParameterDescriptor typeParameterDescriptor) { - List parameters = classDescriptor.getTypeConstructor().getParameters(); - int index = parameters.indexOf(typeParameterDescriptor); - if (index < 0) { - throw new UnsupportedOperationException("can't find type parameter index"); - } - return index; - } - private static class CompilationException extends RuntimeException { } } diff --git a/idea/testData/codegen/classes/diamondInheritance.jet b/idea/testData/codegen/classes/diamondInheritance.jet new file mode 100644 index 00000000000..8266ca75d38 --- /dev/null +++ b/idea/testData/codegen/classes/diamondInheritance.jet @@ -0,0 +1,22 @@ +class Base() { + public var v : Int +} + +class Left() : Base() {} +class Right() : Base() {} + +class D() : Left(), Right() + +fun vl(l : Left) : Int = l.v +fun vr(r : Right) : Int = r.v + +fun box() : String { + val d = new D() + d.v = 42 + + if (d.v != 42) return "Fail #1" + if (vl(d) != 42) return "Fail #2" + if (vr(d) != 42) return "Fail #3" + + return "OK" +} \ No newline at end of file diff --git a/idea/testData/codegen/classes/rightHandOverride.jet b/idea/testData/codegen/classes/rightHandOverride.jet new file mode 100644 index 00000000000..8f5562442fa --- /dev/null +++ b/idea/testData/codegen/classes/rightHandOverride.jet @@ -0,0 +1,18 @@ +class Left() {} +class Right() { + virtual fun f() = 42 +} + +class D() : Left(), Right() { + override fun f() = 239 +} + +fun box() : String { + val r : Right = new Right() + val d : D = new D() + + if (r.f() != 42) return "Fail #1" + if (d.f() != 239) return "Fail #2" + + return "OK" +} \ No newline at end of file diff --git a/idea/testData/codegen/typeInfo/asSafeWithGenerics.jet b/idea/testData/codegen/typeInfo/asSafeWithGenerics.jet new file mode 100644 index 00000000000..8d521b5c260 --- /dev/null +++ b/idea/testData/codegen/typeInfo/asSafeWithGenerics.jet @@ -0,0 +1,8 @@ +class Wrapper() { + fun castToSelf(wrapper: Any) = wrapper as? Wrapper +} + +fun foo() { + val wrapper = new Wrapper() + return wrapper.castToSelf(new Wrapper()) +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index cd1a4d03095..e856c5e7ea0 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -36,6 +36,14 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("classes/propertyDelegation.jet"); } + public void testDiamondInheritance() throws Exception { + blackBoxFile("classes/diamondInheritance.jet"); + } + + public void testRightHandOverride() throws Exception { + blackBoxFile("classes/rightHandOverride.jet"); + } + private static void checkInterface(Class aClass, Class ifs) { for (Class anInterface : aClass.getInterfaces()) { if (anInterface == ifs) return; diff --git a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index e8ecfbe0b53..71453d13979 100644 --- a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.parsing.JetParsingTest; +import javax.swing.JComponent; import java.lang.reflect.Method; import java.nio.channels.NonWritableChannelException; import java.util.HashMap; diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index 800973cf507..b34f95aaef1 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -65,6 +65,12 @@ public class TypeInfoTest extends CodegenTestCase { assertFalse((Boolean) foo.invoke(null)); } + public void testAsSafeWithGenerics() throws Exception { + loadFile(); + Method foo = generateFunction(); + assertNull(foo.invoke(null)); + } + private Runnable newRunnable() { return new Runnable() { @Override