[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:
Dmitriy Novozhilov
2023-01-18 14:12:11 +02:00
committed by Space Team
parent c98c8d3682
commit c86495dcae
40 changed files with 583 additions and 365 deletions
@@ -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()