[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.annotations.Annotations
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
@@ -69,31 +68,23 @@ class KotlinResolutionCallbacksImpl(
}
override fun analyzeAndGetLambdaResultArguments(
outerCall: KotlinCall,
lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean,
receiverType: UnwrappedType?,
parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType?
): List<SimpleKotlinCallArgument> {
val psiCallArgument = lambdaArgument.psiCallArgument
val outerCallContext = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.outerCallContext ?:
(psiCallArgument as FunctionExpressionImpl).outerCallContext
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
val outerCallContext = psiCallArgument.outerCallContext
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
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,
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 expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
@@ -105,10 +96,10 @@ class KotlinResolutionCallbacksImpl(
.replaceBindingTrace(trace)
.replaceContextDependency(lambdaInfo.contextDependency)
.replaceExpectedType(approximatesExpectedType)
.replaceDataFlowInfo(outerCall.psiKotlinCall.resultDataFlowInfo)
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, ktFunction, LambdaInfo.STUB_EMPTY)
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
var hasReturnWithoutExpression = false
val returnArguments = lambdaInfo.returnStatements.mapNotNullTo(ArrayList()) { (expression, typeInfo) ->
@@ -81,30 +81,43 @@ class ParseErrorKotlinCallArgument(
get() = dataFlowInfoAfterThisArgument
}
class LambdaKotlinCallArgumentImpl(
abstract class PSIFunctionKotlinCallArgument(
val outerCallContext: BasicCallResolutionContext,
override val valueArgument: ValueArgument,
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
val ktLambdaExpression: KtLambdaExpression,
override val argumentName: Name?,
override val parametersTypes: Array<UnwrappedType?>?
override val argumentName: Name?
) : LambdaKotlinCallArgument, PSIKotlinCallArgument() {
override val dataFlowInfoAfterThisArgument: DataFlowInfo
override val dataFlowInfoAfterThisArgument: DataFlowInfo // todo drop this and use only lambdaInitialDataFlowInfo
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(
val outerCallContext: BasicCallResolutionContext,
override val valueArgument: ValueArgument,
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
val ktFunction: KtNamedFunction,
override val argumentName: Name?,
outerCallContext: BasicCallResolutionContext,
valueArgument: ValueArgument,
dataFlowInfoBeforeThisArgument: DataFlowInfo,
argumentName: Name?,
override val ktFunction: KtNamedFunction,
override val receiverType: UnwrappedType?,
override val parametersTypes: Array<UnwrappedType?>,
override val returnType: UnwrappedType?
) : FunctionExpression, PSIKotlinCallArgument() {
override val dataFlowInfoAfterThisArgument: DataFlowInfo
get() = dataFlowInfoBeforeThisArgument
) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
override val expression get() = ktFunction
}
class CallableReferenceKotlinCallArgumentImpl(
@@ -171,6 +184,13 @@ class EmptyLabeledReturn(
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
internal fun createSimplePSICallArgument(
contextForArgument: BasicCallResolutionContext,
@@ -423,6 +423,9 @@ class PSICallResolver(
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
}
@@ -501,14 +504,14 @@ class PSICallResolver(
val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) {
is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName,
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression,
resolveParametersTypes(outerCallContext, ktExpression.functionLiteral))
is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?:
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
}