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 38a724a200c..1fc8264d58d 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -16476,6 +16476,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); } + @TestMetadata("flexibilityThroughTypeVariable.kt") + public void testFlexibilityThroughTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt"); + } + + @TestMetadata("flexibilityThroughTypeVariableOut.kt") + public void testFlexibilityThroughTypeVariableOut() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt"); + } + @TestMetadata("genericsAndArrays.kt") public void testGenericsAndArrays() throws Exception { runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index b0655211bdb..e9f49673a4a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -173,7 +173,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { } } - private fun TypeParameterDescriptor.shouldBeFlexible(): Boolean { + fun TypeParameterDescriptor.shouldBeFlexible(): Boolean { return upperBounds.any { it.isFlexible() || ((it.constructor.declarationDescriptor as? TypeParameterDescriptor)?.run { shouldBeFlexible() } ?: false) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt index 9b5260809c7..5432c6c6537 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components +import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.shouldBeFlexible import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.* @@ -27,7 +28,11 @@ class ConstraintIncorporator( fun getConstraintsForVariable(typeVariable: TypeVariableMarker): Collection - fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) + fun addNewIncorporatedConstraint( + lowerType: KotlinTypeMarker, + upperType: KotlinTypeMarker, + shouldTryUseDifferentFlexibilityForUpperType: Boolean + ) fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext) } @@ -49,11 +54,14 @@ class ConstraintIncorporator( typeVariable: TypeVariableMarker, constraint: Constraint ) { + val shouldBeTypeVariableFlexible = + typeVariable is TypeVariableFromCallableDescriptor && typeVariable.originalTypeParameter.shouldBeFlexible() + // \alpha <: constraint.type if (constraint.kind != ConstraintKind.LOWER) { getConstraintsForVariable(typeVariable).forEach { if (it.kind != ConstraintKind.UPPER) { - addNewIncorporatedConstraint(it.type, constraint.type) + addNewIncorporatedConstraint(it.type, constraint.type, shouldBeTypeVariableFlexible) } } } @@ -62,7 +70,7 @@ class ConstraintIncorporator( if (constraint.kind != ConstraintKind.UPPER) { getConstraintsForVariable(typeVariable).forEach { if (it.kind != ConstraintKind.LOWER) { - addNewIncorporatedConstraint(constraint.type, it.type) + addNewIncorporatedConstraint(constraint.type, it.type, shouldBeTypeVariableFlexible) } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt index 94fce42ad1b..1e1f4c5a44d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt @@ -148,10 +148,33 @@ class ConstraintInjector( } } - fun runIsSubtypeOf(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) { - if (!AbstractTypeChecker.isSubtypeOf(this@TypeCheckerContext as AbstractTypeCheckerContext, lowerType, upperType)) { + fun runIsSubtypeOf( + lowerType: KotlinTypeMarker, + upperType: KotlinTypeMarker, + shouldTryUseDifferentFlexibilityForUpperType: Boolean = false + ) { + fun isSubtypeOf(upperType: KotlinTypeMarker) = + AbstractTypeChecker.isSubtypeOf( + this@TypeCheckerContext as AbstractTypeCheckerContext, + lowerType, + upperType + ) + + if (!isSubtypeOf(upperType)) { // todo improve error reporting -- add information about base types - c.addError(NewConstraintError(lowerType, upperType, position)) + if (shouldTryUseDifferentFlexibilityForUpperType && upperType is SimpleType) { + /* + * Please don't reuse this logic. + * It's necessary to solve constraint systems when flexibility isn't propagated through a type variable. + * It's OK in the old inference because it uses already substituted types, that are with the correct flexibility. + */ + val flexibleUpperType = createFlexibleType(upperType, upperType.withNullability(true)) + if (!isSubtypeOf(flexibleUpperType)) { + c.addError(NewConstraintError(lowerType, flexibleUpperType, position)) + } + } else { + c.addError(NewConstraintError(lowerType, upperType, position)) + } } } @@ -181,10 +204,14 @@ class ConstraintInjector( } // from ConstraintIncorporator.Context - override fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) { + override fun addNewIncorporatedConstraint( + lowerType: KotlinTypeMarker, + upperType: KotlinTypeMarker, + shouldTryUseDifferentFlexibilityForUpperType: Boolean + ) { if (lowerType === upperType) return if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) { - runIsSubtypeOf(lowerType, upperType) + runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType) } } diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt new file mode 100644 index 00000000000..754b5196000 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +// Issue: KT-36254 + +// FILE: Convertor.java + +public interface Convertor { + Dst convert(Src o); +} + +// FILE: main.kt + +fun takeConvertor(c: Convertor) {} + +fun main() { + takeConvertor(Convertor { null }) +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.txt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.txt new file mode 100644 index 00000000000..fb13d3641dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.txt @@ -0,0 +1,11 @@ +package + +public fun main(): kotlin.Unit +public fun takeConvertor(/*0*/ c: Convertor): kotlin.Unit + +public interface Convertor { + public abstract fun convert(/*0*/ o: Src!): Dst! + 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/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt new file mode 100644 index 00000000000..fb3e0dcba7f --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt @@ -0,0 +1,20 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +// Issue: KT-36254 + +// FILE: Convertor.java + +public interface Convertor { + Out convert(Out o); +} + +// FILE: main.kt + +fun takeConvertor(c: Convertor) {} + +class Out {} + +fun main(o: Out) { + takeConvertor(Convertor { o }) +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.txt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.txt new file mode 100644 index 00000000000..10194d57d25 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.txt @@ -0,0 +1,18 @@ +package + +public fun main(/*0*/ o: Out): kotlin.Unit +public fun takeConvertor(/*0*/ c: Convertor): kotlin.Unit + +public interface Convertor { + public abstract fun convert(/*0*/ o: Out!): Out! + 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 Out { + public constructor Out() + 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/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index d36b4ae7374..a7c46fc948f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16483,6 +16483,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); } + @TestMetadata("flexibilityThroughTypeVariable.kt") + public void testFlexibilityThroughTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt"); + } + + @TestMetadata("flexibilityThroughTypeVariableOut.kt") + public void testFlexibilityThroughTypeVariableOut() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt"); + } + @TestMetadata("genericsAndArrays.kt") public void testGenericsAndArrays() throws Exception { runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 05aebd0e52e..7f25f19028a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -16478,6 +16478,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); } + @TestMetadata("flexibilityThroughTypeVariable.kt") + public void testFlexibilityThroughTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt"); + } + + @TestMetadata("flexibilityThroughTypeVariableOut.kt") + public void testFlexibilityThroughTypeVariableOut() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt"); + } + @TestMetadata("genericsAndArrays.kt") public void testGenericsAndArrays() throws Exception { runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt");