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:
Victor Petukhov
2020-10-14 18:02:17 +03:00
parent ee5edf4caa
commit c6da2a1138
18 changed files with 538 additions and 57 deletions
@@ -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)
@@ -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)
@@ -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()
}
}
@@ -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()
}
@@ -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(