[NI] Introduce transactions for constraint system.
This will be used for callable reference resolution.
This commit is contained in:
+1
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
|
||||
+13
-6
@@ -23,21 +23,22 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
|
||||
interface ConstraintSystemBuilder {
|
||||
interface ConstraintSystemOperation {
|
||||
val hasContradiction: Boolean
|
||||
|
||||
fun registerVariable(variable: NewTypeVariable)
|
||||
|
||||
fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition)
|
||||
fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition)
|
||||
|
||||
fun isProperType(type: UnwrappedType): Boolean
|
||||
}
|
||||
|
||||
interface ConstraintSystemBuilder : ConstraintSystemOperation {
|
||||
fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall)
|
||||
fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument)
|
||||
|
||||
fun addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition): Boolean
|
||||
|
||||
fun isProperType(type: UnwrappedType): Boolean
|
||||
// if runOperations return true, then this operation will be applied, and function return true
|
||||
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
|
||||
|
||||
/**
|
||||
* This function removes variables for which we know exact type.
|
||||
@@ -45,3 +46,9 @@ interface ConstraintSystemBuilder {
|
||||
*/
|
||||
fun simplify(): NewTypeSubstitutor
|
||||
}
|
||||
|
||||
fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
|
||||
runTransaction {
|
||||
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position)
|
||||
!hasContradiction
|
||||
}
|
||||
@@ -57,3 +57,5 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
|
||||
|
||||
return substitute(TypeSubstitutor.create(wrappedSubstitution))
|
||||
}
|
||||
|
||||
fun <E> MutableList<E>.trimToSize(newSize: Int) = subList(newSize, size).clear()
|
||||
+11
-20
@@ -16,12 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
class MutableVariableWithConstraints(
|
||||
@@ -29,7 +31,7 @@ class MutableVariableWithConstraints(
|
||||
constraints: Collection<Constraint> = emptyList()
|
||||
) : VariableWithConstraints {
|
||||
override val constraints: List<Constraint> get() = mutableConstraints
|
||||
private val mutableConstraints = MyArrayList(constraints)
|
||||
private val mutableConstraints = ArrayList(constraints)
|
||||
|
||||
// return new actual constraint, if this constraint is new
|
||||
fun addConstraint(constraint: Constraint): Constraint? {
|
||||
@@ -50,15 +52,15 @@ class MutableVariableWithConstraints(
|
||||
return actualConstraint
|
||||
}
|
||||
|
||||
fun removeLastConstraints(shouldRemove: (Constraint) -> Boolean) {
|
||||
mutableConstraints.removeLast(shouldRemove)
|
||||
// This method should be used only for transaction in constraint system
|
||||
// shouldRemove should give true only for tail elements
|
||||
internal fun removeLastConstraints(shouldRemove: (Constraint) -> Boolean) {
|
||||
mutableConstraints.trimToSize(mutableConstraints.indexOfLast { !shouldRemove(it) } + 1)
|
||||
}
|
||||
|
||||
// todo optimize it!
|
||||
fun removeConstrains(shouldRemove: (Constraint) -> Boolean) {
|
||||
val newConstraints = mutableConstraints.filter { !shouldRemove(it) }
|
||||
mutableConstraints.clear()
|
||||
mutableConstraints.addAll(newConstraints)
|
||||
// This method should be used only when constraint system has state COMPLETION
|
||||
internal fun removeConstrains(shouldRemove: (Constraint) -> Boolean) {
|
||||
mutableConstraints.removeAll(shouldRemove)
|
||||
}
|
||||
|
||||
private fun newConstraintIsUseless(oldKind: ConstraintKind, newKind: ConstraintKind) =
|
||||
@@ -68,24 +70,13 @@ class MutableVariableWithConstraints(
|
||||
ConstraintKind.UPPER -> newKind == ConstraintKind.UPPER
|
||||
}
|
||||
|
||||
private class MyArrayList<E>(c: Collection<E>): ArrayList<E>(c) {
|
||||
fun removeLast(predicate: (E) -> Boolean) {
|
||||
val newSize = indexOfLast { !predicate(it) } + 1
|
||||
|
||||
if (newSize != size) {
|
||||
removeRange(newSize, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Constraints for $typeVariable"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class MutableConstraintStorage : ConstraintStorage {
|
||||
internal class MutableConstraintStorage : ConstraintStorage {
|
||||
override val allTypeVariables: MutableMap<TypeConstructor, NewTypeVariable> = LinkedHashMap()
|
||||
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> = LinkedHashMap()
|
||||
override val initialConstraints: MutableList<InitialConstraint> = ArrayList()
|
||||
|
||||
+55
-26
@@ -17,9 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||
@@ -29,6 +27,7 @@ import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import java.util.*
|
||||
|
||||
class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val resultTypeResolver: ResultTypeResolver):
|
||||
@@ -39,11 +38,13 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
KotlinCallCompleter.Context,
|
||||
FixationOrderCalculator.Context
|
||||
{
|
||||
val storage = MutableConstraintStorage()
|
||||
private val storage = MutableConstraintStorage()
|
||||
private var state = State.BUILDING
|
||||
private val typeVariablesTransaction: MutableList<NewTypeVariable> = SmartList()
|
||||
|
||||
private enum class State {
|
||||
BUILDING,
|
||||
TRANSACTION,
|
||||
FREEZED,
|
||||
COMPLETION
|
||||
}
|
||||
@@ -73,44 +74,72 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
return this
|
||||
}
|
||||
|
||||
// ConstraintSystemBuilder
|
||||
// ConstraintSystemOperation
|
||||
override fun registerVariable(variable: NewTypeVariable) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
|
||||
transactionRegisterVariable(variable)
|
||||
storage.allTypeVariables[variable.freshTypeConstructor] = variable
|
||||
storage.notFixedTypeVariables[variable.freshTypeConstructor] = MutableVariableWithConstraints(variable)
|
||||
}
|
||||
|
||||
override fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
|
||||
constraintInjector.addInitialSubtypeConstraint(apply { checkState(State.BUILDING, State.COMPLETION) }, lowerType, upperType, position)
|
||||
constraintInjector.addInitialSubtypeConstraint(apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }, lowerType, upperType, position)
|
||||
|
||||
override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) =
|
||||
constraintInjector.addInitialEqualityConstraint(apply { checkState(State.BUILDING, State.COMPLETION) }, a, b, position)
|
||||
constraintInjector.addInitialEqualityConstraint(apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }, a, b, position)
|
||||
|
||||
override fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
storage.lambdaArguments.add(resolvedLambdaArgument)
|
||||
// ConstraintSystemBuilder
|
||||
private fun transactionRegisterVariable(variable: NewTypeVariable) {
|
||||
if (state != State.TRANSACTION) return
|
||||
typeVariablesTransaction.add(variable)
|
||||
}
|
||||
|
||||
override fun addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition): Boolean {
|
||||
private fun closeTransaction(beforeState: State) {
|
||||
checkState(State.TRANSACTION)
|
||||
typeVariablesTransaction.clear()
|
||||
state = beforeState
|
||||
}
|
||||
|
||||
override fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
val beforeState = state
|
||||
val beforeInitialConstraintCount = storage.initialConstraints.size
|
||||
val beforeErrorsCount = storage.errors.size
|
||||
val beforeMaxTypeDepthFromInitialConstraints = storage.maxTypeDepthFromInitialConstraints
|
||||
|
||||
if (hasContradiction) return false
|
||||
addSubtypeConstraint(lowerType, upperType, position)
|
||||
if (!hasContradiction) return true
|
||||
state = State.TRANSACTION
|
||||
// typeVariablesTransaction is clear
|
||||
if (runOperations()) {
|
||||
closeTransaction(beforeState)
|
||||
return true
|
||||
}
|
||||
|
||||
val shouldRemove = { c: Constraint -> c.position === position ||
|
||||
(c.position is IncorporationConstraintPosition && c.position.from === position) }
|
||||
for (addedTypeVariable in typeVariablesTransaction) {
|
||||
storage.allTypeVariables.remove(addedTypeVariable.freshTypeConstructor)
|
||||
storage.notFixedTypeVariables.remove(addedTypeVariable.freshTypeConstructor)
|
||||
}
|
||||
storage.maxTypeDepthFromInitialConstraints = beforeMaxTypeDepthFromInitialConstraints
|
||||
storage.errors.trimToSize(beforeErrorsCount)
|
||||
|
||||
val addedInitialConstraints = storage.initialConstraints.subList(beforeInitialConstraintCount, storage.initialConstraints.size)
|
||||
|
||||
val shouldRemove = { c: Constraint -> addedInitialConstraints.contains(c.position.initialConstraint) }
|
||||
|
||||
for (variableWithConstraint in storage.notFixedTypeVariables.values) {
|
||||
variableWithConstraint.removeLastConstraints(shouldRemove)
|
||||
}
|
||||
storage.errors.clear()
|
||||
storage.initialConstraints.removeAt(storage.initialConstraints.lastIndex)
|
||||
|
||||
addedInitialConstraints.clear() // remove constraint from storage.initialConstraints
|
||||
closeTransaction(beforeState)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
storage.lambdaArguments.add(resolvedLambdaArgument)
|
||||
}
|
||||
|
||||
private fun getVariablesForFixation(): Map<NewTypeVariable, UnwrappedType> {
|
||||
val fixedVariables = LinkedHashMap<NewTypeVariable, UnwrappedType>()
|
||||
|
||||
@@ -140,7 +169,7 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
|
||||
// ConstraintSystemBuilder, KotlinCallCompleter.Context
|
||||
override val hasContradiction: Boolean
|
||||
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION) }
|
||||
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }
|
||||
|
||||
override fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
@@ -162,7 +191,7 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
|
||||
// ResultTypeResolver.Context, ConstraintSystemBuilder
|
||||
override fun isProperType(type: UnwrappedType): Boolean {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
return !type.contains {
|
||||
storage.allTypeVariables.containsKey(it.constructor)
|
||||
}
|
||||
@@ -170,31 +199,31 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
|
||||
// ConstraintInjector.Context
|
||||
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
return storage.allTypeVariables
|
||||
}
|
||||
|
||||
override var maxTypeDepthFromInitialConstraints: Int
|
||||
get() = storage.maxTypeDepthFromInitialConstraints
|
||||
set(value) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
storage.maxTypeDepthFromInitialConstraints = value
|
||||
}
|
||||
|
||||
override fun addInitialConstraint(initialConstraint: InitialConstraint) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
storage.initialConstraints.add(initialConstraint)
|
||||
}
|
||||
|
||||
// ConstraintInjector.Context, FixationOrderCalculator.Context
|
||||
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> get() {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
return storage.notFixedTypeVariables
|
||||
}
|
||||
|
||||
// ConstraintInjector.Context, KotlinCallCompleter.Context
|
||||
override fun addError(error: KotlinCallDiagnostic) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
storage.errors.add(error)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user