[K/N] Fix K2 ObjC interop: Fields are not supported for Companion of subclass of ObjC type

^KT-63048
This commit is contained in:
Vladimir Sukharev
2023-11-03 20:07:17 +01:00
committed by Space Team
parent 3ea4a6a937
commit 4d4ad6c0d8
6 changed files with 34 additions and 6 deletions
@@ -11,10 +11,12 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmSerializeIrMode
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.Fir2IrConversionScope
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.InjectedValue
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.*
@@ -95,4 +97,8 @@ class JvmFir2IrExtensions(
irDeserializer.deserializeTopLevelClass(
irClass, components.irBuiltIns, components.symbolTable, components.irProviders, this
)
override fun hasBackingField(property: FirProperty, session: FirSession): Boolean =
// NOTE maybe there might be platform-specific logic, similar to JvmGeneratorExtensionsImpl.isPropertyWithPlatformField()
Fir2IrExtensions.Default.hasBackingField(property, session)
}
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrMemberWithContainerSource
@@ -20,6 +23,14 @@ interface Fir2IrExtensions {
fun registerDeclarations(symbolTable: SymbolTable)
fun findInjectedValue(calleeReference: FirReference, conversionScope: Fir2IrConversionScope): InjectedValue?
/**
* Platform-dependent logic to determine, whether a backing field is required.
* Should be called instead of `FirProperty.hasBackingField()` to decide whether to create a backing field.
* The implementation should return `true` in case platform-dependent condition for backing field existence is met,
* otherwise return a result of Fir2IrExtensions.Default.hasBackingField()
*/
fun hasBackingField(property: FirProperty, session: FirSession): Boolean
object Default : Fir2IrExtensions {
override val irNeedsDeserialization: Boolean
get() = false
@@ -29,5 +40,6 @@ interface Fir2IrExtensions {
override fun deserializeToplevelClass(irClass: IrClass, components: Fir2IrComponents): Boolean = false
override fun registerDeclarations(symbolTable: SymbolTable) {}
override fun findInjectedValue(calleeReference: FirReference, conversionScope: Fir2IrConversionScope) = null
override fun hasBackingField(property: FirProperty, session: FirSession): Boolean = property.hasBackingField
}
}
@@ -131,7 +131,7 @@ class Fir2IrLazyProperty(
}
}
}
fir.hasBackingField && origin != IrDeclarationOrigin.FAKE_OVERRIDE -> {
extensions.hasBackingField(fir, session) && origin != IrDeclarationOrigin.FAKE_OVERRIDE -> {
with(declarationStorage) {
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
@@ -141,7 +141,7 @@ internal fun FirFunction.getInitMethodIfObjCConstructor(session: FirSession, sco
else
this
internal fun FirProperty.isExternalObjCClassProperty(session: FirSession) =
fun FirProperty.isExternalObjCClassProperty(session: FirSession): Boolean =
(containingClassLookupTag()?.toSymbol(session) as? FirClassSymbol)?.isExternalObjCClass(session) == true
internal fun FirClassSymbol<*>.isExternalObjCClass(session: FirSession): Boolean =
@@ -22,8 +22,12 @@ import org.jetbrains.kotlin.constant.EvaluatedConstTracker
import org.jetbrains.kotlin.descriptors.isEmpty
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.native.FirNativeKotlinMangler
import org.jetbrains.kotlin.fir.backend.native.interop.isExternalObjCClassProperty
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
import org.jetbrains.kotlin.fir.references.FirReference
@@ -51,6 +55,11 @@ internal object NativeFir2IrExtensions : Fir2IrExtensions {
override fun deserializeToplevelClass(irClass: IrClass, components: Fir2IrComponents) = false
override fun registerDeclarations(symbolTable: SymbolTable) {}
override fun findInjectedValue(calleeReference: FirReference, conversionScope: Fir2IrConversionScope) = null
override fun hasBackingField(property: FirProperty, session: FirSession): Boolean =
if (property.isExternalObjCClassProperty(session))
property.isLateInit
else
Fir2IrExtensions.Default.hasBackingField(property, session)
}
internal fun PhaseContext.fir2Ir(
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs
import org.jetbrains.kotlin.konan.test.blackbox.support.TestKind
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestExecutable
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.PipelineType
import org.jetbrains.kotlin.test.TestMetadata
import org.junit.jupiter.api.Tag
@@ -26,9 +25,12 @@ abstract class BaseCInteropCheckersTest : AbstractNativeSimpleTest() {
@Test
@TestMetadata(TEST_DATA_DIR)
fun testBuilding() {
val defFile = File(TEST_DATA_DIR, DEF_FILE)
muteCInteropTestIfNecessary(defFile, targets.testTarget)
val library = cinteropToLibrary(
targets = targets,
defFile = File(TEST_DATA_DIR, DEF_FILE),
defFile = defFile,
outputDir = buildDir,
freeCompilerArgs = TestCompilerArgs.EMPTY
).assertSuccess().resultingArtifact
@@ -42,7 +44,6 @@ abstract class BaseCInteropCheckersTest : AbstractNativeSimpleTest() {
val compilationResult = compileToExecutable(testCase, library.asLibraryDependency()).assertSuccess()
}
companion object {
const val TEST_DATA_DIR = "native/native.tests/testData/CInterop/KT-63048"
const val DEF_FILE = "library.def"
@@ -54,4 +55,4 @@ class CInteropCheckersTest : BaseCInteropCheckersTest()
@FirPipeline
@Tag("frontend-fir")
class FirCInteropCheckersTest : BaseCInteropCheckersTest()
class FirCInteropCheckersTest : BaseCInteropCheckersTest()