diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 1e849212564..e6cda724585 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -12632,6 +12632,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + @TestMetadata("manyFlexibleTypeParametersFromJavaAndConversions.kt") + public void testManyFlexibleTypeParametersFromJavaAndConversions() throws Exception { + runTest("compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt"); + } + @TestMetadata("noCoercionToUniForNullableLambdaReturnType.kt") public void testNoCoercionToUniForNullableLambdaReturnType() throws Exception { runTest("compiler/testData/codegen/box/inference/noCoercionToUniForNullableLambdaReturnType.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt index 7a0619c027a..77b13e9b247 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt @@ -8,8 +8,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.model import org.jetbrains.kotlin.resolve.calls.inference.trimToSize import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.tower.isSuccess -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker @@ -49,6 +48,7 @@ class MutableVariableWithConstraints private constructor( // return new actual constraint, if this constraint is new fun addConstraint(constraint: Constraint): Constraint? { + val isLowerAndFlexibleTypeWithDefNotNullLowerBound = constraint.isLowerAndFlexibleTypeWithDefNotNullLowerBound() for (previousConstraint in constraints) { if (previousConstraint.typeHashCode == constraint.typeHashCode @@ -75,12 +75,23 @@ class MutableVariableWithConstraints private constructor( return actualConstraint } } + + if (isLowerAndFlexibleTypeWithDefNotNullLowerBound && + previousConstraint.isStrongerThanLowerAndFlexibleTypeWithDefNotNullLowerBound(constraint) + ) { + return null + } } mutableConstraints.add(constraint) if (simplifiedConstraints != null && simplifiedConstraints !== mutableConstraints) { simplifiedConstraints!!.add(constraint) } + + if (simplifiedConstraints != null && isLowerAndFlexibleTypeWithDefNotNullLowerBound) { + simplifiedConstraints = null + } + return constraint } @@ -114,10 +125,50 @@ class MutableVariableWithConstraints private constructor( } } - private fun SmartList.simplifyConstraints(): SmartList { - val equalityConstraints = - filter { it.kind == ConstraintKind.EQUALITY } - .groupBy { it.typeHashCode } + private fun SmartList.simplifyConstraints(): SmartList = + simplifyLowerConstraints().simplifyEqualityConstraints() + + private fun SmartList.simplifyLowerConstraints(): SmartList { + val usefulConstraints = SmartList() + for (constraint in this) { + if (!constraint.isLowerAndFlexibleTypeWithDefNotNullLowerBound()) { + usefulConstraints.add(constraint) + continue + } + + // Now we have to check that some constraint T!!.T? <: K is useless or not + // If there is constraint T..T? <: K, then the original one (T!!.T?) is useless + // This is so because CST(T..T?, T!!..T?) == CST(T..T?) + + val thereIsStrongerConstraint = this.any { it.isStrongerThanLowerAndFlexibleTypeWithDefNotNullLowerBound(constraint) } + + if (!thereIsStrongerConstraint) { + usefulConstraints.add(constraint) + } + } + + return usefulConstraints + } + + // Such constraint is applicable for simplification + private fun Constraint.isLowerAndFlexibleTypeWithDefNotNullLowerBound(): Boolean = + kind == ConstraintKind.LOWER && type is FlexibleType && type.lowerBound.isDefinitelyNotNullType + + private fun Constraint.isStrongerThanLowerAndFlexibleTypeWithDefNotNullLowerBound(other: Constraint): Boolean { + if (this === other) return false + + if (typeHashCode != other.typeHashCode || kind == ConstraintKind.UPPER) return false + if (type !is FlexibleType) return false + + val otherFlexibleType = other.type as? FlexibleType ?: return false + val otherLowerBound = otherFlexibleType.lowerBound as? DefinitelyNotNullType ?: return false + val otherUpperBound = otherFlexibleType.upperBound + + return type.lowerBound == otherLowerBound.original && type.upperBound == otherUpperBound + } + + private fun SmartList.simplifyEqualityConstraints(): SmartList { + val equalityConstraints = filter { it.kind == ConstraintKind.EQUALITY }.groupBy { it.typeHashCode } return when { equalityConstraints.isEmpty() -> this else -> filterTo(SmartList()) { isUsefulConstraint(it, equalityConstraints) } diff --git a/compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt b/compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt new file mode 100644 index 00000000000..44ec3d6dfd9 --- /dev/null +++ b/compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt @@ -0,0 +1,64 @@ +// TARGET_BACKEND: JVM + +// FILE: Combiner.java + +public class Combiner { + public static void combine( + Inv source1, Inv source2, + Inv source3, Inv source4, + Inv source5, + Function5 combiner + ) { + return; + } +} + +// FILE: Function5.java + +public interface Function5 { + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); +} + +// FILE: Test.kt + +fun kCombine( + s1: Inv, s2: Inv, s3: Inv, s4: Inv, s5: Inv, + f: Function5 +) { +} + +data class Quantiple( + val first: T1, + val second: T2, + val third: T3, + val fourth: T4, + val fifth: T5 +) + +fun materialize(): (K1, K2, K3, K4, K5) -> Quantiple = { _, _, _, _, _ -> TODO() } + +class Inv + +fun test( + p1: Inv, p2: Inv, p3: Inv, p4: Inv, p5: Inv +) { + Combiner.combine( + p1, p2, p3, p4, p5, + materialize() + ) + + Combiner.combine( + p1, p2, p3, p4, p5, + ::Quantiple + ) + + kCombine( + p1, p2, p3, p4, p5, + materialize() + ) +} + +fun box(): String { + test(Inv(), Inv(), Inv(), Inv(), Inv()) + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 802eb2ed777..7aaf32654ed 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13857,6 +13857,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + @TestMetadata("manyFlexibleTypeParametersFromJavaAndConversions.kt") + public void testManyFlexibleTypeParametersFromJavaAndConversions() throws Exception { + runTest("compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt"); + } + @TestMetadata("noCoercionToUniForNullableLambdaReturnType.kt") public void testNoCoercionToUniForNullableLambdaReturnType() throws Exception { runTest("compiler/testData/codegen/box/inference/noCoercionToUniForNullableLambdaReturnType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b1b35a35afc..b6237083194 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13857,6 +13857,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + @TestMetadata("manyFlexibleTypeParametersFromJavaAndConversions.kt") + public void testManyFlexibleTypeParametersFromJavaAndConversions() throws Exception { + runTest("compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt"); + } + @TestMetadata("noCoercionToUniForNullableLambdaReturnType.kt") public void testNoCoercionToUniForNullableLambdaReturnType() throws Exception { runTest("compiler/testData/codegen/box/inference/noCoercionToUniForNullableLambdaReturnType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 25affe9786c..f76b169818c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12632,6 +12632,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + @TestMetadata("manyFlexibleTypeParametersFromJavaAndConversions.kt") + public void testManyFlexibleTypeParametersFromJavaAndConversions() throws Exception { + runTest("compiler/testData/codegen/box/inference/manyFlexibleTypeParametersFromJavaAndConversions.kt"); + } + @TestMetadata("noCoercionToUniForNullableLambdaReturnType.kt") public void testNoCoercionToUniForNullableLambdaReturnType() throws Exception { runTest("compiler/testData/codegen/box/inference/noCoercionToUniForNullableLambdaReturnType.kt");