[K/N] Implement objc overridablity condition for IR

^KT-61511
This commit is contained in:
Pavel Kunyavskiy
2023-10-09 11:16:48 +02:00
committed by Space Team
parent 202f30f910
commit 156c341eeb
16 changed files with 219 additions and 11 deletions
@@ -26,11 +26,15 @@ import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.native.FirNativeKotlinMangler
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.signaturer.Ir2FirManglerAdapter
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrMemberWithContainerSource
import org.jetbrains.kotlin.ir.objcinterop.IrObjCOverridabilityCondition
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -40,11 +44,18 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
internal val KlibFactories = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer)
internal object NativeFir2IrExtensions : Fir2IrExtensions {
override val irNeedsDeserialization = false
override val externalOverridabilityConditions = listOf(IrObjCOverridabilityCondition)
override fun generateOrGetFacadeClass(declaration: IrMemberWithContainerSource, components: Fir2IrComponents) = null
override fun deserializeToplevelClass(irClass: IrClass, components: Fir2IrComponents) = false
override fun registerDeclarations(symbolTable: SymbolTable) {}
override fun findInjectedValue(calleeReference: FirReference, conversionScope: Fir2IrConversionScope) = null
}
internal fun PhaseContext.fir2Ir(
input: FirOutput.Full,
): Fir2IrOutput {
val fir2IrExtensions = Fir2IrExtensions.Default
var builtInsModule: KotlinBuiltIns? = null
val resolvedLibraries = config.resolvedLibraries.getFullResolvedList()
@@ -85,7 +96,7 @@ internal fun PhaseContext.fir2Ir(
useIrFakeOverrideBuilder = configuration.getBoolean(CommonConfigurationKeys.USE_IR_FAKE_OVERRIDE_BUILDER),
)
val (irModuleFragment, components, pluginContext, irActualizedResult) = input.firResult.convertToIrAndActualize(
fir2IrExtensions,
NativeFir2IrExtensions,
fir2IrConfiguration,
IrGenerationExtension.getInstances(config.project),
signatureComposer = DescriptorSignatureComposerStub(KonanManglerDesc),
@@ -172,6 +172,7 @@ class KonanDriver(
copy(BinaryOptions.objcExportDisableSwiftMemberNameMangling)
copy(BinaryOptions.objcExportIgnoreInterfaceMethodCollisions)
copy(KonanConfigKeys.OBJC_GENERICS)
copy(CommonConfigurationKeys.USE_IR_FAKE_OVERRIDE_BUILDER)
}
// For the second stage, remove already compiled source files from the configuration.
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.DescriptorMetadataSource
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
import org.jetbrains.kotlin.ir.linkage.partial.partialLinkageConfig
import org.jetbrains.kotlin.ir.objcinterop.IrObjCOverridabilityCondition
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -154,7 +155,8 @@ internal fun PsiToIrContext.psiToIr(
cachedLibraries = config.cachedLibraries,
lazyIrForCaches = config.lazyIrForCaches,
libraryBeingCached = config.libraryToCache,
userVisibleIrModulesSupport = config.userVisibleIrModulesSupport
userVisibleIrModulesSupport = config.userVisibleIrModulesSupport,
externalOverridabilityConditions = listOf(IrObjCOverridabilityCondition)
).also { linker ->
// context.config.librariesWithDependencies could change at each iteration.
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.overrides.IrExternalOverridabilityCondition
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
@@ -306,7 +307,8 @@ internal class KonanIrLinker(
private val cachedLibraries: CachedLibraries,
private val lazyIrForCaches: Boolean,
private val libraryBeingCached: PartialCacheInfo?,
override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport
override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport,
externalOverridabilityConditions: List<IrExternalOverridabilityCondition>,
) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) {
override fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean = moduleDescriptor.isNativeStdlib()
@@ -321,7 +323,8 @@ internal class KonanIrLinker(
typeSystem = IrTypeSystemContextImpl(builtIns),
friendModules = friendModules,
partialLinkageSupport = partialLinkageSupport,
platformSpecificClassFilter = KonanFakeOverrideClassFilter
platformSpecificClassFilter = KonanFakeOverrideClassFilter,
externalOverridabilityConditions = externalOverridabilityConditions,
)
val moduleDeserializers = mutableMapOf<ModuleDescriptor, KonanPartialModuleDeserializer>()
@@ -4101,6 +4101,11 @@ if (PlatformInfo.isAppleTarget(project)) {
createInterop("kt59167") {
it.defFile 'interop/kt59167/kt59167.def'
}
createInterop("overridabilityCondition") {
it.defFile 'interop/objc/overridabilityCondition/lib.def'
it.headers "$projectDir/interop/objc/overridabilityCondition/lib.h"
it.extraOpts "-Xcompile-source", "$projectDir/interop/objc/overridabilityCondition/lib.m"
}
}
createInterop("withSpaces") {
@@ -4673,6 +4678,12 @@ if (PlatformInfo.isAppleTarget(project)) {
interop = "objcDirect"
}
interopTest("interop_objc_overridabilityCondition") {
interop = "overridabilityCondition"
source = "interop/objc/overridabilityCondition/main.kt"
flags = [ "-Xuse-ir-fake-override-builder" ]
}
interopTest("interop_objc_foreignException") {
source = "interop/objc/foreignException/objc_wrap.kt"
interop = 'foreignException'
@@ -0,0 +1,2 @@
language = Objective-C
headersFilter = **/lib.h
@@ -0,0 +1,10 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSUUID.h>
@interface ObjCClass : NSObject
- (NSString*)fooWithArg:(int)arg arg2:(NSString*)arg2;
- (NSString*)fooWithArg:(int)ohNoOtherName name2:(NSString*)name2;
- (NSString*)fooWithArg:(int)arg name3:(NSString*)name3;
@end
@@ -0,0 +1,18 @@
#import "lib.h"
@implementation ObjCClass {
}
- (NSString*)fooWithArg:(int)arg arg2:(NSString*)arg2 {
return @"A";
}
- (NSString*)fooWithArg:(int)ohNoOtherName name2:(NSString*)name2 {
return @"B";
}
- (NSString*)fooWithArg:(int)arg name3:(NSString*)name3 {
return @"C";
}
@end
@@ -0,0 +1,54 @@
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import lib.ObjCClass
@Suppress("CONFLICTING_OVERLOADS")
class OverrideAll : ObjCClass() {
override fun fooWithArg(arg: Int, arg2: String?) = "D"
override fun fooWithArg(ohNoOtherName: Int, name2: String?) = "E"
override fun fooWithArg(arg: Int, name3: String?) = "F"
}
@Suppress("CONFLICTING_OVERLOADS")
class OverrideNone : ObjCClass() {
}
@Suppress("CONFLICTING_OVERLOADS")
class OverrideOne : ObjCClass() {
override fun fooWithArg(arg: Int, arg2: String?) = "G"
}
@Suppress("CONFLICTING_OVERLOADS")
class OverrideWithDifferentFirstArgName : ObjCClass() {
override fun fooWithArg(a: Int, arg2: String?) = "H"
override fun fooWithArg(b: Int, name2: String?) = "I"
override fun fooWithArg(c: Int, name3: String?) = "J"
}
fun test(x: ObjCClass, expected: String) {
val res = x.fooWithArg(arg = 0, arg2 = "") +
x.fooWithArg(ohNoOtherName = 0, name2="") +
x.fooWithArg(arg = 0, name3 = "")
if (res != expected) throw IllegalStateException("Fail ${x::class}: ${res} instead of $expected")
}
fun main() {
test(ObjCClass(), "ABC")
test(OverrideAll(), "DEF")
test(OverrideNone(), "ABC")
test(OverrideOne(), "GBC")
test(OverrideWithDifferentFirstArgName(), "HIJ")
// Also test non-virtual calls
val x1 = OverrideAll()
val res1 = x1.fooWithArg(arg = 0, arg2 = "") +
x1.fooWithArg(ohNoOtherName = 0, name2="") +
x1.fooWithArg(arg = 0, name3 = "")
if (res1 != "DEF") throw IllegalStateException("Fail OverrideAll non-virtual: ${res1} instead of DEF")
val x2 = OverrideNone()
val res2 = x2.fooWithArg(arg = 0, arg2 = "") +
x2.fooWithArg(ohNoOtherName = 0, name2="") +
x2.fooWithArg(arg = 0, name3 = "")
if (res2 != "ABC") throw IllegalStateException("Fail OverrideNone non-virtual: ${res2} instead of ABC")
}