From e666b8754540787e02b2853993e6604eb498f3f3 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 21 Aug 2017 14:57:21 +0300 Subject: [PATCH] [NI] Support `AllCandidates` mode for features in IDE --- .../tower/KotlinToResolvedCallTransformer.kt | 1 + .../resolve/calls/tower/PSICallResolver.kt | 26 ++++++++++++++----- .../resolve/calls/KotlinCallResolver.kt | 19 ++++++++++++-- .../calls/components/KotlinCallCompleter.kt | 25 ++++++++++++++++-- .../resolve/calls/model/ResolutionAtoms.kt | 6 +++-- 5 files changed, 65 insertions(+), 12 deletions(-) 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 90fe7194f6a..8fcf1ea903c 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 @@ -98,6 +98,7 @@ class KotlinToResolvedCallTransformer( return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall } + CallResolutionResult.Type.ALL_CANDIDATES -> error("Cannot transform result for ALL_CANDIDATES mode") } } 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 d14c6b2d707..eaca4710562 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 @@ -41,9 +41,9 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency +import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.* -import org.jetbrains.kotlin.resolve.calls.results.ManyCandidates import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors @@ -93,7 +93,8 @@ class PSICallResolver( val factoryProviderForInvoke = FactoryProviderForInvoke(context, scopeTower, kotlinCall) val expectedType = calculateExpectedType(context) - var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke) + var result = kotlinCallResolver.resolveCall( + scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) { @@ -125,7 +126,8 @@ class PSICallResolver( it.knownTypeParametersResultingSubstitutor) } - val result = kotlinCallResolver.resolveGivenCandidates(scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates) + val result = kotlinCallResolver.resolveGivenCandidates( + scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates) return convertToOverloadResolutionResults(context, result, tracingStrategy) } @@ -142,7 +144,8 @@ class PSICallResolver( val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName) - return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, refinedProviderForInvokeFactory) + return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, + refinedProviderForInvokeFactory, context.collectAllCandidates) } private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name { @@ -173,6 +176,15 @@ class PSICallResolver( result: CallResolutionResult, tracingStrategy: TracingStrategy ): OverloadResolutionResults { + if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) { + val resolvedCalls = result.allCandidates?.map { + val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor() + kotlinToResolvedCallTransformer.transformToResolvedCall(it.resolvedCall, false, resultingSubstitutor) + } + + return AllCandidates(resolvedCalls ?: emptyList()) + } + val trace = context.trace result.diagnostics.firstIsInstanceOrNull()?.let { @@ -559,8 +571,10 @@ class PSICallResolver( ktExpression, argumentName, lhsNewResult, name) } - // valueArgument.getArgumentExpression()!! instead of ktExpression is hack -- type info should be stored also for parenthesized expression - val typeInfo = expressionTypingServices.getTypeInfo(valueArgument.getArgumentExpression()!!, context) + val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument + + // argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression + val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context) return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt index b5cd5998e42..12d4457ddc9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt @@ -38,7 +38,8 @@ class KotlinCallResolver( resolutionCallbacks: KotlinResolutionCallbacks, kotlinCall: KotlinCall, expectedType: UnwrappedType?, - factoryProviderForInvoke: CandidateFactoryProviderForInvoke + factoryProviderForInvoke: CandidateFactoryProviderForInvoke, + collectAllCandidates: Boolean ): CallResolutionResult { kotlinCall.checkCallInvariants() @@ -53,6 +54,11 @@ class KotlinCallResolver( KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException() } + if (collectAllCandidates) { + val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor) + return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks) + } + val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) @@ -63,12 +69,21 @@ class KotlinCallResolver( resolutionCallbacks: KotlinResolutionCallbacks, kotlinCall: KotlinCall, expectedType: UnwrappedType?, - givenCandidates: Collection + givenCandidates: Collection, + collectAllCandidates: Boolean ): CallResolutionResult { kotlinCall.checkCallInvariants() val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() } + + if (collectAllCandidates) { + val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), + TowerResolver.AllCandidatesCollector(), + useOrder = false) + return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks) + + } val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), TowerResolver.SuccessfulResultCollector(), useOrder = true) 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 c2728e9e761..4b22b5b571d 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 @@ -68,7 +68,25 @@ class KotlinCallCompleter( else { CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) } + } + fun createAllCandidatesResult( + candidates: Collection, + expectedType: UnwrappedType?, + resolutionCallbacks: KotlinResolutionCallbacks + ): CallResolutionResult { + val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder() + for (candidate in candidates) { + candidate.prepareForCompletion(expectedType) + runCompletion( + candidate.resolvedCall, + ConstraintSystemCompletionMode.FULL, + diagnosticsHolder, + candidate.getSystem(), + resolutionCallbacks, + skipPostponedArguments = true) + } + return CallResolutionResult(CallResolutionResult.Type.ALL_CANDIDATES, null, emptyList(), ConstraintStorage.Empty, candidates) } private fun runCompletion( @@ -76,11 +94,14 @@ class KotlinCallCompleter( completionMode: ConstraintSystemCompletionMode, diagnosticsHolder: KotlinDiagnosticsHolder, constraintSystem: NewConstraintSystem, - resolutionCallbacks: KotlinResolutionCallbacks + resolutionCallbacks: KotlinResolutionCallbacks, + skipPostponedArguments: Boolean = false ) { val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) { - postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) + if (!skipPostponedArguments) { + postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) + } } constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index f3551632b09..f1951998827 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -150,14 +150,16 @@ class CallResolutionResult( val type: Type, val resultCallAtom: ResolvedCallAtom?, diagnostics: List, - val constraintSystem: ConstraintStorage + val constraintSystem: ConstraintStorage, + val allCandidates: Collection? = null ) : ResolvedAtom() { override val atom: ResolutionAtom? get() = null enum class Type { COMPLETED, // resultSubstitutor possible create use constraintSystem PARTIAL, - ERROR // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates + ERROR, // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates + ALL_CANDIDATES // allCandidates != null } init {