NI: take into account effective variance during adding constraints from LHS instead of only use site variance
^KT-39220 Fixed
This commit is contained in:
+5
@@ -10171,6 +10171,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt37853.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt39220.kt")
|
||||
public void testKt39220() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt39220.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt6175.kt");
|
||||
|
||||
+12
-8
@@ -22,10 +22,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.convertVariance
|
||||
import org.jetbrains.kotlin.types.model.TypeVariance
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -280,11 +279,16 @@ private fun ConstraintSystemBuilder.addConstraintFromLHS(
|
||||
val expectedTypeProjectionForLHS = expectedType.arguments.first()
|
||||
val expectedTypeForLHS = expectedTypeProjectionForLHS.type
|
||||
val constraintPosition = LHSArgumentConstraintPosition(argument, lhsResult.qualifier ?: lhsResult.unboundDetailedReceiver)
|
||||
val expectedTypeVariance = expectedTypeProjectionForLHS.projectionKind.convertVariance()
|
||||
val effectiveVariance = AbstractTypeChecker.effectiveVariance(
|
||||
expectedType.constructor.parameters.first().variance.convertVariance(),
|
||||
expectedTypeVariance
|
||||
) ?: expectedTypeVariance
|
||||
|
||||
when (expectedTypeProjectionForLHS.projectionKind) {
|
||||
Variance.INVARIANT -> addEqualityConstraint(lhsType, expectedTypeForLHS, constraintPosition)
|
||||
Variance.IN_VARIANCE -> addSubtypeConstraint(expectedTypeForLHS, lhsType, constraintPosition)
|
||||
Variance.OUT_VARIANCE -> addSubtypeConstraint(lhsType, expectedTypeForLHS, constraintPosition)
|
||||
when (effectiveVariance) {
|
||||
TypeVariance.INV -> addEqualityConstraint(lhsType, expectedTypeForLHS, constraintPosition)
|
||||
TypeVariance.IN -> addSubtypeConstraint(expectedTypeForLHS, lhsType, constraintPosition)
|
||||
TypeVariance.OUT -> addSubtypeConstraint(lhsType, expectedTypeForLHS, constraintPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -FINAL_UPPER_BOUND
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
interface Foo {
|
||||
fun resolve(var1: Int): String
|
||||
fun resolve(var1: String): String
|
||||
|
||||
suspend fun resolve2(var1: Int): String
|
||||
suspend fun resolve2(var1: String): String
|
||||
|
||||
val Int.x1 get() = ""
|
||||
val String.x1 get() = ""
|
||||
|
||||
var Int.x2
|
||||
get() = ""
|
||||
set(value) {}
|
||||
var String.x2
|
||||
get() = ""
|
||||
set(value) {}
|
||||
|
||||
val Int.x3 get() = ""
|
||||
var String.x3
|
||||
get() = ""
|
||||
set(value) {}
|
||||
|
||||
// CR on property with to receivers are forbidden
|
||||
fun <T: Foo> test() {
|
||||
// with LHS and property
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><T>(<!UNRESOLVED_REFERENCE!>Foo::x1<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><Foo>(<!UNRESOLVED_REFERENCE!>Foo::x1<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!>(<!UNRESOLVED_REFERENCE!>Foo::x1<!>)
|
||||
|
||||
// with LHS and mutable property
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><T>(<!UNRESOLVED_REFERENCE!>Foo::x2<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><Foo>(<!UNRESOLVED_REFERENCE!>Foo::x2<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!>(<!UNRESOLVED_REFERENCE!>Foo::x2<!>)
|
||||
|
||||
// with LHS and propery + mutable property (mixed)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><T>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!><Foo>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar8<!>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar9<!><T>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar9<!><Foo>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar9<!>(<!UNRESOLVED_REFERENCE!>Foo::x3<!>)
|
||||
}
|
||||
}
|
||||
|
||||
val Int.x1 get() = ""
|
||||
val String.x1 get() = ""
|
||||
|
||||
fun <K> bar1(f: KFunction2<K, String, String>) {}
|
||||
|
||||
fun <K> bar2(f: KFunction2<out K, String, String>) {}
|
||||
|
||||
fun <K> bar3(f: Any?) {}
|
||||
|
||||
fun <K> bar4(f: Function2<K, String, String>) {}
|
||||
|
||||
fun <K> bar5(f: suspend (K, String) -> String) {}
|
||||
|
||||
fun <K> bar6(f: KSuspendFunction2<K, String, String>) {}
|
||||
|
||||
fun <K> bar7(f: K.(String) -> String) {}
|
||||
|
||||
fun <K> bar8(f: KProperty2<K, Int, String>) {}
|
||||
|
||||
fun <K> bar9(f: KMutableProperty2<K, Int, String>) {}
|
||||
|
||||
fun <K> bar10(f: KProperty1<K, String>) {}
|
||||
|
||||
fun resolve(var2: Number, var1: Int) = ""
|
||||
fun resolve(var2: Number, var1: String) = ""
|
||||
|
||||
fun <T : Foo, R: Number, D: Int> main() {
|
||||
// with LHS
|
||||
bar1<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar1<Foo>(Foo::resolve) // OK
|
||||
bar1(Foo::resolve) // OK
|
||||
|
||||
// without LHS
|
||||
bar1<R>(::resolve) // OK
|
||||
bar1<Number>(::resolve) // OK
|
||||
bar1(::resolve) // OK
|
||||
|
||||
// with LHS and conflicting projection
|
||||
bar2<T>(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
bar2<Foo>(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
bar2(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
|
||||
// with LHS and Any? expected type
|
||||
bar3<T>(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
bar3<Foo>(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
bar3(<!UNRESOLVED_REFERENCE!>Foo::resolve<!>)
|
||||
|
||||
// with LHS and `Function` expected type
|
||||
bar4<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar4<Foo>(Foo::resolve) // OK
|
||||
bar4(Foo::resolve) // OK
|
||||
|
||||
// with LHS and `SuspendFunction` expected type
|
||||
bar5<T>(Foo::resolve2) // ERROR before the fix in NI
|
||||
bar5<Foo>(Foo::resolve2) // OK
|
||||
bar5(Foo::resolve2) // OK
|
||||
|
||||
// with LHS and `KSuspendFunction` expected type
|
||||
bar6<T>(Foo::resolve2) // ERROR before the fix in NI
|
||||
bar6<Foo>(Foo::resolve2) // OK
|
||||
bar6(Foo::resolve2) // OK
|
||||
|
||||
// with LHS and sentension function expected type
|
||||
bar7<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar7<Foo>(Foo::resolve) // OK
|
||||
bar7(Foo::resolve) // OK
|
||||
|
||||
// with LHS and sentension function expected type
|
||||
<!INAPPLICABLE_CANDIDATE!>bar10<!><D>(Int::x1) // ERROR before the fix in NI
|
||||
bar10<Int>(Int::x1) // OK
|
||||
bar10(Int::x1) // OK
|
||||
|
||||
fun Int.ext() {
|
||||
// with LHS and sentension function expected type
|
||||
<!INAPPLICABLE_CANDIDATE!>bar10<!><D>(::x1) // ERROR before the fix in NI
|
||||
<!INAPPLICABLE_CANDIDATE!>bar10<!><Int>(::x1) // OK
|
||||
<!INAPPLICABLE_CANDIDATE!>bar10<!>(::x1) // OK
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -FINAL_UPPER_BOUND
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
interface Foo {
|
||||
fun resolve(var1: Int): String
|
||||
fun resolve(var1: String): String
|
||||
|
||||
suspend fun resolve2(var1: Int): String
|
||||
suspend fun resolve2(var1: String): String
|
||||
|
||||
val Int.x1 get() = ""
|
||||
val String.x1 get() = ""
|
||||
|
||||
var Int.x2
|
||||
get() = ""
|
||||
set(value) {}
|
||||
var String.x2
|
||||
get() = ""
|
||||
set(value) {}
|
||||
|
||||
val Int.x3 get() = ""
|
||||
var String.x3
|
||||
get() = ""
|
||||
set(value) {}
|
||||
|
||||
// CR on property with to receivers are forbidden
|
||||
fun <T: Foo> test() {
|
||||
// with LHS and property
|
||||
bar8<T>(<!TYPE_MISMATCH, TYPE_MISMATCH!>Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!><!>)
|
||||
bar8<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!>)
|
||||
bar8(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!>)
|
||||
|
||||
// with LHS and mutable property
|
||||
bar8<T>(<!TYPE_MISMATCH, TYPE_MISMATCH!>Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x2<!><!>)
|
||||
bar8<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x2<!>)
|
||||
bar8(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x2<!>)
|
||||
|
||||
// with LHS and propery + mutable property (mixed)
|
||||
bar8<T>(<!TYPE_MISMATCH, TYPE_MISMATCH!>Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!><!>)
|
||||
bar8<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!>)
|
||||
bar8(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!>)
|
||||
bar9<T>(<!TYPE_MISMATCH, TYPE_MISMATCH!>Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!><!>)
|
||||
bar9<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!>)
|
||||
bar9(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x3<!>)
|
||||
}
|
||||
}
|
||||
|
||||
val Int.x1 get() = ""
|
||||
val String.x1 get() = ""
|
||||
|
||||
fun <K> bar1(f: KFunction2<K, String, String>) {}
|
||||
|
||||
fun <K> bar2(f: KFunction2<<!CONFLICTING_PROJECTION!>out<!> K, String, String>) {}
|
||||
|
||||
fun <K> bar3(f: Any?) {}
|
||||
|
||||
fun <K> bar4(f: Function2<K, String, String>) {}
|
||||
|
||||
fun <K> bar5(f: suspend (K, String) -> String) {}
|
||||
|
||||
fun <K> bar6(f: KSuspendFunction2<K, String, String>) {}
|
||||
|
||||
fun <K> bar7(f: K.(String) -> String) {}
|
||||
|
||||
fun <K> bar8(f: KProperty2<K, Int, String>) {}
|
||||
|
||||
fun <K> bar9(f: KMutableProperty2<K, Int, String>) {}
|
||||
|
||||
fun <K> bar10(f: KProperty1<K, String>) {}
|
||||
|
||||
fun resolve(var2: Number, var1: Int) = ""
|
||||
fun resolve(var2: Number, var1: String) = ""
|
||||
|
||||
fun <T : Foo, R: Number, D: Int> main() {
|
||||
// with LHS
|
||||
bar1<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar1<Foo>(Foo::resolve) // OK
|
||||
bar1(Foo::resolve) // OK
|
||||
|
||||
// without LHS
|
||||
bar1<R>(::resolve) // OK
|
||||
bar1<Number>(::resolve) // OK
|
||||
bar1(::resolve) // OK
|
||||
|
||||
// with LHS and conflicting projection
|
||||
bar2<T>(<!TYPE_MISMATCH!>Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!><!>)
|
||||
bar2<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!>)
|
||||
bar2(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!>)
|
||||
|
||||
// with LHS and Any? expected type
|
||||
bar3<T>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!>)
|
||||
bar3<Foo>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!>)
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar3<!>(Foo::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>resolve<!>)
|
||||
|
||||
// with LHS and `Function` expected type
|
||||
bar4<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar4<Foo>(Foo::resolve) // OK
|
||||
bar4(Foo::resolve) // OK
|
||||
|
||||
// with LHS and `SuspendFunction` expected type
|
||||
bar5<T>(Foo::resolve2) // ERROR before the fix in NI
|
||||
bar5<Foo>(Foo::resolve2) // OK
|
||||
bar5(Foo::resolve2) // OK
|
||||
|
||||
// with LHS and `KSuspendFunction` expected type
|
||||
bar6<T>(Foo::resolve2) // ERROR before the fix in NI
|
||||
bar6<Foo>(Foo::resolve2) // OK
|
||||
bar6(Foo::resolve2) // OK
|
||||
|
||||
// with LHS and sentension function expected type
|
||||
bar7<T>(Foo::resolve) // ERROR before the fix in NI
|
||||
bar7<Foo>(Foo::resolve) // OK
|
||||
bar7(Foo::resolve) // OK
|
||||
|
||||
// with LHS and sentension function expected type
|
||||
bar10<D>(<!TYPE_MISMATCH, TYPE_MISMATCH!>Int::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!><!>) // ERROR before the fix in NI
|
||||
bar10<Int>(Int::x1) // OK
|
||||
bar10(Int::x1) // OK
|
||||
|
||||
fun Int.ext() {
|
||||
// with LHS and sentension function expected type
|
||||
bar10<D>(::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!>) // ERROR before the fix in NI
|
||||
bar10<Int>(::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!>) // OK
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar10<!>(::<!CALLABLE_REFERENCE_RESOLUTION_AMBIGUITY!>x1<!>) // OK
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package
|
||||
|
||||
public val kotlin.Int.x1: kotlin.String
|
||||
public val kotlin.String.x1: kotlin.String
|
||||
public fun </*0*/ K> bar1(/*0*/ f: kotlin.reflect.KFunction2<K, kotlin.String, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ K> bar10(/*0*/ f: kotlin.reflect.KProperty1<K, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ K> bar2(/*0*/ f: kotlin.reflect.KFunction2<out K, kotlin.String, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ K> bar3(/*0*/ f: kotlin.Any?): kotlin.Unit
|
||||
public fun </*0*/ K> bar4(/*0*/ f: (K, kotlin.String) -> kotlin.String): kotlin.Unit
|
||||
public fun </*0*/ K> bar5(/*0*/ f: suspend (K, kotlin.String) -> kotlin.String): kotlin.Unit
|
||||
public fun </*0*/ K> bar6(/*0*/ f: kotlin.reflect.KSuspendFunction2<K, kotlin.String, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ K> bar7(/*0*/ f: K.(kotlin.String) -> kotlin.String): kotlin.Unit
|
||||
public fun </*0*/ K> bar8(/*0*/ f: kotlin.reflect.KProperty2<K, kotlin.Int, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ K> bar9(/*0*/ f: kotlin.reflect.KMutableProperty2<K, kotlin.Int, kotlin.String>): kotlin.Unit
|
||||
public fun </*0*/ T : Foo, /*1*/ R : kotlin.Number, /*2*/ D : kotlin.Int> main(): kotlin.Unit
|
||||
public fun resolve(/*0*/ var2: kotlin.Number, /*1*/ var1: kotlin.Int): kotlin.String
|
||||
public fun resolve(/*0*/ var2: kotlin.Number, /*1*/ var1: kotlin.String): kotlin.String
|
||||
|
||||
public interface Foo {
|
||||
public open val kotlin.Int.x1: kotlin.String
|
||||
public open val kotlin.String.x1: kotlin.String
|
||||
public open var kotlin.Int.x2: kotlin.String
|
||||
public open var kotlin.String.x2: kotlin.String
|
||||
public open val kotlin.Int.x3: kotlin.String
|
||||
public open var kotlin.String.x3: 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 abstract fun resolve(/*0*/ var1: kotlin.Int): kotlin.String
|
||||
public abstract fun resolve(/*0*/ var1: kotlin.String): kotlin.String
|
||||
public abstract suspend fun resolve2(/*0*/ var1: kotlin.Int): kotlin.String
|
||||
public abstract suspend fun resolve2(/*0*/ var1: kotlin.String): kotlin.String
|
||||
public open fun </*0*/ T : Foo> test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -10178,6 +10178,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt37853.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt39220.kt")
|
||||
public void testKt39220() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt39220.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt6175.kt");
|
||||
|
||||
Generated
+5
@@ -10173,6 +10173,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt37853.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt39220.kt")
|
||||
public void testKt39220() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt39220.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt6175.kt");
|
||||
|
||||
Reference in New Issue
Block a user