Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls
import org.jetbrains.kotlin.types.AbstractFlexibilityChecker.hasDifferentFlexibilityAtDepth
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.model.*
object NewCommonSuperTypeCalculator {
fun TypeSystemCommonSuperTypesContext.commonSuperType(types: List): KotlinTypeMarker {
val maxDepth = types.maxOfOrNull { it.typeDepth() } ?: 0
return commonSuperType(types, -maxDepth, true)
}
private fun TypeSystemCommonSuperTypesContext.commonSuperType(
types: List,
depth: Int,
isTopLevelType: Boolean = false
): KotlinTypeMarker {
if (types.isEmpty()) throw IllegalStateException("Empty collection for input")
types.singleOrNull()?.let { return it }
var thereIsFlexibleTypes = false
val lowers = types.map {
when (it) {
is SimpleTypeMarker -> {
if (it.isCapturedDynamic()) return it
it
}
is FlexibleTypeMarker -> {
if (it.isDynamic()) return it
// raw types are allowed here and will be transformed to FlexibleTypes
thereIsFlexibleTypes = true
it.lowerBound()
}
else -> error("sealed")
}
}
val contextStubTypesEqualToAnything = newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
val contextStubTypesNotEqual = newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false)
val lowerSuperType = commonSuperTypeForSimpleTypes(lowers, depth, contextStubTypesEqualToAnything, contextStubTypesNotEqual)
if (!thereIsFlexibleTypes) return lowerSuperType
val upperSuperType = commonSuperTypeForSimpleTypes(
types.map { it.upperBoundIfFlexible() }, depth, contextStubTypesEqualToAnything, contextStubTypesNotEqual
)
if (!isTopLevelType) {
val nonStubTypes =
types.filter { !isStubRelatedType(it.lowerBoundIfFlexible()) && !isStubRelatedType(it.upperBoundIfFlexible()) }
val equalToEachOtherTypes = nonStubTypes.filter { potentialCommonSuperType ->
nonStubTypes.all {
AbstractTypeChecker.equalTypes(this, it, potentialCommonSuperType)
}
}
if (equalToEachOtherTypes.isNotEmpty()) {
// TODO: merge flexibilities of type arguments instead of select the first suitable type
return equalToEachOtherTypes.first()
}
}
return createFlexibleType(lowerSuperType, upperSuperType)
}
private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForSimpleTypes(
types: List,
depth: Int,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext,
contextStubTypesNotEqual: AbstractTypeCheckerContext
): SimpleTypeMarker {
if (types.any { it.isError() }) {
return createErrorType("CST(${types.joinToString()}")
}
// i.e. result type also should be marked nullable
val notAllNotNull =
types.any { !isStubRelatedType(it) && !AbstractNullabilityChecker.isSubtypeOfAny(contextStubTypesEqualToAnything, it) }
val notNullTypes = if (notAllNotNull) types.map { it.withNullability(false) } else types
val commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth, contextStubTypesEqualToAnything, contextStubTypesNotEqual)
return if (notAllNotNull)
refineNullabilityForUndefinedNullability(types, commonSuperType) ?: commonSuperType.withNullability(true)
else
commonSuperType
}
private fun TypeSystemCommonSuperTypesContext.refineNullabilityForUndefinedNullability(
types: List,
commonSuperType: SimpleTypeMarker
): SimpleTypeMarker? {
if (!commonSuperType.canHaveUndefinedNullability()) return null
val actuallyNotNull =
types.all { hasPathByNotMarkedNullableNodes(it, commonSuperType.typeConstructor()) }
return if (actuallyNotNull) commonSuperType else null
}
// Makes representative sample, i.e. (A, B, A) -> (A, B)
private fun TypeSystemCommonSuperTypesContext.uniquify(
types: List,
contextStubTypesNotEqual: AbstractTypeCheckerContext
): List {
val uniqueTypes = arrayListOf()
for (type in types) {
val isNewUniqueType = uniqueTypes.all {
val equalsModuloFlexibility = AbstractTypeChecker.equalTypes(contextStubTypesNotEqual, it, type) &&
!it.typeConstructor().isIntegerLiteralTypeConstructor()
!equalsModuloFlexibility || hasDifferentFlexibilityAtDepth(listOf(it, type))
}
if (isNewUniqueType) {
uniqueTypes += type
}
}
return uniqueTypes
}
// This function leaves only supertypes, i.e. A0 is a strong supertype for A iff A != A0 && A <: A0
// Explanation: consider types (A : A0, B : B0, A0, B0), then CST(A, B, A0, B0) == CST(CST(A, A0), CST(B, B0)) == CST(A0, B0)
private fun TypeSystemCommonSuperTypesContext.filterSupertypes(
list: List,
contextStubTypesNotEqual: AbstractTypeCheckerContext
): List {
val supertypes = list.toMutableList()
val iterator = supertypes.iterator()
while (iterator.hasNext()) {
val potentialSubtype = iterator.next()
val isSubtype = supertypes.any { supertype ->
supertype !== potentialSubtype &&
AbstractTypeChecker.isSubtypeOf(contextStubTypesNotEqual, potentialSubtype, supertype) &&
!hasDifferentFlexibilityAtDepth(listOf(potentialSubtype, supertype))
}
if (isSubtype) iterator.remove()
}
return supertypes
}
/*
* Common Supertype calculator works with proper types and stub types (which is a replacement for non-proper types)
* Also, there are two invariant related to stub types:
* - resulting type should be only proper type
* - one of the input types is definitely proper type
* */
private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForNotNullTypes(
types: List,
depth: Int,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext,
contextStubTypesNotEqual: AbstractTypeCheckerContext
): SimpleTypeMarker {
if (types.size == 1) return types.single()
val nonStubTypes = types.filter { !isStubRelatedType(it) }
if (nonStubTypes.size == 1) return nonStubTypes.single()
assert(nonStubTypes.isNotEmpty()) {
"There should be at least one non-stub type to compute common supertype but there are: $types"
}
val uniqueTypes = uniquify(nonStubTypes, contextStubTypesNotEqual)
if (uniqueTypes.size == 1) return uniqueTypes.single()
val explicitSupertypes = filterSupertypes(uniqueTypes, contextStubTypesNotEqual)
if (explicitSupertypes.size == 1) return explicitSupertypes.single()
findErrorTypeInSupertypes(explicitSupertypes, contextStubTypesEqualToAnything)?.let { return it }
findCommonIntegerLiteralTypesSuperType(explicitSupertypes)?.let { return it }
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth, contextStubTypesEqualToAnything)
}
private fun TypeSystemCommonSuperTypesContext.isStubRelatedType(type: SimpleTypeMarker): Boolean {
return type.isStubType() || isCapturedStubType(type)
}
private fun TypeSystemCommonSuperTypesContext.isCapturedStubType(type: SimpleTypeMarker): Boolean {
val projectedType =
type.asCapturedType()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }?.getType() ?: return false
return projectedType.asSimpleType()?.isStubType() == true
}
private fun TypeSystemCommonSuperTypesContext.findErrorTypeInSupertypes(
types: List,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext
): SimpleTypeMarker? {
for (type in types) {
collectAllSupertypes(type, contextStubTypesEqualToAnything).firstOrNull { it.isError() }?.let { return it.toErrorType() }
}
return null
}
private fun TypeSystemCommonSuperTypesContext.findSuperTypeConstructorsAndIntersectResult(
types: List,
depth: Int,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext
): SimpleTypeMarker =
intersectTypes(
allCommonSuperTypeConstructors(types, contextStubTypesEqualToAnything)
.map { superTypeWithGivenConstructor(types, it, depth) }
)
/**
* Note that if there is captured type C, then no one else is not subtype of C => lowerType cannot help here
*/
private fun TypeSystemCommonSuperTypesContext.allCommonSuperTypeConstructors(
types: List,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext
): List {
val result = collectAllSupertypes(types.first(), contextStubTypesEqualToAnything)
// retain all super constructors of the first type that are present in the supertypes of all other types
for (type in types) {
if (type === types.first()) continue
result.retainAll(collectAllSupertypes(type, contextStubTypesEqualToAnything))
}
// remove all constructors that have subtype(s) with constructors from the resulting set - they are less precise
return result.filterNot { target ->
result.any { other ->
other != target && other.supertypes().any { it.typeConstructor() == target }
}
}
}
private fun TypeSystemCommonSuperTypesContext.collectAllSupertypes(
type: SimpleTypeMarker,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext
) =
LinkedHashSet().apply {
contextStubTypesEqualToAnything.anySupertype(
type,
{ add(it.typeConstructor()); false },
{ AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible }
)
}
private fun TypeSystemCommonSuperTypesContext.superTypeWithGivenConstructor(
types: List,
constructor: TypeConstructorMarker,
depth: Int
): SimpleTypeMarker {
if (constructor.parametersCount() == 0) return createSimpleType(
constructor,
emptyList(),
nullable = false
)
val typeCheckerContext = newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
/**
* Sometimes one type can have several supertypes with given type constructor, suppose A <: List and A <: List.
* Also suppose that B <: List.
* Note that common supertype for A and B is CS(List, List) & CS(List, List),
* but it is too complicated and we will return not so accurate type: CS(List, List, List)
*/
val correspondingSuperTypes = types.flatMap {
with(AbstractTypeChecker) {
typeCheckerContext.findCorrespondingSupertypes(it, constructor)
}
}
val arguments = ArrayList(constructor.parametersCount())
for (index in 0 until constructor.parametersCount()) {
val parameter = constructor.getParameter(index)
var thereIsStar = false
val typeProjections = correspondingSuperTypes.mapNotNull {
val typeArgumentFromSupertype = it.getArgumentOrNull(index) ?: return@mapNotNull null
// We have to uncapture types with status FOR_SUBTYPING because such captured types are creating during
// `findCorrespondingSupertypes` call. Normally, we shouldn't create intermediate captured types here, it's needed only
// to check subtyping. It'll be fixed but for a while we do this uncapturing here
val typeArgument = uncaptureFromSubtyping(typeArgumentFromSupertype)
when {
typeArgument.isStarProjection() -> {
thereIsStar = true
null
}
typeArgument.getType().lowerBoundIfFlexible().isStubType() -> null
else -> typeArgument
}
}
// This is used for folding recursive types like Inv> into Inv<*>
fun collapseRecursiveArgumentIfPossible(argument: TypeArgumentMarker): TypeArgumentMarker {
if (argument.isStarProjection()) return argument
val argumentType = argument.getType().asSimpleType()
val argumentConstructor = argumentType?.typeConstructor()
return if (argument.getVariance() == TypeVariance.OUT && argumentConstructor == constructor && argumentType.asArgumentList()[index].isStarProjection()) {
createStarProjection(parameter)
} else {
argument
}
}
val argument =
if (thereIsStar || typeProjections.isEmpty() || checkRecursion(types, typeProjections, parameter)) {
createStarProjection(parameter)
} else {
collapseRecursiveArgumentIfPossible(calculateArgument(parameter, typeProjections, depth))
}
arguments.add(argument)
}
return createSimpleType(constructor, arguments, nullable = false, isExtensionFunction = types.all { it.isExtensionFunction() })
}
private fun TypeSystemCommonSuperTypesContext.uncaptureFromSubtyping(typeArgument: TypeArgumentMarker): TypeArgumentMarker {
val capturedType = typeArgument.getType().asSimpleType()?.asCapturedType() ?: return typeArgument
if (capturedType.captureStatus() != CaptureStatus.FOR_SUBTYPING) return typeArgument
return capturedType.typeConstructor().projection()
}
private fun TypeSystemCommonSuperTypesContext.checkRecursion(
originalTypesForCst: List,
typeArgumentsForSuperConstructorParameter: List,
parameter: TypeParameterMarker,
): Boolean {
if (parameter.getVariance() == TypeVariance.IN)
return false // arguments for contravariant parameters are intersected, recursion should not be possible
val originalTypesSet = originalTypesForCst.toSet()
val typeArgumentsTypeSet = typeArgumentsForSuperConstructorParameter.map { it.getType().lowerBoundIfFlexible() }.toSet()
if (originalTypesSet.size != typeArgumentsTypeSet.size)
return false
// only needed in case of captured star projections in argument types
val originalTypeConstructorSet by lazy { typeConstructorsWithExpandedStarProjections(originalTypesSet).toSet() }
for (argumentType in typeArgumentsTypeSet) {
if (argumentType in originalTypesSet) continue
var starProjectionFound = false
for (supertype in supertypesIfCapturedStarProjection(argumentType).orEmpty()) {
if (supertype.lowerBoundIfFlexible().typeConstructor() !in originalTypeConstructorSet)
return false
else starProjectionFound = true
}
if (!starProjectionFound)
return false
}
return true
}
private fun TypeSystemCommonSuperTypesContext.typeConstructorsWithExpandedStarProjections(types: Set) = sequence {
for (type in types) {
if (isCapturedStarProjection(type)) {
for (supertype in supertypesIfCapturedStarProjection(type).orEmpty()) {
yield(supertype.lowerBoundIfFlexible().typeConstructor())
}
} else {
yield(type.typeConstructor())
}
}
}
private fun TypeSystemCommonSuperTypesContext.isCapturedStarProjection(type: SimpleTypeMarker): Boolean =
type.asCapturedType()?.typeConstructor()?.projection()?.isStarProjection() == true
private fun TypeSystemCommonSuperTypesContext.supertypesIfCapturedStarProjection(type: SimpleTypeMarker): Collection? {
val constructor = type.asCapturedType()?.typeConstructor() ?: return null
return if (constructor.projection().isStarProjection())
constructor.supertypes()
else null
}
// no star projections in arguments
private fun TypeSystemCommonSuperTypesContext.calculateArgument(
parameter: TypeParameterMarker,
arguments: List,
depth: Int
): TypeArgumentMarker {
if (depth > 0) {
return createStarProjection(parameter)
}
// Inv, Inv = Inv
if (parameter.getVariance() == TypeVariance.INV && arguments.all { it.getVariance() == TypeVariance.INV }) {
val first = arguments.first()
if (arguments.all { it.getType() == first.getType() }) return first
}
val asOut: Boolean
if (parameter.getVariance() != TypeVariance.INV) {
asOut = parameter.getVariance() == TypeVariance.OUT
} else {
val thereIsOut = arguments.any { it.getVariance() == TypeVariance.OUT }
val thereIsIn = arguments.any { it.getVariance() == TypeVariance.IN }
if (thereIsOut) {
if (thereIsIn) {
// CS(Inv, Inv) = Inv<*>
return createStarProjection(parameter)
} else {
asOut = true
}
} else {
asOut = !thereIsIn
}
}
// CS(Out, Out) = Out
// CS(In, In) = In
// CS(Inv, Inv) = Inv)
if (asOut) {
val argumentTypes = arguments.map { it.getType() }
val parameterIsNotInv = parameter.getVariance() != TypeVariance.INV
if (parameterIsNotInv) {
return commonSuperType(argumentTypes, depth + 1).asTypeArgument()
}
val equalToEachOtherType = arguments.firstOrNull { potentialSuperType ->
arguments.all { AbstractTypeChecker.equalTypes(this, it.getType(), potentialSuperType.getType()) }
}
return if (equalToEachOtherType == null) {
createTypeArgument(commonSuperType(argumentTypes, depth + 1), TypeVariance.OUT)
} else {
val thereIsNotInv = arguments.any { it.getVariance() != TypeVariance.INV }
createTypeArgument(equalToEachOtherType.getType(), if (thereIsNotInv) TypeVariance.OUT else TypeVariance.INV)
}
} else {
val type = intersectTypes(arguments.map { it.getType() })
return if (parameter.getVariance() != TypeVariance.INV) type.asTypeArgument() else createTypeArgument(
type,
TypeVariance.IN
)
}
}
}