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 316f9bbe55f..c3b1edc1349 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.resolve.calls; import com.google.common.collect.Lists; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; import kotlin.Unit; import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; @@ -62,6 +64,8 @@ import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage.recordScopeAndDataFlowInfo; import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS; import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS; +import static org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode.EXIT_ON_FIRST_ERROR; +import static org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode.FULLY; import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER; import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; @@ -565,38 +569,22 @@ public class CallResolver { @NotNull private OverloadResolutionResultsImpl performResolution( - @NotNull final ResolutionTask task, - @NotNull final CallTransformer callTransformer + @NotNull ResolutionTask task, + @NotNull CallTransformer callTransformer ) { + List> contexts = collectCallCandidateContext(task, callTransformer, EXIT_ON_FIRST_ERROR); + boolean isSuccess = ContainerUtil.exists(contexts, new Condition>() { + @Override + public boolean value(CallCandidateResolutionContext context) { + return context.candidateCall.getStatus().possibleTransformToSuccess(); + } + }); + if (!isSuccess) { + contexts = collectCallCandidateContext(task, callTransformer, FULLY); + } - for (final ResolutionCandidate resolutionCandidate : task.getCandidates()) { - candidatePerfCounter.time(new Function0() { - @Override - public Unit invoke() { - TemporaryBindingTrace candidateTrace = TemporaryBindingTrace.create( - task.trace, "trace to resolve candidate"); - Collection> contexts = - callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace, CandidateResolveMode.FULLY); - for (CallCandidateResolutionContext context : contexts) { - - candidateResolver.performResolutionForCandidateCall(context, task); - - /* important for 'variable as function case': temporary bind reference to descriptor (will be rewritten) - to have a binding to variable while 'invoke' call resolve */ - task.tracing.bindReference(context.candidateCall.getTrace(), context.candidateCall); - - Collection> resolvedCalls = callTransformer.transformCall(context, CallResolver.this, task); - - for (MutableResolvedCall resolvedCall : resolvedCalls) { - BindingTrace trace = resolvedCall.getTrace(); - task.tracing.bindReference(trace, resolvedCall); - task.tracing.bindResolvedCall(trace, resolvedCall); - task.addResolvedCall(resolvedCall); - } - } - return Unit.INSTANCE$; - } - }); + for (CallCandidateResolutionContext context : contexts) { + addResolvedCall(task, callTransformer, context); } OverloadResolutionResultsImpl results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors( @@ -606,4 +594,48 @@ public class CallResolver { } return results; } + + @NotNull + private List> collectCallCandidateContext( + @NotNull final ResolutionTask task, + @NotNull final CallTransformer callTransformer, + @NotNull final CandidateResolveMode candidateResolveMode + ) { + final List> candidateResolutionContexts = ContainerUtil.newArrayList(); + for (final ResolutionCandidate resolutionCandidate : task.getCandidates()) { + candidatePerfCounter.time(new Function0() { + @Override + public Unit invoke() { + TemporaryBindingTrace candidateTrace = TemporaryBindingTrace.create( + task.trace, "trace to resolve candidate"); + Collection> contexts = + callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace, candidateResolveMode); + for (CallCandidateResolutionContext context : contexts) { + candidateResolver.performResolutionForCandidateCall(context, task); + candidateResolutionContexts.add(context); + } + return Unit.INSTANCE$; + } + }); + } + return candidateResolutionContexts; + } + + private void addResolvedCall( + @NotNull ResolutionTask task, + @NotNull CallTransformer callTransformer, + @NotNull CallCandidateResolutionContext context) { + /* important for 'variable as function case': temporary bind reference to descriptor (will be rewritten) + to have a binding to variable while 'invoke' call resolve */ + task.tracing.bindReference(context.candidateCall.getTrace(), context.candidateCall); + + Collection> resolvedCalls = callTransformer.transformCall(context, this, task); + + for (MutableResolvedCall resolvedCall : resolvedCalls) { + BindingTrace trace = resolvedCall.getTrace(); + task.tracing.bindReference(trace, resolvedCall); + task.tracing.bindResolvedCall(trace, resolvedCall); + task.addResolvedCall(resolvedCall); + } + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionStatus.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionStatus.java index e3dc280c23b..389f754689a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionStatus.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionStatus.java @@ -57,6 +57,10 @@ public enum ResolutionStatus { return success; } + public boolean possibleTransformToSuccess() { + return this == UNKNOWN_STATUS || this == INCOMPLETE_TYPE_INFERENCE || this == SUCCESS; + } + @NotNull public ResolutionStatus combine(ResolutionStatus other) { if (this == UNKNOWN_STATUS) return other;