[FE] Allow lambda argument cast to contextual functional type
This commit is contained in:
committed by
TeamCityServer
parent
d8faa9686d
commit
7fce2691e2
+5
-2
@@ -106,6 +106,7 @@ class KotlinResolutionCallbacksImpl(
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
contextReceiversTypes: List<UnwrappedType>,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?,
|
||||
annotations: Annotations,
|
||||
@@ -170,10 +171,12 @@ class KotlinResolutionCallbacksImpl(
|
||||
val refinedReceiverType = receiverType?.let {
|
||||
@OptIn(TypeRefinement::class) callComponents.kotlinTypeChecker.kotlinTypeRefiner.refineType(it)
|
||||
}
|
||||
val refinedContextReceiverTypes = contextReceiversTypes.map {
|
||||
@OptIn(TypeRefinement::class) callComponents.kotlinTypeChecker.kotlinTypeRefiner.refineType(it)
|
||||
}
|
||||
|
||||
// TODO: Context receivers?
|
||||
val expectedType = createFunctionType(
|
||||
builtIns, annotations, refinedReceiverType, emptyList(), parameters, null,
|
||||
builtIns, annotations, refinedReceiverType, refinedContextReceiverTypes, parameters, null,
|
||||
lambdaInfo.expectedType, isSuspend
|
||||
)
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ class FunctionExpressionImpl(
|
||||
val containingBlockForFunction: KtExpression,
|
||||
override val ktFunction: KtNamedFunction,
|
||||
override val receiverType: UnwrappedType?,
|
||||
override val contextReceiversTypes: Array<UnwrappedType?>,
|
||||
override val parametersTypes: Array<UnwrappedType?>,
|
||||
override val returnType: UnwrappedType?
|
||||
) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
|
||||
@@ -250,13 +251,14 @@ fun processFunctionalExpression(
|
||||
// if function is a not anonymous function, resolve it as simple expression
|
||||
if (!postponedExpression.isFunctionalExpression()) return null
|
||||
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference, typeResolver)
|
||||
val contextReceiversTypes = resolveContextReceiversTypes(outerCallContext, postponedExpression, typeResolver)
|
||||
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression, typeResolver) ?: emptyArray()
|
||||
val returnType = resolveType(outerCallContext, postponedExpression.typeReference, typeResolver)
|
||||
?: if (postponedExpression.hasBlockBody()) builtIns.unitType else null
|
||||
|
||||
FunctionExpressionImpl(
|
||||
outerCallContext, valueArgument, startDataFlowInfo, argumentName,
|
||||
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType
|
||||
argumentExpression, postponedExpression, receiverType, contextReceiversTypes, parametersTypes, returnType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -286,6 +288,18 @@ private fun resolveParametersTypes(
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveContextReceiversTypes(
|
||||
context: BasicCallResolutionContext,
|
||||
ktFunction: KtFunction,
|
||||
typeResolver: TypeResolver
|
||||
): Array<UnwrappedType?> {
|
||||
val contextReceivers = ktFunction.contextReceivers
|
||||
|
||||
return Array(contextReceivers.size) {
|
||||
contextReceivers[it]?.typeReference()?.let { typeRef -> resolveType(context, typeRef, typeResolver) }
|
||||
}
|
||||
}
|
||||
|
||||
@JvmName("resolveTypeWithGivenTypeReference")
|
||||
internal fun resolveType(
|
||||
context: BasicCallResolutionContext,
|
||||
|
||||
+1
@@ -76,6 +76,7 @@ interface KotlinResolutionCallbacks {
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
contextReceiversTypes: List<UnwrappedType>,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?, // null means, that return type is not proper i.e. it depends on some type variables
|
||||
annotations: Annotations,
|
||||
|
||||
+13
-1
@@ -86,7 +86,7 @@ private fun preprocessLambdaArgument(
|
||||
|
||||
if (expectedType != null) {
|
||||
val lambdaType = createFunctionType(
|
||||
csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver, emptyList(), // TODO: Context receivers?
|
||||
csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver, resolvedArgument.contextReceivers,
|
||||
resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend
|
||||
)
|
||||
csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPositionImpl(argument))
|
||||
@@ -114,6 +114,14 @@ private fun extraLambdaInfo(
|
||||
argumentAsFunctionExpression?.returnType ?: expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype }
|
||||
?: typeVariable.defaultType
|
||||
|
||||
val contextReceiversTypes = argumentAsFunctionExpression?.contextReceiversTypes?.mapIndexed { index, contextReceiverType ->
|
||||
if (contextReceiverType != null) {
|
||||
contextReceiverType
|
||||
} else {
|
||||
diagnosticsHolder.addDiagnostic(NotEnoughInformationForLambdaParameter(argument, index))
|
||||
ErrorUtils.createErrorType("<Unknown lambda context receiver type>")
|
||||
}
|
||||
} ?: emptyList()
|
||||
val parameters = argument.parametersTypes?.mapIndexed { index, parameterType ->
|
||||
if (parameterType != null) {
|
||||
parameterType
|
||||
@@ -130,6 +138,7 @@ private fun extraLambdaInfo(
|
||||
argument,
|
||||
isSuspend,
|
||||
receiverType,
|
||||
contextReceiversTypes,
|
||||
parameters,
|
||||
returnType,
|
||||
typeVariable.takeIf { newTypeVariableUsed },
|
||||
@@ -146,6 +155,7 @@ private fun extractLambdaInfoFromFunctionalType(
|
||||
val parametersTypes = argument.parametersTypes
|
||||
val expectedParameters = expectedType.getValueParameterTypesFromFunctionType()
|
||||
val expectedReceiver = expectedType.getReceiverTypeFromFunctionType()?.unwrap()
|
||||
val expectedContextReceivers = expectedType.getContextReceiverTypesFromFunctionType().map { it.unwrap() }.toTypedArray()
|
||||
val argumentAsFunctionExpression = argument.safeAs<FunctionExpression>()
|
||||
|
||||
val receiverFromExpected = argumentAsFunctionExpression?.receiverType == null && expectedReceiver != null
|
||||
@@ -186,6 +196,7 @@ private fun extractLambdaInfoFromFunctionalType(
|
||||
type.orExpected(index)
|
||||
} ?: expectedParameters.map { it.type.unwrap() }) to (if (receiverFromExpected) expectedReceiver else null)
|
||||
}
|
||||
val contextReceivers = (argumentAsFunctionExpression?.contextReceiversTypes ?: expectedContextReceivers).filterNotNull()
|
||||
|
||||
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
|
||||
|
||||
@@ -193,6 +204,7 @@ private fun extractLambdaInfoFromFunctionalType(
|
||||
argument,
|
||||
expectedType.isSuspendFunctionType,
|
||||
receiver,
|
||||
contextReceivers,
|
||||
parameters,
|
||||
returnType,
|
||||
typeVariableForLambdaReturnType = returnTypeVariable,
|
||||
|
||||
+10
-4
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
@@ -94,10 +91,14 @@ class PostponedArgumentsAnalyzer(
|
||||
|
||||
val expectedParameters = lambda.expectedType.valueParameters()
|
||||
val expectedReceiver = lambda.expectedType.receiver()
|
||||
val expectedContextReceivers = lambda.expectedType.contextReceivers()
|
||||
|
||||
val receiver = lambda.receiver?.let {
|
||||
expectedOrActualType(expectedReceiver ?: expectedParameters?.getOrNull(0), lambda.receiver)
|
||||
}
|
||||
val contextReceivers = lambda.contextReceivers.mapIndexedNotNull { i, contextReceiver ->
|
||||
expectedOrActualType(expectedContextReceivers?.getOrNull(i), contextReceiver)
|
||||
}
|
||||
|
||||
val expectedParametersToMatchAgainst = when {
|
||||
receiver == null && expectedReceiver != null && expectedParameters != null -> listOf(expectedReceiver) + expectedParameters
|
||||
@@ -131,6 +132,7 @@ class PostponedArgumentsAnalyzer(
|
||||
lambda.atom,
|
||||
lambda.isSuspend,
|
||||
receiver,
|
||||
contextReceivers,
|
||||
parameters,
|
||||
expectedTypeForReturnArguments,
|
||||
convertedAnnotations ?: Annotations.EMPTY,
|
||||
@@ -220,6 +222,10 @@ class PostponedArgumentsAnalyzer(
|
||||
return forFunctionalType { getReceiverTypeFromFunctionType()?.unwrap() }
|
||||
}
|
||||
|
||||
private fun UnwrappedType?.contextReceivers(): List<UnwrappedType>? {
|
||||
return forFunctionalType { getContextReceiverTypesFromFunctionType().map { it.unwrap() } }
|
||||
}
|
||||
|
||||
private fun UnwrappedType?.valueParameters(): List<UnwrappedType>? {
|
||||
return forFunctionalType { getValueParameterTypesFromFunctionType().map { it.type.unwrap() } }
|
||||
}
|
||||
|
||||
+2
@@ -73,6 +73,8 @@ interface FunctionExpression : LambdaKotlinCallArgument {
|
||||
// null means that there function can not have receiver
|
||||
val receiverType: UnwrappedType?
|
||||
|
||||
val contextReceiversTypes: Array<UnwrappedType?>
|
||||
|
||||
// null means that return type is not declared, for fun(){ ... } returnType == Unit
|
||||
val returnType: UnwrappedType?
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ fun File.open(): InputStream = TODO()
|
||||
fun withAutoClose(block: context(AutoCloseScope) () -> Unit) {
|
||||
val scope = AutoCloseScopeImpl() // Not shown here
|
||||
try {
|
||||
with(scope) { block() }
|
||||
with(scope) { block(<!NO_VALUE_FOR_PARAMETER!>)<!> }
|
||||
} finally {
|
||||
scope.close()
|
||||
}
|
||||
|
||||
+17
@@ -45,9 +45,26 @@ fun test() {
|
||||
with(C()) {
|
||||
with(R()) {
|
||||
f1(lf1)
|
||||
f1 { _ ->
|
||||
r
|
||||
c
|
||||
}
|
||||
|
||||
f2(lf2)
|
||||
f2 { _ ->
|
||||
c
|
||||
}
|
||||
|
||||
f3(lf3)
|
||||
f3 {
|
||||
r
|
||||
c
|
||||
}
|
||||
|
||||
f4(lf4)
|
||||
f4 {
|
||||
c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -45,9 +45,26 @@ fun test() {
|
||||
with(C()) {
|
||||
with(R()) {
|
||||
f1(lf1)
|
||||
f1 { _ ->
|
||||
r
|
||||
c
|
||||
}
|
||||
|
||||
f2(lf2)
|
||||
f2 { _ ->
|
||||
c
|
||||
}
|
||||
|
||||
f3(lf3)
|
||||
f3 {
|
||||
r
|
||||
c
|
||||
}
|
||||
|
||||
f4(lf4)
|
||||
f4 {
|
||||
c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user