Clarify naming around inference fork points

^KT-43296 In Progress
This commit is contained in:
Denis.Zharkov
2022-11-03 13:21:17 +01:00
committed by Space Team
parent 715a73c8fb
commit 02b2927921
5 changed files with 53 additions and 29 deletions
@@ -62,8 +62,7 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c
) {
val topLevelTypeVariables = topLevelType.extractTypeVariables()
// NB: it's called in ConstraintSystemForks resolution stage by FE 1.0
processForkConstraints()
resolveForkPointsConstraints()
completion@ while (true) {
// TODO: This is very slow
@@ -25,10 +25,29 @@ interface NewConstraintSystem {
fun asConstraintSystemCompleterContext(): ConstraintSystemCompletionContext
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzerContext
fun processForkConstraints()
fun resolveForkPointsConstraints()
fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeInfo?
}
typealias ForkPointData = List<ConstraintsFromSingleFork>
typealias ConstraintsFromSingleFork = Set<Pair<TypeVariableMarker, Constraint>>
/**
* In some cases we're not only adding constraints linearly to the system, but sometimes we need to consider several variants of constraints
*
* For example, from smartcast we've got a value of a type A<Int, String> & A<E, F> that we'd like to pass as an argument to the parameter
* of type A<Xv, Yv> (where Xv and Yv are the type variables of the current call)
*
* So, we've got a subtyping constraint
* A<Int, String> & A<E, F> <: A<Xv, Yv>
*
* And we might go with the first intersection component, having the following variables constraint set: {Xv=Int,Yv=String}
* Or, if we'd consider the second component it would be {Xv=E, Yv=F}
*
* And all existing and future constraints might work differently depending on which option we've chosen.
* Thus, ideally we need to create two versions of the constraint system and try to resolve each of them.
* But that lead to exponential complexity, so we only use some set of heuristics for that
*
* Lately, we call such situation a "fork point" and each of the options a "fork point branch"
* Each branch is defined by the set of constraints that need to be added to the system if we choose the particular branch.
*/
typealias ForkPointData = List<ForkPointBranchDescription>
typealias ForkPointBranchDescription = Set<Pair<TypeVariableMarker, Constraint>>
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsFromSingleFork
import org.jetbrains.kotlin.resolve.calls.inference.ForkPointBranchDescription
import org.jetbrains.kotlin.resolve.calls.inference.ForkPointData
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.*
@@ -46,7 +46,7 @@ class ConstraintInjector(
constraints: MutableList<Pair<TypeVariableMarker, Constraint>>
)
fun processForkConstraints()
fun resolveForkPointsConstraints()
}
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
@@ -141,7 +141,7 @@ class ConstraintInjector(
processConstraints(c, typeCheckerState, skipProperEqualityConstraints = false)
}
fun processForkConstraints(
fun processGivenForkPointBranchConstraints(
c: Context,
constraintSet: Collection<Pair<TypeVariableMarker, Constraint>>,
position: IncorporationConstraintPosition
@@ -166,7 +166,7 @@ class ConstraintInjector(
// During completion, we start processing fork constrains immediately
if (c.atCompletionState) {
c.processForkConstraints()
c.resolveForkPointsConstraints()
}
}
}
@@ -275,8 +275,8 @@ class ConstraintInjector(
private var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null
private var forkPointsData: MutableList<ForkPointData>? = null
private var stackForConstraintsSetsFromCurrentForkPoint: Stack<MutableList<ConstraintsFromSingleFork>>? = null
private var stackForCurrentConstraintSetFromSingleFork: Stack<MutableList<Pair<TypeVariableMarker, Constraint>>>? = null
private var stackForConstraintsSetsFromCurrentForkPoint: Stack<MutableList<ForkPointBranchDescription>>? = null
private var stackForConstraintSetFromCurrentForkPointBranch: Stack<MutableList<Pair<TypeVariableMarker, Constraint>>>? = null
override val isInferenceCompatibilityEnabled = languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
@@ -294,9 +294,9 @@ class ConstraintInjector(
fun addPossibleNewConstraint(variable: TypeVariableMarker, constraint: Constraint) {
val constraintsSetsFromCurrentFork = stackForConstraintsSetsFromCurrentForkPoint?.lastOrNull()
if (constraintsSetsFromCurrentFork != null) {
val currentConstraintSetForFork = stackForCurrentConstraintSetFromSingleFork?.lastOrNull()
require(currentConstraintSetForFork != null) { "Constraint has been added not under fork {...} call " }
currentConstraintSetForFork.add(variable to constraint)
val currentConstraintSetForForkPointBranch = stackForConstraintSetFromCurrentForkPointBranch?.lastOrNull()
require(currentConstraintSetForForkPointBranch != null) { "Constraint has been added not under fork {...} call " }
currentConstraintSetForForkPointBranch.add(variable to constraint)
return
}
@@ -333,7 +333,7 @@ class ConstraintInjector(
)
return true
} else if (constraintSets.size == 1) {
processForkConstraints(
processGivenForkPointBranchConstraints(
c,
constraintSets.single(),
position,
@@ -347,17 +347,17 @@ class ConstraintInjector(
var anyForkSuccessful = false
override fun fork(block: () -> Boolean) {
if (stackForCurrentConstraintSetFromSingleFork == null) {
stackForCurrentConstraintSetFromSingleFork = SmartList()
if (stackForConstraintSetFromCurrentForkPointBranch == null) {
stackForConstraintSetFromCurrentForkPointBranch = SmartList()
}
stackForCurrentConstraintSetFromSingleFork!!.add(SmartList())
stackForConstraintSetFromCurrentForkPointBranch!!.add(SmartList())
block().also { anyForkSuccessful = anyForkSuccessful || it }
stackForConstraintsSetsFromCurrentForkPoint!!.last()
.addIfNotNull(
stackForCurrentConstraintSetFromSingleFork?.popLast()?.takeIf { it.isNotEmpty() }?.toSet()
stackForConstraintSetFromCurrentForkPointBranch?.popLast()?.takeIf { it.isNotEmpty() }?.toSet()
)
}
}
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
abstract class ConstraintSystemCompletionContext : VariableFixationFinder.Context, ResultTypeResolver.Context {
abstract val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker>
@@ -33,7 +35,7 @@ abstract class ConstraintSystemCompletionContext : VariableFixationFinder.Contex
abstract fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, position: FixVariableConstraintPosition<*>)
abstract fun couldBeResolvedWithUnrestrictedBuilderInference(): Boolean
abstract fun processForkConstraints()
abstract fun resolveForkPointsConstraints()
fun <A : PostponedResolvedAtomMarker> analyzeArgumentWithFixedParameterTypes(
languageVersionSettings: LanguageVersionSettings,
@@ -357,7 +357,11 @@ class NewConstraintSystemImpl(
return storage.constraintsFromAllForkPoints
}
override fun processForkConstraints() {
/**
* This function tries to find the solution (set of constraints) that is consistent with some branch of each fork
* And those constraints are being immediately applied to the system
*/
override fun resolveForkPointsConstraints() {
if (constraintsFromAllForkPoints.isEmpty()) return
val allForkPointsData = constraintsFromAllForkPoints.toList()
constraintsFromAllForkPoints.clear()
@@ -369,7 +373,7 @@ class NewConstraintSystemImpl(
// 1. {Xv=Int} is a one-element set (but potentially there might be more constraints in the set)
// 2. {Xv=T} second constraints set
for ((position, forkPointData) in allForkPointsData) {
if (!processForkPointData(forkPointData, position)) {
if (!applyConstraintsFromFirstSuccessfulBranchOfTheFork(forkPointData, position)) {
addError(NoSuccessfulFork(position))
}
}
@@ -392,7 +396,7 @@ class NewConstraintSystemImpl(
var result: ConstraintSystemError? = null
runTransaction {
for ((position, forkPointData) in allForkPointsData) {
if (!processForkPointData(forkPointData, position)) {
if (!applyConstraintsFromFirstSuccessfulBranchOfTheFork(forkPointData, position)) {
result = NoSuccessfulFork(position)
break
}
@@ -409,20 +413,20 @@ class NewConstraintSystemImpl(
/**
* @return true if there is a successful constraints set for the fork
*/
private fun processForkPointData(
private fun applyConstraintsFromFirstSuccessfulBranchOfTheFork(
forkPointData: ForkPointData,
position: IncorporationConstraintPosition
): Boolean {
return forkPointData.any { constraintSetForSingleFork ->
return forkPointData.any { constraintSetForForkBranch ->
runTransaction {
constraintInjector.processForkConstraints(
constraintInjector.processGivenForkPointBranchConstraints(
this@NewConstraintSystemImpl.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
constraintSetForSingleFork,
constraintSetForForkBranch,
position,
)
if (constraintsFromAllForkPoints.isNotEmpty()) {
processForkConstraints()
resolveForkPointsConstraints()
}
!hasContradiction