Make candidates lazy in ResolutionTask & ResolutionTaskHolder
This commit is contained in:
@@ -427,7 +427,7 @@ public class CallResolver {
|
||||
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
|
||||
OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null;
|
||||
for (ResolutionTask<D, F> task : prioritizedTasks) {
|
||||
if (successfulResults != null && !context.collectAllCandidates) continue;
|
||||
if (task.getCandidates().isEmpty()) continue;
|
||||
|
||||
TemporaryBindingTrace taskTrace =
|
||||
TemporaryBindingTrace.create(context.trace, "trace to resolve a task for", task.call.getCalleeExpression());
|
||||
@@ -453,6 +453,8 @@ public class CallResolver {
|
||||
traceForFirstNonemptyCandidateSet = taskTrace;
|
||||
resultsForFirstNonemptyCandidateSet = results;
|
||||
}
|
||||
|
||||
if (successfulResults != null && !context.collectAllCandidates) break;
|
||||
}
|
||||
OverloadResolutionResultsImpl<F> results;
|
||||
if (successfulResults != null) {
|
||||
@@ -517,7 +519,7 @@ public class CallResolver {
|
||||
};
|
||||
TemporaryBindingTrace temporaryTrace =
|
||||
TemporaryBindingTrace.create(task.trace, "trace for resolution guarded for extra function literal arguments");
|
||||
ResolutionTask<D, F> newTask = new ResolutionTask<D, F>(task.getCandidates(), task.toBasic(), task.tracing).
|
||||
ResolutionTask<D, F> newTask = task.replaceContext(task.toBasic()).
|
||||
replaceBindingTrace(temporaryTrace).replaceCall(callWithoutFLArgs);
|
||||
|
||||
OverloadResolutionResultsImpl<F> resultsWithFunctionLiteralsStripped = performResolution(newTask, callTransformer);
|
||||
|
||||
+22
-12
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
@@ -37,13 +38,13 @@ import java.util.Collection;
|
||||
* Stores candidates for call resolution.
|
||||
*/
|
||||
public class ResolutionTask<D extends CallableDescriptor, F extends D> extends CallResolutionContext<ResolutionTask<D, F>> {
|
||||
private final Collection<ResolutionCandidate<D>> candidates;
|
||||
private final Function0<Collection<ResolutionCandidate<D>>> lazyCandidates;
|
||||
private final Collection<MutableResolvedCall<F>> resolvedCalls;
|
||||
private DescriptorCheckStrategy checkingStrategy;
|
||||
public final TracingStrategy tracing;
|
||||
|
||||
private ResolutionTask(
|
||||
@NotNull Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull Function0<Collection<ResolutionCandidate<D>>> lazyCandidates,
|
||||
@NotNull TracingStrategy tracing,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope scope,
|
||||
@@ -61,17 +62,17 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
|
||||
) {
|
||||
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
|
||||
dataFlowInfoForArguments, callResolverExtension, isAnnotationContext, collectAllCandidates);
|
||||
this.candidates = candidates;
|
||||
this.lazyCandidates = lazyCandidates;
|
||||
this.resolvedCalls = resolvedCalls;
|
||||
this.tracing = tracing;
|
||||
}
|
||||
|
||||
public ResolutionTask(
|
||||
@NotNull Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull TracingStrategy tracing
|
||||
@NotNull TracingStrategy tracing,
|
||||
@NotNull Function0<Collection<ResolutionCandidate<D>>> lazyCandidates
|
||||
) {
|
||||
this(candidates, tracing,
|
||||
this(lazyCandidates, tracing,
|
||||
context.trace, context.scope, context.call,
|
||||
context.expectedType, context.dataFlowInfo, context.contextDependency, context.checkArguments,
|
||||
context.resolutionResultsCache, context.dataFlowInfoForArguments,
|
||||
@@ -79,16 +80,21 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
|
||||
}
|
||||
|
||||
public ResolutionTask(
|
||||
@NotNull Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull final Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull JetReferenceExpression reference,
|
||||
@NotNull BasicCallResolutionContext context
|
||||
) {
|
||||
this(candidates, context, TracingStrategyImpl.create(reference, context.call));
|
||||
this(context, TracingStrategyImpl.create(reference, context.call), new Function0<Collection<ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<ResolutionCandidate<D>> invoke() {
|
||||
return candidates;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<ResolutionCandidate<D>> getCandidates() {
|
||||
return candidates;
|
||||
return lazyCandidates.invoke();
|
||||
}
|
||||
|
||||
public void addResolvedCall(@NotNull MutableResolvedCall<F> resolvedCall) {
|
||||
@@ -122,16 +128,20 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
|
||||
boolean collectAllCandidates
|
||||
) {
|
||||
ResolutionTask<D, F> newTask = new ResolutionTask<D, F>(
|
||||
candidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
|
||||
lazyCandidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
|
||||
resolutionResultsCache, dataFlowInfoForArguments, callResolverExtension, resolvedCalls, isAnnotationContext,
|
||||
collectAllCandidates);
|
||||
newTask.setCheckingStrategy(checkingStrategy);
|
||||
return newTask;
|
||||
}
|
||||
|
||||
public ResolutionTask<D, F> replaceContext(@NotNull BasicCallResolutionContext newContext) {
|
||||
return new ResolutionTask<D, F>(newContext, tracing, lazyCandidates);
|
||||
}
|
||||
|
||||
public ResolutionTask<D, F> replaceCall(@NotNull Call newCall) {
|
||||
return new ResolutionTask<D, F>(
|
||||
candidates, tracing, trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments,
|
||||
lazyCandidates, tracing, trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments,
|
||||
resolutionResultsCache, dataFlowInfoForArguments, callResolverExtension, resolvedCalls,
|
||||
isAnnotationContext, collectAllCandidates);
|
||||
}
|
||||
@@ -142,6 +152,6 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return candidates.toString();
|
||||
return lazyCandidates.toString();
|
||||
}
|
||||
}
|
||||
|
||||
+18
-28
@@ -16,14 +16,12 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls.tasks
|
||||
|
||||
import com.google.common.base.Predicate
|
||||
import com.google.common.collect.Collections2
|
||||
import com.google.common.collect.Lists
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.jet.storage.StorageManager
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.utils.toReadOnlyList
|
||||
|
||||
public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
private val storageManager: StorageManager,
|
||||
@@ -31,15 +29,10 @@ public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
private val priorityProvider: ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>>,
|
||||
private val tracing: TracingStrategy
|
||||
) {
|
||||
private val isSafeCall: Boolean
|
||||
private val isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call)
|
||||
|
||||
private val candidatesList = Lists.newArrayList<Collection<ResolutionCandidate<D>>>()
|
||||
|
||||
private var internalTasks: MutableList<ResolutionTask<D, F>>? = null
|
||||
|
||||
{
|
||||
this.isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call)
|
||||
}
|
||||
private val candidatesList = ArrayList<() -> Collection<ResolutionCandidate<D>>>()
|
||||
private var internalTasks: List<ResolutionTask<D, F>>? = null
|
||||
|
||||
public fun setIsSafeCall(candidates: Collection<ResolutionCandidate<D>>): Collection<ResolutionCandidate<D>> {
|
||||
for (candidate in candidates) {
|
||||
@@ -48,17 +41,17 @@ public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
return candidates
|
||||
}
|
||||
|
||||
public fun addCandidates(candidates: Collection<ResolutionCandidate<D>>) {
|
||||
public fun addCandidates(lazyCandidates: () -> Collection<ResolutionCandidate<D>>) {
|
||||
assertNotFinished()
|
||||
if (!candidates.isEmpty()) {
|
||||
candidatesList.add(setIsSafeCall(candidates))
|
||||
}
|
||||
candidatesList.add(storageManager.createLazyValue {
|
||||
setIsSafeCall(lazyCandidates()).toReadOnlyList()
|
||||
})
|
||||
}
|
||||
|
||||
public fun addCandidates(candidatesList: List<Collection<ResolutionCandidate<D>>>) {
|
||||
assertNotFinished()
|
||||
for (candidates in candidatesList) {
|
||||
addCandidates(candidates)
|
||||
addCandidates { candidates }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,20 +61,17 @@ public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
|
||||
public fun getTasks(): List<ResolutionTask<D, F>> {
|
||||
if (internalTasks == null) {
|
||||
internalTasks = Lists.newArrayList()
|
||||
|
||||
run {
|
||||
var priority = priorityProvider.getMaxPriority()
|
||||
while (priority >= 0) {
|
||||
for (candidates in candidatesList) {
|
||||
val filteredCandidates = candidates.filter { priority == priorityProvider.getPriority(it) }
|
||||
if (!filteredCandidates.isEmpty()) {
|
||||
internalTasks!!.add(ResolutionTask(filteredCandidates, basicCallResolutionContext, tracing))
|
||||
}
|
||||
val tasks = ArrayList<ResolutionTask<D, F>>()
|
||||
for (priority in (0..priorityProvider.getMaxPriority()).reversed()) {
|
||||
for (candidateIndex in 0..candidatesList.size - 1) {
|
||||
val lazyCandidates = storageManager.createLazyValue {
|
||||
candidatesList[candidateIndex]().filter { priorityProvider.getPriority(it) == priority }.toReadOnlyList()
|
||||
}
|
||||
priority--
|
||||
tasks.add(ResolutionTask(basicCallResolutionContext, tracing, lazyCandidates))
|
||||
}
|
||||
}
|
||||
|
||||
internalTasks = tasks
|
||||
}
|
||||
return internalTasks!!
|
||||
}
|
||||
|
||||
+55
-35
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
@@ -134,46 +135,54 @@ public class TaskPrioritizer {
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver(
|
||||
@NotNull ReceiverValue explicitReceiver,
|
||||
@NotNull final ReceiverValue explicitReceiver,
|
||||
@NotNull Collection<ReceiverValue> implicitReceivers,
|
||||
@NotNull TaskPrioritizerContext<D, F> c,
|
||||
boolean isExplicit
|
||||
@NotNull final TaskPrioritizerContext<D, F> c,
|
||||
final boolean isExplicit
|
||||
) {
|
||||
addMembers(explicitReceiver, c, /*static=*/false, isExplicit);
|
||||
|
||||
for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
|
||||
for (final CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
|
||||
//member extensions
|
||||
for (ReceiverValue implicitReceiver : implicitReceivers) {
|
||||
addMemberExtensionCandidates(implicitReceiver, explicitReceiver,
|
||||
callableDescriptorCollector, c, createKind(EXTENSION_RECEIVER, isExplicit));
|
||||
}
|
||||
//extensions
|
||||
Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
|
||||
c.scope, explicitReceiver, callableDescriptorCollector.getExtensionsByName(c.scope, c.name, c.context.trace),
|
||||
createKind(EXTENSION_RECEIVER, isExplicit), c.context.call);
|
||||
c.result.addCandidates(extensions);
|
||||
c.result.addCandidates(new Function0<Collection<? extends ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<? extends ResolutionCandidate<D>> invoke() {
|
||||
return convertWithImpliedThis(
|
||||
c.scope, explicitReceiver, callableDescriptorCollector.getExtensionsByName(c.scope, c.name, c.context.trace),
|
||||
createKind(EXTENSION_RECEIVER, isExplicit), c.context.call);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor, F extends D> void addMembers(
|
||||
ReceiverValue explicitReceiver,
|
||||
TaskPrioritizerContext<D, F> c,
|
||||
boolean staticMembers,
|
||||
boolean isExplicit
|
||||
final ReceiverValue explicitReceiver,
|
||||
final TaskPrioritizerContext<D, F> c,
|
||||
final boolean staticMembers,
|
||||
final boolean isExplicit
|
||||
) {
|
||||
List<JetType> variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context);
|
||||
|
||||
for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
|
||||
Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
|
||||
for (JetType type : variantsForExplicitReceiver) {
|
||||
Collection<D> membersForThisVariant =
|
||||
staticMembers
|
||||
? callableDescriptorCollector.getStaticMembersByName(type, c.name, c.context.trace)
|
||||
: callableDescriptorCollector.getMembersByName(type, c.name, c.context.trace);
|
||||
convertWithReceivers(membersForThisVariant, explicitReceiver,
|
||||
NO_RECEIVER, members, createKind(DISPATCH_RECEIVER, isExplicit), c.context.call);
|
||||
}
|
||||
c.result.addCandidates(members);
|
||||
for (final CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
|
||||
c.result.addCandidates(new Function0<Collection<? extends ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<? extends ResolutionCandidate<D>> invoke() {
|
||||
List<JetType> variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context);
|
||||
Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
|
||||
for (JetType type : variantsForExplicitReceiver) {
|
||||
Collection<D> membersForThisVariant =
|
||||
staticMembers
|
||||
? callableDescriptorCollector.getStaticMembersByName(type, c.name, c.context.trace)
|
||||
: callableDescriptorCollector.getMembersByName(type, c.name, c.context.trace);
|
||||
convertWithReceivers(membersForThisVariant, explicitReceiver,
|
||||
NO_RECEIVER, members, createKind(DISPATCH_RECEIVER, isExplicit), c.context.call);
|
||||
}
|
||||
return members;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,15 +192,21 @@ public class TaskPrioritizer {
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates(
|
||||
@NotNull ReceiverValue dispatchReceiver,
|
||||
@NotNull ReceiverValue receiverParameter,
|
||||
@NotNull CallableDescriptorCollector<D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
|
||||
@NotNull ExplicitReceiverKind receiverKind
|
||||
@NotNull final ReceiverValue dispatchReceiver,
|
||||
@NotNull final ReceiverValue receiverParameter,
|
||||
@NotNull final CallableDescriptorCollector<D> callableDescriptorCollector,
|
||||
@NotNull final TaskPrioritizerContext<D, F> c,
|
||||
@NotNull final ExplicitReceiverKind receiverKind
|
||||
) {
|
||||
Collection<D> memberExtensions = callableDescriptorCollector.getExtensionsByName(
|
||||
dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace);
|
||||
c.result.addCandidates(convertWithReceivers(
|
||||
memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call));
|
||||
c.result.addCandidates(new Function0<Collection<? extends ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<? extends ResolutionCandidate<D>> invoke() {
|
||||
Collection<D> memberExtensions = callableDescriptorCollector.getExtensionsByName(
|
||||
dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace);
|
||||
return convertWithReceivers(
|
||||
memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver(
|
||||
@@ -354,12 +369,17 @@ public class TaskPrioritizer {
|
||||
|
||||
public <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull final Collection<ResolutionCandidate<D>> candidates,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(
|
||||
storageManager, context, new MyPriorityProvider<D>(context), tracing);
|
||||
result.addCandidates(candidates);
|
||||
result.addCandidates(new Function0<Collection<? extends ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<? extends ResolutionCandidate<D>> invoke() {
|
||||
return candidates;
|
||||
}
|
||||
});
|
||||
return result.getTasks();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// KT-6153 java.lang.IllegalStateException while building
|
||||
object Bug {
|
||||
fun title(id:Int) = when (id) {
|
||||
0 -> "OK"
|
||||
else -> throw Exception("unsupported $id")
|
||||
}
|
||||
|
||||
private fun <T> T.header(id: Int) = StringBuilder().append(title(id))
|
||||
|
||||
fun run() = header(0)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Bug.run().toString()
|
||||
}
|
||||
@@ -6008,6 +6008,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt6153.kt")
|
||||
public void testKt6153() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt6153.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unjustifiedReferenceTarget.kt")
|
||||
public void testUnjustifiedReferenceTarget() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/unjustifiedReferenceTarget.kt");
|
||||
|
||||
Reference in New Issue
Block a user