[FIR] Organize code for postponed arguments
This commit is contained in:
+117
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.isExtensionFunctionType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
|
||||||
|
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
|
||||||
|
return when (this) {
|
||||||
|
is ConeClassLikeType -> fullyExpandedType(session).lookupTag.classId.asString().startsWith("kotlin/Function")
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||||
|
return when (val type = this) {
|
||||||
|
is ConeClassLikeType -> {
|
||||||
|
val classId = type.fullyExpandedType(session).lookupTag.classId
|
||||||
|
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef, session: FirSession): ConeKotlinType? {
|
||||||
|
if (isBuiltinFunctionalType(session) && expectedTypeRef.isExtensionFunctionType(session)) {
|
||||||
|
return ((this as ConeClassLikeType).fullyExpandedType(session).typeArguments.first() as ConeKotlinTypeProjection).type
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? {
|
||||||
|
require(this is ConeClassLikeType)
|
||||||
|
val projection = fullyExpandedType(session).typeArguments.last()
|
||||||
|
return (projection as? ConeKotlinTypeProjection)?.type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType?> {
|
||||||
|
require(this is ConeClassLikeType)
|
||||||
|
return fullyExpandedType(session).typeArguments.dropLast(1).map {
|
||||||
|
(it as? ConeKotlinTypeProjection)?.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
|
val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
|
||||||
|
|
||||||
|
fun extractLambdaInfoFromFunctionalType(
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
expectedTypeRef: FirTypeRef,
|
||||||
|
argument: FirAnonymousFunction,
|
||||||
|
returnTypeVariable: ConeTypeVariableForLambdaReturnType?,
|
||||||
|
components: BodyResolveComponents,
|
||||||
|
candidate: Candidate?
|
||||||
|
): ResolvedLambdaAtom? {
|
||||||
|
val session = components.session
|
||||||
|
if (expectedType == null) return null
|
||||||
|
if (expectedType is ConeFlexibleType) {
|
||||||
|
return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, returnTypeVariable, components, candidate)
|
||||||
|
}
|
||||||
|
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
||||||
|
|
||||||
|
val receiverType = argument.receiverType ?: expectedType.receiverType(expectedTypeRef, session)
|
||||||
|
val returnType = argument.returnType ?: expectedType.returnType(session) ?: return null
|
||||||
|
val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType(session), session)
|
||||||
|
|
||||||
|
return ResolvedLambdaAtom(
|
||||||
|
argument,
|
||||||
|
expectedType,
|
||||||
|
expectedType.isSuspendFunctionType(session),
|
||||||
|
receiverType,
|
||||||
|
parameters,
|
||||||
|
returnType,
|
||||||
|
typeVariableForLambdaReturnType = returnTypeVariable,
|
||||||
|
candidate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractLambdaParameters(
|
||||||
|
expectedType: ConeKotlinType,
|
||||||
|
argument: FirAnonymousFunction,
|
||||||
|
expectedTypeIsExtensionFunctionType: Boolean,
|
||||||
|
session: FirSession
|
||||||
|
): List<ConeKotlinType> {
|
||||||
|
val parameters = argument.valueParameters
|
||||||
|
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session)
|
||||||
|
|
||||||
|
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
return expectedParameters.map { it?.type ?: nullableAnyType }
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.mapIndexed { index, parameter ->
|
||||||
|
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: nullableAnyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeKotlinType.extractParametersForFunctionalType(
|
||||||
|
isExtensionFunctionType: Boolean,
|
||||||
|
session: FirSession
|
||||||
|
): List<ConeKotlinType?> {
|
||||||
|
return valueParameterTypesIncludingReceiver(session).let {
|
||||||
|
if (isExtensionFunctionType) {
|
||||||
|
it.drop(1)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-235
@@ -8,21 +8,11 @@ package org.jetbrains.kotlin.fir.resolve.inference
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.CandidateApplicability
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.isExtensionFunctionType
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun Candidate.preprocessLambdaArgument(
|
fun Candidate.preprocessLambdaArgument(
|
||||||
@@ -58,47 +48,6 @@ fun Candidate.preprocessCallableReference(
|
|||||||
postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, bodyResolveComponents.session)
|
postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, bodyResolveComponents.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
|
|
||||||
return when (this) {
|
|
||||||
is ConeClassLikeType -> fullyExpandedType(session).lookupTag.classId.asString().startsWith("kotlin/Function")
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
|
||||||
return when (val type = this) {
|
|
||||||
is ConeClassLikeType -> {
|
|
||||||
val classId = type.fullyExpandedType(session).lookupTag.classId
|
|
||||||
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef, session: FirSession): ConeKotlinType? {
|
|
||||||
if (isBuiltinFunctionalType(session) && expectedTypeRef.isExtensionFunctionType(session)) {
|
|
||||||
return ((this as ConeClassLikeType).fullyExpandedType(session).typeArguments.first() as ConeKotlinTypeProjection).type
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? {
|
|
||||||
require(this is ConeClassLikeType)
|
|
||||||
val projection = fullyExpandedType(session).typeArguments.last()
|
|
||||||
return (projection as? ConeKotlinTypeProjection)?.type
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType?> {
|
|
||||||
require(this is ConeClassLikeType)
|
|
||||||
return fullyExpandedType(session).typeArguments.dropLast(1).map {
|
|
||||||
(it as? ConeKotlinTypeProjection)?.type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
|
||||||
private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
|
|
||||||
|
|
||||||
|
|
||||||
private fun extraLambdaInfo(
|
private fun extraLambdaInfo(
|
||||||
expectedType: ConeKotlinType?,
|
expectedType: ConeKotlinType?,
|
||||||
argument: FirAnonymousFunction,
|
argument: FirAnonymousFunction,
|
||||||
@@ -139,187 +88,3 @@ private fun extraLambdaInfo(
|
|||||||
candidate
|
candidate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun extractLambdaInfoFromFunctionalType(
|
|
||||||
expectedType: ConeKotlinType?,
|
|
||||||
expectedTypeRef: FirTypeRef,
|
|
||||||
argument: FirAnonymousFunction,
|
|
||||||
returnTypeVariable: ConeTypeVariableForLambdaReturnType?,
|
|
||||||
components: BodyResolveComponents,
|
|
||||||
candidate: Candidate?
|
|
||||||
): ResolvedLambdaAtom? {
|
|
||||||
val session = components.session
|
|
||||||
if (expectedType == null) return null
|
|
||||||
if (expectedType is ConeFlexibleType) {
|
|
||||||
return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, returnTypeVariable, components, candidate)
|
|
||||||
}
|
|
||||||
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
|
||||||
|
|
||||||
val receiverType = argument.receiverType ?: expectedType.receiverType(expectedTypeRef, session)
|
|
||||||
val returnType = argument.returnType ?: expectedType.returnType(session) ?: return null
|
|
||||||
val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType(session), session)
|
|
||||||
|
|
||||||
return ResolvedLambdaAtom(
|
|
||||||
argument,
|
|
||||||
expectedType,
|
|
||||||
expectedType.isSuspendFunctionType(session),
|
|
||||||
receiverType,
|
|
||||||
parameters,
|
|
||||||
returnType,
|
|
||||||
typeVariableForLambdaReturnType = returnTypeVariable,
|
|
||||||
candidate
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractLambdaParameters(
|
|
||||||
expectedType: ConeKotlinType,
|
|
||||||
argument: FirAnonymousFunction,
|
|
||||||
expectedTypeIsExtensionFunctionType: Boolean,
|
|
||||||
session: FirSession
|
|
||||||
): List<ConeKotlinType> {
|
|
||||||
val parameters = argument.valueParameters
|
|
||||||
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session)
|
|
||||||
|
|
||||||
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type
|
|
||||||
if (parameters.isEmpty()) {
|
|
||||||
return expectedParameters.map { it?.type ?: nullableAnyType }
|
|
||||||
}
|
|
||||||
|
|
||||||
return parameters.mapIndexed { index, parameter ->
|
|
||||||
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: nullableAnyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ConeKotlinType.extractParametersForFunctionalType(
|
|
||||||
isExtensionFunctionType: Boolean,
|
|
||||||
session: FirSession
|
|
||||||
): List<ConeKotlinType?> {
|
|
||||||
return valueParameterTypesIncludingReceiver(session).let {
|
|
||||||
if (isExtensionFunctionType) {
|
|
||||||
it.drop(1)
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
|
||||||
|
|
||||||
sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker {
|
|
||||||
abstract override val inputTypes: Collection<ConeKotlinType>
|
|
||||||
abstract override val outputType: ConeKotlinType?
|
|
||||||
override var analyzed: Boolean = false
|
|
||||||
abstract val expectedType: ConeKotlinType?
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResolvedLambdaAtom(
|
|
||||||
val atom: FirAnonymousFunction,
|
|
||||||
override val expectedType: ConeKotlinType?,
|
|
||||||
val isSuspend: Boolean,
|
|
||||||
val receiver: ConeKotlinType?,
|
|
||||||
val parameters: List<ConeKotlinType>,
|
|
||||||
val returnType: ConeKotlinType,
|
|
||||||
val typeVariableForLambdaReturnType: ConeTypeVariableForLambdaReturnType?,
|
|
||||||
val candidateForOuterCall: Candidate?
|
|
||||||
) : PostponedResolvedAtom() {
|
|
||||||
init {
|
|
||||||
candidateForOuterCall?.let {
|
|
||||||
it.postponedAtoms += this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var returnStatements: Collection<FirStatement>
|
|
||||||
|
|
||||||
override val inputTypes: Collection<ConeKotlinType> get() = receiver?.let { parameters + it } ?: parameters
|
|
||||||
override val outputType: ConeKotlinType get() = returnType
|
|
||||||
}
|
|
||||||
|
|
||||||
class LambdaWithTypeVariableAsExpectedTypeAtom(
|
|
||||||
val atom: FirAnonymousFunction,
|
|
||||||
override val expectedType: ConeKotlinType,
|
|
||||||
val expectedTypeRef: FirTypeRef,
|
|
||||||
val candidateForOuterCall: Candidate
|
|
||||||
) : PostponedResolvedAtom() {
|
|
||||||
init {
|
|
||||||
candidateForOuterCall.postponedAtoms += this
|
|
||||||
}
|
|
||||||
|
|
||||||
override val inputTypes: Collection<ConeKotlinType> get() = listOf(expectedType)
|
|
||||||
override val outputType: ConeKotlinType? get() = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResolvedCallableReferenceAtom(
|
|
||||||
val reference: FirCallableReferenceAccess,
|
|
||||||
override val expectedType: ConeKotlinType?,
|
|
||||||
val lhs: DoubleColonLHS?,
|
|
||||||
private val session: FirSession
|
|
||||||
) : PostponedResolvedAtom() {
|
|
||||||
var postponed: Boolean = false
|
|
||||||
|
|
||||||
var resultingCandidate: Pair<Candidate, CandidateApplicability>? = null
|
|
||||||
|
|
||||||
override val inputTypes: Collection<ConeKotlinType>
|
|
||||||
get() {
|
|
||||||
if (!postponed) return emptyList()
|
|
||||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.inputTypes
|
|
||||||
?: listOfNotNull(expectedType)
|
|
||||||
}
|
|
||||||
override val outputType: ConeKotlinType?
|
|
||||||
get() {
|
|
||||||
if (!postponed) return null
|
|
||||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.outputType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class InputOutputTypes(val inputTypes: List<ConeKotlinType>, val outputType: ConeKotlinType)
|
|
||||||
|
|
||||||
private fun extractInputOutputTypesFromCallableReferenceExpectedType(
|
|
||||||
expectedType: ConeKotlinType?,
|
|
||||||
session: FirSession
|
|
||||||
): InputOutputTypes? {
|
|
||||||
if (expectedType == null) return null
|
|
||||||
|
|
||||||
return when {
|
|
||||||
expectedType.isBuiltinFunctionalType(session) || expectedType.isSuspendFunctionType(session) ->
|
|
||||||
extractInputOutputTypesFromFunctionType(expectedType, session)
|
|
||||||
|
|
||||||
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
|
|
||||||
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
|
|
||||||
//
|
|
||||||
// ReflectionTypes.isNumberedKFunction(expectedType) -> {
|
|
||||||
// val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
|
||||||
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ReflectionTypes.isNumberedKSuspendFunction(expectedType) -> {
|
|
||||||
// val kSuspendFunctionType = expectedType.immediateSupertypes().first { it.isSuspendFunctionType }.unwrap()
|
|
||||||
// extractInputOutputTypesFromFunctionType(kSuspendFunctionType)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> {
|
|
||||||
// val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap()
|
|
||||||
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
|
||||||
// }
|
|
||||||
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractInputOutputTypesFromFunctionType(
|
|
||||||
functionType: ConeKotlinType,
|
|
||||||
session: FirSession
|
|
||||||
): InputOutputTypes {
|
|
||||||
val parameters = functionType.valueParameterTypesIncludingReceiver(session).map {
|
|
||||||
it ?: ConeClassLikeTypeImpl(
|
|
||||||
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
|
|
||||||
isNullable = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl(
|
|
||||||
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
|
|
||||||
isNullable = true
|
|
||||||
)
|
|
||||||
|
|
||||||
return InputOutputTypes(parameters, outputType)
|
|
||||||
}
|
|
||||||
|
|||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.CandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeTypeVariable
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
|
|
||||||
|
// --------------------------- Variables ---------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
||||||
|
|
||||||
|
// -------------------------- Atoms --------------------------
|
||||||
|
|
||||||
|
sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker {
|
||||||
|
abstract override val inputTypes: Collection<ConeKotlinType>
|
||||||
|
abstract override val outputType: ConeKotlinType?
|
||||||
|
override var analyzed: Boolean = false
|
||||||
|
abstract val expectedType: ConeKotlinType?
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------- Lambdas -------------
|
||||||
|
|
||||||
|
class ResolvedLambdaAtom(
|
||||||
|
val atom: FirAnonymousFunction,
|
||||||
|
override val expectedType: ConeKotlinType?,
|
||||||
|
val isSuspend: Boolean,
|
||||||
|
val receiver: ConeKotlinType?,
|
||||||
|
val parameters: List<ConeKotlinType>,
|
||||||
|
val returnType: ConeKotlinType,
|
||||||
|
val typeVariableForLambdaReturnType: ConeTypeVariableForLambdaReturnType?,
|
||||||
|
val candidateOfOuterCall: Candidate?
|
||||||
|
) : PostponedResolvedAtom() {
|
||||||
|
init {
|
||||||
|
candidateOfOuterCall?.let {
|
||||||
|
it.postponedAtoms += this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var returnStatements: Collection<FirStatement>
|
||||||
|
|
||||||
|
override val inputTypes: Collection<ConeKotlinType> get() = receiver?.let { parameters + it } ?: parameters
|
||||||
|
override val outputType: ConeKotlinType get() = returnType
|
||||||
|
}
|
||||||
|
|
||||||
|
class LambdaWithTypeVariableAsExpectedTypeAtom(
|
||||||
|
val atom: FirAnonymousFunction,
|
||||||
|
override val expectedType: ConeKotlinType,
|
||||||
|
val expectedTypeRef: FirTypeRef,
|
||||||
|
val candidateOfOuterCall: Candidate
|
||||||
|
) : PostponedResolvedAtom() {
|
||||||
|
init {
|
||||||
|
candidateOfOuterCall.postponedAtoms += this
|
||||||
|
}
|
||||||
|
|
||||||
|
override val inputTypes: Collection<ConeKotlinType> get() = listOf(expectedType)
|
||||||
|
override val outputType: ConeKotlinType? get() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------- References -------------
|
||||||
|
|
||||||
|
class ResolvedCallableReferenceAtom(
|
||||||
|
val reference: FirCallableReferenceAccess,
|
||||||
|
override val expectedType: ConeKotlinType?,
|
||||||
|
val lhs: DoubleColonLHS?,
|
||||||
|
private val session: FirSession
|
||||||
|
) : PostponedResolvedAtom() {
|
||||||
|
var postponed: Boolean = false
|
||||||
|
|
||||||
|
var resultingCandidate: Pair<Candidate, CandidateApplicability>? = null
|
||||||
|
|
||||||
|
override val inputTypes: Collection<ConeKotlinType>
|
||||||
|
get() {
|
||||||
|
if (!postponed) return emptyList()
|
||||||
|
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.inputTypes
|
||||||
|
?: listOfNotNull(expectedType)
|
||||||
|
}
|
||||||
|
override val outputType: ConeKotlinType?
|
||||||
|
get() {
|
||||||
|
if (!postponed) return null
|
||||||
|
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.outputType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------- Utils --------------------------
|
||||||
|
|
||||||
|
private data class InputOutputTypes(val inputTypes: List<ConeKotlinType>, val outputType: ConeKotlinType)
|
||||||
|
|
||||||
|
private fun extractInputOutputTypesFromCallableReferenceExpectedType(
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
session: FirSession
|
||||||
|
): InputOutputTypes? {
|
||||||
|
if (expectedType == null) return null
|
||||||
|
|
||||||
|
return when {
|
||||||
|
expectedType.isBuiltinFunctionalType(session) || expectedType.isSuspendFunctionType(session) ->
|
||||||
|
extractInputOutputTypesFromFunctionType(expectedType, session)
|
||||||
|
|
||||||
|
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
|
||||||
|
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
|
||||||
|
//
|
||||||
|
// ReflectionTypes.isNumberedKFunction(expectedType) -> {
|
||||||
|
// val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
||||||
|
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ReflectionTypes.isNumberedKSuspendFunction(expectedType) -> {
|
||||||
|
// val kSuspendFunctionType = expectedType.immediateSupertypes().first { it.isSuspendFunctionType }.unwrap()
|
||||||
|
// extractInputOutputTypesFromFunctionType(kSuspendFunctionType)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> {
|
||||||
|
// val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap()
|
||||||
|
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||||
|
// }
|
||||||
|
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractInputOutputTypesFromFunctionType(
|
||||||
|
functionType: ConeKotlinType,
|
||||||
|
session: FirSession
|
||||||
|
): InputOutputTypes {
|
||||||
|
val parameters = functionType.valueParameterTypesIncludingReceiver(session).map {
|
||||||
|
it ?: ConeClassLikeTypeImpl(
|
||||||
|
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
|
||||||
|
isNullable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl(
|
||||||
|
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
|
||||||
|
isNullable = true
|
||||||
|
)
|
||||||
|
|
||||||
|
return InputOutputTypes(parameters, outputType)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user