diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index e3a01804a34..4dcf3bd601b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -706,15 +706,15 @@ class CandidateResolver( candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess() private inline fun CallCandidateResolutionContext.check( - checker: CallCandidateResolutionContext.() -> Unit + crossinline checker: CallCandidateResolutionContext.() -> Unit ) { - if (shouldContinue()) checker() + if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() } } private inline fun CallCandidateResolutionContext.checkAndReport( - checker: CallCandidateResolutionContext.() -> ResolutionStatus + crossinline checker: CallCandidateResolutionContext.() -> ResolutionStatus ) { - if (shouldContinue()) { + check { candidateCall.addStatus(checker()) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java index e18ad4ac416..849ae8490b5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.resolve.calls.model; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor; @@ -42,6 +44,10 @@ public interface MutableResolvedCall extends Resol void markCallAsCompleted(); + void addRemainingTasks(Function0 task); + + void performRemainingTasks(); + boolean isCompleted(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java index 73be3a9dbe0..9cb7a2d6b7a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java @@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve.calls.model; import com.google.common.collect.Maps; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.SmartList; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor; @@ -81,6 +83,7 @@ public class ResolvedCallImpl implements MutableRe private Boolean hasInferredReturnType = null; private boolean completed = false; private KotlinType smartCastDispatchReceiverType = null; + private Queue> remainingTasks = null; private ResolvedCallImpl( @NotNull ResolutionCandidate candidate, @@ -283,7 +286,7 @@ public class ResolvedCallImpl implements MutableRe for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) { arguments.add(null); } - + for (Map.Entry entry : valueArguments.entrySet()) { ValueParameterDescriptor parameterDescriptor = entry.getKey(); ResolvedValueArgument value = entry.getValue(); @@ -299,7 +302,7 @@ public class ResolvedCallImpl implements MutableRe return null; } } - + return arguments; } @@ -353,6 +356,23 @@ public class ResolvedCallImpl implements MutableRe constraintSystem = null; tracing = null; completed = true; + remainingTasks = null; + } + + @Override + public void addRemainingTasks(Function0 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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index 7a5f1174eba..630d6c8e292 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -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.context.* 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.results.OverloadResolutionResultsImpl 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.isDynamic import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.sure import java.lang.IllegalStateException import java.util.* @@ -208,12 +208,15 @@ class NewResolutionOldInference( val callCandidateResolutionContext = CallCandidateResolutionContext.create( resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, - CandidateResolveMode.FULLY // todo + CandidateResolveMode.EXIT_ON_FIRST_ERROR ) candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status)) - MyCandidate(diagnostics, resolvedCall) + MyCandidate(diagnostics, resolvedCall) { + resolvedCall.performRemainingTasks() + listOfNotNull(createPreviousResolveError(resolvedCall.status)) + } } if (basicCallContext.collectAllCandidates) { val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), @@ -315,12 +318,26 @@ class NewResolutionOldInference( override val isDebuggerContext: Boolean get() = resolutionContext.isDebuggerContext } - internal data class MyCandidate( - val diagnostics: List, - val resolvedCall: MutableResolvedCall<*> + internal class MyCandidate( + // Diagnostics that are already computed + // 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, + val resolvedCall: MutableResolvedCall<*>, + finalDiagnosticsComputation: (() -> List)? = null ) : Candidate { - override val resultingApplicability: ResolutionCandidateApplicability = getResultApplicability(diagnostics) - override val isSuccessful get() = resultingApplicability.isSuccess + val diagnostics: List by lazy(LazyThreadSafetyMode.NONE) { + 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( @@ -366,16 +383,27 @@ class NewResolutionOldInference( val callCandidateResolutionContext = CallCandidateResolutionContext.create( candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, - CandidateResolveMode.FULLY // todo + CandidateResolveMode.EXIT_ON_FIRST_ERROR ) candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo - val diagnostics = (towerCandidate.diagnostics + - checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) + - createPreviousResolveError(candidateCall.status)).filterNotNull() // todo - return MyCandidate(diagnostics, candidateCall) + val diagnostics = createDiagnosticsForCandidate(towerCandidate, candidateCall) + return MyCandidate(diagnostics, candidateCall) { + candidateCall.performRemainingTasks() + createDiagnosticsForCandidate(towerCandidate, candidateCall) + } } + private fun createDiagnosticsForCandidate( + towerCandidate: CandidateWithBoundDispatchReceiver, + candidateCall: ResolvedCallImpl + ): List = + mutableListOf().apply { + addAll(towerCandidate.diagnostics) + addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor)) + addIfNotNull(createPreviousResolveError(candidateCall.status)) + } + private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List { if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList() if (descriptor.name != name && (name == OperatorNameConventions.UNARY_PLUS || name == OperatorNameConventions.UNARY_MINUS)) { @@ -405,7 +433,9 @@ class NewResolutionOldInference( "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 {