From 3b41fcb5babaafcc0e0c3402a89a4bb49ae014f1 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Tue, 12 Apr 2016 03:22:45 +0300 Subject: [PATCH] Refactoring. Add type safety to resolution. --- .../kotlin/resolve/calls/CallResolver.java | 47 ++-- ...erence.kt => NewResolutionOldInference.kt} | 227 ++++++++++++------ .../resolve/calls/tower/InvokeProcessors.kt | 75 +++--- .../calls/tower/ScopeTowerProcessors.kt | 41 ++-- .../resolve/calls/tower/TowerResolver.kt | 40 ++- 5 files changed, 257 insertions(+), 173 deletions(-) rename compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/{NewResolveOldInference.kt => NewResolutionOldInference.kt} (63%) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 1472257d1b1..fa5b945869b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -38,7 +38,7 @@ import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.tasks.*; -import org.jetbrains.kotlin.resolve.calls.tower.NewResolveOldInference; +import org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; @@ -58,6 +58,7 @@ import java.util.*; import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS; import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE; +import static org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference.ResolutionKind.*; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; @SuppressWarnings("RedundantTypeArguments") @@ -67,7 +68,7 @@ public class CallResolver { private ArgumentTypeResolver argumentTypeResolver; private GenericCandidateResolver genericCandidateResolver; private CallCompleter callCompleter; - private NewResolveOldInference newCallResolver; + private NewResolutionOldInference newCallResolver; private final KotlinBuiltIns builtIns; private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter); @@ -110,7 +111,7 @@ public class CallResolver { // component dependency cycle @Inject - public void setCallCompleter(@NotNull NewResolveOldInference newCallResolver) { + public void setCallCompleter(@NotNull NewResolutionOldInference newCallResolver) { this.newCallResolver = newCallResolver; } @@ -122,7 +123,7 @@ public class CallResolver { Name referencedName = nameExpression.getReferencedNameAsName(); return computeTasksAndResolveCall( context, referencedName, nameExpression, - ResolveKind.VARIABLE); + Variable.INSTANCE); } @NotNull @@ -132,7 +133,7 @@ public class CallResolver { ) { return computeTasksAndResolveCall( context, nameExpression.getReferencedNameAsName(), nameExpression, - ResolveKind.CALLABLE_REFERENCE); + CallableReference.INSTANCE); } @NotNull @@ -145,7 +146,7 @@ public class CallResolver { BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS); return computeTasksAndResolveCall( callResolutionContext, name, functionReference, - ResolveKind.FUNCTION); + Function.INSTANCE); } @NotNull @@ -155,7 +156,7 @@ public class CallResolver { ) { return computeTasksAndResolveCall( context, OperatorNameConventions.INVOKE, tracing, - ResolveKind.INVOKE); + Invoke.INSTANCE); } @NotNull @@ -163,7 +164,7 @@ public class CallResolver { @NotNull BasicCallResolutionContext context, @NotNull Name name, @NotNull KtReferenceExpression referenceExpression, - @NotNull ResolveKind kind + @NotNull NewResolutionOldInference.ResolutionKind kind ) { TracingStrategy tracing = TracingStrategyImpl.create(referenceExpression, context.call); return computeTasksAndResolveCall(context, name, tracing, kind); @@ -174,7 +175,7 @@ public class CallResolver { @NotNull final BasicCallResolutionContext context, @NotNull final Name name, @NotNull final TracingStrategy tracing, - @NotNull final ResolveKind kind + @NotNull final NewResolutionOldInference.ResolutionKind kind ) { return callResolvePerfCounter.time(new Function0>() { @Override @@ -207,7 +208,7 @@ public class CallResolver { @Override public OverloadResolutionResults invoke() { ResolutionTask resolutionTask = new ResolutionTask( - ResolveKind.GIVEN_CANDIDATES, null, candidates + new NewResolutionOldInference.ResolutionKind.GivenCandidates(), null, candidates ); return doResolveCallOrGetCachedResults(context, resolutionTask, tracing); } @@ -256,7 +257,7 @@ public class CallResolver { KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) context.call.getCallElement(); return computeTasksAndResolveCall( context, name, arrayAccessExpression, - ResolveKind.FUNCTION); + Function.INSTANCE); } KtExpression calleeExpression = context.call.getCalleeExpression(); @@ -264,7 +265,7 @@ public class CallResolver { KtSimpleNameExpression expression = (KtSimpleNameExpression) calleeExpression; return computeTasksAndResolveCall( context, expression.getReferencedNameAsName(), expression, - ResolveKind.FUNCTION); + Function.INSTANCE); } else if (calleeExpression instanceof KtConstructorCalleeExpression) { return (OverloadResolutionResults) resolveCallForConstructor(context, (KtConstructorCalleeExpression) calleeExpression); @@ -488,7 +489,7 @@ public class CallResolver { ResolutionTask resolutionTask = new ResolutionTask( - ResolveKind.GIVEN_CANDIDATES, null, candidates + new NewResolutionOldInference.ResolutionKind.GivenCandidates(), null, candidates ); @@ -592,14 +593,13 @@ public class CallResolver { } } - if (resolutionTask.resolveKind != ResolveKind.GIVEN_CANDIDATES) { + if (!(resolutionTask.resolutionKind instanceof GivenCandidates)) { assert resolutionTask.name != null; - return (OverloadResolutionResultsImpl) - newCallResolver.runResolve(context, resolutionTask.name, resolutionTask.resolveKind, tracing); + return newCallResolver.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing); } else { assert resolutionTask.givenCandidates != null; - return newCallResolver.runResolveForGivenCandidates(context, tracing, resolutionTask.givenCandidates); + return newCallResolver.runResolutionForGivenCandidates(context, tracing, resolutionTask.givenCandidates); } } @@ -613,24 +613,17 @@ public class CallResolver { final Collection> givenCandidates; @NotNull - final ResolveKind resolveKind; + final NewResolutionOldInference.ResolutionKind resolutionKind; private ResolutionTask( - @NotNull ResolveKind kind, + @NotNull NewResolutionOldInference.ResolutionKind kind, @Nullable Name name, @Nullable Collection> candidates ) { this.name = name; givenCandidates = candidates; - resolveKind = kind; + resolutionKind = kind; } } - public enum ResolveKind { - FUNCTION, - INVOKE, - VARIABLE, - CALLABLE_REFERENCE, - GIVEN_CANDIDATES, - } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt similarity index 63% rename from compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt rename to compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index de32e6fb676..46b9f04a7cd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.resolve.TemporaryBindingTrace -import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.CandidateResolver import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getUnaryPlusOrMinusOperatorFunctionName @@ -51,7 +50,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.sure -class NewResolveOldInference( +class NewResolutionOldInference( private val candidateResolver: CandidateResolver, private val towerResolver: TowerResolver, private val resolutionResultsHandler: ResolutionResultsHandler, @@ -59,23 +58,93 @@ class NewResolveOldInference( private val syntheticScopes: SyntheticScopes ) { - fun runResolve( + sealed class ResolutionKind { + abstract internal fun createTowerProcessor( + outer: NewResolutionOldInference, + name: Name, + tracing: TracingStrategy, + scopeTower: ScopeTower, + explicitReceiver: Receiver?, + context: BasicCallResolutionContext + ): ScopeTowerProcessor> + + object Function : ResolutionKind() { + override fun createTowerProcessor( + outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy, + scopeTower: ScopeTower, explicitReceiver: Receiver?, context: BasicCallResolutionContext + ): ScopeTowerProcessor> { + val invokeContext = outer.InvokeContext(scopeTower, name, context, tracing) + return outer.createFunctionTowerProcessor(invokeContext, explicitReceiver) + } + + } + object Variable : ResolutionKind() { + override fun createTowerProcessor( + outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy, + scopeTower: ScopeTower, explicitReceiver: Receiver?, context: BasicCallResolutionContext + ): ScopeTowerProcessor> { + val simpleContext = outer.SimpleContext(scopeTower, name, context, tracing) + return createVariableProcessor(simpleContext, explicitReceiver) + } + + } + + object CallableReference : ResolutionKind() { + override fun createTowerProcessor( + outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy, + scopeTower: ScopeTower, explicitReceiver: Receiver?, context: BasicCallResolutionContext + ): ScopeTowerProcessor> { + val simpleContextF = outer.SimpleContext(scopeTower, name, context, tracing) + val simpleContextV = outer.SimpleContext(scopeTower, name, context, tracing) + return CompositeScopeTowerProcessor( + createFunctionProcessor(simpleContextF, explicitReceiver), + createVariableProcessor(simpleContextV, explicitReceiver) + ) + } + } + + object Invoke : ResolutionKind() { + override fun createTowerProcessor( + outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy, + scopeTower: ScopeTower, explicitReceiver: Receiver?, context: BasicCallResolutionContext + ): ScopeTowerProcessor> { + val invokeContext = outer.InvokeContext(scopeTower, name, context, tracing) + // todo + val call = (context.call as? CallTransformer.CallForImplicitInvoke).sure { + "Call should be CallForImplicitInvoke, but it is: ${context.call}" + } + return outer.createProcessorWithReceiverValueOrEmpty(explicitReceiver) { + createCallTowerProcessorForExplicitInvoke(invokeContext, call.dispatchReceiver, it) + } + } + + } + + class GivenCandidates : ResolutionKind() { + override fun createTowerProcessor( + outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy, + scopeTower: ScopeTower, explicitReceiver: Receiver?, context: BasicCallResolutionContext + ): ScopeTowerProcessor> { + throw IllegalStateException("Should be not called") + } + } + } + + fun runResolution( context: BasicCallResolutionContext, name: Name, - kind: CallResolver.ResolveKind, + kind: ResolutionKind, tracing: TracingStrategy - ): OverloadResolutionResultsImpl<*> { + ): OverloadResolutionResultsImpl { val explicitReceiver = context.call.explicitReceiver val dynamicScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor) val scopeTower = ScopeTowerImpl(context, dynamicScope, syntheticScopes, context.call.createLookupLocation()) - val baseContext = Context(scopeTower, name, context, tracing) - - var processor = createResolveProcessor(kind, explicitReceiver, context, baseContext) + var processor = kind.createTowerProcessor(this, name, tracing, scopeTower, explicitReceiver, context) if (context.collectAllCandidates) { - return allCandidatesResult(towerResolver.collectAllCandidates(baseContext, processor)) + return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor)) } // Temporary fix for code migration (unaryPlus()/unaryMinus()) val unaryConventionName = getUnaryPlusOrMinusOperatorFunctionName(context.call) @@ -84,15 +153,16 @@ class NewResolveOldInference( OperatorNameConventions.PLUS else OperatorNameConventions.MINUS - val otherBaseContext = Context(scopeTower, deprecatedName, context, tracing) - processor = CompositeScopeTowerProcessor(processor, createResolveProcessor(kind, explicitReceiver, context, otherBaseContext)) + + val deprecatedProcessor = kind.createTowerProcessor(this, deprecatedName, tracing, scopeTower, explicitReceiver, context) + processor = CompositeScopeTowerProcessor(processor, deprecatedProcessor) } - val candidates = towerResolver.runResolve(baseContext, processor, useOrder = kind != CallResolver.ResolveKind.CALLABLE_REFERENCE) + val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference) return convertToOverloadResults(candidates, tracing, context) } - fun runResolveForGivenCandidates( + fun runResolutionForGivenCandidates( basicCallContext: BasicCallResolutionContext, tracing: TracingStrategy, candidates: Collection> @@ -102,7 +172,7 @@ class NewResolveOldInference( val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments) if (candidate.descriptor.isHiddenInResolution()) { - return@mapNotNull Candidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), resolvedCall) + return@mapNotNull MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), resolvedCall) } val callCandidateResolutionContext = CallCandidateResolutionContext.create( @@ -113,65 +183,42 @@ class NewResolveOldInference( val diagnostics = listOfNotNull(SynthesizedDescriptorDiagnostic.check { candidate.descriptor.isSynthesized }, createPreviousResolveError(resolvedCall.status)) - Candidate(ResolutionCandidateStatus(diagnostics), resolvedCall) + MyCandidate(ResolutionCandidateStatus(diagnostics), resolvedCall) } if (basicCallContext.collectAllCandidates) { val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), TowerResolver.AllCandidatesCollector { it.candidateStatus }, useOrder = false) - return allCandidatesResult(allCandidates) as OverloadResolutionResultsImpl + return allCandidatesResult(allCandidates) } val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), TowerResolver.SuccessfulResultCollector { it.candidateStatus }, useOrder = true) - return convertToOverloadResults(processedCandidates, tracing, basicCallContext) as OverloadResolutionResultsImpl + return convertToOverloadResults(processedCandidates, tracing, basicCallContext) } - private fun allCandidatesResult(allCandidates: Collection) - = OverloadResolutionResultsImpl.nameNotFound().apply { - this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall } + private fun allCandidatesResult(allCandidates: Collection>) + = OverloadResolutionResultsImpl.nameNotFound().apply { + this.allCandidates = allCandidates.map { it.resolvedCall } } - private fun createResolveProcessor( - kind: CallResolver.ResolveKind, - explicitReceiver : Receiver?, - context: BasicCallResolutionContext, - baseContext: Context) - = when (kind) { - CallResolver.ResolveKind.VARIABLE -> createVariableProcessor(baseContext, explicitReceiver) - CallResolver.ResolveKind.FUNCTION -> createFunctionTowerProcessor(baseContext, explicitReceiver) - CallResolver.ResolveKind.CALLABLE_REFERENCE -> CompositeScopeTowerProcessor( - createFunctionProcessor(baseContext, explicitReceiver), - createVariableProcessor(baseContext, explicitReceiver) - ) - CallResolver.ResolveKind.INVOKE -> { - // todo - val call = (context.call as? CallTransformer.CallForImplicitInvoke).sure { - "Call should be CallForImplicitInvoke, but it is: ${context.call}" - } - createProcessorWithReceiverValueOrEmpty(explicitReceiver) { - createCallTowerProcessorForExplicitInvoke(baseContext, call.dispatchReceiver, it) - } - } - CallResolver.ResolveKind.GIVEN_CANDIDATES -> { - throw UnsupportedOperationException("Kind $kind unsupported yet") - } - } - - private fun createProcessorWithReceiverValueOrEmpty( + private fun createProcessorWithReceiverValueOrEmpty( explicitReceiver: Receiver?, - create: (ReceiverValue?) -> ScopeTowerProcessor - ): ScopeTowerProcessor { + create: (ReceiverValue?) -> ScopeTowerProcessor> + ): ScopeTowerProcessor> { return if (explicitReceiver is QualifierReceiver) { (explicitReceiver as? ClassQualifier)?.classValueReceiver?.let(create) - ?: KnownResultProcessor(listOf()) + ?: KnownResultProcessor>(listOf()) } else { create(explicitReceiver as ReceiverValue?) } } - private fun createFunctionTowerProcessor(baseContext: Context, explicitReceiver: Receiver?): CompositeScopeTowerProcessor { + private fun createFunctionTowerProcessor( + baseContext: InvokeTowerContext, MyCandidate>, + explicitReceiver: Receiver? + ): CompositeScopeTowerProcessor> { // a.foo() -- simple function call val simpleFunction = createFunctionProcessor(baseContext, explicitReceiver) @@ -185,11 +232,11 @@ class NewResolveOldInference( } - private fun convertToOverloadResults( - candidates: Collection, + private fun convertToOverloadResults( + candidates: Collection>, tracing: TracingStrategy, basicCallContext: BasicCallResolutionContext - ): OverloadResolutionResultsImpl<*> { + ): OverloadResolutionResultsImpl { val resolvedCalls = candidates.mapNotNull { val (status, resolvedCall) = it if (resolvedCall is VariableAsFunctionResolvedCallImpl) { @@ -224,23 +271,33 @@ class NewResolveOldInference( resolvedCall } - return resolutionResultsHandler.computeResultAndReportErrors(basicCallContext, tracing, resolvedCalls as List>) + return resolutionResultsHandler.computeResultAndReportErrors(basicCallContext, tracing, resolvedCalls) } - private data class Candidate(val candidateStatus: ResolutionCandidateStatus, val resolvedCall: MutableResolvedCall<*>) + internal data class MyCandidate( + val candidateStatus: ResolutionCandidateStatus, + val resolvedCall: MutableResolvedCall<@UnsafeVariance D> + ) : Candidate { + override val descriptor: D + get() = resolvedCall.candidateDescriptor - private inner class Context( + override val isSuccessful: Boolean + get() = candidateStatus.resultingApplicability.isSuccess + override val status: ResolutionCandidateStatus + get() = candidateStatus + } + + private inner open class SimpleContext( override val scopeTower: ScopeTower, override val name: Name, - private val basicCallContext: BasicCallResolutionContext, - private val tracing: TracingStrategy - ) : TowerContext { - + protected val basicCallContext: BasicCallResolutionContext, + protected val tracing: TracingStrategy + ) : TowerContext> { override fun createCandidate( - towerCandidate: CandidateWithBoundDispatchReceiver<*>, + towerCandidate: CandidateWithBoundDispatchReceiver, explicitReceiverKind: ExplicitReceiverKind, extensionReceiver: ReceiverValue? - ): Candidate { + ): MyCandidate { val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate") val candidateCall = ResolvedCallImpl( basicCallContext.call, towerCandidate.descriptor, @@ -252,11 +309,11 @@ class NewResolveOldInference( // see spec-docs/dynamic-types.md if (extensionReceiver != null && extensionReceiver.type.isDynamic() && !towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()) { - return Candidate(ResolutionCandidateStatus(listOf(ExtensionWithStaticTypeWithDynamicReceiver)), candidateCall) + return MyCandidate(ResolutionCandidateStatus(listOf(ExtensionWithStaticTypeWithDynamicReceiver)), candidateCall) } if (towerCandidate.descriptor.isHiddenInResolution()) { - return Candidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), candidateCall) + return MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), candidateCall) } val callCandidateResolutionContext = CallCandidateResolutionContext.create( @@ -268,7 +325,7 @@ class NewResolveOldInference( val diagnostics = (towerCandidate.diagnostics + checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) + createPreviousResolveError(candidateCall.status)).filterNotNull() // todo - return Candidate(ResolutionCandidateStatus(diagnostics), candidateCall) + return MyCandidate(ResolutionCandidateStatus(diagnostics), candidateCall) } private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List { @@ -282,38 +339,52 @@ class NewResolveOldInference( return listOfNotNull(conventionError, infixError) } - override fun getStatus(candidate: Candidate): ResolutionCandidateStatus = candidate.candidateStatus + } - override fun transformCandidate(variable: Candidate, invoke: Candidate): Candidate { + private inner class InvokeContext( + scopeTower: ScopeTower, + name: Name, + basicCallContext: BasicCallResolutionContext, + tracing: TracingStrategy + ) : InvokeTowerContext, MyCandidate>, + SimpleContext(scopeTower, name, basicCallContext, tracing) { + + override fun transformCandidate( + variable: MyCandidate, + invoke: MyCandidate + ): MyCandidate { val resolvedCallImpl = VariableAsFunctionResolvedCallImpl( - invoke.resolvedCall as MutableResolvedCall, - variable.resolvedCall as MutableResolvedCall + invoke.resolvedCall, + variable.resolvedCall ) assert(variable.candidateStatus.resultingApplicability.isSuccess) { "Variable call must be success: $variable" } - return Candidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl) + return MyCandidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl) } - override fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext { + override fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext> { val newCall = CallTransformer.stripCallArguments(basicCallContext.call).let { if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it } - return Context(scopeTower, name, basicCallContext.replaceCall(newCall), tracing) + return SimpleContext(scopeTower, name, basicCallContext.replaceCall(newCall), tracing) } - override fun contextForInvoke(variable: Candidate, useExplicitReceiver: Boolean): Pair>? { + override fun contextForInvoke( + variable: MyCandidate, + useExplicitReceiver: Boolean + ): Pair>>? { assert(variable.resolvedCall.status.possibleTransformToSuccess()) { "Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " + "and descriptor: ${variable.resolvedCall.candidateDescriptor}" } val calleeExpression = variable.resolvedCall.call.calleeExpression val variableDescriptor = variable.resolvedCall.resultingDescriptor - assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null && variableDescriptor is VariableDescriptor) { - "Unexpected varialbe candidate: $variable" + assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null) { + "Unexpected variable candidate: $variable" } - val variableType = (variableDescriptor as VariableDescriptor).type + val variableType = variableDescriptor.type if (variableType is DeferredType && variableType.isComputing) { return null // todo: create special check that there is no invoke on variable @@ -333,7 +404,7 @@ class NewResolveOldInference( .replaceContextDependency(ContextDependency.DEPENDENT) // todo val newScopeTower = ScopeTowerImpl(basicCallResolutionContext, scopeTower.dynamicScope, scopeTower.syntheticScopes, scopeTower.location) - val newContext = Context(newScopeTower, OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke) + val newContext = SimpleContext(newScopeTower, OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke) return variableReceiver to newContext } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt index b775aa098bf..c9278dbfec4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver @@ -25,29 +26,29 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.* -abstract class AbstractInvokeTowerProcessor( - protected val functionContext: TowerContext, - private val variableProcessor: ScopeTowerProcessor -) : ScopeTowerProcessor { +abstract class AbstractInvokeTowerProcessor, V : Candidate>( + protected val invokeContext: InvokeTowerContext, + private val variableProcessor: ScopeTowerProcessor +) : ScopeTowerProcessor { // todo optimize it private val previousData = ArrayList() private val invokeProcessors: MutableList> = ArrayList() - private inner class VariableInvokeProcessor(val variableCandidate: C): ScopeTowerProcessor { - val invokeProcessor: ScopeTowerProcessor = createInvokeProcessor(variableCandidate) + private inner class VariableInvokeProcessor(val variableCandidate: V): ScopeTowerProcessor { + val invokeProcessor: ScopeTowerProcessor = createInvokeProcessor(variableCandidate) override fun process(data: TowerData) = invokeProcessor.process(data).map { candidateGroup -> - candidateGroup.map { functionContext.transformCandidate(variableCandidate, it) } + candidateGroup.map { invokeContext.transformCandidate(variableCandidate, it) } } } - protected abstract fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor + protected abstract fun createInvokeProcessor(variableCandidate: V): ScopeTowerProcessor - override fun process(data: TowerData): List> { + override fun process(data: TowerData): List> { previousData.add(data) - val candidateGroups = ArrayList>(0) + val candidateGroups = ArrayList>(0) for (processorsGroup in invokeProcessors) { candidateGroups.addAll(processorsGroup.processVariableGroup(data)) @@ -55,7 +56,7 @@ abstract class AbstractInvokeTowerProcessor( for (variableCandidates in variableProcessor.process(data)) { val successfulVariables = variableCandidates.filter { - functionContext.getStatus(it).resultingApplicability.isSuccess + it.isSuccessful } if (successfulVariables.isNotEmpty()) { @@ -71,7 +72,7 @@ abstract class AbstractInvokeTowerProcessor( return candidateGroups } - private fun Collection.processVariableGroup(data: TowerData): List> { + private fun Collection.processVariableGroup(data: TowerData): List> { return when (size) { 0 -> emptyList() 1 -> single().process(data) @@ -84,44 +85,44 @@ abstract class AbstractInvokeTowerProcessor( } // todo KT-9522 Allow invoke convention for synthetic property -class InvokeTowerProcessor( - functionContext: TowerContext, +class InvokeTowerProcessor, V : Candidate>( + invokeContext: InvokeTowerContext, private val explicitReceiver: Receiver? -) : AbstractInvokeTowerProcessor( - functionContext, - createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = false), explicitReceiver) +) : AbstractInvokeTowerProcessor( + invokeContext, + createVariableProcessor(invokeContext.contextForVariable(stripExplicitReceiver = false), explicitReceiver) ) { // todo filter by operator - override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor { - val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false) + override fun createInvokeProcessor(variableCandidate: V): ScopeTowerProcessor { + val (variableReceiver, invokeContext) = invokeContext.contextForInvoke(variableCandidate, useExplicitReceiver = false) ?: return KnownResultProcessor(emptyList()) return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions) } } -class InvokeExtensionTowerProcessor( - functionContext: TowerContext, +class InvokeExtensionTowerProcessor, V : Candidate>( + invokeContext: InvokeTowerContext, private val explicitReceiver: ReceiverValue? -) : AbstractInvokeTowerProcessor( - functionContext, - createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = true), explicitReceiver = null) +) : AbstractInvokeTowerProcessor( + invokeContext, + createVariableProcessor(invokeContext.contextForVariable(stripExplicitReceiver = true), explicitReceiver = null) ) { - override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor { - val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = true) + override fun createInvokeProcessor(variableCandidate: V): ScopeTowerProcessor { + val (variableReceiver, invokeContext) = invokeContext.contextForInvoke(variableCandidate, useExplicitReceiver = true) ?: return KnownResultProcessor(emptyList()) - val invokeDescriptor = functionContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver) + val invokeDescriptor = invokeContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver) ?: return KnownResultProcessor(emptyList()) return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver) } } -private class InvokeExtensionScopeTowerProcessor( - context: TowerContext, +private class InvokeExtensionScopeTowerProcessor>( + context: TowerContext, private val invokeCandidateDescriptor: CandidateWithBoundDispatchReceiver, private val explicitReceiver: ReceiverValue? -) : AbstractSimpleScopeTowerProcessor(context) { +) : AbstractSimpleScopeTowerProcessor(context) { override fun simpleProcess(data: TowerData): Collection { if (explicitReceiver != null && data == TowerData.Empty) { @@ -150,23 +151,23 @@ private fun ScopeTower.getExtensionInvokeCandidateDescriptor( } // case 1.(foo())() or (foo())() -fun createCallTowerProcessorForExplicitInvoke( - contextForInvoke: TowerContext, +fun , V : Candidate> createCallTowerProcessorForExplicitInvoke( + invokeContext: InvokeTowerContext, expressionForInvoke: ReceiverValue, explicitReceiver: ReceiverValue? -): ScopeTowerProcessor { - val invokeExtensionDescriptor = contextForInvoke.scopeTower.getExtensionInvokeCandidateDescriptor(expressionForInvoke) +): ScopeTowerProcessor { + val invokeExtensionDescriptor = invokeContext.scopeTower.getExtensionInvokeCandidateDescriptor(expressionForInvoke) if (explicitReceiver != null) { if (invokeExtensionDescriptor == null) { // case 1.(foo())(), where foo() isn't extension function return KnownResultProcessor(emptyList()) } else { - return InvokeExtensionScopeTowerProcessor(contextForInvoke, invokeExtensionDescriptor, explicitReceiver = explicitReceiver) + return InvokeExtensionScopeTowerProcessor(invokeContext, invokeExtensionDescriptor, explicitReceiver = explicitReceiver) } } else { - val usualInvoke = ExplicitReceiverScopeTowerProcessor(contextForInvoke, expressionForInvoke, ScopeTowerLevel::getFunctions) // todo operator + val usualInvoke = ExplicitReceiverScopeTowerProcessor(invokeContext, expressionForInvoke, ScopeTowerLevel::getFunctions) // todo operator if (invokeExtensionDescriptor == null) { return usualInvoke @@ -174,7 +175,7 @@ fun createCallTowerProcessorForExplicitInvoke( else { return CompositeScopeTowerProcessor( usualInvoke, - InvokeExtensionScopeTowerProcessor(contextForInvoke, invokeExtensionDescriptor, explicitReceiver = null) + InvokeExtensionScopeTowerProcessor(invokeContext, invokeExtensionDescriptor, explicitReceiver = null) ) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index 73850780904..9c82c7d9a26 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.resolve.calls.tower +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver @@ -37,8 +40,8 @@ class CompositeScopeTowerProcessor( override fun process(data: TowerData): List> = processors.flatMap { it.process(data) } } -internal abstract class AbstractSimpleScopeTowerProcessor( - val context: TowerContext +internal abstract class AbstractSimpleScopeTowerProcessor>( + val context: TowerContext ) : ScopeTowerProcessor { protected val name: Name get() = context.name @@ -47,11 +50,11 @@ internal abstract class AbstractSimpleScopeTowerProcessor( override fun process(data: TowerData): List> = listOfNotNull(simpleProcess(data).check { it.isNotEmpty() }) } -internal class ExplicitReceiverScopeTowerProcessor( - context: TowerContext, +internal class ExplicitReceiverScopeTowerProcessor>( + context: TowerContext, val explicitReceiver: ReceiverValue, - val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> -): AbstractSimpleScopeTowerProcessor(context) { + val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> +): AbstractSimpleScopeTowerProcessor(context) { override fun simpleProcess(data: TowerData): Collection { return when (data) { TowerData.Empty -> resolveAsMember() @@ -72,11 +75,11 @@ internal class ExplicitReceiverScopeTowerProcessor( } } -private class QualifierScopeTowerProcessor( - context: TowerContext, +private class QualifierScopeTowerProcessor>( + context: TowerContext, val qualifier: QualifierReceiver, - val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> -): AbstractSimpleScopeTowerProcessor(context) { + val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> +): AbstractSimpleScopeTowerProcessor(context) { override fun simpleProcess(data: TowerData): Collection { if (data != TowerData.Empty) return emptyList() @@ -87,10 +90,10 @@ private class QualifierScopeTowerProcessor( } } -private class NoExplicitReceiverScopeTowerProcessor( - context: TowerContext, - val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> -) : AbstractSimpleScopeTowerProcessor(context) { +private class NoExplicitReceiverScopeTowerProcessor>( + context: TowerContext, + val collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> +) : AbstractSimpleScopeTowerProcessor(context) { override fun simpleProcess(data: TowerData): Collection = when(data) { is TowerData.TowerLevel -> { @@ -107,10 +110,10 @@ private class NoExplicitReceiverScopeTowerProcessor( } } -private fun createSimpleProcessor( - context: TowerContext, +private fun > createSimpleProcessor( + context: TowerContext, explicitReceiver: Receiver?, - collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> + collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> ) : ScopeTowerProcessor { if (explicitReceiver is ReceiverValue) { return ExplicitReceiverScopeTowerProcessor(context, explicitReceiver, collectCandidates) @@ -133,8 +136,8 @@ private fun createSimpleProcessor( } } -fun createVariableProcessor(context: TowerContext, explicitReceiver: Receiver?) +fun > createVariableProcessor(context: TowerContext, explicitReceiver: Receiver?) = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getVariables) -fun createFunctionProcessor(context: TowerContext, explicitReceiver: Receiver?) +fun > createFunctionProcessor(context: TowerContext, explicitReceiver: Receiver?) = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getFunctions) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index d54c6add883..28a5cb9fc03 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.resolve.calls.tower +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind @@ -26,25 +29,35 @@ import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.utils.addToStdlib.check import java.util.* -interface TowerContext { +interface Candidate { + val descriptor: D + + // this operation should be very fast + val isSuccessful: Boolean + + val status: ResolutionCandidateStatus +} + +interface TowerContext> { val name: Name val scopeTower: ScopeTower fun createCandidate( - towerCandidate: CandidateWithBoundDispatchReceiver<*>, + towerCandidate: CandidateWithBoundDispatchReceiver, explicitReceiverKind: ExplicitReceiverKind, extensionReceiver: ReceiverValue? ): C +} - fun getStatus(candidate: C): ResolutionCandidateStatus +interface InvokeTowerContext, V : Candidate>: TowerContext { - fun transformCandidate(variable: C, invoke: C): C + fun transformCandidate(variable: V, invoke: F): F - fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext + fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext // foo() -> ReceiverValue(foo), context for invoke // null means that there is no invoke on variable - fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair>? + fun contextForInvoke(variable: V, useExplicitReceiver: Boolean): Pair>? } sealed class TowerData { @@ -54,21 +67,24 @@ sealed class TowerData { class BothTowerLevelAndImplicitReceiver(val level: ScopeTowerLevel, val implicitReceiver: ReceiverValue) : TowerData() } -interface ScopeTowerProcessor { +interface ScopeTowerProcessor { // Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel) // Candidates in one groups have same priority, first group has highest priority. fun process(data: TowerData): List> } class TowerResolver { - fun runResolve( - context: TowerContext, + fun > runResolve( + scopeTower: ScopeTower, processor: ScopeTowerProcessor, useOrder: Boolean - ): Collection = context.scopeTower.run(processor, SuccessfulResultCollector { context.getStatus(it) }, useOrder) + ): Collection = scopeTower.run(processor, SuccessfulResultCollector { it.status }, useOrder) - fun collectAllCandidates(context: TowerContext, processor: ScopeTowerProcessor): Collection - = context.scopeTower.run(processor, AllCandidatesCollector { context.getStatus(it) }, false) + fun > collectAllCandidates( + scopeTower: ScopeTower, + processor: ScopeTowerProcessor + ): Collection + = scopeTower.run(processor, AllCandidatesCollector { it.status }, false) private fun ScopeTower.createNonLocalLevels(): List { val result = ArrayList()