[FIR] Don't remove subsumed members from intersection overrides's overriddens
This fixes a bunch of missing overridden symbols in IR. This is also required for fixing KT-59921 in the following commit where we need to keep all overridden symbols of intersection overrides so that we can enhance them properly. #KT-57300 Fixed #KT-57299 Fixed #KT-59921 #KT-57300 #KT-62788 #KT-64271 #KT-64382
This commit is contained in:
committed by
Space Team
parent
d80dee6e1c
commit
3b841dcb98
+12
-6
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.constructors
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.getNonSubsumedOverriddenSymbols
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.unwrapFakeOverridesOrDelegated
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.popLast
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
|
||||
sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
object Regular : FirJsNameClashClassMembersChecker(MppCheckerKind.Platform) {
|
||||
@@ -113,13 +115,17 @@ sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirCla
|
||||
}
|
||||
}
|
||||
|
||||
fun addAllSymbolsFrom(symbols: Collection<FirCallableSymbol<*>>) {
|
||||
fun addAllSymbolsFrom(symbols: Collection<FirCallableSymbol<*>>, sessionHolder: SessionHolder) {
|
||||
for (symbol in symbols) {
|
||||
when (symbol) {
|
||||
is FirIntersectionCallableSymbol -> {
|
||||
addAllSymbolsFrom(symbol.intersections)
|
||||
for (intersectedSymbol in symbol.intersections) {
|
||||
overrideIntersections.getOrPut(intersectedSymbol) { hashSetOf() }.addAll(symbol.intersections)
|
||||
val nonSubsumedOverriddenSymbols = symbol.getNonSubsumedOverriddenSymbols(
|
||||
sessionHolder.session,
|
||||
sessionHolder.scopeSession
|
||||
)
|
||||
addAllSymbolsFrom(nonSubsumedOverriddenSymbols, sessionHolder)
|
||||
for (intersectedSymbol in nonSubsumedOverriddenSymbols) {
|
||||
overrideIntersections.getOrPut(intersectedSymbol) { hashSetOf() }.addAll(nonSubsumedOverriddenSymbols)
|
||||
}
|
||||
}
|
||||
else -> allSymbols.add(symbol)
|
||||
@@ -137,8 +143,8 @@ sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirCla
|
||||
val scope = declaration.symbol.unsubstitutedScope(context)
|
||||
|
||||
scope.processDeclaredConstructors(allSymbols::add)
|
||||
addAllSymbolsFrom(scope.collectAllFunctions())
|
||||
addAllSymbolsFrom(scope.collectAllProperties())
|
||||
addAllSymbolsFrom(scope.collectAllFunctions(), context.sessionHolder)
|
||||
addAllSymbolsFrom(scope.collectAllProperties(), context.sessionHolder)
|
||||
|
||||
for (callableMemberSymbol in allSymbols) {
|
||||
val overriddenLeaves = scope.collectOverriddenLeaves(callableMemberSymbol)
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -335,7 +334,11 @@ fun FirCallableSymbol<*>.getImplementationStatus(
|
||||
}
|
||||
|
||||
if (symbol is FirIntersectionCallableSymbol) {
|
||||
if (containingClassSymbol === parentClassSymbol && symbol.subjectToManyNotImplemented(sessionHolder)) {
|
||||
val dispatchReceiverScope = symbol.dispatchReceiverScope(sessionHolder.session, sessionHolder.scopeSession)
|
||||
val memberWithBaseScope = MemberWithBaseScope(symbol, dispatchReceiverScope)
|
||||
val nonSubsumed = memberWithBaseScope.getNonSubsumedOverriddenSymbols()
|
||||
|
||||
if (containingClassSymbol === parentClassSymbol && !memberWithBaseScope.isTrivialIntersection() && nonSubsumed.subjectToManyNotImplemented(sessionHolder)) {
|
||||
return ImplementationStatus.AMBIGUOUSLY_INHERITED
|
||||
}
|
||||
|
||||
@@ -345,7 +348,7 @@ fun FirCallableSymbol<*>.getImplementationStatus(
|
||||
var hasImplementation = false
|
||||
var hasImplementationVar = false
|
||||
|
||||
for (intersection in symbol.intersections) {
|
||||
for (intersection in nonSubsumed) {
|
||||
val unwrapped = intersection.unwrapFakeOverrides()
|
||||
val isVar = unwrapped is FirPropertySymbol && unwrapped.isVar
|
||||
val isFromClass = unwrapped.getContainingClassSymbol(sessionHolder.session)?.classKind == ClassKind.CLASS
|
||||
@@ -403,11 +406,11 @@ fun FirCallableSymbol<*>.getImplementationStatus(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(sessionHolder: SessionHolder): Boolean {
|
||||
private fun List<FirCallableSymbol<*>>.subjectToManyNotImplemented(sessionHolder: SessionHolder): Boolean {
|
||||
var nonAbstractCountInClass = 0
|
||||
var nonAbstractCountInInterface = 0
|
||||
var abstractCountInInterface = 0
|
||||
for (intersectionSymbol in intersections) {
|
||||
for (intersectionSymbol in this) {
|
||||
val containingClassSymbol = intersectionSymbol.getContainingClassSymbol(sessionHolder.session) as? FirRegularClassSymbol
|
||||
val hasInterfaceContainer = containingClassSymbol?.classKind == ClassKind.INTERFACE
|
||||
if (intersectionSymbol.modality != Modality.ABSTRACT) {
|
||||
|
||||
+24
-9
@@ -17,8 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.isVisibleInClass
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
@@ -26,15 +25,14 @@ import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
||||
import org.jetbrains.kotlin.fir.delegatedWrapperData
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenMembers
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
@@ -121,6 +119,15 @@ sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClas
|
||||
AbstractTypeChecker.isSubtypeOf(typeCheckerState, inheritedTypeSubstituted, baseType)
|
||||
}
|
||||
|
||||
/**
|
||||
* An intersection override is trivial if one of the overridden symbols subsumes all others.
|
||||
*
|
||||
* @see org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScopeContext.convertGroupedCallablesToIntersectionResults
|
||||
*/
|
||||
fun FirCallableSymbol<*>.isTrivialIntersectionOverride(): Boolean {
|
||||
return callableId.classId != containingClass.classId || MemberWithBaseScope(this, classScope).isTrivialIntersection()
|
||||
}
|
||||
|
||||
val intersectionSymbols = when {
|
||||
//substitution override means simple materialization of single method, so nothing to check
|
||||
symbol.isSubstitutionOverride -> return
|
||||
@@ -134,7 +141,9 @@ sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClas
|
||||
//current symbol needs to be added, because basically it is the implementation
|
||||
cleared + symbol
|
||||
}
|
||||
symbol is FirIntersectionCallableSymbol && symbol.callableId.classId == containingClass.classId ->
|
||||
symbol is FirIntersectionCallableSymbol && !symbol.isTrivialIntersectionOverride() ->
|
||||
// We intentionally don't use getNonSubsumedOverriddenSymbols here, otherwise we'll get lots of new errors (compared to K1)
|
||||
// in cases where a Java superclass inherits multiple members with conflicting nullability annotations.
|
||||
symbol.intersections
|
||||
else -> return
|
||||
}
|
||||
@@ -203,12 +212,18 @@ sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClas
|
||||
reporter.reportOn(containingClass.source, FirErrors.VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, symbol, overriddenVar, context)
|
||||
}
|
||||
|
||||
private fun FirTypeScope.collectFunctionsNamed(name: Name, containingClass: FirClass): List<FirNamedFunctionSymbol> {
|
||||
private fun FirTypeScope.collectFunctionsNamed(
|
||||
name: Name,
|
||||
containingClass: FirClass,
|
||||
context: CheckerContext,
|
||||
): List<FirNamedFunctionSymbol> {
|
||||
val allFunctions = mutableListOf<FirNamedFunctionSymbol>()
|
||||
|
||||
processFunctionsByName(name) { sym ->
|
||||
when (sym) {
|
||||
is FirIntersectionOverrideFunctionSymbol -> sym.intersections.mapNotNullTo(allFunctions) { it as? FirNamedFunctionSymbol }
|
||||
is FirIntersectionOverrideFunctionSymbol -> sym
|
||||
.getNonSubsumedOverriddenSymbols(context.session, context.scopeSession)
|
||||
.mapNotNullTo(allFunctions) { it as? FirNamedFunctionSymbol }
|
||||
else -> allFunctions.add(sym)
|
||||
}
|
||||
}
|
||||
@@ -225,7 +240,7 @@ sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClas
|
||||
scope: FirTypeScope,
|
||||
name: Name
|
||||
) {
|
||||
val allFunctions = scope.collectFunctionsNamed(name, containingClass)
|
||||
val allFunctions = scope.collectFunctionsNamed(name, containingClass, context)
|
||||
|
||||
val sameArgumentGroups = allFunctions.groupBy { function ->
|
||||
buildList {
|
||||
|
||||
+2
-4
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.collectOverriddenFunctionsWhere
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.processOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||
@@ -17,11 +16,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.getSingleMatchedExpectForActualOrNull
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.scopes.processAllFunctions
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
@@ -66,7 +64,7 @@ sealed class FirMultipleDefaultsInheritedFromSupertypesChecker(mppKind: MppCheck
|
||||
// default values of actual functions are located in corresponding expect functions
|
||||
val overriddenWithDefaults = overridden.getSingleMatchedExpectForActualOrNull() as? FirNamedFunctionSymbol ?: overridden
|
||||
// Substitution overrides copy default values from originals
|
||||
if (!overriddenWithDefaults.isSubstitutionOverride && overriddenWithDefaults.valueParameterSymbols.any { it.hasDefaultValue }) {
|
||||
if (!overriddenWithDefaults.isSubstitutionOrIntersectionOverride && overriddenWithDefaults.valueParameterSymbols.any { it.hasDefaultValue }) {
|
||||
overriddenFunctions += overriddenWithDefaults
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ sealed class FirNotImplementedOverrideChecker(mppKind: MppCheckerKind) : FirClas
|
||||
|
||||
fun collectSymbol(symbol: FirCallableSymbol<*>) {
|
||||
val delegatedWrapperData = symbol.delegatedWrapperData
|
||||
if (delegatedWrapperData != null) {
|
||||
if (delegatedWrapperData != null && symbol !is FirIntersectionCallableSymbol) {
|
||||
val directOverriddenMembersWithBaseScope = classScope
|
||||
.getDirectOverriddenMembersWithBaseScope(symbol)
|
||||
.filter { it.member != symbol }
|
||||
|
||||
Reference in New Issue
Block a user