diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 9f2fc37b99f..338ea3fa8c7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -58,7 +58,6 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; -import org.jetbrains.kotlin.utils.StringsKt; import org.jetbrains.org.objectweb.asm.*; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; @@ -849,12 +848,12 @@ public class FunctionCodegen { if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = valueParameterIterator.next(); - List destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter); + String nameForDestructuredParameter = ValueParameterDescriptorImpl.getNameForDestructuredParameterOrNull(parameter); parameterName = - destructuringVariables == null + nameForDestructuredParameter == null ? computeParameterName(i, parameter) - : "$" + joinParameterNames(destructuringVariables); + : nameForDestructuredParameter; } else { String lowercaseKind = kind.name().toLowerCase(); @@ -904,11 +903,11 @@ public class FunctionCodegen { List destructuredParametersForSuspendLambda ) { for (ValueParameterDescriptor parameter : destructuredParametersForSuspendLambda) { - List destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter); - if (destructuringVariables == null) continue; + String nameForDestructuredParameter = ValueParameterDescriptorImpl.getNameForDestructuredParameterOrNull(parameter); + if (nameForDestructuredParameter == null) continue; Type type = typeMapper.mapType(parameter.getType()); - mv.visitLocalVariable("$" + joinParameterNames(destructuringVariables), type.getDescriptor(), null, methodBegin, methodEnd, shift); + mv.visitLocalVariable(nameForDestructuredParameter, type.getDescriptor(), null, methodBegin, methodEnd, shift); shift += type.getSize(); } return shift; @@ -923,14 +922,6 @@ public class FunctionCodegen { return parameter.getName().asString(); } - private static String joinParameterNames(@NotNull List variables) { - // stub for anonymous destructuring declaration entry - return StringsKt.join( - CollectionsKt.map(variables, descriptor -> descriptor.getName().isSpecial() ? "$_$" : descriptor.getName().asString()), - "_" - ); - } - private static void generateFacadeDelegateMethodBody( @NotNull MethodVisitor mv, @NotNull Method asmMethod, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index b3b5da9a260..b5732810055 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -24,11 +24,9 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrTypeAlias -import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.toKotlinType @@ -118,6 +116,7 @@ class ExpressionCodegen( fun generate() { mv.visitCode() + val startLabel = markNewLabel() irFunction.markLineNumber(true) val info = BlockInfo.create() val result = irFunction.body!!.accept(this, info) @@ -137,9 +136,35 @@ class ExpressionCodegen( } } writeLocalVariablesInTable(info) + writeParameterInLocalVariableTable(startLabel) mv.visitEnd() } + private fun writeParameterInLocalVariableTable(startLabel: Label) { + if (!irFunction.isStatic) { + mv.visitLocalVariable("this", classCodegen.type.descriptor, null, startLabel, markNewLabel(), 0) + } + val extensionReceiverParameter = irFunction.extensionReceiverParameter + if (extensionReceiverParameter != null) { + writeValueParameterInLocalVariableTable(extensionReceiverParameter, startLabel) + } + for (param in irFunction.valueParameters) { + writeValueParameterInLocalVariableTable(param, startLabel) + } + } + + private fun writeValueParameterInLocalVariableTable(param: IrValueParameter, startLabel: Label) { + val descriptor = param.descriptor + val nameForDestructuredParameter = if (descriptor is ValueParameterDescriptor) + ValueParameterDescriptorImpl.getNameForDestructuredParameterOrNull(descriptor) else null + val type = typeMapper.mapType(descriptor) + // NOTE: we expect all value parameters to be present in the frame. + mv.visitLocalVariable( + nameForDestructuredParameter ?: param.name.asString(), + type.descriptor, null, startLabel, markNewLabel(), findLocalIndex(param.symbol) + ) + } + private fun endsWithReturn(body: IrBody): Boolean { val lastStatement = if (body is IrStatementContainer) { body.statements.lastOrNull() ?: body @@ -169,7 +194,18 @@ class ExpressionCodegen( private fun writeLocalVariablesInTable(info: BlockInfo) { val endLabel = markNewLabel() info.variables.forEach { - mv.visitLocalVariable(it.declaration.name.asString(), it.type.descriptor, null, it.startLabel, endLabel, it.index) + when (it.declaration.origin) { + IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, + IrDeclarationOrigin.FOR_LOOP_ITERATOR, + IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE -> { + // Ignore implicitly created variables + } + else -> { + mv.visitLocalVariable( + it.declaration.name.asString(), it.type.descriptor, null, it.startLabel, endLabel, it.index + ) + } + } } info.variables.reversed().forEach { @@ -1141,4 +1177,4 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo internal fun CallableDescriptor.isInlineCall(state: GenerationState) = (!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(this)) && - (InlineUtil.isInline(this) || InlineUtil.isArrayConstructorWithLambda(this)) \ No newline at end of file + (InlineUtil.isInline(this) || InlineUtil.isArrayConstructorWithLambda(this)) diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt index 51d840b3f1b..74a3318de80 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt @@ -1,3 +1,4 @@ +// 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/destructuringInSuspendLambda/dataClass.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/dataClass.kt index 163b5a3262a..f8b7b5bbf0d 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/dataClass.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/dataClass.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR data class Data(val x: String, val y: Int) suspend fun test() { diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/extensionComponents.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/extensionComponents.kt index c8d17d929de..efeb0db2432 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/extensionComponents.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/extensionComponents.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class A(val x: String, val y: String, val z: T) suspend fun foo(a: A, block: suspend (A) -> String): String = block(a) diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/generic.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/generic.kt index 13de9f3f934..53c718e6ddb 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/generic.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/generic.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR data class A(val x: T, val y: F) suspend fun foo(a: A, block: suspend (A) -> String) = block(a) diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/inline.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/inline.kt index 81842fb31d6..89e082c31a4 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/inline.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/inline.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR data class A(val x: String, val y: String) suspend inline fun foo(a: A, block: suspend (A) -> String): String = block(a) diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/otherParameters.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/otherParameters.kt index d92891e2ddf..22f848f0f5b 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/otherParameters.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/otherParameters.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR data class A(val x: String, val y: String) suspend fun foo(a: A, block: suspend (Int, A, String) -> String): String = block(1, a, "#") diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/underscoreNames.kt b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/underscoreNames.kt index 0fcd8294522..6d893ceedcb 100644 --- a/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/underscoreNames.kt +++ b/compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/underscoreNames.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class A { operator fun component1() = "O" operator fun component2(): String = throw RuntimeException("fail 0") diff --git a/compiler/testData/checkLocalVariablesTable/itInLambda.kt b/compiler/testData/checkLocalVariablesTable/itInLambda.kt index 359fccf3e96..96ca2a2d6a8 100644 --- a/compiler/testData/checkLocalVariablesTable/itInLambda.kt +++ b/compiler/testData/checkLocalVariablesTable/itInLambda.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR public fun Iterable.myforEach(operation: (T) -> Unit) : Unit { for (element in this) operation(element) } diff --git a/compiler/testData/checkLocalVariablesTable/itInReturnedLambda.kt b/compiler/testData/checkLocalVariablesTable/itInReturnedLambda.kt index 23478ff5561..c57dd18cbba 100644 --- a/compiler/testData/checkLocalVariablesTable/itInReturnedLambda.kt +++ b/compiler/testData/checkLocalVariablesTable/itInReturnedLambda.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun foo() { fun bar() : (Int) -> Unit { return { diff --git a/compiler/testData/checkLocalVariablesTable/jvmOverloads.kt b/compiler/testData/checkLocalVariablesTable/jvmOverloads.kt index 88bc6135abb..92522cfcb8d 100644 --- a/compiler/testData/checkLocalVariablesTable/jvmOverloads.kt +++ b/compiler/testData/checkLocalVariablesTable/jvmOverloads.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class C { @kotlin.jvm.JvmOverloads fun foo(firstParam: Int, secondParam: String = "") { } diff --git a/compiler/testData/checkLocalVariablesTable/kt11117.kt b/compiler/testData/checkLocalVariablesTable/kt11117.kt index 6a6351cdfaf..8b214b5a8f4 100644 --- a/compiler/testData/checkLocalVariablesTable/kt11117.kt +++ b/compiler/testData/checkLocalVariablesTable/kt11117.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class A(val value: String) fun A.test(): String { diff --git a/compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt b/compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt index e562031bbd9..923ff0bd8c2 100644 --- a/compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt +++ b/compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun foo() { var a = { diff --git a/compiler/testData/checkLocalVariablesTable/localFun.kt b/compiler/testData/checkLocalVariablesTable/localFun.kt index 8e97ed0f3b8..f893c74d7cd 100644 --- a/compiler/testData/checkLocalVariablesTable/localFun.kt +++ b/compiler/testData/checkLocalVariablesTable/localFun.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun foo() { fun bar() { } diff --git a/compiler/testData/checkLocalVariablesTable/underscoreNames.kt b/compiler/testData/checkLocalVariablesTable/underscoreNames.kt index 3269346d8d0..4639550ce8b 100644 --- a/compiler/testData/checkLocalVariablesTable/underscoreNames.kt +++ b/compiler/testData/checkLocalVariablesTable/underscoreNames.kt @@ -1,3 +1,4 @@ +// 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) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.java b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.java index 31066737455..2a0e5ab48ae 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.java @@ -42,8 +42,8 @@ import java.util.regex.Pattern; */ public abstract class AbstractCheckLocalVariablesTableTest extends TestCaseWithTmpdir { - private File ktFile; - private KotlinCoreEnvironment environment; + protected File ktFile; + protected KotlinCoreEnvironment environment; public AbstractCheckLocalVariablesTableTest() { } @@ -82,6 +82,10 @@ public abstract class AbstractCheckLocalVariablesTableTest extends TestCaseWithT ClassReader cr = new ClassReader(outputFile.asByteArray()); List actualLocalVariables = readLocalVariable(cr, methodName); + doCompare(text, actualLocalVariables); + } + + protected void doCompare(String text, List actualLocalVariables) { KotlinTestUtils.assertEqualsToFile(ktFile, text.substring(0, text.indexOf("// VARIABLE : ")) + getActualVariablesAsString(actualLocalVariables)); } @@ -93,8 +97,7 @@ public abstract class AbstractCheckLocalVariablesTableTest extends TestCaseWithT return builder.toString(); } - - private static class LocalVariable { + protected static class LocalVariable { private final String name; private final String type; private final int index; diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt new file mode 100644 index 00000000000..3ec2f545cf9 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.codegen.ir + +import com.intellij.openapi.util.Comparing +import org.jetbrains.kotlin.codegen.AbstractCheckLocalVariablesTableTest +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.junit.ComparisonFailure +import java.nio.charset.Charset + +abstract class AbstractIrCheckLocalVariablesTableTest : AbstractCheckLocalVariablesTableTest() { + @Throws(Exception::class) + override fun setUp() { + super.setUp() + assert(environment != null) + environment.configuration.put(JVMConfigurationKeys.IR, true) + } + + override fun doCompare(text: String?, actualLocalVariables: MutableList) { + val actual = getActualVariablesAsList(actualLocalVariables) + val expected = getExpectedVariablesAsList() + if (!Comparing.equal(expected, actual)) { + throw ComparisonFailure( + "Variables differ from expected", + expected.joinToString("\n"), + actual.joinToString("\n") + ) + } + } + + private fun getActualVariablesAsList(list: List): List { + return list.map { it.toString() } + .map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } // Ignore index + .sorted() + } + + private fun getExpectedVariablesAsList(): List { + return ktFile.readLines(Charset.forName("utf-8")) + .filter { line -> line.startsWith("// VARIABLE ") } + .filter { !it.contains("NAME=\$i\$") } + .map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } // Ignore index + .sorted() + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java new file mode 100644 index 00000000000..865b50a1cad --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java @@ -0,0 +1,154 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.codegen.ir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/checkLocalVariablesTable") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLocalVariablesTableTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInCheckLocalVariablesTable() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("catchClause.kt") + public void testCatchClause() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/catchClause.kt"); + } + + @TestMetadata("copyFunction.kt") + public void testCopyFunction() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt"); + } + + @TestMetadata("destructuringInLambdas.kt") + public void testDestructuringInLambdas() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt"); + } + + @TestMetadata("destructuringInlineLambda.kt") + public void testDestructuringInlineLambda() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt"); + } + + @TestMetadata("inlineLambdaWithItParam.kt") + public void testInlineLambdaWithItParam() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt"); + } + + @TestMetadata("inlineLambdaWithParam.kt") + public void testInlineLambdaWithParam() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithParam.kt"); + } + + @TestMetadata("inlineProperty.kt") + public void testInlineProperty() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/inlineProperty.kt"); + } + + @TestMetadata("inlineSimple.kt") + public void testInlineSimple() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/inlineSimple.kt"); + } + + @TestMetadata("inlineSimpleChain.kt") + public void testInlineSimpleChain() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/inlineSimpleChain.kt"); + } + + @TestMetadata("itInLambda.kt") + public void testItInLambda() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/itInLambda.kt"); + } + + @TestMetadata("itInReturnedLambda.kt") + public void testItInReturnedLambda() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/itInReturnedLambda.kt"); + } + + @TestMetadata("jvmOverloads.kt") + public void testJvmOverloads() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/jvmOverloads.kt"); + } + + @TestMetadata("kt11117.kt") + public void testKt11117() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/kt11117.kt"); + } + + @TestMetadata("lambdaAsVar.kt") + public void testLambdaAsVar() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt"); + } + + @TestMetadata("localFun.kt") + public void testLocalFun() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/localFun.kt"); + } + + @TestMetadata("underscoreNames.kt") + public void testUnderscoreNames() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/underscoreNames.kt"); + } + + @TestMetadata("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DestructuringInSuspendLambda extends AbstractIrCheckLocalVariablesTableTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInDestructuringInSuspendLambda() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("dataClass.kt") + public void testDataClass() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/dataClass.kt"); + } + + @TestMetadata("extensionComponents.kt") + public void testExtensionComponents() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/extensionComponents.kt"); + } + + @TestMetadata("generic.kt") + public void testGeneric() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/generic.kt"); + } + + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/inline.kt"); + } + + @TestMetadata("otherParameters.kt") + public void testOtherParameters() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/otherParameters.kt"); + } + + @TestMetadata("underscoreNames.kt") + public void testUnderscoreNames() throws Exception { + runTest("compiler/testData/checkLocalVariablesTable/destructuringInSuspendLambda/underscoreNames.kt"); + } + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index 7d023404199..bd3b7b13371 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -27,10 +27,10 @@ import org.jetbrains.kotlin.cli.AbstractCliTest import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.defaultConstructor.AbstractDefaultArgumentsReflectionTest import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest -import org.jetbrains.kotlin.codegen.AbstractCustomScriptCodegenTest import org.jetbrains.kotlin.codegen.ir.AbstractIrBlackBoxAgainstJavaCodegenTest import org.jetbrains.kotlin.codegen.ir.AbstractIrBlackBoxCodegenTest import org.jetbrains.kotlin.codegen.ir.AbstractIrBlackBoxInlineCodegenTest +import org.jetbrains.kotlin.codegen.ir.AbstractIrCheckLocalVariablesTableTest import org.jetbrains.kotlin.generators.tests.generator.testGroup import org.jetbrains.kotlin.generators.util.KT_OR_KTS_WITHOUT_DOTS_IN_NAME import org.jetbrains.kotlin.integration.AbstractAntTaskTest @@ -356,6 +356,10 @@ fun main(args: Array) { model("codegen/boxAgainstJava", targetBackend = TargetBackend.JVM_IR) } + testClass { + model("checkLocalVariablesTable", targetBackend = TargetBackend.JVM_IR) + } + testClass { model("codegen/boxInline", targetBackend = TargetBackend.JVM_IR) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt index cb179067d1b..10bd223f49e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.utils.join open class ValueParameterDescriptorImpl( containingDeclaration: CallableDescriptor, @@ -60,6 +61,16 @@ open class ValueParameterDescriptorImpl( WithDestructuringDeclaration(containingDeclaration, original, index, annotations, name, outType, declaresDefaultValue, isCrossinline, isNoinline, varargElementType, source, destructuringVariables) + + @JvmStatic + fun getNameForDestructuredParameterOrNull(valueParameterDescriptor: ValueParameterDescriptor): String? { + val variablesOrNull = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(valueParameterDescriptor) + return if (variablesOrNull == null) null else + "$" + join( + variablesOrNull.map { descriptor -> if (descriptor.name.isSpecial) "\$_\$" else descriptor.name.asString() }, + "_" + ) + } } class WithDestructuringDeclaration internal constructor( @@ -81,6 +92,13 @@ open class ValueParameterDescriptorImpl( // as value parameters. // Must be forced via ForceResolveUtil.forceResolveAllContents() val destructuringVariables by lazy(destructuringVariables) + + override fun copy(newOwner: CallableDescriptor, newName: Name, newIndex: Int): ValueParameterDescriptor { + return WithDestructuringDeclaration( + newOwner, null, newIndex, annotations, newName, type, declaresDefaultValue(), + isCrossinline, isNoinline, varargElementType, SourceElement.NO_SOURCE + ) { destructuringVariables } + } } private val original: ValueParameterDescriptor = original ?: this