Reuse built functional types for postponed arguments by expected types and paths from a top level type variable
^KT-42221 Fixed
This commit is contained in:
+16
-4
@@ -17,11 +17,23 @@ interface ConstraintSystemOperation {
|
||||
fun unmarkPostponedVariable(variable: TypeVariableMarker)
|
||||
fun removePostponedVariables()
|
||||
|
||||
fun getRevisedVariableForParameter(expectedType: TypeVariableMarker, index: Int): TypeVariableMarker?
|
||||
fun getRevisedVariableForReturnType(expectedType: TypeVariableMarker): TypeVariableMarker?
|
||||
fun getBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
topLevelVariable: TypeConstructorMarker,
|
||||
pathToExpectedType: List<Pair<TypeConstructorMarker, Int>>
|
||||
): KotlinTypeMarker?
|
||||
|
||||
fun putRevisedVariableForParameter(expectedType: TypeVariableMarker, index: Int, newVariable: TypeVariableMarker)
|
||||
fun putRevisedVariableForReturnType(expectedType: TypeVariableMarker, newVariable: TypeVariableMarker)
|
||||
fun getBuiltFunctionalExpectedTypeForPostponedArgument(expectedTypeVariable: TypeConstructorMarker): KotlinTypeMarker?
|
||||
|
||||
fun putBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
topLevelVariable: TypeConstructorMarker,
|
||||
pathToExpectedType: List<Pair<TypeConstructorMarker, Int>>,
|
||||
builtFunctionalType: KotlinTypeMarker
|
||||
)
|
||||
|
||||
fun putBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
expectedTypeVariable: TypeConstructorMarker,
|
||||
builtFunctionalType: KotlinTypeMarker
|
||||
)
|
||||
|
||||
fun addSubtypeConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition)
|
||||
fun addEqualityConstraint(a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition)
|
||||
|
||||
+75
-34
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
private typealias Context = ConstraintSystemCompletionContext
|
||||
private typealias ResolvedAtomProvider = (TypeVariableMarker) -> Any?
|
||||
@@ -133,48 +134,22 @@ class PostponedArgumentInputTypesResolver(
|
||||
|
||||
private fun Context.createTypeVariableForReturnType(argument: PostponedAtomWithRevisableExpectedType): TypeVariableMarker =
|
||||
with(resolutionTypeSystemContext) {
|
||||
val expectedType = argument.expectedType
|
||||
?: throw IllegalStateException("Postponed argument's expected type must not be null")
|
||||
|
||||
val variable = getBuilder().currentStorage().allTypeVariables[expectedType.typeConstructor()]
|
||||
if (variable != null) {
|
||||
val revisedVariableForReturnType = getBuilder().getRevisedVariableForReturnType(variable)
|
||||
if (revisedVariableForReturnType != null) return revisedVariableForReturnType
|
||||
}
|
||||
|
||||
return when (argument) {
|
||||
is LambdaWithTypeVariableAsExpectedTypeMarker -> createTypeVariableForLambdaReturnType()
|
||||
is PostponedCallableReferenceMarker -> createTypeVariableForCallableReferenceReturnType()
|
||||
else -> throw IllegalStateException("Unsupported postponed argument type of $argument")
|
||||
}.also {
|
||||
if (variable != null) getBuilder().putRevisedVariableForReturnType(variable, it)
|
||||
|
||||
getBuilder().registerVariable(it)
|
||||
}
|
||||
}.also { getBuilder().registerVariable(it) }
|
||||
}
|
||||
|
||||
private fun Context.createTypeVariableForParameterType(
|
||||
argument: PostponedAtomWithRevisableExpectedType,
|
||||
index: Int
|
||||
): TypeVariableMarker = with(resolutionTypeSystemContext) {
|
||||
val expectedType = argument.expectedType
|
||||
?: throw IllegalStateException("Postponed argument's expected type must not be null")
|
||||
|
||||
val variable = getBuilder().currentStorage().allTypeVariables[expectedType.typeConstructor()]
|
||||
if (variable != null) {
|
||||
val revisedVariableForParameter = getBuilder().getRevisedVariableForParameter(variable, index)
|
||||
if (revisedVariableForParameter != null) return revisedVariableForParameter
|
||||
}
|
||||
|
||||
return when (argument) {
|
||||
is LambdaWithTypeVariableAsExpectedTypeMarker -> createTypeVariableForLambdaParameterType(argument, index)
|
||||
is PostponedCallableReferenceMarker -> createTypeVariableForCallableReferenceParameterType(argument, index)
|
||||
else -> throw IllegalStateException("Unsupported postponed argument type of $argument")
|
||||
}.also {
|
||||
if (variable != null) getBuilder().putRevisedVariableForParameter(variable, index, it)
|
||||
|
||||
getBuilder().registerVariable(it)
|
||||
}
|
||||
}.also { getBuilder().registerVariable(it) }
|
||||
}
|
||||
|
||||
private fun Context.createTypeVariablesForParameters(
|
||||
@@ -243,14 +218,73 @@ class PostponedArgumentInputTypesResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.computeTypeVariablePathInsideGivenType(
|
||||
type: KotlinTypeMarker,
|
||||
targetVariable: TypeConstructorMarker,
|
||||
path: Stack<Pair<TypeConstructorMarker, Int>> = Stack()
|
||||
): List<Pair<TypeConstructorMarker, Int>>? {
|
||||
val typeConstructor = type.typeConstructor()
|
||||
|
||||
if (typeConstructor == targetVariable)
|
||||
return emptyList()
|
||||
|
||||
for (i in 0 until type.argumentsCount()) {
|
||||
val argumentType = type.getArgument(i).getType()
|
||||
|
||||
if (argumentType.typeConstructor() == targetVariable) {
|
||||
return path.toList() + (typeConstructor to i)
|
||||
} else if (argumentType.argumentsCount() != 0) {
|
||||
path.push(typeConstructor to i)
|
||||
computeTypeVariablePathInsideGivenType(argumentType, targetVariable, path)?.let { return it }
|
||||
path.pop()
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun Context.selectFirstRelatedVariable(
|
||||
variables: Set<TypeVariableTypeConstructorMarker>,
|
||||
targetVariable: TypeConstructorMarker,
|
||||
variableDependencyProvider: TypeVariableDependencyInformationProvider
|
||||
): TypeVariableTypeConstructorMarker? {
|
||||
val relatedVariables = variableDependencyProvider.getDeeplyDependentVariables(targetVariable).orEmpty() +
|
||||
variableDependencyProvider.getShallowlyDependentVariables(targetVariable)
|
||||
|
||||
return variables.firstOrNull { it in relatedVariables && it in notFixedTypeVariables }
|
||||
}
|
||||
|
||||
private fun Context.buildNewFunctionalExpectedType(
|
||||
argument: PostponedAtomWithRevisableExpectedType,
|
||||
parameterTypesInfo: ParameterTypesInfo
|
||||
parameterTypesInfo: ParameterTypesInfo,
|
||||
variableDependencyProvider: TypeVariableDependencyInformationProvider,
|
||||
topLevelTypeVariables: Set<TypeVariableTypeConstructorMarker>
|
||||
): KotlinTypeMarker? = with(resolutionTypeSystemContext) {
|
||||
val expectedType = argument.expectedType
|
||||
val expectedType = argument.expectedType ?: return null
|
||||
val expectedTypeConstructor = expectedType.typeConstructor()
|
||||
|
||||
if (expectedType == null || expectedType.typeConstructor() !in notFixedTypeVariables)
|
||||
return null
|
||||
if (expectedTypeConstructor !in notFixedTypeVariables) return null
|
||||
|
||||
val relatedTopLevelVariable = selectFirstRelatedVariable(topLevelTypeVariables, expectedTypeConstructor, variableDependencyProvider)
|
||||
val pathFromRelatedTopLevelVariable = if (relatedTopLevelVariable != null) {
|
||||
val constraintTypes = notFixedTypeVariables.getValue(relatedTopLevelVariable).constraints.map { it.type }.toSet()
|
||||
val containingType = constraintTypes.find { constraintType ->
|
||||
constraintType.contains { it.typeConstructor() == expectedTypeConstructor }
|
||||
}
|
||||
if (containingType != null) {
|
||||
computeTypeVariablePathInsideGivenType(containingType, expectedTypeConstructor)
|
||||
} else null
|
||||
} else null
|
||||
|
||||
if (pathFromRelatedTopLevelVariable != null && relatedTopLevelVariable != null) {
|
||||
// try to take from the cache of functional types by paths from a top level type variable
|
||||
getBuilder().getBuiltFunctionalExpectedTypeForPostponedArgument(relatedTopLevelVariable, pathFromRelatedTopLevelVariable)
|
||||
?.let { return it }
|
||||
} else {
|
||||
// try to take from the cache of functional types by expected types
|
||||
getBuilder().getBuiltFunctionalExpectedTypeForPostponedArgument(expectedTypeConstructor)
|
||||
?.let { return it }
|
||||
}
|
||||
|
||||
val parametersFromConstraints = parameterTypesInfo.parametersFromConstraints
|
||||
val parametersFromDeclaration = getDeclaredParametersConsideringExtensionFunctionsPresence(parameterTypesInfo)
|
||||
@@ -319,6 +353,12 @@ class PostponedArgumentInputTypesResolver(
|
||||
createArgumentConstraintPosition(argument)
|
||||
)
|
||||
|
||||
if (pathFromRelatedTopLevelVariable != null && relatedTopLevelVariable != null) {
|
||||
getBuilder().putBuiltFunctionalExpectedTypeForPostponedArgument(relatedTopLevelVariable, pathFromRelatedTopLevelVariable, newExpectedType)
|
||||
} else {
|
||||
getBuilder().putBuiltFunctionalExpectedTypeForPostponedArgument(expectedTypeConstructor, newExpectedType)
|
||||
}
|
||||
|
||||
return newExpectedType
|
||||
}
|
||||
|
||||
@@ -326,7 +366,8 @@ class PostponedArgumentInputTypesResolver(
|
||||
c: Context,
|
||||
postponedArguments: List<PostponedAtomWithRevisableExpectedType>,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
dependencyProvider: TypeVariableDependencyInformationProvider
|
||||
dependencyProvider: TypeVariableDependencyInformationProvider,
|
||||
topLevelTypeVariables: Set<TypeVariableTypeConstructorMarker>
|
||||
): Boolean = with(resolutionTypeSystemContext) {
|
||||
// We can collect parameter types from declaration in any mode, they can't change during completion.
|
||||
for (argument in postponedArguments) {
|
||||
@@ -349,7 +390,7 @@ class PostponedArgumentInputTypesResolver(
|
||||
val parameterTypesInfo =
|
||||
c.extractParameterTypesInfo(argument, postponedArguments, dependencyProvider) ?: return@any false
|
||||
val newExpectedType =
|
||||
c.buildNewFunctionalExpectedType(argument, parameterTypesInfo) ?: return@any false
|
||||
c.buildNewFunctionalExpectedType(argument, parameterTypesInfo, dependencyProvider, topLevelTypeVariables) ?: return@any false
|
||||
|
||||
argument.reviseExpectedType(newExpectedType)
|
||||
|
||||
|
||||
+4
-4
@@ -39,8 +39,8 @@ interface ConstraintStorage {
|
||||
val hasContradiction: Boolean
|
||||
val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
|
||||
val postponedTypeVariables: List<TypeVariableMarker>
|
||||
val revisedVariablesForParameters: Map<Pair<TypeVariableMarker, Int>, TypeVariableMarker>
|
||||
val revisedReturnTypes: Map<TypeVariableMarker, TypeVariableMarker>
|
||||
val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker>
|
||||
val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
|
||||
|
||||
object Empty : ConstraintStorage {
|
||||
override val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker> get() = emptyMap()
|
||||
@@ -51,8 +51,8 @@ interface ConstraintStorage {
|
||||
override val hasContradiction: Boolean get() = false
|
||||
override val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> get() = emptyMap()
|
||||
override val postponedTypeVariables: List<TypeVariableMarker> get() = emptyList()
|
||||
override val revisedVariablesForParameters: Map<Pair<TypeVariableMarker, Int>, TypeVariableMarker> = emptyMap()
|
||||
override val revisedReturnTypes: Map<TypeVariableMarker, TypeVariableMarker> = emptyMap()
|
||||
override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> = emptyMap()
|
||||
override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> = emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -202,6 +202,8 @@ internal class MutableConstraintStorage : ConstraintStorage {
|
||||
override val hasContradiction: Boolean get() = errors.any { !it.applicability.isSuccess }
|
||||
override val fixedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker> = LinkedHashMap()
|
||||
override val postponedTypeVariables: MutableList<TypeVariableMarker> = SmartList()
|
||||
override val revisedVariablesForParameters: MutableMap<Pair<TypeVariableMarker, Int>, TypeVariableMarker> = LinkedHashMap()
|
||||
override val revisedReturnTypes: MutableMap<TypeVariableMarker, TypeVariableMarker> = LinkedHashMap()
|
||||
override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: MutableMap<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> =
|
||||
LinkedHashMap()
|
||||
override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker> =
|
||||
LinkedHashMap()
|
||||
}
|
||||
|
||||
+17
-10
@@ -115,21 +115,28 @@ class NewConstraintSystemImpl(
|
||||
storage.postponedTypeVariables.clear()
|
||||
}
|
||||
|
||||
override fun getRevisedVariableForParameter(expectedType: TypeVariableMarker, index: Int): TypeVariableMarker? {
|
||||
return storage.revisedVariablesForParameters[expectedType to index]
|
||||
override fun putBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
topLevelVariable: TypeConstructorMarker,
|
||||
pathToExpectedType: List<Pair<TypeConstructorMarker, Int>>,
|
||||
builtFunctionalType: KotlinTypeMarker
|
||||
) {
|
||||
storage.builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables[topLevelVariable to pathToExpectedType] = builtFunctionalType
|
||||
}
|
||||
|
||||
override fun getRevisedVariableForReturnType(expectedType: TypeVariableMarker): TypeVariableMarker? {
|
||||
return storage.revisedReturnTypes[expectedType]
|
||||
override fun putBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
expectedTypeVariable: TypeConstructorMarker,
|
||||
builtFunctionalType: KotlinTypeMarker
|
||||
) {
|
||||
storage.builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables[expectedTypeVariable] = builtFunctionalType
|
||||
}
|
||||
|
||||
override fun putRevisedVariableForParameter(expectedType: TypeVariableMarker, index: Int, newVariable: TypeVariableMarker) {
|
||||
storage.revisedVariablesForParameters[expectedType to index] = newVariable
|
||||
}
|
||||
override fun getBuiltFunctionalExpectedTypeForPostponedArgument(
|
||||
topLevelVariable: TypeConstructorMarker,
|
||||
pathToExpectedType: List<Pair<TypeConstructorMarker, Int>>
|
||||
) = storage.builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables[topLevelVariable to pathToExpectedType]
|
||||
|
||||
override fun putRevisedVariableForReturnType(expectedType: TypeVariableMarker, newVariable: TypeVariableMarker) {
|
||||
storage.revisedReturnTypes[expectedType] = newVariable
|
||||
}
|
||||
override fun getBuiltFunctionalExpectedTypeForPostponedArgument(expectedTypeVariable: TypeConstructorMarker) =
|
||||
storage.builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables[expectedTypeVariable]
|
||||
|
||||
override fun addSubtypeConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) =
|
||||
constraintInjector.addInitialSubtypeConstraint(
|
||||
|
||||
Reference in New Issue
Block a user