From e75efc88ff51e2381fc322ff48450764da252777 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 16 Sep 2016 16:33:19 +0300 Subject: [PATCH] Add support for desctructuring of lambda parameters in JVM backend #KT-5828 In Progress --- .../codegen/ClosureGenerationStrategy.kt | 64 +++++++++++++++++++ .../DefaultParameterValueSubstitutor.kt | 4 +- .../kotlin/codegen/ExpressionCodegen.java | 22 +++++-- .../kotlin/codegen/FunctionCodegen.java | 43 +++++++++++-- .../kotlin/codegen/inline/InlineCodegen.java | 3 + .../destructuringInLambdas.kt | 13 ++++ .../extensionComponents.kt | 21 ++++++ .../destructuringDeclInLambdaParam/generic.kt | 11 ++++ .../destructuringDeclInLambdaParam/inline.kt | 5 ++ .../otherParameters.kt | 11 ++++ .../destructuringDeclInLambdaParam/simple.kt | 5 ++ .../stdlibUsages.kt | 16 +++++ .../codegen/BlackBoxCodegenTestGenerated.java | 45 +++++++++++++ ...CheckLocalVariablesTableTestGenerated.java | 6 ++ .../tinyApp/outs/destructuringParam.out | 51 +++++++++++++++ .../lambdas/destructuringParam.kt | 21 ++++++ ...KotlinEvaluateExpressionTestGenerated.java | 6 ++ 17 files changed, 332 insertions(+), 15 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureGenerationStrategy.kt create mode 100644 compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/extensionComponents.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/generic.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/inline.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/otherParameters.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/simple.kt create mode 100644 compiler/testData/codegen/box/destructuringDeclInLambdaParam/stdlibUsages.kt create mode 100644 idea/testData/debugger/tinyApp/outs/destructuringParam.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/destructuringParam.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureGenerationStrategy.kt new file mode 100644 index 00000000000..0c795e7e57d --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureGenerationStrategy.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen + +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver + +class ClosureGenerationStrategy( + state: GenerationState, + declaration: KtDeclarationWithBody +) : FunctionGenerationStrategy.FunctionDefault(state, declaration) { + + override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { + processDestructuringInLambdaParameters(codegen) + + super.doGenerateBody(codegen, signature) + } + + private fun processDestructuringInLambdaParameters(codegen: ExpressionCodegen) { + val savedIsShouldMarkLineNumbers = codegen.isShouldMarkLineNumbers + // Do not write line numbers until destructuring happens + // (otherwise destructuring variables will be uninitialized in the beginning of lambda) + codegen.isShouldMarkLineNumbers = false + + for (parameterDescriptor in codegen.context.functionDescriptor.valueParameters) { + if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue + + for (entry in parameterDescriptor.destructuringVariables) { + codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type)) + } + + val destructuringDeclaration = + (DescriptorToSourceUtils.descriptorToDeclaration(parameterDescriptor) as? KtParameter)?.destructuringDeclaration + ?: error("Destructuring declaration for descriptor $parameterDescriptor not found") + + codegen.initializeDestructuringDeclarationVariables( + destructuringDeclaration, + TransientReceiver(parameterDescriptor.type), + codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor") + ) + } + + codegen.isShouldMarkLineNumbers = savedIsShouldMarkLineNumbers + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt index 175f820a3b0..0e6bb3732d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt @@ -139,7 +139,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) { } if (!state.classBuilderMode.generateBodies) { - FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, Label(), Label(), remainingParameters, isStatic) + FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, Label(), Label(), remainingParameters, isStatic, typeMapper) mv.visitEnd() return } @@ -215,7 +215,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) { mv.visitLabel(methodEnd) FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, methodBegin, methodEnd, - remainingParameters, isStatic) + remainingParameters, isStatic, typeMapper) FunctionCodegen.endVisit(mv, null, methodElement) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 5a82cdfb8bc..bd8567f8ed9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1589,7 +1589,7 @@ public class ExpressionCodegen extends KtVisitor impleme assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText(); return genClosure( - declaration, descriptor, new FunctionGenerationStrategy.FunctionDefault(state, declaration), samType, null, null + declaration, descriptor, new ClosureGenerationStrategy(state, declaration), samType, null, null ); } @@ -3872,12 +3872,7 @@ public class ExpressionCodegen extends KtVisitor impleme v.store(tempVarIndex, initializerAsmType); StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType); - for (KtDestructuringDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) { - ResolvedCall resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration); - assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); - Call call = makeFakeCall(initializerAsReceiver); - initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, local)); - } + initializeDestructuringDeclarationVariables(multiDeclaration, initializerAsReceiver, local); if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) { v.aconst(null); @@ -3888,6 +3883,19 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.none(); } + public void initializeDestructuringDeclarationVariables( + @NotNull KtDestructuringDeclaration destructuringDeclaration, + @NotNull ReceiverValue receiver, + @NotNull StackValue receiverStackValue + ) { + for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) { + ResolvedCall resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration); + assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); + Call call = makeFakeCall(receiver); + initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, receiverStackValue)); + } + } + @NotNull private StackValue getVariableMetadataValue(VariableDescriptor variableDescriptor) { StackValue value = findLocalOrCapturedValue(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext)); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 5bcd66b57ee..675358a5d90 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import kotlin.collections.CollectionsKt; import kotlin.jvm.functions.Function1; import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers; @@ -207,7 +209,8 @@ public class FunctionCodegen { getThisTypeForFunction(functionDescriptor, methodContext, typeMapper), new Label(), new Label(), - contextKind + contextKind, + typeMapper ); mv.visitEnd(); @@ -395,7 +398,8 @@ public class FunctionCodegen { mv.visitLabel(methodEnd); Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); - generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); + generateLocalVariableTable( + mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind(), typeMapper); if (context.isInlineMethodContext() && functionFakeIndex != -1) { mv.visitLocalVariable( @@ -436,11 +440,12 @@ public class FunctionCodegen { @Nullable Type thisType, @NotNull Label methodBegin, @NotNull Label methodEnd, - @NotNull OwnerKind ownerKind + @NotNull OwnerKind ownerKind, + @NotNull KotlinTypeMapper typeMapper ) { generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd, functionDescriptor.getValueParameters(), - AsmUtil.isStaticMethod(ownerKind, functionDescriptor)); + AsmUtil.isStaticMethod(ownerKind, functionDescriptor), typeMapper); } public static void generateLocalVariablesForParameters( @@ -450,7 +455,8 @@ public class FunctionCodegen { @NotNull Label methodBegin, @NotNull Label methodEnd, Collection valueParameters, - boolean isStatic + boolean isStatic, + KotlinTypeMapper typeMapper ) { Iterator valueParameterIterator = valueParameters.iterator(); List params = jvmMethodSignature.getValueParameters(); @@ -474,7 +480,12 @@ public class FunctionCodegen { if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = valueParameterIterator.next(); - parameterName = parameter.getName().asString(); + List destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter); + + parameterName = + destructuringVariables == null + ? parameter.getName().asString() + : "$" + joinParameterNames(destructuringVariables); } else { String lowercaseKind = kind.name().toLowerCase(); @@ -487,6 +498,26 @@ public class FunctionCodegen { mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); shift += type.getSize(); } + + for (ValueParameterDescriptor parameter : valueParameters) { + List destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter); + if (destructuringVariables == null) continue; + + for (VariableDescriptor entry : destructuringVariables) { + Type type = typeMapper.mapType(parameter.getType()); + mv.visitLocalVariable(entry.getName().asString(), type.getDescriptor(), null, methodBegin, methodEnd, shift); + shift += type.getSize(); + } + } + } + + private static String joinParameterNames(@NotNull List variables) { + return org.jetbrains.kotlin.utils.StringsKt.join(CollectionsKt.map(variables, new Function1() { + @Override + public String invoke(VariableDescriptor descriptor) { + return descriptor.getName().asString(); + } + }), "_"); } private static void generateFacadeDelegateMethodBody( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index bad43d30580..d377018f6e8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -571,6 +571,9 @@ public class InlineCodegen extends CallGenerator { ); } } + else if (expression instanceof KtFunctionLiteral) { + strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression); + } else { strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression); } diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt new file mode 100644 index 00000000000..779e4e522ca --- /dev/null +++ b/compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt @@ -0,0 +1,13 @@ +data class A(val x: String, val y: String) + +fun foo(a: A, block: (A) -> String): String = block(a) + +fun box() { + foo(A("O", "K")) { (x, y) -> x + y } +} + +// METHOD : DestructuringInLambdasKt$box$1.invoke(LA;)Ljava/lang/String; +// VARIABLE : NAME=this TYPE=LDestructuringInLambdasKt$box$1; INDEX=0 +// VARIABLE : NAME=$x_y TYPE=LA; INDEX=1 +// VARIABLE : NAME=x TYPE=LA; INDEX=2 +// VARIABLE : NAME=y TYPE=LA; INDEX=3 diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/extensionComponents.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/extensionComponents.kt new file mode 100644 index 00000000000..201e2cb3a60 --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/extensionComponents.kt @@ -0,0 +1,21 @@ +class A(val x: String, val y: String, val z: T) + +fun foo(a: A, block: (A) -> String): String = block(a) + +operator fun A<*>.component1() = x + +object B { + operator fun A<*>.component2() = y +} + +fun B.bar(): String { + + operator fun A.component3() = z + + val x = foo(A("O", "K", 123)) { (x, y, z) -> x + y + z.toString() } + if (x != "OK123") return "fail 1: $x" + + return "OK" +} + +fun box() = B.bar() diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/generic.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/generic.kt new file mode 100644 index 00000000000..4dadddb91cd --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/generic.kt @@ -0,0 +1,11 @@ +data class A(val x: T, val y: F) + +fun foo(a: A, block: (A) -> String) = block(a) + +fun box(): String { + val x = foo(A("OK", 1)) { (x, y) -> x + (y.toString()) } + + if (x != "OK1") return "fail1: $x" + + return "OK" +} diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/inline.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/inline.kt new file mode 100644 index 00000000000..6835b91f21c --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/inline.kt @@ -0,0 +1,5 @@ +data class A(val x: String, val y: String) + +inline fun foo(a: A, block: (A) -> String): String = block(a) + +fun box() = foo(A("O", "K")) { (x, y) -> x + y } diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/otherParameters.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/otherParameters.kt new file mode 100644 index 00000000000..f973aca1710 --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/otherParameters.kt @@ -0,0 +1,11 @@ +data class A(val x: String, val y: String) + +fun foo(a: A, block: (Int, A, String) -> String): String = block(1, a, "#") + +fun box(): String { + val x = foo(A("O", "K")) { i, (x, y), v -> i.toString() + x + y + v } + + if (x != "1OK#") return "fail 1: $x" + + return "OK" +} diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/simple.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/simple.kt new file mode 100644 index 00000000000..50523e3fec4 --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/simple.kt @@ -0,0 +1,5 @@ +data class A(val x: String, val y: String) + +fun foo(a: A, block: (A) -> String): String = block(a) + +fun box() = foo(A("O", "K")) { (x, y) -> x + y } diff --git a/compiler/testData/codegen/box/destructuringDeclInLambdaParam/stdlibUsages.kt b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/stdlibUsages.kt new file mode 100644 index 00000000000..fe527e1237d --- /dev/null +++ b/compiler/testData/codegen/box/destructuringDeclInLambdaParam/stdlibUsages.kt @@ -0,0 +1,16 @@ +// WITH_RUNTIME + +fun box(): String { + val r1 = listOf("O", "K", "fail").let { + (x, y) -> x + y + } + + + if (r1 != "OK") return "fail 1: $r1" + + val r2 = listOf(Pair("O", "K")).map { (x, y) -> x + y }[0] + + if (r2 != "OK") return "fail 2: $r2" + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7d458c725dc..32796d3b889 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5657,6 +5657,51 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DestructuringDeclInLambdaParam extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInDestructuringDeclInLambdaParam() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/destructuringDeclInLambdaParam"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("extensionComponents.kt") + public void testExtensionComponents() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/extensionComponents.kt"); + doTest(fileName); + } + + @TestMetadata("generic.kt") + public void testGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/generic.kt"); + doTest(fileName); + } + + @TestMetadata("inline.kt") + public void testInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/inline.kt"); + doTest(fileName); + } + + @TestMetadata("otherParameters.kt") + public void testOtherParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/otherParameters.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/simple.kt"); + doTest(fileName); + } + + @TestMetadata("stdlibUsages.kt") + public void testStdlibUsages() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam/stdlibUsages.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/diagnostics") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java index 35c54ad1269..830a8cc700e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java @@ -47,6 +47,12 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar doTest(fileName); } + @TestMetadata("destructuringInLambdas.kt") + public void testDestructuringInLambdas() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt"); + doTest(fileName); + } + @TestMetadata("inlineLambdaWithItParam.kt") public void testInlineLambdaWithItParam() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt"); diff --git a/idea/testData/debugger/tinyApp/outs/destructuringParam.out b/idea/testData/debugger/tinyApp/outs/destructuringParam.out new file mode 100644 index 00000000000..c67aad5679a --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/destructuringParam.out @@ -0,0 +1,51 @@ +LineBreakpoint created at destructuringParam.kt:12 lambdaOrdinal = 1 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! destructuringParam.DestructuringParamKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +destructuringParam.kt:12 +Compile bytecode for x +Compile bytecode for y +package destructuringParam +data class A(val x: String, val y: String) + +fun foo(a: A, block: (A) -> String): String = block(a) + +fun box() { + +} + +fun main(args: Array) { + //Breakpoint! (lambdaOrdinal = 1) + foo(A("O", "K")) { (x, y) -> x + y } +} + +// PRINT_FRAME + +// EXPRESSION: x +// RESULT: "O": Ljava/lang/String; + +// EXPRESSION: y +// RESULT: "K": Ljava/lang/String; + + frame = invoke:12, DestructuringParamKt$main$1 {destructuringParam} + this = this = {destructuringParam.DestructuringParamKt$main$1@uniqueID}Function1 + field = arity: int = 1 (sp = Lambda.!EXT!) + local = $x_y: destructuringParam.A = {destructuringParam.A@uniqueID}A(x=O, y=K) (sp = null) + field = x: java.lang.String = O (sp = destructuringParam.kt, 2) + field = value: char[] = {char[1]@uniqueID} (sp = String.!EXT!) + element = 0 = 'O' 79 + field = hash: int = 0 (sp = String.!EXT!) + field = y: java.lang.String = K (sp = destructuringParam.kt, 2) + field = value: char[] = {char[1]@uniqueID} (sp = String.!EXT!) + element = 0 = 'K' 75 + field = hash: int = 0 (sp = String.!EXT!) + local = x: destructuringParam.A = O (sp = destructuringParam.kt, 12) + field = value: char[] = {char[1]@uniqueID} (sp = String.!EXT!) + element = 0 = 'O' 79 + field = hash: int = 0 (sp = String.!EXT!) + local = y: destructuringParam.A = K (sp = destructuringParam.kt, 12) + field = value: char[] = {char[1]@uniqueID} (sp = String.!EXT!) + element = 0 = 'K' 75 + field = hash: int = 0 (sp = String.!EXT!) +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/destructuringParam.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/destructuringParam.kt new file mode 100644 index 00000000000..2f44774ee29 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/destructuringParam.kt @@ -0,0 +1,21 @@ +package destructuringParam +data class A(val x: String, val y: String) + +fun foo(a: A, block: (A) -> String): String = block(a) + +fun box() { + +} + +fun main(args: Array) { + //Breakpoint! (lambdaOrdinal = 1) + foo(A("O", "K")) { (x, y) -> x + y } +} + +// PRINT_FRAME + +// EXPRESSION: x +// RESULT: "O": Ljava/lang/String; + +// EXPRESSION: y +// RESULT: "K": Ljava/lang/String; diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index da5dcfe0ce9..29bb33bad0b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -789,6 +789,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("destructuringParam.kt") + public void testDestructuringParam() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/destructuringParam.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("inlineFunctionalExpression.kt") public void testInlineFunctionalExpression() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/inlineFunctionalExpression.kt");