[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
+8
-1
@@ -33,7 +33,14 @@ internal class KtFirTypeInfoProvider(
|
||||
|
||||
override fun getFunctionClassKind(type: KtType): FunctionClassKind? {
|
||||
val coneType = (type as KtFirType).coneType
|
||||
return coneType.functionClassKind(analysisSession.useSiteSession)
|
||||
return when (coneType.functionalTypeKind(analysisSession.useSiteSession)) {
|
||||
ConeFunctionalTypeKind.Function -> FunctionClassKind.Function
|
||||
ConeFunctionalTypeKind.KFunction -> FunctionClassKind.KFunction
|
||||
ConeFunctionalTypeKind.SuspendFunction -> FunctionClassKind.SuspendFunction
|
||||
ConeFunctionalTypeKind.KSuspendFunction -> FunctionClassKind.KSuspendFunction
|
||||
null -> null
|
||||
else -> null // TODO: consider handling of custom functional type kinds from plugins
|
||||
}
|
||||
}
|
||||
|
||||
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull
|
||||
|
||||
+3
-2
@@ -49,9 +49,10 @@ internal class KtFirFunctionalType(
|
||||
|
||||
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
|
||||
|
||||
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendOrKSuspendFunctionType(builder.rootSession) }
|
||||
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendFunctionType(builder.rootSession) }
|
||||
|
||||
override val isReflectType: Boolean get() = withValidityAssertion { coneType.isKFunctionType(builder.rootSession) }
|
||||
override val isReflectType: Boolean
|
||||
get() = withValidityAssertion { coneType.functionalTypeKind(builder.rootSession)?.isReflectType == true }
|
||||
|
||||
override val arity: Int
|
||||
get() = withValidityAssertion {
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType
|
||||
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.name.JvmNames.SYNCHRONIZED_ANNOTATION_CLASS_ID
|
||||
|
||||
object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
|
||||
@@ -33,7 +33,7 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
|
||||
return
|
||||
}
|
||||
if (declaration.isSuspend ||
|
||||
(declaration as? FirAnonymousFunction)?.typeRef?.coneType?.isSuspendOrKSuspendFunctionType(session) == true
|
||||
(declaration as? FirAnonymousFunction)?.typeRef?.coneType?.isSuspendFunctionType(session) == true
|
||||
) {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_SUSPEND, context)
|
||||
return
|
||||
@@ -46,4 +46,4 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -278,7 +278,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
|
||||
}
|
||||
|
||||
private fun FirTypeRef?.isFunctionalTypeRef(session: FirSession): Boolean {
|
||||
return this?.coneType?.isBuiltinFunctionalType(session) == true
|
||||
return this?.coneType?.isSomeFunctionalType(session) == true
|
||||
}
|
||||
|
||||
private fun FirContractDescription?.getParameterCallsEffectDeclaration(index: Int): ConeCallsEffectDeclaration? {
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ internal fun checkConstantArguments(
|
||||
}
|
||||
expression is FirQualifiedAccessExpression -> {
|
||||
val expressionType = expression.typeRef.coneType
|
||||
if (expressionType.isKFunctionType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(session)) {
|
||||
if (expressionType.isReflectFunctionalType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(session)) {
|
||||
return checkConstantArguments(expression.dispatchReceiver, session)
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD
|
||||
import org.jetbrains.kotlin.builtins.functions.isSuspendType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -61,7 +62,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
val inalienableParameters = function.valueParameters.filter {
|
||||
if (it.isNoinline) return@filter false
|
||||
val type = it.returnTypeRef.coneType
|
||||
!type.isMarkedNullable && type.isFunctionalType(context.session) { kind -> !kind.isReflectType }
|
||||
!type.isMarkedNullable && type.isNonReflectFunctionalType(context.session)
|
||||
}.map { it.symbol }
|
||||
|
||||
val visitor = inlineVisitor(
|
||||
@@ -233,7 +234,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
// TODO: receivers are currently not inline (KT-5837)
|
||||
// if (targetSymbol.isInline) return true
|
||||
return targetSymbol.name == OperatorNameConventions.INVOKE &&
|
||||
targetSymbol.dispatchReceiverType?.isBuiltinFunctionalType(session) == true
|
||||
targetSymbol.dispatchReceiverType?.isSomeFunctionalType(session) == true
|
||||
}
|
||||
|
||||
private fun checkQualifiedAccess(
|
||||
@@ -404,8 +405,9 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
) {
|
||||
for (param in function.valueParameters) {
|
||||
val coneType = param.returnTypeRef.coneType
|
||||
val isFunctionalType = coneType.isFunctionalType(context.session)
|
||||
val isSuspendFunctionalType = coneType.isSuspendOrKSuspendFunctionType(context.session)
|
||||
val functionalKind = coneType.functionalTypeKind(context.session)
|
||||
val isFunctionalType = functionalKind != null
|
||||
val isSuspendFunctionalType = functionalKind?.isSuspendType == true
|
||||
val defaultValue = param.defaultValue
|
||||
|
||||
if (!(isFunctionalType || isSuspendFunctionalType) && (param.isNoinline || param.isCrossinline)) {
|
||||
@@ -488,7 +490,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
function.valueParameters.any { param ->
|
||||
val type = param.returnTypeRef.coneType
|
||||
!param.isNoinline && !type.isNullable
|
||||
&& (type.isFunctionalType(session) || type.isSuspendOrKSuspendFunctionType(session))
|
||||
&& (type.isSimpleFunctionType(session) || type.isSuspendFunctionType(session))
|
||||
}
|
||||
if (hasInlinableParameters) return
|
||||
if (function.isInlineOnly(session)) return
|
||||
|
||||
+2
-2
@@ -130,7 +130,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||
private fun findEnclosingSuspendFunction(context: CheckerContext): FirFunction? {
|
||||
return context.containingDeclarations.lastOrNull {
|
||||
when (it) {
|
||||
is FirAnonymousFunction -> it.typeRef.coneType.isSuspendOrKSuspendFunctionType(context.session)
|
||||
is FirAnonymousFunction -> it.typeRef.coneType.isSuspendFunctionType(context.session)
|
||||
is FirSimpleFunction -> it.isSuspend
|
||||
else -> false
|
||||
}
|
||||
@@ -218,7 +218,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||
calledDeclarationSymbol: FirCallableSymbol<*>
|
||||
): Triple<FirExpression?, FirExpression?, ConeKotlinType?> {
|
||||
if (this is FirImplicitInvokeCall &&
|
||||
dispatchReceiver != FirNoReceiverExpression && dispatchReceiver.typeRef.coneType.isSuspendOrKSuspendFunctionType(session)
|
||||
dispatchReceiver != FirNoReceiverExpression && dispatchReceiver.typeRef.coneType.isSuspendFunctionType(session)
|
||||
) {
|
||||
val variableForInvoke = dispatchReceiver
|
||||
val variableForInvokeType = variableForInvoke.typeRef.coneType
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isFunctionalType
|
||||
import org.jetbrains.kotlin.fir.types.isSimpleFunctionType
|
||||
|
||||
object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
|
||||
@@ -278,7 +278,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
val reference = node.fir.calleeReference.resolved ?: return dataForNode
|
||||
val functionSymbol = reference.resolvedSymbol as? FirFunctionSymbol<*> ?: return dataForNode
|
||||
val symbol = if (functionSymbol.callableId.callableName.identifier == "invoke") {
|
||||
localProperties.find { it.name == reference.name && it.resolvedReturnTypeRef.coneType.isFunctionalType(session) }
|
||||
localProperties.find { it.name == reference.name && it.resolvedReturnTypeRef.coneType.isSimpleFunctionType(session) }
|
||||
} else null
|
||||
symbol ?: return dataForNode
|
||||
|
||||
|
||||
+4
-4
@@ -7,15 +7,15 @@ package org.jetbrains.kotlin.fir.analysis.checkers.type
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.fir.types.isSomeFunctionalType
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object FirTypeAnnotationChecker : FirTypeRefChecker() {
|
||||
@@ -33,7 +33,7 @@ object FirTypeAnnotationChecker : FirTypeRefChecker() {
|
||||
}
|
||||
}
|
||||
if (annotation.toAnnotationClassId(context.session) == StandardClassIds.Annotations.ExtensionFunctionType) {
|
||||
if (!typeRef.type.isBuiltinFunctionalType(context.session)) {
|
||||
if (!typeRef.type.isSomeFunctionalType(context.session)) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidExtensionFunctionTypeOnNonFunctionTypes)) {
|
||||
reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE, context)
|
||||
} else {
|
||||
|
||||
@@ -5,21 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
open class ConeTypeRenderer() {
|
||||
open class ConeTypeRenderer {
|
||||
|
||||
lateinit var builder: StringBuilder
|
||||
lateinit var idRenderer: ConeIdRenderer
|
||||
|
||||
open fun renderAsPossibleFunctionType(
|
||||
type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit = { render() }
|
||||
type: ConeKotlinType,
|
||||
functionalClassKindExtractor: (ConeKotlinType) -> ConeFunctionalTypeKind?,
|
||||
renderType: ConeTypeProjection.() -> Unit = { render() }
|
||||
) {
|
||||
val kind = type.functionTypeKind
|
||||
if (!kind.withPrettyRender()) {
|
||||
val kind = functionalClassKindExtractor(type)
|
||||
if (kind?.isReflectType != false) {
|
||||
type.renderType()
|
||||
return
|
||||
}
|
||||
@@ -27,8 +26,9 @@ open class ConeTypeRenderer() {
|
||||
if (type.isMarkedNullable) {
|
||||
builder.append("(")
|
||||
}
|
||||
if (kind == FunctionClassKind.SuspendFunction) {
|
||||
builder.append("suspend ")
|
||||
kind.prefixForTypeRender?.let {
|
||||
builder.append(it)
|
||||
builder.append(" ")
|
||||
}
|
||||
val typeArguments = type.typeArguments
|
||||
val isExtension = type.isExtensionFunctionType
|
||||
@@ -57,14 +57,6 @@ open class ConeTypeRenderer() {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
private fun FunctionClassKind?.withPrettyRender(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@withPrettyRender != null)
|
||||
}
|
||||
return this != null && this != FunctionClassKind.KSuspendFunction && this != FunctionClassKind.KFunction
|
||||
}
|
||||
|
||||
fun render(type: ConeKotlinType) {
|
||||
if (type !is ConeFlexibleType && type !is ConeDefinitelyNotNullType) {
|
||||
// We don't render attributes for flexible/definitely not null types here,
|
||||
@@ -216,4 +208,4 @@ open class ConeTypeRenderer() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.fir.types.ConeFunctionalTypeKind
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
|
||||
|
||||
@@ -16,9 +17,13 @@ class ConeTypeRendererForDebugging() : ConeTypeRenderer() {
|
||||
idRenderer.builder = builder
|
||||
}
|
||||
|
||||
override fun renderAsPossibleFunctionType(type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit) {
|
||||
override fun renderAsPossibleFunctionType(
|
||||
type: ConeKotlinType,
|
||||
functionalClassKindExtractor: (ConeKotlinType) -> ConeFunctionalTypeKind?,
|
||||
renderType: ConeTypeProjection.() -> Unit
|
||||
) {
|
||||
builder.append("R|")
|
||||
super.renderAsPossibleFunctionType(type, renderType)
|
||||
super.renderAsPossibleFunctionType(type, functionalClassKindExtractor, renderType)
|
||||
builder.append("|")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* [ConeFunctionalTypeKind] describes a family of various similar functional types (like kotlin.FunctionN)
|
||||
* All types in the same family have corresponding shape of classId: [packageFqName].[classNamePrefix]N,
|
||||
* where `N` is an arity of function
|
||||
*
|
||||
* Functional type kind may be either reflect type or non-reflect type
|
||||
* Each non-reflect kind should have corresponding reflect kind and vice-versa (like `kotlin.FunctionN` and `kotlin.reflection.KFunctionN`)
|
||||
*
|
||||
* Classes for such functional types are synthetic and generated by compiler itself
|
||||
* [annotationOnInvokeClassId] is a classId of annotation, which will be added to `invoke` function of generated
|
||||
* functional interface. This argument is mandatory for non-standard functional kinds
|
||||
*
|
||||
* Assume we have `some.CustomFunctionN` and `some.KCustomFunctionN` families with [annotationOnInvokeClassId] = /some.Anno
|
||||
* Classes for those kinds will look like this:
|
||||
*
|
||||
* interface CustomFunctionN<P1, P2, ..., PN, R> : kotlin.Function<R> {
|
||||
* @some.Anno
|
||||
* operator fun invoke(p1: P1, p2: P2, ..., pN: PN): R
|
||||
* }
|
||||
*
|
||||
* interface KCustomFunctionN<P1, P2, ..., PN, R> : kotlin.reflect.KFunction<R>, some.CustomFunctionN<P1, P2, ..., PN, R> {
|
||||
* @some.Anno
|
||||
* override operator fun invoke(p1: P1, p2: P2, ..., pN: PN): R
|
||||
* }
|
||||
*
|
||||
* Note that if you provide some new functional type kind it's your responsibility to handle all references to it in backend
|
||||
* with [IrGenerationExtension] implementation
|
||||
*/
|
||||
abstract class ConeFunctionalTypeKind internal constructor(
|
||||
val packageFqName: FqName,
|
||||
val classNamePrefix: String,
|
||||
val isReflectType: Boolean,
|
||||
val annotationOnInvokeClassId: ClassId?
|
||||
) {
|
||||
/*
|
||||
* This constructor is needed to enforce not nullable [annotationOnInvokeClassId] for
|
||||
* functional kinds provided by compiler plugins
|
||||
*/
|
||||
constructor(
|
||||
packageFqName: FqName,
|
||||
classNamePrefix: String,
|
||||
annotationOnInvokeClassId: ClassId,
|
||||
isReflectType: Boolean
|
||||
) : this(packageFqName, classNamePrefix, isReflectType, annotationOnInvokeClassId)
|
||||
|
||||
/*
|
||||
* Specifies how corresponding type will be rendered
|
||||
* E.g. if `prefixForTypeRender = @Some` and type is `some.CustomFunction2<Int, String, Double>`,
|
||||
* then type will be rendered as `@Some (Int, String) -> Double`
|
||||
*/
|
||||
open val prefixForTypeRender: String?
|
||||
get() = null
|
||||
|
||||
/**
|
||||
* @return corresponding non-reflect kind for reflect kind
|
||||
* @return [this] if [isReflectType] is false
|
||||
*
|
||||
* Should be overridden for reflect kinds
|
||||
*/
|
||||
open fun nonReflectKind(): ConeFunctionalTypeKind {
|
||||
return if (isReflectType) error("Should be overridden explicitly") else this
|
||||
}
|
||||
|
||||
/**
|
||||
* @return corresponding reflect kind for non-reflect kind
|
||||
* @return [this] if [isReflectType] is true
|
||||
*
|
||||
* Should be overridden for non reflect kinds
|
||||
*/
|
||||
open fun reflectKind(): ConeFunctionalTypeKind {
|
||||
return if (isReflectType) this else error("Should be overridden explicitly")
|
||||
}
|
||||
|
||||
fun numberedClassName(arity: Int): Name = Name.identifier("$classNamePrefix$arity")
|
||||
|
||||
// ------------------------------------------- Builtin functional kinds -------------------------------------------
|
||||
|
||||
object Function : ConeFunctionalTypeKind(
|
||||
StandardNames.BUILT_INS_PACKAGE_FQ_NAME,
|
||||
"Function",
|
||||
isReflectType = false,
|
||||
annotationOnInvokeClassId = null
|
||||
) {
|
||||
override fun reflectKind(): ConeFunctionalTypeKind = KFunction
|
||||
}
|
||||
|
||||
object SuspendFunction : ConeFunctionalTypeKind(
|
||||
StandardNames.COROUTINES_PACKAGE_FQ_NAME,
|
||||
"SuspendFunction",
|
||||
isReflectType = false,
|
||||
annotationOnInvokeClassId = null
|
||||
) {
|
||||
override val prefixForTypeRender: String
|
||||
get() = "suspend"
|
||||
|
||||
override fun reflectKind(): ConeFunctionalTypeKind = KSuspendFunction
|
||||
}
|
||||
|
||||
object KFunction : ConeFunctionalTypeKind(
|
||||
StandardNames.KOTLIN_REFLECT_FQ_NAME,
|
||||
"KFunction",
|
||||
isReflectType = true,
|
||||
annotationOnInvokeClassId = null
|
||||
) {
|
||||
override fun nonReflectKind(): ConeFunctionalTypeKind = Function
|
||||
}
|
||||
|
||||
object KSuspendFunction : ConeFunctionalTypeKind(
|
||||
StandardNames.KOTLIN_REFLECT_FQ_NAME,
|
||||
"KSuspendFunction",
|
||||
isReflectType = true,
|
||||
annotationOnInvokeClassId = null
|
||||
) {
|
||||
override fun nonReflectKind(): ConeFunctionalTypeKind = SuspendFunction
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.renderer.*
|
||||
import org.jetbrains.kotlin.fir.renderer.ConeIdRendererForDebugging
|
||||
import org.jetbrains.kotlin.fir.renderer.ConeIdShortRenderer
|
||||
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging
|
||||
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererWithJavaFlexibleTypes
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -111,14 +113,6 @@ fun ConeClassLikeType.replaceArgumentsWithStarProjections(): ConeClassLikeType {
|
||||
return withArguments(newArguments)
|
||||
}
|
||||
|
||||
val ConeKotlinType?.functionTypeKind: FunctionClassKind?
|
||||
get() {
|
||||
val classId = (this as? ConeClassLikeType)?.lookupTag?.classId ?: return null
|
||||
return FunctionClassKind.getFunctionalClassKind(
|
||||
classId.shortClassName.asString(), classId.packageFqName
|
||||
)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.renderForDebugging(): String {
|
||||
val builder = StringBuilder()
|
||||
ConeTypeRendererForDebugging(builder).render(this)
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntersectionOverrideStorage
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirSubstitutionOverrideStorage
|
||||
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver
|
||||
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionalTypeKindService
|
||||
import org.jetbrains.kotlin.fir.types.TypeComponents
|
||||
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
@@ -71,6 +72,9 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
|
||||
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
|
||||
register(FirOverrideService::class, FirOverrideService(this))
|
||||
register(FirDynamicMembersStorage::class, FirDynamicMembersStorage(this))
|
||||
|
||||
// TODO: replace with proper implementation
|
||||
register(FirFunctionalTypeKindService::class, FirFunctionalTypeKindService.Default)
|
||||
}
|
||||
|
||||
@OptIn(SessionConfiguration::class)
|
||||
|
||||
+36
-52
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.providers.impl
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
@@ -25,16 +24,15 @@ import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer
|
||||
import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer
|
||||
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
|
||||
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.constructClassType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.toLookupTag
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
|
||||
@@ -53,7 +51,7 @@ open class FirBuiltinSymbolProvider(
|
||||
val kotlinScopeProvider: FirKotlinScopeProvider
|
||||
) : FirSymbolProvider(session) {
|
||||
private val allPackageFragments = loadBuiltIns().groupBy { it.fqName }
|
||||
private val syntheticFunctionalInterfaceCache = SyntheticFunctionalInterfaceCache(moduleData, kotlinScopeProvider)
|
||||
private val syntheticFunctionalInterfaceCache = SyntheticFunctionalInterfaceCache(session, moduleData, kotlinScopeProvider)
|
||||
|
||||
private fun loadBuiltIns(): List<BuiltInsPackageFragment> {
|
||||
val classLoader = this::class.java.classLoader
|
||||
@@ -201,7 +199,11 @@ private data class BinaryVersionAndPackageFragment(
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModuleData, private val kotlinScopeProvider: FirKotlinScopeProvider) {
|
||||
private class SyntheticFunctionalInterfaceCache(
|
||||
private val session: FirSession,
|
||||
private val moduleData: FirModuleData,
|
||||
private val kotlinScopeProvider: FirKotlinScopeProvider
|
||||
) {
|
||||
private val syntheticFunctionalInterfaceCache =
|
||||
moduleData.session.firCachesFactory.createCache(::createSyntheticFunctionalInterface)
|
||||
|
||||
@@ -212,7 +214,7 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
|
||||
private fun createSyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
|
||||
return with(classId) {
|
||||
val className = relativeClassName.asString()
|
||||
val kind = FunctionClassKind.byClassNamePrefix(packageFqName, className) ?: return@with null
|
||||
val kind = session.functionalTypeService.getKindByClassNamePrefix(packageFqName, className) ?: return null
|
||||
val prefix = kind.classNamePrefix
|
||||
val arity = className.substring(prefix.length).toIntOrNull() ?: return null
|
||||
FirRegularClassSymbol(classId).apply symbol@{
|
||||
@@ -279,55 +281,30 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
|
||||
isTailRec = false
|
||||
isExternal = false
|
||||
isSuspend =
|
||||
kind == FunctionClassKind.SuspendFunction ||
|
||||
kind == FunctionClassKind.KSuspendFunction
|
||||
kind == ConeFunctionalTypeKind.SuspendFunction ||
|
||||
kind == ConeFunctionalTypeKind.KSuspendFunction
|
||||
}
|
||||
val typeArguments = typeParameters.map {
|
||||
buildResolvedTypeRef {
|
||||
type = ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
|
||||
}
|
||||
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false).toFirResolvedTypeRef()
|
||||
}
|
||||
|
||||
fun createSuperType(
|
||||
kind: FunctionClassKind,
|
||||
): FirResolvedTypeRef {
|
||||
return buildResolvedTypeRef {
|
||||
type = kind.classId(arity).toLookupTag()
|
||||
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
|
||||
}
|
||||
fun createSuperType(kind: ConeFunctionalTypeKind): FirResolvedTypeRef {
|
||||
return kind.classId(arity).toLookupTag()
|
||||
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
|
||||
.toFirResolvedTypeRef()
|
||||
}
|
||||
|
||||
superTypeRefs += when (kind) {
|
||||
FunctionClassKind.Function -> listOf(
|
||||
buildResolvedTypeRef {
|
||||
type = StandardClassIds.Function.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
}
|
||||
)
|
||||
|
||||
FunctionClassKind.SuspendFunction -> listOf(
|
||||
buildResolvedTypeRef {
|
||||
type = StandardClassIds.Function.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
}
|
||||
)
|
||||
|
||||
FunctionClassKind.KFunction -> listOf(
|
||||
buildResolvedTypeRef {
|
||||
type = StandardClassIds.KFunction.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
},
|
||||
createSuperType(FunctionClassKind.Function)
|
||||
)
|
||||
|
||||
FunctionClassKind.KSuspendFunction -> listOf(
|
||||
buildResolvedTypeRef {
|
||||
type = StandardClassIds.KFunction.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
},
|
||||
createSuperType(FunctionClassKind.SuspendFunction)
|
||||
)
|
||||
if (kind.isReflectType) {
|
||||
superTypeRefs += StandardClassIds.KFunction.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
.toFirResolvedTypeRef()
|
||||
superTypeRefs += createSuperType(kind.nonReflectKind())
|
||||
} else {
|
||||
superTypeRefs += StandardClassIds.Function.toLookupTag()
|
||||
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
|
||||
.toFirResolvedTypeRef()
|
||||
}
|
||||
|
||||
addDeclaration(
|
||||
buildSimpleFunction {
|
||||
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
|
||||
@@ -357,6 +334,14 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
|
||||
}
|
||||
}
|
||||
dispatchReceiverType = classId.defaultType(this@klass.typeParameters.map { it.symbol })
|
||||
kind.annotationOnInvokeClassId?.let { annotationClassId ->
|
||||
annotations += buildAnnotation {
|
||||
annotationTypeRef = annotationClassId
|
||||
.constructClassLikeType(emptyArray(), isNullable = false)
|
||||
.toFirResolvedTypeRef()
|
||||
argumentMapping = FirEmptyAnnotationArgumentMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -364,6 +349,5 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun FunctionClassKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
|
||||
private fun ConeFunctionalTypeKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
|
||||
}
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.serialization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
@@ -681,7 +682,7 @@ class FirElementSerializer private constructor(
|
||||
return lowerBound
|
||||
}
|
||||
is ConeClassLikeType -> {
|
||||
if (type.isSuspendFunctionType(session)) {
|
||||
if (type.functionalTypeKind(session) == FunctionalTypeKind.SuspendFunction) {
|
||||
val runtimeFunctionType = type.suspendFunctionTypeToFunctionTypeWithContinuation(
|
||||
session, StandardClassIds.Continuation
|
||||
)
|
||||
|
||||
+24
-2
@@ -5,11 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.serialization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
|
||||
@@ -21,3 +24,22 @@ class TypeApproximatorForMetadataSerializer(session: FirSession) :
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: FirSession, continuationClassId: ClassId): ConeClassLikeType {
|
||||
require(this.isSuspendFunctionType(session))
|
||||
val kind =
|
||||
if (isReflectFunctionalType(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
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -233,8 +233,8 @@ class FirJvmSerializerExtension(
|
||||
private fun FirFunction.needsInlineParameterNullCheckRequirement(): Boolean =
|
||||
this is FirSimpleFunction && isInline && !isSuspend && !isParamAssertionsDisabled &&
|
||||
!Visibilities.isPrivate(visibility) &&
|
||||
(valueParameters.any { it.returnTypeRef.coneType.isBuiltinFunctionalType(session) } ||
|
||||
receiverParameter?.typeRef?.coneType?.isBuiltinFunctionalType(session) == true)
|
||||
(valueParameters.any { it.returnTypeRef.coneType.isSomeFunctionalType(session) } ||
|
||||
receiverParameter?.typeRef?.coneType?.isSomeFunctionalType(session) == true)
|
||||
|
||||
override fun serializeProperty(
|
||||
property: FirProperty,
|
||||
|
||||
+3
-3
@@ -172,8 +172,8 @@ class FirJvmTypeMapper(val session: FirSession) : FirSessionComponent {
|
||||
val parameters = classifier?.typeParameters.orEmpty().map { it.symbol }
|
||||
val arguments = type.arguments
|
||||
|
||||
if ((defaultType.isFunctionalType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY)
|
||||
|| defaultType.isKFunctionType(session)
|
||||
if ((defaultType.isSimpleFunctionType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY)
|
||||
|| defaultType.isReflectFunctionalType(session)
|
||||
) {
|
||||
writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode)
|
||||
return
|
||||
@@ -264,7 +264,7 @@ class ConeTypeSystemCommonBackendContextForTypeMapping(
|
||||
|
||||
override fun SimpleTypeMarker.isSuspendFunction(): Boolean {
|
||||
require(this is ConeSimpleKotlinType)
|
||||
return isSuspendOrKSuspendFunctionType(session)
|
||||
return isSuspendFunctionType(session)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isKClass(): Boolean {
|
||||
|
||||
+1
-1
@@ -538,7 +538,7 @@ class Fir2IrDeclarationStorage(
|
||||
?: if (isLambda) SpecialNames.ANONYMOUS else Name.special("<no name provided>")
|
||||
val visibility = simpleFunction?.visibility ?: Visibilities.Local
|
||||
val isSuspend =
|
||||
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendOrKSuspendFunctionType(session) == true
|
||||
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendFunctionType(session) == true
|
||||
else simpleFunction?.isSuspend == true
|
||||
val created = function.convertWithOffsets { startOffset, endOffset ->
|
||||
val result = declareIrSimpleFunction(signature, simpleFunction?.containerSource) { symbol ->
|
||||
|
||||
+6
-6
@@ -134,7 +134,7 @@ internal class AdapterGenerator(
|
||||
}
|
||||
|
||||
internal fun ConeKotlinType.kFunctionTypeToFunctionType(): IrSimpleType =
|
||||
kFunctionTypeToFunctionType(session).toIrType() as IrSimpleType
|
||||
reflectFunctionalTypeToNonReflectFunctionalType(session).toIrType() as IrSimpleType
|
||||
|
||||
internal fun generateAdaptedCallableReference(
|
||||
callableReferenceAccess: FirCallableReferenceAccess,
|
||||
@@ -479,7 +479,7 @@ internal class AdapterGenerator(
|
||||
}
|
||||
// If the expected type is a built-in functional type, we don't need SAM conversion.
|
||||
val expectedType = argument.getExpectedType(parameter)
|
||||
if (expectedType is ConeTypeParameterType || expectedType.isBuiltinFunctionalType(session)) {
|
||||
if (expectedType is ConeTypeParameterType || expectedType.isSomeFunctionalType(session)) {
|
||||
return false
|
||||
}
|
||||
// On the other hand, the actual type should be either a functional type or a subtype of a class that has a contributed `invoke`.
|
||||
@@ -514,10 +514,10 @@ internal class AdapterGenerator(
|
||||
return this
|
||||
}
|
||||
// Expect the expected type to be a suspend functional type.
|
||||
if (!parameterType.isSuspendOrKSuspendFunctionType(session)) {
|
||||
if (!parameterType.isSuspendFunctionType(session)) {
|
||||
return this
|
||||
}
|
||||
val expectedFunctionalType = parameterType.suspendFunctionTypeToFunctionType(session)
|
||||
val expectedFunctionalType = parameterType.customFunctionalTypeToSimpleFunctionalType(session)
|
||||
if (this is IrVararg) {
|
||||
// element-wise conversion if and only if we can build 1-to-1 mapping for elements.
|
||||
return applyConversionOnVararg(argument) { firVarargArgument ->
|
||||
@@ -546,9 +546,9 @@ internal class AdapterGenerator(
|
||||
argument: FirExpression
|
||||
): IrSimpleFunctionSymbol? {
|
||||
val argumentType = argument.typeRef.coneType
|
||||
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) ?: return null
|
||||
val argumentTypeWithInvoke = argumentType.findSubtypeOfSimpleFunctionalType(session, expectedFunctionalType) ?: return null
|
||||
|
||||
return if (argumentTypeWithInvoke.isBuiltinFunctionalType(session)) {
|
||||
return if (argumentTypeWithInvoke.isSomeFunctionalType(session)) {
|
||||
(argumentTypeWithInvoke as? ConeClassLikeType)?.findBaseInvokeSymbol(session, scopeSession)
|
||||
} else {
|
||||
argumentTypeWithInvoke.findContributedInvokeSymbol(
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ class CallAndReferenceGenerator(
|
||||
// This would cause ClassCastException in case of usual type approximation,
|
||||
// because '{ X1 & ... & Xm }' would be approximated to 'Nothing'.
|
||||
// JVM_OLD just relies on type mapping for generic argument types in such case.
|
||||
if (!kotlinType.isKFunctionType(session))
|
||||
if (!kotlinType.isReflectFunctionalType(session))
|
||||
return kotlinType
|
||||
if (kotlinType !is ConeSimpleKotlinType)
|
||||
return kotlinType
|
||||
|
||||
+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()
|
||||
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.fir.types.isSomeFunctionalType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION_CLASS_ID
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.same
|
||||
@@ -104,7 +104,7 @@ class FirOverloadByLambdaReturnTypeResolver(
|
||||
.values.singleOrNull()?.toMap() ?: return null
|
||||
|
||||
if (!lambdas.values.same { it.parameters.size }) return null
|
||||
if (!lambdas.values.all { it.expectedType?.isBuiltinFunctionalType(session) == true }) return null
|
||||
if (!lambdas.values.all { it.expectedType?.isSomeFunctionalType(session) == true }) return null
|
||||
|
||||
val originalCalleeReference = call.calleeReference
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
import org.jetbrains.kotlin.types.model.safeSubstitute
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@@ -581,18 +582,15 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(
|
||||
result
|
||||
}
|
||||
// referenced function of a Kotlin function type
|
||||
FirDeclarationOrigin.BuiltIns -> {
|
||||
if (dispatchReceiverClassLookupTagOrNull()?.isBuiltinFunctionalType() == true) {
|
||||
ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE
|
||||
} else {
|
||||
null
|
||||
}
|
||||
FirDeclarationOrigin.BuiltIns -> runIf(dispatchReceiverClassLookupTagOrNull()?.isSomeFunctionalType(session) == true) {
|
||||
ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE
|
||||
}
|
||||
FirDeclarationOrigin.Synthetic -> null
|
||||
FirDeclarationOrigin.DynamicScope -> null
|
||||
FirDeclarationOrigin.RenamedForOverride -> null
|
||||
FirDeclarationOrigin.WrappedIntegerOperator -> null
|
||||
FirDeclarationOrigin.ScriptCustomization -> null
|
||||
|
||||
FirDeclarationOrigin.Synthetic,
|
||||
FirDeclarationOrigin.DynamicScope,
|
||||
FirDeclarationOrigin.RenamedForOverride,
|
||||
FirDeclarationOrigin.WrappedIntegerOperator,
|
||||
FirDeclarationOrigin.ScriptCustomization,
|
||||
is FirDeclarationOrigin.Plugin -> null // TODO: figure out what to do with plugin generated functions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,9 +293,9 @@ private fun argumentTypeWithSuspendConversion(
|
||||
}
|
||||
|
||||
// We want to check the argument type against non-suspend functional type.
|
||||
val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session)
|
||||
val expectedFunctionalType = expectedType.customFunctionalTypeToSimpleFunctionalType(session)
|
||||
|
||||
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType)
|
||||
val argumentTypeWithInvoke = argumentType.findSubtypeOfSimpleFunctionalType(session, expectedFunctionalType)
|
||||
|
||||
return argumentTypeWithInvoke?.findContributedInvokeSymbol(
|
||||
session,
|
||||
@@ -308,7 +308,7 @@ private fun argumentTypeWithSuspendConversion(
|
||||
null,
|
||||
invokeSymbol.fir.returnTypeRef.coneType,
|
||||
isSuspend = true,
|
||||
isKFunctionType = argumentType.isKFunctionType(session)
|
||||
isKFunctionType = argumentType.isReflectFunctionalType(session)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
|
||||
candidateExpectedType: ConeKotlinType,
|
||||
context: ResolutionContext
|
||||
): ConeKotlinType? {
|
||||
if (candidateExpectedType.isBuiltinFunctionalType(session)) return null
|
||||
if (candidateExpectedType.isSomeFunctionalType(session)) return null
|
||||
|
||||
// TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
|
||||
|
||||
@@ -521,7 +521,7 @@ fun FirExpression.isFunctional(
|
||||
else -> {
|
||||
// Either a functional type or a subtype of a class that has a contributed `invoke`.
|
||||
val coneType = typeRef.coneTypeSafe<ConeKotlinType>() ?: return false
|
||||
if (coneType.isBuiltinFunctionalType(session)) {
|
||||
if (coneType.isSomeFunctionalType(session)) {
|
||||
return true
|
||||
}
|
||||
val classLikeExpectedFunctionType = expectedFunctionType?.lowerBoundIfFlexible() as? ConeClassLikeType
|
||||
|
||||
@@ -297,7 +297,7 @@ object CheckDslScopeViolation : ResolutionStage() {
|
||||
// ```
|
||||
// `useX()` is a call to `invoke` with `useX` as the dispatch receiver. In the FIR tree, extension receiver is represented as an
|
||||
// implicit `this` expression passed as the first argument.
|
||||
if (candidate.dispatchReceiverValue?.type?.fullyExpandedType(context.session)?.isBuiltinFunctionalType(context.session) == true &&
|
||||
if (candidate.dispatchReceiverValue?.type?.fullyExpandedType(context.session)?.isSomeFunctionalType(context.session) == true &&
|
||||
(candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE
|
||||
) {
|
||||
val firstArg = candidate.argumentMapping?.keys?.firstOrNull() as? FirThisReceiverExpression ?: return
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ fun extractLambdaInfoFromFunctionalType(
|
||||
duringCompletion
|
||||
)
|
||||
}
|
||||
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
||||
if (!expectedType.isSomeFunctionalType(session)) return null
|
||||
|
||||
val singleStatement = argument.body?.statements?.singleOrNull() as? FirReturnExpression
|
||||
if (argument.returnType == null && singleStatement != null &&
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ private fun extractLambdaInfo(
|
||||
|
||||
val isFunctionSupertype =
|
||||
expectedType != null && expectedType.lowerBoundIfFlexible()
|
||||
.isBuiltinFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
.isSomeFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
|
||||
val typeVariable = ConeTypeVariableForLambdaReturnType(argument, "_L")
|
||||
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType(
|
||||
if (expectedType == null) return null
|
||||
|
||||
return when {
|
||||
expectedType.isBuiltinFunctionalType(session) ->
|
||||
expectedType.isSomeFunctionalType(session) ->
|
||||
InputOutputTypes(expectedType.valueParameterTypesIncludingReceiver(session), expectedType.returnType(session))
|
||||
|
||||
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
|
||||
|
||||
+1
-1
@@ -561,7 +561,7 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
// From the argument mapping, the expected type of this anonymous function would be:
|
||||
when {
|
||||
// a built-in functional type, no-brainer
|
||||
expectedArgumentType.isBuiltinFunctionalType(session) -> expectedArgumentType
|
||||
expectedArgumentType.isSomeFunctionalType(session) -> expectedArgumentType
|
||||
// fun interface (a.k.a. SAM), then unwrap it and build a functional type from that interface function
|
||||
expectedArgumentType is ConeClassLikeType -> {
|
||||
val firRegularClass =
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isFunctionalOrSuspendFunctionalType
|
||||
import org.jetbrains.kotlin.fir.types.isNonReflectFunctionalType
|
||||
|
||||
tailrec fun FirExpression.unwrapAnonymousFunctionExpression(): FirAnonymousFunction? = when (this) {
|
||||
is FirAnonymousFunctionExpression -> anonymousFunction
|
||||
@@ -47,7 +47,7 @@ fun FirFunctionCall.replaceLambdaArgumentInvocationKinds(session: FirSession) {
|
||||
val kind = byParameter[parameter] ?: EventOccurrencesRange.UNKNOWN.takeIf {
|
||||
// Inline functional parameters have to be called in-place; that's the only permitted operation on them.
|
||||
isInline && !parameter.isNoinline && !parameter.isCrossinline &&
|
||||
parameter.returnTypeRef.coneType.isFunctionalOrSuspendFunctionalType(session)
|
||||
parameter.returnTypeRef.coneType.isNonReflectFunctionalType(session)
|
||||
} ?: continue
|
||||
lambda.replaceInvocationKind(kind)
|
||||
}
|
||||
|
||||
+1
-2
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWri
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.transformVarargTypeToArrayType
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
|
||||
import org.jetbrains.kotlin.fir.types.constructStarProjectedType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
@@ -859,7 +858,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
|
||||
lambda: FirAnonymousFunction
|
||||
): List<FirValueParameter> {
|
||||
if (expectedType == null) return lambda.valueParameters
|
||||
if (!expectedType.isFunctionalOrSuspendFunctionalType(session)) return lambda.valueParameters
|
||||
if (!expectedType.isNonReflectFunctionalType(session)) return lambda.valueParameters
|
||||
val parameterTypes = expectedType.typeArguments
|
||||
.mapTo(mutableListOf()) { it.type ?: session.builtinTypes.nullableAnyType.type }
|
||||
.also { it.removeLastOrNull() }
|
||||
|
||||
@@ -742,7 +742,13 @@ class FirRenderer(
|
||||
}
|
||||
|
||||
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
|
||||
typeRenderer.renderAsPossibleFunctionType(resolvedTypeRef.type)
|
||||
typeRenderer.renderAsPossibleFunctionType(
|
||||
resolvedTypeRef.type,
|
||||
l@{
|
||||
val classId = it.classId ?: return@l null
|
||||
FirFunctionalTypeKindService.Default.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
abstract class FirFunctionalTypeKindService : FirSessionComponent {
|
||||
abstract fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind?
|
||||
|
||||
/*
|
||||
* Should be used only in places where session is unavaliable by default (e.g. in default cone type render)
|
||||
*/
|
||||
object Default : FirFunctionalTypeKindService() {
|
||||
override fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind? {
|
||||
return when (FunctionClassKind.parseClassName(className, packageFqName)?.kind) {
|
||||
FunctionClassKind.Function -> ConeFunctionalTypeKind.Function
|
||||
FunctionClassKind.SuspendFunction -> ConeFunctionalTypeKind.SuspendFunction
|
||||
FunctionClassKind.KFunction -> ConeFunctionalTypeKind.KFunction
|
||||
FunctionClassKind.KSuspendFunction -> ConeFunctionalTypeKind.KSuspendFunction
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val FirSession.functionalTypeService: FirFunctionalTypeKindService by FirSession.sessionComponentAccessor()
|
||||
+4
-1
@@ -337,7 +337,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
||||
return
|
||||
}
|
||||
val projectionBuilder = StringBuilder()
|
||||
ConeTypeRendererForDebugging(projectionBuilder).renderAsPossibleFunctionType(this) {
|
||||
ConeTypeRendererForDebugging(projectionBuilder).renderAsPossibleFunctionType(
|
||||
this,
|
||||
{ it.functionalTypeKind(session) }
|
||||
) {
|
||||
localTypeProjectionRenderer(projectionBuilder)
|
||||
}
|
||||
builder.append(projectionBuilder.toString().removeCurrentFilePackage())
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
|
||||
type.anySuperTypeConstructor {
|
||||
it is ConeKotlinType &&
|
||||
(it.classId?.asFqNameString() in BuiltinParcelableTypes.PARCELABLE_SUPERTYPE_FQNAMES ||
|
||||
it.isBuiltinFunctionalType(session))
|
||||
it.isSomeFunctionalType(session))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user