[FIR] Treat properties from ObjC-classes as abstract
In short, the problem is some platform libraries contain invalid Kotlin code. Specifically, some classes may inherit multiple members with default implementations, but do not define an explicit override, like `UIView.bounds`. Since we can't refactor platrofm libraries just now, we want to treat such properties as abstract. ^KT-65866 Fixed ^KT-65855
This commit is contained in:
committed by
Space Team
parent
2ae8d28b33
commit
22fc90e5a1
+16
-5
@@ -5,16 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.backend.native
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.decodeObjCMethodAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.isObjCClass
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
|
||||
/**
|
||||
@@ -37,7 +41,14 @@ class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChe
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility = standardOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
|
||||
): Visibility {
|
||||
val nonSubsumed = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols()
|
||||
return chooseIntersectionVisibilityOrNull(nonSubsumed) { it.isAbstract || it.member.isObjCClassProperty(session) }
|
||||
?: Visibilities.Unknown
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.isObjCClassProperty(session: FirSession) =
|
||||
this is FirPropertySymbol && (containingClassLookupTag()?.toSymbol(session) as? FirClassSymbol<*>)?.isObjCClass(session) ?: false
|
||||
|
||||
/**
|
||||
* mimics ObjCOverridabilityCondition.isOverridable
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ internal fun FirConstructorSymbol.isObjCConstructor(session: FirSession) =
|
||||
/**
|
||||
* mimics IrClass.isObjCClass()
|
||||
*/
|
||||
private fun FirClassSymbol<*>.isObjCClass(session: FirSession) = classId.packageFqName != NativeStandardInteropNames.cInteropPackage &&
|
||||
fun FirClassSymbol<*>.isObjCClass(session: FirSession) = classId.packageFqName != NativeStandardInteropNames.cInteropPackage &&
|
||||
selfOrAnySuperClass(session) {
|
||||
it.classId == NativeStandardInteropNames.objCObjectClassId
|
||||
}
|
||||
|
||||
+7
-1
@@ -160,9 +160,15 @@ fun MemberWithBaseScope<FirCallableSymbol<*>>.getNonSubsumedOverriddenSymbols():
|
||||
.map { it.member }
|
||||
}
|
||||
|
||||
fun List<MemberWithBaseScope<FirCallableSymbol<*>>>.getNonSubsumedNonPhantomOverriddenSymbols(): List<MemberWithBaseScope<FirCallableSymbol<*>>> {
|
||||
fun Collection<MemberWithBaseScope<FirCallableSymbol<*>>>.getNonSubsumedNonPhantomOverriddenSymbols(): List<MemberWithBaseScope<FirCallableSymbol<*>>> {
|
||||
// It's crucial that we only unwrap phantom intersection overrides.
|
||||
// See comments in the following tests for explanation:
|
||||
// - intersectionWithMultipleDefaultsInJavaOverriddenByIntersectionInKotlin.kt
|
||||
// - intersectionOverridesIntersection.kt
|
||||
return flatMap { it.flattenPhantomIntersectionsRecursively() }
|
||||
.nonSubsumed()
|
||||
// To learn why `distinctBy` is needed, see:
|
||||
// - intersectionWithMultipleDefaultsInJavaWithAdditionalSymbolsAfterNonSubsumed.kt
|
||||
.distinctBy { it.member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>() }
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,13 @@ fun <D : FirCallableSymbol<*>> overrides(
|
||||
return result
|
||||
}
|
||||
|
||||
fun chooseIntersectionVisibilityOrNull(
|
||||
inline fun chooseIntersectionVisibilityOrNull(
|
||||
nonSubsumedOverrides: List<MemberWithBaseScope<FirCallableSymbol<*>>>,
|
||||
isAbstract: (MemberWithBaseScope<FirCallableSymbol<*>>) -> Boolean = MemberWithBaseScope<FirCallableSymbol<*>>::isAbstract,
|
||||
): Visibility? {
|
||||
val nonAbstract = nonSubsumedOverrides.filter {
|
||||
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
|
||||
!it.isAbstract && it.member.callableId != StandardClassIds.Callables.clone
|
||||
!isAbstract(it) && it.member.callableId != StandardClassIds.Callables.clone
|
||||
}
|
||||
val allAreAbstract = nonAbstract.isEmpty()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user