Cone conflict resolver: extract JVM equivalent call filtering to a separate class
This commit is contained in:
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
|
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
||||||
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
|
|||||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.jvm.ConeEquivalentCallConflictResolver
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirAmbiguityError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirAmbiguityError
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirInapplicableCandidateError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirInapplicableCandidateError
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirUnresolvedNameError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirUnresolvedNameError
|
||||||
@@ -61,7 +61,11 @@ class FirCallResolver(
|
|||||||
topLevelScopes = topLevelScopes.asReversed(),
|
topLevelScopes = topLevelScopes.asReversed(),
|
||||||
localScopes = localScopes.asReversed()
|
localScopes = localScopes.asReversed()
|
||||||
)
|
)
|
||||||
private val conflictResolver = ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
|
||||||
|
private val conflictResolver = ConeCompositeConflictResolver(
|
||||||
|
ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents),
|
||||||
|
ConeEquivalentCallConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
||||||
|
)
|
||||||
|
|
||||||
fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall {
|
fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall {
|
||||||
qualifiedResolver.reset()
|
qualifiedResolver.reset()
|
||||||
|
|||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.arrayElementType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||||
|
import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
|
||||||
|
|
||||||
|
abstract class AbstractConeCallConflictResolver(
|
||||||
|
private val specificityComparator: TypeSpecificityComparator,
|
||||||
|
protected val inferenceComponents: InferenceComponents
|
||||||
|
) : ConeCallConflictResolver {
|
||||||
|
protected fun Collection<Candidate>.setIfOneOrEmpty(): Set<Candidate>? = when (size) {
|
||||||
|
0 -> emptySet()
|
||||||
|
1 -> setOf(single())
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
||||||
|
* `false` otherwise.
|
||||||
|
*/
|
||||||
|
protected fun compareCallsByUsedArguments(
|
||||||
|
call1: FlatSignature<Candidate>,
|
||||||
|
call2: FlatSignature<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Boolean {
|
||||||
|
if (discriminateGenerics) {
|
||||||
|
val isGeneric1 = call1.isGeneric
|
||||||
|
val isGeneric2 = call2.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
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call1.isExpect && call2.isExpect) return true
|
||||||
|
if (call1.isExpect && !call2.isExpect) return false
|
||||||
|
|
||||||
|
return createEmptyConstraintSystem().isSignatureNotLessSpecific(
|
||||||
|
call1,
|
||||||
|
call2,
|
||||||
|
OverloadabilitySpecificityCallbacks,
|
||||||
|
specificityComparator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
|
||||||
|
return when (val declaration = call.symbol.fir) {
|
||||||
|
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
||||||
|
is FirConstructor -> createFlatSignature(call, declaration)
|
||||||
|
is FirVariable<*> -> createFlatSignature(call, declaration)
|
||||||
|
is FirClass<*> -> createFlatSignature(call, declaration)
|
||||||
|
else -> error("Not supported: $declaration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createFlatSignature(call: Candidate, variable: FirVariable<*>): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
(variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(),
|
||||||
|
listOfNotNull<ConeKotlinType>(variable.receiverTypeRef?.coneTypeUnsafe()),
|
||||||
|
variable.receiverTypeRef != null,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
(variable as? FirProperty)?.isExpect == true,
|
||||||
|
false // TODO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
constructor.typeParameters.map { it.symbol },
|
||||||
|
computeParameterTypes(call, constructor),
|
||||||
|
//constructor.receiverTypeRef != null,
|
||||||
|
false,
|
||||||
|
constructor.valueParameters.any { it.isVararg },
|
||||||
|
constructor.valueParameters.count { it.defaultValue != null },
|
||||||
|
constructor.isExpect,
|
||||||
|
false // TODO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createFlatSignature(call: Candidate, function: FirSimpleFunction): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
function.typeParameters.map { it.symbol },
|
||||||
|
computeParameterTypes(call, function),
|
||||||
|
function.receiverTypeRef != null,
|
||||||
|
function.valueParameters.any { it.isVararg },
|
||||||
|
function.valueParameters.count { it.defaultValue != null },
|
||||||
|
function.isExpect,
|
||||||
|
false // TODO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirValueParameter.argumentType(): ConeKotlinType {
|
||||||
|
val type = returnTypeRef.coneTypeUnsafe<ConeKotlinType>()
|
||||||
|
if (isVararg) return type.arrayElementType(inferenceComponents.session)!!
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeParameterTypes(
|
||||||
|
call: Candidate,
|
||||||
|
function: FirFunction<*>
|
||||||
|
): List<ConeKotlinType> {
|
||||||
|
return (call.resultingTypeForCallableReference?.typeArguments?.map { it as ConeKotlinType }
|
||||||
|
?: (listOfNotNull(function.receiverTypeRef?.coneTypeUnsafe()) +
|
||||||
|
call.argumentMapping?.map { it.value.argumentType() }.orEmpty()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFlatSignature(call: Candidate, klass: FirClass<*>): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
(klass as? FirRegularClass)?.typeParameters?.map { it.symbol }.orEmpty(),
|
||||||
|
valueParameterTypes = emptyList(),
|
||||||
|
hasExtensionReceiver = false,
|
||||||
|
hasVarargs = false,
|
||||||
|
numDefaults = 0,
|
||||||
|
isExpect = (klass as? FirRegularClass)?.isExpect == true,
|
||||||
|
isSyntheticMember = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createEmptyConstraintSystem(): SimpleConstraintSystem {
|
||||||
|
return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem())
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
interface ConeCallConflictResolver {
|
||||||
|
fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Collection<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Set<Candidate> = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics)
|
||||||
|
|
||||||
|
fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Set<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Set<Candidate>
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
class ConeCompositeConflictResolver(
|
||||||
|
private vararg val conflictResolvers: AbstractConeCallConflictResolver
|
||||||
|
) : ConeCallConflictResolver {
|
||||||
|
override fun chooseMaximallySpecificCandidates(candidates: Set<Candidate>, discriminateGenerics: Boolean): Set<Candidate> {
|
||||||
|
if (candidates.size <= 1) return candidates
|
||||||
|
var currentCandidates = candidates
|
||||||
|
var index = 0
|
||||||
|
while (currentCandidates.size > 1 && index < conflictResolvers.size) {
|
||||||
|
val conflictResolver = conflictResolvers[index++]
|
||||||
|
currentCandidates = conflictResolver.chooseMaximallySpecificCandidates(candidates, discriminateGenerics)
|
||||||
|
}
|
||||||
|
return currentCandidates
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
-193
@@ -5,19 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|
||||||
import org.jetbrains.kotlin.fir.types.arrayElementType
|
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||||
import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
|
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
@@ -25,154 +21,21 @@ import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
class ConeOverloadConflictResolver(
|
class ConeOverloadConflictResolver(
|
||||||
val specificityComparator: TypeSpecificityComparator,
|
specificityComparator: TypeSpecificityComparator,
|
||||||
val inferenceComponents: InferenceComponents
|
inferenceComponents: InferenceComponents
|
||||||
|
) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) {
|
||||||
|
|
||||||
) {
|
override fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Set<Candidate>,
|
||||||
fun chooseMaximallySpecificCandidates(
|
|
||||||
candidates: Collection<Candidate>,
|
|
||||||
//checkArgumentsMode: CheckArgumentTypesMode,
|
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean
|
||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
candidates.setIfOneOrEmpty()?.let { return it }
|
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
|
||||||
|
|
||||||
val candidatesSet = filterOutEquivalentCalls(candidates)
|
|
||||||
|
|
||||||
findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) }
|
|
||||||
|
|
||||||
if (discriminateGenerics) {
|
if (discriminateGenerics) {
|
||||||
findMaximallySpecificCall(candidatesSet, true)?.let { return setOf(it) }
|
findMaximallySpecificCall(candidates, true)?.let { return setOf(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidatesSet
|
return candidates
|
||||||
}
|
|
||||||
|
|
||||||
private fun filterOutEquivalentCalls(candidates: Collection<Candidate>): Set<Candidate> {
|
|
||||||
val result = mutableSetOf<Candidate>()
|
|
||||||
outerLoop@ for (myCandidate in candidates) {
|
|
||||||
val me = myCandidate.symbol.fir
|
|
||||||
if (me is FirCallableMemberDeclaration<*> && me.symbol.callableId.className == null) {
|
|
||||||
for (otherCandidate in result) {
|
|
||||||
val other = otherCandidate.symbol.fir
|
|
||||||
if (other is FirCallableMemberDeclaration<*> && other.symbol.callableId.className == null) {
|
|
||||||
if (areEquivalentTopLevelCallables(me, myCandidate, other, otherCandidate)) {
|
|
||||||
continue@outerLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result += myCandidate
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun areEquivalentTopLevelCallables(
|
|
||||||
first: FirCallableMemberDeclaration<*>,
|
|
||||||
firstCandidate: Candidate,
|
|
||||||
second: FirCallableMemberDeclaration<*>,
|
|
||||||
secondCandidate: Candidate
|
|
||||||
): Boolean {
|
|
||||||
if (first.symbol.callableId != second.symbol.callableId) return false
|
|
||||||
if (first.isExpect != second.isExpect) return false
|
|
||||||
if (first.receiverTypeRef?.coneTypeUnsafe<ConeKotlinType>() != second.receiverTypeRef?.coneTypeUnsafe()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
val firstSignature = createFlatSignature(firstCandidate, first)
|
|
||||||
val secondSignature = createFlatSignature(secondCandidate, second)
|
|
||||||
return compareCallsByUsedArguments(firstSignature, secondSignature, false) &&
|
|
||||||
compareCallsByUsedArguments(secondSignature, firstSignature, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
|
|
||||||
return when (val declaration = call.symbol.fir) {
|
|
||||||
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
|
||||||
is FirConstructor -> createFlatSignature(call, declaration)
|
|
||||||
is FirVariable<*> -> createFlatSignature(call, declaration)
|
|
||||||
is FirClass<*> -> createFlatSignature(call, declaration)
|
|
||||||
else -> error("Not supported: $declaration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate, declaration: FirCallableMemberDeclaration<*>): FlatSignature<Candidate> {
|
|
||||||
return when (declaration) {
|
|
||||||
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
|
||||||
is FirConstructor -> createFlatSignature(call, declaration)
|
|
||||||
is FirVariable<*> -> createFlatSignature(call, declaration as FirVariable<*>)
|
|
||||||
else -> error("Not supported: $declaration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature<Candidate> {
|
|
||||||
return FlatSignature(
|
|
||||||
call,
|
|
||||||
constructor.typeParameters.map { it.symbol },
|
|
||||||
computeParameterTypes(call, constructor),
|
|
||||||
//constructor.receiverTypeRef != null,
|
|
||||||
false,
|
|
||||||
constructor.valueParameters.any { it.isVararg },
|
|
||||||
constructor.valueParameters.count { it.defaultValue != null },
|
|
||||||
constructor.isExpect,
|
|
||||||
false // TODO
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirValueParameter.argumentType(): ConeKotlinType {
|
|
||||||
val type = returnTypeRef.coneTypeUnsafe<ConeKotlinType>()
|
|
||||||
if (isVararg) return type.arrayElementType(inferenceComponents.session)!!
|
|
||||||
return type
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate, function: FirSimpleFunction): FlatSignature<Candidate> {
|
|
||||||
return FlatSignature(
|
|
||||||
call,
|
|
||||||
function.typeParameters.map { it.symbol },
|
|
||||||
computeParameterTypes(call, function),
|
|
||||||
function.receiverTypeRef != null,
|
|
||||||
function.valueParameters.any { it.isVararg },
|
|
||||||
function.valueParameters.count { it.defaultValue != null },
|
|
||||||
function.isExpect,
|
|
||||||
false // TODO
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun computeParameterTypes(
|
|
||||||
call: Candidate,
|
|
||||||
function: FirFunction<*>
|
|
||||||
): List<ConeKotlinType> {
|
|
||||||
return (call.resultingTypeForCallableReference?.typeArguments?.map { it as ConeKotlinType }
|
|
||||||
?: (listOfNotNull<ConeKotlinType>(function.receiverTypeRef?.coneTypeUnsafe()) +
|
|
||||||
call.argumentMapping?.map { it.value.argumentType() }.orEmpty()))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate, variable: FirVariable<*>): FlatSignature<Candidate> {
|
|
||||||
return FlatSignature(
|
|
||||||
call,
|
|
||||||
(variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(),
|
|
||||||
listOfNotNull<ConeKotlinType>(variable.receiverTypeRef?.coneTypeUnsafe()),
|
|
||||||
variable.receiverTypeRef != null,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
(variable as? FirProperty)?.isExpect == true,
|
|
||||||
false // TODO
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFlatSignature(call: Candidate, klass: FirClass<*>): FlatSignature<Candidate> {
|
|
||||||
return FlatSignature(
|
|
||||||
call,
|
|
||||||
(klass as? FirRegularClass)?.typeParameters?.map { it.symbol }.orEmpty(),
|
|
||||||
valueParameterTypes = emptyList(),
|
|
||||||
hasExtensionReceiver = false,
|
|
||||||
hasVarargs = false,
|
|
||||||
numDefaults = 0,
|
|
||||||
isExpect = (klass as? FirRegularClass)?.isExpect == true,
|
|
||||||
isSyntheticMember = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createEmptyConstraintSystem(): SimpleConstraintSystem {
|
|
||||||
return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findMaximallySpecificCall(
|
private fun findMaximallySpecificCall(
|
||||||
@@ -180,11 +43,9 @@ class ConeOverloadConflictResolver(
|
|||||||
discriminateGenerics: Boolean//,
|
discriminateGenerics: Boolean//,
|
||||||
//isDebuggerContext: Boolean
|
//isDebuggerContext: Boolean
|
||||||
): Candidate? {
|
): Candidate? {
|
||||||
val filteredCandidates = candidates//uniquifyCandidatesSet(candidates)
|
if (candidates.size <= 1) return candidates.singleOrNull()
|
||||||
|
|
||||||
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
|
val conflictingCandidates = candidates.map { candidateCall ->
|
||||||
|
|
||||||
val conflictingCandidates = filteredCandidates.map { candidateCall ->
|
|
||||||
createFlatSignature(candidateCall)
|
createFlatSignature(candidateCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +69,7 @@ class ConeOverloadConflictResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result == null) return null
|
if (result == null) return null
|
||||||
if (any { it != result && isNotWorse(it, result!!) }) {
|
if (any { it != result && isNotWorse(it, result) }) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -235,38 +96,6 @@ class ConeOverloadConflictResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
|
||||||
* `false` otherwise.
|
|
||||||
*/
|
|
||||||
private fun compareCallsByUsedArguments(
|
|
||||||
call1: FlatSignature<Candidate>,
|
|
||||||
call2: FlatSignature<Candidate>,
|
|
||||||
discriminateGenerics: Boolean
|
|
||||||
): Boolean {
|
|
||||||
if (discriminateGenerics) {
|
|
||||||
val isGeneric1 = call1.isGeneric
|
|
||||||
val isGeneric2 = call2.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
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!call1.isExpect && call2.isExpect) return true
|
|
||||||
if (call1.isExpect && !call2.isExpect) return false
|
|
||||||
|
|
||||||
return createEmptyConstraintSystem().isSignatureNotLessSpecific(
|
|
||||||
call1,
|
|
||||||
call2,
|
|
||||||
OverloadabilitySpecificityCallbacks,
|
|
||||||
specificityComparator
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isOfNotLessSpecificShape(
|
private fun isOfNotLessSpecificShape(
|
||||||
call1: FlatSignature<Candidate>,
|
call1: FlatSignature<Candidate>,
|
||||||
call2: FlatSignature<Candidate>
|
call2: FlatSignature<Candidate>
|
||||||
@@ -282,12 +111,6 @@ class ConeOverloadConflictResolver(
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <C> Collection<C>.setIfOneOrEmpty(): Set<C>? = when (size) {
|
|
||||||
0 -> emptySet()
|
|
||||||
1 -> setOf(single())
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object NoSubstitutor : TypeSubstitutorMarker
|
object NoSubstitutor : TypeSubstitutorMarker
|
||||||
@@ -295,19 +118,21 @@ object NoSubstitutor : TypeSubstitutorMarker
|
|||||||
class ConeSimpleConstraintSystemImpl(val system: NewConstraintSystemImpl) : SimpleConstraintSystem {
|
class ConeSimpleConstraintSystemImpl(val system: NewConstraintSystemImpl) : SimpleConstraintSystem {
|
||||||
override fun registerTypeVariables(typeParameters: Collection<TypeParameterMarker>): TypeSubstitutorMarker = with(context) {
|
override fun registerTypeVariables(typeParameters: Collection<TypeParameterMarker>): TypeSubstitutorMarker = with(context) {
|
||||||
val csBuilder = system.getBuilder()
|
val csBuilder = system.getBuilder()
|
||||||
val substitutionMap = typeParameters.associate {
|
val substitutionMap = typeParameters.associateWith {
|
||||||
require(it is FirTypeParameterSymbol)
|
require(it is FirTypeParameterSymbol)
|
||||||
val variable = TypeParameterBasedTypeVariable(it)
|
val variable = TypeParameterBasedTypeVariable(it)
|
||||||
csBuilder.registerVariable(variable)
|
csBuilder.registerVariable(variable)
|
||||||
|
|
||||||
|
variable.defaultType
|
||||||
it to variable.defaultType
|
|
||||||
}
|
}
|
||||||
val substitutor = substitutorByMap(substitutionMap.cast())
|
val substitutor = substitutorByMap(substitutionMap.cast())
|
||||||
for (typeParameter in typeParameters) {
|
for (typeParameter in typeParameters) {
|
||||||
require(typeParameter is FirTypeParameterSymbol)
|
require(typeParameter is FirTypeParameterSymbol)
|
||||||
for (upperBound in typeParameter.fir.bounds) {
|
for (upperBound in typeParameter.fir.bounds) {
|
||||||
addSubtypeConstraint(substitutionMap[typeParameter]!!, substitutor.substituteOrSelf(upperBound.coneTypeUnsafe()))
|
addSubtypeConstraint(
|
||||||
|
substitutionMap[typeParameter] ?: error("No ${typeParameter.fir.render()} in substitution map"),
|
||||||
|
substitutor.substituteOrSelf(upperBound.coneTypeUnsafe())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return substitutor
|
return substitutor
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls.jvm
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.AbstractConeCallConflictResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.InferenceComponents
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
|
||||||
|
// This conflict resolver filters JVM equivalent top-level functions
|
||||||
|
// like emptyArray() from intrinsics and built-ins
|
||||||
|
class ConeEquivalentCallConflictResolver(
|
||||||
|
specificityComparator: TypeSpecificityComparator,
|
||||||
|
inferenceComponents: InferenceComponents
|
||||||
|
) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) {
|
||||||
|
override fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Set<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Set<Candidate> {
|
||||||
|
return filterOutEquivalentCalls(candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filterOutEquivalentCalls(candidates: Collection<Candidate>): Set<Candidate> {
|
||||||
|
val result = mutableSetOf<Candidate>()
|
||||||
|
outerLoop@ for (myCandidate in candidates) {
|
||||||
|
val me = myCandidate.symbol.fir
|
||||||
|
if (me is FirCallableMemberDeclaration<*> && me.symbol.callableId.className == null) {
|
||||||
|
for (otherCandidate in result) {
|
||||||
|
val other = otherCandidate.symbol.fir
|
||||||
|
if (other is FirCallableMemberDeclaration<*> && other.symbol.callableId.className == null) {
|
||||||
|
if (areEquivalentTopLevelCallables(me, myCandidate, other, otherCandidate)) {
|
||||||
|
continue@outerLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += myCandidate
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun areEquivalentTopLevelCallables(
|
||||||
|
first: FirCallableMemberDeclaration<*>,
|
||||||
|
firstCandidate: Candidate,
|
||||||
|
second: FirCallableMemberDeclaration<*>,
|
||||||
|
secondCandidate: Candidate
|
||||||
|
): Boolean {
|
||||||
|
if (first.symbol.callableId != second.symbol.callableId) return false
|
||||||
|
if (first.isExpect != second.isExpect) return false
|
||||||
|
if (first.receiverTypeRef?.coneTypeUnsafe<ConeKotlinType>() != second.receiverTypeRef?.coneTypeUnsafe()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val firstSignature = createFlatSignature(firstCandidate, first)
|
||||||
|
val secondSignature = createFlatSignature(secondCandidate, second)
|
||||||
|
return compareCallsByUsedArguments(firstSignature, secondSignature, false) &&
|
||||||
|
compareCallsByUsedArguments(secondSignature, firstSignature, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFlatSignature(call: Candidate, declaration: FirCallableMemberDeclaration<*>): FlatSignature<Candidate> {
|
||||||
|
return when (declaration) {
|
||||||
|
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
||||||
|
is FirConstructor -> createFlatSignature(call, declaration)
|
||||||
|
is FirVariable<*> -> createFlatSignature(call, declaration as FirVariable<*>)
|
||||||
|
else -> error("Not supported: $declaration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user