Generalize signature comparison: callable references overloading conflict resolution.

This commit is contained in:
Dmitry Petrov
2016-02-17 16:34:49 +03:00
parent c5f3cbc645
commit 4ac05f1cd8
3 changed files with 57 additions and 102 deletions
@@ -57,16 +57,25 @@ class FlatSignature<out T>(
}
}
val extensionReceiverParameterType = originalDescriptor.extensionReceiverParameter?.type
val valueArgumentParameterTypes = call.call.valueArguments.map { valueArgumentToParameterType[it] }
val valueParameterTypes = extensionReceiverParameterType.singletonOrEmptyList() + valueArgumentParameterTypes
val valueParameterTypes = originalDescriptor.extensionReceiverTypeOrEmpty() + valueArgumentParameterTypes
val hasVarargs = originalDescriptor.valueParameters.any { it.varargElementType != null }
return FlatSignature(call, originalTypeParameters, valueParameterTypes, hasVarargs, numDefaults)
}
fun <D : CallableDescriptor> createFromCallableDescriptor(descriptor: D): FlatSignature<D> =
FlatSignature(descriptor,
descriptor.typeParameters,
valueParameterTypes = descriptor.extensionReceiverTypeOrEmpty() + descriptor.valueParameters.map { it.flatType },
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
numDefaults = 0)
val ValueParameterDescriptor.flatType: KotlinType
get() = varargElementType ?: type
fun CallableDescriptor.extensionReceiverTypeOrEmpty() =
extensionReceiverParameter?.type.singletonOrEmptyList()
}
}
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
interface SpecificityComparisonCallbacks<T> {
fun isNotLessSpecificByOrigin(signature1: FlatSignature<T>, signature2: FlatSignature<T>): Boolean?
fun isNotLessSpecificSignature(signature1: FlatSignature<T>, signature2: FlatSignature<T>): Boolean?
fun isTypeNotLessSpecific(type1: KotlinType, type2: KotlinType): Boolean?
}
@@ -34,7 +34,7 @@ fun <T> isSignatureNotLessSpecific(
callHandle: CallHandle,
callbacks: SpecificityComparisonCallbacks<T>
): Boolean {
callbacks.isNotLessSpecificByOrigin(signature1, signature2)?.let { return it }
callbacks.isNotLessSpecificSignature(signature1, signature2)?.let { return it }
val typeParameters = signature2.typeParameters
val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl()
@@ -19,18 +19,19 @@ package org.jetbrains.kotlin.resolve.calls.results
import gnu.trove.THashSet
import gnu.trove.TObjectHashingStrategy
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
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.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
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.types.KotlinType
import org.jetbrains.kotlin.types.Specificity
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.getSpecificityRelationTo
class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
@@ -151,23 +152,41 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
if (discriminateGenerics)
SpecificityComparisonDiscriminatingGenerics
else
DefaultSpecificityComparison)
DefaultCallSpecificityComparison)
private abstract inner class SpecificityComparisonWithNumerics : SpecificityComparisonCallbacks<MutableResolvedCall<*>> {
override fun isTypeNotLessSpecific(type1: KotlinType, type2: KotlinType): Boolean? =
numericTypeMoreSpecific(type1, type2)
private abstract inner class SpecificityComparisonWithNumerics<T> : SpecificityComparisonCallbacks<T> {
override fun isNotLessSpecificSignature(signature1: FlatSignature<T>, signature2: FlatSignature<T>): Boolean?
= null
override fun isTypeNotLessSpecific(type1: KotlinType, type2: KotlinType): Boolean? {
val _double = builtIns.doubleType
val _float = builtIns.floatType
val _long = builtIns.longType
val _int = builtIns.intType
val _byte = builtIns.byteType
val _short = builtIns.shortType
when {
TypeUtils.equalTypes(type1, _double) && TypeUtils.equalTypes(type2, _float) -> return true
TypeUtils.equalTypes(type1, _int) -> {
when {
TypeUtils.equalTypes(type2, _long) -> return true
TypeUtils.equalTypes(type2, _byte) -> return true
TypeUtils.equalTypes(type2, _short) -> return true
}
}
TypeUtils.equalTypes(type1, _short) && TypeUtils.equalTypes(type2, _byte) -> return true
}
return false
}
}
private val DefaultSpecificityComparison = object : SpecificityComparisonWithNumerics() {
override fun isNotLessSpecificByOrigin(
signature1: FlatSignature<MutableResolvedCall<*>>,
signature2: FlatSignature<MutableResolvedCall<*>>
): Boolean? =
null
}
private val DefaultCallSpecificityComparison = object : SpecificityComparisonWithNumerics<MutableResolvedCall<*>>() {}
private val DefaultDescriptorSpecificityComparison = object : SpecificityComparisonWithNumerics<CallableDescriptor>() {}
private val SpecificityComparisonDiscriminatingGenerics = object : SpecificityComparisonWithNumerics() {
override fun isNotLessSpecificByOrigin(
private val SpecificityComparisonDiscriminatingGenerics = object : SpecificityComparisonWithNumerics<MutableResolvedCall<*>>() {
override fun isNotLessSpecificSignature(
signature1: FlatSignature<MutableResolvedCall<*>>,
signature2: FlatSignature<MutableResolvedCall<*>>
): Boolean? {
@@ -236,42 +255,12 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
* `null` if undecided.
*/
private fun compareFunctionParameterTypes(f: CallableDescriptor, g: CallableDescriptor): Boolean {
val fReceiverType = f.extensionReceiverType
val gReceiverType = g.extensionReceiverType
if (fReceiverType != null && gReceiverType != null) {
if (!typeNotLessSpecific(fReceiverType, gReceiverType)) {
return false
}
}
if (f.valueParameters.size != g.valueParameters.size) return false
if (f.varargParameterPosition() != g.varargParameterPosition()) return false
val fParams = f.valueParameters
val gParams = g.valueParameters
val fSize = fParams.size
val gSize = gParams.size
if (fSize != gSize) return false
for (i in 0..fSize - 1) {
val fParam = fParams[i]
val gParam = gParams[i]
val fParamIsVararg = fParam.varargElementType != null
val gParamIsVararg = gParam.varargElementType != null
if (fParamIsVararg != gParamIsVararg) {
return false
}
val fParamType = getVarargElementTypeOrType(fParam)
val gParamType = getVarargElementTypeOrType(gParam)
if (!typeNotLessSpecific(fParamType, gParamType)) {
return false
}
}
return true
val fSignature = FlatSignature.createFromCallableDescriptor(f)
val gSignature = FlatSignature.createFromCallableDescriptor(g)
return isSignatureNotLessSpecific(fSignature, gSignature, CallHandle.NONE, DefaultDescriptorSpecificityComparison)
}
private fun isNotLessSpecificCallableReference(f: CallableDescriptor, g: CallableDescriptor): Boolean =
@@ -279,52 +268,6 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
tryCompareDescriptorsFromScripts(f, g) ?:
compareFunctionParameterTypes(f, g)
private fun getVarargElementTypeOrType(parameterDescriptor: ValueParameterDescriptor): KotlinType =
parameterDescriptor.varargElementType ?: parameterDescriptor.type
private fun typeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean {
val isSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(specific, general) || numericTypeMoreSpecific(specific, general)
if (!isSubtype) return false
if (isDefinitelyLessSpecificByTypeSpecificity(specific, general)) return false
return true
}
private fun isDefinitelyLessSpecificByTypeSpecificity(specific: KotlinType, general: KotlinType): Boolean {
val sThanG = specific.getSpecificityRelationTo(general)
val gThanS = general.getSpecificityRelationTo(specific)
return sThanG == Specificity.Relation.LESS_SPECIFIC &&
gThanS != Specificity.Relation.LESS_SPECIFIC
}
private fun numericTypeMoreSpecific(specific: KotlinType, general: KotlinType): Boolean {
val _double = builtIns.doubleType
val _float = builtIns.floatType
val _long = builtIns.longType
val _int = builtIns.intType
val _byte = builtIns.byteType
val _short = builtIns.shortType
when {
TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float) -> return true
TypeUtils.equalTypes(specific, _int) -> {
when {
TypeUtils.equalTypes(general, _long) -> return true
TypeUtils.equalTypes(general, _byte) -> return true
TypeUtils.equalTypes(general, _short) -> return true
}
}
TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte) -> return true
}
return false
}
private val CallableDescriptor.extensionReceiverType: KotlinType?
get() = extensionReceiverParameter?.type
companion object {
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
@Suppress("CAST_NEVER_SUCCEEDS")
@@ -364,3 +307,6 @@ internal fun <D : CallableDescriptor> FlatSignature<ResolvedCall<D>>.callHandle(
internal fun <D : CallableDescriptor> FlatSignature<ResolvedCall<D>>.descriptorVisibility() =
candidateDescriptor().visibility
internal fun CallableDescriptor.varargParameterPosition() =
valueParameters.indexOfFirst { it.varargElementType != null }