Generate non-local destructuring declarations as properties
#KT-5620 Fixed #KT-15810 Fixed
This commit is contained in:
@@ -3439,6 +3439,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) {
|
public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) {
|
||||||
|
return initializeDestructuringDeclaration(multiDeclaration, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackValue initializeDestructuringDeclaration(
|
||||||
|
@NotNull KtDestructuringDeclaration multiDeclaration,
|
||||||
|
boolean asProperty
|
||||||
|
) {
|
||||||
KtExpression initializer = multiDeclaration.getInitializer();
|
KtExpression initializer = multiDeclaration.getInitializer();
|
||||||
if (initializer == null) return StackValue.none();
|
if (initializer == null) return StackValue.none();
|
||||||
|
|
||||||
@@ -3455,7 +3462,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);
|
||||||
|
|
||||||
initializeDestructuringDeclarationVariables(multiDeclaration, initializerAsReceiver, local);
|
initializeDestructuringDeclarationVariables(multiDeclaration, initializerAsReceiver, local, asProperty);
|
||||||
|
|
||||||
if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
|
if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
|
||||||
v.aconst(null);
|
v.aconst(null);
|
||||||
@@ -3470,6 +3477,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
@NotNull KtDestructuringDeclaration destructuringDeclaration,
|
@NotNull KtDestructuringDeclaration destructuringDeclaration,
|
||||||
@NotNull ReceiverValue receiver,
|
@NotNull ReceiverValue receiver,
|
||||||
@NotNull StackValue receiverStackValue
|
@NotNull StackValue receiverStackValue
|
||||||
|
) {
|
||||||
|
initializeDestructuringDeclarationVariables(destructuringDeclaration, receiver, receiverStackValue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeDestructuringDeclarationVariables(
|
||||||
|
@NotNull KtDestructuringDeclaration destructuringDeclaration,
|
||||||
|
@NotNull ReceiverValue receiver,
|
||||||
|
@NotNull StackValue receiverStackValue,
|
||||||
|
boolean asProperty
|
||||||
) {
|
) {
|
||||||
for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) {
|
for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) {
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
|
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
|
||||||
@@ -3481,7 +3497,21 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
// Do not call `componentX` for destructuring entry called _
|
// Do not call `componentX` for destructuring entry called _
|
||||||
if (variableDescriptor.getName().isSpecial()) continue;
|
if (variableDescriptor.getName().isSpecial()) continue;
|
||||||
|
|
||||||
initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, receiverStackValue));
|
if (asProperty && variableDescriptor instanceof PropertyDescriptor) {
|
||||||
|
StackValue.Property propertyValue = intermediateValueForProperty(
|
||||||
|
(PropertyDescriptor) variableDescriptor,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
StackValue.LOCAL_0,
|
||||||
|
null);
|
||||||
|
|
||||||
|
propertyValue.store(invokeFunction(call, resolvedCall, receiverStackValue), v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, receiverStackValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -216,6 +216,17 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
else if (declaration instanceof KtTypeAlias) {
|
else if (declaration instanceof KtTypeAlias) {
|
||||||
genTypeAlias((KtTypeAlias) declaration);
|
genTypeAlias((KtTypeAlias) declaration);
|
||||||
}
|
}
|
||||||
|
else if (declaration instanceof KtDestructuringDeclarationEntry) {
|
||||||
|
try {
|
||||||
|
propertyCodegen.genDestructuringDeclaration((KtDestructuringDeclarationEntry) declaration);
|
||||||
|
}
|
||||||
|
catch (ProcessCanceledException | CompilationException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new CompilationException("Failed to generate destructuring declaration entry " + declaration.getName(), e, declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Unknown parameter: " + declaration);
|
throw new IllegalArgumentException("Unknown parameter: " + declaration);
|
||||||
}
|
}
|
||||||
@@ -466,6 +477,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
initializeProperty(codegen.invoke(), (KtProperty) declaration);
|
initializeProperty(codegen.invoke(), (KtProperty) declaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (declaration instanceof KtDestructuringDeclaration) {
|
||||||
|
codegen.invoke().initializeDestructuringDeclaration((KtDestructuringDeclaration) declaration, true);
|
||||||
|
}
|
||||||
else if (declaration instanceof KtAnonymousInitializer) {
|
else if (declaration instanceof KtAnonymousInitializer) {
|
||||||
KtExpression body = ((KtAnonymousInitializer) declaration).getBody();
|
KtExpression body = ((KtAnonymousInitializer) declaration).getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -105,6 +105,18 @@ public class PropertyCodegen {
|
|||||||
gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
|
gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void genDestructuringDeclaration(@NotNull KtDestructuringDeclarationEntry entry) {
|
||||||
|
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, entry);
|
||||||
|
if (!(variableDescriptor instanceof PropertyDescriptor)) {
|
||||||
|
throw ExceptionLogger.logDescriptorNotFound(
|
||||||
|
"Destructuring declaration entry" + entry.getName() + " should have a property descriptor: " + variableDescriptor, entry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
|
||||||
|
genDestructuringDeclaration(entry, propertyDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
|
public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
|
||||||
assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
|
assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
|
||||||
gen(null, deserializedProperty, null, null);
|
gen(null, deserializedProperty, null, null);
|
||||||
@@ -129,6 +141,19 @@ public class PropertyCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void genDestructuringDeclaration(
|
||||||
|
@Nullable KtDestructuringDeclarationEntry entry,
|
||||||
|
@NotNull PropertyDescriptor descriptor
|
||||||
|
) {
|
||||||
|
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
|
||||||
|
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
||||||
|
|
||||||
|
genBackingFieldAndAnnotations(entry, descriptor, false);
|
||||||
|
|
||||||
|
generateGetter(entry, descriptor, null);
|
||||||
|
generateSetter(entry, descriptor, null);
|
||||||
|
}
|
||||||
|
|
||||||
private void genBackingFieldAndAnnotations(
|
private void genBackingFieldAndAnnotations(
|
||||||
@Nullable KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter
|
@Nullable KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -228,6 +228,11 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
|||||||
else if (declaration instanceof KtClassOrObject) {
|
else if (declaration instanceof KtClassOrObject) {
|
||||||
genClassOrObject((KtClassOrObject) declaration);
|
genClassOrObject((KtClassOrObject) declaration);
|
||||||
}
|
}
|
||||||
|
else if (declaration instanceof KtDestructuringDeclaration) {
|
||||||
|
for (KtDestructuringDeclarationEntry entry : ((KtDestructuringDeclaration) declaration).getEntries()) {
|
||||||
|
genSimpleMember(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
val (abc, def) = A()
|
||||||
|
|
||||||
|
val rv = abc + def
|
||||||
|
|
||||||
|
class A {
|
||||||
|
operator fun component1() = 123
|
||||||
|
operator fun component2() = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected: rv: 125
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
>>> val (a, b) = listOf(1, 2)
|
||||||
|
>>> a
|
||||||
|
1
|
||||||
|
>>> b
|
||||||
|
2
|
||||||
@@ -48,6 +48,12 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("destructuringDeclaration.kts")
|
||||||
|
public void testDestructuringDeclaration() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/destructuringDeclaration.kts");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("empty.kts")
|
@TestMetadata("empty.kts")
|
||||||
public void testEmpty() throws Exception {
|
public void testEmpty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/empty.kts");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/empty.kts");
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("destructuringDeclaration.repl")
|
||||||
|
public void testDestructuringDeclaration() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/destructuringDeclaration.repl");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("empty.repl")
|
@TestMetadata("empty.repl")
|
||||||
public void testEmpty() throws Exception {
|
public void testEmpty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/empty.repl");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/empty.repl");
|
||||||
|
|||||||
Reference in New Issue
Block a user