Generalize signature comparison: make it work for regular call overloading conflict resolution.
This commit is contained in:
+2
@@ -38,6 +38,8 @@ enum class ConstraintPositionKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun valueParameterPosition(index: Int) = ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(index)
|
||||||
|
|
||||||
interface ConstraintPosition {
|
interface ConstraintPosition {
|
||||||
val kind: ConstraintPositionKind
|
val kind: ConstraintPositionKind
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ class FlatSignature<out T>(
|
|||||||
val hasVarargs: Boolean,
|
val hasVarargs: Boolean,
|
||||||
val numDefaults: Int
|
val numDefaults: Int
|
||||||
) {
|
) {
|
||||||
override fun toString() = "<${typeParameters.joinToString {it.name.asString()} }> ${valueParameterTypes.joinToString()}; " +
|
|
||||||
"${if (hasVarargs) "varargs;" else ""} $numDefaults"
|
|
||||||
|
|
||||||
val isGeneric = typeParameters.isNotEmpty()
|
val isGeneric = typeParameters.isNotEmpty()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.results
|
||||||
|
|
||||||
|
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.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
|
||||||
|
interface SpecificityComparisonCallbacks<T> {
|
||||||
|
fun isNotLessSpecificByOrigin(signature1: FlatSignature<T>, signature2: FlatSignature<T>): Boolean?
|
||||||
|
fun isTypeNotLessSpecific(type1: KotlinType, type2: KotlinType): Boolean?
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> isSignatureNotLessSpecific(
|
||||||
|
signature1: FlatSignature<T>,
|
||||||
|
signature2: FlatSignature<T>,
|
||||||
|
callHandle: CallHandle,
|
||||||
|
callbacks: SpecificityComparisonCallbacks<T>
|
||||||
|
): Boolean {
|
||||||
|
callbacks.isNotLessSpecificByOrigin(signature1, signature2)?.let { return it }
|
||||||
|
|
||||||
|
val typeParameters = signature2.typeParameters
|
||||||
|
val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl()
|
||||||
|
var numConstraints = 0
|
||||||
|
val typeSubstitutor = constraintSystemBuilder.registerTypeVariables(callHandle, typeParameters)
|
||||||
|
|
||||||
|
for ((type1, type2) in signature1.valueParameterTypes.zip(signature2.valueParameterTypes)) {
|
||||||
|
if (type1 == null || type2 == null) continue
|
||||||
|
|
||||||
|
if (isDefinitelyLessSpecificByTypeSpecificity(type1, type2)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeParameters.isEmpty() || !TypeUtils.dependsOnTypeParameters(type2, typeParameters)) {
|
||||||
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(type1, type2)) {
|
||||||
|
callbacks.isTypeNotLessSpecific(type1, type2)?.let { if (!it) return false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val constraintPosition = valueParameterPosition(numConstraints++)
|
||||||
|
val substitutedType2 = typeSubstitutor.safeSubstitute(type2, Variance.INVARIANT)
|
||||||
|
constraintSystemBuilder.addSubtypeConstraint(type1, substitutedType2, constraintPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numConstraints > 0) {
|
||||||
|
constraintSystemBuilder.fixVariables()
|
||||||
|
val constraintSystem = constraintSystemBuilder.build()
|
||||||
|
if (constraintSystem.status.hasContradiction()) {
|
||||||
|
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
|
||||||
|
}
|
||||||
+33
-52
@@ -21,17 +21,16 @@ import gnu.trove.TObjectHashingStrategy
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionMutableResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionMutableResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.types.*
|
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.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.getSpecificityRelationTo
|
||||||
|
|
||||||
class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
||||||
|
|
||||||
@@ -147,59 +146,41 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||||
call2: FlatSignature<MutableResolvedCall<D>>,
|
call2: FlatSignature<MutableResolvedCall<D>>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean
|
||||||
): Boolean {
|
): Boolean =
|
||||||
if (discriminateGenerics) {
|
isSignatureNotLessSpecific(call1, call2, call1.callHandle(),
|
||||||
val isGeneric1 = call1.isGeneric
|
if (discriminateGenerics)
|
||||||
val isGeneric2 = call2.isGeneric
|
SpecificityComparisonDiscriminatingGenerics
|
||||||
|
else
|
||||||
|
DefaultSpecificityComparison)
|
||||||
|
|
||||||
|
private abstract inner class SpecificityComparisonWithNumerics : SpecificityComparisonCallbacks<MutableResolvedCall<*>> {
|
||||||
|
override fun isTypeNotLessSpecific(type1: KotlinType, type2: KotlinType): Boolean? =
|
||||||
|
numericTypeMoreSpecific(type1, type2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DefaultSpecificityComparison = object : SpecificityComparisonWithNumerics() {
|
||||||
|
override fun isNotLessSpecificByOrigin(
|
||||||
|
signature1: FlatSignature<MutableResolvedCall<*>>,
|
||||||
|
signature2: FlatSignature<MutableResolvedCall<*>>
|
||||||
|
): Boolean? =
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private val SpecificityComparisonDiscriminatingGenerics = object : SpecificityComparisonWithNumerics() {
|
||||||
|
override fun isNotLessSpecificByOrigin(
|
||||||
|
signature1: FlatSignature<MutableResolvedCall<*>>,
|
||||||
|
signature2: FlatSignature<MutableResolvedCall<*>>
|
||||||
|
): Boolean? {
|
||||||
|
val isGeneric1 = signature1.isGeneric
|
||||||
|
val isGeneric2 = signature2.isGeneric
|
||||||
// generic loses to non-generic
|
// generic loses to non-generic
|
||||||
if (isGeneric1 && !isGeneric2) return false
|
if (isGeneric1 && !isGeneric2) return false
|
||||||
if (!isGeneric1 && isGeneric2) return true
|
if (!isGeneric1 && isGeneric2) return true
|
||||||
// two generics are non-comparable
|
// two generics are non-comparable
|
||||||
if (isGeneric1 && isGeneric2) return false
|
if (isGeneric1 && isGeneric2) return false
|
||||||
|
// otherwise continue comparing signatures
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val typeParameters = call2.typeParameters
|
|
||||||
val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl()
|
|
||||||
var hasConstraints = false
|
|
||||||
val typeSubstitutor = constraintSystemBuilder.registerTypeVariables(call1.callHandle(), typeParameters)
|
|
||||||
|
|
||||||
fun compareTypesAndUpdateConstraints(type1: KotlinType?, type2: KotlinType?, constraintPosition: ConstraintPosition): Boolean {
|
|
||||||
if (type1 == null || type2 == null) return true
|
|
||||||
|
|
||||||
if (typeParameters.isEmpty() || !TypeUtils.dependsOnTypeParameters(type2, typeParameters)) {
|
|
||||||
if (!typeNotLessSpecific(type1, type2)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (isDefinitelyLessSpecificByTypeSpecificity(type1, type2)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hasConstraints = true
|
|
||||||
val substitutedType2 = typeSubstitutor.safeSubstitute(type2, Variance.INVARIANT)
|
|
||||||
constraintSystemBuilder.addSubtypeConstraint(type1, substitutedType2, constraintPosition)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var argumentIndex = 0
|
|
||||||
for ((type1, type2) in call1.valueParameterTypes.zip(call2.valueParameterTypes)) {
|
|
||||||
// We use this constraint system for subtyping relation check only,
|
|
||||||
// so exact value parameter position doesn't matter.
|
|
||||||
if (!compareTypesAndUpdateConstraints(type1, type2, VALUE_PARAMETER_POSITION.position(++argumentIndex))) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasConstraints) {
|
|
||||||
constraintSystemBuilder.fixVariables()
|
|
||||||
val constraintSystem = constraintSystemBuilder.build()
|
|
||||||
if (constraintSystem.status.hasContradiction()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D: CallableDescriptor> isOfNotLessSpecificShape(
|
private fun <D: CallableDescriptor> isOfNotLessSpecificShape(
|
||||||
|
|||||||
Reference in New Issue
Block a user