diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 05675d4d54e..abb55139874 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -25,10 +25,10 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; -import org.jetbrains.asm4.signature.SignatureWriter; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.LocalLookup; +import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationStateAware; @@ -43,12 +43,13 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import java.util.Collection; +import java.util.Collections; import java.util.List; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.AsmUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.isConst; -import static org.jetbrains.jet.codegen.FunctionTypesUtil.getFunctionImplClassName; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; public class ClosureCodegen extends GenerationStateAware { @@ -290,40 +291,22 @@ public class ClosureCodegen extends GenerationStateAware { @NotNull private String getGenericSignature() { - SignatureWriter signatureWriter = new SignatureWriter(); - JvmClassName funClass = getFunctionImplClassName(funDescriptor); - signatureWriter.visitClassType(funClass.getInternalName()); - ReceiverParameterDescriptor receiverParameter = funDescriptor.getReceiverParameter(); - if (receiverParameter != null) { - appendType(signatureWriter, receiverParameter.getType(), '='); - } - for (ValueParameterDescriptor parameter : funDescriptor.getValueParameters()) { - appendType(signatureWriter, parameter.getType(), '='); - } + ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); + Collection supertypes = classDescriptor.getTypeConstructor().getSupertypes(); + assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor; + JetType supertype = supertypes.iterator().next(); - appendType(signatureWriter, funDescriptor.getReturnType(), '='); - signatureWriter.visitEnd(); + BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true); + typeMapper.writeFormalTypeParameters(Collections.emptyList(), sw); + sw.writeSupersStart(); + sw.writeSuperclass(); + typeMapper.mapType(supertype, sw, JetTypeMapperMode.TYPE_PARAMETER); + sw.writeSuperclassEnd(); + sw.writeSupersEnd(); - return signatureWriter.toString(); - } - - private void appendType(SignatureWriter signatureWriter, JetType type, char variance) { - signatureWriter.visitTypeArgument(variance); - - Type rawRetType = typeMapper.mapType(type, JetTypeMapperMode.TYPE_PARAMETER); - while (rawRetType.getSort() == Type.ARRAY) { - signatureWriter.visitArrayType(); - rawRetType = rawRetType.getElementType(); - } - - if (rawRetType.getSort() == Type.OBJECT) { - signatureWriter.visitClassType(rawRetType.getInternalName()); - signatureWriter.visitEnd(); - } - else { - assert isPrimitive(rawRetType); - signatureWriter.visitBaseType(rawRetType.getDescriptor().charAt(0)); - } + String signature = sw.makeJavaGenericSignature(); + assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor; + return signature; } private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionTypesUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionTypesUtil.java index 78886ac2823..0d403dd8bc6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionTypesUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionTypesUtil.java @@ -25,6 +25,8 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeImpl; +import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.ArrayList; @@ -85,13 +87,54 @@ public class FunctionTypesUtil { } @NotNull - public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor funDescriptor, int arity) { - if (funDescriptor.getReceiverParameter() != null) { - return EXTENSION_FUNCTIONS.get(arity).getDefaultType(); + public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor descriptor, boolean kFunction) { + int arity = descriptor.getValueParameters().size(); + + ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); + ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject(); + + List typeArguments = new ArrayList(arity + 2); + if (receiverParameter != null) { + typeArguments.add(new TypeProjection(receiverParameter.getType())); + } + else if (kFunction && expectedThisObject != null) { + typeArguments.add(new TypeProjection(expectedThisObject.getType())); + } + + for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { + typeArguments.add(new TypeProjection(parameter.getType())); + } + + typeArguments.add(new TypeProjection(descriptor.getReturnType())); + + ClassDescriptor classDescriptor; + if (kFunction) { + if (expectedThisObject != null) { + classDescriptor = K_MEMBER_FUNCTIONS.get(arity); + } + else if (receiverParameter != null) { + classDescriptor = K_EXTENSION_FUNCTIONS.get(arity); + } + else { + classDescriptor = K_FUNCTIONS.get(arity); + } } else { - return FUNCTIONS.get(arity).getDefaultType(); + if (receiverParameter != null) { + classDescriptor = EXTENSION_FUNCTIONS.get(arity); + } + else { + classDescriptor = FUNCTIONS.get(arity); + } } + + return new JetTypeImpl( + classDescriptor.getDefaultType().getAnnotations(), + classDescriptor.getTypeConstructor(), + false, + typeArguments, + classDescriptor.getMemberScope(typeArguments) + ); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java index 19f9779c035..05f737656ab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java @@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; import java.util.HashMap; @@ -80,9 +81,9 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { } } - private ClassDescriptor recordClassForFunction(FunctionDescriptor funDescriptor) { + @NotNull + private ClassDescriptor recordClassForFunction(@NotNull FunctionDescriptor funDescriptor, @NotNull JetType superType) { ClassDescriptor classDescriptor; - int arity = funDescriptor.getValueParameters().size(); classDescriptor = new ClassDescriptorImpl( funDescriptor.getContainingDeclaration(), @@ -92,7 +93,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { ((ClassDescriptorImpl)classDescriptor).initialize( false, Collections.emptyList(), - Collections.singleton(getSuperTypeForClosure(funDescriptor, arity)), + Collections.singleton(superType), JetScope.EMPTY, Collections.emptySet(), null, @@ -258,7 +259,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { if (functionDescriptor == null) return; String name = inventAnonymousClassName(expression); - ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); + JetType superType = getSuperTypeForClosure(functionDescriptor, false); + ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(functionLiteral, classDescriptor, name, true); classStack.push(classDescriptor); @@ -274,8 +276,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { // working around a problem with shallow analysis if (functionDescriptor == null) return; + ResolvedCall referencedFunction = + bindingContext.get(RESOLVED_CALL, expression.getCallableReference()); + if (referencedFunction == null) return; + JetType superType = getSuperTypeForClosure((FunctionDescriptor) referencedFunction.getResultingDescriptor(), true); + String name = inventAnonymousClassName(expression); - ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); + ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(expression, classDescriptor, name, true); classStack.push(classDescriptor); @@ -326,7 +333,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { } else { String name = inventAnonymousClassName(function); - ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); + JetType superType = getSuperTypeForClosure(functionDescriptor, false); + ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(function, classDescriptor, name, true); classStack.push(classDescriptor); diff --git a/compiler/testData/codegen/box/callableReference/toString.kt b/compiler/testData/codegen/box/callableReference/toString.kt new file mode 100644 index 00000000000..1670fa0609d --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/toString.kt @@ -0,0 +1,21 @@ +fun foo(s: String) {} + +class A { + fun bar(): String = "" +} + +fun A.baz() {} + + +fun box(): String { + val f = "${::foo}" + if (f != "jet.KFunctionImpl1") return "Fail foo: $f" + + val g = "${A::bar}" + if (g != "jet.KMemberFunctionImpl0") return "Fail bar: $f" + + val h = "${A::baz}" + if (h != "jet.KExtensionFunctionImpl0") return "Fail baz: $h" + + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/functionNtoString.kt b/compiler/testData/codegen/box/functions/functionNtoString.kt index bfef8690d4a..afc04d88154 100644 --- a/compiler/testData/codegen/box/functions/functionNtoString.kt +++ b/compiler/testData/codegen/box/functions/functionNtoString.kt @@ -6,22 +6,22 @@ fun check(expected: String, obj: Any?) { fun box(): String { - check("jet.FunctionImpl0") + check("jet.FunctionImpl0") { () : Unit -> } - check("jet.FunctionImpl0") + check("jet.FunctionImpl0") { () : Int -> 42 } - check("jet.FunctionImpl1") + check("jet.FunctionImpl1") { (s: String) : Long -> 42.toLong() } - check("jet.FunctionImpl2") + check("jet.FunctionImpl2") { (x: Int, y: Int) : Unit -> } - check("jet.ExtensionFunctionImpl0") + check("jet.ExtensionFunctionImpl0") { Int.() : Unit -> } - check("jet.ExtensionFunctionImpl0") + check("jet.ExtensionFunctionImpl0") { Unit.() : Int -> 42 } - check("jet.ExtensionFunctionImpl1") + check("jet.ExtensionFunctionImpl1") { String.(s: String) : Long -> 42.toLong() } - check("jet.ExtensionFunctionImpl2") + check("jet.ExtensionFunctionImpl2") { Int.(x: Int, y: Int) : Unit -> } return "OK" diff --git a/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt b/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt index 5e5d9c482f9..e9604552c5d 100644 --- a/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt +++ b/compiler/testData/codegen/box/reflection/functionLiteralGenericSignature.kt @@ -12,18 +12,20 @@ val unitFun = { } val intFun = { 42 } val stringParamFun = { (x: String) : Unit -> } val listFun = { (l: List) : List -> l } +val mutableListFun = { (l: MutableList) : MutableList -> null!! } val extensionFun = { Any.() : Unit -> } val extensionWithArgFun = { Long.(x: Any) : Date -> Date() } fun box(): String { - assertGenericSuper("jet.FunctionImpl0", unitFun) - assertGenericSuper("jet.FunctionImpl0", intFun) - assertGenericSuper("jet.FunctionImpl1", stringParamFun) - assertGenericSuper("jet.FunctionImpl1", listFun) + assertGenericSuper("jet.FunctionImpl0", unitFun) + assertGenericSuper("jet.FunctionImpl0", intFun) + assertGenericSuper("jet.FunctionImpl1", stringParamFun) + assertGenericSuper("jet.FunctionImpl1, ? extends java.util.List>", listFun) + assertGenericSuper("jet.FunctionImpl1, ? extends java.util.List>", mutableListFun) - assertGenericSuper("jet.ExtensionFunctionImpl0", extensionFun) - assertGenericSuper("jet.ExtensionFunctionImpl1", extensionWithArgFun) + assertGenericSuper("jet.ExtensionFunctionImpl0", extensionFun) + assertGenericSuper("jet.ExtensionFunctionImpl1", extensionWithArgFun) return "OK" } diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 2bec24f153a..1fcde357b04 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -564,6 +564,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/callableReference/sortListOfStrings.kt"); } + @TestMetadata("toString.kt") + public void testToString() throws Exception { + doTest("compiler/testData/codegen/box/callableReference/toString.kt"); + } + @TestMetadata("topLevelFromClass.kt") public void testTopLevelFromClass() throws Exception { doTest("compiler/testData/codegen/box/callableReference/topLevelFromClass.kt");