[FIR] Allow declarations to override parts of non-trivial intersection
A class can inherit two declarations that are compatible from the overridability standpoint and are therefore combined to a non-trivial intersection. At the same time, the class can declare a member declaration that only overrides one of the intersection's members. In this case, we break up the intersection and only add the overridden parts to the declared member's direct overridden list. If the class doesn't override the intersection, it exists as intersection override, like before. #KT-65487 Fixed
This commit is contained in:
committed by
Space Team
parent
889182629e
commit
26fae9e83a
+84
-22
@@ -86,17 +86,59 @@ abstract class AbstractFirUseSiteMemberScope(
|
||||
|
||||
protected abstract fun FirNamedFunctionSymbol.isVisibleInCurrentClass(): Boolean
|
||||
|
||||
private fun FirCallableSymbol<*>.isInvisible(): Boolean {
|
||||
return this is FirNamedFunctionSymbol && !isVisibleInCurrentClass()
|
||||
}
|
||||
|
||||
protected fun collectFunctionsFromSupertypes(
|
||||
name: Name,
|
||||
destination: MutableList<FirNamedFunctionSymbol>,
|
||||
explicitlyDeclaredFunctions: Set<FirNamedFunctionSymbol>
|
||||
) {
|
||||
for (chosenSymbolFromSupertype in getFunctionsFromSupertypesByName(name)) {
|
||||
val superSymbol = chosenSymbolFromSupertype.extractSomeSymbolFromSuperType()
|
||||
if (!superSymbol.isVisibleInCurrentClass()) continue
|
||||
val overriddenBy = superSymbol.getOverridden(explicitlyDeclaredFunctions)
|
||||
if (overriddenBy == null) {
|
||||
destination += chosenSymbolFromSupertype.chosenSymbol
|
||||
for (resultOfIntersection in getFunctionsFromSupertypesByName(name)) {
|
||||
resultOfIntersection.collectNonOverriddenDeclarations(explicitlyDeclaredFunctions, destination)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the receiver [ResultOfIntersection] is not overridden by any symbol in [explicitlyDeclared],
|
||||
* adds its [ResultOfIntersection.chosenSymbol] to [destination].
|
||||
*
|
||||
* If the [ResultOfIntersection] is [ResultOfIntersection.NonTrivial] and only some of the intersected symbols are overridden,
|
||||
* constructs a new [ResultOfIntersection] consisting of the non-overridden symbols and adds its [ResultOfIntersection.chosenSymbol]
|
||||
* to [destination].
|
||||
*
|
||||
* It's the opposite operation of [collectDirectOverriddenForDeclared].
|
||||
*/
|
||||
protected fun <T : FirCallableSymbol<*>> ResultOfIntersection<T>.collectNonOverriddenDeclarations(
|
||||
explicitlyDeclared: Set<FirCallableSymbol<*>>,
|
||||
destination: MutableList<in T>,
|
||||
) {
|
||||
when (this) {
|
||||
is ResultOfIntersection.SingleMember -> {
|
||||
val chosenSymbol = chosenSymbol
|
||||
if (chosenSymbol.isInvisible()) return
|
||||
val overriddenBy = chosenSymbol.getOverridden(explicitlyDeclared)
|
||||
if (overriddenBy == null) {
|
||||
destination += chosenSymbol
|
||||
}
|
||||
}
|
||||
is ResultOfIntersection.NonTrivial -> {
|
||||
// For non-trivial intersections, some of the intersected symbols can be overridden and some not.
|
||||
val (visibleNotOverridden, overriddenOrInvisible) = overriddenMembers
|
||||
.partition { !it.member.isInvisible() && it.member.getOverridden(explicitlyDeclared) == null }
|
||||
|
||||
if (overriddenOrInvisible.isEmpty()) {
|
||||
// Case 1: all intersected symbols are overridden.
|
||||
destination += chosenSymbol
|
||||
} else if (visibleNotOverridden.isNotEmpty()) {
|
||||
// Case 2: some intersected symbols are overridden.
|
||||
// Create a new ResultOfIntersection from the non-overridden and add it to destination.
|
||||
destination += supertypeScopeContext
|
||||
.convertGroupedCallablesToIntersectionResults(visibleNotOverridden.map { it.baseScope to listOf(it.member) })
|
||||
.map { it.chosenSymbol }
|
||||
}
|
||||
// Case 3: all are overridden. Don't add anything to destination.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,27 +163,47 @@ abstract class AbstractFirUseSiteMemberScope(
|
||||
|
||||
private fun computeDirectOverriddenForDeclaredFunction(declaredFunctionSymbol: FirNamedFunctionSymbol): List<ResultOfIntersection<FirNamedFunctionSymbol>> {
|
||||
val result = mutableListOf<ResultOfIntersection<FirNamedFunctionSymbol>>()
|
||||
val declaredFunction = declaredFunctionSymbol.fir
|
||||
for (resultOfIntersection in getFunctionsFromSupertypesByName(declaredFunctionSymbol.name)) {
|
||||
val symbolFromSupertype = resultOfIntersection.extractSomeSymbolFromSuperType()
|
||||
if (overrideChecker.isOverriddenFunction(declaredFunction, symbolFromSupertype.fir)) {
|
||||
result.add(resultOfIntersection)
|
||||
}
|
||||
resultOfIntersection.collectDirectOverriddenForDeclared(declaredFunctionSymbol, result, overrideChecker::isOverriddenFunction)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
protected fun <D : FirCallableSymbol<*>> ResultOfIntersection<D>.extractSomeSymbolFromSuperType(): D {
|
||||
return if (this.isIntersectionOverride()) {
|
||||
/*
|
||||
* we don't want to create intersection override if some declared function actually overrides some functions
|
||||
* from supertypes, so instead of intersection override symbol we check actual symbol from supertype
|
||||
*
|
||||
* TODO: is it enough to check only one function?
|
||||
*/
|
||||
keySymbol
|
||||
} else {
|
||||
chosenSymbol
|
||||
/**
|
||||
* If [declared] overrides the receiver [ResultOfIntersection], adds it to [result].
|
||||
* If the [ResultOfIntersection] is [ResultOfIntersection.NonTrivial] and [declared] only overrides some of the intersected symbols,
|
||||
* a new [ResultOfIntersection] is constructed containing only the overridden symbols.
|
||||
*
|
||||
* Opposite operation to [collectNonOverriddenDeclarations].
|
||||
*/
|
||||
protected inline fun <T : FirCallableSymbol<*>> ResultOfIntersection<T>.collectDirectOverriddenForDeclared(
|
||||
declared: T,
|
||||
result: MutableList<in ResultOfIntersection<T>>,
|
||||
isOverridden: (T, T) -> Boolean,
|
||||
) {
|
||||
when (this) {
|
||||
is ResultOfIntersection.SingleMember -> {
|
||||
val symbolFromSupertype = chosenSymbol
|
||||
if (isOverridden(declared, symbolFromSupertype)) {
|
||||
result.add(this)
|
||||
}
|
||||
}
|
||||
is ResultOfIntersection.NonTrivial -> {
|
||||
// For non-trivial intersections, declared can override a subset of the intersected symbols.
|
||||
val (overridden, nonOverridden) = overriddenMembers.partition {
|
||||
isOverridden(declared, it.member)
|
||||
}
|
||||
|
||||
if (nonOverridden.isEmpty()) {
|
||||
// Case 1: all intersected symbols are overridden
|
||||
result += this
|
||||
} else if (overridden.isNotEmpty()) {
|
||||
// Case 2: some intersected symbols are overridden.
|
||||
// Create a new ResultOfIntersection from the overridden symbols and add it to result.
|
||||
result += supertypeScopeContext.convertGroupedCallablesToIntersectionResults(overridden.map { it.baseScope to listOf(it.member) })
|
||||
}
|
||||
// Case 3: No intersected symbols are overridden. Don't add anything to result.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-15
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirIntersectionScopeOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.firOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -49,12 +46,8 @@ class FirClassUseSiteMemberScope(
|
||||
|
||||
|
||||
val (properties, fields) = getPropertiesAndFieldsFromSupertypesByName(name)
|
||||
for (propertyFromSupertype in properties) {
|
||||
val superSymbol = propertyFromSupertype.extractSomeSymbolFromSuperType()
|
||||
val overriddenBy = superSymbol.getOverridden(explicitlyDeclaredProperties)
|
||||
if (overriddenBy == null) {
|
||||
add(propertyFromSupertype.chosenSymbol)
|
||||
}
|
||||
for (resultOfIntersection in properties) {
|
||||
resultOfIntersection.collectNonOverriddenDeclarations(explicitlyDeclaredProperties, this@buildList)
|
||||
}
|
||||
addAll(fields)
|
||||
}
|
||||
@@ -62,12 +55,8 @@ class FirClassUseSiteMemberScope(
|
||||
|
||||
private fun computeDirectOverriddenForDeclaredProperty(declaredPropertySymbol: FirPropertySymbol): List<FirTypeIntersectionScopeContext.ResultOfIntersection<FirPropertySymbol>> {
|
||||
val result = mutableListOf<FirTypeIntersectionScopeContext.ResultOfIntersection<FirPropertySymbol>>()
|
||||
val declaredProperty = declaredPropertySymbol.fir
|
||||
for (resultOfIntersection in getPropertiesAndFieldsFromSupertypesByName(declaredPropertySymbol.name).first) {
|
||||
val symbolFromSupertype = resultOfIntersection.extractSomeSymbolFromSuperType()
|
||||
if (overrideChecker.isOverriddenProperty(declaredProperty, symbolFromSupertype.fir)) {
|
||||
result.add(resultOfIntersection)
|
||||
}
|
||||
resultOfIntersection.collectDirectOverriddenForDeclared(declaredPropertySymbol, result, overrideChecker::isOverriddenProperty)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user