NI: Support forking inference with heuristics
Mostly, it only affects FIR It partially allows to consider several variance of constraints like A<Int> & A<T> <: A<X_var> that are mostly brought by smart casts ^KT-49542 Fixed ^KT-50489 Relates
This commit is contained in:
@@ -62,6 +62,34 @@ open class TypeCheckerState(
|
||||
isFromNullabilityConstraint: Boolean = false
|
||||
): Boolean? = null
|
||||
|
||||
// Handling cases like A<Int> & A<T> <: A<F_var>
|
||||
// There are two possible solutions for F_var (Int and T) and both of them may work well or not with other constrains
|
||||
// Effectively, we need to fork constraint system to two copies: one with F_var=Int and the other with F_var=T
|
||||
// and then maintain them both until we find some contradiction with one of the versions.
|
||||
//
|
||||
// But that might lead to the exponential size of CS, thus we use the following heuristics:
|
||||
// we accumulate forks data until the last stage of the candidate resolution and then try to apply back then
|
||||
// until some of the constrains set has no contradiction.
|
||||
//
|
||||
// `atForkPoint` works trivially in non-inference context and for FE1.0: it just run basic subtyping mechanism for each subTypeArguments
|
||||
// component until the first success
|
||||
open fun runForkingPoint(block: ForkPointContext.() -> Unit): Boolean = with(ForkPointContext.Default()) {
|
||||
block()
|
||||
result
|
||||
}
|
||||
|
||||
interface ForkPointContext {
|
||||
fun fork(block: () -> Boolean)
|
||||
|
||||
class Default : ForkPointContext {
|
||||
var result: Boolean = false
|
||||
override fun fork(block: () -> Boolean) {
|
||||
if (result) return
|
||||
result = block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class LowerCapturedTypePolicy {
|
||||
CHECK_ONLY_LOWER,
|
||||
CHECK_SUBTYPE_AND_LOWER,
|
||||
@@ -362,8 +390,11 @@ object AbstractTypeChecker {
|
||||
|
||||
if (!anyNonOutParameter && state.isSubtypeForSameConstructor(newArguments, superType)) return true
|
||||
|
||||
// TODO: rethink this; now components order in intersection type affects semantic due to run subtyping (which can add constraints) only until the first successful candidate
|
||||
return supertypesWithSameConstructor.any { state.isSubtypeForSameConstructor(it.asArgumentList(), superType) }
|
||||
return state.runForkingPoint {
|
||||
for (subTypeArguments in supertypesWithSameConstructor) {
|
||||
fork { state.isSubtypeForSameConstructor(subTypeArguments.asArgumentList(), superType) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,3 +235,5 @@ inline fun <T, U, K, V> List<T>.flatGroupBy(
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <E> MutableList<E>.popLast(): E = removeAt(lastIndex)
|
||||
|
||||
Reference in New Issue
Block a user