Clarify naming around inference fork points
^KT-43296 In Progress
This commit is contained in:
committed by
Space Team
parent
715a73c8fb
commit
02b2927921
+1
-2
@@ -62,8 +62,7 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c
|
|||||||
) {
|
) {
|
||||||
val topLevelTypeVariables = topLevelType.extractTypeVariables()
|
val topLevelTypeVariables = topLevelType.extractTypeVariables()
|
||||||
|
|
||||||
// NB: it's called in ConstraintSystemForks resolution stage by FE 1.0
|
resolveForkPointsConstraints()
|
||||||
processForkConstraints()
|
|
||||||
|
|
||||||
completion@ while (true) {
|
completion@ while (true) {
|
||||||
// TODO: This is very slow
|
// TODO: This is very slow
|
||||||
|
|||||||
+22
-3
@@ -25,10 +25,29 @@ interface NewConstraintSystem {
|
|||||||
|
|
||||||
fun asConstraintSystemCompleterContext(): ConstraintSystemCompletionContext
|
fun asConstraintSystemCompleterContext(): ConstraintSystemCompletionContext
|
||||||
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzerContext
|
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzerContext
|
||||||
fun processForkConstraints()
|
fun resolveForkPointsConstraints()
|
||||||
|
|
||||||
fun getEmptyIntersectionTypeKind(types: Collection<KotlinTypeMarker>): EmptyIntersectionTypeInfo?
|
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>>
|
||||||
|
|||||||
+14
-14
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
|||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
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.ForkPointData
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.*
|
||||||
@@ -46,7 +46,7 @@ class ConstraintInjector(
|
|||||||
constraints: MutableList<Pair<TypeVariableMarker, Constraint>>
|
constraints: MutableList<Pair<TypeVariableMarker, Constraint>>
|
||||||
)
|
)
|
||||||
|
|
||||||
fun processForkConstraints()
|
fun resolveForkPointsConstraints()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
|
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
|
||||||
@@ -141,7 +141,7 @@ class ConstraintInjector(
|
|||||||
processConstraints(c, typeCheckerState, skipProperEqualityConstraints = false)
|
processConstraints(c, typeCheckerState, skipProperEqualityConstraints = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processForkConstraints(
|
fun processGivenForkPointBranchConstraints(
|
||||||
c: Context,
|
c: Context,
|
||||||
constraintSet: Collection<Pair<TypeVariableMarker, Constraint>>,
|
constraintSet: Collection<Pair<TypeVariableMarker, Constraint>>,
|
||||||
position: IncorporationConstraintPosition
|
position: IncorporationConstraintPosition
|
||||||
@@ -166,7 +166,7 @@ class ConstraintInjector(
|
|||||||
|
|
||||||
// During completion, we start processing fork constrains immediately
|
// During completion, we start processing fork constrains immediately
|
||||||
if (c.atCompletionState) {
|
if (c.atCompletionState) {
|
||||||
c.processForkConstraints()
|
c.resolveForkPointsConstraints()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,8 +275,8 @@ class ConstraintInjector(
|
|||||||
private var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null
|
private var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null
|
||||||
|
|
||||||
private var forkPointsData: MutableList<ForkPointData>? = null
|
private var forkPointsData: MutableList<ForkPointData>? = null
|
||||||
private var stackForConstraintsSetsFromCurrentForkPoint: Stack<MutableList<ConstraintsFromSingleFork>>? = null
|
private var stackForConstraintsSetsFromCurrentForkPoint: Stack<MutableList<ForkPointBranchDescription>>? = null
|
||||||
private var stackForCurrentConstraintSetFromSingleFork: Stack<MutableList<Pair<TypeVariableMarker, Constraint>>>? = null
|
private var stackForConstraintSetFromCurrentForkPointBranch: Stack<MutableList<Pair<TypeVariableMarker, Constraint>>>? = null
|
||||||
|
|
||||||
override val isInferenceCompatibilityEnabled = languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
|
override val isInferenceCompatibilityEnabled = languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
|
||||||
|
|
||||||
@@ -294,9 +294,9 @@ class ConstraintInjector(
|
|||||||
fun addPossibleNewConstraint(variable: TypeVariableMarker, constraint: Constraint) {
|
fun addPossibleNewConstraint(variable: TypeVariableMarker, constraint: Constraint) {
|
||||||
val constraintsSetsFromCurrentFork = stackForConstraintsSetsFromCurrentForkPoint?.lastOrNull()
|
val constraintsSetsFromCurrentFork = stackForConstraintsSetsFromCurrentForkPoint?.lastOrNull()
|
||||||
if (constraintsSetsFromCurrentFork != null) {
|
if (constraintsSetsFromCurrentFork != null) {
|
||||||
val currentConstraintSetForFork = stackForCurrentConstraintSetFromSingleFork?.lastOrNull()
|
val currentConstraintSetForForkPointBranch = stackForConstraintSetFromCurrentForkPointBranch?.lastOrNull()
|
||||||
require(currentConstraintSetForFork != null) { "Constraint has been added not under fork {...} call " }
|
require(currentConstraintSetForForkPointBranch != null) { "Constraint has been added not under fork {...} call " }
|
||||||
currentConstraintSetForFork.add(variable to constraint)
|
currentConstraintSetForForkPointBranch.add(variable to constraint)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ class ConstraintInjector(
|
|||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
} else if (constraintSets.size == 1) {
|
} else if (constraintSets.size == 1) {
|
||||||
processForkConstraints(
|
processGivenForkPointBranchConstraints(
|
||||||
c,
|
c,
|
||||||
constraintSets.single(),
|
constraintSets.single(),
|
||||||
position,
|
position,
|
||||||
@@ -347,17 +347,17 @@ class ConstraintInjector(
|
|||||||
var anyForkSuccessful = false
|
var anyForkSuccessful = false
|
||||||
|
|
||||||
override fun fork(block: () -> Boolean) {
|
override fun fork(block: () -> Boolean) {
|
||||||
if (stackForCurrentConstraintSetFromSingleFork == null) {
|
if (stackForConstraintSetFromCurrentForkPointBranch == null) {
|
||||||
stackForCurrentConstraintSetFromSingleFork = SmartList()
|
stackForConstraintSetFromCurrentForkPointBranch = SmartList()
|
||||||
}
|
}
|
||||||
|
|
||||||
stackForCurrentConstraintSetFromSingleFork!!.add(SmartList())
|
stackForConstraintSetFromCurrentForkPointBranch!!.add(SmartList())
|
||||||
|
|
||||||
block().also { anyForkSuccessful = anyForkSuccessful || it }
|
block().also { anyForkSuccessful = anyForkSuccessful || it }
|
||||||
|
|
||||||
stackForConstraintsSetsFromCurrentForkPoint!!.last()
|
stackForConstraintsSetsFromCurrentForkPoint!!.last()
|
||||||
.addIfNotNull(
|
.addIfNotNull(
|
||||||
stackForCurrentConstraintSetFromSingleFork?.popLast()?.takeIf { it.isNotEmpty() }?.toSet()
|
stackForConstraintSetFromCurrentForkPointBranch?.popLast()?.takeIf { it.isNotEmpty() }?.toSet()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -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.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
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 class ConstraintSystemCompletionContext : VariableFixationFinder.Context, ResultTypeResolver.Context {
|
||||||
abstract val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker>
|
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 fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, position: FixVariableConstraintPosition<*>)
|
||||||
|
|
||||||
abstract fun couldBeResolvedWithUnrestrictedBuilderInference(): Boolean
|
abstract fun couldBeResolvedWithUnrestrictedBuilderInference(): Boolean
|
||||||
abstract fun processForkConstraints()
|
abstract fun resolveForkPointsConstraints()
|
||||||
|
|
||||||
fun <A : PostponedResolvedAtomMarker> analyzeArgumentWithFixedParameterTypes(
|
fun <A : PostponedResolvedAtomMarker> analyzeArgumentWithFixedParameterTypes(
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
|
|||||||
+12
-8
@@ -357,7 +357,11 @@ class NewConstraintSystemImpl(
|
|||||||
return storage.constraintsFromAllForkPoints
|
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
|
if (constraintsFromAllForkPoints.isEmpty()) return
|
||||||
val allForkPointsData = constraintsFromAllForkPoints.toList()
|
val allForkPointsData = constraintsFromAllForkPoints.toList()
|
||||||
constraintsFromAllForkPoints.clear()
|
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)
|
// 1. {Xv=Int} – is a one-element set (but potentially there might be more constraints in the set)
|
||||||
// 2. {Xv=T} – second constraints set
|
// 2. {Xv=T} – second constraints set
|
||||||
for ((position, forkPointData) in allForkPointsData) {
|
for ((position, forkPointData) in allForkPointsData) {
|
||||||
if (!processForkPointData(forkPointData, position)) {
|
if (!applyConstraintsFromFirstSuccessfulBranchOfTheFork(forkPointData, position)) {
|
||||||
addError(NoSuccessfulFork(position))
|
addError(NoSuccessfulFork(position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,7 +396,7 @@ class NewConstraintSystemImpl(
|
|||||||
var result: ConstraintSystemError? = null
|
var result: ConstraintSystemError? = null
|
||||||
runTransaction {
|
runTransaction {
|
||||||
for ((position, forkPointData) in allForkPointsData) {
|
for ((position, forkPointData) in allForkPointsData) {
|
||||||
if (!processForkPointData(forkPointData, position)) {
|
if (!applyConstraintsFromFirstSuccessfulBranchOfTheFork(forkPointData, position)) {
|
||||||
result = NoSuccessfulFork(position)
|
result = NoSuccessfulFork(position)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -409,20 +413,20 @@ class NewConstraintSystemImpl(
|
|||||||
/**
|
/**
|
||||||
* @return true if there is a successful constraints set for the fork
|
* @return true if there is a successful constraints set for the fork
|
||||||
*/
|
*/
|
||||||
private fun processForkPointData(
|
private fun applyConstraintsFromFirstSuccessfulBranchOfTheFork(
|
||||||
forkPointData: ForkPointData,
|
forkPointData: ForkPointData,
|
||||||
position: IncorporationConstraintPosition
|
position: IncorporationConstraintPosition
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return forkPointData.any { constraintSetForSingleFork ->
|
return forkPointData.any { constraintSetForForkBranch ->
|
||||||
runTransaction {
|
runTransaction {
|
||||||
constraintInjector.processForkConstraints(
|
constraintInjector.processGivenForkPointBranchConstraints(
|
||||||
this@NewConstraintSystemImpl.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
|
this@NewConstraintSystemImpl.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
|
||||||
constraintSetForSingleFork,
|
constraintSetForForkBranch,
|
||||||
position,
|
position,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (constraintsFromAllForkPoints.isNotEmpty()) {
|
if (constraintsFromAllForkPoints.isNotEmpty()) {
|
||||||
processForkConstraints()
|
resolveForkPointsConstraints()
|
||||||
}
|
}
|
||||||
|
|
||||||
!hasContradiction
|
!hasContradiction
|
||||||
|
|||||||
Reference in New Issue
Block a user