Fix generic signature for KFunctionN types on JVM

#KT-15473 Fixed
This commit is contained in:
Alexander Udalov
2016-12-29 19:15:47 +03:00
parent bf3b5281a9
commit 0dbb02ec6a
12 changed files with 152 additions and 58 deletions
@@ -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,
@@ -0,0 +1,10 @@
package test;
import kotlin.reflect.KFunction;
class Bar extends Foo {
@Override
public KFunction<Request> request() {
return null;
}
}
@@ -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
}
@@ -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
}
@@ -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;>;
@@ -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
@@ -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
@@ -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.