diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index d1c0b5880c9..0b22a318dbd 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -11196,6 +11196,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/upperBounds/doNotInferFromBoundsOnly.kt"); } + @TestMetadata("flexibilityInCommonSuperTypeCalculation.kt") + public void testFlexibilityInCommonSuperTypeCalculation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt"); + } + + @TestMetadata("flexibilityInCommonSuperTypeCalculation.ni.kt") + public void testFlexibilityInCommonSuperTypeCalculation_ni() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt"); + } + @TestMetadata("intersectUpperBounds.kt") public void testIntersectUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/intersectUpperBounds.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index 2ec2cbb7336..d0e41539851 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -16,11 +16,9 @@ package org.jetbrains.kotlin.resolve.calls -import org.jetbrains.kotlin.types.AbstractNullabilityChecker +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.AbstractFlexibilityChecker.hasDifferentFlexibilityAtDepth import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes -import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.AbstractTypeCheckerContext -import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext import org.jetbrains.kotlin.types.model.* @@ -32,10 +30,14 @@ object NewCommonSuperTypeCalculator { fun TypeSystemCommonSuperTypesContext.commonSuperType(types: List): KotlinTypeMarker { val maxDepth = types.maxBy { it.typeDepth() }?.typeDepth() ?: 0 - return commonSuperType(types, -maxDepth) + return commonSuperType(types, -maxDepth, true) } - private fun TypeSystemCommonSuperTypesContext.commonSuperType(types: List, depth: Int): KotlinTypeMarker { + private fun TypeSystemCommonSuperTypesContext.commonSuperType( + types: List, + depth: Int, + isTopLevelType: Boolean = false + ): KotlinTypeMarker { if (types.isEmpty()) throw IllegalStateException("Empty collection for input") types.singleOrNull()?.let { return it } @@ -69,6 +71,22 @@ object NewCommonSuperTypeCalculator { val upperSuperType = commonSuperTypeForSimpleTypes( types.map { it.upperBoundIfFlexible() }, depth, contextStubTypesEqualToAnything, contextStubTypesNotEqual ) + + if (!isTopLevelType) { + val nonStubTypes = + types.filter { !isStubRelatedType(it.lowerBoundIfFlexible()) && !isStubRelatedType(it.upperBoundIfFlexible()) } + val equalToEachOtherTypes = nonStubTypes.filter { potentialCommonSuperType -> + nonStubTypes.all { + AbstractTypeChecker.equalTypes(this, it, potentialCommonSuperType) + } + } + + if (equalToEachOtherTypes.isNotEmpty()) { + // TODO: merge flexibilities of type arguments instead of select the first suitable type + return equalToEachOtherTypes.first() + } + } + return createFlexibleType(lowerSuperType, upperSuperType) } @@ -109,8 +127,10 @@ object NewCommonSuperTypeCalculator { val uniqueTypes = arrayListOf() for (type in types) { val isNewUniqueType = uniqueTypes.all { - !AbstractTypeChecker.equalTypes(contextStubTypesNotEqual, it, type) || - it.typeConstructor().isIntegerLiteralTypeConstructor() + val equalsModuloFlexibility = AbstractTypeChecker.equalTypes(contextStubTypesNotEqual, it, type) && + !it.typeConstructor().isIntegerLiteralTypeConstructor() + + !equalsModuloFlexibility || hasDifferentFlexibilityAtDepth(listOf(it, type)) } if (isNewUniqueType) { uniqueTypes += type @@ -121,7 +141,7 @@ object NewCommonSuperTypeCalculator { // This function leaves only supertypes, i.e. A0 is a strong supertype for A iff A != A0 && A <: A0 // Explanation: consider types (A : A0, B : B0, A0, B0), then CST(A, B, A0, B0) == CST(CST(A, A0), CST(B, B0)) == CST(A0, B0) - private fun filterSupertypes( + private fun TypeSystemCommonSuperTypesContext.filterSupertypes( list: List, contextStubTypesNotEqual: AbstractTypeCheckerContext ): List { @@ -130,7 +150,9 @@ object NewCommonSuperTypeCalculator { while (iterator.hasNext()) { val potentialSubtype = iterator.next() val isSubtype = supertypes.any { supertype -> - supertype !== potentialSubtype && AbstractTypeChecker.isSubtypeOf(contextStubTypesNotEqual, potentialSubtype, supertype) + supertype !== potentialSubtype && + AbstractTypeChecker.isSubtypeOf(contextStubTypesNotEqual, potentialSubtype, supertype) && + !hasDifferentFlexibilityAtDepth(listOf(potentialSubtype, supertype)) } if (isSubtype) iterator.remove() @@ -352,14 +374,26 @@ object NewCommonSuperTypeCalculator { // CS(Out, Out) = Out // CS(In, In) = In if (asOut) { - val type = commonSuperType(arguments.map { it.getType() }, depth + 1) - return if (parameter.getVariance() != TypeVariance.INV) return type.asTypeArgument() else createTypeArgument( - type, - TypeVariance.OUT - ) + val argumentTypes = arguments.map { it.getType() } + val parameterIsNotInv = parameter.getVariance() != TypeVariance.INV + + if (parameterIsNotInv) { + return commonSuperType(argumentTypes, depth + 1).asTypeArgument() + } + + val equalToEachOtherType = arguments.firstOrNull { potentialSuperType -> + arguments.all { AbstractTypeChecker.equalTypes(this, it.getType(), potentialSuperType.getType()) } + } + + return if (equalToEachOtherType == null) { + createTypeArgument(commonSuperType(argumentTypes, depth + 1), TypeVariance.OUT) + } else { + createTypeArgument(equalToEachOtherType.getType(), TypeVariance.INV) + } } else { val type = intersectTypes(arguments.map { it.getType() }) - return if (parameter.getVariance() != TypeVariance.INV) return type.asTypeArgument() else createTypeArgument( + + return if (parameter.getVariance() != TypeVariance.INV) type.asTypeArgument() else createTypeArgument( type, TypeVariance.IN ) diff --git a/compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableFromBothBranches.kt b/compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableFromBothBranches.kt index 3b672bd96c7..03de747369f 100644 --- a/compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableFromBothBranches.kt +++ b/compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableFromBothBranches.kt @@ -16,5 +16,5 @@ fun foo(f: () -> R): R = f() fun test(n: Number) { val a = select(foo { JavaTest.createNumberArray() }, emptyArray()) - ..kotlin.Array?)")!>a + ..kotlin.Array<(kotlin.Number..kotlin.Number?)>?)")!>a } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.fir.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.fir.kt new file mode 100644 index 00000000000..38ae04e2545 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.fir.kt @@ -0,0 +1,273 @@ +// !DIAGNOSTICS: -UNSUPPORTED -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST -USELESS_CAST -UNUSED_PARAMETER -UNCHECKED_CAST -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE -UNREACHABLE_CODE -DEBUG_INFO_CONSTANT +// !LANGUAGE: -NewInference +// SKIP_TXT + +// FILE: Test.java +import java.util.List; + +public class Test { + public static B foo() { return null; } + public static T bar() { return null; } + public static T id(T x) { return null; } + public static List getList(T x) { return null; } + public static List getRawList() { return null; } +} + +// FILE: main.kt +class A(x: T) +class B + +fun select(vararg x: T): T = null as T + +fun case_1() { + val x = Test.foo() // B! + + val result_1 = select(A(x), A(B())) + val result_2 = select(A(B()), A(x), A(if (true) B() else null)) + val result_3 = select(A(x), A(if (true) B() else null)) + + result_1 + result_2 + result_3 +} + +fun case_2() { + val x = Test.bar() // Any! + val y: Any? = null + + val result = select(A(Any()), A(y), A(x)) + + result +} + +fun case_3() { + val x = Test.bar() // T! + val y: T? = null + val result = select(A(y), A(x), A(null as T)) + + result +} + +fun case_4() { + val x = Test.bar() // Nothing! + val y = null // Nothing? + + val result = select(A(x), A(y), A(return)) + + result +} + +class C(x: T, y: K, z: L) + +fun case_5() { + val x = Test.foo() // B! + val y: B? = null + + val result_1 = select(C(x, B(), 10), C(B(), x, 10)) + val result_2 = select(C(B(), x, y), C(x, B(), y), C(y, x, B()), C(x, y, B()), C(y, B(), x), C(B(), y, x)) + + result_1 + result_2 +} + +fun case_6() { + val x1 = Test.bar, B, Int>, B, B>>() // C, B, Int>, B, B>! + val x2 = C(null as C, B?, Int>?, Test.id(B()), B()) // C, B?, Int>?, B?, B> + val x3 = C(C(A(Test.id(1f)), B(), Test.id(1)), Test.id(B()), B()) // C, B, Int!>, B!, B> + val x4 = C(C(A(Test.id(3f)), null as B?, null as Int?), null as B?, null as B?) // C?, B?, Int?>, B?, B?> + val x5 = C(Test.id(C(A(1f), Test.id(B()), 1)), B(), Test.id(B())) // C, B!, Int>!, B, B!> + val x6 = Test.id(C(select(C(Test.id(A(1f)), null as B?, null as Int?), null), Test.id(B()), null as B?)) // C, B?, Int?>?, B!, B?>! + val x7 = C(C(Test.id(A(1f)), B(), 1), B(), B()) // C!, B, Int>, B, B> + val x8 = C(Test.id(C(null as A?, B(), null as Int?)), null as B?, Test.id(B())) // C?, B, Int?>, B?, B> + val x9 = null as C, B?, Int>, B, B>? // C, B?, Int>, B, B>? + + val result_1 = select(x1, x2, x3, x4, x5, x6, x7, x8, x9) + val result_2 = select(x9, x8, x7, x6, x5, x4, x3, x2, x1) + val result_3 = select(x5, x7, x9, x3, x1, x2, x8, x4, x6) + + result_1 + result_2 + result_3 +} + +fun case_7() { + val x0: Int = 1 + val x1 = C(A(Test.id(x0)), B(), B()) + val x2 = C(Test.id(A(1)), B(), B()) + x1 + x2 + + val result_5 = select(x1, x2) + result_5 +} + +fun case_8() { + val x1 = A(10) + val x2 = select(A(""), null) + val x3 = Test.id(A(null)) + + val result_1 = select(x1, x2, x3) + result_1 +} + +fun case_9() { + val x1 = A(A(10)) + val x2 = A(select(A(""), null)) + val x3 = A(Test.id(A('s'))) + + val result_1 = select(x1, x2, x3) + result_1 +} + +fun case_10() { + val x1 = 10 + val x2 = select(10, null) + val x3 = Test.id(10) + + val result_1 = select(x2, x1, x3) + val result_2 = select(x2, x3, x1) + val result_3 = select(x1, x2, x3) + val result_4 = select(x1, x3, x2) + val result_5 = select(x3, x2, x1) + val result_6 = select(x3, x1, x2) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 +} + +fun case_11(y: T) { + val x1 = Test.bar() // T! + val x2 = select(y, null) + if (y != null) { + val x3 = Test.id(y) // T! + val result_1 = select(A(y), A(x1)) + val result_2 = select(A(y), A(x1), A(x2)) + val result_3 = select(A(y), A(x3), A(x2)) + val result_4 = select(A(y as T), A(x1)) + val result_5 = select(A(y as T), A(x1), A(x2)) + val result_6 = select(A(y as T), A(x3), A(x2)) + val result_7 = select(A(y as T), A(x1)) + val result_8 = select(A(y as T), A(x3)) + val result_9 = select(A(x3), A(y as T)) + + val result_10 = select(y, x1) + val result_11 = select(y, x2, x2) + val result_12 = select(y, x3, x2) + val result_13 = select(y as T, x1) + val result_14 = select(y as T, x1, x2) + val result_15 = select(y as T, x3, x2) + val result_16 = select(y as T, x1) + val result_17 = select(y as T, x3) + val result_18 = select(x3, y as T) + + x1 + x2 + x3 + y + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 + result_9 + + result_10 + result_11 + result_12 + result_13 + result_14 + result_15 + result_16 + result_17 + result_18 + } +} + +fun case_12() { + val x1 = Test.getList(10) + val x2 = null as MutableList + val x3 = select(null as List, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 +} + +fun case_13() { + val x1 = Test.getList(10) + val x2: dynamic = null + val x3 = null as MutableList + val x4 = select(null as List, null) + + val result_1 = select(x1, x2, x3, x4) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x2) + val result_5 = select(x4, x2) + val result_6 = select(x4, x3, x2) + val result_7 = select(A(x1), A(x2), A(x3), A(x4)) + val result_8 = select(A(x2), A(x1)) + val result_9 = select(A(x2), A(x1), A(x3)) + val result_10 = select(A(x3), A(x2)) + val result_11 = select(A(x4), A(x2)) + val result_12 = select(A(x4), A(x3), A(x2)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 + result_9 + result_10 + result_11 + result_12 +} + +fun case_14() { + val x1 = Test.getRawList() + val x2 = null as List + val x3 = select(null as MutableList, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 +} diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt new file mode 100644 index 00000000000..22ea1790c38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt @@ -0,0 +1,273 @@ +// !DIAGNOSTICS: -UNSUPPORTED -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST -USELESS_CAST -UNUSED_PARAMETER -UNCHECKED_CAST -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE -UNREACHABLE_CODE -DEBUG_INFO_CONSTANT +// !LANGUAGE: -NewInference +// SKIP_TXT + +// FILE: Test.java +import java.util.List; + +public class Test { + public static B foo() { return null; } + public static T bar() { return null; } + public static T id(T x) { return null; } + public static List getList(T x) { return null; } + public static List getRawList() { return null; } +} + +// FILE: main.kt +class A(x: T) +class B + +fun select(vararg x: T): T = null as T + +fun case_1() { + val x = Test.foo() // B! + + val result_1 = select(A(x), A(B())) + val result_2 = select(A(B()), A(x), A(if (true) B() else null)) + val result_3 = select(A(x), A(if (true) B() else null)) + + ")!>result_1 + ")!>result_2 + ")!>result_3 +} + +fun case_2() { + val x = Test.bar() // Any! + val y: Any? = null + + val result = select(A(Any()), A(y), A(x)) + + ")!>result +} + +fun case_3() { + val x = Test.bar() // T! + val y: T? = null + val result = select(A(y), A(x), A(null as T)) + + ")!>result +} + +fun case_4() { + val x = Test.bar() // Nothing! + val y = null // Nothing? + + val result = select(A(x), A(y), A(return)) + + ")!>result +} + +class C(x: T, y: K, z: L) + +fun case_5() { + val x = Test.foo() // B! + val y: B? = null + + val result_1 = select(C(x, B(), 10), C(B(), x, 10)) + val result_2 = select(C(B(), x, y), C(x, B(), y), C(y, x, B()), C(x, y, B()), C(y, B(), x), C(B(), y, x)) + + ")!>result_1 + ")!>result_2 +} + +fun case_6() { + val x1 = Test.bar, B, Int>, B, B>>() // C, B, Int>, B, B>! + val x2 = C(null as C, B?, Int>?, Test.id(B()), B()) // C, B?, Int>?, B?, B> + val x3 = C(C(A(Test.id(1f)), B(), Test.id(1)), Test.id(B()), B()) // C, B, Int!>, B!, B> + val x4 = C(C(A(Test.id(3f)), null as B?, null as Int?), null as B?, null as B?) // C?, B?, Int?>, B?, B?> + val x5 = C(Test.id(C(A(1f), Test.id(B()), 1)), B(), Test.id(B())) // C, B!, Int>!, B, B!> + val x6 = Test.id(C(select(C(Test.id(A(1f)), null as B?, null as Int?), null), Test.id(B()), null as B?)) // C, B?, Int?>?, B!, B?>! + val x7 = C(C(Test.id(A(1f)), B(), 1), B(), B()) // C!, B, Int>, B, B> + val x8 = C(Test.id(C(null as A?, B(), null as Int?)), null as B?, Test.id(B())) // C?, B, Int?>, B?, B> + val x9 = null as C, B?, Int>, B, B>? // C, B?, Int>, B, B>? + + val result_1 = select(x1, x2, x3, x4, x5, x6, x7, x8, x9) + val result_2 = select(x9, x8, x7, x6, x5, x4, x3, x2, x1) + val result_3 = select(x5, x7, x9, x3, x1, x2, x8, x4, x6) + + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_1 + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_2 + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_3 +} + +fun case_7() { + val x0: Int = 1 + val x1 = C(A(Test.id(x0)), B(), B()) + val x2 = C(Test.id(A(1)), B(), B()) + , B, B>")!>x1 + ..A?), B, B>")!>x2 + + val result_5 = select(x1, x2) + , B, B>")!>result_5 +} + +fun case_8() { + val x1 = A(10) + val x2 = select(A(""), null) + val x3 = Test.id(A(null)) + + val result_1 = select(x1, x2, x3) + ?")!>result_1 +} + +fun case_9() { + val x1 = A(A(10)) + val x2 = A(select(A(""), null)) + val x3 = A(Test.id(A('s'))) + + val result_1 = select(x1, x2, x3) + ?>")!>result_1 +} + +fun case_10() { + val x1 = 10 + val x2 = select(10, null) + val x3 = Test.id(10) + + val result_1 = select(x2, x1, x3) + val result_2 = select(x2, x3, x1) + val result_3 = select(x1, x2, x3) + val result_4 = select(x1, x3, x2) + val result_5 = select(x3, x2, x1) + val result_6 = select(x3, x1, x2) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 +} + +fun case_11(y: T) { + val x1 = Test.bar() // T! + val x2 = select(y, null) + if (y != null) { + val x3 = Test.id(y) // T! + val result_1 = select(A(y), A(x1)) + val result_2 = select(A(y), A(x1), A(x2)) + val result_3 = select(A(y), A(x3), A(x2)) + val result_4 = select(A(y as T), A(x1)) + val result_5 = select(A(y as T), A(x1), A(x2)) + val result_6 = select(A(y as T), A(x3), A(x2)) + val result_7 = select(A(y as T), A(x1)) + val result_8 = select(A(y as T), A(x3)) + val result_9 = select(A(x3), A(y as T)) + + val result_10 = select(y, x1) + val result_11 = select(y, x2, x2) + val result_12 = select(y, x3, x2) + val result_13 = select(y as T, x1) + val result_14 = select(y as T, x1, x2) + val result_15 = select(y as T, x3, x2) + val result_16 = select(y as T, x1) + val result_17 = select(y as T, x3) + val result_18 = select(x3, y as T) + + x1 + x2 + x3 + y + + ")!>result_1 + ")!>result_2 + ")!>result_3 + ")!>result_4 + ")!>result_5 + ")!>result_6 + ")!>result_7 + ")!>result_8 + ")!>result_9 + + result_10 + result_11 + result_12 + result_13 + result_14 + result_15 + result_16 + result_17 + result_18 + } +} + +fun case_12() { + val x1 = Test.getList(10) + val x2 = null as MutableList + val x3 = select(null as List, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)")!>result_1 + ..kotlin.collections.List?)")!>result_2 + ?")!>result_3 + ?")!>result_4 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_5 + >")!>result_6 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_7 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_8 +} + +fun case_13() { + val x1 = Test.getList(10) + val x2: dynamic = null + val x3 = null as MutableList + val x4 = select(null as List, null) + + val result_1 = select(x1, x2, x3, x4) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x2) + val result_5 = select(x4, x2) + val result_6 = select(x4, x3, x2) + val result_7 = select(A(x1), A(x2), A(x3), A(x4)) + val result_8 = select(A(x2), A(x1)) + val result_9 = select(A(x2), A(x1), A(x3)) + val result_10 = select(A(x3), A(x2)) + val result_11 = select(A(x4), A(x2)) + val result_12 = select(A(x4), A(x3), A(x2)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_7 + ")!>result_8 + ")!>result_9 + >")!>result_10 + ?>")!>result_11 + ")!>result_12 +} + +fun case_14() { + val x1 = Test.getRawList() + val x2 = null as List + val x3 = select(null as MutableList, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + ..kotlin.collections.List?)")!>result_1 + ..kotlin.collections.List?)")!>result_2 + ?")!>result_3 + ?..kotlin.collections.List?)")!>result_4 + ..kotlin.collections.List?)>")!>result_5 + ..kotlin.collections.List?)>")!>result_6 + ?>")!>result_7 + ?..kotlin.collections.List?)>")!>result_8 +} diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.fir.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.fir.kt new file mode 100644 index 00000000000..bbfcd1839ba --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.fir.kt @@ -0,0 +1,273 @@ +// !DIAGNOSTICS: -UNSUPPORTED -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST -USELESS_CAST -UNUSED_PARAMETER -UNCHECKED_CAST -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE -UNREACHABLE_CODE -DEBUG_INFO_CONSTANT +// !LANGUAGE: +NewInference +// SKIP_TXT + +// FILE: Test.java +import java.util.List; + +public class Test { + public static B foo() { return null; } + public static T bar() { return null; } + public static T id(T x) { return null; } + public static List getList(T x) { return null; } + public static List getRawList() { return null; } +} + +// FILE: main.kt +class A(x: T) +class B + +fun select(vararg x: T): T = null as T + +fun case_1() { + val x = Test.foo() // B! + + val result_1 = select(A(x), A(B())) + val result_2 = select(A(B()), A(x), A(if (true) B() else null)) + val result_3 = select(A(x), A(if (true) B() else null)) + + result_1 + result_2 + result_3 +} + +fun case_2() { + val x = Test.bar() // Any! + val y: Any? = null + + val result = select(A(Any()), A(y), A(x)) + + result +} + +fun case_3() { + val x = Test.bar() // T! + val y: T? = null + val result = select(A(y), A(x), A(null as T)) + + result +} + +fun case_4() { + val x = Test.bar() // Nothing! + val y = null // Nothing? + + val result = select(A(x), A(y), A(return)) + + result +} + +class C(x: T, y: K, z: L) + +fun case_5() { + val x = Test.foo() // B! + val y: B? = null + + val result_1 = select(C(x, B(), 10), C(B(), x, 10)) + val result_2 = select(C(B(), x, y), C(x, B(), y), C(y, x, B()), C(x, y, B()), C(y, B(), x), C(B(), y, x)) + + result_1 + result_2 +} + +fun case_6() { + val x1 = Test.bar, B, Int>, B, B>>() // C, B, Int>, B, B>! + val x2 = C(null as C, B?, Int>?, Test.id(B()), B()) // C, B?, Int>?, B?, B> + val x3 = C(C(A(Test.id(1f)), B(), Test.id(1)), Test.id(B()), B()) // C, B, Int!>, B!, B> + val x4 = C(C(A(Test.id(3f)), null as B?, null as Int?), null as B?, null as B?) // C?, B?, Int?>, B?, B?> + val x5 = C(Test.id(C(A(1f), Test.id(B()), 1)), B(), Test.id(B())) // C, B!, Int>!, B, B!> + val x6 = Test.id(C(select(C(Test.id(A(1f)), null as B?, null as Int?), null), Test.id(B()), null as B?)) // C, B?, Int?>?, B!, B?>! + val x7 = C(C(Test.id(A(1f)), B(), 1), B(), B()) // C!, B, Int>, B, B> + val x8 = C(Test.id(C(null as A?, B(), null as Int?)), null as B?, Test.id(B())) // C?, B, Int?>, B?, B> + val x9 = null as C, B?, Int>, B, B>? // C, B?, Int>, B, B>? + + val result_1 = select(x1, x2, x3, x4, x5, x6, x7, x8, x9) + val result_2 = select(x9, x8, x7, x6, x5, x4, x3, x2, x1) + val result_3 = select(x5, x7, x9, x3, x1, x2, x8, x4, x6) + + result_1 + result_2 + result_3 +} + +fun case_7() { + val x0: Int = 1 + val x1 = C(A(Test.id(x0)), B(), B()) + val x2 = C(Test.id(A(1)), B(), B()) + x1 + x2 + + val result_5 = select(x1, x2) + result_5 +} + +fun case_8() { + val x1 = A(10) + val x2 = select(A(""), null) + val x3 = Test.id(A(null)) + + val result_1 = select(x1, x2, x3) + result_1 +} + +fun case_9() { + val x1 = A(A(10)) + val x2 = A(select(A(""), null)) + val x3 = A(Test.id(A('s'))) + + val result_1 = select(x1, x2, x3) + result_1 +} + +fun case_10() { + val x1 = 10 + val x2 = select(10, null) + val x3 = Test.id(10) + + val result_1 = select(x2, x1, x3) + val result_2 = select(x2, x3, x1) + val result_3 = select(x1, x2, x3) + val result_4 = select(x1, x3, x2) + val result_5 = select(x3, x2, x1) + val result_6 = select(x3, x1, x2) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 +} + +fun case_11(y: T) { + val x1 = Test.bar() // T! + val x2 = select(y, null) + if (y != null) { + val x3 = Test.id(y) // T! + val result_1 = select(A(y), A(x1)) + val result_2 = select(A(y), A(x1), A(x2)) + val result_3 = select(A(y), A(x3), A(x2)) + val result_4 = select(A(y as T), A(x1)) + val result_5 = select(A(y as T), A(x1), A(x2)) + val result_6 = select(A(y as T), A(x3), A(x2)) + val result_7 = select(A(y as T), A(x1)) + val result_8 = select(A(y as T), A(x3)) + val result_9 = select(A(x3), A(y as T)) + + val result_10 = select(y, x1) + val result_11 = select(y, x2, x2) + val result_12 = select(y, x3, x2) + val result_13 = select(y as T, x1) + val result_14 = select(y as T, x1, x2) + val result_15 = select(y as T, x3, x2) + val result_16 = select(y as T, x1) + val result_17 = select(y as T, x3) + val result_18 = select(x3, y as T) + + x1 + x2 + x3 + y + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 + result_9 + + result_10 + result_11 + result_12 + result_13 + result_14 + result_15 + result_16 + result_17 + result_18 + } +} + +fun case_12() { + val x1 = Test.getList(10) + val x2 = null as MutableList + val x3 = select(null as List, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 +} + +fun case_13() { + val x1 = Test.getList(10) + val x2: dynamic = null + val x3 = null as MutableList + val x4 = select(null as List, null) + + val result_1 = select(x1, x2, x3, x4) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x2) + val result_5 = select(x4, x2) + val result_6 = select(x4, x3, x2) + val result_7 = select(A(x1), A(x2), A(x3), A(x4)) + val result_8 = select(A(x2), A(x1)) + val result_9 = select(A(x2), A(x1), A(x3)) + val result_10 = select(A(x3), A(x2)) + val result_11 = select(A(x4), A(x2)) + val result_12 = select(A(x4), A(x3), A(x2)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 + result_9 + result_10 + result_11 + result_12 +} + +fun case_14() { + val x1 = Test.getRawList() + val x2 = null as List + val x3 = select(null as MutableList, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + result_7 + result_8 +} diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt new file mode 100644 index 00000000000..2ea53605e6f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt @@ -0,0 +1,273 @@ +// !DIAGNOSTICS: -UNSUPPORTED -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST -USELESS_CAST -UNUSED_PARAMETER -UNCHECKED_CAST -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE -UNREACHABLE_CODE -DEBUG_INFO_CONSTANT +// !LANGUAGE: +NewInference +// SKIP_TXT + +// FILE: Test.java +import java.util.List; + +public class Test { + public static B foo() { return null; } + public static T bar() { return null; } + public static T id(T x) { return null; } + public static List getList(T x) { return null; } + public static List getRawList() { return null; } +} + +// FILE: main.kt +class A(x: T) +class B + +fun select(vararg x: T): T = null as T + +fun case_1() { + val x = Test.foo() // B! + + val result_1 = select(A(x), A(B())) + val result_2 = select(A(B()), A(x), A(if (true) B() else null)) + val result_3 = select(A(x), A(if (true) B() else null)) + + ")!>result_1 + ")!>result_2 + ")!>result_3 +} + +fun case_2() { + val x = Test.bar() // Any! + val y: Any? = null + + val result = select(A(Any()), A(y), A(x)) + + ")!>result +} + +fun case_3() { + val x = Test.bar() // T! + val y: T? = null + val result = select(A(y), A(x), A(null as T)) + + ")!>result +} + +fun case_4() { + val x = Test.bar() // Nothing! + val y = null // Nothing? + + val result = select(A(x), A(y), A(return)) + + ")!>result +} + +class C(x: T, y: K, z: L) + +fun case_5() { + val x = Test.foo() // B! + val y: B? = null + + val result_1 = select(C(x, B(), 10), C(B(), x, 10)) + val result_2 = select(C(B(), x, y), C(x, B(), y), C(y, x, B()), C(x, y, B()), C(y, B(), x), C(B(), y, x)) + + ")!>result_1 + ")!>result_2 +} + +fun case_6() { + val x1 = Test.bar, B, Int>, B, B>>() // C, B, Int>, B, B>! + val x2 = C(null as C, B?, Int>?, Test.id(B()), B()) // C, B?, Int>?, B?, B> + val x3 = C(C(A(Test.id(1f)), B(), Test.id(1)), Test.id(B()), B()) // C, B, Int!>, B!, B> + val x4 = C(C(A(Test.id(3f)), null as B?, null as Int?), null as B?, null as B?) // C?, B?, Int?>, B?, B?> + val x5 = C(Test.id(C(A(1f), Test.id(B()), 1)), B(), Test.id(B())) // C, B!, Int>!, B, B!> + val x6 = Test.id(C(select(C(Test.id(A(1f)), null as B?, null as Int?), null), Test.id(B()), null as B?)) // C, B?, Int?>?, B!, B?>! + val x7 = C(C(Test.id(A(1f)), B(), 1), B(), B()) // C!, B, Int>, B, B> + val x8 = C(Test.id(C(null as A?, B(), null as Int?)), null as B?, Test.id(B())) // C?, B, Int?>, B?, B> + val x9 = null as C, B?, Int>, B, B>? // C, B?, Int>, B, B>? + + val result_1 = select(x1, x2, x3, x4, x5, x6, x7, x8, x9) + val result_2 = select(x9, x8, x7, x6, x5, x4, x3, x2, x1) + val result_3 = select(x5, x7, x9, x3, x1, x2, x8, x4, x6) + + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_1 + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_2 + ?, (B..B?), (kotlin.Int..kotlin.Int?)>?, (B..B?), (B..B?)>?")!>result_3 +} + +fun case_7() { + val x0: Int = 1 + val x1 = C(A(Test.id(x0)), B(), B()) + val x2 = C(Test.id(A(1)), B(), B()) + , B, B>")!>x1 + ..A?), B, B>")!>x2 + + val result_5 = select(x1, x2) + , B, B>")!>result_5 +} + +fun case_8() { + val x1 = A(10) + val x2 = select(A(""), null) + val x3 = Test.id(A(null)) + + val result_1 = select(x1, x2, x3) + & java.io.Serializable}?>?")!>result_1 +} + +fun case_9() { + val x1 = A(A(10)) + val x2 = A(select(A(""), null)) + val x3 = A(Test.id(A('s'))) + + val result_1 = select(x1, x2, x3) + & java.io.Serializable}>?>")!>result_1 +} + +fun case_10() { + val x1 = 10 + val x2 = select(10, null) + val x3 = Test.id(10) + + val result_1 = select(x2, x1, x3) + val result_2 = select(x2, x3, x1) + val result_3 = select(x1, x2, x3) + val result_4 = select(x1, x3, x2) + val result_5 = select(x3, x2, x1) + val result_6 = select(x3, x1, x2) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 +} + +fun case_11(y: T) { + val x1 = Test.bar() // T! + val x2 = select(y, null) + if (y != null) { + val x3 = Test.id(y) // T! + val result_1 = select(A(y), A(x1)) + val result_2 = select(A(y), A(x1), A(x2)) + val result_3 = select(A(y), A(x3), A(x2)) + val result_4 = select(A(y as T), A(x1)) + val result_5 = select(A(y as T), A(x1), A(x2)) + val result_6 = select(A(y as T), A(x3), A(x2)) + val result_7 = select(A(y as T), A(x1)) + val result_8 = select(A(y as T), A(x3)) + val result_9 = select(A(x3), A(y as T)) + + val result_10 = select(y, x1) + val result_11 = select(y, x2, x2) + val result_12 = select(y, x3, x2) + val result_13 = select(y as T, x1) + val result_14 = select(y as T, x1, x2) + val result_15 = select(y as T, x3, x2) + val result_16 = select(y as T, x1) + val result_17 = select(y as T, x3) + val result_18 = select(x3, y as T) + + x1 + x2 + x3 + y + + ")!>result_1 + ")!>result_2 + ")!>result_3 + ")!>result_4 + ")!>result_5 + ")!>result_6 + ")!>result_7 + ")!>result_8 + ")!>result_9 + + result_10 + result_11 + result_12 + result_13 + result_14 + result_15 + result_16 + result_17 + result_18 + } +} + +fun case_12() { + val x1 = Test.getList(10) + val x2 = null as MutableList + val x3 = select(null as List, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)")!>result_1 + ..kotlin.collections.List?)")!>result_2 + ?")!>result_3 + ?")!>result_4 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_5 + >")!>result_6 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_7 + ..kotlin.collections.List<(kotlin.Int..kotlin.Int?)>?)>")!>result_8 +} + +fun case_13() { + val x1 = Test.getList(10) + val x2: dynamic = null + val x3 = null as MutableList + val x4 = select(null as List, null) + + val result_1 = select(x1, x2, x3, x4) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x2) + val result_5 = select(x4, x2) + val result_6 = select(x4, x3, x2) + val result_7 = select(A(x1), A(x2), A(x3), A(x4)) + val result_8 = select(A(x2), A(x1)) + val result_9 = select(A(x2), A(x1), A(x3)) + val result_10 = select(A(x3), A(x2)) + val result_11 = select(A(x4), A(x2)) + val result_12 = select(A(x4), A(x3), A(x2)) + + result_1 + result_2 + result_3 + result_4 + result_5 + result_6 + ")!>result_7 + ")!>result_8 + ")!>result_9 + ")!>result_10 + ")!>result_11 + ")!>result_12 +} + +fun case_14() { + val x1 = Test.getRawList() + val x2 = null as List + val x3 = select(null as MutableList, null) + + val result_1 = select(x1, x2) + val result_2 = select(x2, x1) + val result_3 = select(x2, x1, x3) + val result_4 = select(x3, x1) + val result_5 = select(A(x1), A(x2)) + val result_6 = select(A(x2), A(x1)) + val result_7 = select(A(x3), A(x1), A(x2)) + val result_8 = select(A(x1), A(x3)) + + ..kotlin.collections.List<*>?)")!>result_1 + ..kotlin.collections.List<*>?)")!>result_2 + ?..kotlin.collections.List<*>?)")!>result_3 + ?..kotlin.collections.List<*>?)")!>result_4 + ..kotlin.collections.List<*>?)>")!>result_5 + ..kotlin.collections.List<*>?)>")!>result_6 + ?..kotlin.collections.List<*>?)>")!>result_7 + ?..kotlin.collections.List<*>?)>")!>result_8 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 35524c58668..ae713e90ed8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -11203,6 +11203,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/doNotInferFromBoundsOnly.kt"); } + @TestMetadata("flexibilityInCommonSuperTypeCalculation.kt") + public void testFlexibilityInCommonSuperTypeCalculation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt"); + } + + @TestMetadata("flexibilityInCommonSuperTypeCalculation.ni.kt") + public void testFlexibilityInCommonSuperTypeCalculation_ni() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt"); + } + @TestMetadata("intersectUpperBounds.kt") public void testIntersectUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/intersectUpperBounds.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 053d687294a..1d401b64cec 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -11198,6 +11198,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/upperBounds/doNotInferFromBoundsOnly.kt"); } + @TestMetadata("flexibilityInCommonSuperTypeCalculation.kt") + public void testFlexibilityInCommonSuperTypeCalculation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.kt"); + } + + @TestMetadata("flexibilityInCommonSuperTypeCalculation.ni.kt") + public void testFlexibilityInCommonSuperTypeCalculation_ni() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/flexibilityInCommonSuperTypeCalculation.ni.kt"); + } + @TestMetadata("intersectUpperBounds.kt") public void testIntersectUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/intersectUpperBounds.kt"); diff --git a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index cc7f3739be2..e86a22940a9 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -580,3 +580,28 @@ object AbstractNullabilityChecker { return isEqualTypeConstructors(type.typeConstructor(), end) } } + + +object AbstractFlexibilityChecker { + fun TypeSystemCommonSuperTypesContext.hasDifferentFlexibilityAtDepth(types: Collection): Boolean { + if (types.isEmpty()) return false + if (hasDifferentFlexibility(types)) return true + + for (i in 0 until types.first().argumentsCount()) { + val typeArgumentForOtherTypes = types.mapNotNull { + if (it.argumentsCount() > i && !it.getArgument(i).isStarProjection()) it.getArgument(i).getType() else null + } + + if (hasDifferentFlexibilityAtDepth(typeArgumentForOtherTypes)) return true + } + + return false + } + + private fun TypeSystemCommonSuperTypesContext.hasDifferentFlexibility(types: Collection): Boolean { + val firstType = types.first() + if (types.all { it === firstType }) return false + + return !types.all { it.isFlexible() } && !types.all { !it.isFlexible() } + } +}