[NI] Store stub resolved call to trace because some clients read this before all calls are completed.

This is bad idea, but this is how it works in old inference.
Now we just save old behaviour.
Future plan: fix checks where we get unfinished resolved calls.
This commit is contained in:
Stanislav Erokhin
2017-04-06 15:45:00 +03:00
parent 78f8d29a4c
commit c4ddc7a3a6
6 changed files with 63 additions and 11 deletions
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyVariableAsFunctionCall;
import org.jetbrains.kotlin.types.KotlinType;
import java.util.Collection;
@@ -60,7 +61,7 @@ public class OverloadResolutionResultsUtil {
}
}
else {
if (resultingCall instanceof StubOnlyResolvedCall) {
if (resultingCall instanceof StubOnlyResolvedCall || resultingCall instanceof StubOnlyVariableAsFunctionCall) {
return null;
}
}
@@ -62,16 +62,47 @@ class KotlinToResolvedCallTransformer(
trace: BindingTrace? // if trace is not null then all information will be reported to this trace
): ResolvedCall<D> {
if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) {
baseResolvedCall.allInnerCalls.forEach { transformAndReportCompletedCall<D>(it, context, trace) }
return transformAndReportCompletedCall(baseResolvedCall.completedCall, context, trace)
val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList<ResolvedCall<*>>()) { transformAndReportCompletedCall<CallableDescriptor>(it, context, trace) }
val result = transformAndReportCompletedCall<D>(baseResolvedCall.completedCall, context, trace)
allResolvedCalls.add(result)
if (trace != null) {
val callCheckerContext = CallCheckerContext(context.replaceBindingTrace(trace), languageFeatureSettings)
for (resolvedCall in allResolvedCalls) {
runCallCheckers(resolvedCall, callCheckerContext)
}
}
return result
}
val onlyResolvedCall = (baseResolvedCall as ResolvedKotlinCall.OnlyResolvedKotlinCall)
trace?.record(BindingContext.ONLY_RESOLVED_CALL, onlyResolvedCall.candidate.kotlinCall.psiKotlinCall.psiCall, onlyResolvedCall)
return StubOnlyResolvedCall(onlyResolvedCall.candidate.lastCall)
return createStubResolvedCallAndWriteItToTrace(onlyResolvedCall.candidate, trace)
}
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: KotlinResolutionCandidate, trace: BindingTrace?): ResolvedCall<D> {
val result = when (candidate) {
is VariableAsFunctionKotlinResolutionCandidate -> {
val variableStub = StubOnlyResolvedCall<VariableDescriptor>(candidate.resolvedVariable)
val invokeStub = StubOnlyResolvedCall<FunctionDescriptor>(candidate.invokeCandidate)
StubOnlyVariableAsFunctionCall(variableStub, invokeStub) as ResolvedCall<D>
}
is SimpleKotlinResolutionCandidate -> {
StubOnlyResolvedCall<D>(candidate)
}
}
if (trace != null) {
val tracing = candidate.kotlinCall.psiKotlinCall.tracingStrategy
tracing.bindReference(trace, result)
tracing.bindResolvedCall(trace, result)
}
return result
}
private fun <D : CallableDescriptor> transformAndReportCompletedCall(
completedCall: CompletedKotlinCall,
context: BasicCallResolutionContext,
@@ -97,12 +128,11 @@ class KotlinToResolvedCallTransformer(
(resolvedCall as ResolvedCall<D>)
}
}
runCallCheckers(resolvedCall, context)
return resolvedCall
}
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) {
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
resolvedCall.variableCall.call.calleeExpression
else
@@ -111,9 +141,12 @@ class KotlinToResolvedCallTransformer(
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
else resolvedCall.call.callElement
val callCheckerContext = CallCheckerContext(context, languageFeatureSettings)
for (callChecker in callCheckers) {
callChecker.check(resolvedCall, reportOn, callCheckerContext)
if (resolvedCall is VariableAsFunctionResolvedCall) {
callChecker.check(resolvedCall.variableCall, reportOn, callCheckerContext)
}
}
}
@@ -348,4 +381,9 @@ class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinRe
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
get() = candidate.argumentMappingByOriginal
override val kotlinCall: KotlinCall get() = candidate.kotlinCall
}
}
class StubOnlyVariableAsFunctionCall(
override val variableCall: StubOnlyResolvedCall<VariableDescriptor>,
override val functionCall: StubOnlyResolvedCall<FunctionDescriptor>
) : VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
@@ -41,7 +43,8 @@ import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
class LambdaAnalyzerImpl(
val expressionTypingServices: ExpressionTypingServices,
val trace: BindingTrace,
val typeApproximator: TypeApproximator
val typeApproximator: TypeApproximator,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
): LambdaAnalyzer {
override fun analyzeAndGetRelatedCalls(
@@ -87,4 +90,8 @@ class LambdaAnalyzerImpl(
return listOfNotNull(simpleArgument)
}
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) {
kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace)
}
}
@@ -89,7 +89,7 @@ class PSICallResolver(
) : OverloadResolutionResults<D> {
val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, name, tracingStrategy)
val scopeTower = ASTScopeTower(context)
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator)
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer)
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
val factoryProviderForInvoke = FactoryProviderForInvoke(context, callContext, kotlinCall)
@@ -112,7 +112,7 @@ class PSICallResolver(
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
val scopeTower = ASTScopeTower(context)
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator)
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer)
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
val givenCandidates = resolutionCandidates.map {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.types.UnwrappedType
@@ -34,4 +35,8 @@ interface LambdaAnalyzer {
parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables
): List<KotlinCallArgument>
// todo this is hack for some client which try to read ResolvedCall from trace before all calls completed
fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate)
}
@@ -69,6 +69,7 @@ class KotlinCallCompleter(
expectedType: UnwrappedType?,
lambdaAnalyzer: LambdaAnalyzer
): ResolvedKotlinCall {
lambdaAnalyzer.bindStubResolvedCallForCandidate(candidate)
val topLevelCall =
if (candidate is VariableAsFunctionKotlinResolutionCandidate) {
candidate.invokeCandidate