From fa52f5f513da0e0a483b5aad9551ec2998705368 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 13 May 2011 15:08:57 +0200 Subject: [PATCH 1/4] initial implementation of as? --- .../jetbrains/jet/codegen/ClassCodegen.java | 6 ++-- .../jet/codegen/ExpressionCodegen.java | 35 ++++++++++++++++--- .../jetbrains/jet/codegen/JetTypeMapper.java | 16 +++++++-- .../jet/codegen/PropertyCodegen.java | 4 +-- .../jetbrains/jet/codegen/TypeInfoTest.java | 13 +++++++ 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 36975870014..92af8158517 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -73,7 +73,7 @@ public class ClassCodegen { ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor); v.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, - JetTypeMapper.jvmName(descriptor, kind), + JetTypeMapper.jetJvmName(descriptor, kind), null, superClass, new String[] { "jet/JetObject", JetTypeMapper.jvmNameForInterface(descriptor) } @@ -113,7 +113,7 @@ public class ClassCodegen { else if (first instanceof JetDelegatorToSuperCall) { JetType superType = bindingContext.resolveTypeReference(first.getTypeReference()); ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - return JetTypeMapper.jvmName(superClassDescriptor, kind); + return typeMapper.jvmName(superClassDescriptor, kind); } return "java/lang/Object"; @@ -177,7 +177,7 @@ public class ClassCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, classDescriptor, kind); - String classname = JetTypeMapper.jvmName(classDescriptor, kind); + String classname = typeMapper.jvmName(classDescriptor, kind); final Type classType = Type.getType("L" + classname + ";"); if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 4260ee3e098..2071803269d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -43,6 +43,7 @@ public class ExpressionCodegen extends JetVisitor { private static final String ITERATOR_NEXT_DESCRIPTOR = "()Ljava/lang/Object;"; private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V"; + private static final Type OBJECT_TYPE = Type.getType(Object.class); private static final Type ITERATOR_TYPE = Type.getType(Iterator.class); private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class); private static final Type JET_OBJECT_TYPE = Type.getType(JetObject.class); @@ -501,11 +502,11 @@ public class ExpressionCodegen extends JetVisitor { String fieldOwner; String interfaceOwner; if (isInsideClass || isStatic) { - fieldOwner = interfaceOwner = JetTypeMapper.getOwner(propertyDescriptor, contextKind); + fieldOwner = interfaceOwner = typeMapper.getOwner(propertyDescriptor, contextKind); } else { fieldOwner = null; - interfaceOwner = JetTypeMapper.getOwner(propertyDescriptor, OwnerKind.INTERFACE); + interfaceOwner = typeMapper.getOwner(propertyDescriptor, OwnerKind.INTERFACE); } return StackValue.property(propertyDescriptor.getName(), fieldOwner, interfaceOwner, typeMapper.mapType(outType), isStatic, getter, setter); @@ -1201,7 +1202,7 @@ public class ExpressionCodegen extends JetVisitor { v.load(0, JetTypeMapper.jetImplementationType(contextClass)); } else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) { - v.getfield(JetTypeMapper.jvmName(contextClass, contextKind), "$this", JetTypeMapper.jetInterfaceType(contextClass).getDescriptor()); + v.getfield(typeMapper.jvmName(contextClass, contextKind), "$this", JetTypeMapper.jetInterfaceType(contextClass).getDescriptor()); } else { throw new UnsupportedOperationException("Unknown kind: " + contextKind); @@ -1242,11 +1243,35 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) { JetSimpleNameExpression operationSign = expression.getOperationSign(); - if (operationSign.getReferencedNameElementType() == JetTokens.COLON) { + IElementType opToken = operationSign.getReferencedNameElementType(); + if (opToken == JetTokens.COLON) { gen(expression.getLeft()); } else { - throw new UnsupportedOperationException("should generate a cast, but don't know how"); + 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?"); + } + Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); + gen(expression.getLeft(), OBJECT_TYPE); + if (opToken == JetTokens.AS_SAFE) { + v.dup(); + v.instanceOf(type); + Label isInstance = new Label(); + v.ifne(isInstance); + v.pop(); + v.aconst(null); + v.mark(isInstance); + myStack.push(StackValue.onStack(type)); + } + else { + throw new UnsupportedOperationException("as not yet implemented"); + } } } diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index c7cb69c4c82..a32aefb4913 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -32,7 +32,15 @@ public class JetTypeMapper { return psiClass.getQualifiedName().replace(".", "/"); } - static String jvmName(ClassDescriptor jetClass, OwnerKind kind) { + public String jvmName(ClassDescriptor jetClass, OwnerKind kind) { + PsiElement declaration = bindingContext.getDeclarationPsiElement(jetClass); + if (declaration instanceof PsiClass) { + return jvmName((PsiClass) declaration); + } + return jetJvmName(jetClass, kind); + } + + public static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) { if (kind == OwnerKind.INTERFACE) { return jvmNameForInterface(jetClass); } @@ -48,6 +56,10 @@ public class JetTypeMapper { } } + public Type jvmType(ClassDescriptor jetClass, OwnerKind kind) { + return Type.getType("L" + jvmName(jetClass, kind) + ";"); + } + static Type psiClassType(PsiClass psiClass) { return Type.getType("L" + jvmName(psiClass) + ";"); } @@ -84,7 +96,7 @@ public class JetTypeMapper { return jvmNameForInterface(descriptor) + "$$DImpl"; } - static String getOwner(DeclarationDescriptor descriptor, OwnerKind kind) { + public String getOwner(DeclarationDescriptor descriptor, OwnerKind kind) { String owner; if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { owner = jvmName((NamespaceDescriptor) descriptor.getContainingDeclaration()); diff --git a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 3efba079165..dcdead60d80 100644 --- a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -160,7 +160,7 @@ public class PropertyCodegen { } else { iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD, - JetTypeMapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), + mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), type.getDescriptor()); } iv.areturn(type); @@ -206,7 +206,7 @@ public class PropertyCodegen { else { iv.load(paramCode, type); iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, - JetTypeMapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), + mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), type.getDescriptor()); } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index bc316608e86..cd9773c6beb 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -28,5 +28,18 @@ public class TypeInfoTest extends CodegenTestCase { TypeInfo typeInfo = (TypeInfo) foo.invoke(null); assertNotNull(typeInfo); } + + public void testAsSafeOperator() throws Exception { + loadText("fun foo(x: Any) = x as? Runnable"); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertNull(foo.invoke(null, new Object())); + Runnable r = new Runnable() { + @Override + public void run() { + } + }; + assertSame(r, foo.invoke(null, r)); + } } From 5711927522ea1471559e7368dd76a4002167d09e Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 13 May 2011 16:07:32 +0200 Subject: [PATCH 2/4] initial implementation of 'is' operator --- .../jet/codegen/ExpressionCodegen.java | 21 +++++++++++++++++++ .../jetbrains/jet/codegen/TypeInfoTest.java | 15 +++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 2071803269d..76dc4cfe4c6 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1281,6 +1281,27 @@ public class ExpressionCodegen extends JetVisitor { v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); } + @Override + public void visitIsExpression(JetIsExpression expression) { + JetPattern pattern = expression.getPattern(); + if (!(pattern instanceof JetTypePattern)) { + throw new UnsupportedOperationException("can only generate a type pattern with 'is'"); + } + JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference(); + JetType jetType = bindingContext.resolveTypeReference(typeReference); + if (jetType.getArguments().size() > 0) { + throw new UnsupportedOperationException("don't know how to handle type arguments in is"); + } + DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); + if (!(descriptor instanceof ClassDescriptor)) { + throw new UnsupportedOperationException("don't know how to handle non-class types in is"); + } + gen(expression.getLeftHandSide(), OBJECT_TYPE); + Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); + v.instanceOf(type); + myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE)); + } + private static class CompilationException extends RuntimeException { } } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index cd9773c6beb..d4cbf33b702 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -34,12 +34,23 @@ public class TypeInfoTest extends CodegenTestCase { System.out.println(generateToText()); Method foo = generateFunction(); assertNull(foo.invoke(null, new Object())); - Runnable r = new Runnable() { + Runnable r = newRunnable(); + assertSame(r, foo.invoke(null, r)); + } + + public void testIsOperator() throws Exception { + loadText("fun foo(x: Any) = x is Runnable"); + Method foo = generateFunction(); + assertFalse((Boolean) foo.invoke(null, new Object())); + assertTrue((Boolean) foo.invoke(null, newRunnable())); + } + + private Runnable newRunnable() { + return new Runnable() { @Override public void run() { } }; - assertSame(r, foo.invoke(null, r)); } } From 26790f1346d2a61198347c54186699ac992866c8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 13 May 2011 18:06:25 +0200 Subject: [PATCH 3/4] 'is' works with generic types correctly (initial implementation of reified generics) --- .../jetbrains/jet/codegen/ClassCodegen.java | 72 +++++++++++++++---- .../jet/codegen/ExpressionCodegen.java | 47 ++++++++++-- .../jetbrains/jet/codegen/JetTypeMapper.java | 24 +++++-- .../org/jetbrains/jet/lang/ErrorHandler.java | 3 +- .../codegen/typeInfo/isWithGenerics.jet | 7 ++ .../jetbrains/jet/codegen/TypeInfoTest.java | 7 ++ stdlib/src/jet/typeinfo/TypeInfo.java | 52 ++++++++++++-- 7 files changed, 179 insertions(+), 33 deletions(-) create mode 100644 idea/testData/codegen/typeInfo/isWithGenerics.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 92af8158517..f962710f5d8 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -3,7 +3,6 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; -import jet.typeinfo.TypeInfo; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -28,8 +27,6 @@ public class ClassCodegen { private final Codegens factory; private final JetTypeMapper typeMapper; - private static final Type TYPEINFO_TYPE = Type.getType(TypeInfo.class); - public ClassCodegen(Project project, Codegens factory, BindingContext bindingContext) { this.project = project; this.factory = factory; @@ -79,13 +76,14 @@ public class ClassCodegen { new String[] { "jet/JetObject", JetTypeMapper.jvmNameForInterface(descriptor) } ); - v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); + int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC; + v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); generateStaticInitializer(descriptor, v); generatePrimaryConstructor(aClass, v, kind); - generateGetTypeInfo(aClass, v); + generateGetTypeInfo(descriptor, v); generateClassBody(aClass, v, kind); @@ -193,6 +191,17 @@ public class ClassCodegen { frameMap.enter(parameter, argTypes[i].getSize()); } + int firstTypeParameter = -1; + int typeParamCount = classDescriptor.getTypeConstructor().getParameters().size(); + if (kind == OwnerKind.IMPLEMENTATION) { + if (typeParamCount > 0) { + firstTypeParameter = frameMap.enterTemp(); + for (int i = 1; i < typeParamCount; i++) { + frameMap.enterTemp(); + } + } + } + List specifiers = aClass.getDelegationSpecifiers(); if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) { @@ -264,6 +273,10 @@ public class ClassCodegen { n++; } + if (firstTypeParameter > 0 && kind == OwnerKind.IMPLEMENTATION) { + generateTypeInfoInitializer(classDescriptor, firstTypeParameter, typeParamCount, iv); + } + generateInitializers(aClass, kind, codegen, iv); int curParam = 0; @@ -284,6 +297,25 @@ public class ClassCodegen { mv.visitEnd(); } + private void generateTypeInfoInitializer(ClassDescriptor classDescriptor, int firstTypeParameter, int typeParamCount, InstructionAdapter iv) { + iv.load(0, JetTypeMapper.TYPE_OBJECT); + iv.anew(JetTypeMapper.TYPE_TYPEINFO); + iv.dup(); + + iv.aconst(typeMapper.jvmType(classDescriptor, OwnerKind.INTERFACE)); + iv.iconst(typeParamCount); + iv.newarray(JetTypeMapper.TYPE_TYPEINFO); + + for (int i = 0; i < typeParamCount; i++) { + iv.dup(); + iv.iconst(i); + iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); + iv.astore(JetTypeMapper.TYPE_OBJECT); + } + iv.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;[Ljet/typeinfo/TypeInfo;)V"); + iv.putfield(typeMapper.jvmName(classDescriptor, OwnerKind.IMPLEMENTATION), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + private void generateInitializers(JetClass aClass, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter iv) { for (JetDeclaration declaration : aClass.getDeclarations()) { if (declaration instanceof JetProperty) { @@ -360,15 +392,16 @@ public class ClassCodegen { } private void generateStaticInitializer(ClassDescriptor descriptor, ClassVisitor cv) { + if (descriptor.getTypeConstructor().getParameters().size() > 0) { + // we will have a dynamic type info field + return; + } final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "", "()V", null, null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); - v.anew(TYPEINFO_TYPE); - v.dup(); - v.aconst(Type.getObjectType(JetTypeMapper.jvmNameForInterface(descriptor))); - v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;)V"); + newTypeInfo(v, Type.getObjectType(JetTypeMapper.jvmNameForInterface(descriptor))); v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); mv.visitInsn(Opcodes.RETURN); @@ -377,7 +410,14 @@ public class ClassCodegen { mv.visitEnd(); } - private void generateGetTypeInfo(JetClass aClass, ClassVisitor cv) { + public static void newTypeInfo(InstructionAdapter v, Type asmType) { + v.anew(JetTypeMapper.TYPE_TYPEINFO); + v.dup(); + v.aconst(asmType); + v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;)V"); + } + + private void generateGetTypeInfo(ClassDescriptor descriptor, ClassVisitor cv) { final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", @@ -385,9 +425,15 @@ public class ClassCodegen { null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); - ClassDescriptor descriptor = bindingContext.getClassDescriptor(aClass); - v.getstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - v.areturn(TYPEINFO_TYPE); + String owner = JetTypeMapper.jvmNameForImplementation(descriptor); + if (descriptor.getTypeConstructor().getParameters().size() > 0) { + v.load(0, JetTypeMapper.TYPE_OBJECT); + v.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + else { + v.getstatic(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + v.areturn(JetTypeMapper.TYPE_TYPEINFO); mv.visitMaxs(0, 0); mv.visitEnd(); } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 76dc4cfe4c6..736082b0022 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1147,6 +1147,13 @@ public class ExpressionCodegen extends JetVisitor { Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); pushMethodArguments(expression, method); + + for (JetTypeReference typeArgumentReference : constructorType.getTypeArgumentsAsTypes()) { + JetType typeArgument = bindingContext.resolveTypeReference(typeArgumentReference); + // TODO is the makeNullable() call correct here? + ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument))); + } + v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "", method.getDescriptor()); myStack.push(StackValue.onStack(type)); return; @@ -1289,19 +1296,47 @@ public class ExpressionCodegen extends JetVisitor { } JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference(); JetType jetType = bindingContext.resolveTypeReference(typeReference); - if (jetType.getArguments().size() > 0) { - throw new UnsupportedOperationException("don't know how to handle type arguments in is"); - } DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); if (!(descriptor instanceof ClassDescriptor)) { throw new UnsupportedOperationException("don't know how to handle non-class types in is"); } - gen(expression.getLeftHandSide(), OBJECT_TYPE); - Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); - v.instanceOf(type); + if (jetType.getArguments().size() > 0) { + newTypeInfo(jetType); + gen(expression.getLeftHandSide(), OBJECT_TYPE); + v.invokevirtual("jet/typeinfo/TypeInfo", "isInstance", "(Ljava/lang/Object;)Z"); + } + else { + gen(expression.getLeftHandSide(), OBJECT_TYPE); + Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); + v.instanceOf(type); + } myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE)); } + private void newTypeInfo(JetType jetType) { + v.anew(JetTypeMapper.TYPE_TYPEINFO); + v.dup(); + + v.aconst(typeMapper.jvmType((ClassDescriptor) jetType.getConstructor().getDeclarationDescriptor(), OwnerKind.INTERFACE)); + List arguments = jetType.getArguments(); + if (arguments.size() > 0) { + v.iconst(arguments.size()); + v.newarray(JetTypeMapper.TYPE_TYPEINFO); + + for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) { + TypeProjection argument = arguments.get(i); + v.dup(); + v.iconst(i); + newTypeInfo(argument.getType()); + v.astore(JetTypeMapper.TYPE_OBJECT); + } + v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;[Ljet/typeinfo/TypeInfo;)V"); + } + else { + v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;)V"); + } + } + private static class CompilationException extends RuntimeException { } } diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a32aefb4913..260389ff6d7 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import jet.typeinfo.TypeInfo; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -12,6 +13,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.ArrayList; import java.util.List; /** @@ -19,6 +21,7 @@ import java.util.List; */ public class JetTypeMapper { static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object"); + static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class); private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; @@ -57,6 +60,9 @@ public class JetTypeMapper { } public Type jvmType(ClassDescriptor jetClass, OwnerKind kind) { + if (jetClass == standardLibrary.getString()) { + return Type.getType(String.class); + } return Type.getType("L" + jvmName(jetClass, kind) + ";"); } @@ -227,17 +233,21 @@ public class JetTypeMapper { public Method mapConstructorSignature(ConstructorDescriptor descriptor, OwnerKind kind) { boolean delegate = kind == OwnerKind.DELEGATING_IMPLEMENTATION; List parameters = descriptor.getUnsubstitutedValueParameters(); - int count = parameters.size(); - int first = delegate ? 1 : 0; - Type[] parameterTypes = new Type[count + first]; + List parameterTypes = new ArrayList(); + ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); if (delegate) { - parameterTypes[0] = jetInterfaceType(descriptor.getContainingDeclaration()); + parameterTypes.add(jetInterfaceType(classDescriptor)); + } + for (ValueParameterDescriptor parameter : parameters) { + parameterTypes.add(mapType(parameter.getOutType())); } - for (int i = 0; i < count; i++) { - parameterTypes[i + first] = mapType(parameters.get(i).getOutType()); + List typeParameters = classDescriptor.getTypeConstructor().getParameters(); + for (TypeParameterDescriptor typeParameter : typeParameters) { + parameterTypes.add(TYPE_TYPEINFO); } - return new Method("", Type.VOID_TYPE, parameterTypes); + + return new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); } static int getAccessModifiers(JetDeclaration p, int defaultFlags) { diff --git a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java index e34a917e9ad..2f591de0e6c 100644 --- a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java +++ b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java @@ -15,7 +15,8 @@ public class ErrorHandler { public static final ErrorHandler THROW_EXCEPTION = new ErrorHandler() { @Override public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) { - throw new IllegalStateException("Unresolved reference: " + referenceExpression.getText()); + throw new IllegalStateException("Unresolved reference: " + referenceExpression.getText() + + " at offset " + referenceExpression.getTextRange().getStartOffset()); } @Override diff --git a/idea/testData/codegen/typeInfo/isWithGenerics.jet b/idea/testData/codegen/typeInfo/isWithGenerics.jet new file mode 100644 index 00000000000..416799acd8a --- /dev/null +++ b/idea/testData/codegen/typeInfo/isWithGenerics.jet @@ -0,0 +1,7 @@ +class Wrapper() { +} + +fun foo() { + val wrapper = new Wrapper() + return wrapper is Wrapper +} diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index d4cbf33b702..d9f7a070b07 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -45,6 +45,13 @@ public class TypeInfoTest extends CodegenTestCase { assertTrue((Boolean) foo.invoke(null, newRunnable())); } + public void testIsWithGenerics() throws Exception { + loadFile(); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertFalse((Boolean) foo.invoke(null)); + } + private Runnable newRunnable() { return new Runnable() { @Override diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 7a6b78f2c23..5f80f501fe2 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -2,29 +2,49 @@ package jet.typeinfo; import jet.JetObject; +import java.util.Arrays; + /** * @author abreslav */ public class TypeInfo implements JetObject { - private TypeInfo typeInfo; - private TypeInfo typeArgument; - private Class theClass; + private final Class theClass; + private final TypeInfo[] typeParameters; public TypeInfo(Class theClass) { this.theClass = theClass; + this.typeParameters = null; } - private TypeInfo(TypeInfo typeArgument) { - this.typeArgument = typeArgument; + public TypeInfo(Class theClass, TypeInfo[] typeParameters) { + this.theClass = theClass; + this.typeParameters = typeParameters; } public boolean isInstance(Object obj) { + if (obj instanceof JetObject) { + return isSubtypeOf(((JetObject) obj).getTypeInfo()); + } throw new UnsupportedOperationException(); // TODO } public boolean isSubtypeOf(TypeInfo other) { - throw new UnsupportedOperationException(); // TODO + if (!theClass.isAssignableFrom(other.theClass)) { + return false; + } + if (typeParameters != null) { + if (other.typeParameters == null || other.typeParameters.length != typeParameters.length) { + throw new IllegalArgumentException("inconsistent type infos for the same class"); + } + for (int i = 0; i < typeParameters.length; i++) { + // TODO handle variance here + if (!typeParameters [i].equals(other.typeParameters [i])) { + return false; + } + } + } + return true; } @Override @@ -35,4 +55,24 @@ public class TypeInfo implements JetObject { } return typeInfo; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TypeInfo typeInfo = (TypeInfo) o; + + if (!theClass.equals(typeInfo.theClass)) return false; + if (!Arrays.equals(typeParameters, typeInfo.typeParameters)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = theClass.hashCode(); + result = 31 * result + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); + return result; + } } From 82dabdc8d5c3fd3d81d8830bfcf938b7bf90268d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 13 May 2011 18:21:30 +0200 Subject: [PATCH 4/4] !is is supported --- .../org/jetbrains/jet/codegen/ExpressionCodegen.java | 3 ++- .../org/jetbrains/jet/lang/psi/JetIsExpression.java | 11 +++++++++++ .../tests/org/jetbrains/jet/codegen/TypeInfoTest.java | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 736082b0022..4767cf6d25d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1310,7 +1310,8 @@ public class ExpressionCodegen extends JetVisitor { Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); v.instanceOf(type); } - myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE)); + StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); + myStack.push(expression.isNot() ? StackValue.not(value) : value); } private void newTypeInfo(JetType jetType) { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetIsExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetIsExpression.java index a4e8ffb2a33..b3fa7f19d54 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetIsExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetIsExpression.java @@ -3,6 +3,8 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; /** * @author abreslav @@ -27,4 +29,13 @@ public class JetIsExpression extends JetExpression { return findChildByClass(JetPattern.class); } + @NotNull + public JetSimpleNameExpression getOperationReference() { + return (JetSimpleNameExpression) findChildByType(JetNodeTypes.OPERATION_REFERENCE); + } + + public boolean isNot() { + return getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IS; + } + } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index d9f7a070b07..998704da068 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -52,6 +52,13 @@ public class TypeInfoTest extends CodegenTestCase { assertFalse((Boolean) foo.invoke(null)); } + public void testNotIsOperator() throws Exception { + loadText("fun foo(x: Any) = x !is Runnable"); + Method foo = generateFunction(); + assertTrue((Boolean) foo.invoke(null, new Object())); + assertFalse((Boolean) foo.invoke(null, newRunnable())); + } + private Runnable newRunnable() { return new Runnable() { @Override