Refactoring. Support in OverloadingConflictResolver any kind of ResolvedCalls.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,12 +19,8 @@ package org.jetbrains.kotlin.resolve.calls.results
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
class FlatSignature<out T>(
|
||||
val origin: T,
|
||||
@@ -37,34 +33,6 @@ class FlatSignature<out T>(
|
||||
val isGeneric = typeParameters.isNotEmpty()
|
||||
|
||||
companion object {
|
||||
fun <D : CallableDescriptor, RC : ResolvedCall<D>> createFromResolvedCall(resolvedCall: RC): FlatSignature<RC> {
|
||||
val originalDescriptor = resolvedCall.candidateDescriptor.original
|
||||
val originalValueParameters = originalDescriptor.valueParameters
|
||||
|
||||
var numDefaults = 0
|
||||
val valueArgumentToParameterType = HashMap<ValueArgument, KotlinType>()
|
||||
for ((valueParameter, resolvedValueArgument) in resolvedCall.valueArguments.entries) {
|
||||
if (resolvedValueArgument is DefaultValueArgument) {
|
||||
numDefaults++
|
||||
}
|
||||
else {
|
||||
val originalValueParameter = originalValueParameters[valueParameter.index]
|
||||
val parameterType = originalValueParameter.argumentValueType
|
||||
for (valueArgument in resolvedValueArgument.arguments) {
|
||||
valueArgumentToParameterType[valueArgument] = parameterType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FlatSignature(resolvedCall,
|
||||
originalDescriptor.typeParameters,
|
||||
valueParameterTypes = originalDescriptor.extensionReceiverTypeOrEmpty() +
|
||||
resolvedCall.call.valueArguments.map { valueArgumentToParameterType[it] },
|
||||
hasExtensionReceiver = originalDescriptor.extensionReceiverParameter != null,
|
||||
hasVarargs = originalDescriptor.valueParameters.any { it.varargElementType != null },
|
||||
numDefaults = numDefaults)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> createFromCallableDescriptor(descriptor: D): FlatSignature<D> =
|
||||
FlatSignature(descriptor,
|
||||
descriptor.typeParameters,
|
||||
|
||||
+51
@@ -16,14 +16,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.results
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.valueParameterPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
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.resolve.calls.results.FlatSignature.Companion.extensionReceiverTypeOrEmpty
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import java.util.*
|
||||
|
||||
interface SpecificityComparisonCallbacks {
|
||||
fun isNonSubtypeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean
|
||||
@@ -76,3 +86,44 @@ fun <T> isSignatureNotLessSpecific(
|
||||
val constraintSystem = constraintSystemBuilder.build()
|
||||
return !constraintSystem.status.hasContradiction()
|
||||
}
|
||||
|
||||
|
||||
fun <RC : ResolvedCall<*>> RC.createFlatSignature(): FlatSignature<RC> {
|
||||
val originalDescriptor = candidateDescriptor.original
|
||||
val originalValueParameters = originalDescriptor.valueParameters
|
||||
|
||||
var numDefaults = 0
|
||||
val valueArgumentToParameterType = HashMap<ValueArgument, KotlinType>()
|
||||
for ((valueParameter, resolvedValueArgument) in valueArguments.entries) {
|
||||
if (resolvedValueArgument is DefaultValueArgument) {
|
||||
numDefaults++
|
||||
}
|
||||
else {
|
||||
val originalValueParameter = originalValueParameters[valueParameter.index]
|
||||
val parameterType = originalValueParameter.argumentValueType
|
||||
for (valueArgument in resolvedValueArgument.arguments) {
|
||||
valueArgumentToParameterType[valueArgument] = parameterType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FlatSignature(this,
|
||||
originalDescriptor.typeParameters,
|
||||
valueParameterTypes = originalDescriptor.extensionReceiverTypeOrEmpty() +
|
||||
call.valueArguments.map { valueArgumentToParameterType[it] },
|
||||
hasExtensionReceiver = originalDescriptor.extensionReceiverParameter != null,
|
||||
hasVarargs = originalDescriptor.valueParameters.any { it.varargElementType != null },
|
||||
numDefaults = numDefaults)
|
||||
}
|
||||
|
||||
fun createOverloadingConflictResolver(
|
||||
builtIns: KotlinBuiltIns,
|
||||
specificityComparator: TypeSpecificityComparator
|
||||
) = OverloadingConflictResolver(
|
||||
builtIns,
|
||||
specificityComparator,
|
||||
MutableResolvedCall<*>::getResultingDescriptor,
|
||||
MutableResolvedCall<*>::createFlatSignature,
|
||||
{ (it as? VariableAsFunctionResolvedCallImpl)?.variableCall },
|
||||
{ DescriptorToSourceUtils.descriptorToDeclaration(it) != null}
|
||||
)
|
||||
+117
-60
@@ -21,28 +21,105 @@ import gnu.trove.TObjectHashingStrategy
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionMutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.*
|
||||
|
||||
class OverloadingConflictResolver(
|
||||
class OverloadingConflictResolver<C : Any>(
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val specificityComparator: TypeSpecificityComparator
|
||||
private val specificityComparator: TypeSpecificityComparator,
|
||||
private val getResultingDescriptor: (C) -> CallableDescriptor,
|
||||
private val createFlatSignature: (C) -> FlatSignature<C>,
|
||||
private val getVariableCandidates: (C) -> C?, // vor variable WithInvoke
|
||||
private val isFromSources: (CallableDescriptor) -> Boolean
|
||||
) {
|
||||
|
||||
fun <D : CallableDescriptor> findMaximallySpecific(
|
||||
candidates: Set<MutableResolvedCall<D>>,
|
||||
private val resolvedCallHashingStrategy = object : TObjectHashingStrategy<C> {
|
||||
override fun equals(call1: C?, call2: C?): Boolean =
|
||||
if (call1 != null && call2 != null)
|
||||
call1.resultingDescriptor == call2.resultingDescriptor
|
||||
else
|
||||
call1 == call2
|
||||
|
||||
override fun computeHashCode(call: C?): Int =
|
||||
call?.resultingDescriptor?.hashCode() ?: 0
|
||||
}
|
||||
|
||||
private val C.resultingDescriptor: CallableDescriptor get() = getResultingDescriptor(this)
|
||||
|
||||
// if result contains only one element -- it is maximally specific; otherwise we have ambiguity
|
||||
fun chooseMaximallySpecificCandidates(
|
||||
candidates: Set<C>,
|
||||
checkArgumentsMode: CheckArgumentTypesMode,
|
||||
discriminateGenerics: Boolean,
|
||||
isDebuggerContext: Boolean
|
||||
): MutableResolvedCall<D>? =
|
||||
): Set<C> {
|
||||
if (candidates.size == 1) return candidates
|
||||
|
||||
val fixedCandidates = if (getVariableCandidates(candidates.first()) != null) {
|
||||
findMaximallySpecificVariableAsFunctionCalls(candidates) ?: return candidates
|
||||
}
|
||||
else {
|
||||
candidates
|
||||
}
|
||||
|
||||
val noEquivalentCalls = filterOutEquivalentCalls(fixedCandidates)
|
||||
val noOverrides = OverridingUtil.filterOverrides(noEquivalentCalls) { it.resultingDescriptor }
|
||||
if (noOverrides.size == 1) {
|
||||
return noOverrides
|
||||
}
|
||||
|
||||
val maximallySpecific = findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext)
|
||||
if (maximallySpecific != null) {
|
||||
return setOf(maximallySpecific)
|
||||
}
|
||||
|
||||
if (discriminateGenerics) {
|
||||
val maximallySpecificGenericsDiscriminated = findMaximallySpecific(noOverrides, checkArgumentsMode, true, isDebuggerContext)
|
||||
if (maximallySpecificGenericsDiscriminated != null) {
|
||||
return setOf(maximallySpecificGenericsDiscriminated)
|
||||
}
|
||||
}
|
||||
|
||||
return noOverrides
|
||||
}
|
||||
|
||||
// Sometimes we should compare "copies" from sources and from binary files.
|
||||
// But we cannot compare return types for such copies, because it may lead us to recursive problem (see KT-11995).
|
||||
// Because of this we compare them without return type and choose descriptor from source if we found duplicate.
|
||||
private fun filterOutEquivalentCalls(
|
||||
candidates: Set<C>): Set<C> {
|
||||
if (candidates.size <= 1) return candidates
|
||||
|
||||
val fromSourcesGoesFirst = candidates.sortedBy { if (isFromSources(it.resultingDescriptor)) 0 else 1 }
|
||||
|
||||
val result = LinkedHashSet<C>()
|
||||
outerLoop@ for (meD in fromSourcesGoesFirst) {
|
||||
for (otherD in result) {
|
||||
val me = meD.resultingDescriptor
|
||||
val other = otherD.resultingDescriptor
|
||||
val ignoreReturnType = isFromSources(me) != isFromSources(other)
|
||||
if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(me, other, ignoreReturnType)) {
|
||||
continue@outerLoop
|
||||
}
|
||||
}
|
||||
result.add(meD)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun findMaximallySpecific(
|
||||
candidates: Set<C>,
|
||||
checkArgumentsMode: CheckArgumentTypesMode,
|
||||
discriminateGenerics: Boolean,
|
||||
isDebuggerContext: Boolean
|
||||
): C? =
|
||||
if (candidates.size <= 1)
|
||||
candidates.firstOrNull()
|
||||
else when (checkArgumentsMode) {
|
||||
@@ -58,33 +135,31 @@ class OverloadingConflictResolver(
|
||||
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(candidates: Set<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> {
|
||||
val variableCalls = candidates.mapTo(newResolvedCallSet<MutableResolvedCall<VariableDescriptor>>(candidates.size)) {
|
||||
if (it is VariableAsFunctionMutableResolvedCall)
|
||||
it.variableCall
|
||||
else
|
||||
throw AssertionError("Regular call among variable-as-function calls: $it")
|
||||
// null means ambiguity between variables
|
||||
private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Set<C>): Set<C>? {
|
||||
val variableCalls = candidates.mapTo(newResolvedCallSet(candidates.size)) {
|
||||
getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it")
|
||||
}
|
||||
|
||||
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false, false) ?: return emptySet()
|
||||
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false, false) ?: return null
|
||||
|
||||
return candidates.filterTo(newResolvedCallSet<MutableResolvedCall<D>>(2)) {
|
||||
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor
|
||||
return candidates.filterTo(newResolvedCallSet(2)) {
|
||||
getVariableCandidates(it)!!.resultingDescriptor == maxSpecificVariableCall.resultingDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> findMaximallySpecificCall(
|
||||
candidates: Set<MutableResolvedCall<D>>,
|
||||
private fun findMaximallySpecificCall(
|
||||
candidates: Set<C>,
|
||||
discriminateGenerics: Boolean,
|
||||
isDebuggerContext: Boolean
|
||||
): MutableResolvedCall<D>? {
|
||||
): C? {
|
||||
val filteredCandidates = uniquifyCandidatesSet(candidates)
|
||||
|
||||
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
|
||||
|
||||
val conflictingCandidates = filteredCandidates.map {
|
||||
candidateCall ->
|
||||
FlatSignature.createFromResolvedCall(candidateCall)
|
||||
createFlatSignature(candidateCall)
|
||||
}
|
||||
|
||||
val bestCandidatesByParameterTypes = conflictingCandidates.filter {
|
||||
@@ -132,9 +207,9 @@ class OverloadingConflictResolver(
|
||||
/**
|
||||
* `call1` is not less specific than `call2`
|
||||
*/
|
||||
private fun <D : CallableDescriptor> isNotLessSpecificCallWithArgumentMapping(
|
||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||
call2: FlatSignature<MutableResolvedCall<D>>,
|
||||
private fun isNotLessSpecificCallWithArgumentMapping(
|
||||
call1: FlatSignature<C>,
|
||||
call2: FlatSignature<C>,
|
||||
discriminateGenerics: Boolean
|
||||
): Boolean {
|
||||
return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?:
|
||||
@@ -145,9 +220,9 @@ class OverloadingConflictResolver(
|
||||
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
||||
* `false` otherwise.
|
||||
*/
|
||||
private fun <D : CallableDescriptor> compareCallsByUsedArguments(
|
||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||
call2: FlatSignature<MutableResolvedCall<D>>,
|
||||
private fun compareCallsByUsedArguments(
|
||||
call1: FlatSignature<C>,
|
||||
call2: FlatSignature<C>,
|
||||
discriminateGenerics: Boolean
|
||||
): Boolean {
|
||||
if (discriminateGenerics) {
|
||||
@@ -188,9 +263,9 @@ class OverloadingConflictResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D: CallableDescriptor> isOfNotLessSpecificShape(
|
||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||
call2: FlatSignature<MutableResolvedCall<D>>
|
||||
private fun isOfNotLessSpecificShape(
|
||||
call1: FlatSignature<C>,
|
||||
call2: FlatSignature<C>
|
||||
): Boolean {
|
||||
val hasVarargs1 = call1.hasVarargs
|
||||
val hasVarargs2 = call2.hasVarargs
|
||||
@@ -204,9 +279,9 @@ class OverloadingConflictResolver(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun <D: CallableDescriptor> isOfNotLessSpecificVisibilityForDebugger(
|
||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||
call2: FlatSignature<MutableResolvedCall<D>>,
|
||||
private fun isOfNotLessSpecificVisibilityForDebugger(
|
||||
call1: FlatSignature<C>,
|
||||
call2: FlatSignature<C>,
|
||||
isDebuggerContext: Boolean
|
||||
): Boolean {
|
||||
if (isDebuggerContext) {
|
||||
@@ -254,34 +329,16 @@ class OverloadingConflictResolver(
|
||||
tryCompareDescriptorsFromScripts(f, g) ?:
|
||||
isNotLessSpecificCallableReferenceDescriptor(f, g)
|
||||
|
||||
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
|
||||
private fun <D : CallableDescriptor> uniquifyCandidatesSet(candidates: Collection<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> =
|
||||
THashSet<MutableResolvedCall<D>>(candidates.size, getCallHashingStrategy<MutableResolvedCall<D>>()).apply { addAll(candidates) }
|
||||
// Different smart casts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
|
||||
private fun uniquifyCandidatesSet(candidates: Collection<C>): Set<C> =
|
||||
THashSet(candidates.size, resolvedCallHashingStrategy).apply { addAll(candidates) }
|
||||
|
||||
private fun <C> newResolvedCallSet(expectedSize: Int): MutableSet<C> =
|
||||
THashSet<C>(expectedSize, getCallHashingStrategy<C>())
|
||||
private fun newResolvedCallSet(expectedSize: Int): MutableSet<C> =
|
||||
THashSet(expectedSize, resolvedCallHashingStrategy)
|
||||
|
||||
private object ResolvedCallHashingStrategy : TObjectHashingStrategy<ResolvedCall<*>> {
|
||||
override fun equals(call1: ResolvedCall<*>?, call2: ResolvedCall<*>?): Boolean =
|
||||
if (call1 != null && call2 != null)
|
||||
call1.resultingDescriptor == call2.resultingDescriptor
|
||||
else
|
||||
call1 == call2
|
||||
|
||||
override fun computeHashCode(call: ResolvedCall<*>?): Int =
|
||||
call?.resultingDescriptor?.hashCode() ?: 0
|
||||
}
|
||||
|
||||
private val MutableResolvedCall<*>.resultingVariableDescriptor: VariableDescriptor
|
||||
get() = (this as VariableAsFunctionResolvedCall).variableCall.resultingDescriptor
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <C> getCallHashingStrategy() =
|
||||
ResolvedCallHashingStrategy as TObjectHashingStrategy<C>
|
||||
|
||||
private fun <D : CallableDescriptor> FlatSignature<ResolvedCall<D>>.candidateDescriptor() =
|
||||
private fun FlatSignature<C>.candidateDescriptor() =
|
||||
origin.resultingDescriptor.original
|
||||
|
||||
private fun <D : CallableDescriptor> FlatSignature<ResolvedCall<D>>.descriptorVisibility() =
|
||||
private fun FlatSignature<C>.descriptorVisibility() =
|
||||
candidateDescriptor().visibility
|
||||
}
|
||||
|
||||
+18
-80
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,46 +17,31 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.results;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*;
|
||||
|
||||
public class ResolutionResultsHandler {
|
||||
private static final Function1<MutableResolvedCall<?>, CallableDescriptor> MAP_RESOLVED_CALL_TO_RESULTING_DESCRIPTOR =
|
||||
new Function1<MutableResolvedCall<?>, CallableDescriptor>() {
|
||||
@Override
|
||||
public CallableDescriptor invoke(MutableResolvedCall<?> resolvedCall) {
|
||||
return resolvedCall.getResultingDescriptor();
|
||||
}
|
||||
};
|
||||
|
||||
private static final Function1<MutableResolvedCall<?>, Integer> MAP_RESOLVED_CALL_TO_SOURCE_PRESENCE =
|
||||
new Function1<MutableResolvedCall<?>, Integer>() {
|
||||
@Override
|
||||
public Integer invoke(MutableResolvedCall<?> resolvedCall) {
|
||||
return DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.getResultingDescriptor()) != null ? 0 : 1;
|
||||
}
|
||||
};
|
||||
private final OverloadingConflictResolver<MutableResolvedCall<?>> overloadingConflictResolver;
|
||||
|
||||
private final OverloadingConflictResolver overloadingConflictResolver;
|
||||
|
||||
public ResolutionResultsHandler(@NotNull OverloadingConflictResolver overloadingConflictResolver) {
|
||||
this.overloadingConflictResolver = overloadingConflictResolver;
|
||||
public ResolutionResultsHandler(
|
||||
@NotNull KotlinBuiltIns builtIns,
|
||||
@NotNull TypeSpecificityComparator specificityComparator
|
||||
) {
|
||||
overloadingConflictResolver = FlatSignatureSpecificityKt.createOverloadingConflictResolver(builtIns, specificityComparator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -195,35 +180,6 @@ public class ResolutionResultsHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sometimes we should compare "copies" from sources and from binary files.
|
||||
// But we cannot compare return types for such copies, because it may lead us to recursive problem (see KT-11995).
|
||||
// Because of this we compare them without return type and choose descriptor from source if we found duplicate.
|
||||
@NotNull
|
||||
private static <D extends CallableDescriptor> Set<MutableResolvedCall<D>> filterOutEquivalentCalls(
|
||||
@NotNull Set<MutableResolvedCall<D>> candidates
|
||||
) {
|
||||
if (candidates.size() <= 1) return candidates;
|
||||
|
||||
List<MutableResolvedCall<D>> fromSourcesGoesFirst = CollectionsKt.sortedBy(candidates, MAP_RESOLVED_CALL_TO_SOURCE_PRESENCE);
|
||||
|
||||
Set<MutableResolvedCall<D>> result = new LinkedHashSet<MutableResolvedCall<D>>();
|
||||
outerLoop:
|
||||
for (MutableResolvedCall<D> meD : fromSourcesGoesFirst) {
|
||||
for (MutableResolvedCall<D> otherD : result) {
|
||||
D me = meD.getResultingDescriptor();
|
||||
D other = otherD.getResultingDescriptor();
|
||||
boolean ignoreReturnType = (DescriptorToSourceUtils.descriptorToDeclaration(me) == null) !=
|
||||
(DescriptorToSourceUtils.descriptorToDeclaration(other) == null);
|
||||
if (DescriptorEquivalenceForOverrides.INSTANCE.areCallableDescriptorsEquivalent(me, other, ignoreReturnType)) {
|
||||
continue outerLoop;
|
||||
}
|
||||
}
|
||||
result.add(meD);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
|
||||
@NotNull Set<MutableResolvedCall<D>> candidates,
|
||||
@@ -231,34 +187,16 @@ public class ResolutionResultsHandler {
|
||||
boolean isDebuggerContext,
|
||||
@NotNull CheckArgumentTypesMode checkArgumentsMode
|
||||
) {
|
||||
if (candidates.size() == 1) {
|
||||
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
|
||||
}
|
||||
OverloadingConflictResolver<MutableResolvedCall<D>> myResolver = (OverloadingConflictResolver) overloadingConflictResolver;
|
||||
|
||||
if (candidates.iterator().next() instanceof VariableAsFunctionResolvedCall) {
|
||||
candidates = overloadingConflictResolver.findMaximallySpecificVariableAsFunctionCalls(candidates);
|
||||
}
|
||||
Set<MutableResolvedCall<D>> specificCalls =
|
||||
myResolver.chooseMaximallySpecificCandidates(candidates, checkArgumentsMode, discriminateGenerics, isDebuggerContext);
|
||||
|
||||
Set<MutableResolvedCall<D>> noEquivalentCalls = filterOutEquivalentCalls(candidates);
|
||||
Set<MutableResolvedCall<D>> noOverrides =
|
||||
OverridingUtil.filterOverrides(noEquivalentCalls, MAP_RESOLVED_CALL_TO_RESULTING_DESCRIPTOR);
|
||||
if (noOverrides.size() == 1) {
|
||||
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
||||
if (specificCalls.size() == 1) {
|
||||
return OverloadResolutionResultsImpl.success(specificCalls.iterator().next());
|
||||
}
|
||||
|
||||
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext);
|
||||
if (maximallySpecific != null) {
|
||||
return OverloadResolutionResultsImpl.success(maximallySpecific);
|
||||
else {
|
||||
return OverloadResolutionResultsImpl.ambiguity(specificCalls);
|
||||
}
|
||||
|
||||
if (discriminateGenerics) {
|
||||
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(
|
||||
noOverrides, checkArgumentsMode, true, isDebuggerContext);
|
||||
if (maximallySpecificGenericsDiscriminated != null) {
|
||||
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
|
||||
}
|
||||
}
|
||||
|
||||
return OverloadResolutionResultsImpl.ambiguity(noOverrides);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user