Fix UI freezes caused by calls with a huge number overloads

While we have an overload resolution algorithm working for O(n^2),
call resolution for the single particular call may work more then just
a second.
Thus, we need to call ProgressManager.checkCanceled() with more granularity

^KT-35135 Fixed
This commit is contained in:
Denis Zharkov
2020-02-14 15:42:07 +03:00
parent 842e2dc02f
commit aac72871e7
9 changed files with 52 additions and 5 deletions
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.types.checker.NewKotlinTypeCheckerImpl
import org.jetbrains.kotlin.types.expressions.DeclarationScopeProviderForLocalClassifierAnalyzer
import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
import org.jetbrains.kotlin.util.ProgressManagerBasedCancellationChecker
fun StorageComponentContainer.configureModule(
moduleContext: ModuleContext,
@@ -97,6 +98,7 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
useImpl<CompilerDeserializationConfiguration>()
useImpl<ClassicTypeSystemContextForCS>()
useInstance(ProgressManagerBasedCancellationChecker)
}
/**
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature.Companion.argumentValueType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.CancellationChecker
import java.util.*
@@ -55,12 +56,14 @@ fun createOverloadingConflictResolver(
builtIns: KotlinBuiltIns,
module: ModuleDescriptor,
specificityComparator: TypeSpecificityComparator,
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
cancellationChecker: CancellationChecker,
) = OverloadingConflictResolver(
builtIns,
module,
specificityComparator,
platformOverloadsSpecificityComparator,
cancellationChecker,
MutableResolvedCall<*>::getResultingDescriptor,
ConstraintSystemBuilderImpl.Companion::forSpecificity,
MutableResolvedCall<*>::createFlatSignature,
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.kotlin.resolve.calls.tower.TowerUtilsKt;
import org.jetbrains.kotlin.util.CancellationChecker;
import java.util.*;
@@ -42,10 +43,11 @@ public class ResolutionResultsHandler {
@NotNull KotlinBuiltIns builtIns,
@NotNull ModuleDescriptor module,
@NotNull TypeSpecificityComparator specificityComparator,
@NotNull PlatformOverloadsSpecificityComparator platformOverloadsSpecificityComparator
@NotNull PlatformOverloadsSpecificityComparator platformOverloadsSpecificityComparator,
@NotNull CancellationChecker cancellationChecker
) {
overloadingConflictResolver = FlatSignatureForResolvedCallKt.createOverloadingConflictResolver(
builtIns, module, specificityComparator, platformOverloadsSpecificityComparator
builtIns, module, specificityComparator, platformOverloadsSpecificityComparator, cancellationChecker
);
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.util
import com.intellij.openapi.progress.ProgressManager
object ProgressManagerBasedCancellationChecker : CancellationChecker {
override fun check() {
ProgressManager.checkCanceled()
}
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver
import org.jetbrains.kotlin.resolve.calls.tower.isInapplicable
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.util.CancellationChecker
class CallableReferenceOverloadConflictResolver(
@@ -39,6 +40,7 @@ class CallableReferenceOverloadConflictResolver(
module: ModuleDescriptor,
specificityComparator: TypeSpecificityComparator,
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
cancellationChecker: CancellationChecker,
statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector
) : OverloadingConflictResolver<CallableReferenceCandidate>(
@@ -46,6 +48,7 @@ class CallableReferenceOverloadConflictResolver(
module,
specificityComparator,
platformOverloadsSpecificityComparator,
cancellationChecker,
{ it.candidate },
{ statelessCallbacks.createConstraintSystemForOverloadResolution(constraintInjector, builtIns) },
Companion::createFlatSignature,
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.results.OverloadingConflictResolver
import org.jetbrains.kotlin.resolve.calls.results.PlatformOverloadsSpecificityComparator
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.CancellationChecker
import java.util.*
class NewOverloadingConflictResolver(
@@ -34,6 +35,7 @@ class NewOverloadingConflictResolver(
module: ModuleDescriptor,
specificityComparator: TypeSpecificityComparator,
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
cancellationChecker: CancellationChecker,
statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector
) : OverloadingConflictResolver<KotlinResolutionCandidate>(
@@ -41,6 +43,7 @@ class NewOverloadingConflictResolver(
module,
specificityComparator,
platformOverloadsSpecificityComparator,
cancellationChecker,
{
// todo investigate
it.resolvedCall.candidateDescriptor
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.requireOrDescribe
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.util.CancellationChecker
import java.util.*
open class OverloadingConflictResolver<C : Any>(
@@ -38,6 +39,7 @@ open class OverloadingConflictResolver<C : Any>(
private val module: ModuleDescriptor,
private val specificityComparator: TypeSpecificityComparator,
private val platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
private val cancellationChecker: CancellationChecker,
private val getResultingDescriptor: (C) -> CallableDescriptor,
private val createEmptyConstraintSystem: () -> SimpleConstraintSystem,
private val createFlatSignature: (C) -> FlatSignature<C>,
@@ -78,7 +80,8 @@ open class OverloadingConflictResolver<C : Any>(
val noEquivalentCalls = filterOutEquivalentCalls(fixedCandidates)
val noOverrides = OverridingUtil.filterOverrides(
noEquivalentCalls,
isTypeRefinementEnabled
isTypeRefinementEnabled,
cancellationChecker::check
) { a, b ->
val aDescriptor = a.resultingDescriptor
val bDescriptor = b.resultingDescriptor
@@ -124,6 +127,7 @@ open class OverloadingConflictResolver<C : Any>(
val result = LinkedHashSet<C>()
outerLoop@ for (meD in fromSourcesGoesFirst) {
cancellationChecker.check()
for (otherD in result) {
val me = meD.resultingDescriptor.originalIfTypeRefinementEnabled
val other = otherD.resultingDescriptor.originalIfTypeRefinementEnabled
@@ -209,6 +213,7 @@ open class OverloadingConflictResolver<C : Any>(
}
val bestCandidatesByParameterTypes = conflictingCandidates.filter { candidate ->
cancellationChecker.check()
isMostSpecific(candidate, conflictingCandidates) { call1, call2 ->
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics)
}
@@ -20,6 +20,7 @@ import kotlin.Pair;
import kotlin.Unit;
import kotlin.annotations.jvm.Mutable;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull;
@@ -97,7 +98,7 @@ public class OverridingUtil {
DescriptorUtilsKt
.isTypeRefinementEnabled(DescriptorUtilsKt.getModule(candidateSet.iterator().next()));
return filterOverrides(candidateSet, allowDescriptorCopies, new Function2<D, D, Pair<CallableDescriptor, CallableDescriptor>>() {
return filterOverrides(candidateSet, allowDescriptorCopies, null, new Function2<D, D, Pair<CallableDescriptor, CallableDescriptor>>() {
@Override
public Pair<CallableDescriptor, CallableDescriptor> invoke(D a, D b) {
return new Pair<CallableDescriptor, CallableDescriptor>(a, b);
@@ -109,6 +110,7 @@ public class OverridingUtil {
public static <D> Set<D> filterOverrides(
@NotNull Set<D> candidateSet,
boolean allowDescriptorCopies,
@Nullable Function0<?> cancellationCallback,
@NotNull Function2<? super D, ? super D, Pair<CallableDescriptor, CallableDescriptor>> transformFirst
) {
if (candidateSet.size() <= 1) return candidateSet;
@@ -116,6 +118,9 @@ public class OverridingUtil {
Set<D> result = new LinkedHashSet<D>();
outerLoop:
for (D meD : candidateSet) {
if (cancellationCallback != null) {
cancellationCallback.invoke();
}
for (Iterator<D> iterator = result.iterator(); iterator.hasNext(); ) {
D otherD = iterator.next();
Pair<CallableDescriptor, CallableDescriptor> meAndOther = transformFirst.invoke(meD, otherD);
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.util
interface CancellationChecker {
fun check()
}