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