[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.
This commit is contained in:
Generated
+10
@@ -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");
|
||||
|
||||
+12
-11
@@ -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<VariableWithConstraints, FixationDirection>()
|
||||
private val fixationDirectionsForVariables: MutableMap<VariableWithConstraints, FixationDirection> =
|
||||
newLinkedHashMapWithExpectedSize(csCompleterContext.notFixedTypeVariables.size)
|
||||
private val variablesWithQueuedConstraints = mutableSetOf<TypeVariableMarker>()
|
||||
private val typesToProcess: Queue<KotlinTypeMarker> = 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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ fun test7(cls: Cls) {
|
||||
}
|
||||
|
||||
fun test8(cls: Cls) {
|
||||
// TODO
|
||||
id(
|
||||
wrapIn(cls)
|
||||
)
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class In<in I>(arg: I)
|
||||
class Out<out O>(val prop: O)
|
||||
class Inv<T>(val prop: T)
|
||||
|
||||
interface Upper
|
||||
class Lower : Upper
|
||||
|
||||
fun <K> id(arg: K): K = arg
|
||||
|
||||
fun test(lower: Lower) {
|
||||
id<Inv<Upper>>(Inv(lower))
|
||||
id<In<Upper>>(In(lower))
|
||||
id<Out<Upper>>(Out(lower))
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class In<in I>(arg: I)
|
||||
class Out<out O>(val prop: O)
|
||||
class Inv<T>(val prop: T)
|
||||
|
||||
interface Upper
|
||||
class Lower : Upper
|
||||
|
||||
fun <K> id(arg: K): K = arg
|
||||
|
||||
fun test(lower: Lower) {
|
||||
id<Inv<Upper>>(Inv(lower))
|
||||
id<In<Upper>>(In(lower))
|
||||
id<Out<Upper>>(Out(lower))
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ K> id(/*0*/ arg: K): K
|
||||
public fun test(/*0*/ lower: Lower): kotlin.Unit
|
||||
|
||||
public final class In</*0*/ in I> {
|
||||
public constructor In</*0*/ in I>(/*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</*0*/ T> {
|
||||
public constructor Inv</*0*/ T>(/*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</*0*/ out O> {
|
||||
public constructor Out</*0*/ out O>(/*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
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
interface Bound
|
||||
interface Upper : Bound
|
||||
class Lower : Upper
|
||||
|
||||
class Inv<T>
|
||||
|
||||
fun <T : Bound, U : T> makeInv(v: U): Inv<T> = TODO()
|
||||
fun <K> id(arg: K): K = arg
|
||||
|
||||
fun test(lower: Lower) {
|
||||
id<Inv<Upper>>(makeInv(lower))
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
interface Bound
|
||||
interface Upper : Bound
|
||||
class Lower : Upper
|
||||
|
||||
class Inv<T>
|
||||
|
||||
fun <T : Bound, U : T> makeInv(v: U): Inv<T> = TODO()
|
||||
fun <K> id(arg: K): K = arg
|
||||
|
||||
fun test(lower: Lower) {
|
||||
id<Inv<Upper>>(makeInv(lower))
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ K> id(/*0*/ arg: K): K
|
||||
public fun </*0*/ T : Bound, /*1*/ U : T> makeInv(/*0*/ v: U): Inv<T>
|
||||
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</*0*/ T> {
|
||||
public constructor Inv</*0*/ 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 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
|
||||
}
|
||||
@@ -45,7 +45,7 @@ fun test1(int: Int, any: Any) {
|
||||
readFromMyList(getMyList(any), int)
|
||||
readFromMyList<Int>(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>getMyList(any)<!>, int)
|
||||
|
||||
readFromMyList<Int>(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>getMyListToReadFrom(any)<!>, int)
|
||||
readFromMyList<Int>(<!NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>getMyListToReadFrom(any)<!>, int)
|
||||
readFromMyList(getMyListToReadFrom(any), int)
|
||||
|
||||
readFromMyList(getMyListToReadFrom(int), any)
|
||||
|
||||
@@ -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");
|
||||
|
||||
Generated
+10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user