Approximate captured types in contravariant positions properly
^KT-43802 Fixed
This commit is contained in:
+6
@@ -12370,6 +12370,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt");
|
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
|
@Test
|
||||||
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
||||||
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.calls
|
|||||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||||
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.contracts.EffectSystem
|
import org.jetbrains.kotlin.contracts.EffectSystem
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
@@ -248,7 +249,12 @@ class CallCompleter(
|
|||||||
val system = builder.build()
|
val system = builder.build()
|
||||||
setConstraintSystem(system)
|
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 <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
||||||
|
|||||||
+7
-1
@@ -347,7 +347,13 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
val resultingSystem = constraintSystem.build()
|
val resultingSystem = constraintSystem.build()
|
||||||
resolvedCall.setConstraintSystem(resultingSystem)
|
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
|
// See KT-5385
|
||||||
|
|||||||
-4
@@ -151,10 +151,6 @@ internal class ConstraintSystemImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SubstitutionWithCapturedTypeApproximation(substitution: TypeSubstitution) : DelegatedTypeSubstitution(substitution) {
|
|
||||||
override fun approximateCapturedTypes() = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun satisfyInitialConstraints(): Boolean {
|
private fun satisfyInitialConstraints(): Boolean {
|
||||||
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
|
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
|
||||||
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
|
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
|
||||||
|
|||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
class Foo<T : Number>(var x: T) {
|
||||||
|
fun setX1(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Number> Foo<T>.setX(y: T): T {
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo2<T>(var x: T) {
|
||||||
|
fun setX1(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Foo2<T>.setX(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Float.bar() {}
|
||||||
|
|
||||||
|
fun test1() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("Type is unknown"), UNRESOLVED_REFERENCE!>Foo<*>::setX<!>
|
||||||
|
val foo = Foo<Float>(1f)
|
||||||
|
|
||||||
|
fooSetRef.<!UNRESOLVED_REFERENCE!>invoke<!>(foo, 1)
|
||||||
|
|
||||||
|
foo.x.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo<*>, CapturedType(*), CapturedType(*)>")!>Foo<*>::setX1<!>
|
||||||
|
val foo = Foo<Float>(1f)
|
||||||
|
|
||||||
|
fooSetRef.<!INAPPLICABLE_CANDIDATE!>invoke<!>(foo, 1)
|
||||||
|
|
||||||
|
foo.x.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("Type is unknown"), UNRESOLVED_REFERENCE!>Foo2<*>::setX<!>
|
||||||
|
val foo = Foo2<Int>(1)
|
||||||
|
|
||||||
|
fooSetRef.<!UNRESOLVED_REFERENCE!>invoke<!>(foo, "")
|
||||||
|
|
||||||
|
foo.x.<!INAPPLICABLE_CANDIDATE!>bar<!>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo2<*>, CapturedType(*), CapturedType(*)>")!>Foo2<*>::setX1<!>
|
||||||
|
val foo = Foo2<Int>(1)
|
||||||
|
|
||||||
|
fooSetRef.<!INAPPLICABLE_CANDIDATE!>invoke<!>(foo, "")
|
||||||
|
|
||||||
|
foo.x.<!INAPPLICABLE_CANDIDATE!>bar<!>()
|
||||||
|
}
|
||||||
compiler/testData/diagnostics/tests/inference/capturedTypes/approximateContravariantCapturedTypes.kt
Vendored
+60
@@ -0,0 +1,60 @@
|
|||||||
|
class Foo<T : Number>(var x: T) {
|
||||||
|
fun setX1(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Number> Foo<T>.setX(y: T): T {
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo2<T>(var x: T) {
|
||||||
|
fun setX1(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Foo2<T>.setX(y: T): T {
|
||||||
|
this.x = y
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Float.bar() {}
|
||||||
|
|
||||||
|
fun test1() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo<*>, kotlin.Nothing, kotlin.Number>")!>Foo<*>::<!TYPE_MISMATCH("Nothing; Foo<*>")!>setX<!><!>
|
||||||
|
val foo = Foo<Float>(1f)
|
||||||
|
|
||||||
|
fooSetRef.invoke(foo, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
|
||||||
|
|
||||||
|
foo.x.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo<*>, kotlin.Nothing, kotlin.Number>")!>Foo<*>::setX1<!>
|
||||||
|
val foo = Foo<Float>(1f)
|
||||||
|
|
||||||
|
fooSetRef.invoke(foo, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
|
||||||
|
|
||||||
|
foo.x.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo2<*>, kotlin.Nothing, kotlin.Any?>")!>Foo2<*>::<!TYPE_MISMATCH("Nothing; Foo2<*>")!>setX<!><!>
|
||||||
|
val foo = Foo2<Int>(1)
|
||||||
|
|
||||||
|
fooSetRef.invoke(foo, <!TYPE_MISMATCH!>""<!>)
|
||||||
|
|
||||||
|
foo.x.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>bar<!>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() {
|
||||||
|
val fooSetRef = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<Foo2<*>, kotlin.Nothing, kotlin.Any?>")!>Foo2<*>::setX1<!>
|
||||||
|
val foo = Foo2<Int>(1)
|
||||||
|
|
||||||
|
fooSetRef.invoke(foo, <!TYPE_MISMATCH!>""<!>)
|
||||||
|
|
||||||
|
foo.x.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>bar<!>()
|
||||||
|
}
|
||||||
+27
@@ -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 </*0*/ T> Foo2<T>.setX(/*0*/ y: T): T
|
||||||
|
public fun </*0*/ T : kotlin.Number> Foo<T>.setX(/*0*/ y: T): T
|
||||||
|
|
||||||
|
public final class Foo</*0*/ T : kotlin.Number> {
|
||||||
|
public constructor Foo</*0*/ T : kotlin.Number>(/*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</*0*/ T> {
|
||||||
|
public constructor Foo2</*0*/ T>(/*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
|
||||||
|
}
|
||||||
Generated
+6
@@ -12376,6 +12376,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt");
|
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
|
@Test
|
||||||
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
||||||
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
||||||
|
|||||||
@@ -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(
|
class IndexedParametersSubstitution(
|
||||||
val parameters: Array<TypeParameterDescriptor>,
|
val parameters: Array<TypeParameterDescriptor>,
|
||||||
val arguments: Array<TypeProjection>,
|
val arguments: Array<TypeProjection>,
|
||||||
|
|||||||
@@ -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
|
@NotNull
|
||||||
public static TypeSubstitutor createChainedSubstitutor(@NotNull TypeSubstitution first, @NotNull TypeSubstitution second) {
|
public static TypeSubstitutor createChainedSubstitutor(@NotNull TypeSubstitution first, @NotNull TypeSubstitution second) {
|
||||||
return create(DisjointKeysUnionTypeSubstitution.create(first, second));
|
return create(DisjointKeysUnionTypeSubstitution.create(first, second));
|
||||||
|
|||||||
Reference in New Issue
Block a user