JVM_IR: KT-40330 Unify field names for captured 'this' with JVM
NB some cases such as captured extension receiver for an extension lambda are not supported yet; to be discussed, to what extent should we actually follow JVM code shape here.
This commit is contained in:
+57
-9
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
@@ -31,11 +31,13 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
interface LocalNameProvider {
|
||||
fun localName(declaration: IrDeclarationWithName): String =
|
||||
@@ -637,7 +639,7 @@ class LocalDeclarationsLowering(
|
||||
oldDeclaration: IrFunction,
|
||||
newDeclaration: IrFunction
|
||||
) = ArrayList<IrValueParameter>(capturedValues.size + oldDeclaration.valueParameters.size).apply {
|
||||
val generatedNames = mutableSetOf<Name>()
|
||||
val generatedNames = mutableSetOf<String>()
|
||||
capturedValues.mapIndexedTo(this) { i, capturedValue ->
|
||||
val p = capturedValue.owner
|
||||
buildValueParameter(newDeclaration) {
|
||||
@@ -743,7 +745,7 @@ class LocalDeclarationsLowering(
|
||||
|
||||
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
|
||||
val classDeclaration = localClassContext.declaration
|
||||
val generatedNames = mutableSetOf<Name>()
|
||||
val generatedNames = mutableSetOf<String>()
|
||||
localClassContext.closure.capturedValues.forEach { capturedValue ->
|
||||
|
||||
val owner = capturedValue.owner
|
||||
@@ -772,18 +774,64 @@ class LocalDeclarationsLowering(
|
||||
private fun Name.stripSpecialMarkers(): String =
|
||||
if (isSpecial) asString().substring(1, asString().length - 1) else asString()
|
||||
|
||||
private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, existing: MutableSet<Name>): Name {
|
||||
private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, usedNames: MutableSet<String>): Name {
|
||||
if (declaration is IrValueParameter && declaration.name.asString() == "<this>") {
|
||||
if (declaration.isDispatchReceiver()) {
|
||||
return findFirstUnusedName("this\$0", usedNames) {
|
||||
"this\$$it"
|
||||
}
|
||||
} else if (declaration.isExtensionReceiver()) {
|
||||
val parentNameSuffix = declaration.parentNameSuffixForExtensionReceiver
|
||||
return findFirstUnusedName("\$this_$parentNameSuffix", usedNames) {
|
||||
"\$this_$parentNameSuffix\$$it"
|
||||
}
|
||||
}
|
||||
// TODO captured extension receivers of extension lambdas?
|
||||
}
|
||||
val base = if (declaration.name.isSpecial)
|
||||
declaration.name.stripSpecialMarkers()
|
||||
else
|
||||
declaration.name.asString()
|
||||
var chosen = base.synthesizedName
|
||||
var suffix = 0
|
||||
while (!existing.add(chosen))
|
||||
chosen = "$base$${++suffix}".synthesizedName
|
||||
return chosen
|
||||
return findFirstUnusedName(base.synthesizedString, usedNames) {
|
||||
"$base$$it".synthesizedString
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun findFirstUnusedName(initialName: String, usedNames: MutableSet<String>, nextName: (Int) -> String): Name {
|
||||
var chosen = initialName
|
||||
var suffix = 0
|
||||
while (!usedNames.add(chosen))
|
||||
chosen = nextName(++suffix)
|
||||
return Name.identifier(chosen)
|
||||
}
|
||||
|
||||
private fun IrValueParameter.isDispatchReceiver(): Boolean =
|
||||
when (val parent = this.parent) {
|
||||
is IrFunction ->
|
||||
parent.dispatchReceiverParameter == this
|
||||
is IrClass ->
|
||||
parent.thisReceiver == this
|
||||
else ->
|
||||
false
|
||||
}
|
||||
|
||||
private fun IrValueParameter.isExtensionReceiver(): Boolean {
|
||||
val parentFun = parent as? IrFunction ?: return false
|
||||
return parentFun.extensionReceiverParameter == this
|
||||
}
|
||||
|
||||
private val IrValueParameter.parentNameSuffixForExtensionReceiver: String
|
||||
get() {
|
||||
val parentFun = parent as? IrSimpleFunction
|
||||
?: throw AssertionError("Extension receiver parent is not a simple function: ${parent.render()}")
|
||||
val correspondingProperty = parentFun.safeAs<IrSimpleFunction>()?.correspondingPropertySymbol?.owner
|
||||
return when {
|
||||
correspondingProperty != null ->
|
||||
correspondingProperty.name.stripSpecialMarkers()
|
||||
else ->
|
||||
parentFun.name.stripSpecialMarkers()
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectClosureForLocalDeclarations() {
|
||||
//TODO: maybe use for granular declarations
|
||||
|
||||
Reference in New Issue
Block a user