FIR: detect extension function types by reference annotation
Later it should be replaced by cone type annotation analysis
This commit is contained in:
committed by
Mikhail Glukhikh
parent
3d73c28d1e
commit
fda777ecae
@@ -27,6 +27,7 @@ fun resolveArgumentExpression(
|
|||||||
csBuilder: ConstraintSystemBuilder,
|
csBuilder: ConstraintSystemBuilder,
|
||||||
argument: FirExpression,
|
argument: FirExpression,
|
||||||
expectedType: ConeKotlinType,
|
expectedType: ConeKotlinType,
|
||||||
|
expectedTypeRef: FirTypeRef,
|
||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
||||||
@@ -42,7 +43,7 @@ fun resolveArgumentExpression(
|
|||||||
typeProvider
|
typeProvider
|
||||||
)
|
)
|
||||||
// TODO:!
|
// TODO:!
|
||||||
is FirAnonymousFunction -> preprocessLambdaArgument(csBuilder, argument, expectedType, acceptLambdaAtoms)
|
is FirAnonymousFunction -> preprocessLambdaArgument(csBuilder, argument, expectedType, expectedTypeRef, acceptLambdaAtoms)
|
||||||
// TODO:!
|
// TODO:!
|
||||||
is FirCallableReferenceAccess -> Unit
|
is FirCallableReferenceAccess -> Unit
|
||||||
// TODO:!
|
// TODO:!
|
||||||
@@ -51,6 +52,7 @@ fun resolveArgumentExpression(
|
|||||||
csBuilder,
|
csBuilder,
|
||||||
argument.expression,
|
argument.expression,
|
||||||
expectedType,
|
expectedType,
|
||||||
|
expectedTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
acceptLambdaAtoms,
|
acceptLambdaAtoms,
|
||||||
@@ -60,6 +62,7 @@ fun resolveArgumentExpression(
|
|||||||
csBuilder,
|
csBuilder,
|
||||||
argument.expression,
|
argument.expression,
|
||||||
expectedType,
|
expectedType,
|
||||||
|
expectedTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
acceptLambdaAtoms,
|
acceptLambdaAtoms,
|
||||||
@@ -120,6 +123,7 @@ internal fun Candidate.resolveArgument(
|
|||||||
this.system.getBuilder(),
|
this.system.getBuilder(),
|
||||||
argument,
|
argument,
|
||||||
expectedType,
|
expectedType,
|
||||||
|
parameter.returnTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
{ this.postponedAtoms += it },
|
{ this.postponedAtoms += it },
|
||||||
|
|||||||
+25
-5
@@ -15,6 +15,7 @@ fun preprocessLambdaArgument(
|
|||||||
csBuilder: ConstraintSystemBuilder,
|
csBuilder: ConstraintSystemBuilder,
|
||||||
argument: FirAnonymousFunction,
|
argument: FirAnonymousFunction,
|
||||||
expectedType: ConeKotlinType?,
|
expectedType: ConeKotlinType?,
|
||||||
|
expectedTypeRef: FirTypeRef,
|
||||||
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
||||||
forceResolution: Boolean = false
|
forceResolution: Boolean = false
|
||||||
) {
|
) {
|
||||||
@@ -22,7 +23,9 @@ fun preprocessLambdaArgument(
|
|||||||
//return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType)
|
//return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
val resolvedArgument = extractLambdaInfoFromFunctionalType(expectedType, argument) ?: extraLambdaInfo(expectedType, argument, csBuilder)
|
val resolvedArgument =
|
||||||
|
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument)
|
||||||
|
?: extraLambdaInfo(expectedType, expectedTypeRef, argument, csBuilder)
|
||||||
|
|
||||||
if (expectedType != null) {
|
if (expectedType != null) {
|
||||||
// val lambdaType = createFunctionType(
|
// val lambdaType = createFunctionType(
|
||||||
@@ -58,7 +61,19 @@ private val ConeKotlinType.isSuspendFunctionType: Boolean
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ConeKotlinType.receiverType: ConeKotlinType? get() = null
|
private fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef): ConeKotlinType? {
|
||||||
|
if (isFunctionalTypeWithReceiver(expectedTypeRef)) {
|
||||||
|
return (this.typeArguments.first() as ConeTypedProjection).type
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isFunctionalTypeWithReceiver(typeRef: FirTypeRef) =
|
||||||
|
typeRef.annotations.any {
|
||||||
|
val coneTypeSafe = it.annotationTypeRef.coneTypeSafe<ConeClassType>() ?: return@any false
|
||||||
|
coneTypeSafe.lookupTag.classId.asString() == "kotlin/ExtensionFunctionType"
|
||||||
|
}
|
||||||
|
|
||||||
private val ConeKotlinType.returnType: ConeKotlinType
|
private val ConeKotlinType.returnType: ConeKotlinType
|
||||||
get() {
|
get() {
|
||||||
require(this is ConeClassType)
|
require(this is ConeClassType)
|
||||||
@@ -81,6 +96,7 @@ private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeS
|
|||||||
|
|
||||||
private fun extraLambdaInfo(
|
private fun extraLambdaInfo(
|
||||||
expectedType: ConeKotlinType?,
|
expectedType: ConeKotlinType?,
|
||||||
|
expectedTypeRef: FirTypeRef,
|
||||||
argument: FirAnonymousFunction,
|
argument: FirAnonymousFunction,
|
||||||
csBuilder: ConstraintSystemBuilder
|
csBuilder: ConstraintSystemBuilder
|
||||||
): ResolvedLambdaAtom {
|
): ResolvedLambdaAtom {
|
||||||
@@ -93,7 +109,7 @@ private fun extraLambdaInfo(
|
|||||||
|
|
||||||
val typeVariable = TypeVariableForLambdaReturnType(argument, "_L")
|
val typeVariable = TypeVariableForLambdaReturnType(argument, "_L")
|
||||||
|
|
||||||
val receiverType = null//argumentAsFunctionExpression?.receiverType
|
val receiverType = argumentAsFunctionExpression?.receiverType
|
||||||
val returnType =
|
val returnType =
|
||||||
argumentAsFunctionExpression?.returnType
|
argumentAsFunctionExpression?.returnType
|
||||||
?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype }
|
?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype }
|
||||||
@@ -107,12 +123,16 @@ private fun extraLambdaInfo(
|
|||||||
return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
|
return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractLambdaInfoFromFunctionalType(expectedType: ConeKotlinType?, argument: FirAnonymousFunction): ResolvedLambdaAtom? {
|
private fun extractLambdaInfoFromFunctionalType(
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
expectedTypeRef: FirTypeRef,
|
||||||
|
argument: FirAnonymousFunction
|
||||||
|
): ResolvedLambdaAtom? {
|
||||||
if (expectedType == null || !expectedType.isBuiltinFunctionalType) return null
|
if (expectedType == null || !expectedType.isBuiltinFunctionalType) return null
|
||||||
val parameters = extractLambdaParameters(expectedType, argument)
|
val parameters = extractLambdaParameters(expectedType, argument)
|
||||||
|
|
||||||
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
||||||
val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.receiverType
|
val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.receiverType(expectedTypeRef)
|
||||||
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.returnType
|
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.returnType
|
||||||
|
|
||||||
return ResolvedLambdaAtom(
|
return ResolvedLambdaAtom(
|
||||||
|
|||||||
+1
@@ -106,6 +106,7 @@ class PostponedArgumentsAnalyzer(
|
|||||||
c.getBuilder(),
|
c.getBuilder(),
|
||||||
it,
|
it,
|
||||||
lambda.returnType.let(::substitute),
|
lambda.returnType.let(::substitute),
|
||||||
|
lambda.atom.returnTypeRef, // TODO: proper ref
|
||||||
checkerSink,
|
checkerSink,
|
||||||
false,
|
false,
|
||||||
{ atom = it },
|
{ atom = it },
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
|||||||
resolveArgumentExpression(
|
resolveArgumentExpression(
|
||||||
candidate.csBuilder, explicitReceiverExpression,
|
candidate.csBuilder, explicitReceiverExpression,
|
||||||
candidate.substitutor.substituteOrSelf(receiverParameterValue.type),
|
candidate.substitutor.substituteOrSelf(receiverParameterValue.type),
|
||||||
|
explicitReceiverExpression.typeRef,
|
||||||
sink, isReceiver = true, typeProvider = callInfo.typeProvider, acceptLambdaAtoms = { candidate.postponedAtoms += it }
|
sink, isReceiver = true, typeProvider = callInfo.typeProvider, acceptLambdaAtoms = { candidate.postponedAtoms += it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user