From 384bd858e9f641e6ba1f822ce063691e826e8d15 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Thu, 19 Dec 2019 13:56:53 +0300 Subject: [PATCH] [NI] Support fixation to subtype in completion mode calculator Allow full compltion mode for return type depending on type parameters in contravariant position only if they have proper equality constraint. --- ...irOldFrontendDiagnosticsTestGenerated.java | 10 +++++ .../components/CompletionModeCalculator.kt | 23 ++++++----- .../tests/inference/completion/basic.fir.kt | 1 - .../equalityConstraintUpstairs.fir.kt | 17 ++++++++ .../completion/equalityConstraintUpstairs.kt | 17 ++++++++ .../completion/equalityConstraintUpstairs.txt | 40 +++++++++++++++++++ .../completion/transitiveConstraint.fir.kt | 15 +++++++ .../completion/transitiveConstraint.kt | 15 +++++++ .../completion/transitiveConstraint.txt | 31 ++++++++++++++ .../tests/inference/dependantOnVariance.kt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 10 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 10 +++++ 12 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt create mode 100644 compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.txt create mode 100644 compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt create mode 100644 compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.txt diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index c99eb06e260..fc88b841d55 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10379,6 +10379,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); } + @TestMetadata("equalityConstraintUpstairs.kt") + public void testEqualityConstraintUpstairs() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt"); + } + @TestMetadata("kt33166.kt") public void testKt33166() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); @@ -10389,6 +10394,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); } + @TestMetadata("transitiveConstraint.kt") + public void testTransitiveConstraint() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt"); + } + @TestMetadata("withExact.kt") public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt index ba3831f2486..373901a400b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import java.util.* typealias CsCompleterContext = KotlinConstraintSystemCompleter.Context @@ -45,10 +46,11 @@ class CompletionModeCalculator { private val csCompleterContext: CsCompleterContext ) { private enum class FixationDirection { - TO_SUBTYPE, TO_SUPERTYPE, EQUALITY + TO_SUBTYPE, EQUALITY } - private val fixationDirectionsForVariables = mutableMapOf() + private val fixationDirectionsForVariables: MutableMap = + newLinkedHashMapWithExpectedSize(csCompleterContext.notFixedTypeVariables.size) private val variablesWithQueuedConstraints = mutableSetOf() private val typesToProcess: Queue = ArrayDeque() @@ -68,14 +70,14 @@ class CompletionModeCalculator { while (typesToProcess.isNotEmpty()) { val type = typesToProcess.poll() ?: break - fixationRequirementForTopLevel(type)?.let { directionForVariable -> + fixationDirectionForTopLevel(type)?.let { directionForVariable -> updateDirection(directionForVariable) enqueueTypesFromConstraints(directionForVariable.variable) } // find all variables in type and make requirements for them - type.contains { fromReturnType -> - for (directionForVariable in directionsForVariablesInTypeArguments(fromReturnType)) { + type.contains { typePart -> + for (directionForVariable in directionsForVariablesInTypeArguments(typePart)) { updateDirection(directionForVariable) enqueueTypesFromConstraints(directionForVariable.variable) } @@ -106,16 +108,16 @@ class CompletionModeCalculator { private fun updateDirection(directionForVariable: FixationDirectionForVariable) { val (variable, newDirection) = directionForVariable fixationDirectionsForVariables[variable]?.let { oldDirection -> - // To sub and to super are merged into equality, old equality stays if (oldDirection != FixationDirection.EQUALITY && oldDirection != newDirection) fixationDirectionsForVariables[variable] = FixationDirection.EQUALITY + } ?: run { + fixationDirectionsForVariables[variable] = newDirection } - fixationDirectionsForVariables[variable] = newDirection } private data class FixationDirectionForVariable(val variable: VariableWithConstraints, val direction: FixationDirection) - private fun CsCompleterContext.fixationRequirementForTopLevel(type: KotlinTypeMarker): FixationDirectionForVariable? { + private fun CsCompleterContext.fixationDirectionForTopLevel(type: KotlinTypeMarker): FixationDirectionForVariable? { return notFixedTypeVariables[type.typeConstructor()]?.let { FixationDirectionForVariable(it, FixationDirection.TO_SUBTYPE) } @@ -138,10 +140,10 @@ class CompletionModeCalculator { val parameter = type.typeConstructor().getParameter(position) val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance()) - ?: TypeVariance.OUT // Discuss + ?: TypeVariance.INV val direction = when (effectiveVariance) { - TypeVariance.IN -> FixationDirection.TO_SUPERTYPE + TypeVariance.IN -> FixationDirection.EQUALITY // Assuming that variables in contravariant positions are fixed to subtype TypeVariance.OUT -> FixationDirection.TO_SUBTYPE TypeVariance.INV -> FixationDirection.EQUALITY } @@ -169,7 +171,6 @@ class CompletionModeCalculator { private fun Constraint.hasRequiredKind(direction: FixationDirection) = when (direction) { FixationDirection.TO_SUBTYPE -> kind.isLower() || kind.isEqual() - FixationDirection.TO_SUPERTYPE -> kind.isUpper() || kind.isEqual() FixationDirection.EQUALITY -> kind.isEqual() } } diff --git a/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt index 84291207f65..9a6e6faf539 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt @@ -57,7 +57,6 @@ fun test7(cls: Cls) { } fun test8(cls: Cls) { - // TODO id( wrapIn(cls) ) diff --git a/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.fir.kt new file mode 100644 index 00000000000..38eb20aa215 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.fir.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class In(arg: I) +class Out(val prop: O) +class Inv(val prop: T) + +interface Upper +class Lower : Upper + +fun id(arg: K): K = arg + +fun test(lower: Lower) { + id>(Inv(lower)) + id>(In(lower)) + id>(Out(lower)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt new file mode 100644 index 00000000000..38eb20aa215 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class In(arg: I) +class Out(val prop: O) +class Inv(val prop: T) + +interface Upper +class Lower : Upper + +fun id(arg: K): K = arg + +fun test(lower: Lower) { + id>(Inv(lower)) + id>(In(lower)) + id>(Out(lower)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.txt b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.txt new file mode 100644 index 00000000000..8aca1e1147d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.txt @@ -0,0 +1,40 @@ +package + +public fun id(/*0*/ arg: K): K +public fun test(/*0*/ lower: Lower): kotlin.Unit + +public final class In { + public constructor In(/*0*/ arg: I) + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ prop: T) + public final val prop: 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Lower : Upper { + public constructor Lower() + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out(/*0*/ prop: O) + public final val prop: O + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Upper { + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.fir.kt new file mode 100644 index 00000000000..d9f159a0129 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.fir.kt @@ -0,0 +1,15 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE + +interface Bound +interface Upper : Bound +class Lower : Upper + +class Inv + +fun makeInv(v: U): Inv = TODO() +fun id(arg: K): K = arg + +fun test(lower: Lower) { + id>(makeInv(lower)) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt new file mode 100644 index 00000000000..d9f159a0129 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt @@ -0,0 +1,15 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE + +interface Bound +interface Upper : Bound +class Lower : Upper + +class Inv + +fun makeInv(v: U): Inv = TODO() +fun id(arg: K): K = arg + +fun test(lower: Lower) { + id>(makeInv(lower)) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.txt b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.txt new file mode 100644 index 00000000000..5fc8f50689c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.txt @@ -0,0 +1,31 @@ +package + +public fun id(/*0*/ arg: K): K +public fun makeInv(/*0*/ v: U): Inv +public fun test(/*0*/ lower: Lower): kotlin.Unit + +public interface Bound { + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv() + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Lower : Upper { + public constructor Lower() + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Upper : Bound { + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt b/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt index 6ac4cc9409d..5a413f7a3fa 100644 --- a/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt +++ b/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt @@ -45,7 +45,7 @@ fun test1(int: Int, any: Any) { readFromMyList(getMyList(any), int) readFromMyList(getMyList(any), int) - readFromMyList(getMyListToReadFrom(any), int) + readFromMyList(getMyListToReadFrom(any), int) readFromMyList(getMyListToReadFrom(any), int) readFromMyList(getMyListToReadFrom(int), any) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 005d0d545cc..d2021d36288 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10386,6 +10386,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); } + @TestMetadata("equalityConstraintUpstairs.kt") + public void testEqualityConstraintUpstairs() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt"); + } + @TestMetadata("kt33166.kt") public void testKt33166() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); @@ -10396,6 +10401,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); } + @TestMetadata("transitiveConstraint.kt") + public void testTransitiveConstraint() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt"); + } + @TestMetadata("withExact.kt") public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index ecabe26b1f5..75b49667932 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10381,6 +10381,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); } + @TestMetadata("equalityConstraintUpstairs.kt") + public void testEqualityConstraintUpstairs() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/equalityConstraintUpstairs.kt"); + } + @TestMetadata("kt33166.kt") public void testKt33166() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); @@ -10391,6 +10396,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); } + @TestMetadata("transitiveConstraint.kt") + public void testTransitiveConstraint() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/transitiveConstraint.kt"); + } + @TestMetadata("withExact.kt") public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt");