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");
|
* 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,
|
||||||
|
|||||||
+51
@@ -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}
|
||||||
|
)
|
||||||
+117
-60
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+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");
|
* 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user