diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index e712c89e665..6b5b22fd29f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -237,6 +237,7 @@ private val tailrecPhase = makeIrFilePhase( @Suppress("Reformat") private val jvmFilePhases = + renameAnonymousParametersLowering then typeAliasAnnotationMethodsPhase then stripTypeAliasDeclarationsPhase then provisionalFunctionExpressionPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RenameAnonymousParametersLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RenameAnonymousParametersLowering.kt new file mode 100644 index 00000000000..ad6426570b2 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RenameAnonymousParametersLowering.kt @@ -0,0 +1,85 @@ +/* + * 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.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.codegen.getNameForDestructuredParameterOrNull +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor +import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +internal val renameAnonymousParametersLowering = makeIrFilePhase( + ::RenameAnonymousParametersLowering, + name = "RenameAnonymousParameters", + description = "Mangles variable names for anonymous parameters (only allowed in lambdas)" +) + +private class RenameAnonymousParametersLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() { + + val oldParameterToNew: MutableMap = mutableMapOf() + + override fun lower(irFile: IrFile) = irFile.transformChildrenVoid() + + override fun visitValueParameter(declaration: IrValueParameter) = + declaration.computeNewParameterName()?.let { name -> + val descriptor = if (declaration.descriptor is ReceiverParameterDescriptor) { + WrappedReceiverParameterDescriptor(declaration.descriptor.annotations) + } else { + WrappedValueParameterDescriptor(declaration.descriptor.annotations) + } + IrValueParameterImpl( + declaration.startOffset, declaration.endOffset, + declaration.origin, + IrValueParameterSymbolImpl(descriptor), + name, + declaration.index, + declaration.type, + declaration.varargElementType, + declaration.isCrossinline, + declaration.isNoinline + ).apply { + descriptor.bind(this) + parent = declaration.parent + defaultValue = declaration.defaultValue + annotations += declaration.annotations + oldParameterToNew[declaration] = this + } + } ?: super.visitValueParameter(declaration) + + override fun visitGetValue(expression: IrGetValue): IrExpression { + val oldParameter = expression.symbol.owner + return oldParameterToNew[oldParameter]?.let { + IrGetValueImpl(expression.startOffset, expression.endOffset, it.type, it.symbol) + } ?: super.visitGetValue(expression) + } + + private fun IrValueParameter.computeNewParameterName(): Name? { + // Consistent with naming on old (non-IR) backend; see FunctionCodegen.java. + descriptor.safeAs()?.let { + getNameForDestructuredParameterOrNull(it)?.let { return Name.identifier(it) } + if (DescriptorToSourceUtils.getSourceFromDescriptor(it)?.safeAs()?.isSingleUnderscore == true) { + return Name.identifier("\$noName_${it.index}") + } + } + return null + } +} diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt index bc5d25b361d..cc2cf2a5745 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR data class A(val x: String, val y: Int) fun foo(a: A, block: (A) -> String): String = block(a) diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt b/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt index 05cc9338cf9..2026e03abc0 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR inline fun foo(x: (Int, Station) -> Unit) { x(1, Station(null, "", 1)) } diff --git a/compiler/testData/checkLocalVariablesTable/underscoreNames.kt b/compiler/testData/checkLocalVariablesTable/underscoreNames.kt index dfedc33a270..759e86921aa 100644 --- a/compiler/testData/checkLocalVariablesTable/underscoreNames.kt +++ b/compiler/testData/checkLocalVariablesTable/underscoreNames.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR data class A(val x: Double = 1.0, val y: String = "", val z: Char = '0') fun foo(a: A, block: (A, String, Int) -> String): String = block(a, "", 1)