[Commonizer] Allow rewriting callables names to succeed commonization
^KT-34602
This commit is contained in:
+2
-2
@@ -52,8 +52,8 @@ interface CirHasTypeParameters {
|
||||
}
|
||||
|
||||
interface CirCallableMemberWithParameters {
|
||||
val valueParameters: List<CirValueParameter>
|
||||
val hasStableParameterNames: Boolean
|
||||
var valueParameters: List<CirValueParameter>
|
||||
var hasStableParameterNames: Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ data class CirClassConstructorImpl(
|
||||
override val typeParameters: List<CirTypeParameter>,
|
||||
override val visibility: Visibility,
|
||||
override val containingClassDetails: CirContainingClassDetails,
|
||||
override val valueParameters: List<CirValueParameter>,
|
||||
override val hasStableParameterNames: Boolean,
|
||||
override var valueParameters: List<CirValueParameter>,
|
||||
override var hasStableParameterNames: Boolean,
|
||||
override val isPrimary: Boolean,
|
||||
override val kind: CallableMemberDescriptor.Kind
|
||||
) : CirClassConstructor
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ data class CirFunctionImpl(
|
||||
override val visibility: Visibility,
|
||||
override val modality: Modality,
|
||||
override val containingClassDetails: CirContainingClassDetails?,
|
||||
override val valueParameters: List<CirValueParameter>,
|
||||
override val hasStableParameterNames: Boolean,
|
||||
override var valueParameters: List<CirValueParameter>,
|
||||
override var hasStableParameterNames: Boolean,
|
||||
override val extensionReceiver: CirExtensionReceiver?,
|
||||
override val returnType: CirType,
|
||||
override val kind: CallableMemberDescriptor.Kind,
|
||||
|
||||
+5
@@ -51,4 +51,9 @@ abstract class AbstractListCommonizer<T, R>(
|
||||
|
||||
return !error
|
||||
}
|
||||
|
||||
protected fun forEachSingleElementCommonizer(action: (index: Int, Commonizer<T, R>) -> Unit) {
|
||||
val commonizers = commonizers ?: failInEmptyState()
|
||||
commonizers.forEachIndexed(action)
|
||||
}
|
||||
}
|
||||
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 com.intellij.util.containers.FactoryMap
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirCallableMemberWithParameters
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClassifierId
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirHasAnnotations
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirValueParameter
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirValueParameterFactory
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.CallableValueParametersCommonizer.CallableToPatch.Companion.doNothing
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.CallableValueParametersCommonizer.CallableToPatch.Companion.patchCallables
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCache
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.isObjCInteropCallableAnnotation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class CallableValueParametersCommonizer(
|
||||
cache: CirClassifiersCache
|
||||
) : Commonizer<CirCallableMemberWithParameters, CallableValueParametersCommonizer.Result> {
|
||||
class Result(
|
||||
val hasStableParameterNames: Boolean,
|
||||
val valueParameters: List<CirValueParameter>,
|
||||
val patchCallables: () -> Unit
|
||||
)
|
||||
|
||||
private class CallableToPatch(
|
||||
val callable: CirCallableMemberWithParameters,
|
||||
val originalNames: ValueParameterNames
|
||||
) {
|
||||
init {
|
||||
check(originalNames is ValueParameterNames.Generated || originalNames is ValueParameterNames.Real)
|
||||
}
|
||||
|
||||
val canNamesBeOverwritten by lazy { callable.canNamesBeOverwritten() }
|
||||
|
||||
companion object {
|
||||
fun doNothing(): () -> Unit = {}
|
||||
|
||||
fun List<CallableToPatch>.patchCallables(generated: Boolean, newNames: List<Name>): () -> Unit {
|
||||
val callablesToPatch = filter { it.originalNames is ValueParameterNames.Generated == generated }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?: return doNothing()
|
||||
|
||||
return {
|
||||
callablesToPatch.forEach { callableToPatch ->
|
||||
val callable = callableToPatch.callable
|
||||
callable.hasStableParameterNames = false
|
||||
callable.valueParameters = callable.valueParameters.mapIndexed { index, valueParameter ->
|
||||
val newName = newNames[index]
|
||||
if (valueParameter.name != newName) {
|
||||
CirValueParameterFactory.create(
|
||||
annotations = valueParameter.annotations,
|
||||
name = newName,
|
||||
returnType = valueParameter.returnType,
|
||||
varargElementType = valueParameter.varargElementType,
|
||||
declaresDefaultValue = valueParameter.declaresDefaultValue,
|
||||
isCrossinline = valueParameter.isCrossinline,
|
||||
isNoinline = valueParameter.isNoinline
|
||||
)
|
||||
} else valueParameter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ValueParameterNames {
|
||||
object Generated : ValueParameterNames()
|
||||
|
||||
data class Real(val names: List<Name>) : ValueParameterNames()
|
||||
|
||||
class MultipleReal(valueParameters: List<CirValueParameter>) : ValueParameterNames() {
|
||||
val generatedNames: List<Name> = generatedNames(valueParameters)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun buildFor(callable: CirCallableMemberWithParameters): ValueParameterNames {
|
||||
val valueParameters = callable.valueParameters
|
||||
if (valueParameters.isEmpty())
|
||||
return Real(emptyList())
|
||||
|
||||
var real = false
|
||||
val names = callable.valueParameters.mapIndexed { index, valueParameter ->
|
||||
val name = valueParameter.name
|
||||
val plainName = name.asString()
|
||||
|
||||
if (valueParameter.varargElementType != null) {
|
||||
if (plainName != VARIADIC_ARGUMENTS) {
|
||||
real = true
|
||||
}
|
||||
} else {
|
||||
if (!plainName.startsWith(REGULAR_ARGUMENT_PREFIX)
|
||||
|| index.toString() != plainName.substring(REGULAR_ARGUMENT_PREFIX.length)
|
||||
) {
|
||||
real = true
|
||||
}
|
||||
}
|
||||
|
||||
name
|
||||
}
|
||||
|
||||
return if (real) Real(names) else Generated
|
||||
}
|
||||
|
||||
fun generatedNames(valueParameters: List<CirValueParameter>): List<Name> =
|
||||
valueParameters.mapIndexed { index, valueParameter ->
|
||||
if (valueParameter.varargElementType != null) {
|
||||
VARIADIC_ARGUMENTS_NAME
|
||||
} else {
|
||||
REGULAR_ARGUMENT_NAMES.getValue(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val valueParameters = ValueParameterListCommonizer(cache)
|
||||
private val callables: MutableList<CallableToPatch> = mutableListOf()
|
||||
private var hasStableParameterNames = true
|
||||
private var valueParameterNames: ValueParameterNames? = null
|
||||
private var error = false
|
||||
|
||||
override val result: Result
|
||||
get() {
|
||||
// don't inline `patchCallables` property;
|
||||
// valueParameters.overwriteNames() should be called strongly before valueParameters.result
|
||||
val patchCallables = when (val valueParameterNames = checkState(valueParameterNames, error)) {
|
||||
ValueParameterNames.Generated -> doNothing()
|
||||
is ValueParameterNames.Real -> {
|
||||
val newNames = valueParameterNames.names
|
||||
valueParameters.overwriteNames(newNames)
|
||||
callables.patchCallables(generated = true, newNames)
|
||||
}
|
||||
is ValueParameterNames.MultipleReal -> {
|
||||
val generatedNames = valueParameterNames.generatedNames
|
||||
valueParameters.overwriteNames(generatedNames)
|
||||
callables.patchCallables(generated = false, generatedNames)
|
||||
}
|
||||
}
|
||||
|
||||
return Result(
|
||||
hasStableParameterNames = hasStableParameterNames,
|
||||
valueParameters = valueParameters.result,
|
||||
patchCallables = patchCallables
|
||||
)
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: CirCallableMemberWithParameters): Boolean {
|
||||
if (error)
|
||||
return false
|
||||
|
||||
error = !valueParameters.commonizeWith(next.valueParameters)
|
||||
|| !commonizeValueParameterNames(next)
|
||||
|
||||
return !error
|
||||
}
|
||||
|
||||
private fun commonizeValueParameterNames(next: CirCallableMemberWithParameters): Boolean {
|
||||
val nextNames = ValueParameterNames.buildFor(next)
|
||||
val nextCallable = CallableToPatch(next, nextNames)
|
||||
|
||||
valueParameterNames = when (val currentNames = valueParameterNames) {
|
||||
null -> {
|
||||
when (nextNames) {
|
||||
ValueParameterNames.Generated,
|
||||
is ValueParameterNames.Real -> {
|
||||
hasStableParameterNames = next.hasStableParameterNames
|
||||
}
|
||||
else -> failIllegalState(currentNames, nextNames)
|
||||
}
|
||||
nextNames
|
||||
}
|
||||
ValueParameterNames.Generated -> {
|
||||
@Suppress("LiftReturnOrAssignment")
|
||||
when (nextNames) {
|
||||
ValueParameterNames.Generated -> {
|
||||
hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames
|
||||
}
|
||||
is ValueParameterNames.Real -> {
|
||||
if (callables.any { !it.canNamesBeOverwritten }) return false
|
||||
hasStableParameterNames = false
|
||||
}
|
||||
else -> failIllegalState(currentNames, nextNames)
|
||||
}
|
||||
nextNames
|
||||
}
|
||||
is ValueParameterNames.Real -> {
|
||||
when (nextNames) {
|
||||
ValueParameterNames.Generated -> {
|
||||
if (!nextCallable.canNamesBeOverwritten) return false
|
||||
hasStableParameterNames = false
|
||||
currentNames
|
||||
}
|
||||
is ValueParameterNames.Real -> {
|
||||
if (nextNames == currentNames) {
|
||||
hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames
|
||||
currentNames
|
||||
} else {
|
||||
if (callables.any { !it.canNamesBeOverwritten } || !nextCallable.canNamesBeOverwritten) return false
|
||||
hasStableParameterNames = false
|
||||
ValueParameterNames.MultipleReal(nextCallable.callable.valueParameters)
|
||||
}
|
||||
}
|
||||
else -> failIllegalState(currentNames, nextNames)
|
||||
}
|
||||
}
|
||||
is ValueParameterNames.MultipleReal -> {
|
||||
if (!nextCallable.canNamesBeOverwritten) return false
|
||||
currentNames
|
||||
}
|
||||
}
|
||||
|
||||
callables += nextCallable
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val VARIADIC_ARGUMENTS = "variadicArguments"
|
||||
private const val REGULAR_ARGUMENT_PREFIX = "arg"
|
||||
|
||||
private val VARIADIC_ARGUMENTS_NAME = Name.identifier(VARIADIC_ARGUMENTS).intern()
|
||||
private val REGULAR_ARGUMENT_NAMES = FactoryMap.create<Int, Name> { index ->
|
||||
Name.identifier(REGULAR_ARGUMENT_PREFIX + index).intern()
|
||||
}
|
||||
|
||||
private fun CirCallableMemberWithParameters.canNamesBeOverwritten(): Boolean {
|
||||
return (this as CirHasAnnotations).annotations.none { annotation ->
|
||||
(annotation.type.classifierId as? CirClassifierId.ClassOrTypeAlias)?.classId?.isObjCInteropCallableAnnotation == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun failIllegalState(current: ValueParameterNames?, next: ValueParameterNames): Nothing =
|
||||
throw IllegalCommonizerStateException("unexpected next state $next with current state $current")
|
||||
}
|
||||
}
|
||||
+18
-20
@@ -17,19 +17,23 @@ class ClassConstructorCommonizer(cache: CirClassifiersCache) : AbstractStandardC
|
||||
private lateinit var kind: CallableMemberDescriptor.Kind
|
||||
private val visibility = VisibilityCommonizer.equalizing()
|
||||
private val typeParameters = TypeParameterListCommonizer(cache)
|
||||
private val valueParameters = ValueParameterListCommonizer(cache)
|
||||
private var hasStableParameterNames = true
|
||||
private val valueParameters = CallableValueParametersCommonizer(cache)
|
||||
|
||||
override fun commonizationResult() = CirClassConstructorFactory.create(
|
||||
annotations = emptyList(),
|
||||
typeParameters = typeParameters.result,
|
||||
visibility = visibility.result,
|
||||
containingClassDetails = CirContainingClassDetailsFactory.DOES_NOT_MATTER,
|
||||
valueParameters = valueParameters.result,
|
||||
hasStableParameterNames = hasStableParameterNames,
|
||||
isPrimary = isPrimary,
|
||||
kind = kind
|
||||
)
|
||||
override fun commonizationResult(): CirClassConstructor {
|
||||
val valueParameters = valueParameters.result
|
||||
valueParameters.patchCallables()
|
||||
|
||||
return CirClassConstructorFactory.create(
|
||||
annotations = emptyList(),
|
||||
typeParameters = typeParameters.result,
|
||||
visibility = visibility.result,
|
||||
containingClassDetails = CirContainingClassDetailsFactory.DOES_NOT_MATTER,
|
||||
valueParameters = valueParameters.valueParameters,
|
||||
hasStableParameterNames = valueParameters.hasStableParameterNames,
|
||||
isPrimary = isPrimary,
|
||||
kind = kind
|
||||
)
|
||||
}
|
||||
|
||||
override fun initialize(first: CirClassConstructor) {
|
||||
isPrimary = first.isPrimary
|
||||
@@ -37,18 +41,12 @@ class ClassConstructorCommonizer(cache: CirClassifiersCache) : AbstractStandardC
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirClassConstructor): Boolean {
|
||||
val result = !next.containingClassDetails.kind.isSingleton // don't commonize constructors for objects and enum entries
|
||||
return !next.containingClassDetails.kind.isSingleton // don't commonize constructors for objects and enum entries
|
||||
&& next.containingClassDetails.modality != Modality.SEALED // don't commonize constructors for sealed classes (not not their subclasses)
|
||||
&& isPrimary == next.isPrimary
|
||||
&& kind == next.kind
|
||||
&& visibility.commonizeWith(next)
|
||||
&& typeParameters.commonizeWith(next.typeParameters)
|
||||
&& valueParameters.commonizeWith(next.valueParameters)
|
||||
|
||||
if (result) {
|
||||
hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames
|
||||
}
|
||||
|
||||
return result
|
||||
&& valueParameters.commonizeWith(next)
|
||||
}
|
||||
}
|
||||
|
||||
+22
-24
@@ -12,34 +12,32 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCach
|
||||
class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirFunction>(cache) {
|
||||
private val annotations = AnnotationsCommonizer()
|
||||
private val modifiers = FunctionModifiersCommonizer()
|
||||
private val valueParameters = ValueParameterListCommonizer(cache)
|
||||
private var hasStableParameterNames = true
|
||||
private val valueParameters = CallableValueParametersCommonizer(cache)
|
||||
|
||||
override fun commonizationResult() = CirFunctionFactory.create(
|
||||
annotations = annotations.result,
|
||||
name = name,
|
||||
typeParameters = typeParameters.result,
|
||||
visibility = visibility.result,
|
||||
modality = modality.result,
|
||||
containingClassDetails = null,
|
||||
valueParameters = valueParameters.result,
|
||||
hasStableParameterNames = hasStableParameterNames,
|
||||
extensionReceiver = extensionReceiver.result,
|
||||
returnType = returnType.result,
|
||||
kind = kind,
|
||||
modifiers = modifiers.result
|
||||
)
|
||||
override fun commonizationResult(): CirFunction {
|
||||
val valueParameters = valueParameters.result
|
||||
valueParameters.patchCallables()
|
||||
|
||||
return CirFunctionFactory.create(
|
||||
annotations = annotations.result,
|
||||
name = name,
|
||||
typeParameters = typeParameters.result,
|
||||
visibility = visibility.result,
|
||||
modality = modality.result,
|
||||
containingClassDetails = null,
|
||||
valueParameters = valueParameters.valueParameters,
|
||||
hasStableParameterNames = valueParameters.hasStableParameterNames,
|
||||
extensionReceiver = extensionReceiver.result,
|
||||
returnType = returnType.result,
|
||||
kind = kind,
|
||||
modifiers = modifiers.result
|
||||
)
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirFunction): Boolean {
|
||||
val result = super.doCommonizeWith(next)
|
||||
return super.doCommonizeWith(next)
|
||||
&& annotations.commonizeWith(next.annotations)
|
||||
&& modifiers.commonizeWith(next.modifiers)
|
||||
&& valueParameters.commonizeWith(next.valueParameters)
|
||||
|
||||
if (result) {
|
||||
hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames
|
||||
}
|
||||
|
||||
return result
|
||||
&& valueParameters.commonizeWith(next)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -39,7 +39,6 @@ class ValueParameterCommonizer(cache: CirClassifiersCache) : AbstractStandardCom
|
||||
override fun doCommonizeWith(next: CirValueParameter): Boolean {
|
||||
val result = !next.declaresDefaultValue
|
||||
&& varargElementType.isNull() == next.varargElementType.isNull()
|
||||
&& name == next.name
|
||||
&& returnType.commonizeWith(next.returnType)
|
||||
|
||||
if (result) {
|
||||
@@ -49,4 +48,8 @@ class ValueParameterCommonizer(cache: CirClassifiersCache) : AbstractStandardCom
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun overwriteName(name: Name) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -7,7 +7,14 @@ package org.jetbrains.kotlin.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirValueParameter
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCache
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class ValueParameterListCommonizer(cache: CirClassifiersCache) : AbstractListCommonizer<CirValueParameter, CirValueParameter>(
|
||||
singleElementCommonizerFactory = { ValueParameterCommonizer(cache) }
|
||||
)
|
||||
) {
|
||||
fun overwriteNames(names: List<Name>) {
|
||||
forEachSingleElementCommonizer { index, singleElementCommonizer ->
|
||||
(singleElementCommonizer as ValueParameterCommonizer).overwriteName(names[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -28,21 +28,21 @@ data class PropertyApproximationKey(
|
||||
/** Used for approximation of [SimpleFunctionDescriptor]s before running concrete [Commonizer]s */
|
||||
data class FunctionApproximationKey(
|
||||
val name: Name,
|
||||
val valueParameters: List<Pair<Name, CirTypeSignature>>,
|
||||
val valueParameters: List<CirTypeSignature>,
|
||||
val extensionReceiverParameter: CirTypeSignature?
|
||||
) {
|
||||
constructor(function: SimpleFunctionDescriptor) : this(
|
||||
function.name.intern(),
|
||||
function.valueParameters.map { it.name.intern() to it.type.signature },
|
||||
function.valueParameters.map { it.type.signature },
|
||||
function.extensionReceiverParameter?.type?.signature
|
||||
)
|
||||
}
|
||||
|
||||
/** Used for approximation of [ConstructorDescriptor]s before running concrete [Commonizer]s */
|
||||
data class ConstructorApproximationKey(
|
||||
val valueParameters: List<Pair<Name, CirTypeSignature>>
|
||||
val valueParameters: List<CirTypeSignature>
|
||||
) {
|
||||
constructor(constructor: ConstructorDescriptor) : this(
|
||||
constructor.valueParameters.map { it.name.intern() to it.type.signature }
|
||||
constructor.valueParameters.map { it.type.signature }
|
||||
)
|
||||
}
|
||||
@@ -26,7 +26,14 @@ private val KOTLIN_NATIVE_SYNTHETIC_PACKAGES = ForwardDeclarationsFqNames.synthe
|
||||
fqName.asString()
|
||||
}
|
||||
|
||||
private const val DARWIN_PACKAGE_PREFIX = "platform.darwin"
|
||||
private const val CINTEROP_PACKAGE = "kotlinx.cinterop"
|
||||
private const val DARWIN_PACKAGE = "platform.darwin"
|
||||
|
||||
private val OBJC_INTEROP_CALLABLE_ANNOTATIONS = listOf(
|
||||
"ObjCMethod",
|
||||
"ObjCConstructor",
|
||||
"ObjCFactory"
|
||||
)
|
||||
|
||||
internal val FqName.isUnderStandardKotlinPackages: Boolean
|
||||
get() = hasAnyPrefix(STANDARD_KOTLIN_PACKAGES)
|
||||
@@ -35,7 +42,7 @@ internal val FqName.isUnderKotlinNativeSyntheticPackages: Boolean
|
||||
get() = hasAnyPrefix(KOTLIN_NATIVE_SYNTHETIC_PACKAGES)
|
||||
|
||||
internal val FqName.isUnderDarwinPackage: Boolean
|
||||
get() = asString().hasPrefix(DARWIN_PACKAGE_PREFIX)
|
||||
get() = asString().hasPrefix(DARWIN_PACKAGE)
|
||||
|
||||
private fun FqName.hasAnyPrefix(prefixes: List<String>): Boolean =
|
||||
asString().let { fqName -> prefixes.any(fqName::hasPrefix) }
|
||||
@@ -48,3 +55,6 @@ private fun String.hasPrefix(prefix: String): Boolean {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
internal val ClassId.isObjCInteropCallableAnnotation: Boolean
|
||||
get() = packageFqName.asString() == CINTEROP_PACKAGE && relativeClassName.asString() in OBJC_INTEROP_CALLABLE_ANNOTATIONS
|
||||
|
||||
Reference in New Issue
Block a user