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:
Victor Petukhov
2020-06-01 13:13:03 +03:00
parent 561c6747a6
commit 8d05253369
7 changed files with 315 additions and 8 deletions
@@ -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");
@@ -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
}
}
+127
View File
@@ -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");
@@ -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");