Fix generic signature for KFunctionN types on JVM
#KT-15473 Fixed
This commit is contained in:
@@ -80,6 +80,7 @@ import org.jetbrains.org.objectweb.asm.Type;
|
|||||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod;
|
import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod;
|
||||||
@@ -505,49 +506,41 @@ public class KotlinTypeMapper {
|
|||||||
@Nullable JvmSignatureWriter signatureVisitor,
|
@Nullable JvmSignatureWriter signatureVisitor,
|
||||||
@NotNull TypeMappingMode mode
|
@NotNull TypeMappingMode mode
|
||||||
) {
|
) {
|
||||||
if (signatureVisitor != null) {
|
if (signatureVisitor == null) return;
|
||||||
|
|
||||||
// Nothing mapping rules:
|
// Nothing mapping rules:
|
||||||
// Map<Nothing, Foo> -> Map
|
// Map<Nothing, Foo> -> Map
|
||||||
// Map<Foo, List<Nothing>> -> Map<Foo, List>
|
// Map<Foo, List<Nothing>> -> Map<Foo, List>
|
||||||
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
|
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
|
||||||
// In<Nothing, Nothing> -> In
|
// In<Nothing, Nothing> -> In
|
||||||
// Inv<in Nothing, Foo> -> Inv
|
// Inv<in Nothing, Foo> -> Inv
|
||||||
if (signatureVisitor.skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.getArguments().isEmpty()) {
|
if (signatureVisitor.skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.getArguments().isEmpty()) {
|
||||||
signatureVisitor.writeAsmType(asmType);
|
signatureVisitor.writeAsmType(asmType);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type);
|
|
||||||
assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null";
|
|
||||||
|
|
||||||
List<PossiblyInnerType> 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type);
|
||||||
|
assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null";
|
||||||
|
|
||||||
|
List<PossiblyInnerType> 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
|
@Nullable
|
||||||
@@ -560,6 +553,31 @@ public class KotlinTypeMapper {
|
|||||||
return SpecialNames.safeIdentifier(klass.getName()).getIdentifier();
|
return SpecialNames.safeIdentifier(klass.getName()).getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeGenericArguments(
|
||||||
|
@NotNull JvmSignatureWriter signatureVisitor,
|
||||||
|
@NotNull PossiblyInnerType type,
|
||||||
|
@NotNull TypeMappingMode mode
|
||||||
|
) {
|
||||||
|
ClassDescriptor classDescriptor = type.getClassDescriptor();
|
||||||
|
List<TypeParameterDescriptor> parameters = classDescriptor.getDeclaredTypeParameters();
|
||||||
|
List<TypeProjection> arguments = type.getArguments();
|
||||||
|
|
||||||
|
if (classDescriptor instanceof FunctionClassDescriptor &&
|
||||||
|
((FunctionClassDescriptor) classDescriptor).getFunctionKind() == FunctionClassDescriptor.Kind.KFunction) {
|
||||||
|
// kotlin.reflect.KFunction{n}<P1, ... Pn, R> is mapped to kotlin.reflect.KFunction<R> 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(
|
private void writeGenericArguments(
|
||||||
@NotNull JvmSignatureWriter signatureVisitor,
|
@NotNull JvmSignatureWriter signatureVisitor,
|
||||||
@NotNull List<? extends TypeProjection> arguments,
|
@NotNull List<? extends TypeProjection> arguments,
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
import kotlin.reflect.KFunction;
|
||||||
|
|
||||||
|
class Bar extends Foo {
|
||||||
|
@Override
|
||||||
|
public KFunction<Request> request() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
public/*package*/ open class Bar : test.Foo {
|
||||||
|
public/*package*/ constructor Bar()
|
||||||
|
public open fun request(): kotlin.reflect.KFunction<test.Request!>
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
+11
@@ -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<LRequest;>;
|
||||||
+1
-1
@@ -10,6 +10,6 @@ fun box(): String {
|
|||||||
return test(Foo()::test)
|
return test(Foo()::test)
|
||||||
}
|
}
|
||||||
|
|
||||||
// method: CallableFunctionKt$box$1::invoke
|
// method: FunctionReferenceInvokeKt$box$1::invoke
|
||||||
// jvm signature: ()Ljava/lang/String;
|
// jvm signature: ()Ljava/lang/String;
|
||||||
// generic signature: null
|
// generic signature: null
|
||||||
+1
-1
@@ -8,6 +8,6 @@ fun box(): String {
|
|||||||
return test(Foo("OK")::a)
|
return test(Foo("OK")::a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// method: CallablePropertyKt$box$1::get
|
// method: PropertyReferenceGetKt$box$1::get
|
||||||
// jvm signature: ()Ljava/lang/Object;
|
// jvm signature: ()Ljava/lang/Object;
|
||||||
// generic signature: null
|
// generic signature: null
|
||||||
+15
@@ -36,6 +36,21 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
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")
|
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/class")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -54,18 +54,6 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("Comparable.kt")
|
||||||
public void testComparable() throws Exception {
|
public void testComparable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Comparable.kt");
|
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")
|
@TestMetadata("compiler/testData/writeSignature/constructor")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.idea.kdoc;
|
package org.jetbrains.kotlin.idea.kdoc;
|
||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest;
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
import org.jetbrains.kotlin.test.TargetBackend;
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest;
|
||||||
import org.jetbrains.kotlin.test.TestMetadata;
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
Reference in New Issue
Block a user