Add basic support for multi-platform projects to the compiler (#1254)
Add compiler pass removing `expect` declarations Thus support multi-platform projects in the compiler. Also * Add some trivial checks to ensure that `expect` declarations are not generated to bitcode. * Add minor improvement to exported symbol name clash detection. * Don't create LLVM declarations for Obj-C-interop fake functions.
This commit is contained in:
committed by
GitHub
parent
155618c7dd
commit
7567c96bc9
+4
@@ -41,6 +41,10 @@ internal class KonanLower(val context: Context) {
|
||||
fun lowerModule(irModule: IrModuleFragment) {
|
||||
val phaser = PhaseManager(context)
|
||||
|
||||
phaser.phase(KonanPhase.REMOVE_EXPECT_DECLARATIONS) {
|
||||
irModule.files.forEach(ExpectDeclarationsRemoving(context)::lower)
|
||||
}
|
||||
|
||||
phaser.phase(KonanPhase.TEST_PROCESSOR) {
|
||||
TestProcessor(context).process(irModule)
|
||||
}
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ enum class KonanPhase(val description: String,
|
||||
/* */ SERIALIZER("Serialize descriptor tree and inline IR bodies"),
|
||||
/* */ BACKEND("All backend"),
|
||||
/* ... */ LOWER("IR Lowering"),
|
||||
/* ... ... */ REMOVE_EXPECT_DECLARATIONS("Expect declarations removing"),
|
||||
/* ... ... */ TEST_PROCESSOR("Unit test processor"),
|
||||
/* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"),
|
||||
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_BEFORE_INLINE),
|
||||
|
||||
+3
@@ -344,3 +344,6 @@ val ClassDescriptor.enumEntries: List<ClassDescriptor>
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.filter { it.kind == ClassKind.ENUM_ENTRY }
|
||||
}
|
||||
|
||||
internal val DeclarationDescriptor.isExpectMember: Boolean
|
||||
get() = this is MemberDescriptor && this.isExpect
|
||||
|
||||
+3
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import llvm.LLVMTypeRef
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
|
||||
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
|
||||
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
|
||||
@@ -47,6 +48,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
* and so should be computable from the descriptor itself without checking a backend state.
|
||||
*/
|
||||
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
|
||||
assert(!this.isExpectMember) { this }
|
||||
|
||||
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
|
||||
// Treat any `@SymbolName` declaration as exported.
|
||||
return true
|
||||
|
||||
+3
-4
@@ -17,10 +17,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.SyntheticModules
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.origin
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
|
||||
@@ -30,6 +27,8 @@ internal interface LlvmImports {
|
||||
|
||||
internal val DeclarationDescriptor.llvmSymbolOrigin: LlvmSymbolOrigin
|
||||
get() {
|
||||
assert(!this.isExpectMember) { this }
|
||||
|
||||
val module = this.module
|
||||
val moduleOrigin = module.origin
|
||||
when (moduleOrigin) {
|
||||
|
||||
+5
@@ -444,6 +444,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.descriptor.getObjCInitMethod() != null) {
|
||||
// Do not generate any ctors for external Objective-C classes.
|
||||
return
|
||||
}
|
||||
|
||||
val constructorDescriptor = declaration.descriptor
|
||||
val classDescriptor = constructorDescriptor.constructedClass
|
||||
if (constructorDescriptor.isPrimary) {
|
||||
|
||||
+15
-5
@@ -18,11 +18,10 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.isKotlinObjCClass
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -384,8 +383,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
val descriptor = declaration.descriptor
|
||||
val llvmFunctionType = getLlvmFunctionType(descriptor)
|
||||
|
||||
if ((descriptor is ConstructorDescriptor && descriptor.getObjCInitMethod() != null)) {
|
||||
return
|
||||
}
|
||||
|
||||
val llvmFunction = if (descriptor.isExternal) {
|
||||
if (descriptor.isIntrinsic) {
|
||||
if (descriptor.isIntrinsic || descriptor.getExternalObjCMethodInfo() != null) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -395,7 +398,14 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
)
|
||||
} else {
|
||||
val symbolName = if (descriptor.isExported()) {
|
||||
descriptor.symbolName
|
||||
descriptor.symbolName.also {
|
||||
if (!MainFunctionDetector.isMain(descriptor)) {
|
||||
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
|
||||
} else {
|
||||
// As a workaround, allow `main` functions to clash because frontend accepts this.
|
||||
// See [OverloadResolver.isTopLevelMainInDifferentFiles] usage.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
"kfun:" + qualifyInternalName(descriptor)
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
|
||||
/**
|
||||
* This pass removes all declarations with `isExpect == true`.
|
||||
*/
|
||||
internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
|
||||
irFile.declarations.removeAll { it.descriptor.isExpectMember }
|
||||
}
|
||||
}
|
||||
@@ -1918,6 +1918,11 @@ task memory_escape2(type: RunKonanTest) {
|
||||
source = "runtime/memory/escape2.kt"
|
||||
}
|
||||
|
||||
task mpp1(type: RunStandaloneKonanTest) {
|
||||
source = "codegen/mpp/mpp1.kt"
|
||||
flags = ['-tr', '-Xmulti-platform']
|
||||
}
|
||||
|
||||
task unit1(type: RunKonanTest) {
|
||||
goldValue = "First\nkotlin.Unit\n"
|
||||
source = "codegen/basics/unit1.kt"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package codegen.mpp.mpp1
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
fun box() {
|
||||
assertEquals(A().B().fourtyTwo(), 42)
|
||||
assertEquals(seventeen(), 17)
|
||||
}
|
||||
|
||||
expect class A {
|
||||
constructor()
|
||||
|
||||
inner class B {
|
||||
fun fourtyTwo(): Int
|
||||
|
||||
constructor()
|
||||
}
|
||||
}
|
||||
|
||||
actual class A {
|
||||
actual inner class B actual constructor() {
|
||||
actual fun fourtyTwo() = 42
|
||||
}
|
||||
}
|
||||
|
||||
actual fun seventeen() = 17
|
||||
expect fun seventeen(): Int
|
||||
|
||||
@Test fun runTest() {
|
||||
box()
|
||||
}
|
||||
Reference in New Issue
Block a user