diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 043c687891c..fbda7bed45a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -80,6 +80,7 @@ import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.Collection; +import java.util.Collections; import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod; @@ -505,49 +506,41 @@ public class KotlinTypeMapper { @Nullable JvmSignatureWriter signatureVisitor, @NotNull TypeMappingMode mode ) { - if (signatureVisitor != null) { + if (signatureVisitor == null) return; - // Nothing mapping rules: - // Map -> Map - // Map> -> Map - // In == In<*, Foo> -> In - // In -> In - // Inv -> Inv - if (signatureVisitor.skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.getArguments().isEmpty()) { - signatureVisitor.writeAsmType(asmType); - return; - } - - PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type); - assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null"; - - List innerTypesAsList = possiblyInnerType.segments(); - PossiblyInnerType outermostInnerType = innerTypesAsList.get(0); - ClassDescriptor outermostClass = outermostInnerType.getClassDescriptor(); - - if (innerTypesAsList.size() == 1) { - signatureVisitor.writeClassBegin(asmType); - } - else { - signatureVisitor.writeOuterClassBegin( - asmType, - mapType(outermostClass.getDefaultType()).getInternalName()); - } - - writeGenericArguments( - signatureVisitor, - outermostInnerType.getArguments(), outermostClass.getDeclaredTypeParameters(), mode); - - for (PossiblyInnerType innerPart : innerTypesAsList.subList(1, innerTypesAsList.size())) { - ClassDescriptor classDescriptor = innerPart.getClassDescriptor(); - signatureVisitor.writeInnerClass(getJvmShortName(classDescriptor)); - writeGenericArguments( - signatureVisitor, innerPart.getArguments(), - classDescriptor.getDeclaredTypeParameters(), mode); - } - - signatureVisitor.writeClassEnd(); + // Nothing mapping rules: + // Map -> Map + // Map> -> Map + // In == In<*, Foo> -> In + // In -> In + // Inv -> Inv + if (signatureVisitor.skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.getArguments().isEmpty()) { + signatureVisitor.writeAsmType(asmType); + return; } + + PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type); + assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null"; + + List innerTypesAsList = possiblyInnerType.segments(); + + if (innerTypesAsList.size() == 1) { + signatureVisitor.writeClassBegin(asmType); + } + else { + ClassDescriptor outermostClass = innerTypesAsList.get(0).getClassDescriptor(); + signatureVisitor.writeOuterClassBegin(asmType, mapType(outermostClass.getDefaultType()).getInternalName()); + } + + for (int i = 0; i < innerTypesAsList.size(); i++) { + PossiblyInnerType innerPart = innerTypesAsList.get(i); + if (i > 0) { + signatureVisitor.writeInnerClass(getJvmShortName(innerPart.getClassDescriptor())); + } + writeGenericArguments(signatureVisitor, innerPart, mode); + } + + signatureVisitor.writeClassEnd(); } @Nullable @@ -560,6 +553,31 @@ public class KotlinTypeMapper { return SpecialNames.safeIdentifier(klass.getName()).getIdentifier(); } + private void writeGenericArguments( + @NotNull JvmSignatureWriter signatureVisitor, + @NotNull PossiblyInnerType type, + @NotNull TypeMappingMode mode + ) { + ClassDescriptor classDescriptor = type.getClassDescriptor(); + List parameters = classDescriptor.getDeclaredTypeParameters(); + List arguments = type.getArguments(); + + if (classDescriptor instanceof FunctionClassDescriptor && + ((FunctionClassDescriptor) classDescriptor).getFunctionKind() == FunctionClassDescriptor.Kind.KFunction) { + // kotlin.reflect.KFunction{n} is mapped to kotlin.reflect.KFunction on JVM (see JavaToKotlinClassMap). + // So for these classes, we need to skip all type arguments except the very last one + writeGenericArguments( + signatureVisitor, + Collections.singletonList(CollectionsKt.last(arguments)), + Collections.singletonList(CollectionsKt.last(parameters)), + mode + ); + return; + } + + writeGenericArguments(signatureVisitor, arguments, parameters, mode); + } + private void writeGenericArguments( @NotNull JvmSignatureWriter signatureVisitor, @NotNull List arguments, diff --git a/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.java b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.java new file mode 100644 index 00000000000..50fe10d7dee --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.java @@ -0,0 +1,10 @@ +package test; + +import kotlin.reflect.KFunction; + +class Bar extends Foo { + @Override + public KFunction request() { + return null; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.kt b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.kt new file mode 100644 index 00000000000..a81262ed591 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.kt @@ -0,0 +1,9 @@ +// KT-15473 Invalid KFunction byte code signature for callable references + +package test + +class Request(val id: Long) + +open class Foo { + open fun request() = ::Request +} diff --git a/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.txt b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.txt new file mode 100644 index 00000000000..fac461bc655 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.txt @@ -0,0 +1,16 @@ +package test + +public/*package*/ open class Bar : test.Foo { + public/*package*/ constructor Bar() + public open fun request(): kotlin.reflect.KFunction +} + +public open class Foo { + public constructor Foo() + public open fun request(): kotlin.reflect.KFunction1<@kotlin.ParameterName(name = "id") kotlin.Long, test.Request> +} + +public final class Request { + public constructor Request(/*0*/ kotlin.Long) + public final val id: kotlin.Long +} diff --git a/compiler/testData/writeSignature/callableReference/constructorReferenceInReturnType.kt b/compiler/testData/writeSignature/callableReference/constructorReferenceInReturnType.kt new file mode 100644 index 00000000000..cbbde8d79bb --- /dev/null +++ b/compiler/testData/writeSignature/callableReference/constructorReferenceInReturnType.kt @@ -0,0 +1,11 @@ +// KT-15473 Invalid KFunction byte code signature for callable references + +class Request(val id: Long) + +open class Foo { + open fun request() = ::Request +} + +// method: Foo::request +// jvm signature: ()Lkotlin/reflect/KFunction; +// generic signature: ()Lkotlin/reflect/KFunction; diff --git a/compiler/testData/writeSignature/callableFunction.kt b/compiler/testData/writeSignature/callableReference/functionReferenceInvoke.kt similarity index 81% rename from compiler/testData/writeSignature/callableFunction.kt rename to compiler/testData/writeSignature/callableReference/functionReferenceInvoke.kt index 1698487d7ee..7766da5fc03 100644 --- a/compiler/testData/writeSignature/callableFunction.kt +++ b/compiler/testData/writeSignature/callableReference/functionReferenceInvoke.kt @@ -10,6 +10,6 @@ fun box(): String { return test(Foo()::test) } -// method: CallableFunctionKt$box$1::invoke +// method: FunctionReferenceInvokeKt$box$1::invoke // jvm signature: ()Ljava/lang/String; // generic signature: null diff --git a/compiler/testData/writeSignature/callableProperty.kt b/compiler/testData/writeSignature/callableReference/propertyReferenceGet.kt similarity index 81% rename from compiler/testData/writeSignature/callableProperty.kt rename to compiler/testData/writeSignature/callableReference/propertyReferenceGet.kt index 6205a90e85b..68fccd25b67 100644 --- a/compiler/testData/writeSignature/callableProperty.kt +++ b/compiler/testData/writeSignature/callableReference/propertyReferenceGet.kt @@ -8,6 +8,6 @@ fun box(): String { return test(Foo("OK")::a) } -// method: CallablePropertyKt$box$1::get +// method: PropertyReferenceGetKt$box$1::get // jvm signature: ()Ljava/lang/Object; // generic signature: null diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileJavaAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileJavaAgainstKotlinTestGenerated.java index a06a769d01a..546b1c0d6e6 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileJavaAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileJavaAgainstKotlinTestGenerated.java @@ -36,6 +36,21 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("compiler/testData/compileJavaAgainstKotlin/callableReference") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CallableReference extends AbstractCompileJavaAgainstKotlinTest { + public void testAllFilesPresentInCallableReference() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin/callableReference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("GenericSignature.kt") + public void testGenericSignature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/callableReference/GenericSignature.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/compileJavaAgainstKotlin/class") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java index 1c227aa9b24..ae894a774be 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java @@ -54,18 +54,6 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest { doTest(fileName); } - @TestMetadata("callableFunction.kt") - public void testCallableFunction() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/callableFunction.kt"); - doTest(fileName); - } - - @TestMetadata("callableProperty.kt") - public void testCallableProperty() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/callableProperty.kt"); - doTest(fileName); - } - @TestMetadata("Comparable.kt") public void testComparable() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Comparable.kt"); @@ -201,6 +189,33 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest { } } + @TestMetadata("compiler/testData/writeSignature/callableReference") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CallableReference extends AbstractWriteSignatureTest { + public void testAllFilesPresentInCallableReference() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeSignature/callableReference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("constructorReferenceInReturnType.kt") + public void testConstructorReferenceInReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/callableReference/constructorReferenceInReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("functionReferenceInvoke.kt") + public void testFunctionReferenceInvoke() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/callableReference/functionReferenceInvoke.kt"); + doTest(fileName); + } + + @TestMetadata("propertyReferenceGet.kt") + public void testPropertyReferenceGet() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/callableReference/propertyReferenceGet.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/writeSignature/constructor") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index d00ab0d93ee..17f3a3fa6e4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocResolveTestGenerated.java index 0c7e994b0c8..fe2173ef668 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocResolveTestGenerated.java @@ -17,10 +17,10 @@ package org.jetbrains.kotlin.idea.kdoc; import com.intellij.testFramework.TestDataPath; -import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest; import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest; import org.jetbrains.kotlin.test.TestMetadata; import org.junit.runner.RunWith; diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index b3965bb3a2d..286305a9daa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.