Refactoring. Support in OverloadingConflictResolver any kind of ResolvedCalls.

This commit is contained in:
Stanislav Erokhin
2016-08-23 17:55:39 +03:00
parent b695f5edd9
commit 5ad0e4e9b8
4 changed files with 187 additions and 173 deletions
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor 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.types.KotlinType
import org.jetbrains.kotlin.utils.singletonOrEmptyList import org.jetbrains.kotlin.utils.singletonOrEmptyList
import java.util.*
class FlatSignature<out T>( class FlatSignature<out T>(
val origin: T, val origin: T,
@@ -37,34 +33,6 @@ class FlatSignature<out T>(
val isGeneric = typeParameters.isNotEmpty() val isGeneric = typeParameters.isNotEmpty()
companion object { 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> = fun <D : CallableDescriptor> createFromCallableDescriptor(descriptor: D): FlatSignature<D> =
FlatSignature(descriptor, FlatSignature(descriptor,
descriptor.typeParameters, descriptor.typeParameters,
@@ -16,14 +16,24 @@
package org.jetbrains.kotlin.resolve.calls.results 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.CallHandle
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.valueParameterPosition 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.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import java.util.*
interface SpecificityComparisonCallbacks { interface SpecificityComparisonCallbacks {
fun isNonSubtypeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean fun isNonSubtypeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean
@@ -76,3 +86,44 @@ fun <T> isSignatureNotLessSpecific(
val constraintSystem = constraintSystemBuilder.build() val constraintSystem = constraintSystemBuilder.build()
return !constraintSystem.status.hasContradiction() 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}
)
@@ -21,28 +21,105 @@ import gnu.trove.TObjectHashingStrategy
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities 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.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.resolve.descriptorUtil.varargParameterPosition
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import java.util.*
class OverloadingConflictResolver( class OverloadingConflictResolver<C : Any>(
private val builtIns: KotlinBuiltIns, 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( private val resolvedCallHashingStrategy = object : TObjectHashingStrategy<C> {
candidates: Set<MutableResolvedCall<D>>, 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, checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean, discriminateGenerics: Boolean,
isDebuggerContext: 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) if (candidates.size <= 1)
candidates.firstOrNull() candidates.firstOrNull()
else when (checkArgumentsMode) { else when (checkArgumentsMode) {
@@ -58,33 +135,31 @@ class OverloadingConflictResolver(
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext) findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
} }
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(candidates: Set<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> { // null means ambiguity between variables
val variableCalls = candidates.mapTo(newResolvedCallSet<MutableResolvedCall<VariableDescriptor>>(candidates.size)) { private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Set<C>): Set<C>? {
if (it is VariableAsFunctionMutableResolvedCall) val variableCalls = candidates.mapTo(newResolvedCallSet(candidates.size)) {
it.variableCall getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it")
else
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)) { return candidates.filterTo(newResolvedCallSet(2)) {
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor getVariableCandidates(it)!!.resultingDescriptor == maxSpecificVariableCall.resultingDescriptor
} }
} }
private fun <D : CallableDescriptor> findMaximallySpecificCall( private fun findMaximallySpecificCall(
candidates: Set<MutableResolvedCall<D>>, candidates: Set<C>,
discriminateGenerics: Boolean, discriminateGenerics: Boolean,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): MutableResolvedCall<D>? { ): C? {
val filteredCandidates = uniquifyCandidatesSet(candidates) val filteredCandidates = uniquifyCandidatesSet(candidates)
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull() if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
val conflictingCandidates = filteredCandidates.map { val conflictingCandidates = filteredCandidates.map {
candidateCall -> candidateCall ->
FlatSignature.createFromResolvedCall(candidateCall) createFlatSignature(candidateCall)
} }
val bestCandidatesByParameterTypes = conflictingCandidates.filter { val bestCandidatesByParameterTypes = conflictingCandidates.filter {
@@ -132,9 +207,9 @@ class OverloadingConflictResolver(
/** /**
* `call1` is not less specific than `call2` * `call1` is not less specific than `call2`
*/ */
private fun <D : CallableDescriptor> isNotLessSpecificCallWithArgumentMapping( private fun isNotLessSpecificCallWithArgumentMapping(
call1: FlatSignature<MutableResolvedCall<D>>, call1: FlatSignature<C>,
call2: FlatSignature<MutableResolvedCall<D>>, call2: FlatSignature<C>,
discriminateGenerics: Boolean discriminateGenerics: Boolean
): Boolean { ): Boolean {
return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?: return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?:
@@ -145,9 +220,9 @@ class OverloadingConflictResolver(
* Returns `true` if `d1` is definitely not less specific than `d2`, * Returns `true` if `d1` is definitely not less specific than `d2`,
* `false` otherwise. * `false` otherwise.
*/ */
private fun <D : CallableDescriptor> compareCallsByUsedArguments( private fun compareCallsByUsedArguments(
call1: FlatSignature<MutableResolvedCall<D>>, call1: FlatSignature<C>,
call2: FlatSignature<MutableResolvedCall<D>>, call2: FlatSignature<C>,
discriminateGenerics: Boolean discriminateGenerics: Boolean
): Boolean { ): Boolean {
if (discriminateGenerics) { if (discriminateGenerics) {
@@ -188,9 +263,9 @@ class OverloadingConflictResolver(
} }
} }
private fun <D: CallableDescriptor> isOfNotLessSpecificShape( private fun isOfNotLessSpecificShape(
call1: FlatSignature<MutableResolvedCall<D>>, call1: FlatSignature<C>,
call2: FlatSignature<MutableResolvedCall<D>> call2: FlatSignature<C>
): Boolean { ): Boolean {
val hasVarargs1 = call1.hasVarargs val hasVarargs1 = call1.hasVarargs
val hasVarargs2 = call2.hasVarargs val hasVarargs2 = call2.hasVarargs
@@ -204,9 +279,9 @@ class OverloadingConflictResolver(
return true return true
} }
private fun <D: CallableDescriptor> isOfNotLessSpecificVisibilityForDebugger( private fun isOfNotLessSpecificVisibilityForDebugger(
call1: FlatSignature<MutableResolvedCall<D>>, call1: FlatSignature<C>,
call2: FlatSignature<MutableResolvedCall<D>>, call2: FlatSignature<C>,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): Boolean { ): Boolean {
if (isDebuggerContext) { if (isDebuggerContext) {
@@ -254,34 +329,16 @@ class OverloadingConflictResolver(
tryCompareDescriptorsFromScripts(f, g) ?: tryCompareDescriptorsFromScripts(f, g) ?:
isNotLessSpecificCallableReferenceDescriptor(f, g) isNotLessSpecificCallableReferenceDescriptor(f, g)
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects // Different smart casts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
private fun <D : CallableDescriptor> uniquifyCandidatesSet(candidates: Collection<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> = private fun uniquifyCandidatesSet(candidates: Collection<C>): Set<C> =
THashSet<MutableResolvedCall<D>>(candidates.size, getCallHashingStrategy<MutableResolvedCall<D>>()).apply { addAll(candidates) } THashSet(candidates.size, resolvedCallHashingStrategy).apply { addAll(candidates) }
private fun <C> newResolvedCallSet(expectedSize: Int): MutableSet<C> = private fun newResolvedCallSet(expectedSize: Int): MutableSet<C> =
THashSet<C>(expectedSize, getCallHashingStrategy<C>()) THashSet(expectedSize, resolvedCallHashingStrategy)
private object ResolvedCallHashingStrategy : TObjectHashingStrategy<ResolvedCall<*>> { private fun FlatSignature<C>.candidateDescriptor() =
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() =
origin.resultingDescriptor.original origin.resultingDescriptor.original
private fun <D : CallableDescriptor> FlatSignature<ResolvedCall<D>>.descriptorVisibility() = private fun FlatSignature<C>.descriptorVisibility() =
candidateDescriptor().visibility candidateDescriptor().visibility
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; package org.jetbrains.kotlin.resolve.calls.results;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.resolve.BindingTrace; 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.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode; import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; 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 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.*; import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*;
public class ResolutionResultsHandler { 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 = private final OverloadingConflictResolver<MutableResolvedCall<?>> overloadingConflictResolver;
new Function1<MutableResolvedCall<?>, Integer>() {
@Override
public Integer invoke(MutableResolvedCall<?> resolvedCall) {
return DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.getResultingDescriptor()) != null ? 0 : 1;
}
};
private final OverloadingConflictResolver overloadingConflictResolver; public ResolutionResultsHandler(
@NotNull KotlinBuiltIns builtIns,
public ResolutionResultsHandler(@NotNull OverloadingConflictResolver overloadingConflictResolver) { @NotNull TypeSpecificityComparator specificityComparator
this.overloadingConflictResolver = overloadingConflictResolver; ) {
overloadingConflictResolver = FlatSignatureSpecificityKt.createOverloadingConflictResolver(builtIns, specificityComparator);
} }
@NotNull @NotNull
@@ -195,35 +180,6 @@ public class ResolutionResultsHandler {
return true; 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 @NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific( private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
@NotNull Set<MutableResolvedCall<D>> candidates, @NotNull Set<MutableResolvedCall<D>> candidates,
@@ -231,34 +187,16 @@ public class ResolutionResultsHandler {
boolean isDebuggerContext, boolean isDebuggerContext,
@NotNull CheckArgumentTypesMode checkArgumentsMode @NotNull CheckArgumentTypesMode checkArgumentsMode
) { ) {
if (candidates.size() == 1) { OverloadingConflictResolver<MutableResolvedCall<D>> myResolver = (OverloadingConflictResolver) overloadingConflictResolver;
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
}
if (candidates.iterator().next() instanceof VariableAsFunctionResolvedCall) { Set<MutableResolvedCall<D>> specificCalls =
candidates = overloadingConflictResolver.findMaximallySpecificVariableAsFunctionCalls(candidates); myResolver.chooseMaximallySpecificCandidates(candidates, checkArgumentsMode, discriminateGenerics, isDebuggerContext);
}
Set<MutableResolvedCall<D>> noEquivalentCalls = filterOutEquivalentCalls(candidates); if (specificCalls.size() == 1) {
Set<MutableResolvedCall<D>> noOverrides = return OverloadResolutionResultsImpl.success(specificCalls.iterator().next());
OverridingUtil.filterOverrides(noEquivalentCalls, MAP_RESOLVED_CALL_TO_RESULTING_DESCRIPTOR);
if (noOverrides.size() == 1) {
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
} }
else {
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext); return OverloadResolutionResultsImpl.ambiguity(specificCalls);
if (maximallySpecific != null) {
return OverloadResolutionResultsImpl.success(maximallySpecific);
} }
if (discriminateGenerics) {
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(
noOverrides, checkArgumentsMode, true, isDebuggerContext);
if (maximallySpecificGenericsDiscriminated != null) {
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
}
}
return OverloadResolutionResultsImpl.ambiguity(noOverrides);
} }
} }