[K/N] Implement objc overridablity condition for IR
^KT-61511
This commit is contained in:
committed by
Space Team
parent
202f30f910
commit
156c341eeb
+2
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
@@ -32,6 +33,7 @@ class JvmFir2IrExtensions(
|
||||
private val irDeserializer: JvmIrDeserializer,
|
||||
private val mangler: KotlinMangler.IrMangler,
|
||||
) : Fir2IrExtensions, JvmGeneratorExtensions {
|
||||
override val externalOverridabilityConditions: List<IrExternalOverridabilityCondition> = emptyList() // TODO: KT-61370, KT-61804
|
||||
override val classNameOverride: MutableMap<IrClass, JvmClassName> = mutableMapOf()
|
||||
override val cachedFields = CachedFieldsForObjectInstances(IrFactoryImpl, configuration.languageVersionSettings)
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ class Fir2IrConverter(
|
||||
IrFakeOverrideBuilder(
|
||||
typeContextProvider(irBuiltins),
|
||||
Fir2IrFakeOverrideStrategy(friendModulesMap(session), commonMemberStorage.symbolTable, irMangler),
|
||||
externalOverridabilityConditions = emptyList(), // TODO: KT-61370, KT-61804.
|
||||
fir2IrExtensions.externalOverridabilityConditions
|
||||
)
|
||||
},
|
||||
moduleDescriptor, commonMemberStorage, irMangler, specialSymbolProvider, initializedIrBuiltIns
|
||||
|
||||
@@ -8,10 +8,12 @@ package org.jetbrains.kotlin.fir.backend
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrMemberWithContainerSource
|
||||
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
|
||||
interface Fir2IrExtensions {
|
||||
val irNeedsDeserialization: Boolean
|
||||
val externalOverridabilityConditions: List<IrExternalOverridabilityCondition>
|
||||
|
||||
fun generateOrGetFacadeClass(declaration: IrMemberWithContainerSource, components: Fir2IrComponents): IrClass?
|
||||
fun deserializeToplevelClass(irClass: IrClass, components: Fir2IrComponents): Boolean
|
||||
@@ -22,6 +24,7 @@ interface Fir2IrExtensions {
|
||||
override val irNeedsDeserialization: Boolean
|
||||
get() = false
|
||||
|
||||
override val externalOverridabilityConditions: List<IrExternalOverridabilityCondition> = emptyList()
|
||||
override fun generateOrGetFacadeClass(declaration: IrMemberWithContainerSource, components: Fir2IrComponents): IrClass? = null
|
||||
override fun deserializeToplevelClass(irClass: IrClass, components: Fir2IrComponents): Boolean = false
|
||||
override fun registerDeclarations(symbolTable: SymbolTable) {}
|
||||
|
||||
+6
@@ -14,6 +14,12 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
|
||||
|
||||
/**
|
||||
* The same code, as in this class also exists in [org.jetbrains.kotlin.ir.objcinterop.ObjCOverridabilityCondition]
|
||||
* and in [org.jetbrains.kotlin.ir.objcinterop.IrObjCOverridabilityCondition].
|
||||
*
|
||||
* When modifying, all three copies should be synchronized.
|
||||
*/
|
||||
class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChecker {
|
||||
private val standardOverrideChecker = FirStandardOverrideChecker(session)
|
||||
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.ir.objcinterop
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrOverridableMember
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition
|
||||
|
||||
/**
|
||||
* Describes method overriding rules for Objective-C methods.
|
||||
*
|
||||
* The same code, as in this class also exists in [org.jetbrains.kotlin.fir.backend.native.FirNativeOverrideChecker]
|
||||
* and in [org.jetbrains.kotlin.ir.objcinterop.ObjCOverridabilityCondition].
|
||||
*
|
||||
* When modifying, all three copies should be synchronized.
|
||||
*
|
||||
*/
|
||||
object IrObjCOverridabilityCondition : IrExternalOverridabilityCondition {
|
||||
|
||||
override val contract = IrExternalOverridabilityCondition.Contract.BOTH
|
||||
|
||||
override fun isOverridable(
|
||||
superMember: IrOverridableMember,
|
||||
subMember: IrOverridableMember
|
||||
): IrExternalOverridabilityCondition.Result {
|
||||
if (superMember.name == subMember.name) { // Slow path:
|
||||
if (superMember is IrFunction && subMember is IrFunction) {
|
||||
superMember.getExternalObjCMethodInfo()?.let { superInfo ->
|
||||
val subInfo = subMember.getExternalObjCMethodInfo()
|
||||
if (subInfo != null) {
|
||||
// Overriding Objective-C method by Objective-C method in interop stubs.
|
||||
// Don't even check method signatures:
|
||||
return if (superInfo.selector == subInfo.selector) {
|
||||
IrExternalOverridabilityCondition.Result.OVERRIDABLE
|
||||
} else {
|
||||
IrExternalOverridabilityCondition.Result.INCOMPATIBLE
|
||||
}
|
||||
} else {
|
||||
// Overriding Objective-C method by Kotlin method.
|
||||
if (!parameterNamesMatch(superMember, subMember)) {
|
||||
return IrExternalOverridabilityCondition.Result.INCOMPATIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (superMember.isExternalObjCClassProperty() && subMember.isExternalObjCClassProperty()) {
|
||||
return IrExternalOverridabilityCondition.Result.OVERRIDABLE
|
||||
}
|
||||
}
|
||||
|
||||
return IrExternalOverridabilityCondition.Result.UNKNOWN
|
||||
}
|
||||
|
||||
private fun IrOverridableMember.isExternalObjCClassProperty() = this is IrProperty &&
|
||||
(this.parent as? IrClass)?.isExternalObjCClass() == true
|
||||
|
||||
private fun parameterNamesMatch(first: IrFunction, second: IrFunction): Boolean {
|
||||
// The original Objective-C method selector is represented as
|
||||
// function name and parameter names (except first).
|
||||
|
||||
if (first.valueParameters.size != second.valueParameters.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
first.valueParameters.forEachIndexed { index, parameter ->
|
||||
if (index > 0 && parameter.name != second.valueParameters[index].name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.ir.objcinterop
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -18,7 +17,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NativeForwardDeclarationKind
|
||||
import org.jetbrains.kotlin.name.NativeStandardInteropNames
|
||||
import org.jetbrains.kotlin.native.interop.ObjCMethodInfo
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.annotations.getAnnotationStringValue
|
||||
import org.jetbrains.kotlin.resolve.annotations.getArgumentValueOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
@@ -27,7 +25,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.atMostOne
|
||||
|
||||
private fun IrFunction.isFakeOverrideInProgressOfBuilding() = this is IrFunctionWithLateBinding && !isBound && isFakeOverride
|
||||
|
||||
internal val interopPackageName = NativeStandardInteropNames.cInteropPackage
|
||||
internal val objCObjectFqName = NativeStandardInteropNames.objCObjectClassId.asSingleFqName()
|
||||
@@ -118,7 +117,7 @@ private fun FunctionDescriptor.decodeObjCMethodAnnotation(): ObjCMethodInfo? {
|
||||
}
|
||||
|
||||
private fun IrFunction.decodeObjCMethodAnnotation(): ObjCMethodInfo? {
|
||||
assert (this.isReal)
|
||||
require(this.isReal || this.isFakeOverrideInProgressOfBuilding())
|
||||
|
||||
val methodInfo = this.annotations.findAnnotation(objCMethodFqName)?.let {
|
||||
ObjCMethodInfo(
|
||||
@@ -158,6 +157,11 @@ private fun FunctionDescriptor.getObjCMethodInfo(onlyExternal: Boolean): ObjCMet
|
||||
* @param onlyExternal indicates whether to accept overriding methods from Kotlin classes
|
||||
*/
|
||||
private fun IrSimpleFunction.getObjCMethodInfo(onlyExternal: Boolean): ObjCMethodInfo? {
|
||||
// During fake override building we need this method, but overriddenSymbols are not valid yet.
|
||||
// So let's pretend this override is real. It has annotation copied, if it exists
|
||||
if (this.isFakeOverrideInProgressOfBuilding()) {
|
||||
decodeObjCMethodAnnotation()?.let { return it }
|
||||
}
|
||||
if (this.isReal) {
|
||||
this.decodeObjCMethodAnnotation()?.let { return it }
|
||||
|
||||
|
||||
+4
@@ -17,6 +17,10 @@ import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
* This class is applied at [org.jetbrains.kotlin.resolve.OverridingUtil] as configured with
|
||||
* `META-INF/services/org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition` resource.
|
||||
*
|
||||
* The same code, as in this class also exists in [org.jetbrains.kotlin.fir.backend.native.FirNativeOverrideChecker]
|
||||
* and in [org.jetbrains.kotlin.ir.objcinterop.IrObjCOverridabilityCondition].
|
||||
*
|
||||
* When modifying, all three copies should be synchronized.
|
||||
*
|
||||
*/
|
||||
class ObjCOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
|
||||
Reference in New Issue
Block a user