From 0fa98ed63526a2d55f696a06fe185206f08bd4f8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 4 Feb 2020 16:06:24 +0300 Subject: [PATCH] [FIR] Discriminate abstract members when resolving on super --- .../jvm/ConeEquivalentCallConflictResolver.kt | 3 ++- .../jetbrains/kotlin/fir/FirCallResolver.kt | 11 ++++++-- .../resolve/calls/ConeCallConflictResolver.kt | 9 ++++--- .../calls/ConeCompositeConflictResolver.kt | 8 ++++-- .../calls/ConeOverloadConflictResolver.kt | 27 ++++++++++++++++--- .../resolve/problems/incorrectSuperCall.kt | 2 +- .../resolve/problems/incorrectSuperCall.txt | 2 +- ...unqualifiedSuperWithAbstractMembers.fir.kt | 4 +-- ...hMethodOverriddenInAnotherSupertype.fir.kt | 2 +- ...itNotNullOnDelegatedImplementation.fir.txt | 7 ++--- 10 files changed, 56 insertions(+), 19 deletions(-) diff --git a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt index a38e048d852..9218b3c1bf2 100644 --- a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt +++ b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt @@ -22,7 +22,8 @@ class ConeEquivalentCallConflictResolver( ) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) { override fun chooseMaximallySpecificCandidates( candidates: Set, - discriminateGenerics: Boolean + discriminateGenerics: Boolean, + discriminateAbstracts: Boolean ): Set { return filterOutEquivalentCalls(candidates) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 6527c8ff10e..d2b1ffe3e99 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedReifiedParameterRefe import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.references.impl.FirBackingFieldReferenceImpl import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl @@ -139,7 +140,10 @@ class FirCallResolver( val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) { bestCandidates.toSet() } else { - conflictResolver.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = true) + val onSuperReference = (functionCall.explicitReceiver as? FirQualifiedAccessExpression)?.calleeReference is FirSuperReference + conflictResolver.chooseMaximallySpecificCandidates( + bestCandidates, discriminateGenerics = true, discriminateAbstracts = onSuperReference + ) } return ResolutionResult(info, result.currentApplicability, reducedCandidates) } @@ -176,7 +180,10 @@ class FirCallResolver( val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) { bestCandidates.toSet() } else { - conflictResolver.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false) + val onSuperReference = (qualifiedAccess.explicitReceiver as? FirQualifiedAccessExpression)?.calleeReference is FirSuperReference + conflictResolver.chooseMaximallySpecificCandidates( + bestCandidates, discriminateGenerics = false, discriminateAbstracts = onSuperReference + ) } val nameReference = createResolvedNamedReference( callee, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt index 7d89658c8cf..8ee75da797a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt @@ -13,16 +13,19 @@ import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator abstract class ConeCallConflictResolver { fun chooseMaximallySpecificCandidates( candidates: Collection, - discriminateGenerics: Boolean - ): Set = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics) + discriminateGenerics: Boolean, + discriminateAbstracts: Boolean = false + ): Set = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics, discriminateAbstracts) abstract fun chooseMaximallySpecificCandidates( candidates: Set, - discriminateGenerics: Boolean + discriminateGenerics: Boolean, + discriminateAbstracts: Boolean ): Set } abstract class ConeCallConflictResolverFactory : FirSessionComponent { abstract fun create(typeSpecificityComparator: TypeSpecificityComparator, components: InferenceComponents): ConeCallConflictResolver } + val FirSession.callConflictResolverFactory by componentArrayAccessor() \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt index 5dfa875bebe..f86a3140aa8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt @@ -8,13 +8,17 @@ package org.jetbrains.kotlin.fir.resolve.calls class ConeCompositeConflictResolver( private vararg val conflictResolvers: AbstractConeCallConflictResolver ) : ConeCallConflictResolver() { - override fun chooseMaximallySpecificCandidates(candidates: Set, discriminateGenerics: Boolean): Set { + override fun chooseMaximallySpecificCandidates( + candidates: Set, + discriminateGenerics: Boolean, + discriminateAbstracts: Boolean + ): Set { 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) + currentCandidates = conflictResolver.chooseMaximallySpecificCandidates(candidates, discriminateGenerics, discriminateAbstracts) } return currentCandidates } 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 c503aa9b8f2..52176c7a82e 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 @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.modality import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol @@ -27,14 +30,18 @@ class ConeOverloadConflictResolver( override fun chooseMaximallySpecificCandidates( candidates: Set, - discriminateGenerics: Boolean + discriminateGenerics: Boolean, + discriminateAbstracts: Boolean ): Set { - return chooseMaximallySpecificCandidates(candidates, discriminateGenerics, discriminateSAMs = true) + return chooseMaximallySpecificCandidates( + candidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true + ) } private fun chooseMaximallySpecificCandidates( candidates: Set, discriminateGenerics: Boolean, + discriminateAbstracts: Boolean, discriminateSAMs: Boolean ): Set { findMaximallySpecificCall(candidates, false)?.let { return setOf(it) } @@ -49,7 +56,21 @@ class ConeOverloadConflictResolver( 1 -> return filtered 0, candidates.size -> { } - else -> return chooseMaximallySpecificCandidates(filtered, discriminateGenerics, discriminateSAMs = false) + else -> return chooseMaximallySpecificCandidates( + filtered, discriminateGenerics, discriminateAbstracts, discriminateSAMs = false + ) + } + } + + if (discriminateAbstracts) { + val filtered = candidates.filterTo(mutableSetOf()) { (it.symbol.fir as? FirMemberDeclaration)?.modality != Modality.ABSTRACT } + when (filtered.size) { + 1 -> return filtered + 0, candidates.size -> { + } + else -> return chooseMaximallySpecificCandidates( + filtered, discriminateGenerics, discriminateAbstracts = false, discriminateSAMs = false + ) } } diff --git a/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt b/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt index e2477c919c6..10d7b51de68 100644 --- a/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt +++ b/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt @@ -17,7 +17,7 @@ class C : A, B() { super.bar() // should be ambiguity (NB: really we should have overridden bar in C) - super.baz() // Ok + super.baz() // Ok baz() // Ok } } diff --git a/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.txt b/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.txt index f77b0d9114d..1cf0d2252fd 100644 --- a/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.txt +++ b/compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.txt @@ -29,7 +29,7 @@ FILE: incorrectSuperCall.kt public final override fun foo(): R|kotlin/Unit| { super.R|/B.foo|() super.#() - super.#() + super.R|/B.baz|() this@R|/C|.R|/A.baz|() } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt index db0680cf507..8a0e37f2e25 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt @@ -22,7 +22,7 @@ interface I { class B : A(), I { override val x: Int = 12345 - override val y: Int = super.y + override val y: Int = super.y override fun foo(): Int { super.foo() @@ -30,7 +30,7 @@ class B : A(), I { } override fun bar() { - super.bar() + super.bar() } override fun qux() { diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt index 955cf023a96..48e22295f09 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt @@ -15,7 +15,7 @@ class Test1 : C(), A { // Abstract 'foo' defined in 'C' wins against non-abstract 'foo' defined in 'A', // because 'C' is a subclass of 'A' (and 'C::foo' overrides 'A::foo'), // even though 'A' is explicitly listed in supertypes list for 'D'. - super.foo() + super.foo() } } diff --git a/compiler/testData/ir/irText/classes/implicitNotNullOnDelegatedImplementation.fir.txt b/compiler/testData/ir/irText/classes/implicitNotNullOnDelegatedImplementation.fir.txt index 24eeeaf43f5..ae022cecf03 100644 --- a/compiler/testData/ir/irText/classes/implicitNotNullOnDelegatedImplementation.fir.txt +++ b/compiler/testData/ir/irText/classes/implicitNotNullOnDelegatedImplementation.fir.txt @@ -93,11 +93,12 @@ FILE fqName: fileName:/implicitNotNullOnDelegatedImplementation.kt BLOCK_BODY DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .JUnrelatedFoo' INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:K4 modality:FINAL visibility:public superTypes:[.JUnrelatedFoo; .IFoo]' - FUN name:foo visibility:public modality:FINAL <> ($this:.K4) returnType:IrErrorType + FUN name:foo visibility:public modality:FINAL <> ($this:.K4) returnType:kotlin.String? $this: VALUE_PARAMETER name: type:.K4 BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun foo (): IrErrorType declared in .K4' - ERROR_CALL 'Unresolved reference: #' type=IrErrorType + RETURN type=kotlin.Nothing from='public final fun foo (): kotlin.String? declared in .K4' + CALL 'public open fun foo (): kotlin.String? [operator] declared in .JUnrelatedFoo' type=kotlin.String? origin=null + $this: ERROR_CALL 'Unresolved reference: super' type=IrErrorType FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any