diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 1fb24221dd3..152049a8f56 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -20213,6 +20213,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/platformTypes/override.kt"); } + @Test + @TestMetadata("propagateFlexibilityFromOtherConstraints.kt") + public void testPropagateFlexibilityFromOtherConstraints() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt"); + } + @Test @TestMetadata("rawOverrides.kt") public void testRawOverrides() throws Exception { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt index bd5f8914fb2..84e5affdb0c 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt @@ -40,7 +40,9 @@ class ResultTypeResolver( findResultIfThereIsEqualsConstraint(c, variableWithConstraints)?.let { return it } val subType = c.findSubType(variableWithConstraints) - val superType = c.findSuperType(variableWithConstraints) + // Super type should be the most flexible, sub type should be the least one + val superType = c.findSuperType(variableWithConstraints).makeFlexibleIfNecessary(c, variableWithConstraints.constraints) + return if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) { c.resultType(subType, superType, variableWithConstraints) } else { @@ -48,6 +50,30 @@ class ResultTypeResolver( } } + /* + * We propagate nullness flexibility into the result type from type variables in other constraints + * to prevent variable fixation into less flexible type. + * Constraints: + * UPPER(TypeVariable(T)..TypeVariable(T)?) + * UPPER(Foo?) + * Result type = makeFlexibleIfNecessary(Foo?) = Foo! + * + * We don't propagate nullness flexibility in depth as it's non-determined for now (see KT-35534): + * CST(Bar, Bar) = Bar + * CST(Bar, Bar) = Bar + * But: CST(Foo, Foo!) = CST(Foo!, Foo) = Foo! + */ + private fun KotlinTypeMarker?.makeFlexibleIfNecessary(c: Context, constraints: List) = with(c) { + when (val type = this@makeFlexibleIfNecessary) { + is SimpleTypeMarker -> { + if (constraints.any { it.type.typeConstructor().isTypeVariable() && it.type.hasFlexibleNullability() }) { + createFlexibleType(type.makeSimpleTypeDefinitelyNotNullOrNotNull(), type.withNullability(true)) + } else type + } + else -> type + } + } + private fun Context.resultType( firstCandidate: KotlinTypeMarker?, secondCandidate: KotlinTypeMarker?, diff --git a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt new file mode 100644 index 00000000000..4cbcd0abc0a --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt @@ -0,0 +1,32 @@ +// FULL_JDK +// FILE: test.kt + +@file:Suppress("UNUSED_PARAMETER") + +import java.util.Comparator + +abstract class DataView { + abstract val presentationName: String +} + +fun comboBox( + model: SortedComboBoxModel, + graphProperty: GraphProperty, +) {} + +class GraphProperty + +fun test() { + val presentationName: (DataView) -> String = { it.presentationName } + val parentComboBoxModel/*: SortedComboBoxModel*/ = SortedComboBoxModel(Comparator.comparing(presentationName)) + comboBox(parentComboBoxModel, GraphProperty()) +} + +// FILE: SortedComboBoxModel.java + +import java.util.Comparator; + +public class SortedComboBoxModel { + public SortedComboBoxModel(Comparator comparator) { + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt new file mode 100644 index 00000000000..de37642cfb4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt @@ -0,0 +1,32 @@ +// FULL_JDK +// FILE: test.kt + +@file:Suppress("UNUSED_PARAMETER") + +import java.util.Comparator + +abstract class DataView { + abstract val presentationName: String +} + +fun comboBox( + model: SortedComboBoxModel, + graphProperty: GraphProperty, +) {} + +class GraphProperty + +fun test() { + val presentationName: (DataView) -> String = { it.presentationName } + val parentComboBoxModel/*: SortedComboBoxModel*/ = SortedComboBoxModel(Comparator.comparing(presentationName)) + comboBox(parentComboBoxModel, GraphProperty()) +} + +// FILE: SortedComboBoxModel.java + +import java.util.Comparator; + +public class SortedComboBoxModel { + public SortedComboBoxModel(Comparator comparator) { + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.txt b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.txt new file mode 100644 index 00000000000..38e13f7ba03 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.txt @@ -0,0 +1,26 @@ +package + +public fun comboBox(/*0*/ model: SortedComboBoxModel, /*1*/ graphProperty: GraphProperty): kotlin.Unit +public fun test(): kotlin.Unit + +public abstract class DataView { + public constructor DataView() + public abstract val presentationName: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class GraphProperty { + public constructor GraphProperty() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class SortedComboBoxModel { + public constructor SortedComboBoxModel(/*0*/ comparator: java.util.Comparator!) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 24216caa2a4..009583ce0f4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -20219,6 +20219,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/platformTypes/override.kt"); } + @Test + @TestMetadata("propagateFlexibilityFromOtherConstraints.kt") + public void testPropagateFlexibilityFromOtherConstraints() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt"); + } + @Test @TestMetadata("rawOverrides.kt") public void testRawOverrides() throws Exception {