[NI] Add common supertype for PSI lambda arguments

Also move initial dataFlowInfo to lambda arguments.
As result, we can not store outer call for postpone call arguments
This commit is contained in:
Stanislav Erokhin
2017-07-08 23:07:35 +03:00
parent aedb4c0ade
commit 9bbfac11b4
9 changed files with 51 additions and 43 deletions
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
@@ -69,31 +68,23 @@ class KotlinResolutionCallbacksImpl(
} }
override fun analyzeAndGetLambdaResultArguments( override fun analyzeAndGetLambdaResultArguments(
outerCall: KotlinCall,
lambdaArgument: LambdaKotlinCallArgument, lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean, isSuspend: Boolean,
receiverType: UnwrappedType?, receiverType: UnwrappedType?,
parameters: List<UnwrappedType>, parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType? expectedReturnType: UnwrappedType?
): List<SimpleKotlinCallArgument> { ): List<SimpleKotlinCallArgument> {
val psiCallArgument = lambdaArgument.psiCallArgument val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
val outerCallContext = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.outerCallContext ?: val outerCallContext = psiCallArgument.outerCallContext
(psiCallArgument as FunctionExpressionImpl).outerCallContext
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) = fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor, createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo) CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo)
val expression: KtExpression = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.ktLambdaExpression ?:
(psiCallArgument as FunctionExpressionImpl).ktFunction
val ktFunction: KtFunction = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.ktLambdaExpression?.functionLiteral ?:
(psiCallArgument as FunctionExpressionImpl).ktFunction
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE, val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT) if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, ktFunction, lambdaInfo) trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null, val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
@@ -105,10 +96,10 @@ class KotlinResolutionCallbacksImpl(
.replaceBindingTrace(trace) .replaceBindingTrace(trace)
.replaceContextDependency(lambdaInfo.contextDependency) .replaceContextDependency(lambdaInfo.contextDependency)
.replaceExpectedType(approximatesExpectedType) .replaceExpectedType(approximatesExpectedType)
.replaceDataFlowInfo(outerCall.psiKotlinCall.resultDataFlowInfo) .replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext) val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, ktFunction, LambdaInfo.STUB_EMPTY) trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
var hasReturnWithoutExpression = false var hasReturnWithoutExpression = false
val returnArguments = lambdaInfo.returnStatements.mapNotNullTo(ArrayList()) { (expression, typeInfo) -> val returnArguments = lambdaInfo.returnStatements.mapNotNullTo(ArrayList()) { (expression, typeInfo) ->
@@ -81,30 +81,43 @@ class ParseErrorKotlinCallArgument(
get() = dataFlowInfoAfterThisArgument get() = dataFlowInfoAfterThisArgument
} }
class LambdaKotlinCallArgumentImpl( abstract class PSIFunctionKotlinCallArgument(
val outerCallContext: BasicCallResolutionContext, val outerCallContext: BasicCallResolutionContext,
override val valueArgument: ValueArgument, override val valueArgument: ValueArgument,
override val dataFlowInfoBeforeThisArgument: DataFlowInfo, override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
val ktLambdaExpression: KtLambdaExpression, override val argumentName: Name?
override val argumentName: Name?,
override val parametersTypes: Array<UnwrappedType?>?
) : LambdaKotlinCallArgument, PSIKotlinCallArgument() { ) : LambdaKotlinCallArgument, PSIKotlinCallArgument() {
override val dataFlowInfoAfterThisArgument: DataFlowInfo override val dataFlowInfoAfterThisArgument: DataFlowInfo // todo drop this and use only lambdaInitialDataFlowInfo
get() = dataFlowInfoBeforeThisArgument get() = dataFlowInfoBeforeThisArgument
abstract val ktFunction: KtFunction
abstract val expression: KtExpression
lateinit var lambdaInitialDataFlowInfo: DataFlowInfo
}
class LambdaKotlinCallArgumentImpl(
outerCallContext: BasicCallResolutionContext,
valueArgument: ValueArgument,
dataFlowInfoBeforeThisArgument: DataFlowInfo,
argumentName: Name?,
val ktLambdaExpression: KtLambdaExpression,
override val parametersTypes: Array<UnwrappedType?>?
) : PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
override val ktFunction get() = ktLambdaExpression.functionLiteral
override val expression get() = ktLambdaExpression
} }
class FunctionExpressionImpl( class FunctionExpressionImpl(
val outerCallContext: BasicCallResolutionContext, outerCallContext: BasicCallResolutionContext,
override val valueArgument: ValueArgument, valueArgument: ValueArgument,
override val dataFlowInfoBeforeThisArgument: DataFlowInfo, dataFlowInfoBeforeThisArgument: DataFlowInfo,
val ktFunction: KtNamedFunction, argumentName: Name?,
override val argumentName: Name?, override val ktFunction: KtNamedFunction,
override val receiverType: UnwrappedType?, override val receiverType: UnwrappedType?,
override val parametersTypes: Array<UnwrappedType?>, override val parametersTypes: Array<UnwrappedType?>,
override val returnType: UnwrappedType? override val returnType: UnwrappedType?
) : FunctionExpression, PSIKotlinCallArgument() { ) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
override val dataFlowInfoAfterThisArgument: DataFlowInfo override val expression get() = ktFunction
get() = dataFlowInfoBeforeThisArgument
} }
class CallableReferenceKotlinCallArgumentImpl( class CallableReferenceKotlinCallArgumentImpl(
@@ -171,6 +184,13 @@ class EmptyLabeledReturn(
override val isSafeCall: Boolean get() = false override val isSafeCall: Boolean get() = false
} }
internal fun KotlinCallArgument.setResultDataFlowInfoIfRelevant(resultDataFlowInfo: DataFlowInfo) {
if (this is PSIFunctionKotlinCallArgument) {
lambdaInitialDataFlowInfo = resultDataFlowInfo
}
}
// context here is context for value argument analysis // context here is context for value argument analysis
internal fun createSimplePSICallArgument( internal fun createSimplePSICallArgument(
contextForArgument: BasicCallResolutionContext, contextForArgument: BasicCallResolutionContext,
@@ -423,6 +423,9 @@ class PSICallResolver(
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) } val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis, return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments) astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
} }
@@ -501,14 +504,14 @@ class PSICallResolver(
val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) { val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) {
is KtLambdaExpression -> is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName, LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression,
resolveParametersTypes(outerCallContext, ktExpression.functionLiteral)) resolveParametersTypes(outerCallContext, ktExpression.functionLiteral))
is KtNamedFunction -> { is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference) val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray() val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?: val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?:
if (ktExpression.hasBlockBody()) builtIns.unitType else null if (ktExpression.hasBlockBody()) builtIns.unitType else null
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName, receiverType, parametersTypes, returnType) FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression, receiverType, parametersTypes, returnType)
} }
else -> null else -> null
} }
@@ -156,7 +156,6 @@ class CallableReferencesCandidateFactory(
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit, val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
val expectedType: UnwrappedType? val expectedType: UnwrappedType?
) : CandidateFactory<CallableReferenceCandidate> { ) : CandidateFactory<CallableReferenceCandidate> {
private val position = ArgumentConstraintPosition(argument)
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) = fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver) createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver)
@@ -34,7 +34,6 @@ interface KotlinResolutionExternalPredicates {
// This components hold state (trace). Work with this carefully. // This components hold state (trace). Work with this carefully.
interface KotlinResolutionCallbacks { interface KotlinResolutionCallbacks {
fun analyzeAndGetLambdaResultArguments( fun analyzeAndGetLambdaResultArguments(
outerCall: KotlinCall,
lambdaArgument: LambdaKotlinCallArgument, lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean, isSuspend: Boolean,
receiverType: UnwrappedType?, receiverType: UnwrappedType?,
@@ -199,7 +199,7 @@ class KotlinCallCompleter(
val parameters = lambda.parameters.map(::substitute) val parameters = lambda.parameters.map(::substitute)
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute) val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
lambda.analyzed = true lambda.analyzed = true
lambda.resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.outerCall, lambda.argument, lambda.isSuspend, receiver, parameters, expectedType) lambda.resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.argument, lambda.isSuspend, receiver, parameters, expectedType)
for (resultLambdaArgument in lambda.resultArguments) { for (resultLambdaArgument in lambda.resultArguments) {
checkSimpleArgument(c.getBuilder(), resultLambdaArgument, lambda.returnType.let(::substitute)) checkSimpleArgument(c.getBuilder(), resultLambdaArgument, lambda.returnType.let(::substitute))
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
@@ -26,14 +25,12 @@ import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
fun createPostponedArgumentAndPerformInitialChecks( fun createPostponedArgumentAndPerformInitialChecks(
kotlinCall: KotlinCall,
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: PostponableKotlinCallArgument, argument: PostponableKotlinCallArgument,
parameterDescriptor: ValueParameterDescriptor expectedType: UnwrappedType
): KotlinCallDiagnostic? { ): KotlinCallDiagnostic? {
val expectedType = argument.getExpectedType(parameterDescriptor)
val (postponedArgument, diagnostic) = when (argument) { val (postponedArgument, diagnostic) = when (argument) {
is LambdaKotlinCallArgument -> preprocessLambdaArgument(kotlinCall, csBuilder, argument, expectedType) is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType)
is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType) is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType)
is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(csBuilder, argument, expectedType) is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(csBuilder, argument, expectedType)
else -> unexpectedArgument(argument) else -> unexpectedArgument(argument)
@@ -45,7 +42,6 @@ fun createPostponedArgumentAndPerformInitialChecks(
// if expected type isn't function type, then may be it is Function<R>, Any or just `T` // if expected type isn't function type, then may be it is Function<R>, Any or just `T`
private fun preprocessLambdaArgument( private fun preprocessLambdaArgument(
kotlinCall: KotlinCall,
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: LambdaKotlinCallArgument, argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType
@@ -84,7 +80,7 @@ private fun preprocessLambdaArgument(
// what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design // what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design
} }
val resolvedArgument = PostponedLambdaArgument(kotlinCall, argument, isSuspend, receiverType, parameters, returnType) val resolvedArgument = PostponedLambdaArgument(argument, isSuspend, receiverType, parameters, returnType)
csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument)) csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument))
@@ -234,11 +234,12 @@ internal object CheckArguments : ResolutionPart {
val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue
for (argument in resolvedCallArgument.arguments) { for (argument in resolvedCallArgument.arguments) {
val expectedType = argument.getExpectedType(parameterDescriptor)
val diagnostic = when (argument) { val diagnostic = when (argument) {
is SimpleKotlinCallArgument -> is SimpleKotlinCallArgument ->
checkSimpleArgument(csBuilder, argument, argument.getExpectedType(parameterDescriptor)) checkSimpleArgument(csBuilder, argument, expectedType)
is PostponableKotlinCallArgument -> is PostponableKotlinCallArgument ->
createPostponedArgumentAndPerformInitialChecks(kotlinCall, csBuilder, argument, parameterDescriptor) createPostponedArgumentAndPerformInitialChecks(csBuilder, argument, expectedType)
else -> unexpectedArgument(argument) else -> unexpectedArgument(argument)
} }
diagnostics.addIfNotNull(diagnostic) diagnostics.addIfNotNull(diagnostic)
@@ -30,7 +30,6 @@ sealed class PostponedKotlinCallArgument {
} }
class PostponedLambdaArgument( class PostponedLambdaArgument(
val outerCall: KotlinCall,
override val argument: LambdaKotlinCallArgument, override val argument: LambdaKotlinCallArgument,
val isSuspend: Boolean, val isSuspend: Boolean,
val receiver: UnwrappedType?, val receiver: UnwrappedType?,