[FIR] Discriminate abstract members when resolving on super
This commit is contained in:
+2
-1
@@ -22,7 +22,8 @@ class ConeEquivalentCallConflictResolver(
|
|||||||
) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) {
|
) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) {
|
||||||
override fun chooseMaximallySpecificCandidates(
|
override fun chooseMaximallySpecificCandidates(
|
||||||
candidates: Set<Candidate>,
|
candidates: Set<Candidate>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
|
discriminateAbstracts: Boolean
|
||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
return filterOutEquivalentCalls(candidates)
|
return filterOutEquivalentCalls(candidates)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirReference
|
import org.jetbrains.kotlin.fir.references.FirReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
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.FirBackingFieldReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
|
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
|
import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
|
||||||
@@ -139,7 +140,10 @@ class FirCallResolver(
|
|||||||
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||||
bestCandidates.toSet()
|
bestCandidates.toSet()
|
||||||
} else {
|
} 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)
|
return ResolutionResult(info, result.currentApplicability, reducedCandidates)
|
||||||
}
|
}
|
||||||
@@ -176,7 +180,10 @@ class FirCallResolver(
|
|||||||
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||||
bestCandidates.toSet()
|
bestCandidates.toSet()
|
||||||
} else {
|
} 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(
|
val nameReference = createResolvedNamedReference(
|
||||||
callee,
|
callee,
|
||||||
|
|||||||
+6
-3
@@ -13,16 +13,19 @@ import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
|||||||
abstract class ConeCallConflictResolver {
|
abstract class ConeCallConflictResolver {
|
||||||
fun chooseMaximallySpecificCandidates(
|
fun chooseMaximallySpecificCandidates(
|
||||||
candidates: Collection<Candidate>,
|
candidates: Collection<Candidate>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
): Set<Candidate> = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics)
|
discriminateAbstracts: Boolean = false
|
||||||
|
): Set<Candidate> = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics, discriminateAbstracts)
|
||||||
|
|
||||||
abstract fun chooseMaximallySpecificCandidates(
|
abstract fun chooseMaximallySpecificCandidates(
|
||||||
candidates: Set<Candidate>,
|
candidates: Set<Candidate>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
|
discriminateAbstracts: Boolean
|
||||||
): Set<Candidate>
|
): Set<Candidate>
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ConeCallConflictResolverFactory : FirSessionComponent {
|
abstract class ConeCallConflictResolverFactory : FirSessionComponent {
|
||||||
abstract fun create(typeSpecificityComparator: TypeSpecificityComparator, components: InferenceComponents): ConeCallConflictResolver
|
abstract fun create(typeSpecificityComparator: TypeSpecificityComparator, components: InferenceComponents): ConeCallConflictResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
val FirSession.callConflictResolverFactory by componentArrayAccessor<ConeCallConflictResolverFactory>()
|
val FirSession.callConflictResolverFactory by componentArrayAccessor<ConeCallConflictResolverFactory>()
|
||||||
+6
-2
@@ -8,13 +8,17 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
|||||||
class ConeCompositeConflictResolver(
|
class ConeCompositeConflictResolver(
|
||||||
private vararg val conflictResolvers: AbstractConeCallConflictResolver
|
private vararg val conflictResolvers: AbstractConeCallConflictResolver
|
||||||
) : ConeCallConflictResolver() {
|
) : ConeCallConflictResolver() {
|
||||||
override fun chooseMaximallySpecificCandidates(candidates: Set<Candidate>, discriminateGenerics: Boolean): Set<Candidate> {
|
override fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Set<Candidate>,
|
||||||
|
discriminateGenerics: Boolean,
|
||||||
|
discriminateAbstracts: Boolean
|
||||||
|
): Set<Candidate> {
|
||||||
if (candidates.size <= 1) return candidates
|
if (candidates.size <= 1) return candidates
|
||||||
var currentCandidates = candidates
|
var currentCandidates = candidates
|
||||||
var index = 0
|
var index = 0
|
||||||
while (currentCandidates.size > 1 && index < conflictResolvers.size) {
|
while (currentCandidates.size > 1 && index < conflictResolvers.size) {
|
||||||
val conflictResolver = conflictResolvers[index++]
|
val conflictResolver = conflictResolvers[index++]
|
||||||
currentCandidates = conflictResolver.chooseMaximallySpecificCandidates(candidates, discriminateGenerics)
|
currentCandidates = conflictResolver.chooseMaximallySpecificCandidates(candidates, discriminateGenerics, discriminateAbstracts)
|
||||||
}
|
}
|
||||||
return currentCandidates
|
return currentCandidates
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-3
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
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.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
|
||||||
@@ -27,14 +30,18 @@ class ConeOverloadConflictResolver(
|
|||||||
|
|
||||||
override fun chooseMaximallySpecificCandidates(
|
override fun chooseMaximallySpecificCandidates(
|
||||||
candidates: Set<Candidate>,
|
candidates: Set<Candidate>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
|
discriminateAbstracts: Boolean
|
||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
return chooseMaximallySpecificCandidates(candidates, discriminateGenerics, discriminateSAMs = true)
|
return chooseMaximallySpecificCandidates(
|
||||||
|
candidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chooseMaximallySpecificCandidates(
|
private fun chooseMaximallySpecificCandidates(
|
||||||
candidates: Set<Candidate>,
|
candidates: Set<Candidate>,
|
||||||
discriminateGenerics: Boolean,
|
discriminateGenerics: Boolean,
|
||||||
|
discriminateAbstracts: Boolean,
|
||||||
discriminateSAMs: Boolean
|
discriminateSAMs: Boolean
|
||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
|
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
|
||||||
@@ -49,7 +56,21 @@ class ConeOverloadConflictResolver(
|
|||||||
1 -> return filtered
|
1 -> return filtered
|
||||||
0, candidates.size -> {
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class C : A, B() {
|
|||||||
|
|
||||||
super.<!AMBIGUITY!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
super.<!AMBIGUITY!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||||
|
|
||||||
super.<!AMBIGUITY!>baz<!>() // Ok
|
super.baz() // Ok
|
||||||
baz() // Ok
|
baz() // Ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ FILE: incorrectSuperCall.kt
|
|||||||
public final override fun foo(): R|kotlin/Unit| {
|
public final override fun foo(): R|kotlin/Unit| {
|
||||||
super<R|A|R|B|>.R|/B.foo|()
|
super<R|A|R|B|>.R|/B.foo|()
|
||||||
super<R|A|R|B|>.<Ambiguity: bar, [/A.bar, /B.bar]>#()
|
super<R|A|R|B|>.<Ambiguity: bar, [/A.bar, /B.bar]>#()
|
||||||
super<R|A|R|B|>.<Ambiguity: baz, [/A.baz, /B.baz]>#()
|
super<R|A|R|B|>.R|/B.baz|()
|
||||||
this@R|/C|.R|/A.baz|()
|
this@R|/C|.R|/A.baz|()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ interface I {
|
|||||||
|
|
||||||
class B : A(), I {
|
class B : A(), I {
|
||||||
override val x: Int = 12345
|
override val x: Int = 12345
|
||||||
override val y: Int = super.<!AMBIGUITY!>y<!>
|
override val y: Int = super.y
|
||||||
|
|
||||||
override fun foo(): Int {
|
override fun foo(): Int {
|
||||||
super.foo()
|
super.foo()
|
||||||
@@ -30,7 +30,7 @@ class B : A(), I {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun bar() {
|
override fun bar() {
|
||||||
super.<!AMBIGUITY!>bar<!>()
|
super.bar()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun qux() {
|
override fun qux() {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ class Test1 : C(), A {
|
|||||||
// Abstract 'foo' defined in 'C' wins against non-abstract 'foo' defined in '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'),
|
// because 'C' is a subclass of 'A' (and 'C::foo' overrides 'A::foo'),
|
||||||
// even though 'A' is explicitly listed in supertypes list for 'D'.
|
// even though 'A' is explicitly listed in supertypes list for 'D'.
|
||||||
super.<!AMBIGUITY!>foo<!>()
|
super.foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -93,11 +93,12 @@ FILE fqName:<root> fileName:/implicitNotNullOnDelegatedImplementation.kt
|
|||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.JUnrelatedFoo'
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.JUnrelatedFoo'
|
||||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:K4 modality:FINAL visibility:public superTypes:[<root>.JUnrelatedFoo; <root>.IFoo]'
|
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:K4 modality:FINAL visibility:public superTypes:[<root>.JUnrelatedFoo; <root>.IFoo]'
|
||||||
FUN name:foo visibility:public modality:FINAL <> ($this:<root>.K4) returnType:IrErrorType
|
FUN name:foo visibility:public modality:FINAL <> ($this:<root>.K4) returnType:kotlin.String?
|
||||||
$this: VALUE_PARAMETER name:<this> type:<root>.K4
|
$this: VALUE_PARAMETER name:<this> type:<root>.K4
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
RETURN type=kotlin.Nothing from='public final fun foo (): IrErrorType declared in <root>.K4'
|
RETURN type=kotlin.Nothing from='public final fun foo (): kotlin.String? declared in <root>.K4'
|
||||||
ERROR_CALL 'Unresolved reference: <Ambiguity: foo, [/JUnrelatedFoo.foo, /IFoo.foo]>#' type=IrErrorType
|
CALL 'public open fun foo (): kotlin.String? [operator] declared in <root>.JUnrelatedFoo' type=kotlin.String? origin=null
|
||||||
|
$this: ERROR_CALL 'Unresolved reference: super<R|JUnrelatedFoo|R|IFoo|>' type=IrErrorType
|
||||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||||
overridden:
|
overridden:
|
||||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
|
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
|
||||||
|
|||||||
Reference in New Issue
Block a user