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 {
|
||||
val kind: ConstraintPositionKind
|
||||
|
||||
|
||||
@@ -33,9 +33,6 @@ class FlatSignature<out T>(
|
||||
val hasVarargs: Boolean,
|
||||
val numDefaults: Int
|
||||
) {
|
||||
override fun toString() = "<${typeParameters.joinToString {it.name.asString()} }> ${valueParameterTypes.joinToString()}; " +
|
||||
"${if (hasVarargs) "varargs;" else ""} $numDefaults"
|
||||
|
||||
val isGeneric = typeParameters.isNotEmpty()
|
||||
|
||||
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.descriptors.*
|
||||
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.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.*
|
||||
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) {
|
||||
|
||||
@@ -147,59 +146,41 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
||||
call1: FlatSignature<MutableResolvedCall<D>>,
|
||||
call2: FlatSignature<MutableResolvedCall<D>>,
|
||||
discriminateGenerics: Boolean
|
||||
): Boolean {
|
||||
if (discriminateGenerics) {
|
||||
val isGeneric1 = call1.isGeneric
|
||||
val isGeneric2 = call2.isGeneric
|
||||
): Boolean =
|
||||
isSignatureNotLessSpecific(call1, call2, call1.callHandle(),
|
||||
if (discriminateGenerics)
|
||||
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
|
||||
if (isGeneric1 && !isGeneric2) return false
|
||||
if (!isGeneric1 && isGeneric2) return true
|
||||
// two generics are non-comparable
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user