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 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<Nothing, Foo> -> Map
|
||||
// Map<Foo, List<Nothing>> -> Map<Foo, List>
|
||||
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
|
||||
// In<Nothing, Nothing> -> In
|
||||
// Inv<in Nothing, Foo> -> 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<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();
|
||||
// Nothing mapping rules:
|
||||
// Map<Nothing, Foo> -> Map
|
||||
// Map<Foo, List<Nothing>> -> Map<Foo, List>
|
||||
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
|
||||
// In<Nothing, Nothing> -> In
|
||||
// Inv<in Nothing, Foo> -> 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<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
|
||||
@@ -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<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(
|
||||
@NotNull JvmSignatureWriter signatureVisitor,
|
||||
@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)
|
||||
}
|
||||
|
||||
// method: CallableFunctionKt$box$1::invoke
|
||||
// method: FunctionReferenceInvokeKt$box$1::invoke
|
||||
// jvm signature: ()Ljava/lang/String;
|
||||
// generic signature: null
|
||||
+1
-1
@@ -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
|
||||
+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);
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user