Cone conflict resolver: filter equivalent top-level callables
This commit is contained in:
+46
-1
@@ -37,7 +37,7 @@ class ConeOverloadConflictResolver(
|
|||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
candidates.setIfOneOrEmpty()?.let { return it }
|
candidates.setIfOneOrEmpty()?.let { return it }
|
||||||
|
|
||||||
val candidatesSet = candidates.toSet()
|
val candidatesSet = filterOutEquivalentCalls(candidates)
|
||||||
|
|
||||||
findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) }
|
findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) }
|
||||||
|
|
||||||
@@ -48,6 +48,42 @@ class ConeOverloadConflictResolver(
|
|||||||
return candidatesSet
|
return candidatesSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
private fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
|
||||||
return when (val declaration = call.symbol.fir) {
|
return when (val declaration = call.symbol.fir) {
|
||||||
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
is FirSimpleFunction -> createFlatSignature(call, declaration)
|
||||||
@@ -58,6 +94,15 @@ class ConeOverloadConflictResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
private fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature<Candidate> {
|
||||||
return FlatSignature(
|
return FlatSignature(
|
||||||
call,
|
call,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
val x: Array<String> = emptyArray()
|
||||||
|
|
||||||
|
val y: Array<String>
|
||||||
|
get() = emptyArray()
|
||||||
|
|
||||||
|
interface My
|
||||||
|
|
||||||
|
val z: Array<out My>
|
||||||
|
get() = emptyArray()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
FILE: emptyArray.kt
|
||||||
|
public final val x: R|kotlin/Array<kotlin/String>| = R|kotlin/emptyArray|<R|kotlin/String|>()
|
||||||
|
public get(): R|kotlin/Array<kotlin/String>|
|
||||||
|
public final val y: R|kotlin/Array<kotlin/String>|
|
||||||
|
public get(): R|kotlin/Array<kotlin/String>| {
|
||||||
|
^ R|kotlin/emptyArray|<R|kotlin/String|>()
|
||||||
|
}
|
||||||
|
public abstract interface My : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final val z: R|kotlin/Array<out My>|
|
||||||
|
public get(): R|kotlin/Array<out My>| {
|
||||||
|
^ R|kotlin/emptyArray|<R|My|>()
|
||||||
|
}
|
||||||
Generated
+5
@@ -68,6 +68,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/concurrent.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/concurrent.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("emptyArray.kt")
|
||||||
|
public void testEmptyArray() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/emptyArray.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("exception.kt")
|
@TestMetadata("exception.kt")
|
||||||
public void testException() throws Exception {
|
public void testException() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/exception.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/exception.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user