[K2] Document KMP implementation in the K2 Compiler
Add comprehensive documentation explaining the implementation and functions of the Kotlin multiplatform (KMP) support in the K2 Compiler.
This commit is contained in:
committed by
Space Team
parent
04c0cc5a5c
commit
024e94a479
@@ -37,6 +37,14 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* This class is the entry-point for compiling Kotlin code into a metadata KLib.
|
||||
*
|
||||
* **Note: `2` in the name stands for Kotlin `TO` metadata compiler.
|
||||
* This entry-point used by both K1 and K2.**
|
||||
*
|
||||
* Please see `/docs/fir/k2_kmp.md` for more info on the K2/FIR implementation.
|
||||
*/
|
||||
class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
|
||||
|
||||
override val defaultPerformanceManager: CommonCompilerPerformanceManager = K2MetadataCompilerPerformanceManager()
|
||||
|
||||
@@ -9,6 +9,16 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
/**
|
||||
* The main purpose of the lookup tag is to provide a reference to concrete classifier that
|
||||
* allows obtaining FirClassifierSymbol within a given use-site session.
|
||||
*
|
||||
* During the deserialization we use lookup tags to avoid loading the entire class-type hierarchy.
|
||||
*
|
||||
* Use-site lookup of classifiers that are referenced by lookup tags allows type refinement that is needed for the expect/actual support.
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
abstract class ConeClassifierLookupTag : TypeConstructorMarker {
|
||||
abstract val name: Name
|
||||
|
||||
@@ -17,6 +27,9 @@ abstract class ConeClassifierLookupTag : TypeConstructorMarker {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ConeClassifierLookupTag
|
||||
*/
|
||||
abstract class ConeClassLikeLookupTag : ConeClassifierLookupTag() {
|
||||
abstract val classId: ClassId
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ import org.jetbrains.kotlin.ir.util.IdSignatureComposer
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* This storage contains the shared state of FIR2IR.
|
||||
*
|
||||
* State is shared between the conversions of different modules in the same platform compilation.
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
class Fir2IrCommonMemberStorage(
|
||||
signatureComposer: IdSignatureComposer,
|
||||
firMangler: FirMangler
|
||||
|
||||
@@ -93,6 +93,27 @@ inline val FirBasedSymbol<*>.isJavaOrEnhancement: Boolean
|
||||
|
||||
private fun FirFunction.containsDefaultValue(index: Int): Boolean = valueParameters[index].defaultValue != null
|
||||
|
||||
/**
|
||||
* Checks, if the value parameter has a default value w.r.t expect/actuals.
|
||||
*
|
||||
* Requires [FirResolvePhase.EXPECT_ACTUAL_MATCHING]
|
||||
*
|
||||
* In expect/actual declarations, the presence of default values can be determined by the expect declaration.
|
||||
*
|
||||
* ```kotlin
|
||||
* // MODULE: common
|
||||
* expect fun foo(bar: Int = 42)
|
||||
*
|
||||
* // MODULE: platform()(common)
|
||||
* actual fun foo(bar: Int) { ... }
|
||||
* ```
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*
|
||||
* @param index Index of the value parameter to check
|
||||
* @return `true` if a parameter has defined default value, or if there is a default value defined on the expect declaration
|
||||
* for this actual.
|
||||
*/
|
||||
fun FirFunction.itOrExpectHasDefaultParameterValue(index: Int): Boolean =
|
||||
containsDefaultValue(index) || symbol.getSingleExpectForActualOrNull()?.fir?.containsDefaultValue(index) == true
|
||||
|
||||
|
||||
@@ -29,6 +29,15 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.util.WeakPair
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
|
||||
/**
|
||||
* Main operation on the [ConeClassifierLookupTag]
|
||||
*
|
||||
* Lookups the tag into its target within the given [useSiteSession]
|
||||
*
|
||||
* The second step of type refinement, see `/docs/fir/k2_kmp.md`
|
||||
*
|
||||
* @see ConeClassifierLookupTag
|
||||
*/
|
||||
fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): FirClassifierSymbol<*>? =
|
||||
when (this) {
|
||||
is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
|
||||
@@ -37,6 +46,9 @@ fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): FirClassifierS
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* @see toSymbol
|
||||
*/
|
||||
@OptIn(LookupTagInternals::class)
|
||||
fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSymbol<*>? {
|
||||
if (this is ConeClassLookupTagWithFixedSymbol) {
|
||||
@@ -49,6 +61,9 @@ fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSym
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see toSymbol
|
||||
*/
|
||||
fun ConeClassLikeLookupTag.toFirRegularClassSymbol(session: FirSession): FirRegularClassSymbol? =
|
||||
toSymbol(session) as? FirRegularClassSymbol
|
||||
|
||||
|
||||
@@ -19,6 +19,17 @@ import org.jetbrains.kotlin.util.WeakPair
|
||||
import org.jetbrains.kotlin.util.component1
|
||||
import org.jetbrains.kotlin.util.component2
|
||||
|
||||
/**
|
||||
* Compute the recursive type-alias expansion in the given type.
|
||||
*
|
||||
* A type of an expect class, that is actualized by a typealias will be expanded to the expansion of the typealias,
|
||||
* when supplied with the session of actual.
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*
|
||||
* @param useSiteSession Session to be used for classifier lookups, see [toSymbol]
|
||||
* @return Type, that is expanded to the concrete class type w.r.t to the [useSiteSession]
|
||||
*/
|
||||
fun ConeClassLikeType.fullyExpandedType(
|
||||
useSiteSession: FirSession,
|
||||
expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = { alias ->
|
||||
@@ -40,6 +51,9 @@ fun ConeClassLikeType.fullyExpandedType(
|
||||
return fullyExpandedTypeNoCache(useSiteSession, expandedConeType)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see fullyExpandedType
|
||||
*/
|
||||
fun ConeKotlinType.fullyExpandedType(
|
||||
useSiteSession: FirSession
|
||||
): ConeKotlinType = when (this) {
|
||||
@@ -50,6 +64,9 @@ fun ConeKotlinType.fullyExpandedType(
|
||||
else -> this
|
||||
}
|
||||
|
||||
/**
|
||||
* @see fullyExpandedType
|
||||
*/
|
||||
fun ConeSimpleKotlinType.fullyExpandedType(
|
||||
useSiteSession: FirSession
|
||||
): ConeSimpleKotlinType = when (this) {
|
||||
@@ -167,6 +184,9 @@ private fun mapTypeAliasArguments(
|
||||
return substitutor.substituteOrSelf(resultingType)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see fullyExpandedType
|
||||
*/
|
||||
fun FirTypeAlias.fullyExpandedConeType(useSiteSession: FirSession): ConeClassLikeType? {
|
||||
return expandedConeType?.fullyExpandedType(useSiteSession)
|
||||
}
|
||||
|
||||
+8
@@ -31,6 +31,14 @@ class FirExpectActualMatcherProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This transformer populates [expectForActual] mapping for actual declarations.
|
||||
* Also, populates it [memberExpectForActual] mapping
|
||||
*
|
||||
* Should run before any kind of body resolution, since [expectForActual] is used there.
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
open class FirExpectActualMatcherTransformer(
|
||||
final override val session: FirSession,
|
||||
private val scopeSession: ScopeSession,
|
||||
|
||||
@@ -17,12 +17,27 @@ private object ExpectForActualAttributeKey : FirDeclarationDataKey()
|
||||
|
||||
typealias ExpectForActualData = Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<FirBasedSymbol<*>>>
|
||||
|
||||
/**
|
||||
* Actual declaration -> (many) expect declaration mapping. For top-level declarations.
|
||||
*
|
||||
* Populated by [FirResolvePhase.EXPECT_ACTUAL_MATCHING] phase for every top-level actual declaration.
|
||||
*
|
||||
* **Note: Mapping is computed from the declaration-site session of the actual declaration and not refined on the use-sites**
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
@SymbolInternals
|
||||
var FirDeclaration.expectForActual: ExpectForActualData? by FirDeclarationDataRegistry.data(ExpectForActualAttributeKey)
|
||||
|
||||
/**
|
||||
* @see expectForActual
|
||||
*/
|
||||
fun FirFunctionSymbol<*>.getSingleExpectForActualOrNull(): FirFunctionSymbol<*>? =
|
||||
(this as FirBasedSymbol<*>).getSingleExpectForActualOrNull() as? FirFunctionSymbol<*>
|
||||
|
||||
/**
|
||||
* @see expectForActual
|
||||
*/
|
||||
fun FirBasedSymbol<*>.getSingleExpectForActualOrNull(): FirBasedSymbol<*>? {
|
||||
val expectForActual = expectForActual ?: return null
|
||||
val compatibleOrWeakCompatible: List<FirBasedSymbol<*>> =
|
||||
@@ -30,6 +45,9 @@ fun FirBasedSymbol<*>.getSingleExpectForActualOrNull(): FirBasedSymbol<*>? {
|
||||
return compatibleOrWeakCompatible.singleOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* @see expectForActual
|
||||
*/
|
||||
val FirBasedSymbol<*>.expectForActual: ExpectForActualData?
|
||||
get() {
|
||||
lazyResolveToPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING)
|
||||
@@ -45,4 +63,40 @@ typealias MemberExpectForActualData =
|
||||
Map<Pair</* actual member */ FirBasedSymbol<*>, /* expect class */ FirRegularClassSymbol>,
|
||||
Map</* expect member */ FirBasedSymbol<*>, ExpectActualCompatibility<*>>>
|
||||
|
||||
/**
|
||||
* Actual class + expect class + actual member declaration -> (many) expect member declaration mapping.
|
||||
*
|
||||
* This attribute allows finding complex actualizations through type-aliases.
|
||||
*
|
||||
* ```kotlin
|
||||
* // MODULE: common
|
||||
* expect class A {
|
||||
* fun foo() // expect.1
|
||||
* }
|
||||
* expect class B {
|
||||
* fun foo() // expect.2
|
||||
* }
|
||||
*
|
||||
* // MODULE: platform()(common)
|
||||
*
|
||||
* actual typealias A = Impl
|
||||
* actual typealias B = Impl
|
||||
*
|
||||
* // attribute: memberExpectForActual
|
||||
* // value: {
|
||||
* // (symbol: expect class A, symbol: impl.1) => { symbol: expect.1 => Compatible },
|
||||
* // (symbol: expect class B, symbol: impl.1) => { symbol: expect.2 => Compatible },
|
||||
* // }
|
||||
* class Impl {
|
||||
* fun foo() {} // impl.1
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Populated by [FirResolvePhase.EXPECT_ACTUAL_MATCHING] phase for every top-level class declaration that is either actual class or
|
||||
* expansion of actual type-alias.
|
||||
*
|
||||
* **Note: Mapping is computed from the declaration-site session of the actual declaration and not refined on the use-sites**
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
var FirRegularClass.memberExpectForActual: MemberExpectForActualData? by FirDeclarationDataRegistry.data(MemberExpectForActualAttributeKey)
|
||||
|
||||
+3
@@ -7,6 +7,9 @@ package org.jetbrains.kotlin.fir.symbols
|
||||
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
|
||||
/**
|
||||
* @see ConeClassifierLookupTag
|
||||
*/
|
||||
abstract class ConeClassifierLookupTagWithFixedSymbol : ConeClassifierLookupTag() {
|
||||
abstract val symbol: FirClassifierSymbol<*>
|
||||
}
|
||||
+7
@@ -19,6 +19,13 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
data class IrActualizedResult(val actualizedExpectDeclarations: List<IrDeclaration>)
|
||||
|
||||
/**
|
||||
* IrActualizer is responsible for performing actualization.
|
||||
*
|
||||
* The main action is the replacement of references to expect declarations with corresponding actuals on the IR level.
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md`
|
||||
*/
|
||||
object IrActualizer {
|
||||
fun actualize(
|
||||
mainFragment: IrModuleFragment,
|
||||
|
||||
+6
@@ -23,6 +23,12 @@ import org.jetbrains.kotlin.utils.keysToMap
|
||||
import org.jetbrains.kotlin.utils.zipIfSizesAreEqual
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* This object is responsible for matching and checking of
|
||||
* expect-actual pairs
|
||||
*
|
||||
* See `/docs/fir/k2_kmp.md` for details
|
||||
*/
|
||||
object AbstractExpectActualCompatibilityChecker {
|
||||
fun <T : DeclarationSymbolMarker> getClassifiersCompatibility(
|
||||
expectClassSymbol: RegularClassSymbolMarker,
|
||||
|
||||
Reference in New Issue
Block a user