From 96c5003a1394fef9ae14ad2063f4018d60ce90d5 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 6 Nov 2019 15:58:01 +0300 Subject: [PATCH] Cone conflict resolver: filter equivalent top-level callables --- .../calls/ConeOverloadConflictResolver.kt | 47 ++++++++++++++++++- .../testData/resolve/stdlib/emptyArray.kt | 9 ++++ .../testData/resolve/stdlib/emptyArray.txt | 13 +++++ ...FirDiagnosticsWithStdlibTestGenerated.java | 5 ++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 compiler/fir/resolve/testData/resolve/stdlib/emptyArray.kt create mode 100644 compiler/fir/resolve/testData/resolve/stdlib/emptyArray.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt index 2c04807b062..57447f80275 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt @@ -37,7 +37,7 @@ class ConeOverloadConflictResolver( ): Set { candidates.setIfOneOrEmpty()?.let { return it } - val candidatesSet = candidates.toSet() + val candidatesSet = filterOutEquivalentCalls(candidates) findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) } @@ -48,6 +48,42 @@ class ConeOverloadConflictResolver( return candidatesSet } + private fun filterOutEquivalentCalls(candidates: Collection): Set { + val result = mutableSetOf() + 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() != 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 { return when (val declaration = call.symbol.fir) { is FirSimpleFunction -> createFlatSignature(call, declaration) @@ -58,6 +94,15 @@ class ConeOverloadConflictResolver( } } + private fun createFlatSignature(call: Candidate, declaration: FirCallableMemberDeclaration<*>): FlatSignature { + 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 { return FlatSignature( call, diff --git a/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.kt b/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.kt new file mode 100644 index 00000000000..c737aa45ff7 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.kt @@ -0,0 +1,9 @@ +val x: Array = emptyArray() + +val y: Array + get() = emptyArray() + +interface My + +val z: Array + get() = emptyArray() \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.txt b/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.txt new file mode 100644 index 00000000000..6d80949bce7 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/emptyArray.txt @@ -0,0 +1,13 @@ +FILE: emptyArray.kt + public final val x: R|kotlin/Array| = R|kotlin/emptyArray|() + public get(): R|kotlin/Array| + public final val y: R|kotlin/Array| + public get(): R|kotlin/Array| { + ^ R|kotlin/emptyArray|() + } + public abstract interface My : R|kotlin/Any| { + } + public final val z: R|kotlin/Array| + public get(): R|kotlin/Array| { + ^ R|kotlin/emptyArray|() + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 37baa551ca2..3bb1e51ae39 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -68,6 +68,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic 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") public void testException() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/exception.kt");