[FIR] Extract logic of creating intersection overrides into separate class
This commit is contained in:
+21
-26
@@ -21,31 +21,6 @@ abstract class AbstractFirOverrideScope(
|
|||||||
//base symbol as key, overridden as value
|
//base symbol as key, overridden as value
|
||||||
val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>()
|
val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>()
|
||||||
|
|
||||||
private fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean {
|
|
||||||
return overrideChecker.isOverriddenFunction(overrideCandidate, baseDeclaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isOverriddenProperty(overrideCandidate: FirCallableDeclaration, baseDeclaration: FirProperty): Boolean {
|
|
||||||
return overrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun similarFunctionsOrBothProperties(
|
|
||||||
overrideCandidate: FirCallableDeclaration,
|
|
||||||
baseDeclaration: FirCallableDeclaration
|
|
||||||
): Boolean {
|
|
||||||
return when (overrideCandidate) {
|
|
||||||
is FirSimpleFunction -> when (baseDeclaration) {
|
|
||||||
is FirSimpleFunction -> isOverriddenFunction(overrideCandidate, baseDeclaration)
|
|
||||||
is FirProperty -> isOverriddenProperty(overrideCandidate, baseDeclaration)
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
is FirConstructor -> false
|
|
||||||
is FirProperty -> baseDeclaration is FirProperty && isOverriddenProperty(overrideCandidate, baseDeclaration)
|
|
||||||
is FirField -> baseDeclaration is FirField
|
|
||||||
else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receiver is super-type function here
|
// Receiver is super-type function here
|
||||||
protected open fun FirCallableSymbol<*>.getOverridden(overrideCandidates: Set<FirCallableSymbol<*>>): FirCallableSymbol<*>? {
|
protected open fun FirCallableSymbol<*>.getOverridden(overrideCandidates: Set<FirCallableSymbol<*>>): FirCallableSymbol<*>? {
|
||||||
val overrideByBaseItem = overrideByBase[this]
|
val overrideByBaseItem = overrideByBase[this]
|
||||||
@@ -54,10 +29,30 @@ abstract class AbstractFirOverrideScope(
|
|||||||
val baseDeclaration = (this as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
val baseDeclaration = (this as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
||||||
val override = overrideCandidates.firstOrNull {
|
val override = overrideCandidates.firstOrNull {
|
||||||
val overrideCandidate = (it as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
val overrideCandidate = (it as FirBasedSymbol<*>).fir as FirCallableDeclaration
|
||||||
baseDeclaration.modality != Modality.FINAL && similarFunctionsOrBothProperties(overrideCandidate, baseDeclaration)
|
baseDeclaration.modality != Modality.FINAL && overrideChecker.similarFunctionsOrBothProperties(
|
||||||
|
overrideCandidate,
|
||||||
|
baseDeclaration
|
||||||
|
)
|
||||||
} // TODO: two or more overrides for one fun?
|
} // TODO: two or more overrides for one fun?
|
||||||
overrideByBase[this] = override
|
overrideByBase[this] = override
|
||||||
return override
|
return override
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun FirOverrideChecker.similarFunctionsOrBothProperties(
|
||||||
|
overrideCandidate: FirCallableDeclaration,
|
||||||
|
baseDeclaration: FirCallableDeclaration
|
||||||
|
): Boolean {
|
||||||
|
return when (overrideCandidate) {
|
||||||
|
is FirSimpleFunction -> when (baseDeclaration) {
|
||||||
|
is FirSimpleFunction -> isOverriddenFunction(overrideCandidate, baseDeclaration)
|
||||||
|
is FirProperty -> isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
is FirConstructor -> false
|
||||||
|
is FirProperty -> baseDeclaration is FirProperty && isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||||
|
is FirField -> baseDeclaration is FirField
|
||||||
|
else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+20
-482
@@ -5,57 +5,40 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.scopes.impl
|
package org.jetbrains.kotlin.fir.scopes.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
|
||||||
import org.jetbrains.kotlin.fir.*
|
|
||||||
import org.jetbrains.kotlin.fir.caches.*
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.scopes.*
|
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
|
|
||||||
class FirTypeIntersectionScope private constructor(
|
class FirTypeIntersectionScope private constructor(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
overrideChecker: FirOverrideChecker,
|
overrideChecker: FirOverrideChecker,
|
||||||
private val scopes: List<FirTypeScope>,
|
private val scopes: List<FirTypeScope>,
|
||||||
private val dispatchReceiverType: ConeSimpleKotlinType,
|
dispatchReceiverType: ConeSimpleKotlinType,
|
||||||
) : AbstractFirOverrideScope(session, overrideChecker) {
|
) : AbstractFirOverrideScope(session, overrideChecker) {
|
||||||
|
private val intersectionContext = FirTypeIntersectionScopeContext(session, overrideChecker, scopes, dispatchReceiverType)
|
||||||
|
|
||||||
private val absentFunctions: MutableSet<Name> = mutableSetOf()
|
private val absentFunctions: MutableSet<Name> = mutableSetOf()
|
||||||
private val absentProperties: MutableSet<Name> = mutableSetOf()
|
private val absentProperties: MutableSet<Name> = mutableSetOf()
|
||||||
private val absentClassifiers: MutableSet<Name> = mutableSetOf()
|
private val absentClassifiers: MutableSet<Name> = mutableSetOf()
|
||||||
|
|
||||||
private val typeCheckerState = session.typeContext.newTypeCheckerState(
|
|
||||||
errorTypesEqualToAnything = false,
|
|
||||||
stubTypesEqualToAnything = false
|
|
||||||
)
|
|
||||||
|
|
||||||
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf()
|
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf()
|
||||||
|
|
||||||
private val intersectionOverrides =
|
|
||||||
session.intersectionOverrideStorage.cacheByScope.getValue(dispatchReceiverType).intersectionOverrides
|
|
||||||
|
|
||||||
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() }
|
scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||||
if (!processCallablesByName(name, processor, absentFunctions, FirScope::processFunctionsByName)) {
|
processCallablesByName(name, processor, absentFunctions, FirScope::processFunctionsByName)
|
||||||
super.processFunctionsByName(name, processor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||||
if (!processCallablesByName(name, processor, absentProperties, FirScope::processPropertiesByName)) {
|
processCallablesByName(name, processor, absentProperties, FirScope::processPropertiesByName)
|
||||||
super.processPropertiesByName(name, processor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
|
private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
|
||||||
@@ -63,429 +46,22 @@ class FirTypeIntersectionScope private constructor(
|
|||||||
noinline processor: (D) -> Unit,
|
noinline processor: (D) -> Unit,
|
||||||
absentNames: MutableSet<Name>,
|
absentNames: MutableSet<Name>,
|
||||||
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
|
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
|
||||||
): Boolean {
|
|
||||||
if (name in absentNames) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val membersByScope = scopes.mapNotNull { scope ->
|
|
||||||
val resultForScope = mutableListOf<D>()
|
|
||||||
scope.processCallables(name) {
|
|
||||||
if (it !is FirConstructorSymbol) {
|
|
||||||
resultForScope.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultForScope.takeIf { it.isNotEmpty() }?.let {
|
|
||||||
scope to it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (membersByScope.isEmpty()) {
|
|
||||||
absentNames.add(name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
membersByScope.singleOrNull()?.let { (scope, members) ->
|
|
||||||
for (member in members) {
|
|
||||||
overriddenSymbols[member] = listOf(MemberWithBaseScope(member, scope))
|
|
||||||
processor(member)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val allMembersWithScope = membersByScope.flatMapTo(linkedSetOf()) { (scope, members) ->
|
|
||||||
members.map { MemberWithBaseScope(it, scope) }
|
|
||||||
}
|
|
||||||
|
|
||||||
while (allMembersWithScope.size > 1) {
|
|
||||||
val maxByVisibility = findMemberWithMaxVisibility(allMembersWithScope)
|
|
||||||
val extractBothWaysWithPrivate = extractBothWaysOverridable(maxByVisibility, allMembersWithScope)
|
|
||||||
val extractedOverrides = extractBothWaysWithPrivate.filterNot {
|
|
||||||
Visibilities.isPrivate((it.member.fir as FirMemberDeclaration).visibility)
|
|
||||||
}.takeIf { it.isNotEmpty() } ?: extractBothWaysWithPrivate
|
|
||||||
val baseMembersForIntersection = extractedOverrides.calcBaseMembersForIntersectionOverride()
|
|
||||||
if (baseMembersForIntersection.size > 1) {
|
|
||||||
val (mostSpecific, scopeForMostSpecific) = selectMostSpecificMember(baseMembersForIntersection)
|
|
||||||
val intersectionOverride = intersectionOverrides.getValue(
|
|
||||||
mostSpecific,
|
|
||||||
FirIntersectionOverrideStorage.ContextForIntersectionOverrideConstruction(
|
|
||||||
this,
|
|
||||||
baseMembersForIntersection,
|
|
||||||
scopeForMostSpecific
|
|
||||||
)
|
|
||||||
)
|
|
||||||
overriddenSymbols[intersectionOverride.member] = extractedOverrides
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
processor(intersectionOverride.member as D)
|
|
||||||
} else {
|
|
||||||
val mostSpecific = baseMembersForIntersection.single().member
|
|
||||||
overriddenSymbols[mostSpecific] = extractedOverrides
|
|
||||||
processor(mostSpecific)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allMembersWithScope.isNotEmpty()) {
|
|
||||||
val single = allMembersWithScope.single().member
|
|
||||||
overriddenSymbols[single] = allMembersWithScope.toList()
|
|
||||||
processor(single)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified D : FirCallableDeclaration> D.unwrapSubstitutionOverrides(): D {
|
|
||||||
var current = this
|
|
||||||
|
|
||||||
do {
|
|
||||||
val next = current.originalForSubstitutionOverride ?: return current
|
|
||||||
current = next
|
|
||||||
} while (true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <D : FirCallableSymbol<*>> createIntersectionOverride(
|
|
||||||
extractedOverrides: List<MemberWithBaseScope<D>>,
|
|
||||||
mostSpecific: D,
|
|
||||||
scopeForMostSpecific: FirTypeScope
|
|
||||||
): MemberWithBaseScope<FirCallableSymbol<*>> {
|
|
||||||
val newModality = chooseIntersectionOverrideModality(extractedOverrides)
|
|
||||||
val newVisibility = chooseIntersectionVisibility(extractedOverrides)
|
|
||||||
val extractedOverridesSymbols = extractedOverrides.map { it.member }
|
|
||||||
return when (mostSpecific) {
|
|
||||||
is FirNamedFunctionSymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
|
||||||
is FirPropertySymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
|
||||||
else -> throw IllegalStateException("Should not be here")
|
|
||||||
}.withScope(scopeForMostSpecific)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <S : FirCallableSymbol<*>> List<MemberWithBaseScope<S>>.calcBaseMembersForIntersectionOverride(): List<MemberWithBaseScope<S>> {
|
|
||||||
if (size == 1) return this
|
|
||||||
val unwrappedMemberSet = mutableSetOf<MemberWithBaseScope<S>>()
|
|
||||||
for ((member, scope) in this) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
unwrappedMemberSet += MemberWithBaseScope(member.fir.unwrapSubstitutionOverrides().symbol as S, scope)
|
|
||||||
}
|
|
||||||
// If in fact extracted overrides are the same symbols,
|
|
||||||
// we should just take most specific member without creating intersection
|
|
||||||
// A typical sample here is inheritance of the same class in different places of hierarchy
|
|
||||||
if (unwrappedMemberSet.size == 1) {
|
|
||||||
return listOf(selectMostSpecificMember(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
val baseMembers = mutableSetOf<S>()
|
|
||||||
for ((member, scope) in this) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
if (member is FirNamedFunctionSymbol) {
|
|
||||||
scope.processOverriddenFunctions(member) {
|
|
||||||
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
|
||||||
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
|
||||||
baseMembers += symbol as S
|
|
||||||
}
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
} else if (member is FirPropertySymbol) {
|
|
||||||
scope.processOverriddenProperties(member) {
|
|
||||||
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
|
||||||
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
|
||||||
baseMembers += symbol as S
|
|
||||||
}
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filterNot { (member, _) -> member.fir.unwrapSubstitutionOverrides().symbol in baseMembers }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> chooseIntersectionOverrideModality(
|
|
||||||
extractedOverridden: Collection<MemberWithBaseScope<D>>
|
|
||||||
): Modality? {
|
|
||||||
var hasOpen = false
|
|
||||||
var hasAbstract = false
|
|
||||||
|
|
||||||
for ((member) in extractedOverridden) {
|
|
||||||
when ((member.fir as FirMemberDeclaration).modality) {
|
|
||||||
Modality.FINAL -> return Modality.FINAL
|
|
||||||
Modality.SEALED -> {
|
|
||||||
// Members should not be sealed. But, that will be reported as WRONG_MODIFIER_TARGET, and here we shouldn't raise an
|
|
||||||
// internal error. Instead, let the intersection override have the default modality: null.
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
Modality.OPEN -> {
|
|
||||||
hasOpen = true
|
|
||||||
}
|
|
||||||
Modality.ABSTRACT -> {
|
|
||||||
hasAbstract = true
|
|
||||||
}
|
|
||||||
null -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAbstract && !hasOpen) return Modality.ABSTRACT
|
|
||||||
if (!hasAbstract && hasOpen) return Modality.OPEN
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val processDirectOverridden: ProcessOverriddenWithBaseScope<D> = when (extractedOverridden.first().member) {
|
|
||||||
is FirNamedFunctionSymbol -> FirTypeScope::processDirectOverriddenFunctionsWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
|
||||||
is FirPropertySymbol -> FirTypeScope::processDirectOverriddenPropertiesWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
|
||||||
else -> error("Unexpected callable kind: ${extractedOverridden.first().member}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val realOverridden = extractedOverridden.flatMap { realOverridden(it.member, it.baseScope, processDirectOverridden) }
|
|
||||||
val filteredOverridden = filterOutOverridden(realOverridden, processDirectOverridden)
|
|
||||||
|
|
||||||
return filteredOverridden.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> realOverridden(
|
|
||||||
symbol: D,
|
|
||||||
scope: FirTypeScope,
|
|
||||||
processDirectOverridden: ProcessOverriddenWithBaseScope<D>,
|
|
||||||
): Collection<MemberWithBaseScope<D>> {
|
|
||||||
val result = mutableSetOf<MemberWithBaseScope<D>>()
|
|
||||||
|
|
||||||
collectRealOverridden(symbol, scope, result, mutableSetOf(), processDirectOverridden)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> collectRealOverridden(
|
|
||||||
symbol: D,
|
|
||||||
scope: FirTypeScope,
|
|
||||||
result: MutableCollection<MemberWithBaseScope<D>>,
|
|
||||||
visited: MutableSet<D>,
|
|
||||||
processDirectOverridden: FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction,
|
|
||||||
) {
|
) {
|
||||||
if (!visited.add(symbol)) return
|
if (name in absentNames) {
|
||||||
if (!symbol.fir.origin.fromSupertypes) {
|
|
||||||
result.add(MemberWithBaseScope(symbol, scope))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.processDirectOverridden(symbol) { overridden, baseScope ->
|
val callablesWithOverridden = intersectionContext.collectCallables(name, processCallables)
|
||||||
collectRealOverridden(overridden, baseScope, result, visited, processDirectOverridden)
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (callablesWithOverridden.isEmpty()) {
|
||||||
private fun <D : FirCallableSymbol<*>> filterOutOverridden(
|
absentNames.add(name)
|
||||||
extractedOverridden: Collection<MemberWithBaseScope<D>>,
|
return
|
||||||
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
|
||||||
): Collection<MemberWithBaseScope<D>> {
|
|
||||||
return extractedOverridden.filter { overridden1 ->
|
|
||||||
extractedOverridden.none { overridden2 ->
|
|
||||||
overridden1 !== overridden2 && overrides(
|
|
||||||
overridden2,
|
|
||||||
overridden1,
|
|
||||||
processAllOverridden
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether f overrides g
|
|
||||||
private fun <D : FirCallableSymbol<*>> overrides(
|
|
||||||
f: MemberWithBaseScope<D>,
|
|
||||||
g: MemberWithBaseScope<D>,
|
|
||||||
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
|
||||||
): Boolean {
|
|
||||||
val (fMember, fScope) = f
|
|
||||||
val (gMember) = g
|
|
||||||
|
|
||||||
var result = false
|
|
||||||
|
|
||||||
fScope.processAllOverridden(fMember) { overridden, _ ->
|
|
||||||
if (overridden == gMember) {
|
|
||||||
result = true
|
|
||||||
ProcessorAction.STOP
|
|
||||||
} else {
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
for ((chosenSymbol, overriddenMembers) in callablesWithOverridden) {
|
||||||
}
|
overriddenSymbols[chosenSymbol] = overriddenMembers
|
||||||
|
processor(chosenSymbol)
|
||||||
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
|
||||||
extractedOverrides: Collection<MemberWithBaseScope<D>>
|
|
||||||
): Visibility {
|
|
||||||
var maxVisibility: Visibility = Visibilities.Private
|
|
||||||
for ((override) in extractedOverrides) {
|
|
||||||
val visibility = (override.fir as FirMemberDeclaration).visibility
|
|
||||||
// TODO: There is more complex logic at org.jetbrains.kotlin.resolve.OverridingUtil.resolveUnknownVisibilityForMember
|
|
||||||
// TODO: and org.jetbrains.kotlin.resolve.OverridingUtil.findMaxVisibility
|
|
||||||
val compare = Visibilities.compare(visibility, maxVisibility) ?: return Visibilities.DEFAULT_VISIBILITY
|
|
||||||
if (compare > 0) {
|
|
||||||
maxVisibility = visibility
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return maxVisibility
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createIntersectionOverride(
|
|
||||||
mostSpecific: FirNamedFunctionSymbol,
|
|
||||||
overrides: Collection<FirCallableSymbol<*>>,
|
|
||||||
newModality: Modality?,
|
|
||||||
newVisibility: Visibility,
|
|
||||||
): FirNamedFunctionSymbol {
|
|
||||||
|
|
||||||
val newSymbol =
|
|
||||||
FirIntersectionOverrideFunctionSymbol(
|
|
||||||
CallableId(
|
|
||||||
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
|
||||||
mostSpecific.fir.name
|
|
||||||
),
|
|
||||||
overrides
|
|
||||||
)
|
|
||||||
val mostSpecificFunction = mostSpecific.fir
|
|
||||||
FirFakeOverrideGenerator.createCopyForFirFunction(
|
|
||||||
newSymbol,
|
|
||||||
mostSpecificFunction, session, FirDeclarationOrigin.IntersectionOverride,
|
|
||||||
mostSpecificFunction.isExpect,
|
|
||||||
newDispatchReceiverType = dispatchReceiverType,
|
|
||||||
newModality = newModality,
|
|
||||||
newVisibility = newVisibility,
|
|
||||||
).apply {
|
|
||||||
originalForIntersectionOverrideAttr = mostSpecific.fir
|
|
||||||
}
|
|
||||||
return newSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createIntersectionOverride(
|
|
||||||
mostSpecific: FirPropertySymbol,
|
|
||||||
overrides: Collection<FirCallableSymbol<*>>,
|
|
||||||
newModality: Modality?,
|
|
||||||
newVisibility: Visibility,
|
|
||||||
): FirPropertySymbol {
|
|
||||||
val callableId = CallableId(
|
|
||||||
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
|
||||||
mostSpecific.fir.name
|
|
||||||
)
|
|
||||||
val newSymbol = FirIntersectionOverridePropertySymbol(callableId, overrides)
|
|
||||||
val mostSpecificProperty = mostSpecific.fir
|
|
||||||
FirFakeOverrideGenerator.createCopyForFirProperty(
|
|
||||||
newSymbol, mostSpecificProperty, session, FirDeclarationOrigin.IntersectionOverride,
|
|
||||||
newModality = newModality,
|
|
||||||
newVisibility = newVisibility,
|
|
||||||
newDispatchReceiverType = dispatchReceiverType,
|
|
||||||
).apply {
|
|
||||||
originalForIntersectionOverrideAttr = mostSpecific.fir
|
|
||||||
}
|
|
||||||
return newSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> selectMostSpecificMember(overridables: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
|
||||||
require(overridables.isNotEmpty()) { "Should have at least one overridable symbol" }
|
|
||||||
if (overridables.size == 1) {
|
|
||||||
return overridables.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
val candidates: MutableCollection<MemberWithBaseScope<D>> = ArrayList(2)
|
|
||||||
var transitivelyMostSpecific: MemberWithBaseScope<D> = overridables.first()
|
|
||||||
|
|
||||||
for (candidate in overridables) {
|
|
||||||
if (overridables.all { hasMoreSpecificOrSameSignature(candidate.member, it.member) }) {
|
|
||||||
candidates.add(candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasMoreSpecificOrSameSignature(candidate.member, transitivelyMostSpecific.member) &&
|
|
||||||
!hasMoreSpecificOrSameSignature(transitivelyMostSpecific.member, candidate.member)
|
|
||||||
) {
|
|
||||||
transitivelyMostSpecific = candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
|
||||||
candidates.isEmpty() -> transitivelyMostSpecific
|
|
||||||
candidates.size == 1 -> candidates.first()
|
|
||||||
else -> {
|
|
||||||
candidates.firstOrNull {
|
|
||||||
val type = it.member.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
|
||||||
type != null && type !is ConeFlexibleType
|
|
||||||
}?.let { return it }
|
|
||||||
candidates.first()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasMoreSpecificOrSameSignature(
|
|
||||||
a: FirCallableSymbol<*>,
|
|
||||||
b: FirCallableSymbol<*>
|
|
||||||
): Boolean {
|
|
||||||
if (a === b) return true
|
|
||||||
val aFir = a.fir
|
|
||||||
val bFir = b.fir
|
|
||||||
|
|
||||||
val substitutor = buildSubstitutorForOverridesCheck(aFir, bFir, session) ?: return false
|
|
||||||
// NB: these lines throw CCE in modularized tests when changed to just .coneType (FirImplicitTypeRef)
|
|
||||||
val aReturnType = a.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.let(substitutor::substituteOrSelf) ?: return false
|
|
||||||
val bReturnType = b.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return false
|
|
||||||
|
|
||||||
if (aFir is FirSimpleFunction) {
|
|
||||||
require(bFir is FirSimpleFunction) { "b is " + b.javaClass }
|
|
||||||
return isTypeMoreSpecificOrSame(aReturnType, bReturnType)
|
|
||||||
}
|
|
||||||
if (aFir is FirProperty) {
|
|
||||||
require(bFir is FirProperty) { "b is " + b.javaClass }
|
|
||||||
// TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false
|
|
||||||
return if (aFir.isVar && bFir.isVar) {
|
|
||||||
AbstractTypeChecker.equalTypes(typeCheckerState, aReturnType, bReturnType)
|
|
||||||
} else { // both vals or var vs val: val can't be more specific then var
|
|
||||||
!(!aFir.isVar && bFir.isVar) && isTypeMoreSpecificOrSame(aReturnType, bReturnType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw IllegalArgumentException("Unexpected callable: " + a.javaClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isTypeMoreSpecificOrSame(a: ConeKotlinType, b: ConeKotlinType): Boolean =
|
|
||||||
AbstractTypeChecker.isSubtypeOf(typeCheckerState, a, b)
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> findMemberWithMaxVisibility(members: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
|
||||||
assert(members.isNotEmpty())
|
|
||||||
|
|
||||||
var member: MemberWithBaseScope<D>? = null
|
|
||||||
for (candidate in members) {
|
|
||||||
if (member == null) {
|
|
||||||
member = candidate
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = Visibilities.compare(
|
|
||||||
member.member.fir.status.visibility,
|
|
||||||
candidate.member.fir.status.visibility
|
|
||||||
)
|
|
||||||
if (result != null && result < 0) {
|
|
||||||
member = candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return member!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> extractBothWaysOverridable(
|
|
||||||
overrider: MemberWithBaseScope<D>,
|
|
||||||
members: MutableCollection<MemberWithBaseScope<D>>
|
|
||||||
): List<MemberWithBaseScope<D>> {
|
|
||||||
val result = mutableListOf<MemberWithBaseScope<D>>().apply { add(overrider) }
|
|
||||||
|
|
||||||
val iterator = members.iterator()
|
|
||||||
|
|
||||||
val overrideCandidate = overrider.member.fir
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val next = iterator.next()
|
|
||||||
if (next == overrider) {
|
|
||||||
iterator.remove()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (similarFunctionsOrBothProperties(overrideCandidate, next.member.fir)) {
|
|
||||||
result.add(next)
|
|
||||||
iterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||||
@@ -514,7 +90,7 @@ class FirTypeIntersectionScope private constructor(
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <S : FirCallableSymbol<*>> getDirectOverriddenSymbols(symbol: S): Collection<MemberWithBaseScope<S>> {
|
fun <S : FirCallableSymbol<*>> getDirectOverriddenSymbols(symbol: S): Collection<MemberWithBaseScope<S>> {
|
||||||
val intersectionOverride = intersectionOverrides.getValueIfComputed(symbol)
|
val intersectionOverride = intersectionContext.intersectionOverrides.getValueIfComputed(symbol)
|
||||||
val allDirectOverridden = overriddenSymbols[symbol].orEmpty() + intersectionOverride?.let {
|
val allDirectOverridden = overriddenSymbols[symbol].orEmpty() + intersectionOverride?.let {
|
||||||
overriddenSymbols[it.member]
|
overriddenSymbols[it.member]
|
||||||
}.orEmpty()
|
}.orEmpty()
|
||||||
@@ -576,41 +152,3 @@ class FirTypeIntersectionScope private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope) {
|
|
||||||
operator fun component1() = member
|
|
||||||
operator fun component2() = baseScope
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
return other is MemberWithBaseScope<*> && member == other.member
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return member.hashCode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : FirCallableSymbol<*>> D.withScope(baseScope: FirTypeScope) = MemberWithBaseScope(this, baseScope)
|
|
||||||
|
|
||||||
class FirIntersectionOverrideStorage(val session: FirSession) : FirSessionComponent {
|
|
||||||
private val cachesFactory = session.firCachesFactory
|
|
||||||
|
|
||||||
class CacheForScope(cachesFactory: FirCachesFactory) {
|
|
||||||
val intersectionOverrides: FirCache<FirCallableSymbol<*>, MemberWithBaseScope<FirCallableSymbol<*>>, ContextForIntersectionOverrideConstruction<*>> =
|
|
||||||
cachesFactory.createCache { mostSpecific, context ->
|
|
||||||
val (intersectionScope, extractedOverrides, scopeForMostSpecific) = context
|
|
||||||
intersectionScope.createIntersectionOverride(extractedOverrides, mostSpecific, scopeForMostSpecific)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ContextForIntersectionOverrideConstruction<D : FirCallableSymbol<*>>(
|
|
||||||
val intersectionScope: FirTypeIntersectionScope,
|
|
||||||
val extractedOverrides: List<MemberWithBaseScope<D>>,
|
|
||||||
val scopeForMostSpecific: FirTypeScope
|
|
||||||
)
|
|
||||||
|
|
||||||
val cacheByScope: FirCache<ConeKotlinType, CacheForScope, Nothing?> =
|
|
||||||
cachesFactory.createCache { _ -> CacheForScope(cachesFactory) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val FirSession.intersectionOverrideStorage: FirIntersectionOverrideStorage by FirSession.sessionComponentAccessor()
|
|
||||||
|
|||||||
+512
@@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.scopes.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.fir.*
|
||||||
|
import org.jetbrains.kotlin.fir.caches.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntersectionOverrideStorage.ContextForIntersectionOverrideConstruction
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
|
||||||
|
class FirTypeIntersectionScopeContext(
|
||||||
|
val session: FirSession,
|
||||||
|
private val overrideChecker: FirOverrideChecker,
|
||||||
|
@property:PrivateForInline val scopes: List<FirTypeScope>,
|
||||||
|
private val dispatchReceiverType: ConeSimpleKotlinType,
|
||||||
|
) {
|
||||||
|
private val typeCheckerState = session.typeContext.newTypeCheckerState(
|
||||||
|
errorTypesEqualToAnything = false,
|
||||||
|
stubTypesEqualToAnything = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val intersectionOverrides: FirCache<FirCallableSymbol<*>, MemberWithBaseScope<FirCallableSymbol<*>>, ContextForIntersectionOverrideConstruction<*>> =
|
||||||
|
session.intersectionOverrideStorage.cacheByScope.getValue(dispatchReceiverType).intersectionOverrides
|
||||||
|
|
||||||
|
data class ResultOfIntersection<D : FirCallableSymbol<*>>(
|
||||||
|
val chosenSymbol: D,
|
||||||
|
val overriddenMembers: List<MemberWithBaseScope<D>>
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
chosenSymbol: D,
|
||||||
|
overriddenMember: MemberWithBaseScope<D>
|
||||||
|
) : this(chosenSymbol, listOf(overriddenMember))
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(PrivateForInline::class)
|
||||||
|
inline fun <D : FirCallableSymbol<*>> collectCallables(
|
||||||
|
name: Name,
|
||||||
|
processCallables: FirScope.(Name, (D) -> Unit) -> Unit
|
||||||
|
): List<ResultOfIntersection<D>> {
|
||||||
|
val membersByScope = scopes.mapNotNull { scope ->
|
||||||
|
val resultForScope = mutableListOf<D>()
|
||||||
|
scope.processCallables(name) {
|
||||||
|
if (it !is FirConstructorSymbol) {
|
||||||
|
resultForScope.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultForScope.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
scope to it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collectCallablesImpl(membersByScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrivateForInline
|
||||||
|
fun <D : FirCallableSymbol<*>> collectCallablesImpl(
|
||||||
|
membersByScope: List<Pair<FirTypeScope, MutableList<D>>>
|
||||||
|
): List<ResultOfIntersection<D>> {
|
||||||
|
if (membersByScope.isEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
membersByScope.singleOrNull()?.let { (scope, members) ->
|
||||||
|
return members.map { ResultOfIntersection(it, MemberWithBaseScope(it, scope)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val allMembersWithScope = membersByScope.flatMapTo(linkedSetOf()) { (scope, members) ->
|
||||||
|
members.map { MemberWithBaseScope(it, scope) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = mutableListOf<ResultOfIntersection<D>>()
|
||||||
|
|
||||||
|
while (allMembersWithScope.size > 1) {
|
||||||
|
val maxByVisibility = findMemberWithMaxVisibility(allMembersWithScope)
|
||||||
|
val extractBothWaysWithPrivate = extractBothWaysOverridable(maxByVisibility, allMembersWithScope)
|
||||||
|
val extractedOverrides = extractBothWaysWithPrivate.filterNotTo(mutableListOf()) {
|
||||||
|
Visibilities.isPrivate((it.member.fir as FirMemberDeclaration).visibility)
|
||||||
|
}.takeIf { it.isNotEmpty() } ?: extractBothWaysWithPrivate
|
||||||
|
val baseMembersForIntersection = extractedOverrides.calcBaseMembersForIntersectionOverride()
|
||||||
|
if (baseMembersForIntersection.size > 1) {
|
||||||
|
val (mostSpecific, scopeForMostSpecific) = selectMostSpecificMember(baseMembersForIntersection)
|
||||||
|
val intersectionOverride = intersectionOverrides.getValue(
|
||||||
|
mostSpecific,
|
||||||
|
ContextForIntersectionOverrideConstruction(
|
||||||
|
this,
|
||||||
|
extractedOverrides,
|
||||||
|
scopeForMostSpecific
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
result += ResultOfIntersection(intersectionOverride.member as D, extractedOverrides)
|
||||||
|
} else {
|
||||||
|
val mostSpecific = baseMembersForIntersection.single().member
|
||||||
|
result += ResultOfIntersection(mostSpecific, extractedOverrides)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allMembersWithScope.isNotEmpty()) {
|
||||||
|
val single = allMembersWithScope.single().member
|
||||||
|
result += ResultOfIntersection(single, allMembersWithScope.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <D : FirCallableSymbol<*>> createIntersectionOverride(
|
||||||
|
extractedOverrides: List<MemberWithBaseScope<D>>,
|
||||||
|
mostSpecific: D,
|
||||||
|
scopeForMostSpecific: FirTypeScope
|
||||||
|
): MemberWithBaseScope<FirCallableSymbol<*>> {
|
||||||
|
val newModality = chooseIntersectionOverrideModality(extractedOverrides)
|
||||||
|
val newVisibility = chooseIntersectionVisibility(extractedOverrides)
|
||||||
|
val extractedOverridesSymbols = extractedOverrides.map { it.member }
|
||||||
|
return when (mostSpecific) {
|
||||||
|
is FirNamedFunctionSymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
||||||
|
is FirPropertySymbol -> createIntersectionOverride(mostSpecific, extractedOverridesSymbols, newModality, newVisibility)
|
||||||
|
else -> throw IllegalStateException("Should not be here")
|
||||||
|
}.withScope(scopeForMostSpecific)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <S : FirCallableSymbol<*>> List<MemberWithBaseScope<S>>.calcBaseMembersForIntersectionOverride(): List<MemberWithBaseScope<S>> {
|
||||||
|
if (size == 1) return this
|
||||||
|
val unwrappedMemberSet = mutableSetOf<MemberWithBaseScope<S>>()
|
||||||
|
for ((member, scope) in this) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
unwrappedMemberSet += MemberWithBaseScope(member.fir.unwrapSubstitutionOverrides().symbol as S, scope)
|
||||||
|
}
|
||||||
|
// If in fact extracted overrides are the same symbols,
|
||||||
|
// we should just take most specific member without creating intersection
|
||||||
|
// A typical sample here is inheritance of the same class in different places of hierarchy
|
||||||
|
if (unwrappedMemberSet.size == 1) {
|
||||||
|
return listOf(selectMostSpecificMember(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
val baseMembers = mutableSetOf<S>()
|
||||||
|
for ((member, scope) in this) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
if (member is FirNamedFunctionSymbol) {
|
||||||
|
scope.processOverriddenFunctions(member) {
|
||||||
|
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
||||||
|
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
||||||
|
baseMembers += symbol as S
|
||||||
|
}
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
} else if (member is FirPropertySymbol) {
|
||||||
|
scope.processOverriddenProperties(member) {
|
||||||
|
val symbol = it.fir.unwrapSubstitutionOverrides().symbol
|
||||||
|
if (symbol != member.fir.unwrapSubstitutionOverrides().symbol) {
|
||||||
|
baseMembers += symbol as S
|
||||||
|
}
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val result = this.toMutableList()
|
||||||
|
result.removeIf { (member, _) -> member.fir.unwrapSubstitutionOverrides().symbol in baseMembers }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> selectMostSpecificMember(overridables: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
||||||
|
require(overridables.isNotEmpty()) { "Should have at least one overridable symbol" }
|
||||||
|
if (overridables.size == 1) {
|
||||||
|
return overridables.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates: MutableCollection<MemberWithBaseScope<D>> = ArrayList(2)
|
||||||
|
var transitivelyMostSpecific: MemberWithBaseScope<D> = overridables.first()
|
||||||
|
|
||||||
|
for (candidate in overridables) {
|
||||||
|
if (overridables.all { isMoreSpecific(candidate.member, it.member) }) {
|
||||||
|
candidates.add(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMoreSpecific(candidate.member, transitivelyMostSpecific.member) &&
|
||||||
|
!isMoreSpecific(transitivelyMostSpecific.member, candidate.member)
|
||||||
|
) {
|
||||||
|
transitivelyMostSpecific = candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
candidates.isEmpty() -> transitivelyMostSpecific
|
||||||
|
candidates.size == 1 -> candidates.first()
|
||||||
|
else -> {
|
||||||
|
candidates.firstOrNull {
|
||||||
|
val type = it.member.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
|
type != null && type !is ConeFlexibleType
|
||||||
|
}?.let { return it }
|
||||||
|
candidates.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isMoreSpecific(
|
||||||
|
a: FirCallableSymbol<*>,
|
||||||
|
b: FirCallableSymbol<*>
|
||||||
|
): Boolean {
|
||||||
|
val aFir = a.fir
|
||||||
|
val bFir = b.fir
|
||||||
|
|
||||||
|
val substitutor = buildSubstitutorForOverridesCheck(aFir, bFir, session) ?: return false
|
||||||
|
// NB: these lines throw CCE in modularized tests when changed to just .coneType (FirImplicitTypeRef)
|
||||||
|
val aReturnType = a.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.let(substitutor::substituteOrSelf) ?: return false
|
||||||
|
val bReturnType = b.fir.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return false
|
||||||
|
|
||||||
|
if (aFir is FirSimpleFunction) {
|
||||||
|
require(bFir is FirSimpleFunction) { "b is " + b.javaClass }
|
||||||
|
return isTypeMoreSpecific(aReturnType, bReturnType)
|
||||||
|
}
|
||||||
|
if (aFir is FirProperty) {
|
||||||
|
require(bFir is FirProperty) { "b is " + b.javaClass }
|
||||||
|
// TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false
|
||||||
|
return if (aFir.isVar && bFir.isVar) {
|
||||||
|
AbstractTypeChecker.equalTypes(typeCheckerState, aReturnType, bReturnType)
|
||||||
|
} else { // both vals or var vs val: val can't be more specific then var
|
||||||
|
!(!aFir.isVar && bFir.isVar) && isTypeMoreSpecific(aReturnType, bReturnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Unexpected callable: " + a.javaClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isTypeMoreSpecific(a: ConeKotlinType, b: ConeKotlinType): Boolean =
|
||||||
|
AbstractTypeChecker.isSubtypeOf(typeCheckerState, a, b)
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> findMemberWithMaxVisibility(members: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
|
||||||
|
assert(members.isNotEmpty())
|
||||||
|
|
||||||
|
var member: MemberWithBaseScope<D>? = null
|
||||||
|
for (candidate in members) {
|
||||||
|
if (member == null) {
|
||||||
|
member = candidate
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = Visibilities.compare(
|
||||||
|
member.member.fir.status.visibility,
|
||||||
|
candidate.member.fir.status.visibility
|
||||||
|
)
|
||||||
|
if (result != null && result < 0) {
|
||||||
|
member = candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return member!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> extractBothWaysOverridable(
|
||||||
|
overrider: MemberWithBaseScope<D>,
|
||||||
|
members: MutableCollection<MemberWithBaseScope<D>>
|
||||||
|
): MutableList<MemberWithBaseScope<D>> {
|
||||||
|
val result = mutableListOf<MemberWithBaseScope<D>>().apply { add(overrider) }
|
||||||
|
|
||||||
|
val iterator = members.iterator()
|
||||||
|
|
||||||
|
val overrideCandidate = overrider.member.fir
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val next = iterator.next()
|
||||||
|
if (next == overrider) {
|
||||||
|
iterator.remove()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overrideChecker.similarFunctionsOrBothProperties(overrideCandidate, next.member.fir)) {
|
||||||
|
result.add(next)
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> chooseIntersectionOverrideModality(
|
||||||
|
extractedOverridden: Collection<MemberWithBaseScope<D>>
|
||||||
|
): Modality? {
|
||||||
|
var hasOpen = false
|
||||||
|
var hasAbstract = false
|
||||||
|
|
||||||
|
for ((member) in extractedOverridden) {
|
||||||
|
when ((member.fir as FirMemberDeclaration).modality) {
|
||||||
|
Modality.FINAL -> return Modality.FINAL
|
||||||
|
Modality.SEALED -> {
|
||||||
|
// Members should not be sealed. But, that will be reported as WRONG_MODIFIER_TARGET, and here we shouldn't raise an
|
||||||
|
// internal error. Instead, let the intersection override have the default modality: null.
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
Modality.OPEN -> {
|
||||||
|
hasOpen = true
|
||||||
|
}
|
||||||
|
Modality.ABSTRACT -> {
|
||||||
|
hasAbstract = true
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAbstract && !hasOpen) return Modality.ABSTRACT
|
||||||
|
if (!hasAbstract && hasOpen) return Modality.OPEN
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val processDirectOverridden: ProcessOverriddenWithBaseScope<D> = when (extractedOverridden.first().member) {
|
||||||
|
is FirNamedFunctionSymbol -> FirTypeScope::processDirectOverriddenFunctionsWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
||||||
|
is FirPropertySymbol -> FirTypeScope::processDirectOverriddenPropertiesWithBaseScope as ProcessOverriddenWithBaseScope<D>
|
||||||
|
else -> error("Unexpected callable kind: ${extractedOverridden.first().member}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val realOverridden = extractedOverridden.flatMap { realOverridden(it.member, it.baseScope, processDirectOverridden) }
|
||||||
|
val filteredOverridden = filterOutOverridden(realOverridden, processDirectOverridden)
|
||||||
|
|
||||||
|
return filteredOverridden.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> realOverridden(
|
||||||
|
symbol: D,
|
||||||
|
scope: FirTypeScope,
|
||||||
|
processDirectOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||||
|
): Collection<MemberWithBaseScope<D>> {
|
||||||
|
val result = mutableSetOf<MemberWithBaseScope<D>>()
|
||||||
|
|
||||||
|
collectRealOverridden(symbol, scope, result, mutableSetOf(), processDirectOverridden)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified D : FirCallableDeclaration> D.unwrapSubstitutionOverrides(): D {
|
||||||
|
var current = this
|
||||||
|
|
||||||
|
do {
|
||||||
|
val next = current.originalForSubstitutionOverride ?: return current
|
||||||
|
current = next
|
||||||
|
} while (true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> collectRealOverridden(
|
||||||
|
symbol: D,
|
||||||
|
scope: FirTypeScope,
|
||||||
|
result: MutableCollection<MemberWithBaseScope<D>>,
|
||||||
|
visited: MutableSet<D>,
|
||||||
|
processDirectOverridden: FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction,
|
||||||
|
) {
|
||||||
|
if (!visited.add(symbol)) return
|
||||||
|
if (!symbol.fir.origin.fromSupertypes) {
|
||||||
|
result.add(MemberWithBaseScope(symbol, scope))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.processDirectOverridden(symbol) { overridden, baseScope ->
|
||||||
|
collectRealOverridden(overridden, baseScope, result, visited, processDirectOverridden)
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> filterOutOverridden(
|
||||||
|
extractedOverridden: Collection<MemberWithBaseScope<D>>,
|
||||||
|
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||||
|
): Collection<MemberWithBaseScope<D>> {
|
||||||
|
return extractedOverridden.filter { overridden1 ->
|
||||||
|
extractedOverridden.none { overridden2 ->
|
||||||
|
overridden1 !== overridden2 && overrides(
|
||||||
|
overridden2,
|
||||||
|
overridden1,
|
||||||
|
processAllOverridden
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether f overrides g
|
||||||
|
private fun <D : FirCallableSymbol<*>> overrides(
|
||||||
|
f: MemberWithBaseScope<D>,
|
||||||
|
g: MemberWithBaseScope<D>,
|
||||||
|
processAllOverridden: ProcessOverriddenWithBaseScope<D>,
|
||||||
|
): Boolean {
|
||||||
|
val (fMember, fScope) = f
|
||||||
|
val (gMember) = g
|
||||||
|
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
fScope.processAllOverridden(fMember) { overridden, _ ->
|
||||||
|
if (overridden == gMember) {
|
||||||
|
result = true
|
||||||
|
ProcessorAction.STOP
|
||||||
|
} else {
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||||
|
extractedOverrides: Collection<MemberWithBaseScope<D>>
|
||||||
|
): Visibility {
|
||||||
|
var maxVisibility: Visibility = Visibilities.Private
|
||||||
|
for ((override) in extractedOverrides) {
|
||||||
|
val visibility = (override.fir as FirMemberDeclaration).visibility
|
||||||
|
// TODO: There is more complex logic at org.jetbrains.kotlin.resolve.OverridingUtil.resolveUnknownVisibilityForMember
|
||||||
|
// TODO: and org.jetbrains.kotlin.resolve.OverridingUtil.findMaxVisibility
|
||||||
|
val compare = Visibilities.compare(visibility, maxVisibility) ?: return Visibilities.DEFAULT_VISIBILITY
|
||||||
|
if (compare > 0) {
|
||||||
|
maxVisibility = visibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxVisibility
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createIntersectionOverride(
|
||||||
|
mostSpecific: FirNamedFunctionSymbol,
|
||||||
|
overrides: Collection<FirCallableSymbol<*>>,
|
||||||
|
newModality: Modality?,
|
||||||
|
newVisibility: Visibility,
|
||||||
|
): FirNamedFunctionSymbol {
|
||||||
|
|
||||||
|
val newSymbol =
|
||||||
|
FirIntersectionOverrideFunctionSymbol(
|
||||||
|
CallableId(
|
||||||
|
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
||||||
|
mostSpecific.fir.name
|
||||||
|
),
|
||||||
|
overrides
|
||||||
|
)
|
||||||
|
val mostSpecificFunction = mostSpecific.fir
|
||||||
|
FirFakeOverrideGenerator.createCopyForFirFunction(
|
||||||
|
newSymbol,
|
||||||
|
mostSpecificFunction, session, FirDeclarationOrigin.IntersectionOverride,
|
||||||
|
mostSpecificFunction.isExpect,
|
||||||
|
newDispatchReceiverType = dispatchReceiverType,
|
||||||
|
newModality = newModality,
|
||||||
|
newVisibility = newVisibility,
|
||||||
|
).apply {
|
||||||
|
originalForIntersectionOverrideAttr = mostSpecific.fir
|
||||||
|
}
|
||||||
|
return newSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createIntersectionOverride(
|
||||||
|
mostSpecific: FirPropertySymbol,
|
||||||
|
overrides: Collection<FirCallableSymbol<*>>,
|
||||||
|
newModality: Modality?,
|
||||||
|
newVisibility: Visibility,
|
||||||
|
): FirPropertySymbol {
|
||||||
|
val callableId = CallableId(
|
||||||
|
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
||||||
|
mostSpecific.fir.name
|
||||||
|
)
|
||||||
|
val newSymbol = FirIntersectionOverridePropertySymbol(callableId, overrides)
|
||||||
|
val mostSpecificProperty = mostSpecific.fir
|
||||||
|
FirFakeOverrideGenerator.createCopyForFirProperty(
|
||||||
|
newSymbol, mostSpecificProperty, session, FirDeclarationOrigin.IntersectionOverride,
|
||||||
|
newModality = newModality,
|
||||||
|
newVisibility = newVisibility,
|
||||||
|
newDispatchReceiverType = dispatchReceiverType,
|
||||||
|
).apply {
|
||||||
|
originalForIntersectionOverrideAttr = mostSpecific.fir
|
||||||
|
}
|
||||||
|
return newSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope) {
|
||||||
|
operator fun component1() = member
|
||||||
|
operator fun component2() = baseScope
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other is MemberWithBaseScope<*> && member == other.member
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return member.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : FirCallableSymbol<*>> D.withScope(baseScope: FirTypeScope) = MemberWithBaseScope(this, baseScope)
|
||||||
|
|
||||||
|
class FirIntersectionOverrideStorage(val session: FirSession) : FirSessionComponent {
|
||||||
|
private val cachesFactory = session.firCachesFactory
|
||||||
|
|
||||||
|
class CacheForScope(cachesFactory: FirCachesFactory) {
|
||||||
|
val intersectionOverrides: FirCache<FirCallableSymbol<*>, MemberWithBaseScope<FirCallableSymbol<*>>, ContextForIntersectionOverrideConstruction<*>> =
|
||||||
|
cachesFactory.createCache { mostSpecific, context ->
|
||||||
|
val (intersectionScope, extractedOverrides, scopeForMostSpecific) = context
|
||||||
|
intersectionScope.createIntersectionOverride(extractedOverrides, mostSpecific, scopeForMostSpecific)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ContextForIntersectionOverrideConstruction<D : FirCallableSymbol<*>>(
|
||||||
|
val intersectionContext: FirTypeIntersectionScopeContext,
|
||||||
|
val extractedOverrides: List<MemberWithBaseScope<D>>,
|
||||||
|
val scopeForMostSpecific: FirTypeScope
|
||||||
|
)
|
||||||
|
|
||||||
|
val cacheByScope: FirCache<ConeKotlinType, CacheForScope, Nothing?> =
|
||||||
|
cachesFactory.createCache { _ -> CacheForScope(cachesFactory) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirSession.intersectionOverrideStorage: FirIntersectionOverrideStorage by FirSession.sessionComponentAccessor()
|
||||||
Reference in New Issue
Block a user