Add support for desctructuring of lambda parameters in JVM backend
#KT-5828 In Progress
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -139,7 +139,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!state.classBuilderMode.generateBodies) {
|
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()
|
mv.visitEnd()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
|||||||
mv.visitLabel(methodEnd)
|
mv.visitLabel(methodEnd)
|
||||||
|
|
||||||
FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, methodBegin, methodEnd,
|
FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, methodBegin, methodEnd,
|
||||||
remainingParameters, isStatic)
|
remainingParameters, isStatic, typeMapper)
|
||||||
|
|
||||||
FunctionCodegen.endVisit(mv, null, methodElement)
|
FunctionCodegen.endVisit(mv, null, methodElement)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1589,7 +1589,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText();
|
assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText();
|
||||||
|
|
||||||
return genClosure(
|
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<StackValue, StackValue> impleme
|
|||||||
v.store(tempVarIndex, initializerAsmType);
|
v.store(tempVarIndex, initializerAsmType);
|
||||||
StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
|
StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
|
||||||
|
|
||||||
for (KtDestructuringDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
|
initializeDestructuringDeclarationVariables(multiDeclaration, initializerAsReceiver, local);
|
||||||
ResolvedCall<FunctionDescriptor> 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
|
if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
|
||||||
v.aconst(null);
|
v.aconst(null);
|
||||||
@@ -3888,6 +3883,19 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
return StackValue.none();
|
return StackValue.none();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initializeDestructuringDeclarationVariables(
|
||||||
|
@NotNull KtDestructuringDeclaration destructuringDeclaration,
|
||||||
|
@NotNull ReceiverValue receiver,
|
||||||
|
@NotNull StackValue receiverStackValue
|
||||||
|
) {
|
||||||
|
for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) {
|
||||||
|
ResolvedCall<FunctionDescriptor> 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
|
@NotNull
|
||||||
private StackValue getVariableMetadataValue(VariableDescriptor variableDescriptor) {
|
private StackValue getVariableMetadataValue(VariableDescriptor variableDescriptor) {
|
||||||
StackValue value = findLocalOrCapturedValue(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
|
StackValue value = findLocalOrCapturedValue(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
|
|||||||
import com.intellij.util.ArrayUtil;
|
import com.intellij.util.ArrayUtil;
|
||||||
import com.intellij.util.Function;
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
import kotlin.text.StringsKt;
|
import kotlin.text.StringsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.Annotated;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
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.BuiltinMethodsWithSpecialGenericSignature;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||||
import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
|
import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
|
||||||
@@ -207,7 +209,8 @@ public class FunctionCodegen {
|
|||||||
getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
|
getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
|
||||||
new Label(),
|
new Label(),
|
||||||
new Label(),
|
new Label(),
|
||||||
contextKind
|
contextKind,
|
||||||
|
typeMapper
|
||||||
);
|
);
|
||||||
|
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
@@ -395,7 +398,8 @@ public class FunctionCodegen {
|
|||||||
mv.visitLabel(methodEnd);
|
mv.visitLabel(methodEnd);
|
||||||
|
|
||||||
Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
|
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) {
|
if (context.isInlineMethodContext() && functionFakeIndex != -1) {
|
||||||
mv.visitLocalVariable(
|
mv.visitLocalVariable(
|
||||||
@@ -436,11 +440,12 @@ public class FunctionCodegen {
|
|||||||
@Nullable Type thisType,
|
@Nullable Type thisType,
|
||||||
@NotNull Label methodBegin,
|
@NotNull Label methodBegin,
|
||||||
@NotNull Label methodEnd,
|
@NotNull Label methodEnd,
|
||||||
@NotNull OwnerKind ownerKind
|
@NotNull OwnerKind ownerKind,
|
||||||
|
@NotNull KotlinTypeMapper typeMapper
|
||||||
) {
|
) {
|
||||||
generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd,
|
generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd,
|
||||||
functionDescriptor.getValueParameters(),
|
functionDescriptor.getValueParameters(),
|
||||||
AsmUtil.isStaticMethod(ownerKind, functionDescriptor));
|
AsmUtil.isStaticMethod(ownerKind, functionDescriptor), typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateLocalVariablesForParameters(
|
public static void generateLocalVariablesForParameters(
|
||||||
@@ -450,7 +455,8 @@ public class FunctionCodegen {
|
|||||||
@NotNull Label methodBegin,
|
@NotNull Label methodBegin,
|
||||||
@NotNull Label methodEnd,
|
@NotNull Label methodEnd,
|
||||||
Collection<ValueParameterDescriptor> valueParameters,
|
Collection<ValueParameterDescriptor> valueParameters,
|
||||||
boolean isStatic
|
boolean isStatic,
|
||||||
|
KotlinTypeMapper typeMapper
|
||||||
) {
|
) {
|
||||||
Iterator<ValueParameterDescriptor> valueParameterIterator = valueParameters.iterator();
|
Iterator<ValueParameterDescriptor> valueParameterIterator = valueParameters.iterator();
|
||||||
List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
|
List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
|
||||||
@@ -474,7 +480,12 @@ public class FunctionCodegen {
|
|||||||
|
|
||||||
if (kind == JvmMethodParameterKind.VALUE) {
|
if (kind == JvmMethodParameterKind.VALUE) {
|
||||||
ValueParameterDescriptor parameter = valueParameterIterator.next();
|
ValueParameterDescriptor parameter = valueParameterIterator.next();
|
||||||
parameterName = parameter.getName().asString();
|
List<VariableDescriptor> destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter);
|
||||||
|
|
||||||
|
parameterName =
|
||||||
|
destructuringVariables == null
|
||||||
|
? parameter.getName().asString()
|
||||||
|
: "$" + joinParameterNames(destructuringVariables);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String lowercaseKind = kind.name().toLowerCase();
|
String lowercaseKind = kind.name().toLowerCase();
|
||||||
@@ -487,6 +498,26 @@ public class FunctionCodegen {
|
|||||||
mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
|
mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
|
||||||
shift += type.getSize();
|
shift += type.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ValueParameterDescriptor parameter : valueParameters) {
|
||||||
|
List<VariableDescriptor> 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<VariableDescriptor> variables) {
|
||||||
|
return org.jetbrains.kotlin.utils.StringsKt.join(CollectionsKt.map(variables, new Function1<VariableDescriptor, String>() {
|
||||||
|
@Override
|
||||||
|
public String invoke(VariableDescriptor descriptor) {
|
||||||
|
return descriptor.getName().asString();
|
||||||
|
}
|
||||||
|
}), "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateFacadeDelegateMethodBody(
|
private static void generateFacadeDelegateMethodBody(
|
||||||
|
|||||||
@@ -571,6 +571,9 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (expression instanceof KtFunctionLiteral) {
|
||||||
|
strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
|
strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
class A<T>(val x: String, val y: String, val z: T)
|
||||||
|
|
||||||
|
fun <T> foo(a: A<T>, block: (A<T>) -> String): String = block(a)
|
||||||
|
|
||||||
|
operator fun A<*>.component1() = x
|
||||||
|
|
||||||
|
object B {
|
||||||
|
operator fun A<*>.component2() = y
|
||||||
|
}
|
||||||
|
|
||||||
|
fun B.bar(): String {
|
||||||
|
|
||||||
|
operator fun <R> A<R>.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()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
data class A<T, F>(val x: T, val y: F)
|
||||||
|
|
||||||
|
fun <X, Y> foo(a: A<X, Y>, block: (A<X, Y>) -> 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"
|
||||||
|
}
|
||||||
@@ -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 }
|
||||||
+11
@@ -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"
|
||||||
|
}
|
||||||
@@ -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 }
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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")
|
@TestMetadata("compiler/testData/codegen/box/diagnostics")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("destructuringInLambdas.kt")
|
||||||
|
public void testDestructuringInLambdas() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineLambdaWithItParam.kt")
|
@TestMetadata("inlineLambdaWithItParam.kt")
|
||||||
public void testInlineLambdaWithItParam() throws Exception {
|
public void testInlineLambdaWithItParam() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt");
|
||||||
|
|||||||
@@ -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<String>) {
|
||||||
|
//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<destructuringParam.A, java.lang.String>
|
||||||
|
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
|
||||||
+21
@@ -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<String>) {
|
||||||
|
//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;
|
||||||
+6
@@ -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);
|
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")
|
@TestMetadata("inlineFunctionalExpression.kt")
|
||||||
public void testInlineFunctionalExpression() throws Exception {
|
public void testInlineFunctionalExpression() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/inlineFunctionalExpression.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/inlineFunctionalExpression.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user