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) {
|
fun lowerModule(irModule: IrModuleFragment) {
|
||||||
val phaser = PhaseManager(context)
|
val phaser = PhaseManager(context)
|
||||||
|
|
||||||
|
phaser.phase(KonanPhase.REMOVE_EXPECT_DECLARATIONS) {
|
||||||
|
irModule.files.forEach(ExpectDeclarationsRemoving(context)::lower)
|
||||||
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.TEST_PROCESSOR) {
|
phaser.phase(KonanPhase.TEST_PROCESSOR) {
|
||||||
TestProcessor(context).process(irModule)
|
TestProcessor(context).process(irModule)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -29,6 +29,7 @@ enum class KonanPhase(val description: String,
|
|||||||
/* */ SERIALIZER("Serialize descriptor tree and inline IR bodies"),
|
/* */ SERIALIZER("Serialize descriptor tree and inline IR bodies"),
|
||||||
/* */ BACKEND("All backend"),
|
/* */ BACKEND("All backend"),
|
||||||
/* ... */ LOWER("IR Lowering"),
|
/* ... */ LOWER("IR Lowering"),
|
||||||
|
/* ... ... */ REMOVE_EXPECT_DECLARATIONS("Expect declarations removing"),
|
||||||
/* ... ... */ TEST_PROCESSOR("Unit test processor"),
|
/* ... ... */ TEST_PROCESSOR("Unit test processor"),
|
||||||
/* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"),
|
/* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"),
|
||||||
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_BEFORE_INLINE),
|
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_BEFORE_INLINE),
|
||||||
|
|||||||
+3
@@ -344,3 +344,6 @@ val ClassDescriptor.enumEntries: List<ClassDescriptor>
|
|||||||
.filterIsInstance<ClassDescriptor>()
|
.filterIsInstance<ClassDescriptor>()
|
||||||
.filter { it.kind == ClassKind.ENUM_ENTRY }
|
.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 llvm.LLVMTypeRef
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
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.descriptors.isUnit
|
||||||
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
|
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
|
||||||
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
|
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.
|
* and so should be computable from the descriptor itself without checking a backend state.
|
||||||
*/
|
*/
|
||||||
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
|
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
|
||||||
|
assert(!this.isExpectMember) { this }
|
||||||
|
|
||||||
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
|
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
|
||||||
// Treat any `@SymbolName` declaration as exported.
|
// Treat any `@SymbolName` declaration as exported.
|
||||||
return true
|
return true
|
||||||
|
|||||||
+3
-4
@@ -17,10 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.llvm
|
package org.jetbrains.kotlin.backend.konan.llvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
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.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
@@ -30,6 +27,8 @@ internal interface LlvmImports {
|
|||||||
|
|
||||||
internal val DeclarationDescriptor.llvmSymbolOrigin: LlvmSymbolOrigin
|
internal val DeclarationDescriptor.llvmSymbolOrigin: LlvmSymbolOrigin
|
||||||
get() {
|
get() {
|
||||||
|
assert(!this.isExpectMember) { this }
|
||||||
|
|
||||||
val module = this.module
|
val module = this.module
|
||||||
val moduleOrigin = module.origin
|
val moduleOrigin = module.origin
|
||||||
when (moduleOrigin) {
|
when (moduleOrigin) {
|
||||||
|
|||||||
+5
@@ -444,6 +444,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (declaration.descriptor.getObjCInitMethod() != null) {
|
||||||
|
// Do not generate any ctors for external Objective-C classes.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val constructorDescriptor = declaration.descriptor
|
val constructorDescriptor = declaration.descriptor
|
||||||
val classDescriptor = constructorDescriptor.constructedClass
|
val classDescriptor = constructorDescriptor.constructedClass
|
||||||
if (constructorDescriptor.isPrimary) {
|
if (constructorDescriptor.isPrimary) {
|
||||||
|
|||||||
+15
-5
@@ -18,11 +18,10 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
|
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.isKotlinObjCClass
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -384,8 +383,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
val descriptor = declaration.descriptor
|
val descriptor = declaration.descriptor
|
||||||
val llvmFunctionType = getLlvmFunctionType(descriptor)
|
val llvmFunctionType = getLlvmFunctionType(descriptor)
|
||||||
|
|
||||||
|
if ((descriptor is ConstructorDescriptor && descriptor.getObjCInitMethod() != null)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val llvmFunction = if (descriptor.isExternal) {
|
val llvmFunction = if (descriptor.isExternal) {
|
||||||
if (descriptor.isIntrinsic) {
|
if (descriptor.isIntrinsic || descriptor.getExternalObjCMethodInfo() != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +398,14 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val symbolName = if (descriptor.isExported()) {
|
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 {
|
} else {
|
||||||
"kfun:" + qualifyInternalName(descriptor)
|
"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"
|
source = "runtime/memory/escape2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task mpp1(type: RunStandaloneKonanTest) {
|
||||||
|
source = "codegen/mpp/mpp1.kt"
|
||||||
|
flags = ['-tr', '-Xmulti-platform']
|
||||||
|
}
|
||||||
|
|
||||||
task unit1(type: RunKonanTest) {
|
task unit1(type: RunKonanTest) {
|
||||||
goldValue = "First\nkotlin.Unit\n"
|
goldValue = "First\nkotlin.Unit\n"
|
||||||
source = "codegen/basics/unit1.kt"
|
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