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 680ab4c470d..387c875b7b2 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 @@ -12370,6 +12370,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt"); } + @Test + @TestMetadata("approximateContravariantCapturedTypes.kt") + public void testApproximateContravariantCapturedTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt"); + } + @Test @TestMetadata("avoidCreatingUselessCapturedTypes.kt") public void testAvoidCreatingUselessCapturedTypes() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 554759a6af7..e27ac4b3977 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.calls import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.contracts.EffectSystem import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -248,7 +249,12 @@ class CallCompleter( val system = builder.build() setConstraintSystem(system) - setResultingSubstitutor(system.resultingSubstitutor) + val isNewInferenceEnabled = effectSystem.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) + val resultingSubstitutor = if (isNewInferenceEnabled) { + system.resultingSubstitutor.replaceWithContravariantApproximatingSubstitution() + } else system.resultingSubstitutor + + setResultingSubstitutor(resultingSubstitutor) } private fun MutableResolvedCall.updateResolutionStatusFromConstraintSystem( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 32198514bcb..24a35e347cd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -347,7 +347,13 @@ class GenericCandidateResolver( } val resultingSystem = constraintSystem.build() resolvedCall.setConstraintSystem(resultingSystem) - resolvedCall.setResultingSubstitutor(resultingSystem.resultingSubstitutor) + + val isNewInferenceEnabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference) + val resultingSubstitutor = if (isNewInferenceEnabled) { + resultingSystem.resultingSubstitutor.replaceWithContravariantApproximatingSubstitution() + } else resultingSystem.resultingSubstitutor + + resolvedCall.setResultingSubstitutor(resultingSubstitutor) } // See KT-5385 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 524b09462cb..66b667ca1ae 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -151,10 +151,6 @@ internal class ConstraintSystemImpl( ) } - private class SubstitutionWithCapturedTypeApproximation(substitution: TypeSubstitution) : DelegatedTypeSubstitution(substitution) { - override fun approximateCapturedTypes() = true - } - private fun satisfyInitialConstraints(): Boolean { val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) } fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT) diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.fir.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.fir.kt new file mode 100644 index 00000000000..f309d330487 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.fir.kt @@ -0,0 +1,60 @@ +class Foo(var x: T) { + fun setX1(y: T): T { + this.x = y + return y + } +} + +fun Foo.setX(y: T): T { + return y +} + +class Foo2(var x: T) { + fun setX1(y: T): T { + this.x = y + return y + } +} + +fun Foo2.setX(y: T): T { + this.x = y + return y +} + +fun Float.bar() {} + +fun test1() { + val fooSetRef = Foo<*>::setX + val foo = Foo(1f) + + fooSetRef.invoke(foo, 1) + + foo.x.bar() +} + +fun test2() { + val fooSetRef = , CapturedType(*), CapturedType(*)>")!>Foo<*>::setX1 + val foo = Foo(1f) + + fooSetRef.invoke(foo, 1) + + foo.x.bar() +} + +fun test3() { + val fooSetRef = Foo2<*>::setX + val foo = Foo2(1) + + fooSetRef.invoke(foo, "") + + foo.x.bar() +} + +fun test4() { + val fooSetRef = , CapturedType(*), CapturedType(*)>")!>Foo2<*>::setX1 + val foo = Foo2(1) + + fooSetRef.invoke(foo, "") + + foo.x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt new file mode 100644 index 00000000000..966203018bb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt @@ -0,0 +1,60 @@ +class Foo(var x: T) { + fun setX1(y: T): T { + this.x = y + return y + } +} + +fun Foo.setX(y: T): T { + return y +} + +class Foo2(var x: T) { + fun setX1(y: T): T { + this.x = y + return y + } +} + +fun Foo2.setX(y: T): T { + this.x = y + return y +} + +fun Float.bar() {} + +fun test1() { + val fooSetRef = , kotlin.Nothing, kotlin.Number>")!>Foo<*>::")!>setX + val foo = Foo(1f) + + fooSetRef.invoke(foo, 1) + + foo.x.bar() +} + +fun test2() { + val fooSetRef = , kotlin.Nothing, kotlin.Number>")!>Foo<*>::setX1 + val foo = Foo(1f) + + fooSetRef.invoke(foo, 1) + + foo.x.bar() +} + +fun test3() { + val fooSetRef = , kotlin.Nothing, kotlin.Any?>")!>Foo2<*>::")!>setX + val foo = Foo2(1) + + fooSetRef.invoke(foo, "") + + foo.x.bar() +} + +fun test4() { + val fooSetRef = , kotlin.Nothing, kotlin.Any?>")!>Foo2<*>::setX1 + val foo = Foo2(1) + + fooSetRef.invoke(foo, "") + + foo.x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.txt new file mode 100644 index 00000000000..b3b5d87f1ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.txt @@ -0,0 +1,27 @@ +package + +public fun test1(): kotlin.Unit +public fun test2(): kotlin.Unit +public fun test3(): kotlin.Unit +public fun test4(): kotlin.Unit +public fun kotlin.Float.bar(): kotlin.Unit +public fun Foo2.setX(/*0*/ y: T): T +public fun Foo.setX(/*0*/ y: T): T + +public final class Foo { + public constructor Foo(/*0*/ x: T) + public final var x: T + 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 final fun setX1(/*0*/ y: T): T + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Foo2 { + public constructor Foo2(/*0*/ x: T) + public final var x: T + 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 final fun setX1(/*0*/ y: T): T + 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 5dd7cce0ee2..3a7ba5e4092 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 @@ -12376,6 +12376,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt"); } + @Test + @TestMetadata("approximateContravariantCapturedTypes.kt") + public void testApproximateContravariantCapturedTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt"); + } + @Test @TestMetadata("avoidCreatingUselessCapturedTypes.kt") public void testAvoidCreatingUselessCapturedTypes() throws Exception { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt index cf9b1cc6ffd..835936ae961 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt @@ -85,6 +85,15 @@ abstract class TypeConstructorSubstitution : TypeSubstitution() { } } +class SubstitutionWithCapturedTypeApproximation(substitution: TypeSubstitution) : DelegatedTypeSubstitution(substitution) { + override fun approximateCapturedTypes() = true +} + +class SubstitutionWithContravariantCapturedTypeApproximation(substitution: TypeSubstitution) : DelegatedTypeSubstitution(substitution) { + override fun approximateCapturedTypes() = true + override fun approximateContravariantCapturedTypes() = true +} + class IndexedParametersSubstitution( val parameters: Array, val arguments: Array, diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index da175c6f513..78737803f4f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -67,6 +67,29 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { ); } + @NotNull + public TypeSubstitutor replaceWithContravariantApproximatingSubstitution() { + if (substitution instanceof SubstitutionWithCapturedTypeApproximation) { + return new TypeSubstitutor( + new SubstitutionWithContravariantCapturedTypeApproximation( + ((SubstitutionWithCapturedTypeApproximation) substitution).getSubstitution() + ) + ); + } + + if (substitution instanceof IndexedParametersSubstitution && !substitution.approximateContravariantCapturedTypes()) { + return new TypeSubstitutor( + new IndexedParametersSubstitution( + ((IndexedParametersSubstitution) substitution).getParameters(), + ((IndexedParametersSubstitution) substitution).getArguments(), + true + ) + ); + } + + return this; + } + @NotNull public static TypeSubstitutor createChainedSubstitutor(@NotNull TypeSubstitution first, @NotNull TypeSubstitution second) { return create(DisjointKeysUnionTypeSubstitution.create(first, second));