From 459c5fed8c5ba283b59f71e56fa8abf854574c14 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 7 Dec 2016 18:48:45 +0300 Subject: [PATCH] Tweak checks and type parameter heuristics in LazyJavaClassDescriptor.getPurelyImplementedSupertype to support cases of UnaryOperator and BinaryOperator enhancements. --- .../enhancedSignatures/list/listReplaceAll.kt | 2 -- .../list/listReplaceAll.txt | 8 ++--- .../java/FakePureImplementationsProvider.kt | 3 +- .../descriptors/LazyJavaClassDescriptor.kt | 34 ++++++++++++++----- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.kt b/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.kt index 009c34094ed..09acf02f9c0 100644 --- a/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.kt +++ b/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.kt @@ -1,9 +1,7 @@ fun notNullValues(list: MutableList) { - // TODO: Fix platform types list.replaceAll { it.length.toString() } } fun nullableValues(list: MutableList) { - // TODO: Fix platform types list.replaceAll { it?.run { length.toString() } } } \ No newline at end of file diff --git a/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.txt b/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.txt index 14b967cabf6..99267d747dc 100644 --- a/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.txt +++ b/compiler/testData/resolvedCalls/enhancedSignatures/list/listReplaceAll.txt @@ -1,15 +1,13 @@ fun notNullValues(list: MutableList) { - // TODO: Fix platform types list.replaceAll { it.length.toString() } // SUCCESS - // ORIGINAL: fun replaceAll((E!) -> E!): Unit defined in kotlin.collections.MutableList - // SUBSTITUTED: fun replaceAll((String!) -> String!): Unit defined in kotlin.collections.MutableList + // ORIGINAL: fun replaceAll((E) -> E): Unit defined in kotlin.collections.MutableList + // SUBSTITUTED: fun replaceAll((String) -> String): Unit defined in kotlin.collections.MutableList } fun nullableValues(list: MutableList) { - // TODO: Fix platform types list.replaceAll { it?.run { length.toString() } } // SUCCESS - // ORIGINAL: fun replaceAll((E!) -> E!): Unit defined in kotlin.collections.MutableList + // ORIGINAL: fun replaceAll((E) -> E): Unit defined in kotlin.collections.MutableList // SUBSTITUTED: fun replaceAll((String?) -> String?): Unit defined in kotlin.collections.MutableList } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt index 2aa3d55ccb1..e249d6f5f88 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt @@ -32,7 +32,8 @@ object FakePureImplementationsProvider { FQ_NAMES.mutableSet implementedWith fqNameListOf("java.util.HashSet", "java.util.TreeSet", "java.util.LinkedHashSet") FQ_NAMES.mutableMap implementedWith fqNameListOf("java.util.HashMap", "java.util.TreeMap", "java.util.LinkedHashMap", "java.util.concurrent.ConcurrentHashMap", "java.util.concurrent.ConcurrentSkipListMap") - // TODO: FqName("java.util.function.Function") implementedWith fqNameListOf("java.util.function.UnaryOperator") + FqName("java.util.function.Function") implementedWith fqNameListOf("java.util.function.UnaryOperator") + FqName("java.util.function.BiFunction") implementedWith fqNameListOf("java.util.function.BinaryOperator") } private fun fqNameListOf(vararg names: String): List = names.map(::FqName) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt index 9c128f6620b..753bc9857d9 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JvmAnnotationNames @@ -40,12 +41,14 @@ import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass import org.jetbrains.kotlin.resolve.scopes.InnerClassesScopeWrapper import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.toReadOnlyList import java.util.* @@ -187,18 +190,33 @@ class LazyJavaClassDescriptor( } private fun getPurelyImplementedSupertype(): KotlinType? { - val purelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation() - ?: FakePureImplementationsProvider.getPurelyImplementedInterface(fqNameSafe) - ?: return null + val annotatedPurelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation()?.check { + !it.isRoot && it.toUnsafe().startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME) + } - if (purelyImplementedFqName.isRoot || !purelyImplementedFqName.toUnsafe().startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return null + val purelyImplementedFqName = + annotatedPurelyImplementedFqName + ?: FakePureImplementationsProvider.getPurelyImplementedInterface(fqNameSafe) + ?: return null - val classDescriptor = c.module.builtIns.getBuiltInClassByFqNameNullable(purelyImplementedFqName) ?: return null + val classDescriptor = c.module.resolveTopLevelClass(purelyImplementedFqName, NoLookupLocation.FROM_JAVA_LOADER) ?: return null - if (classDescriptor.typeConstructor.parameters.size != getTypeConstructor().parameters.size) return null + val supertypeParameterCount = classDescriptor.typeConstructor.parameters.size + val typeParameters = getTypeConstructor().parameters + val typeParameterCount = typeParameters.size - val parametersAsTypeProjections = getTypeConstructor().parameters.map { - parameter -> TypeProjectionImpl(Variance.INVARIANT, parameter.defaultType) + val parametersAsTypeProjections = when { + typeParameterCount == supertypeParameterCount -> + typeParameters.map { + parameter -> + TypeProjectionImpl(Variance.INVARIANT, parameter.defaultType) + } + typeParameterCount == 1 && supertypeParameterCount > 1 && annotatedPurelyImplementedFqName == null -> + { + val parameter = TypeProjectionImpl(Variance.INVARIANT, typeParameters.single().defaultType) + (1..supertypeParameterCount).map { parameter } // TODO: List(supertypeParameterCount) { parameter } + } + else -> return null } return KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, classDescriptor, parametersAsTypeProjections)