Generate non-local destructuring declarations as properties

#KT-5620 Fixed
 #KT-15810 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-05-24 17:32:11 +03:00
parent 400ecd5e13
commit 47f2386212
8 changed files with 106 additions and 5 deletions
@@ -3439,6 +3439,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Override
public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) {
return initializeDestructuringDeclaration(multiDeclaration, false);
}
public StackValue initializeDestructuringDeclaration(
@NotNull KtDestructuringDeclaration multiDeclaration,
boolean asProperty
) {
KtExpression initializer = multiDeclaration.getInitializer();
if (initializer == null) return StackValue.none();
@@ -3455,7 +3462,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
v.store(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) {
v.aconst(null);
@@ -3470,6 +3477,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@NotNull KtDestructuringDeclaration destructuringDeclaration,
@NotNull ReceiverValue receiver,
@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()) {
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 _
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");
* 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) {
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 {
throw new IllegalArgumentException("Unknown parameter: " + declaration);
}
@@ -466,6 +477,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
initializeProperty(codegen.invoke(), (KtProperty) declaration);
}
}
else if (declaration instanceof KtDestructuringDeclaration) {
codegen.invoke().initializeDestructuringDeclaration((KtDestructuringDeclaration) declaration, true);
}
else if (declaration instanceof KtAnonymousInitializer) {
KtExpression body = ((KtAnonymousInitializer) declaration).getBody();
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");
* 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());
}
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) {
assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
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(
@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");
* 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) {
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
+5
View File
@@ -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);
}
@TestMetadata("destructuringDeclaration.kts")
public void testDestructuringDeclaration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/destructuringDeclaration.kts");
doTest(fileName);
}
@TestMetadata("empty.kts")
public void testEmpty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/empty.kts");
@@ -48,6 +48,12 @@ public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest {
doTest(fileName);
}
@TestMetadata("destructuringDeclaration.repl")
public void testDestructuringDeclaration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/destructuringDeclaration.repl");
doTest(fileName);
}
@TestMetadata("empty.repl")
public void testEmpty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/empty.repl");