From c4ddc7a3a6e9a4ac10f70f28c1a2d5c972c56602 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Thu, 6 Apr 2017 15:45:00 +0300 Subject: [PATCH] [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. --- .../OverloadResolutionResultsUtil.java | 3 +- .../tower/KotlinToResolvedCallTransformer.kt | 52 ++++++++++++++++--- .../resolve/calls/tower/LambdaAnalyzerImpl.kt | 9 +++- .../resolve/calls/tower/PSICallResolver.kt | 4 +- .../calls/components/ExternalComponents.kt | 5 ++ .../calls/components/KotlinCallCompleter.kt | 1 + 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java index e64bf0d49a8..61643f98ea1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java @@ -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; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index 45884d144cb..903ce49bffe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -62,16 +62,47 @@ class KotlinToResolvedCallTransformer( trace: BindingTrace? // if trace is not null then all information will be reported to this trace ): ResolvedCall { if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) { - baseResolvedCall.allInnerCalls.forEach { transformAndReportCompletedCall(it, context, trace) } - return transformAndReportCompletedCall(baseResolvedCall.completedCall, context, trace) + val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList>()) { transformAndReportCompletedCall(it, context, trace) } + val result = transformAndReportCompletedCall(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 createStubResolvedCallAndWriteItToTrace(candidate: KotlinResolutionCandidate, trace: BindingTrace?): ResolvedCall { + val result = when (candidate) { + is VariableAsFunctionKotlinResolutionCandidate -> { + val variableStub = StubOnlyResolvedCall(candidate.resolvedVariable) + val invokeStub = StubOnlyResolvedCall(candidate.invokeCandidate) + StubOnlyVariableAsFunctionCall(variableStub, invokeStub) as ResolvedCall + } + is SimpleKotlinResolutionCandidate -> { + StubOnlyResolvedCall(candidate) + } + } + if (trace != null) { + val tracing = candidate.kotlinCall.psiKotlinCall.tracingStrategy + + tracing.bindReference(trace, result) + tracing.bindResolvedCall(trace, result) + } + return result + } + + private fun transformAndReportCompletedCall( completedCall: CompletedKotlinCall, context: BasicCallResolutionContext, @@ -97,12 +128,11 @@ class KotlinToResolvedCallTransformer( (resolvedCall as ResolvedCall) } } - 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(val candidate: SimpleKotlinRe override val argumentMappingByOriginal: Map get() = candidate.argumentMappingByOriginal override val kotlinCall: KotlinCall get() = candidate.kotlinCall -} \ No newline at end of file +} + +class StubOnlyVariableAsFunctionCall( + override val variableCall: StubOnlyResolvedCall, + override val functionCall: StubOnlyResolvedCall +) : VariableAsFunctionResolvedCall, ResolvedCall by functionCall diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/LambdaAnalyzerImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/LambdaAnalyzerImpl.kt index 707ceee3316..cfe30df8100 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/LambdaAnalyzerImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/LambdaAnalyzerImpl.kt @@ -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(candidate, trace) + } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 00ad78b27e0..f17a7983e99 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -89,7 +89,7 @@ class PSICallResolver( ) : OverloadResolutionResults { 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 { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index f3d80a275f8..a69802354f0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -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, expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables ): List + + // todo this is hack for some client which try to read ResolvedCall from trace before all calls completed + fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) + } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index a4453f82ab6..0ba8df0d969 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -69,6 +69,7 @@ class KotlinCallCompleter( expectedType: UnwrappedType?, lambdaAnalyzer: LambdaAnalyzer ): ResolvedKotlinCall { + lambdaAnalyzer.bindStubResolvedCallForCandidate(candidate) val topLevelCall = if (candidate is VariableAsFunctionKotlinResolutionCandidate) { candidate.invokeCandidate