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
@@ -16,8 +16,8 @@
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.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.SimpleType
@@ -25,9 +25,9 @@ class SamConversionResolverImpl(
storageManager: StorageManager,
private val samWithReceiverResolvers: Iterable<SamWithReceiverResolver>
): 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) {
val abstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) ?: return@computeIfAbsent null
val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) }
@@ -78,9 +78,12 @@ public class SingleAbstractMethodUtils {
// e.g. samType == Comparator<String>?
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>
SimpleType functionTypeDefault = samResolver.resolveFunctionTypeIfSamInterface((JavaClassDescriptor) classifier);
SimpleType functionTypeDefault = samResolver.resolveFunctionTypeIfSamInterface(descriptor);
if (functionTypeDefault != null) {
SimpleType noProjectionsSamType = SingleAbstractMethodUtilsKt.nonProjectionParametrization(samType);
@@ -131,7 +134,7 @@ public class SingleAbstractMethodUtils {
}
@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
// Otherwise android data binding can cause resolve re-entrance
// For details see KT-18687, KT-16149
@@ -140,7 +143,13 @@ public class SingleAbstractMethodUtils {
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);
if (abstractMembers.size() == 1) {
@@ -224,6 +233,9 @@ public class SingleAbstractMethodUtils {
}
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;
}