KT-10785 Fixed. Change predicate that decides whether to dereference assignment target as a property accessor or as a backing field.

This commit is contained in:
Alexey Andreev
2016-02-19 11:30:34 +03:00
parent dbde566b66
commit 0a2cff9056
5 changed files with 78 additions and 19 deletions
@@ -98,6 +98,10 @@ public final class PropertyAccessTest extends SingleFileTranslationTest {
checkFooBoxIsOk(); checkFooBoxIsOk();
} }
public void testPropertyAssignment() throws Exception {
checkFooBoxIsOk();
}
@Override @Override
@NotNull @NotNull
protected List<String> additionalJsFiles(@NotNull EcmaVersion ecmaVersion) { protected List<String> additionalJsFiles(@NotNull EcmaVersion ecmaVersion) {
@@ -359,13 +359,12 @@ public class TranslationContext {
} }
private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) { private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) {
if (descriptor == declarationDescriptor) { if (declarationDescriptor instanceof ClassDescriptor && !DescriptorUtils.isCompanionObject(declarationDescriptor)) {
return true; return descriptor == declarationDescriptor;
} }
if (declarationDescriptor instanceof ConstructorDescriptor) { else {
return descriptor == declarationDescriptor.getContainingDeclaration(); return declarationDescriptor != null && descriptor == DescriptorUtils.getContainingClass(declarationDescriptor);
} }
return false;
} }
@NotNull @NotNull
@@ -392,7 +391,7 @@ public class TranslationContext {
} }
@NotNull @NotNull
private DefinitionPlace getDefinitionPlace() { public DefinitionPlace getDefinitionPlace() {
if (definitionPlace != null) return definitionPlace; if (definitionPlace != null) return definitionPlace;
if (parent != null) return parent.getDefinitionPlace(); if (parent != null) return parent.getDefinitionPlace();
@@ -430,4 +429,9 @@ public class TranslationContext {
} }
return null; return null;
} }
@Nullable
public DeclarationDescriptor getDeclarationDescriptor() {
return declarationDescriptor;
}
} }
@@ -108,6 +108,7 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
return null; return null;
} }
context = context.newDeclaration(descriptor, context.getDefinitionPlace());
JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod(); JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod();
result.add(methodAsPropertyInitializer); result.add(methodAsPropertyInitializer);
return null; return null;
@@ -116,6 +117,7 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
@Override @Override
public Void visitProperty(@NotNull KtProperty expression, TranslationContext context) { public Void visitProperty(@NotNull KtProperty expression, TranslationContext context) {
PropertyDescriptor propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression); PropertyDescriptor propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression);
context.newDeclaration(propertyDescriptor, context.getDefinitionPlace());
PropertyTranslatorKt.translateAccessors(propertyDescriptor, expression, result, context); PropertyTranslatorKt.translateAccessors(propertyDescriptor, expression, result, context);
return null; return null;
} }
@@ -19,18 +19,18 @@ package org.jetbrains.kotlin.js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsBlock; import com.google.dart.compiler.backend.js.ast.JsBlock;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor; import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.psi.KtBinaryExpression;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils; import org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils;
import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
import org.jetbrains.kotlin.js.translate.reference.BackingFieldAccessTranslator; import org.jetbrains.kotlin.js.translate.reference.BackingFieldAccessTranslator;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.isVariableReassignment; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.isVariableReassignment;
@@ -72,7 +72,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
JsBlock rightBlock = new JsBlock(); JsBlock rightBlock = new JsBlock();
this.right = translateRightExpression(context, expression, rightBlock); this.right = translateRightExpression(context, expression, rightBlock);
if (isValProperty(left, context)) { if (isReferenceToBackingFieldFromConstructor(left, context)) {
KtSimpleNameExpression simpleName = getSimpleName(left); KtSimpleNameExpression simpleName = getSimpleName(left);
assert simpleName != null; assert simpleName != null;
this.accessTranslator = BackingFieldAccessTranslator.newInstance(simpleName, context); this.accessTranslator = BackingFieldAccessTranslator.newInstance(simpleName, context);
@@ -83,17 +83,45 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
context.addStatementsToCurrentBlockFrom(rightBlock); context.addStatementsToCurrentBlockFrom(rightBlock);
} }
private static boolean isValProperty( private static boolean isReferenceToBackingFieldFromConstructor(
@NotNull KtExpression expression, @NotNull KtExpression expression,
@NotNull TranslationContext context @NotNull TranslationContext context
) { ) {
KtSimpleNameExpression simpleNameExpression = getSimpleName(expression); if (expression instanceof KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) expression;
if (simpleNameExpression != null) { DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), nameExpression);
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), simpleNameExpression); return isReferenceToBackingFieldFromConstructor(descriptor, context);
return descriptor instanceof PropertyDescriptor && !((PropertyDescriptor) descriptor).isVar(); }
else if (expression instanceof KtDotQualifiedExpression) {
KtDotQualifiedExpression qualifiedExpression = (KtDotQualifiedExpression) expression;
if (qualifiedExpression.getReceiverExpression() instanceof KtThisExpression &&
qualifiedExpression.getSelectorExpression() instanceof KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) qualifiedExpression.getSelectorExpression();
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), nameExpression);
return isReferenceToBackingFieldFromConstructor(descriptor, context);
}
} }
return false; return false;
} }
private static boolean isReferenceToBackingFieldFromConstructor(
@Nullable DeclarationDescriptor descriptor,
@NotNull TranslationContext context
) {
if (!(descriptor instanceof PropertyDescriptor)) {
return false;
}
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (!(context.getDeclarationDescriptor() instanceof ClassDescriptor)) {
return false;
}
ClassDescriptor classDescriptor = (ClassDescriptor) context.getDeclarationDescriptor();
if (classDescriptor != propertyDescriptor.getContainingDeclaration()) {
return false;
}
return !propertyDescriptor.isVar();
}
} }
@@ -0,0 +1,21 @@
// See https://youtrack.jetbrains.com/issue/KT-10785
package foo
class A(var x: Int) {
operator fun plusAssign(other: A) {
x += other.x
}
}
object B {
private var holder = A(42)
val foo: A
get() = holder
}
fun box(): String {
B.foo += A(23)
if (B.foo.x != 65) return "failed: ${B.foo.x}"
return "OK"
}