FIC: Make SAM conversions also for fun interfaces, add base test

This commit is contained in:
Mikhail Zarechenskiy
2019-11-13 13:44:23 +03:00
parent 193d807a1e
commit c71c1d45c6
8 changed files with 85 additions and 10 deletions
@@ -7797,6 +7797,34 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
} }
} }
@TestMetadata("compiler/testData/diagnostics/tests/funInterface")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FunInterface extends AbstractFirDiagnosticsSmokeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInFunInterface() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/funInterface"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("basicFunInterface.kt")
public void testBasicFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterface.kt");
}
@TestMetadata("basicFunInterfaceConversion.kt")
public void testBasicFunInterfaceConversion() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceConversion.kt");
}
@TestMetadata("basicFunInterfaceDisabled.kt")
public void testBasicFunInterfaceDisabled() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceDisabled.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/functionAsExpression") @TestMetadata("compiler/testData/diagnostics/tests/functionAsExpression")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -16,8 +16,8 @@
package org.jetbrains.kotlin.load.java.sam package org.jetbrains.kotlin.load.java.sam
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.load.java.components.SamConversionResolver import org.jetbrains.kotlin.load.java.components.SamConversionResolver
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
@@ -25,9 +25,9 @@ class SamConversionResolverImpl(
storageManager: StorageManager, storageManager: StorageManager,
private val samWithReceiverResolvers: Iterable<SamWithReceiverResolver> private val samWithReceiverResolvers: Iterable<SamWithReceiverResolver>
): SamConversionResolver { ): SamConversionResolver {
private val functionTypesForSamInterfaces = storageManager.createCacheWithNullableValues<JavaClassDescriptor, SimpleType>() private val functionTypesForSamInterfaces = storageManager.createCacheWithNullableValues<ClassDescriptor, SimpleType>()
override fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? { override fun resolveFunctionTypeIfSamInterface(classDescriptor: ClassDescriptor): SimpleType? {
return functionTypesForSamInterfaces.computeIfAbsent(classDescriptor) { return functionTypesForSamInterfaces.computeIfAbsent(classDescriptor) {
val abstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) ?: return@computeIfAbsent null val abstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) ?: return@computeIfAbsent null
val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) } val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) }
@@ -78,9 +78,12 @@ public class SingleAbstractMethodUtils {
// e.g. samType == Comparator<String>? // e.g. samType == Comparator<String>?
ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor(); ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor();
if (classifier instanceof JavaClassDescriptor) { if (classifier instanceof ClassDescriptor) {
ClassDescriptor descriptor = (ClassDescriptor) classifier;
if (!(descriptor instanceof JavaClassDescriptor) && !descriptor.isFun()) return null;
// Function2<T, T, Int> // Function2<T, T, Int>
SimpleType functionTypeDefault = samResolver.resolveFunctionTypeIfSamInterface((JavaClassDescriptor) classifier); SimpleType functionTypeDefault = samResolver.resolveFunctionTypeIfSamInterface(descriptor);
if (functionTypeDefault != null) { if (functionTypeDefault != null) {
SimpleType noProjectionsSamType = SingleAbstractMethodUtilsKt.nonProjectionParametrization(samType); SimpleType noProjectionsSamType = SingleAbstractMethodUtilsKt.nonProjectionParametrization(samType);
@@ -131,7 +134,7 @@ public class SingleAbstractMethodUtils {
} }
@Nullable @Nullable
public static FunctionDescriptor getSingleAbstractMethodOrNull(@NotNull JavaClassDescriptor klass) { public static FunctionDescriptor getSingleAbstractMethodOrNull(@NotNull ClassDescriptor klass) {
// NB: this check MUST BE at start. Please do not touch until following to-do is resolved // NB: this check MUST BE at start. Please do not touch until following to-do is resolved
// Otherwise android data binding can cause resolve re-entrance // Otherwise android data binding can cause resolve re-entrance
// For details see KT-18687, KT-16149 // For details see KT-18687, KT-16149
@@ -140,7 +143,13 @@ public class SingleAbstractMethodUtils {
return null; return null;
} }
if (klass.isDefinitelyNotSamInterface()) return null; if (klass instanceof JavaClassDescriptor) {
if (((JavaClassDescriptor) klass).isDefinitelyNotSamInterface()) {
return null;
}
} else if (!klass.isFun()) {
return null;
}
List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass); List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass);
if (abstractMembers.size() == 1) { if (abstractMembers.size() == 1) {
@@ -224,6 +233,9 @@ public class SingleAbstractMethodUtils {
} }
public static boolean isSamType(@NotNull KotlinType type) { public static boolean isSamType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).isFun()) return true;
return getFunctionTypeForSamType(type, SamConversionResolver.JavaBasedSamConversionResolver.INSTANCE) != null; return getFunctionTypeForSamType(type, SamConversionResolver.JavaBasedSamConversionResolver.INSTANCE) != null;
} }
@@ -0,0 +1,12 @@
// !LANGUAGE: +NewInference +FunctionInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun interface Foo {
fun invoke()
}
fun foo(f: Foo) {}
fun test() {
foo {}
}
@@ -0,0 +1,11 @@
package
public fun foo(/*0*/ f: Foo): kotlin.Unit
public fun test(): kotlin.Unit
public interface Foo {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun invoke(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -7896,6 +7896,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterface.kt"); runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterface.kt");
} }
@TestMetadata("basicFunInterfaceConversion.kt")
public void testBasicFunInterfaceConversion() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceConversion.kt");
}
@TestMetadata("basicFunInterfaceDisabled.kt") @TestMetadata("basicFunInterfaceDisabled.kt")
public void testBasicFunInterfaceDisabled() throws Exception { public void testBasicFunInterfaceDisabled() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceDisabled.kt"); runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceDisabled.kt");
@@ -7891,6 +7891,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterface.kt"); runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterface.kt");
} }
@TestMetadata("basicFunInterfaceConversion.kt")
public void testBasicFunInterfaceConversion() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceConversion.kt");
}
@TestMetadata("basicFunInterfaceDisabled.kt") @TestMetadata("basicFunInterfaceDisabled.kt")
public void testBasicFunInterfaceDisabled() throws Exception { public void testBasicFunInterfaceDisabled() throws Exception {
runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceDisabled.kt"); runTest("compiler/testData/diagnostics/tests/funInterface/basicFunInterfaceDisabled.kt");
@@ -18,20 +18,22 @@ package org.jetbrains.kotlin.load.java.components
import org.jetbrains.kotlin.container.DefaultImplementation import org.jetbrains.kotlin.container.DefaultImplementation
import org.jetbrains.kotlin.container.PlatformSpecificExtension import org.jetbrains.kotlin.container.PlatformSpecificExtension
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
@DefaultImplementation(impl = SamConversionResolver.Empty::class) @DefaultImplementation(impl = SamConversionResolver.Empty::class)
interface SamConversionResolver : PlatformSpecificExtension<SamConversionResolver> { interface SamConversionResolver : PlatformSpecificExtension<SamConversionResolver> {
object Empty : SamConversionResolver { object Empty : SamConversionResolver {
override fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? = null override fun resolveFunctionTypeIfSamInterface(classDescriptor: ClassDescriptor): SimpleType? = null
} }
object JavaBasedSamConversionResolver : SamConversionResolver { object JavaBasedSamConversionResolver : SamConversionResolver {
override fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? { override fun resolveFunctionTypeIfSamInterface(classDescriptor: ClassDescriptor): SimpleType? {
if (classDescriptor !is JavaClassDescriptor) return null
return classDescriptor.defaultFunctionTypeForSamInterface return classDescriptor.defaultFunctionTypeForSamInterface
} }
} }
fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? fun resolveFunctionTypeIfSamInterface(classDescriptor: ClassDescriptor): SimpleType?
} }