[NI] Fix poor performance of recursive types approximation
#KT-32407 Fixed
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStra
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
|
||||
open class TypeApproximatorConfiguration {
|
||||
@@ -119,6 +120,10 @@ class TypeApproximator(builtIns: KotlinBuiltIns) : AbstractTypeApproximator(Clas
|
||||
|
||||
abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionContext) : TypeSystemInferenceExtensionContext by ctx {
|
||||
|
||||
private class ApproximationResult(val type: KotlinTypeMarker?)
|
||||
|
||||
private val cacheForIncorporationConfigToSuperDirection = ConcurrentHashMap<KotlinTypeMarker, ApproximationResult>()
|
||||
private val cacheForIncorporationConfigToSubtypeDirection = ConcurrentHashMap<KotlinTypeMarker, ApproximationResult>()
|
||||
|
||||
private val referenceApproximateToSuperType = this::approximateSimpleToSuperType
|
||||
private val referenceApproximateToSubType = this::approximateSimpleToSubType
|
||||
@@ -136,23 +141,69 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon
|
||||
fun approximateToSubType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration): KotlinTypeMarker? =
|
||||
approximateToSubType(type, conf, -type.typeDepth())
|
||||
|
||||
fun clearCache() {
|
||||
cacheForIncorporationConfigToSubtypeDirection.clear()
|
||||
cacheForIncorporationConfigToSuperDirection.clear()
|
||||
}
|
||||
|
||||
private fun checkExceptionalCases(
|
||||
type: KotlinTypeMarker, depth: Int, conf: TypeApproximatorConfiguration, toSuper: Boolean
|
||||
): ApproximationResult? {
|
||||
return when {
|
||||
type is TypeUtils.SpecialType ->
|
||||
null.toApproximationResult()
|
||||
|
||||
type.isError() ->
|
||||
// todo -- fix builtIns. Now builtIns here is DefaultBuiltIns
|
||||
(if (conf.errorType) null else type.defaultResult(toSuper)).toApproximationResult()
|
||||
|
||||
depth > 3 ->
|
||||
type.defaultResult(toSuper).toApproximationResult()
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinTypeMarker?.toApproximationResult(): ApproximationResult = ApproximationResult(this)
|
||||
|
||||
private inline fun cachedValue(
|
||||
type: KotlinTypeMarker,
|
||||
conf: TypeApproximatorConfiguration,
|
||||
toSuper: Boolean,
|
||||
approximate: () -> KotlinTypeMarker?
|
||||
): KotlinTypeMarker? {
|
||||
// Approximator depends on a configuration, so cache should take it into account
|
||||
// Here, we cache only types for configuration "from incorporation", which is used most intensively
|
||||
if (conf !is TypeApproximatorConfiguration.IncorporationConfiguration) return approximate()
|
||||
|
||||
val cache = if (toSuper) cacheForIncorporationConfigToSuperDirection else cacheForIncorporationConfigToSubtypeDirection
|
||||
return cache.getOrPut(type, { approximate().toApproximationResult() }).type
|
||||
}
|
||||
|
||||
private fun approximateToSuperType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration, depth: Int): KotlinTypeMarker? {
|
||||
if (type is TypeUtils.SpecialType) return null
|
||||
return approximateTo(
|
||||
prepareType(type), conf, { upperBound() },
|
||||
referenceApproximateToSuperType, depth
|
||||
)
|
||||
checkExceptionalCases(type, depth, conf, toSuper = true)?.let { return it.type }
|
||||
|
||||
return cachedValue(type, conf, toSuper = true) {
|
||||
approximateTo(
|
||||
prepareType(type), conf, { upperBound() },
|
||||
referenceApproximateToSuperType, depth
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun approximateToSubType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration, depth: Int): KotlinTypeMarker? {
|
||||
if (type is TypeUtils.SpecialType) return null
|
||||
return approximateTo(
|
||||
prepareType(type), conf, { lowerBound() },
|
||||
referenceApproximateToSubType, depth
|
||||
)
|
||||
checkExceptionalCases(type, depth, conf, toSuper = false)?.let { return it.type }
|
||||
|
||||
return cachedValue(type, conf, toSuper = false) {
|
||||
approximateTo(
|
||||
prepareType(type), conf, { lowerBound() },
|
||||
referenceApproximateToSubType, depth
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// comments for case bound = upperBound, approximateTo = toSuperType
|
||||
// Don't call this method directly, it should be used only in approximateToSuperType/approximateToSubType (use these methods instead)
|
||||
// This method contains detailed implementation only for type approximation, it doesn't check exceptional cases and doesn't use cache
|
||||
private fun approximateTo(
|
||||
type: KotlinTypeMarker,
|
||||
conf: TypeApproximatorConfiguration,
|
||||
@@ -330,13 +381,6 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon
|
||||
toSuper: Boolean,
|
||||
depth: Int
|
||||
): KotlinTypeMarker? {
|
||||
if (type.isError()) {
|
||||
// todo -- fix builtIns. Now builtIns here is DefaultBuiltIns
|
||||
return if (conf.errorType) null else type.defaultResult(toSuper)
|
||||
}
|
||||
|
||||
if (depth > 3) return type.defaultResult(toSuper)
|
||||
|
||||
if (type.argumentsCount() != 0) {
|
||||
return approximateParametrizedType(type, conf, toSuper, depth + 1)
|
||||
}
|
||||
@@ -382,12 +426,15 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon
|
||||
toSuper: Boolean,
|
||||
depth: Int
|
||||
): KotlinTypeMarker? {
|
||||
val approximatedOriginalType = approximateTo(type.original(), conf, toSuper, depth)
|
||||
val originalType = type.original()
|
||||
val approximatedOriginalType =
|
||||
if (toSuper) approximateToSuperType(originalType, conf, depth) else approximateToSubType(originalType, conf, depth)
|
||||
|
||||
return if (conf.definitelyNotNullType) {
|
||||
approximatedOriginalType?.makeDefinitelyNotNullOrNotNull()
|
||||
} else {
|
||||
if (toSuper)
|
||||
(approximatedOriginalType ?: type.original()).withNullability(false)
|
||||
(approximatedOriginalType ?: originalType).withNullability(false)
|
||||
else
|
||||
type.defaultResult(toSuper)
|
||||
}
|
||||
@@ -519,8 +566,8 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon
|
||||
return type.replaceArguments(newArgumentsList)
|
||||
}
|
||||
|
||||
private fun SimpleTypeMarker.defaultResult(toSuper: Boolean) = if (toSuper) nullableAnyType() else {
|
||||
if (isMarkedNullable()) nullableNothingType() else nothingType()
|
||||
private fun KotlinTypeMarker.defaultResult(toSuper: Boolean) = if (toSuper) nullableAnyType() else {
|
||||
if (this is SimpleTypeMarker && isMarkedNullable()) nullableNothingType() else nothingType()
|
||||
}
|
||||
|
||||
// Any? or Any!
|
||||
|
||||
Reference in New Issue
Block a user