From 2033042d33a9715ff610b011847637f36561a97d Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Thu, 13 Nov 2014 18:24:37 +0300 Subject: [PATCH] Make candidates lazy in ResolutionTask & ResolutionTaskHolder --- .../jet/lang/resolve/calls/CallResolver.java | 6 +- .../resolve/calls/tasks/ResolutionTask.java | 34 ++++--- .../calls/tasks/ResolutionTaskHolder.kt | 46 ++++------ .../resolve/calls/tasks/TaskPrioritizer.java | 90 +++++++++++-------- .../codegen/box/regressions/kt6153.kt | 15 ++++ .../BlackBoxCodegenTestGenerated.java | 6 ++ 6 files changed, 120 insertions(+), 77 deletions(-) create mode 100644 compiler/testData/codegen/box/regressions/kt6153.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 5619b8fc81f..a22df0cc91b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -427,7 +427,7 @@ public class CallResolver { TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; OverloadResolutionResultsImpl resultsForFirstNonemptyCandidateSet = null; for (ResolutionTask 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 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 newTask = new ResolutionTask(task.getCandidates(), task.toBasic(), task.tracing). + ResolutionTask newTask = task.replaceContext(task.toBasic()). replaceBindingTrace(temporaryTrace).replaceCall(callWithoutFLArgs); OverloadResolutionResultsImpl resultsWithFunctionLiteralsStripped = performResolution(newTask, callTransformer); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTask.java index 224d65c8306..01ec3c9529a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTask.java @@ -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 extends CallResolutionContext> { - private final Collection> candidates; + private final Function0>> lazyCandidates; private final Collection> resolvedCalls; private DescriptorCheckStrategy checkingStrategy; public final TracingStrategy tracing; private ResolutionTask( - @NotNull Collection> candidates, + @NotNull Function0>> lazyCandidates, @NotNull TracingStrategy tracing, @NotNull BindingTrace trace, @NotNull JetScope scope, @@ -61,17 +62,17 @@ public class ResolutionTask 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> candidates, @NotNull BasicCallResolutionContext context, - @NotNull TracingStrategy tracing + @NotNull TracingStrategy tracing, + @NotNull Function0>> 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 extends C } public ResolutionTask( - @NotNull Collection> candidates, + @NotNull final Collection> candidates, @NotNull JetReferenceExpression reference, @NotNull BasicCallResolutionContext context ) { - this(candidates, context, TracingStrategyImpl.create(reference, context.call)); + this(context, TracingStrategyImpl.create(reference, context.call), new Function0>>() { + @Override + public Collection> invoke() { + return candidates; + } + }); } @NotNull public Collection> getCandidates() { - return candidates; + return lazyCandidates.invoke(); } public void addResolvedCall(@NotNull MutableResolvedCall resolvedCall) { @@ -122,16 +128,20 @@ public class ResolutionTask extends C boolean collectAllCandidates ) { ResolutionTask newTask = new ResolutionTask( - 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 replaceContext(@NotNull BasicCallResolutionContext newContext) { + return new ResolutionTask(newContext, tracing, lazyCandidates); + } + public ResolutionTask replaceCall(@NotNull Call newCall) { return new ResolutionTask( - 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 extends C @Override public String toString() { - return candidates.toString(); + return lazyCandidates.toString(); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTaskHolder.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTaskHolder.kt index 9ed5bfd736c..d78c1469bf9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTaskHolder.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionTaskHolder.kt @@ -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( private val storageManager: StorageManager, @@ -31,15 +29,10 @@ public class ResolutionTaskHolder( private val priorityProvider: ResolutionTaskHolder.PriorityProvider>, private val tracing: TracingStrategy ) { - private val isSafeCall: Boolean + private val isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call) - private val candidatesList = Lists.newArrayList>>() - - private var internalTasks: MutableList>? = null - - { - this.isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call) - } + private val candidatesList = ArrayList<() -> Collection>>() + private var internalTasks: List>? = null public fun setIsSafeCall(candidates: Collection>): Collection> { for (candidate in candidates) { @@ -48,17 +41,17 @@ public class ResolutionTaskHolder( return candidates } - public fun addCandidates(candidates: Collection>) { + public fun addCandidates(lazyCandidates: () -> Collection>) { assertNotFinished() - if (!candidates.isEmpty()) { - candidatesList.add(setIsSafeCall(candidates)) - } + candidatesList.add(storageManager.createLazyValue { + setIsSafeCall(lazyCandidates()).toReadOnlyList() + }) } public fun addCandidates(candidatesList: List>>) { assertNotFinished() for (candidates in candidatesList) { - addCandidates(candidates) + addCandidates { candidates } } } @@ -68,20 +61,17 @@ public class ResolutionTaskHolder( public fun getTasks(): List> { 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>() + 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!! } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java index 72b78ec6dee..07efa7445a5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java @@ -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 void addCandidatesForExplicitReceiver( - @NotNull ReceiverValue explicitReceiver, + @NotNull final ReceiverValue explicitReceiver, @NotNull Collection implicitReceivers, - @NotNull TaskPrioritizerContext c, - boolean isExplicit + @NotNull final TaskPrioritizerContext c, + final boolean isExplicit ) { addMembers(explicitReceiver, c, /*static=*/false, isExplicit); - for (CallableDescriptorCollector callableDescriptorCollector : c.callableDescriptorCollectors) { + for (final CallableDescriptorCollector callableDescriptorCollector : c.callableDescriptorCollectors) { //member extensions for (ReceiverValue implicitReceiver : implicitReceivers) { addMemberExtensionCandidates(implicitReceiver, explicitReceiver, callableDescriptorCollector, c, createKind(EXTENSION_RECEIVER, isExplicit)); } //extensions - Collection> 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>>() { + @Override + public Collection> invoke() { + return convertWithImpliedThis( + c.scope, explicitReceiver, callableDescriptorCollector.getExtensionsByName(c.scope, c.name, c.context.trace), + createKind(EXTENSION_RECEIVER, isExplicit), c.context.call); + } + }); } } private static void addMembers( - ReceiverValue explicitReceiver, - TaskPrioritizerContext c, - boolean staticMembers, - boolean isExplicit + final ReceiverValue explicitReceiver, + final TaskPrioritizerContext c, + final boolean staticMembers, + final boolean isExplicit ) { - List variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context); - - for (CallableDescriptorCollector callableDescriptorCollector : c.callableDescriptorCollectors) { - Collection> members = Lists.newArrayList(); - for (JetType type : variantsForExplicitReceiver) { - Collection 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 callableDescriptorCollector : c.callableDescriptorCollectors) { + c.result.addCandidates(new Function0>>() { + @Override + public Collection> invoke() { + List variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context); + Collection> members = Lists.newArrayList(); + for (JetType type : variantsForExplicitReceiver) { + Collection 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 void addMemberExtensionCandidates( - @NotNull ReceiverValue dispatchReceiver, - @NotNull ReceiverValue receiverParameter, - @NotNull CallableDescriptorCollector callableDescriptorCollector, TaskPrioritizerContext c, - @NotNull ExplicitReceiverKind receiverKind + @NotNull final ReceiverValue dispatchReceiver, + @NotNull final ReceiverValue receiverParameter, + @NotNull final CallableDescriptorCollector callableDescriptorCollector, + @NotNull final TaskPrioritizerContext c, + @NotNull final ExplicitReceiverKind receiverKind ) { - Collection 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>>() { + @Override + public Collection> invoke() { + Collection memberExtensions = callableDescriptorCollector.getExtensionsByName( + dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace); + return convertWithReceivers( + memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call); + } + }); } private static void addCandidatesForNoReceiver( @@ -354,12 +369,17 @@ public class TaskPrioritizer { public List> computePrioritizedTasksFromCandidates( @NotNull BasicCallResolutionContext context, - @NotNull Collection> candidates, + @NotNull final Collection> candidates, @NotNull TracingStrategy tracing ) { ResolutionTaskHolder result = new ResolutionTaskHolder( storageManager, context, new MyPriorityProvider(context), tracing); - result.addCandidates(candidates); + result.addCandidates(new Function0>>() { + @Override + public Collection> invoke() { + return candidates; + } + }); return result.getTasks(); } diff --git a/compiler/testData/codegen/box/regressions/kt6153.kt b/compiler/testData/codegen/box/regressions/kt6153.kt new file mode 100644 index 00000000000..cc21778d197 --- /dev/null +++ b/compiler/testData/codegen/box/regressions/kt6153.kt @@ -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.header(id: Int) = StringBuilder().append(title(id)) + + fun run() = header(0) +} + +fun box(): String { + return Bug.run().toString() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index efd74667060..a53108cd3ee 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -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");