[FIR] Introduce ConeFunctionalTypeKind as a replacement of FunctionClassKind
This is needed to provide an ability to extend different kinds of functional types Also, cleanup and rename utilities related to functional types to avoid possible confusions
This commit is contained in:
committed by
Space Team
parent
c98c8d3682
commit
c86495dcae
+2
-2
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.providers.impl
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.NoMutableState
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.functionalTypeService
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -116,7 +116,7 @@ class FirCachingCompositeSymbolProvider(
|
||||
}
|
||||
|
||||
private fun isNameForFunctionClass(classId: ClassId): Boolean {
|
||||
return FunctionClassKind.byClassNamePrefix(classId.packageFqName, classId.shortClassName.asString()) != null
|
||||
return session.functionalTypeService.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString()) != null
|
||||
}
|
||||
|
||||
@OptIn(FirSymbolProviderInternals::class)
|
||||
|
||||
@@ -66,7 +66,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
): SimpleTypeMarker {
|
||||
val attributesList = attributes?.filterIsInstanceTo<ConeAttribute<*>, MutableList<ConeAttribute<*>>>(mutableListOf())
|
||||
val coneAttributes: ConeAttributes = if (isExtensionFunction) {
|
||||
require(constructor is ConeClassLikeLookupTag && constructor.isBuiltinFunctionalType())
|
||||
require(constructor is ConeClassLikeLookupTag && constructor.isSomeFunctionalType(session))
|
||||
// We don't want to create new instance of ConeAttributes which
|
||||
// contains only CompilerConeAttributes.ExtensionFunctionType
|
||||
// to avoid memory consumption
|
||||
@@ -226,7 +226,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.isTypeOrSubtypeOf {
|
||||
(it.lowerBoundIfFlexible() as ConeKotlinType).isBuiltinFunctionalType(session)
|
||||
(it.lowerBoundIfFlexible() as ConeKotlinType).isSomeFunctionalType(session)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
|
||||
override fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
return this.isBuiltinFunctionalType(session)
|
||||
return this.isSomeFunctionalType(session)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean {
|
||||
@@ -519,13 +519,13 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
|
||||
return fullyExpandedType(session).let {
|
||||
val simpleType = it.lowerBoundIfFlexible()
|
||||
if ((simpleType as ConeKotlinType).isBuiltinFunctionalType(session))
|
||||
if ((simpleType as ConeKotlinType).isSomeFunctionalType(session))
|
||||
this
|
||||
else {
|
||||
var functionalSupertype: KotlinTypeMarker? = null
|
||||
simpleType.anySuperTypeConstructor { type ->
|
||||
simpleType.fastCorrespondingSupertypes(type.typeConstructor())?.any { superType ->
|
||||
val isFunctional = (superType as ConeKotlinType).isBuiltinFunctionalType(session)
|
||||
val isFunctional = (superType as ConeKotlinType).isSomeFunctionalType(session)
|
||||
if (isFunctional)
|
||||
functionalSupertype = superType
|
||||
isFunctional
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
||||
|
||||
// ---------------------------------------------- is type is a functional type ----------------------------------------------
|
||||
|
||||
fun ConeKotlinType.functionalTypeKind(session: FirSession): ConeFunctionalTypeKind? {
|
||||
if (this !is ConeClassLikeType) return null
|
||||
return fullyExpandedType(session).lookupTag.functionalTypeKind(session)
|
||||
}
|
||||
|
||||
private fun ConeClassLikeLookupTag.functionalTypeKind(session: FirSession): ConeFunctionalTypeKind? {
|
||||
val classId = classId
|
||||
return session.functionalTypeService.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString())
|
||||
}
|
||||
|
||||
private inline fun ConeKotlinType.isFunctionalTypeWithPredicate(
|
||||
session: FirSession,
|
||||
errorOnNotFunctionalType: Boolean = false,
|
||||
predicate: (ConeFunctionalTypeKind) -> Boolean
|
||||
): Boolean {
|
||||
val kind = functionalTypeKind(session)
|
||||
?: if (errorOnNotFunctionalType) error("$this is not a functional type") else return false
|
||||
return predicate(kind)
|
||||
}
|
||||
|
||||
// Function
|
||||
fun ConeKotlinType.isSimpleFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalTypeWithPredicate(session) { it == ConeFunctionalTypeKind.Function }
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, [Custom]Function
|
||||
fun ConeKotlinType.isNonReflectFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalTypeWithPredicate(session) { !it.isReflectType }
|
||||
}
|
||||
|
||||
// SuspendFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalTypeWithPredicate(session) {
|
||||
it == ConeFunctionalTypeKind.SuspendFunction || it == ConeFunctionalTypeKind.KSuspendFunction
|
||||
}
|
||||
}
|
||||
|
||||
// KFunction, KSuspendFunction, K[Custom]Function
|
||||
fun ConeKotlinType.isReflectFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalTypeWithPredicate(session) { it.isReflectType }
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, [Custom]Function, KFunction, KSuspendFunction, K[Custom]Function
|
||||
fun ConeKotlinType.isSomeFunctionalType(session: FirSession): Boolean {
|
||||
return functionalTypeKind(session) != null
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, [Custom]Function, KFunction, KSuspendFunction, K[Custom]Function
|
||||
fun ConeClassLikeLookupTag.isSomeFunctionalType(session: FirSession): Boolean {
|
||||
return functionalTypeKind(session) != null
|
||||
}
|
||||
|
||||
// Function, KFunction
|
||||
private fun ConeKotlinType.isSimpleFunctionalType(session: FirSession, errorOnNotFunctionalType: Boolean): Boolean {
|
||||
return isFunctionalTypeWithPredicate(session, errorOnNotFunctionalType) {
|
||||
it == ConeFunctionalTypeKind.Function || it == ConeFunctionalTypeKind.KFunction
|
||||
}
|
||||
}
|
||||
|
||||
// SuspendFunction, [Custom]Function, KSuspendFunction, K[Custom]Function
|
||||
private fun ConeKotlinType.isNotSimpleFunctionalType(session: FirSession): Boolean {
|
||||
return !isSimpleFunctionalType(session, errorOnNotFunctionalType = false)
|
||||
}
|
||||
|
||||
// ---------------------------------------------- functional type conversions ----------------------------------------------
|
||||
|
||||
/*
|
||||
* SuspendFunction/[Custom]Function -> Function
|
||||
* KSuspendFunction/K[Custom]Function -> KFunction
|
||||
*/
|
||||
fun ConeKotlinType.customFunctionalTypeToSimpleFunctionalType(session: FirSession): ConeClassLikeType {
|
||||
val kind = functionalTypeKind(session)
|
||||
require(kind != null && kind != ConeFunctionalTypeKind.Function && kind != ConeFunctionalTypeKind.KFunction)
|
||||
val newKind = if (kind.isReflectType) {
|
||||
ConeFunctionalTypeKind.KFunction
|
||||
} else {
|
||||
ConeFunctionalTypeKind.Function
|
||||
}
|
||||
return createFunctionalTypeWithNewKind(newKind)
|
||||
}
|
||||
|
||||
/*
|
||||
* KFunction -> Function
|
||||
* KSuspendFunction -> SuspendFunction
|
||||
* K[Custom]Function -> [Custom]Function
|
||||
*/
|
||||
fun ConeKotlinType.reflectFunctionalTypeToNonReflectFunctionalType(session: FirSession): ConeClassLikeType {
|
||||
val kind = functionalTypeKind(session)
|
||||
require(kind != null && kind.isReflectType)
|
||||
return createFunctionalTypeWithNewKind(kind.nonReflectKind())
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.createFunctionalTypeWithNewKind(kind: ConeFunctionalTypeKind): ConeClassLikeType {
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
|
||||
return functionalTypeId.toLookupTag().constructClassType(typeArguments, isNullable = false, attributes = attributes)
|
||||
}
|
||||
|
||||
// ---------------------------------------------- functional type subtyping ----------------------------------------------
|
||||
|
||||
// expectedFunctionalType is kotlin.FunctionN or kotlin.reflect.KFunctionN
|
||||
fun ConeKotlinType.findSubtypeOfSimpleFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
|
||||
require(expectedFunctionalType.isSimpleFunctionalType(session, errorOnNotFunctionalType = true))
|
||||
return findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.findSubtypeOfSimpleFunctionalTypeImpl(
|
||||
session: FirSession,
|
||||
expectedFunctionalType: ConeClassLikeType
|
||||
): ConeKotlinType? {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> {
|
||||
// Expect the argument type is a simple functional type.
|
||||
when {
|
||||
isNotSimpleFunctionalType(session) -> null
|
||||
isSubtypeOfFunctionalType(session, expectedFunctionalType) -> this
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
is ConeIntersectionType -> {
|
||||
runUnless(intersectedTypes.any { it.isNotSimpleFunctionalType(session) }) {
|
||||
intersectedTypes.find { it.findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType) != null }
|
||||
}
|
||||
}
|
||||
|
||||
is ConeTypeParameterType -> {
|
||||
val bounds = lookupTag.typeParameterSymbol.resolvedBounds.map { it.coneType }
|
||||
runUnless(bounds.any { it.isNotSimpleFunctionalType(session) }) {
|
||||
bounds.find { it.findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType) != null }
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
|
||||
}
|
||||
|
||||
// ---------------------------------------------- functional type scope utils ----------------------------------------------
|
||||
|
||||
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirNamedFunctionSymbol? {
|
||||
require(this.isSomeFunctionalType(session))
|
||||
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass) ?: return null
|
||||
var baseInvokeSymbol: FirNamedFunctionSymbol? = null
|
||||
functionN.unsubstitutedScope(
|
||||
session,
|
||||
scopeSession,
|
||||
withForcedTypeCalculator = false
|
||||
).processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
baseInvokeSymbol = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
return baseInvokeSymbol
|
||||
}
|
||||
|
||||
fun ConeKotlinType.findContributedInvokeSymbol(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
expectedFunctionalType: ConeClassLikeType,
|
||||
shouldCalculateReturnTypesOfFakeOverrides: Boolean
|
||||
): FirFunctionSymbol<*>? {
|
||||
val baseInvokeSymbol = expectedFunctionalType.findBaseInvokeSymbol(session, scopeSession) ?: return null
|
||||
|
||||
val fakeOverrideTypeCalculator = if (shouldCalculateReturnTypesOfFakeOverrides) {
|
||||
FakeOverrideTypeCalculator.Forced
|
||||
} else {
|
||||
FakeOverrideTypeCalculator.DoNothing
|
||||
}
|
||||
val scope = scope(session, scopeSession, fakeOverrideTypeCalculator, requiredPhase = FirResolvePhase.STATUS) ?: return null
|
||||
var declaredInvoke: FirNamedFunctionSymbol? = null
|
||||
scope.processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
if (functionSymbol.fir.valueParameters.size == baseInvokeSymbol.fir.valueParameters.size) {
|
||||
declaredInvoke = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
}
|
||||
|
||||
var overriddenInvoke: FirFunctionSymbol<*>? = null
|
||||
if (declaredInvoke != null) {
|
||||
// Make sure the user-contributed or type-substituted invoke we just found above is an override of base invoke.
|
||||
scope.processOverriddenFunctions(declaredInvoke!!) { functionSymbol ->
|
||||
if (functionSymbol == baseInvokeSymbol || functionSymbol.originalForSubstitutionOverride == baseInvokeSymbol) {
|
||||
overriddenInvoke = functionSymbol
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (overriddenInvoke != null) declaredInvoke else null
|
||||
}
|
||||
|
||||
// ---------------------------------------------- functional type type argument extraction ----------------------------------------------
|
||||
|
||||
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
|
||||
if (!isSomeFunctionalType(session) || !isExtensionFunctionType(session)) return null
|
||||
return fullyExpandedType(session).let { expanded ->
|
||||
expanded.typeArguments[expanded.contextReceiversNumberForFunctionType].typeOrDefault(session.builtinTypes.nothingType.type)
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
|
||||
require(this is ConeClassLikeType)
|
||||
// TODO: add requirement
|
||||
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
|
||||
require(this is ConeClassLikeType)
|
||||
// TODO: add requirement
|
||||
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType = when (this) {
|
||||
is ConeKotlinTypeProjection -> type
|
||||
is ConeStarProjection -> default
|
||||
}
|
||||
@@ -5,27 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@@ -50,203 +35,10 @@ fun ConeKotlinType.isKMutableProperty(session: FirSession): Boolean {
|
||||
classId.shortClassName.identifier.startsWith("KMutableProperty")
|
||||
}
|
||||
|
||||
fun ConeKotlinType.functionClassKind(session: FirSession): FunctionClassKind? {
|
||||
return classId(session)?.toFunctionClassKind()
|
||||
}
|
||||
|
||||
private fun ClassId.toFunctionClassKind(): FunctionClassKind? {
|
||||
return FunctionClassKind.byClassNamePrefix(packageFqName, relativeClassName.asString())
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, KFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
|
||||
return functionClassKind(session) != null
|
||||
}
|
||||
|
||||
// Function, SuspendFunction, KFunction, KSuspendFunction
|
||||
fun ConeClassLikeLookupTag.isBuiltinFunctionalType(): Boolean {
|
||||
return classId.toFunctionClassKind() != null
|
||||
}
|
||||
|
||||
inline fun ConeKotlinType.isFunctionalType(session: FirSession, predicate: (FunctionClassKind) -> Boolean): Boolean {
|
||||
val kind = functionClassKind(session) ?: return false
|
||||
return predicate(kind)
|
||||
}
|
||||
|
||||
// Function
|
||||
fun ConeKotlinType.isFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.Function }
|
||||
}
|
||||
|
||||
// Function, SuspendFunction
|
||||
fun ConeKotlinType.isFunctionalOrSuspendFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.Function || it == FunctionClassKind.SuspendFunction }
|
||||
}
|
||||
|
||||
// SuspendFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isSuspendOrKSuspendFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it.isSuspendType }
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.SuspendFunction }
|
||||
}
|
||||
|
||||
// KFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isKFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it.isReflectType }
|
||||
}
|
||||
|
||||
fun ConeKotlinType.kFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
|
||||
require(this.isKFunctionType(session))
|
||||
val kind =
|
||||
if (isSuspendOrKSuspendFunctionType(session)) FunctionClassKind.SuspendFunction
|
||||
else FunctionClassKind.Function
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
|
||||
return ConeClassLikeTypeImpl(functionalTypeId.toLookupTag(), typeArguments, isNullable = false)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.suspendFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
|
||||
require(this.isSuspendOrKSuspendFunctionType(session))
|
||||
val kind =
|
||||
if (isKFunctionType(session)) FunctionClassKind.KFunction
|
||||
else FunctionClassKind.Function
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
|
||||
return ConeClassLikeTypeImpl(functionalTypeId.toLookupTag(), typeArguments, isNullable = false, attributes = attributes)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: FirSession, continuationClassId: ClassId): ConeClassLikeType {
|
||||
require(this.isSuspendOrKSuspendFunctionType(session))
|
||||
val kind =
|
||||
if (isKFunctionType(session)) FunctionClassKind.KFunction
|
||||
else FunctionClassKind.Function
|
||||
val fullyExpandedType = type.fullyExpandedType(session)
|
||||
val typeArguments = fullyExpandedType.typeArguments
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size))
|
||||
val lastTypeArgument = typeArguments.last()
|
||||
return ConeClassLikeTypeImpl(
|
||||
functionalTypeId.toLookupTag(),
|
||||
typeArguments = (typeArguments.dropLast(1) + continuationClassId.toLookupTag().constructClassType(
|
||||
arrayOf(lastTypeArgument),
|
||||
isNullable = false
|
||||
) + lastTypeArgument).toTypedArray(),
|
||||
isNullable = fullyExpandedType.isNullable,
|
||||
attributes = fullyExpandedType.attributes
|
||||
)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): Boolean {
|
||||
require(expectedFunctionalType.isBuiltinFunctionalType(session))
|
||||
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
|
||||
}
|
||||
|
||||
fun ConeKotlinType.findSubtypeOfNonSuspendFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
|
||||
require(expectedFunctionalType.isBuiltinFunctionalType(session) && !expectedFunctionalType.isSuspendOrKSuspendFunctionType(session))
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> {
|
||||
// Expect the argument type is not a suspend functional type.
|
||||
if (isSuspendOrKSuspendFunctionType(session) || !isSubtypeOfFunctionalType(session, expectedFunctionalType))
|
||||
null
|
||||
else
|
||||
this
|
||||
}
|
||||
is ConeIntersectionType -> {
|
||||
if (intersectedTypes.any { it.isSuspendOrKSuspendFunctionType(session) })
|
||||
null
|
||||
else
|
||||
intersectedTypes.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
|
||||
}
|
||||
is ConeTypeParameterType -> {
|
||||
val bounds = lookupTag.typeParameterSymbol.resolvedBounds.map { it.coneType }
|
||||
if (bounds.any { it.isSuspendOrKSuspendFunctionType(session) })
|
||||
null
|
||||
else
|
||||
bounds.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirNamedFunctionSymbol? {
|
||||
require(this.isBuiltinFunctionalType(session))
|
||||
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass) ?: return null
|
||||
var baseInvokeSymbol: FirNamedFunctionSymbol? = null
|
||||
functionN.unsubstitutedScope(
|
||||
session,
|
||||
scopeSession,
|
||||
withForcedTypeCalculator = false
|
||||
).processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
baseInvokeSymbol = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
return baseInvokeSymbol
|
||||
}
|
||||
|
||||
fun ConeKotlinType.findContributedInvokeSymbol(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
expectedFunctionalType: ConeClassLikeType,
|
||||
shouldCalculateReturnTypesOfFakeOverrides: Boolean
|
||||
): FirFunctionSymbol<*>? {
|
||||
val baseInvokeSymbol = expectedFunctionalType.findBaseInvokeSymbol(session, scopeSession) ?: return null
|
||||
|
||||
val fakeOverrideTypeCalculator = if (shouldCalculateReturnTypesOfFakeOverrides) {
|
||||
FakeOverrideTypeCalculator.Forced
|
||||
} else {
|
||||
FakeOverrideTypeCalculator.DoNothing
|
||||
}
|
||||
val scope = scope(session, scopeSession, fakeOverrideTypeCalculator, requiredPhase = null) ?: return null
|
||||
var declaredInvoke: FirNamedFunctionSymbol? = null
|
||||
scope.processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
|
||||
if (functionSymbol.fir.valueParameters.size == baseInvokeSymbol.fir.valueParameters.size) {
|
||||
declaredInvoke = functionSymbol
|
||||
return@processFunctionsByName
|
||||
}
|
||||
}
|
||||
|
||||
var overriddenInvoke: FirFunctionSymbol<*>? = null
|
||||
if (declaredInvoke != null) {
|
||||
// Make sure the user-contributed or type-substituted invoke we just found above is an override of base invoke.
|
||||
scope.processOverriddenFunctions(declaredInvoke!!) { functionSymbol ->
|
||||
if (functionSymbol == baseInvokeSymbol || functionSymbol.originalForSubstitutionOverride == baseInvokeSymbol) {
|
||||
overriddenInvoke = functionSymbol
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (overriddenInvoke != null) declaredInvoke else null
|
||||
}
|
||||
|
||||
fun ConeKotlinType.isKClassType(): Boolean {
|
||||
return classId == StandardClassIds.KClass
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType =
|
||||
when (this) {
|
||||
is ConeKotlinTypeProjection -> type
|
||||
is ConeStarProjection -> default
|
||||
}
|
||||
|
||||
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
|
||||
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
|
||||
return fullyExpandedType(session).let { expanded ->
|
||||
expanded.typeArguments[expanded.contextReceiversNumberForFunctionType].typeOrDefault(session.builtinTypes.nothingType.type)
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
|
||||
require(this is ConeClassLikeType)
|
||||
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
|
||||
require(this is ConeClassLikeType)
|
||||
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
|
||||
}
|
||||
|
||||
val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe()
|
||||
val FirAnonymousFunction.receiverType: ConeKotlinType? get() = receiverParameter?.typeRef?.coneTypeSafe()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user