[Commonizer] Limited annotation commonization (@Deprecated for functions)

^KMM-238
^KMM-53
This commit is contained in:
Dmitriy Dolovov
2020-05-06 17:20:54 +07:00
parent be04fbd5bb
commit 735387b685
16 changed files with 329 additions and 65 deletions
@@ -10,22 +10,16 @@ import org.jetbrains.kotlin.descriptors.ClassKind.ANNOTATION_CLASS
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.utils.concat
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.storage.getValue
class CommonizedAnnotationDescriptor(
private val targetComponents: TargetDeclarationsBuilderComponents,
override val fqName: FqName,
rawValueArguments: Map<Name, ConstantValue<*>>
targetComponents: TargetDeclarationsBuilderComponents,
cirAnnotation: CirAnnotation
) : AnnotationDescriptor {
constructor(targetComponents: TargetDeclarationsBuilderComponents, cirAnnotation: CirAnnotation) : this(
targetComponents,
cirAnnotation.fqName,
cirAnnotation.allValueArguments
)
override val fqName: FqName = cirAnnotation.fqName
override val type by targetComponents.storageManager.createLazyValue {
val annotationClass = findClassOrTypeAlias(targetComponents, fqName)
@@ -36,17 +30,10 @@ class CommonizedAnnotationDescriptor(
}
override val allValueArguments by targetComponents.storageManager.createLazyValue {
rawValueArguments.mapValues { (_, value) -> substituteValueArgument(value) }
cirAnnotation.constantValueArguments concat cirAnnotation.annotationValueArguments.mapValues { (_, nestedCirAnnotation) ->
AnnotationValue(CommonizedAnnotationDescriptor(targetComponents, nestedCirAnnotation))
}
}
override val source: SourceElement get() = SourceElement.NO_SOURCE
private fun substituteValueArgument(value: ConstantValue<*>) =
(value as? AnnotationValue)?.value?.let { nestedAnnotationDescriptor ->
// re-build annotation descriptors
val fqName = nestedAnnotationDescriptor.fqName
?: error("Annotation with no FQ name: ${nestedAnnotationDescriptor::class.java}, $nestedAnnotationDescriptor")
AnnotationValue(CommonizedAnnotationDescriptor(targetComponents, fqName, nestedAnnotationDescriptor.allValueArguments))
} ?: value // keep other values as they are platform agnostic
}
@@ -120,11 +120,8 @@ internal fun CirSimpleType.buildType(
}
}
// TODO: commonize annotations, KT-34234
val typeAnnotations = if (!targetComponents.isCommon) annotations.buildDescriptors(targetComponents) else Annotations.EMPTY
val simpleType = simpleType(
annotations = typeAnnotations,
annotations = annotations.buildDescriptors(targetComponents),
constructor = classifier.typeConstructor,
arguments = arguments.map { it.buildArgument(targetComponents, typeParameterResolver) },
nullable = isMarkedNullable,
@@ -13,7 +13,9 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirFunctionOrPr
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.isNonAbstractMemberInInterface
import org.jetbrains.kotlin.name.Name
abstract class AbstractFunctionOrPropertyCommonizer<T : CirFunctionOrProperty>(cache: CirClassifiersCache) : AbstractStandardCommonizer<T, T>() {
abstract class AbstractFunctionOrPropertyCommonizer<T : CirFunctionOrProperty>(
cache: CirClassifiersCache
) : AbstractStandardCommonizer<T, T>() {
protected lateinit var name: Name
protected val modality = ModalityCommonizer.default()
protected val visibility = VisibilityCommonizer.lowering()
@@ -34,7 +34,7 @@ abstract class AbstractNullableCommonizer<T : Any, R : Any, WT, WR>(
final override fun commonizeWith(next: T?): Boolean {
state = when (state) {
State.ERROR -> State.ERROR
State.ERROR -> return false
State.EMPTY -> next?.let {
wrapped = wrappedCommonizerFactory()
doCommonizeWith(next)
@@ -0,0 +1,209 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.utils.DEPRECATED_ANNOTATION_FQN
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.constants.StringValue
/**
* This is limited implementation of annotations commonizer. It helps to commonize only [kotlin.Deprecated] annotations.
*/
class AnnotationsCommonizer : AbstractStandardCommonizer<List<CirAnnotation>, List<CirAnnotation>>() {
private var deprecatedAnnotationCommonizer: DeprecatedAnnotationCommonizer? = null
override fun commonizationResult(): List<CirAnnotation> {
val deprecatedAnnotation = deprecatedAnnotationCommonizer?.result ?: return emptyList()
return listOf(deprecatedAnnotation)
}
override fun initialize(first: List<CirAnnotation>) = Unit
override fun doCommonizeWith(next: List<CirAnnotation>): Boolean {
val nextDeprecatedAnnotation = next.firstOrNull { it.fqName == DEPRECATED_ANNOTATION_FQN } ?: return true
val deprecatedAnnotationCommonizer = deprecatedAnnotationCommonizer ?: DeprecatedAnnotationCommonizer()
return deprecatedAnnotationCommonizer.commonizeWith(nextDeprecatedAnnotation)
}
}
private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnnotation> {
private var level: DeprecationLevel? = null // null level means that state is empty
private var message: String? = null // null -> message is not equal
private var replaceWithExpression: String? = null // null -> replaceWith is not equal
private var replaceWithImports: List<String>? = null
override val result: CirAnnotation
get() {
if (level == null) throw IllegalCommonizerStateException()
return CirAnnotation.create(
fqName = DEPRECATED_ANNOTATION_FQN,
constantValueArguments = mapOf<Name, ConstantValue<*>>(
PROPERTY_NAME_LEVEL to level!!.toDeprecationLevelValue(),
PROPERTY_NAME_MESSAGE to message.toDeprecationMessageValue()
),
annotationValueArguments = mapOf(
PROPERTY_NAME_REPLACE_WITH to replaceWithExpression.toReplaceWithValue(replaceWithImports)
)
)
}
override fun commonizeWith(next: CirAnnotation): Boolean {
val nextLevel: DeprecationLevel = next.getDeprecationLevel() ?: DeprecationLevel.HIDDEN
val nextMessage: String? = next.getDeprecationMessage()
val nextReplaceWith: CirAnnotation? = next.getReplaceWith()
val nextReplaceWithExpression: String? = nextReplaceWith?.getReplaceWithExpression()
val nextReplaceWithImports: List<String>? = nextReplaceWith?.getReplaceWithImports()
return if (level != null) {
doCommonizeWith(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports)
} else {
// empty, just fill in
initialize(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports)
true
}
}
private fun initialize(
nextLevel: DeprecationLevel,
nextMessage: String?,
nextReplaceWithExpression: String?,
nextReplaceWithImports: List<String>?
) {
level = nextLevel
message = nextMessage
if (nextReplaceWithExpression != null && nextReplaceWithImports != null) {
replaceWithExpression = nextReplaceWithExpression
replaceWithImports = nextReplaceWithImports
}
}
private fun doCommonizeWith(
nextLevel: DeprecationLevel,
nextMessage: String?,
nextReplaceWithExpression: String?,
nextReplaceWithImports: List<String>?
): Boolean {
if (nextLevel.ordinal > level!!.ordinal)
level = nextLevel
if (nextMessage != message)
message = null
if (nextReplaceWithExpression != replaceWithExpression || nextReplaceWithImports != replaceWithImports) {
replaceWithExpression = null
replaceWithImports = null
}
return true
}
@Suppress("NOTHING_TO_INLINE")
companion object {
private val PROPERTY_NAME_MESSAGE = Name.identifier(Deprecated::message.name)
private val PROPERTY_NAME_REPLACE_WITH = Name.identifier(Deprecated::replaceWith.name)
private val PROPERTY_NAME_LEVEL = Name.identifier(Deprecated::level.name)
private val PROPERTY_NAME_EXPRESSION = Name.identifier(ReplaceWith::expression.name)
private val PROPERTY_NAME_IMPORTS = Name.identifier(ReplaceWith::imports.name)
// Optimization: Keep most frequently used message constants.
private val FREQUENTLY_USED_MESSAGE_VALUES: Map<String, StringValue> = listOf(
"Use constructor instead",
"Use factory method instead"
).associateWith { StringValue(it) }
private val FALLBACK_MESSAGE_VALUE = StringValue("See actual declarations for concrete deprecation messages")
private val DEPRECATION_LEVEL_FQN = FqName(DeprecationLevel::class.java.name)
private val DEPRECATION_LEVEL_CLASS_ID = ClassId.topLevel(DEPRECATION_LEVEL_FQN)
// Optimization: Keep DeprecationLevel enum constants.
private val DEPRECATION_LEVEL_ENUM_ENTRY_VALUES: Map<String, EnumValue> = DeprecationLevel.values().associate {
it.name to EnumValue(DEPRECATION_LEVEL_CLASS_ID, Name.identifier(it.name))
}
private val REPLACE_WITH_FQN = FqName(ReplaceWith::class.java.name)
// Optimization: Keep empty ReplaceWith instance of CirAnnotation.
private val EMPTY_REPLACE_WITH_CIR_ANNOTATION = createReplaceWithAnnotation("", emptyList())
private fun CirAnnotation.getDeprecationMessage(): String? = constantValueArguments.getString(PROPERTY_NAME_MESSAGE)
private fun String?.toDeprecationMessageValue(): StringValue =
if (this == null)
FALLBACK_MESSAGE_VALUE
else
FREQUENTLY_USED_MESSAGE_VALUES[this] ?: StringValue(this)
private fun CirAnnotation.getDeprecationLevel(): DeprecationLevel? {
val enumEntryName = constantValueArguments.getEnumEntryName(PROPERTY_NAME_LEVEL) ?: return null
return DeprecationLevel.values().firstOrNull { it.name == enumEntryName }
}
private fun DeprecationLevel.toDeprecationLevelValue(): EnumValue =
DEPRECATION_LEVEL_ENUM_ENTRY_VALUES.getValue(name)
private fun CirAnnotation.getReplaceWith(): CirAnnotation? =
annotationValueArguments.getAnnotation(PROPERTY_NAME_REPLACE_WITH)
private fun CirAnnotation.getReplaceWithExpression(): String? =
constantValueArguments.getString(PROPERTY_NAME_EXPRESSION)
private fun CirAnnotation.getReplaceWithImports(): List<String>? =
constantValueArguments.getStringArray(PROPERTY_NAME_IMPORTS)
private fun String?.toReplaceWithValue(imports: List<String>?): CirAnnotation =
if (this == null || imports == null)
EMPTY_REPLACE_WITH_CIR_ANNOTATION
else
createReplaceWithAnnotation(this, imports)
private inline fun Map<Name, ConstantValue<*>>.getString(name: Name): String? =
(this[name] as? StringValue)?.value
private inline fun Map<Name, ConstantValue<*>>.getEnumEntryName(name: Name): String? =
(this[name] as? EnumValue)?.enumEntryName?.asString()
private inline fun Map<Name, CirAnnotation>.getAnnotation(name: Name): CirAnnotation? =
this[name]
private inline fun Map<Name, ConstantValue<*>>.getStringArray(name: Name): List<String>? {
val elements: List<ConstantValue<*>> = (this[name] as? ArrayValue)?.value ?: return null
if (elements.isEmpty()) return emptyList()
val result = mutableListOf<String>()
for (element in elements) {
if (element is StringValue) {
result += element.value
} else
return null
}
return result
}
private inline fun createReplaceWithAnnotation(expression: String, imports: List<String>): CirAnnotation =
CirAnnotation.create(
fqName = REPLACE_WITH_FQN,
constantValueArguments = mapOf(
PROPERTY_NAME_EXPRESSION to StringValue(expression),
PROPERTY_NAME_IMPORTS to ArrayValue(
value = imports.map { StringValue(it) },
computeType = { it.builtIns.getArrayElementType(it.builtIns.stringType) }
)
),
annotationValueArguments = emptyMap()
)
}
}
@@ -26,13 +26,15 @@ abstract class AbstractStandardCommonizer<T, R> : Commonizer<T, R> {
}
final override fun commonizeWith(next: T): Boolean {
if (state == State.ERROR)
return false
val result = when (state) {
State.ERROR -> return false
State.EMPTY -> {
initialize(next)
doCommonizeWith(next)
}
State.IN_PROGRESS -> doCommonizeWith(next)
}
if (state == State.EMPTY)
initialize(next)
val result = doCommonizeWith(next)
state = if (!result) State.ERROR else State.IN_PROGRESS
return result
@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirCommonFuncti
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirFunction
class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirFunction>(cache) {
private val annotations = AnnotationsCommonizer()
private val modifiers = FunctionModifiersCommonizer.default()
private val valueParameters = ValueParameterListCommonizer.default(cache)
private var hasStableParameterNames = true
private var hasSynthesizedParameterNames = false
override fun commonizationResult() = CirCommonFunction(
annotations = annotations.result,
name = name,
modality = modality.result,
visibility = visibility.result,
@@ -31,6 +33,7 @@ class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropert
override fun doCommonizeWith(next: CirFunction): Boolean {
val result = super.doCommonizeWith(next)
&& annotations.commonizeWith(next.annotations)
&& modifiers.commonizeWith(next)
&& valueParameters.commonizeWith(next.valueParameters)
@@ -13,24 +13,17 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.*
class CirAnnotation private constructor(original: AnnotationDescriptor) {
val fqName: FqName = original.fqName?.intern() ?: error("Annotation with no FQ name: ${original::class.java}, $original")
val allValueArguments: Map<Name, ConstantValue<*>> = original.allValueArguments.mapKeys { it.key.intern() }
init {
allValueArguments.forEach { (name, constantValue) ->
checkConstantSupportedInCommonization(
constantValue = constantValue,
constantName = name,
owner = original
)
}
}
class CirAnnotation private constructor(
val fqName: FqName,
val constantValueArguments: Map<Name, ConstantValue<*>>,
val annotationValueArguments: Map<Name, CirAnnotation>
) {
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
private var cachedHashCode = 0
private fun computeHashCode() = hashCode(fqName).appendHashCode(allValueArguments)
private fun computeHashCode() = hashCode(fqName)
.appendHashCode(constantValueArguments)
.appendHashCode(annotationValueArguments)
override fun hashCode(): Int {
var currentHashCode = cachedHashCode
@@ -41,15 +34,61 @@ class CirAnnotation private constructor(original: AnnotationDescriptor) {
return currentHashCode
}
override fun equals(other: Any?): Boolean = when {
other === this -> true
other is CirAnnotation -> fqName == other.fqName && allValueArguments == other.allValueArguments
else -> false
override fun equals(other: Any?): Boolean {
if (other === this) return true
return other is CirAnnotation
&& fqName == other.fqName
&& constantValueArguments == other.constantValueArguments
&& annotationValueArguments == other.annotationValueArguments
}
companion object {
private val interner = Interner<CirAnnotation>()
fun create(original: AnnotationDescriptor): CirAnnotation = interner.intern(CirAnnotation(original))
fun create(original: AnnotationDescriptor): CirAnnotation {
val fqName: FqName = original.fqName?.intern() ?: error("Annotation with no FQ name: ${original::class.java}, $original")
val allValueArguments: Map<Name, ConstantValue<*>> = original.allValueArguments
if (allValueArguments.isEmpty())
return create(fqName = fqName, constantValueArguments = emptyMap(), annotationValueArguments = emptyMap())
val constantValueArguments: MutableMap<Name, ConstantValue<*>> = HashMap()
val annotationValueArguments: MutableMap<Name, CirAnnotation> = HashMap()
allValueArguments.forEach { (name, constantValue) ->
checkConstantSupportedInCommonization(
constantValue = constantValue,
constantName = name,
owner = original,
allowAnnotationValues = true
)
if (constantValue is AnnotationValue)
annotationValueArguments[name.intern()] = create(original = constantValue.value)
else
constantValueArguments[name.intern()] = constantValue
}
return create(
fqName = fqName,
constantValueArguments = constantValueArguments,
annotationValueArguments = annotationValueArguments
)
}
fun create(
fqName: FqName,
constantValueArguments: Map<Name, ConstantValue<*>>,
annotationValueArguments: Map<Name, CirAnnotation>
): CirAnnotation {
return interner.intern(
CirAnnotation(
fqName = fqName,
constantValueArguments = constantValueArguments,
annotationValueArguments = annotationValueArguments
)
)
}
}
}
@@ -40,7 +40,7 @@ data class CirCommonClass(
override val isInline: Boolean,
override val isInner: Boolean
) : CirClass {
override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
override val annotations: List<CirAnnotation> get() = emptyList()
override val isData get() = false
override val isExternal get() = false
override var companion: FqName? = null
@@ -56,7 +56,7 @@ data class CirCommonClassConstructor(
override val hasStableParameterNames: Boolean,
override val hasSynthesizedParameterNames: Boolean
) : CirClassConstructor {
override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
override val annotations: List<CirAnnotation> get() = emptyList()
override val containingClassKind get() = unsupported()
override val containingClassModality get() = unsupported()
override val containingClassIsData get() = unsupported()
@@ -30,6 +30,7 @@ interface CirCallableMemberWithParameters {
interface CirFunction : CirFunctionOrProperty, CirFunctionModifiers, CirCallableMemberWithParameters
data class CirCommonFunction(
override val annotations: List<CirAnnotation>,
override val name: Name,
override val modality: Modality,
override val visibility: Visibility,
@@ -9,7 +9,8 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirExtensionReceiver.Companion.toReceiver
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration, CirDeclarationWithTypeParameters, CirDeclarationWithVisibility, CirDeclarationWithModality, CirMaybeCallableMemberOfClass {
interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration, CirDeclarationWithTypeParameters,
CirDeclarationWithVisibility, CirDeclarationWithModality, CirMaybeCallableMemberOfClass {
val isExternal: Boolean
val extensionReceiver: CirExtensionReceiver?
val returnType: CirType
@@ -17,7 +18,6 @@ interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration,
}
abstract class CirCommonFunctionOrProperty : CirFunctionOrProperty {
final override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
final override val containingClassKind: ClassKind? get() = unsupported()
final override val containingClassModality: Modality? get() = unsupported()
final override val containingClassIsData: Boolean? get() = unsupported()
@@ -50,8 +50,12 @@ data class CirExtensionReceiver(
val type: CirType
) {
companion object {
fun CirType.toReceiverNoAnnotations() = CirExtensionReceiver( /* TODO: commonize annotations, KT-34234 */ emptyList(), this)
fun ReceiverParameterDescriptor.toReceiver() = CirExtensionReceiver(annotations.map(CirAnnotation.Companion::create), CirType.create(type))
fun CirType.toReceiverNoAnnotations() = CirExtensionReceiver(annotations = emptyList(), type = this)
fun ReceiverParameterDescriptor.toReceiver() = CirExtensionReceiver(
annotations = annotations.map(CirAnnotation.Companion::create),
type = CirType.create(type)
)
}
}
@@ -36,6 +36,7 @@ data class CirCommonProperty(
override val setter: CirSetter?,
override val typeParameters: List<CirTypeParameter>
) : CirCommonFunctionOrProperty(), CirProperty {
override val annotations: List<CirAnnotation> get() = emptyList()
override val isVar get() = setter != null
override val isLateInit get() = false
override val isConst get() = false
@@ -7,11 +7,8 @@ package org.jetbrains.kotlin.descriptors.commonizer.utils
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.getAbbreviation
private val DEPRECATED_ANNOTATION_FQN = FqName(Deprecated::class.java.name)
internal fun SimpleFunctionDescriptor.isKniBridgeFunction() =
name.asString().startsWith("kniBridge")
@@ -12,11 +12,13 @@ internal fun checkConstantSupportedInCommonization(
constantValue: ConstantValue<*>,
constantName: Name? = null,
owner: Any,
allowAnnotationValues: Boolean = false,
onError: (String) -> Nothing = ::error
) {
checkConstantSupportedInCommonization(
constantValue = constantValue,
location = { "${owner::class.java}, $owner" + constantName?.asString()?.let { "[$it]" } },
allowAnnotationValues = allowAnnotationValues,
onError = onError
)
}
@@ -24,6 +26,7 @@ internal fun checkConstantSupportedInCommonization(
private fun checkConstantSupportedInCommonization(
constantValue: ConstantValue<*>,
location: () -> String,
allowAnnotationValues: Boolean,
onError: (String) -> Nothing
) {
@Suppress("TrailingComma")
@@ -36,21 +39,28 @@ private fun checkConstantSupportedInCommonization(
is DoubleValue,
is FloatValue,
is EnumValue -> {
// OK
return // OK
}
is AnnotationValue -> {
if (constantValue.value.fqName?.isUnderStandardKotlinPackages != true)
onError("Only ${constantValue::class.java} const values from Kotlin standard packages are supported, $constantValue at ${location()}")
if (allowAnnotationValues) {
if (constantValue.value.fqName?.isUnderStandardKotlinPackages != true)
onError("Only ${constantValue::class.java} const values from Kotlin standard packages are supported, $constantValue at ${location()}")
return // OK
} // else fail (see below)
}
is ArrayValue -> {
constantValue.value.forEachIndexed { index, innerConstantValue ->
checkConstantSupportedInCommonization(
constantValue = innerConstantValue,
location = { "${location()}[$index]" },
allowAnnotationValues = allowAnnotationValues,
onError = onError
)
}
return // OK
}
else -> onError("Unsupported const value type: ${constantValue::class.java}, $constantValue at ${location()}")
}
onError("Unsupported const value type: ${constantValue::class.java}, $constantValue at ${location()}")
}
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name)
private val STANDARD_KOTLIN_PACKAGE_PREFIXES = listOf(
KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString(),
"kotlinx"
@@ -13,6 +13,16 @@ internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
return result
}
internal infix fun <K, V> Map<K, V>.concat(other: Map<K, V>): Map<K, V> =
when {
isEmpty() -> other
other.isEmpty() -> this
else -> HashMap<K, V>(size + other.size, 1F).apply {
putAll(this@concat)
putAll(other)
}
}
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
internal fun Any?.isNull(): Boolean = this == null