From 8d05253369a8dfeb00c8b85a7baf86e1f1baf7f2 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Mon, 1 Jun 2020 13:13:03 +0300 Subject: [PATCH] NI: take into account effective variance during adding constraints from LHS instead of only use site variance ^KT-39220 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 + .../components/PostponeArgumentsChecks.kt | 20 +-- .../tests/inference/kt39220.fir.kt | 127 ++++++++++++++++++ .../diagnostics/tests/inference/kt39220.kt | 127 ++++++++++++++++++ .../diagnostics/tests/inference/kt39220.txt | 34 +++++ .../checkers/DiagnosticsTestGenerated.java | 5 + .../DiagnosticsUsingJavacTestGenerated.java | 5 + 7 files changed, 315 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/kt39220.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/kt39220.kt create mode 100644 compiler/testData/diagnostics/tests/inference/kt39220.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 8bd899a7965..c75a6f83a5a 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index 85f5e8326b3..9a9a0718ae6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.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) } } diff --git a/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt b/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt new file mode 100644 index 00000000000..c54578acf32 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt @@ -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 test() { + // with LHS and property + bar8(Foo::x1) + bar8(Foo::x1) + bar8(Foo::x1) + + // with LHS and mutable property + bar8(Foo::x2) + bar8(Foo::x2) + bar8(Foo::x2) + + // with LHS and propery + mutable property (mixed) + bar8(Foo::x3) + bar8(Foo::x3) + bar8(Foo::x3) + bar9(Foo::x3) + bar9(Foo::x3) + bar9(Foo::x3) + } +} + +val Int.x1 get() = "" +val String.x1 get() = "" + +fun bar1(f: KFunction2) {} + +fun bar2(f: KFunction2) {} + +fun bar3(f: Any?) {} + +fun bar4(f: Function2) {} + +fun bar5(f: suspend (K, String) -> String) {} + +fun bar6(f: KSuspendFunction2) {} + +fun bar7(f: K.(String) -> String) {} + +fun bar8(f: KProperty2) {} + +fun bar9(f: KMutableProperty2) {} + +fun bar10(f: KProperty1) {} + +fun resolve(var2: Number, var1: Int) = "" +fun resolve(var2: Number, var1: String) = "" + +fun main() { + // with LHS + bar1(Foo::resolve) // ERROR before the fix in NI + bar1(Foo::resolve) // OK + bar1(Foo::resolve) // OK + + // without LHS + bar1(::resolve) // OK + bar1(::resolve) // OK + bar1(::resolve) // OK + + // with LHS and conflicting projection + bar2(Foo::resolve) + bar2(Foo::resolve) + bar2(Foo::resolve) + + // with LHS and Any? expected type + bar3(Foo::resolve) + bar3(Foo::resolve) + bar3(Foo::resolve) + + // with LHS and `Function` expected type + bar4(Foo::resolve) // ERROR before the fix in NI + bar4(Foo::resolve) // OK + bar4(Foo::resolve) // OK + + // with LHS and `SuspendFunction` expected type + bar5(Foo::resolve2) // ERROR before the fix in NI + bar5(Foo::resolve2) // OK + bar5(Foo::resolve2) // OK + + // with LHS and `KSuspendFunction` expected type + bar6(Foo::resolve2) // ERROR before the fix in NI + bar6(Foo::resolve2) // OK + bar6(Foo::resolve2) // OK + + // with LHS and sentension function expected type + bar7(Foo::resolve) // ERROR before the fix in NI + bar7(Foo::resolve) // OK + bar7(Foo::resolve) // OK + + // with LHS and sentension function expected type + bar10(Int::x1) // ERROR before the fix in NI + bar10(Int::x1) // OK + bar10(Int::x1) // OK + + fun Int.ext() { + // with LHS and sentension function expected type + bar10(::x1) // ERROR before the fix in NI + bar10(::x1) // OK + bar10(::x1) // OK + } +} diff --git a/compiler/testData/diagnostics/tests/inference/kt39220.kt b/compiler/testData/diagnostics/tests/inference/kt39220.kt new file mode 100644 index 00000000000..e1616522aa3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt39220.kt @@ -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 test() { + // with LHS and property + bar8(Foo::x1) + bar8(Foo::x1) + bar8(Foo::x1) + + // with LHS and mutable property + bar8(Foo::x2) + bar8(Foo::x2) + bar8(Foo::x2) + + // with LHS and propery + mutable property (mixed) + bar8(Foo::x3) + bar8(Foo::x3) + bar8(Foo::x3) + bar9(Foo::x3) + bar9(Foo::x3) + bar9(Foo::x3) + } +} + +val Int.x1 get() = "" +val String.x1 get() = "" + +fun bar1(f: KFunction2) {} + +fun bar2(f: KFunction2<out K, String, String>) {} + +fun bar3(f: Any?) {} + +fun bar4(f: Function2) {} + +fun bar5(f: suspend (K, String) -> String) {} + +fun bar6(f: KSuspendFunction2) {} + +fun bar7(f: K.(String) -> String) {} + +fun bar8(f: KProperty2) {} + +fun bar9(f: KMutableProperty2) {} + +fun bar10(f: KProperty1) {} + +fun resolve(var2: Number, var1: Int) = "" +fun resolve(var2: Number, var1: String) = "" + +fun main() { + // with LHS + bar1(Foo::resolve) // ERROR before the fix in NI + bar1(Foo::resolve) // OK + bar1(Foo::resolve) // OK + + // without LHS + bar1(::resolve) // OK + bar1(::resolve) // OK + bar1(::resolve) // OK + + // with LHS and conflicting projection + bar2(Foo::resolve) + bar2(Foo::resolve) + bar2(Foo::resolve) + + // with LHS and Any? expected type + bar3(Foo::resolve) + bar3(Foo::resolve) + bar3(Foo::resolve) + + // with LHS and `Function` expected type + bar4(Foo::resolve) // ERROR before the fix in NI + bar4(Foo::resolve) // OK + bar4(Foo::resolve) // OK + + // with LHS and `SuspendFunction` expected type + bar5(Foo::resolve2) // ERROR before the fix in NI + bar5(Foo::resolve2) // OK + bar5(Foo::resolve2) // OK + + // with LHS and `KSuspendFunction` expected type + bar6(Foo::resolve2) // ERROR before the fix in NI + bar6(Foo::resolve2) // OK + bar6(Foo::resolve2) // OK + + // with LHS and sentension function expected type + bar7(Foo::resolve) // ERROR before the fix in NI + bar7(Foo::resolve) // OK + bar7(Foo::resolve) // OK + + // with LHS and sentension function expected type + bar10(Int::x1) // ERROR before the fix in NI + bar10(Int::x1) // OK + bar10(Int::x1) // OK + + fun Int.ext() { + // with LHS and sentension function expected type + bar10(::x1) // ERROR before the fix in NI + bar10(::x1) // OK + bar10(::x1) // OK + } +} diff --git a/compiler/testData/diagnostics/tests/inference/kt39220.txt b/compiler/testData/diagnostics/tests/inference/kt39220.txt new file mode 100644 index 00000000000..a176e65d203 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt39220.txt @@ -0,0 +1,34 @@ +package + +public val kotlin.Int.x1: kotlin.String +public val kotlin.String.x1: kotlin.String +public fun bar1(/*0*/ f: kotlin.reflect.KFunction2): kotlin.Unit +public fun bar10(/*0*/ f: kotlin.reflect.KProperty1): kotlin.Unit +public fun bar2(/*0*/ f: kotlin.reflect.KFunction2): kotlin.Unit +public fun bar3(/*0*/ f: kotlin.Any?): kotlin.Unit +public fun bar4(/*0*/ f: (K, kotlin.String) -> kotlin.String): kotlin.Unit +public fun bar5(/*0*/ f: suspend (K, kotlin.String) -> kotlin.String): kotlin.Unit +public fun bar6(/*0*/ f: kotlin.reflect.KSuspendFunction2): kotlin.Unit +public fun bar7(/*0*/ f: K.(kotlin.String) -> kotlin.String): kotlin.Unit +public fun bar8(/*0*/ f: kotlin.reflect.KProperty2): kotlin.Unit +public fun bar9(/*0*/ f: kotlin.reflect.KMutableProperty2): kotlin.Unit +public fun 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 test(): kotlin.Unit + 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 be196460113..ce03af3b83a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 03cf192925e..6520f9b6703 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -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");