diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt index c10437a77b1..77417965b40 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt @@ -2,5 +2,5 @@ package test public open class MethodWithMappedClasses { public constructor MethodWithMappedClasses() - public open fun copy(/*0*/ p0: (kotlin.collections.MutableList..kotlin.collections.List<*>?), /*1*/ p1: kotlin.collections.(Mutable)List!): kotlin.Unit + public open fun copy(/*0*/ p0: kotlin.collections.(Mutable)List!, /*1*/ p1: kotlin.collections.(Mutable)List!): kotlin.Unit } diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt index b278d2b2acf..f2e783c9acf 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt @@ -2,5 +2,5 @@ package test public open class MethodWithTypeParameters { public constructor MethodWithTypeParameters() - public open fun foo(/*0*/ p0: A!, /*1*/ p1: (kotlin.collections.MutableList..kotlin.collections.List?), /*2*/ p2: (kotlin.collections.MutableList..kotlin.collections.List<*>?)): kotlin.Unit where B : kotlin.collections.(Mutable)List! + public open fun foo(/*0*/ p0: A!, /*1*/ p1: (kotlin.collections.MutableList..kotlin.collections.List?), /*2*/ p2: kotlin.collections.(Mutable)List!): kotlin.Unit where B : kotlin.collections.(Mutable)List! } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index 6dacab1460d..2202e37986a 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -33,19 +33,24 @@ private fun D.enhanceSignature(): D { if (this !is JavaCallableMemberDescriptor) return this - val enhancedReceiverType = + val receiverTypeEnhancement = if (extensionReceiverParameter != null) parts(isCovariant = false) { it.extensionReceiverParameter!!.type }.enhance() else null - val enhancedValueParametersTypes = valueParameters.map { + val valueParameterEnhancements = valueParameters.map { p -> parts(isCovariant = false) { it.valueParameters[p.index].type }.enhance() } - val enhancedReturnType = parts(isCovariant = true) { it.returnType!! }.enhance() + val returnTypeEnhancement = parts(isCovariant = true) { it.returnType!! }.enhance() - @Suppress("UNCHECKED_CAST") - return this.enhance(enhancedReceiverType, enhancedValueParametersTypes, enhancedReturnType) as D + if ((receiverTypeEnhancement?.wereChanges ?: false) + || returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) { + @Suppress("UNCHECKED_CAST") + return this.enhance(receiverTypeEnhancement?.type, valueParameterEnhancements.map { it.type }, returnTypeEnhancement.type) as D + } + + return this } private class SignatureParts( @@ -53,12 +58,16 @@ private class SignatureParts( val fromOverridden: Collection, val isCovariant: Boolean ) { - fun enhance(): KotlinType { + fun enhance(): PartEnhancementResult { val qualifiers = fromOverride.computeIndexedQualifiersForOverride(this.fromOverridden, isCovariant) - return fromOverride.enhance(qualifiers) + return fromOverride.enhance(qualifiers)?.let { + enhanced -> PartEnhancementResult(enhanced, wereChanges = true) + } ?: PartEnhancementResult(fromOverride, wereChanges = false) } } +private data class PartEnhancementResult(val type: KotlinType, val wereChanges: Boolean) + private fun D.parts(isCovariant: Boolean, collector: (D) -> KotlinType): SignatureParts { return SignatureParts( collector(this), diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt index 929463ddcb2..8e724187a62 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt @@ -33,13 +33,14 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.makeNotNullable +import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.toReadOnlyList // The index in the lambda is the position of the type component: // Example: for `A>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C, 3 - D, 4 - E`, // which corresponds to the left-to-right breadth-first walk of the tree representation of the type. // For flexible types, both bounds are indexed in the same way: `(A..C)` gives `0 - (A..C), 1 - B and D`. -fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = this.enhancePossiblyFlexible(qualifiers, 0).type +fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = this.enhancePossiblyFlexible(qualifiers, 0).typeIfChanged private enum class TypeComponentPosition { @@ -48,10 +49,12 @@ private enum class TypeComponentPosition { INFLEXIBLE } -private data class Result(val type: KotlinType, val subtreeSize: Int) +private data class Result(val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) { + val typeIfChanged: KotlinType? get() = type.check { wereChanges } +} private fun KotlinType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result { - if (this.isError()) return Result(this, 1) + if (this.isError) return Result(this, 1, false) return if (this.isFlexible()) { with(this.flexibility()) { val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER) @@ -61,8 +64,15 @@ private fun KotlinType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQual "lower = ($lowerBound, ${lowerResult.subtreeSize}), " + "upper = ($upperBound, ${upperResult.subtreeSize})" } + + val wereChanges = lowerResult.wereChanges || upperResult.wereChanges Result( - DelegatingFlexibleType.create(lowerResult.type, upperResult.type, extraCapabilities), lowerResult.subtreeSize + if (wereChanges) + DelegatingFlexibleType.create(lowerResult.type, upperResult.type, extraCapabilities) + else + this@enhancePossiblyFlexible, + lowerResult.subtreeSize, + wereChanges ) } } @@ -71,10 +81,10 @@ private fun KotlinType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQual private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int, position: TypeComponentPosition): Result { val shouldEnhance = position.shouldEnhance() - if (!shouldEnhance && getArguments().isEmpty()) return Result(this, 1) + if (!shouldEnhance && arguments.isEmpty()) return Result(this, 1, false) - val originalClass = getConstructor().declarationDescriptor - ?: return Result(this, 1) + val originalClass = constructor.declarationDescriptor + ?: return Result(this, 1, false) val effectiveQualifiers = qualifiers(index) val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position) @@ -82,6 +92,7 @@ private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers val typeConstructor = enhancedClassifier.typeConstructor var globalArgIndex = index + 1 + var wereChanges = enhancedMutabilityAnnotations != null val enhancedArguments = getArguments().mapIndexed { localArgIndex, arg -> if (arg.isStarProjection) { @@ -89,13 +100,19 @@ private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex]) } else { - val (enhancedType, subtreeSize) = arg.type.enhancePossiblyFlexible(qualifiers, globalArgIndex) + val (enhancedType, subtreeSize, wasChangeInArgument) = arg.type.enhancePossiblyFlexible(qualifiers, globalArgIndex) + wereChanges = wereChanges || wasChangeInArgument globalArgIndex += subtreeSize createProjection(enhancedType, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex]) } } val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position) + wereChanges = wereChanges || enhancedNullabilityAnnotations != null + + val subtreeSize = globalArgIndex - index + if (!wereChanges) return Result(this, subtreeSize, wereChanges = false) + val newAnnotations = listOf( getAnnotations(), enhancedMutabilityAnnotations, @@ -123,7 +140,7 @@ private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers else enhancedClassifier.getDefaultType().getMemberScope(), newCapabilities ) - return Result(enhancedType, globalArgIndex - index) + return Result(enhancedType, subtreeSize, wereChanges = true) } private fun List.compositeAnnotationsOrSingle() = when (size) { diff --git a/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt b/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt index c2f4607e995..966a81b26dc 100644 --- a/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt +++ b/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_RETURN_TYPES: kotlin.Boolean?, kotlin.Boolean -// PARAM_DESCRIPTOR: value-parameter val it: kotlin.collections.Map.Entry<(kotlin.Boolean..kotlin.Boolean?), (kotlin.Boolean..kotlin.Boolean?)> defined in test. -// PARAM_TYPES: kotlin.collections.Map.Entry<(kotlin.Boolean..kotlin.Boolean?), (kotlin.Boolean..kotlin.Boolean?)> +// PARAM_DESCRIPTOR: value-parameter val it: kotlin.collections.Map.Entry<(Boolean..Boolean?), (Boolean..Boolean?)> defined in test. +// PARAM_TYPES: kotlin.collections.Map.Entry<(Boolean..Boolean?), (Boolean..Boolean?)> fun test() { J.getMap().filter { it.key } } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt.after b/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt.after index f9f97a20629..315b3905c1d 100644 --- a/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt.after +++ b/idea/testData/refactoring/extractFunction/basic/callWithPlatformTypeReceiver.kt.after @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_RETURN_TYPES: kotlin.Boolean?, kotlin.Boolean -// PARAM_DESCRIPTOR: value-parameter val it: kotlin.collections.Map.Entry<(kotlin.Boolean..kotlin.Boolean?), (kotlin.Boolean..kotlin.Boolean?)> defined in test. -// PARAM_TYPES: kotlin.collections.Map.Entry<(kotlin.Boolean..kotlin.Boolean?), (kotlin.Boolean..kotlin.Boolean?)> +// PARAM_DESCRIPTOR: value-parameter val it: kotlin.collections.Map.Entry<(Boolean..Boolean?), (Boolean..Boolean?)> defined in test. +// PARAM_TYPES: kotlin.collections.Map.Entry<(Boolean..Boolean?), (Boolean..Boolean?)> fun test() { J.getMap().filter { b(it) } } diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt index 903ada643a9..f07563dbe31 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_NAMES: i, getN -// PARAM_TYPES: kotlin.String?, kotlin.String, kotlin.CharSequence?, CharSequence -// PARAM_DESCRIPTOR: val property: (kotlin.String..kotlin.String?) defined in test +// PARAM_TYPES: String?, String, kotlin.CharSequence?, CharSequence +// PARAM_DESCRIPTOR: val property: (String..String?) defined in test fun test() { val property = System.getProperty("some") val n = property?.length diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt.after index 9efe244a1b3..b5e4df7d88c 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithNull.kt.after @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_NAMES: i, getN -// PARAM_TYPES: kotlin.String?, kotlin.String, kotlin.CharSequence?, CharSequence -// PARAM_DESCRIPTOR: val property: (kotlin.String..kotlin.String?) defined in test +// PARAM_TYPES: String?, String, kotlin.CharSequence?, CharSequence +// PARAM_DESCRIPTOR: val property: (String..String?) defined in test fun test() { val property = System.getProperty("some") val n = i(property) diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt index 1e8d12d5c24..bbe8eafcedb 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_NAMES: i, getN -// PARAM_TYPES: kotlin.String, CharSequence -// PARAM_DESCRIPTOR: val property: (kotlin.String..kotlin.String?) defined in test +// PARAM_TYPES: String, CharSequence +// PARAM_DESCRIPTOR: val property: (String..String?) defined in test fun test() { val property = System.getProperty("some") val n = property.length diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt.after index c491e999205..3a3f4bee1f9 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/flexibleTypesWithoutNull.kt.after @@ -1,7 +1,7 @@ // WITH_RUNTIME // SUGGESTED_NAMES: i, getN -// PARAM_TYPES: kotlin.String, CharSequence -// PARAM_DESCRIPTOR: val property: (kotlin.String..kotlin.String?) defined in test +// PARAM_TYPES: String, CharSequence +// PARAM_DESCRIPTOR: val property: (String..String?) defined in test fun test() { val property = System.getProperty("some") val n = i(property) diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt index be7801895a2..c248e93e1ab 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt @@ -1,6 +1,6 @@ // WITH_RUNTIME -// PARAM_DESCRIPTOR: val data: (kotlin.collections.MutableList<(kotlin.String..kotlin.String?)>..kotlin.collections.List<(kotlin.String..kotlin.String?)>) defined in test -// PARAM_TYPES: kotlin.collections.List<(kotlin.String..kotlin.String?)>, kotlin.collections.MutableList<(kotlin.String..kotlin.String?)>, kotlin.collections.MutableCollection<(kotlin.String..kotlin.String?)>, kotlin.collections.Collection<(kotlin.String..kotlin.String?)> +// PARAM_DESCRIPTOR: val data: (kotlin.collections.MutableList<(String..String?)>..kotlin.collections.List<(String..String?)>) defined in test +// PARAM_TYPES: kotlin.collections.List<(String..String?)>, kotlin.collections.MutableList<(String..String?)>, kotlin.collections.MutableCollection<(String..String?)>, kotlin.collections.Collection<(String..String?)> fun test(): Boolean { val j: J? = null val data = j?.getData() ?: return false diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt.after index d7b603d4ef7..322dda173a8 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/mutablyFlexibleType.kt.after @@ -1,6 +1,6 @@ // WITH_RUNTIME -// PARAM_DESCRIPTOR: val data: (kotlin.collections.MutableList<(kotlin.String..kotlin.String?)>..kotlin.collections.List<(kotlin.String..kotlin.String?)>) defined in test -// PARAM_TYPES: kotlin.collections.List<(kotlin.String..kotlin.String?)>, kotlin.collections.MutableList<(kotlin.String..kotlin.String?)>, kotlin.collections.MutableCollection<(kotlin.String..kotlin.String?)>, kotlin.collections.Collection<(kotlin.String..kotlin.String?)> +// PARAM_DESCRIPTOR: val data: (kotlin.collections.MutableList<(String..String?)>..kotlin.collections.List<(String..String?)>) defined in test +// PARAM_TYPES: kotlin.collections.List<(String..String?)>, kotlin.collections.MutableList<(String..String?)>, kotlin.collections.MutableCollection<(String..String?)>, kotlin.collections.Collection<(String..String?)> fun test(): Boolean { val j: J? = null val data = j?.getData() ?: return false