[FIR] Split TypeUtils from :resolve to :cones and :tree modules

This commit is contained in:
Dmitriy Novozhilov
2020-08-28 11:25:15 +03:00
parent 92ffa4dea9
commit 6ace4164ff
5 changed files with 112 additions and 90 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -40,4 +41,11 @@ fun ConeClassLikeType.withArguments(typeArguments: Array<out ConeTypeProjection>
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, isNullable, attributes)
is ConeClassErrorType -> this
else -> error("Unknown cone type: ${this::class}")
}
}
fun ConeKotlinType.toTypeProjection(variance: Variance): ConeTypeProjection =
when (variance) {
Variance.INVARIANT -> this
Variance.IN_VARIANCE -> ConeKotlinTypeProjectionIn(this)
Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOut(this)
}
@@ -0,0 +1,19 @@
/*
* 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.fir.types
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
object ConeNullabilityChecker {
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
val actualType = with(context) { type.lowerBoundIfFlexible() }
return with(AbstractNullabilityChecker) {
context.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
.hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible)
}
}
}
@@ -7,28 +7,10 @@ package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.Variance
object ConeNullabilityChecker {
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
val actualType = with(context) { type.lowerBoundIfFlexible() }
return with(AbstractNullabilityChecker) {
context.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
.hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible)
}
}
}
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
return when (types.size) {
@@ -57,30 +39,6 @@ fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDe
}
}
fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean =
type.canHaveUndefinedNullability() // TODO: also check nullability
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean {
return when (this) {
is ConeTypeVariableType,
is ConeCapturedType
-> true
is ConeTypeParameterType -> type.isMarkedNullable || !hasNotNullUpperBound()
else -> false
}
}
private fun ConeTypeParameterType.hasNotNullUpperBound(): Boolean {
return lookupTag.typeParameterSymbol.fir.bounds.any {
val boundType = it.coneType
if (boundType is ConeTypeParameterType) {
boundType.hasNotNullUpperBound()
} else {
boundType.nullability == ConeNullability.NOT_NULL
}
}
}
fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(): ConeKotlinType {
if (this is ConeIntersectionType) {
return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull() })
@@ -195,50 +153,11 @@ fun coneFlexibleOrSimpleType(
}
}
fun ConeKotlinType.toTypeProjection(variance: Variance): ConeTypeProjection =
when (variance) {
Variance.INVARIANT -> this
Variance.IN_VARIANCE -> ConeKotlinTypeProjectionIn(this)
Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOut(this)
}
internal fun FirTypeProjection.toConeTypeProjection(): ConeTypeProjection =
when (this) {
is FirStarProjection -> ConeStarProjection
is FirTypeProjectionWithVariance -> {
val type = typeRef.coneType
type.toTypeProjection(this.variance)
}
else -> error("!")
}
fun ConeClassLikeLookupTag.constructClassType(
typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean,
): ConeClassLikeType {
return ConeClassLikeTypeImpl(this, typeArguments, isNullable)
}
fun ClassId.constructClassLikeType(
typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean,
): ConeClassLikeType {
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable)
}
fun ConeClassifierLookupTag.constructType(typeArguments: Array<out ConeTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
return when (this) {
is ConeTypeParameterLookupTag -> ConeTypeParameterTypeImpl(this, isNullable)
is ConeClassLikeLookupTag -> this.constructClassType(typeArguments, isNullable)
else -> error("! ${this::class}")
}
fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean {
val type = this.lowerBoundIfFlexible().fullyExpandedType(session)
return type.attributes.extensionFunctionType != null
}
fun FirTypeRef.isExtensionFunctionType(session: FirSession): Boolean {
return coneTypeSafe<ConeKotlinType>()?.isExtensionFunctionType(session) == true
}
fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean {
val type = this.lowerBoundIfFlexible().fullyExpandedType(session)
return type.attributes.extensionFunctionType != null
}
@@ -13,7 +13,8 @@ import org.jetbrains.kotlin.name.ClassId
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
inline fun <reified T : ConeKotlinType> FirTypeRef.coneTypeUnsafe() = (this as FirResolvedTypeRef).type as T
inline fun <reified T : ConeKotlinType> FirTypeRef.coneTypeUnsafe(): T = (this as FirResolvedTypeRef).type as T
@OptIn(ExperimentalContracts::class)
inline fun <reified T : ConeKotlinType> FirTypeRef.coneTypeSafe(): T? {
contract {
@@ -21,6 +22,7 @@ inline fun <reified T : ConeKotlinType> FirTypeRef.coneTypeSafe(): T? {
}
return (this as? FirResolvedTypeRef)?.type as? T
}
inline val FirTypeRef.coneType: ConeKotlinType get() = coneTypeUnsafe()
val FirTypeRef.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, false)
@@ -59,9 +61,9 @@ val FirFunctionTypeRef.parametersCount: Int
const val EXTENSION_FUNCTION_ANNOTATION = "kotlin/ExtensionFunctionType"
val FirAnnotationCall.isExtensionFunctionAnnotationCall: Boolean
get() = (this as? FirAnnotationCall)?.let {
(it.annotationTypeRef as? FirResolvedTypeRef)?.let {
(it.type as? ConeClassLikeType)?.let {
get() = (this as? FirAnnotationCall)?.let { annotationCall ->
(annotationCall.annotationTypeRef as? FirResolvedTypeRef)?.let { typeRef ->
(typeRef.type as? ConeClassLikeType)?.let {
it.lookupTag.classId.asString() == EXTENSION_FUNCTION_ANNOTATION
}
}
@@ -97,4 +99,38 @@ fun List<FirAnnotationCall>.computeTypeAttributes(): ConeAttributes {
}
}
return ConeAttributes.create(attributes)
}
}
fun FirTypeProjection.toConeTypeProjection(): ConeTypeProjection =
when (this) {
is FirStarProjection -> ConeStarProjection
is FirTypeProjectionWithVariance -> {
val type = typeRef.coneType
type.toTypeProjection(this.variance)
}
else -> error("!")
}
fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean =
type.canHaveUndefinedNullability() // TODO: also check nullability
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean {
return when (this) {
is ConeTypeVariableType,
is ConeCapturedType
-> true
is ConeTypeParameterType -> type.isMarkedNullable || !hasNotNullUpperBound()
else -> false
}
}
private fun ConeTypeParameterType.hasNotNullUpperBound(): Boolean {
return lookupTag.typeParameterSymbol.fir.bounds.any {
val boundType = it.coneType
if (boundType is ConeTypeParameterType) {
boundType.hasNotNullUpperBound()
} else {
boundType.nullability == ConeNullability.NOT_NULL
}
}
}
@@ -0,0 +1,40 @@
/*
* 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.fir.types
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.ClassId
fun ConeClassifierLookupTag.constructType(
typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean
): ConeLookupTagBasedType {
return when (this) {
is ConeTypeParameterLookupTag -> ConeTypeParameterTypeImpl(this, isNullable)
is ConeClassLikeLookupTag -> this.constructClassType(typeArguments, isNullable)
else -> error("! ${this::class}")
}
}
fun ConeClassLikeLookupTag.constructClassType(
typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean,
): ConeClassLikeType {
return ConeClassLikeTypeImpl(this, typeArguments, isNullable)
}
fun ClassId.constructClassLikeType(
typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean,
): ConeClassLikeType {
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable)
}