Postpone full resolution for a candidate known to be failed
It's necessary for performance, because there are some resolution parts that actually can be omitted and at the same time they aren't very cheap (like inference or value arguments types checking)
This commit is contained in:
@@ -706,15 +706,15 @@ class CandidateResolver(
|
|||||||
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
||||||
|
|
||||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
|
||||||
checker: CallCandidateResolutionContext<D>.() -> Unit
|
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
|
||||||
) {
|
) {
|
||||||
if (shouldContinue()) checker()
|
if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
||||||
checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
||||||
) {
|
) {
|
||||||
if (shouldContinue()) {
|
check {
|
||||||
candidateCall.addStatus(checker())
|
candidateCall.addStatus(checker())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.model;
|
package org.jetbrains.kotlin.resolve.calls.model;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function0;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
@@ -42,6 +44,10 @@ public interface MutableResolvedCall<D extends CallableDescriptor> extends Resol
|
|||||||
|
|
||||||
void markCallAsCompleted();
|
void markCallAsCompleted();
|
||||||
|
|
||||||
|
void addRemainingTasks(Function0<Unit> task);
|
||||||
|
|
||||||
|
void performRemainingTasks();
|
||||||
|
|
||||||
boolean isCompleted();
|
boolean isCompleted();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+22
-2
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve.calls.model;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function0;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
@@ -81,6 +83,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
private Boolean hasInferredReturnType = null;
|
private Boolean hasInferredReturnType = null;
|
||||||
private boolean completed = false;
|
private boolean completed = false;
|
||||||
private KotlinType smartCastDispatchReceiverType = null;
|
private KotlinType smartCastDispatchReceiverType = null;
|
||||||
|
private Queue<Function0<Unit>> remainingTasks = null;
|
||||||
|
|
||||||
private ResolvedCallImpl(
|
private ResolvedCallImpl(
|
||||||
@NotNull ResolutionCandidate<D> candidate,
|
@NotNull ResolutionCandidate<D> candidate,
|
||||||
@@ -283,7 +286,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
|
for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
|
||||||
arguments.add(null);
|
arguments.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
|
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
|
||||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||||
ResolvedValueArgument value = entry.getValue();
|
ResolvedValueArgument value = entry.getValue();
|
||||||
@@ -299,7 +302,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,6 +356,23 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
constraintSystem = null;
|
constraintSystem = null;
|
||||||
tracing = null;
|
tracing = null;
|
||||||
completed = true;
|
completed = true;
|
||||||
|
remainingTasks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addRemainingTasks(Function0<Unit> task) {
|
||||||
|
if (remainingTasks == null) {
|
||||||
|
remainingTasks = new ArrayDeque<>();
|
||||||
|
}
|
||||||
|
remainingTasks.add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performRemainingTasks() {
|
||||||
|
if (remainingTasks == null) return;
|
||||||
|
while (!remainingTasks.isEmpty()) {
|
||||||
|
remainingTasks.poll().invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+44
-14
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
||||||
@@ -56,6 +55,7 @@ import org.jetbrains.kotlin.types.ErrorUtils
|
|||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.types.isDynamic
|
import org.jetbrains.kotlin.types.isDynamic
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.sure
|
import org.jetbrains.kotlin.utils.sure
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -208,12 +208,15 @@ class NewResolutionOldInference(
|
|||||||
|
|
||||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||||
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.FULLY // todo
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
||||||
MyCandidate(diagnostics, resolvedCall)
|
MyCandidate(diagnostics, resolvedCall) {
|
||||||
|
resolvedCall.performRemainingTasks()
|
||||||
|
listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (basicCallContext.collectAllCandidates) {
|
if (basicCallContext.collectAllCandidates) {
|
||||||
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
||||||
@@ -315,12 +318,26 @@ class NewResolutionOldInference(
|
|||||||
override val isDebuggerContext: Boolean get() = resolutionContext.isDebuggerContext
|
override val isDebuggerContext: Boolean get() = resolutionContext.isDebuggerContext
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class MyCandidate(
|
internal class MyCandidate(
|
||||||
val diagnostics: List<KotlinCallDiagnostic>,
|
// Diagnostics that are already computed
|
||||||
val resolvedCall: MutableResolvedCall<*>
|
// if resultingApplicability is successful they must be the same as `diagnostics`,
|
||||||
|
// otherwise they might be a bit different but result remains unsuccessful
|
||||||
|
val eagerDiagnostics: List<KotlinCallDiagnostic>,
|
||||||
|
val resolvedCall: MutableResolvedCall<*>,
|
||||||
|
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
|
||||||
) : Candidate {
|
) : Candidate {
|
||||||
override val resultingApplicability: ResolutionCandidateApplicability = getResultApplicability(diagnostics)
|
val diagnostics: List<KotlinCallDiagnostic> by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
override val isSuccessful get() = resultingApplicability.isSuccess
|
finalDiagnosticsComputation?.invoke() ?: eagerDiagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun component1() = diagnostics
|
||||||
|
operator fun component2() = resolvedCall
|
||||||
|
|
||||||
|
override val resultingApplicability: ResolutionCandidateApplicability by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
getResultApplicability(diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isSuccessful = getResultApplicability(eagerDiagnostics).isSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class CandidateFactoryImpl(
|
private inner class CandidateFactoryImpl(
|
||||||
@@ -366,16 +383,27 @@ class NewResolutionOldInference(
|
|||||||
|
|
||||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||||
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.FULLY // todo
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
val diagnostics = (towerCandidate.diagnostics +
|
val diagnostics = createDiagnosticsForCandidate(towerCandidate, candidateCall)
|
||||||
checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) +
|
return MyCandidate(diagnostics, candidateCall) {
|
||||||
createPreviousResolveError(candidateCall.status)).filterNotNull() // todo
|
candidateCall.performRemainingTasks()
|
||||||
return MyCandidate(diagnostics, candidateCall)
|
createDiagnosticsForCandidate(towerCandidate, candidateCall)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createDiagnosticsForCandidate(
|
||||||
|
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||||
|
candidateCall: ResolvedCallImpl<CallableDescriptor>
|
||||||
|
): List<ResolutionDiagnostic> =
|
||||||
|
mutableListOf<ResolutionDiagnostic>().apply {
|
||||||
|
addAll(towerCandidate.diagnostics)
|
||||||
|
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
|
||||||
|
addIfNotNull(createPreviousResolveError(candidateCall.status))
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
||||||
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
|
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
|
||||||
if (descriptor.name != name && (name == OperatorNameConventions.UNARY_PLUS || name == OperatorNameConventions.UNARY_MINUS)) {
|
if (descriptor.name != name && (name == OperatorNameConventions.UNARY_PLUS || name == OperatorNameConventions.UNARY_MINUS)) {
|
||||||
@@ -405,7 +433,9 @@ class NewResolutionOldInference(
|
|||||||
"Variable call must be success: $variable"
|
"Variable call must be success: $variable"
|
||||||
}
|
}
|
||||||
|
|
||||||
return MyCandidate(variable.diagnostics + invoke.diagnostics, resolvedCallImpl)
|
return MyCandidate(variable.eagerDiagnostics + invoke.eagerDiagnostics, resolvedCallImpl) {
|
||||||
|
variable.diagnostics + invoke.diagnostics
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<MyCandidate> {
|
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<MyCandidate> {
|
||||||
|
|||||||
Reference in New Issue
Block a user