From d4453c055e42e1e478921d9700f9aa259d0fc9ee Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 30 Jun 2011 18:57:30 +0200 Subject: [PATCH] pass type arguments to generic functions --- .../jetbrains/jet/codegen/ClosureCodegen.java | 3 +- .../jet/codegen/ExpressionCodegen.java | 36 +++++++++++++------ .../jet/codegen/FunctionCodegen.java | 26 ++++++++++---- .../jetbrains/jet/codegen/JetTypeMapper.java | 3 ++ .../jet/codegen/PropertyCodegen.java | 13 +++---- .../codegen/typeInfo/genericFunction.jet | 10 ++++++ .../jetbrains/jet/codegen/TypeInfoTest.java | 4 +++ stdlib/src/jet/typeinfo/TypeInfo.java | 1 + 8 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 idea/testData/codegen/typeInfo/genericFunction.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java index e5eac77e99d..f3d2983f81d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -123,7 +123,8 @@ public class ClosureCodegen { private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, List body) { FunctionCodegen fc = new FunctionCodegen(null, cv, state); - fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(), funDescriptor.getValueParameters(), null); + fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(), + funDescriptor.getValueParameters(), funDescriptor.getTypeParameters(), null); } private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) { diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index ba161f31dff..10de4a52cce 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -29,6 +29,7 @@ import java.util.*; /** * @author max + * @author yole */ public class ExpressionCodegen extends JetVisitor { private static final String CLASS_OBJECT = "java/lang/Object"; @@ -83,6 +84,7 @@ public class ExpressionCodegen extends JetVisitor { private final BindingContext bindingContext; private final StackValue thisExpression; private final Map outerThisExpressions = new HashMap(); + private final Map typeParameterExpressions = new HashMap(); public ExpressionCodegen(MethodVisitor v, FrameMap myMap, @@ -106,6 +108,10 @@ public class ExpressionCodegen extends JetVisitor { outerThisExpressions.put(outer, expression); } + public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) { + typeParameterExpressions.put(typeParameter, expression); + } + static void loadTypeInfo(JetTypeMapper typeMapper, ClassDescriptor descriptor, InstructionAdapter v) { String owner = typeMapper.jvmName(descriptor, OwnerKind.IMPLEMENTATION); if (descriptor.getTypeConstructor().getParameters().size() > 0) { @@ -785,6 +791,7 @@ public class ExpressionCodegen extends JetVisitor { ensureReceiverOnStack(expression, null); } pushMethodArguments(expression, methodDescriptor); + pushTypeArguments(expression); final String owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent)); v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); } @@ -792,6 +799,7 @@ public class ExpressionCodegen extends JetVisitor { ClassDescriptor containingClass = (ClassDescriptor) functionParent; ensureReceiverOnStack(expression, containingClass); pushMethodArguments(expression, methodDescriptor); + pushTypeArguments(expression); final String owner = typeMapper.jvmName(containingClass, OwnerKind.INTERFACE); int opcode = typeMapper.isInterface(containingClass, OwnerKind.INTERFACE) ? Opcodes.INVOKEINTERFACE @@ -1456,12 +1464,7 @@ public class ExpressionCodegen extends JetVisitor { Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); pushMethodArguments(expression, method); - - for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) { - JetType typeArgument = bindingContext.resolveTypeReference(jetTypeArgument.getTypeReference()); - // TODO is the makeNullable() call correct here? - ClassCodegen.newTypeInfo(v, typeArgument.isNullable(), typeMapper.mapType(TypeUtils.makeNullable(typeArgument))); - } + pushTypeArguments(expression); v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "", method.getDescriptor()); } @@ -1472,6 +1475,14 @@ public class ExpressionCodegen extends JetVisitor { myStack.push(StackValue.onStack(type)); } + private void pushTypeArguments(JetCall expression) { + for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) { + JetType typeArgument = bindingContext.resolveTypeReference(jetTypeArgument.getTypeReference()); + // TODO is the makeNullable() call correct here? + ClassCodegen.newTypeInfo(v, typeArgument.isNullable(), typeMapper.mapType(TypeUtils.makeNullable(typeArgument))); + } + } + private void pushOuterClassArguments(ClassDescriptor classDecl) { if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { v.load(0, JetTypeMapper.jetImplementationType(classDecl)); @@ -1709,7 +1720,7 @@ public class ExpressionCodegen extends JetVisitor { private void generateTypeInfo(JetType jetType) { DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof TypeParameterDescriptor) { - loadTypeParameterTypeInfo(declarationDescriptor); + loadTypeParameterTypeInfo((TypeParameterDescriptor) declarationDescriptor); return; } @@ -1742,11 +1753,16 @@ public class ExpressionCodegen extends JetVisitor { } } - private void loadTypeParameterTypeInfo(DeclarationDescriptor declarationDescriptor) { - DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration(); + private void loadTypeParameterTypeInfo(TypeParameterDescriptor typeParameterDescriptor) { + final StackValue value = typeParameterExpressions.get(typeParameterDescriptor); + if (value != null) { + value.put(JetTypeMapper.TYPE_TYPEINFO, v); + return; + } + DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) { loadTypeInfo(typeMapper, (ClassDescriptor) contextType, v); - v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex()); + v.iconst(typeParameterDescriptor.getIndex()); v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;"); return; } diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 787fab71c3b..46486e24e29 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -2,6 +2,8 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.JetType; @@ -17,6 +19,7 @@ import java.util.List; /** * @author max + * @author yole */ public class FunctionCodegen { private final JetDeclaration owner; @@ -33,21 +36,23 @@ public class FunctionCodegen { final JetTypeReference receiverTypeRef = f.getReceiverTypeRef(); final JetType receiverType = receiverTypeRef == null ? null : state.getBindingContext().resolveTypeReference(receiverTypeRef); Method method = state.getTypeMapper().mapSignature(f); - List paramDescrs = state.getBindingContext().getFunctionDescriptor(f).getValueParameters(); - generateMethod(f, kind, method, receiverType, paramDescrs); + final FunctionDescriptor functionDescriptor = state.getBindingContext().getFunctionDescriptor(f); + generateMethod(f, kind, method, receiverType, functionDescriptor.getValueParameters(), + functionDescriptor.getTypeParameters()); } public void generateMethod(JetDeclarationWithBody f, OwnerKind kind, Method jvmSignature, @Nullable JetType receiverType, - List paramDescrs) { + List paramDescrs, + List typeParameters) { final DeclarationDescriptor contextDesc = owner instanceof JetClassOrObject ? state.getBindingContext().getClassDescriptor((JetClassOrObject) owner) : state.getBindingContext().getNamespaceDescriptor((JetNamespace) owner); final JetExpression bodyExpression = f.getBodyExpression(); final List bodyExpressions = bodyExpression != null ? Collections.singletonList(bodyExpression) : null; - generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, contextDesc); + generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, typeParameters, contextDesc); } public void generatedMethod(List bodyExpressions, @@ -55,6 +60,7 @@ public class FunctionCodegen { Method jvmSignature, JetType receiverType, List paramDescrs, + List typeParameters, DeclarationDescriptor contextDesc) { int flags = Opcodes.ACC_PUBLIC; // TODO. @@ -85,14 +91,22 @@ public class FunctionCodegen { frameMap.enterTemp(); // Next slot for fake this } + StackValue thisExpression = receiverType == null ? null : StackValue.local(thisIdx, state.getTypeMapper().mapType(receiverType)); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), contextDesc, kind, thisExpression, state); + + int firstArg = thisIdx+1; Type[] argTypes = jvmSignature.getArgumentTypes(); for (int i = 0; i < paramDescrs.size(); i++) { ValueParameterDescriptor parameter = paramDescrs.get(i); frameMap.enter(parameter, argTypes[i].getSize()); } + for (int i = 0; i < typeParameters.size(); i++) { + final TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i); + codegen.addTypeParameter(typeParameterDescriptor, + StackValue.local(firstArg + paramDescrs.size() + i, JetTypeMapper.TYPE_TYPEINFO)); + frameMap.enterTemp(); + } - StackValue thisExpression = receiverType == null ? null : StackValue.local(thisIdx, state.getTypeMapper().mapType(receiverType)); - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), contextDesc, kind, thisExpression, state); if (kind instanceof OwnerKind.DelegateKind) { OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; InstructionAdapter iv = new InstructionAdapter(mv); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 899e4f41097..6af99e1fcd9 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -282,6 +282,9 @@ public class JetTypeMapper { for (JetParameter parameter : parameters) { parameterTypes.add(mapType(bindingContext.resolveTypeReference(parameter.getTypeReference()))); } + for (JetTypeParameter p: f.getTypeParameters()) { + parameterTypes.add(TYPE_TYPEINFO); + } final JetTypeReference returnTypeRef = f.getReturnTypeRef(); Type returnType; if (returnTypeRef == null) { diff --git a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 6ad1bda0992..cd1a8cbb512 100644 --- a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lexer.JetTokens; @@ -97,7 +94,9 @@ public class PropertyCodegen { if (getter != null) { if (getter.getBodyExpression() != null) { functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), - null, Collections.emptyList()); + null, + Collections.emptyList(), + Collections.emptyList()); } else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { generateDefaultGetter(p, getter, kind); @@ -119,7 +118,9 @@ public class PropertyCodegen { final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); assert setterDescriptor != null; functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor), - null, setterDescriptor.getValueParameters()); + null, + setterDescriptor.getValueParameters(), + Collections.emptyList()); } else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { generateDefaultSetter(p, setter, kind); diff --git a/idea/testData/codegen/typeInfo/genericFunction.jet b/idea/testData/codegen/typeInfo/genericFunction.jet new file mode 100644 index 00000000000..0bf37d064fe --- /dev/null +++ b/idea/testData/codegen/typeInfo/genericFunction.jet @@ -0,0 +1,10 @@ +class Foo() { } +class Bar() { } + +fun isInstance(obj: Any?) = obj is T + +fun box(): String { + if (! isInstance(Foo())) return "fail 1" + if (isInstance(Foo())) return "fail 2" + return "OK" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index 1535e5e062b..88db7e87331 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -96,6 +96,10 @@ public class TypeInfoTest extends CodegenTestCase { blackBoxFile("typeInfo/nullability.jet"); } + public void testGenericFunction() throws Exception { + blackBoxFile("typeInfo/genericFunction.jet"); + } + private Runnable newRunnable() { return new Runnable() { @Override diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 85f6829bf50..3ef38ffc45f 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -6,6 +6,7 @@ import java.util.Arrays; /** * @author abreslav + * @author yole */ public class TypeInfo implements JetObject { private TypeInfo typeInfo;