Make candidates lazy in ResolutionTask & ResolutionTaskHolder

This commit is contained in:
Stanislav Erokhin
2014-11-13 18:24:37 +03:00
parent eb50e4adb3
commit 2033042d33
6 changed files with 120 additions and 77 deletions
@@ -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);
@@ -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();
}
}
@@ -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!!
}
@@ -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");