From 6ace4164ff4871c34f5111b9ba27f5d62dcb7b01 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 28 Aug 2020 11:25:15 +0300 Subject: [PATCH] [FIR] Split TypeUtils from :resolve to :cones and :tree modules --- .../kotlin/fir/types/ConeTypeUtils.kt | 10 ++- .../fir/types/ConeNullabilityChecker.kt | 19 ++++ .../jetbrains/kotlin/fir/types/TypeUtils.kt | 87 +------------------ .../kotlin/fir/types/FirTypeUtils.kt | 46 ++++++++-- .../kotlin/fir/types/TypeConstructionUtils.kt | 40 +++++++++ 5 files changed, 112 insertions(+), 90 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeNullabilityChecker.kt create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/TypeConstructionUtils.kt diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt index 25b13e92813..f823ed22662 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt @@ -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 is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, isNullable, attributes) is ConeClassErrorType -> this else -> error("Unknown cone type: ${this::class}") -} \ No newline at end of file +} + +fun ConeKotlinType.toTypeProjection(variance: Variance): ConeTypeProjection = + when (variance) { + Variance.INVARIANT -> this + Variance.IN_VARIANCE -> ConeKotlinTypeProjectionIn(this) + Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOut(this) + } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeNullabilityChecker.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeNullabilityChecker.kt new file mode 100644 index 00000000000..ea33025ce58 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeNullabilityChecker.kt @@ -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) + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 4141dd18666..d2dec4d45e0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -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? { 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, - isNullable: Boolean, -): ConeClassLikeType { - return ConeClassLikeTypeImpl(this, typeArguments, isNullable) -} - -fun ClassId.constructClassLikeType( - typeArguments: Array, - isNullable: Boolean, -): ConeClassLikeType { - return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable) -} - -fun ConeClassifierLookupTag.constructType(typeArguments: Array, 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()?.isExtensionFunctionType(session) == true } - -fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean { - val type = this.lowerBoundIfFlexible().fullyExpandedType(session) - return type.attributes.extensionFunctionType != null -} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt index 17ac072b9a4..c19664af276 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt @@ -13,7 +13,8 @@ import org.jetbrains.kotlin.name.ClassId import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract -inline fun FirTypeRef.coneTypeUnsafe() = (this as FirResolvedTypeRef).type as T +inline fun FirTypeRef.coneTypeUnsafe(): T = (this as FirResolvedTypeRef).type as T + @OptIn(ExperimentalContracts::class) inline fun FirTypeRef.coneTypeSafe(): T? { contract { @@ -21,6 +22,7 @@ inline fun 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.computeTypeAttributes(): ConeAttributes { } } return ConeAttributes.create(attributes) -} \ No newline at end of file +} + +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 + } + } +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/TypeConstructionUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/TypeConstructionUtils.kt new file mode 100644 index 00000000000..167a0c9cfe1 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/TypeConstructionUtils.kt @@ -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, + 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, + isNullable: Boolean, +): ConeClassLikeType { + return ConeClassLikeTypeImpl(this, typeArguments, isNullable) +} + +fun ClassId.constructClassLikeType( + typeArguments: Array, + isNullable: Boolean, +): ConeClassLikeType { + return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable) +} +