From fae803ac6fa69332974c01e4dd65139e9afd498d Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Thu, 24 Nov 2011 15:14:54 +0400 Subject: [PATCH] Refactoring property access translation code. --- .idea/workspace.xml | 713 ++++++++++-------- .../google/dart/compiler/util/AstUtil.java | 14 + .../translate/BinaryOperationTranslator.java | 8 +- .../k2js/translate/ExpressionVisitor.java | 32 +- .../k2js/translate/OperationTranslator.java | 32 + .../translate/PropertyAccessTranslator.java | 152 ++-- .../k2js/translate/ReferenceTranslator.java | 7 +- .../k2js/translate/TranslationUtils.java | 1 - .../translate/UnaryOperationTranslator.java | 121 ++- .../k2js/test/OperatorOverloadingTest.java | 15 + .../cases/overloadedCallOnProperty.kt | 17 + .../cases/postfixOnProperty.kt | 18 + .../cases/prefixIncReturnsCorrectValue.kt | 17 + 13 files changed, 756 insertions(+), 391 deletions(-) create mode 100644 translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt create mode 100644 translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt create mode 100644 translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt diff --git a/.idea/workspace.xml b/.idea/workspace.xml index a2b9194b3dd..381b9217ce2 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -8,15 +8,19 @@ - - - + + + - + + - - + + + + + @@ -47,21 +51,6 @@ - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + + + @@ -198,64 +189,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + @@ -273,7 +219,52 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -282,7 +273,7 @@ - + @@ -309,22 +300,22 @@ @@ -399,6 +390,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -809,6 +795,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + localhost @@ -945,7 +1036,7 @@ - + @@ -963,7 +1054,7 @@ - + @@ -1007,7 +1098,7 @@ @@ -1054,6 +1145,13 @@ + + + + + + + @@ -1068,6 +1166,20 @@ + + + + + + + + + + + + + + @@ -1075,6 +1187,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -1082,6 +1215,13 @@ + + + + + + + @@ -1089,79 +1229,32 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/js/src/com/google/dart/compiler/util/AstUtil.java b/js/src/com/google/dart/compiler/util/AstUtil.java index 1b583c11257..09d37bbd348 100644 --- a/js/src/com/google/dart/compiler/util/AstUtil.java +++ b/js/src/com/google/dart/compiler/util/AstUtil.java @@ -8,6 +8,7 @@ import com.google.dart.compiler.InternalCompilerException; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.common.SourceInfo; +import java.util.Arrays; import java.util.List; /** @@ -320,4 +321,17 @@ public class AstUtil { public static JsExpression equalsTrue(JsExpression expression, JsProgram program) { return equals(expression, program.getTrueLiteral()); } + + public static JsBinaryOperation comma(JsExpression... expressions) { + return comma(Arrays.asList(expressions)); + } + + public static JsBinaryOperation comma(List expressions) { + assert expressions.size() >= 2 : "Comma operator applicable to two or more expressions"; + JsBinaryOperation result = new JsBinaryOperation(JsBinaryOperator.COMMA, expressions.get(0), expressions.get(1)); + for (int i = 2; i < expressions.size(); ++i) { + result = new JsBinaryOperation(JsBinaryOperator.COMMA, result, expressions.get(i)); + } + return result; + } } diff --git a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java index 27a11cc4568..4e87c499524 100644 --- a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java @@ -42,7 +42,7 @@ public final class BinaryOperationTranslator extends OperationTranslator { return translateAsBinaryOperation(); } - //TODO: think about the ways to improve logic here + //TODO: method too long @Nullable public JsInvocation translateAsSetterCall() { JetToken jetOperationToken = getOperationToken(); @@ -50,11 +50,11 @@ public final class BinaryOperationTranslator extends OperationTranslator { return null; } JetExpression leftExpression = expression.getLeft(); - JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()). - translateAsPropertySetterCall(leftExpression); - if (setterCall == null) { + PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext()); + if (!propertyAccessTranslator.canBePropertySetterCall(leftExpression)) { return null; } + JsInvocation setterCall = propertyAccessTranslator.translateAsPropertySetterCall(leftExpression); JsExpression right = translateRightExpression(); setterCall.setArguments(Arrays.asList(right)); return setterCall; diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index c5872ebd326..c7b051cc1a0 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -19,6 +19,12 @@ import java.util.List; */ public final class ExpressionVisitor extends TranslatorVisitor { + @NotNull + private JsExpression translateAsExpression(@NotNull JetExpression expression, + @NotNull TranslationContext context) { + return AstUtil.convertToExpression(expression.accept(this, context)); + } + @Override @NotNull public JsNode visitConstantExpression(@NotNull JetConstantExpression expression, @@ -157,7 +163,8 @@ public final class ExpressionVisitor extends TranslatorVisitor { } @Nullable - private JsStatement translateElseAsStatement(JetIfExpression expression, TranslationContext context) { + private JsStatement translateElseAsStatement(@NotNull JetIfExpression expression, + @NotNull TranslationContext context) { JetExpression jetElse = expression.getElse(); if (jetElse == null) { return null; @@ -203,10 +210,6 @@ public final class ExpressionVisitor extends TranslatorVisitor { return translateAsExpression(expression, context); } - private JsExpression translateAsExpression(JetExpression expression, TranslationContext context) { - return AstUtil.convertToExpression(expression.accept(this, context)); - } - @Override @NotNull public JsNode visitWhileExpression(@NotNull JetWhileExpression expression, @NotNull TranslationContext context) { @@ -261,19 +264,13 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull private JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression, @NotNull TranslationContext context) { - JsInvocation getterCall = translateAsGetterCall(expression, context); - if (getterCall != null) { - return getterCall; + PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(context); + if (propertyAccessTranslator.canBePropertyGetterCall(expression)) { + return propertyAccessTranslator.translateAsPropertyGetterCall(expression); } return translateAsQualifiedAccess(expression, context); } - @Nullable - private JsInvocation translateAsGetterCall(@NotNull JetQualifiedExpression expression, - @NotNull TranslationContext context) { - return Translation.propertyAccessTranslator(context).resolveAsPropertyGet(expression); - } - @NotNull private JsExpression translateAsQualifiedAccess(@NotNull JetQualifiedExpression expression, @NotNull TranslationContext context) { @@ -386,5 +383,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { return Translation.functionTranslator(context).translateAsLiteral(expression.getFunctionLiteral()); } + @Override + @NotNull + public JsNode visitThisExpression(@NotNull JetThisExpression expression, + @NotNull TranslationContext context) { + return new JsThisRef(); + } + } diff --git a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java index f8998f6fc18..f122d2f8dcf 100644 --- a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java @@ -1,6 +1,9 @@ package org.jetbrains.k2js.translate; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsName; import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; @@ -43,4 +46,33 @@ public class OperationTranslator extends AbstractTranslator { return BindingUtils.getDescriptorForReferenceExpression (translationContext().bindingContext(), operationReference); } + + + protected final class TemporaryVariable { + + @NotNull + private final JsExpression assignmentExpression; + @NotNull + private final JsName variableName; + + private TemporaryVariable(@NotNull JsExpression initExpression) { + this.variableName = translationContext().enclosingScope().declareTemporary(); + this.assignmentExpression = AstUtil.newAssignment(variableName.makeRef(), initExpression); + } + + @NotNull + public JsNameRef nameReference() { + return variableName.makeRef(); + } + + @NotNull + public JsExpression assignmentExpression() { + return assignmentExpression; + } + } + + @NotNull + public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) { + return new TemporaryVariable(initExpression); + } } diff --git a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java index 2ef432566fa..6ad3fc4bf4a 100644 --- a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java @@ -23,6 +23,9 @@ import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; //TODO ask for code review. Class has messy code. public final class PropertyAccessTranslator extends AbstractTranslator { + private static String MESSAGE = "Cannot be accessor call. Use canBeProperty*Call to ensure this method " + + "can be called safely."; + @NotNull public static PropertyAccessTranslator newInstance(@NotNull TranslationContext context) { return new PropertyAccessTranslator(context); @@ -32,28 +35,88 @@ public final class PropertyAccessTranslator extends AbstractTranslator { super(context); } - @Nullable - public JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) { - JetExpression selectorExpression = expression.getSelectorExpression(); - assert selectorExpression != null : "Selector should not be null."; - JsName getterName = getPropertyGetterName(selectorExpression); - if (getterName == null) { - return null; + + //TODO: ask if these methods can be more clear + public boolean canBePropertyGetterCall(@NotNull JetExpression expression) { + if (expression instanceof JetQualifiedExpression) { + JetSimpleNameExpression selector = getNullableSelector((JetQualifiedExpression) expression); + if (selector == null) { + return false; + } + return (getNullableGetterName(selector) != null); } + if (expression instanceof JetSimpleNameExpression) { + return (getNullableGetterName((JetSimpleNameExpression) expression) != null); + } + return false; + } + + public boolean canBePropertyAccess(@NotNull JetExpression expression) { + return canBePropertyGetterCall(expression); + } + + public boolean canBePropertySetterCall(@NotNull JetExpression expression) { + if (expression instanceof JetQualifiedExpression) { + JetSimpleNameExpression selector = getNullableSelector((JetQualifiedExpression) expression); + if (selector == null) { + return false; + } + return (getNullableSetterName(selector) != null); + } + if (expression instanceof JetSimpleNameExpression) { + return (getNullableSetterName((JetSimpleNameExpression) expression) != null); + } + return false; + } + + @NotNull + public JsInvocation translateAsPropertyGetterCall(@NotNull JetExpression expression) { + if (expression instanceof JetQualifiedExpression) { + return resolveAsPropertyGet((JetQualifiedExpression) expression); + } + if (expression instanceof JetSimpleNameExpression) { + return resolveAsPropertyGet((JetSimpleNameExpression) expression); + } + throw new AssertionError(MESSAGE); + } + + @NotNull + private JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) { + JsName getterName = getNotNullGetterName(getNotNullSelector(expression)); return translateReceiverAndReturnAccessorInvocation(expression, getterName); } - @Nullable - JsInvocation resolveAsPropertyGet(@NotNull JetSimpleNameExpression expression) { - JsName getterName = getPropertyGetterName(expression); - if (getterName == null) { - return null; - } - JsNameRef getterReference = - TranslationUtils.getReference(translationContext(), expression, getterName); + @NotNull + private JsInvocation resolveAsPropertyGet(@NotNull JetSimpleNameExpression expression) { + JsName getterName = getNotNullGetterName(expression); + JsNameRef getterReference = TranslationUtils.getReference(translationContext(), expression, getterName); return AstUtil.newInvocation(getterReference); } + @NotNull + public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) { + if (expression instanceof JetDotQualifiedExpression) { + return resolveAsPropertySet((JetDotQualifiedExpression) expression); + } + if (expression instanceof JetSimpleNameExpression) { + return resolveAsPropertySet((JetSimpleNameExpression) expression); + } + throw new AssertionError(MESSAGE); + } + + @NotNull + private JsInvocation resolveAsPropertySet(@NotNull JetDotQualifiedExpression dotQualifiedExpression) { + JsName setterName = getNotNullSetterName(getNotNullSelector(dotQualifiedExpression)); + return translateReceiverAndReturnAccessorInvocation(dotQualifiedExpression, setterName); + } + + @NotNull + private JsInvocation resolveAsPropertySet(@NotNull JetSimpleNameExpression expression) { + JsName setterName = getNotNullSetterName(expression); + JsNameRef setterReference = Translation.generateCorrectReference(translationContext(), expression, setterName); + return AstUtil.newInvocation(setterReference); + } + @NotNull private JsInvocation translateReceiverAndReturnAccessorInvocation (@NotNull JetQualifiedExpression qualifiedExpression, @NotNull JsName accessorName) { @@ -65,39 +128,32 @@ public final class PropertyAccessTranslator extends AbstractTranslator { } @Nullable - public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) { - if (expression instanceof JetDotQualifiedExpression) { - return resolveAsPropertySet((JetDotQualifiedExpression) expression); - } - if (expression instanceof JetSimpleNameExpression) { - return resolveAsPropertySet((JetSimpleNameExpression) expression); - } - return null; - } - - @Nullable - private JsInvocation resolveAsPropertySet(@NotNull JetDotQualifiedExpression dotQualifiedExpression) { - JetExpression selectorExpression = dotQualifiedExpression.getSelectorExpression(); + private JetSimpleNameExpression getNullableSelector(@NotNull JetQualifiedExpression expression) { + JetExpression selectorExpression = expression.getSelectorExpression(); assert selectorExpression != null : "Selector should not be null."; - JsName setterName = getPropertySetterName(selectorExpression); - if (setterName == null) { + if (!(selectorExpression instanceof JetSimpleNameExpression)) { return null; } - return translateReceiverAndReturnAccessorInvocation(dotQualifiedExpression, setterName); + return (JetSimpleNameExpression) selectorExpression; + } + + + @NotNull + private JetSimpleNameExpression getNotNullSelector(@NotNull JetQualifiedExpression expression) { + JetSimpleNameExpression selectorExpression = getNullableSelector(expression); + assert selectorExpression != null : MESSAGE; + return selectorExpression; + } + + @NotNull + private JsName getNotNullGetterName(@NotNull JetSimpleNameExpression selectorExpression) { + JsName getterName = getNullableGetterName(selectorExpression); + assert getterName != null : MESSAGE; + return getterName; } @Nullable - JsInvocation resolveAsPropertySet(@NotNull JetSimpleNameExpression expression) { - JsName setterName = getPropertySetterName(expression); - if (setterName == null) { - return null; - } - JsNameRef setterReference = Translation.generateCorrectReference(translationContext(), expression, setterName); - return AstUtil.newInvocation(setterReference); - } - - @Nullable - public JsName getPropertyGetterName(@NotNull JetExpression expression) { + private JsName getNullableGetterName(@NotNull JetSimpleNameExpression expression) { PropertyDescriptor property = getPropertyDescriptor(expression); if (property == null) { return null; @@ -109,8 +165,16 @@ public final class PropertyAccessTranslator extends AbstractTranslator { return translationContext().getNameForDescriptor(getter); } + + @NotNull + private JsName getNotNullSetterName(@NotNull JetSimpleNameExpression selectorExpression) { + JsName setterName = getNullableSetterName(selectorExpression); + assert setterName != null : MESSAGE; + return setterName; + } + @Nullable - public JsName getPropertySetterName(@NotNull JetExpression expression) { + private JsName getNullableSetterName(@NotNull JetSimpleNameExpression expression) { PropertyDescriptor property = getPropertyDescriptor(expression); if (property == null) { return null; @@ -123,7 +187,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator { } @Nullable - private PropertyDescriptor getPropertyDescriptor(@NotNull JetExpression expression) { + private PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression) { ResolvedCall resolvedCall = BindingUtils.getResolvedCall(translationContext().bindingContext(), expression); if (resolvedCall != null) { diff --git a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java index eba33d226df..9f69645da31 100644 --- a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java @@ -43,7 +43,12 @@ public class ReferenceTranslator extends AbstractTranslator { @Nullable private JsInvocation resolveAsPropertyAccess(@NotNull JetSimpleNameExpression expression) { - return Translation.propertyAccessTranslator(translationContext()).resolveAsPropertyGet(expression); + + PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext()); + if (propertyAccessTranslator.canBePropertyGetterCall(expression)) { + return propertyAccessTranslator.translateAsPropertyGetterCall(expression); + } + return null; } @Nullable diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java index 235ce06ceca..68311099c28 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java @@ -38,5 +38,4 @@ public final class TranslationUtils { @NotNull String name) { return context.enclosingScope().findExistingName(name); } - } diff --git a/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java index 493061298cd..249b50ee6a0 100644 --- a/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java @@ -4,9 +4,12 @@ import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lexer.JetToken; +import java.util.Arrays; + /** * @author Talanov Pavel */ @@ -27,34 +30,120 @@ public final class UnaryOperationTranslator extends OperationTranslator { @NotNull private final JetUnaryExpression expression; + @NotNull + private final JsExpression baseExpression; private final boolean isPrefix; private final boolean isVariableReassignment; + private final boolean isStatement; + private final boolean isPropertyAccess; + @Nullable + private final JsNameRef operationReference; private UnaryOperationTranslator(@NotNull TranslationContext context, @NotNull JetUnaryExpression expression, boolean isPrefix) { super(context); this.expression = expression; this.isPrefix = isPrefix; - this.isVariableReassignment = BindingUtils.isVariableReassignment + this.isVariableReassignment = isVariableReassignment(expression); + this.isStatement = BindingUtils.isStatement(translationContext().bindingContext(), expression); + this.baseExpression = translateBaseExpression(); + this.isPropertyAccess = isPropertyAccess(); + this.operationReference = getOverloadedOperationReference(expression); + } + + private boolean isPropertyAccess() { + return Translation.propertyAccessTranslator(translationContext()).canBePropertyAccess(getBaseExpression()); + + } + + private boolean isVariableReassignment(JetUnaryExpression expression) { + return BindingUtils.isVariableReassignment (translationContext().bindingContext(), expression); } @NotNull JsExpression translate() { - JsExpression baseExpression = translateBaseExpression(); - JsNameRef operationReference = getOverloadedOperationReference(expression); if (operationReference != null) { - if (isPrefix && !isVariableReassignment) { - return overloadedMethodInvocation(baseExpression, operationReference); - } else if (isPrefix) { - - } + return translateOverload(); } - return jsUnaryExpression(baseExpression); + return jsUnaryExpression(); } @NotNull - private JsExpression jsUnaryExpression(@NotNull JsExpression baseExpression) { + private JsExpression translateOverload() { + if (isStatement || isPrefix) { + return asPrefix(); + } + if (isVariableReassignment) { + return asPostfixWithReassignment(); + } else { + return asPostfixWithNoReassignment(); + } + } + + @NotNull + private JsExpression asPrefix() { + if (isVariableReassignment) { + return variableReassignment(); + } + return overloadedMethodInvocation(baseExpression); + } + + @NotNull + private JsExpression asPostfixWithReassignment() { + // code fragment: expr(a++) + // generate: expr( (t = a, a = a.inc(), t) ) + TemporaryVariable t = declareTemporary(baseExpression); + JsExpression variableReassignment = variableReassignment(); + return AstUtil.comma(t.assignmentExpression(), variableReassignment, t.nameReference()); + } + + @NotNull + private JsExpression asPostfixWithNoReassignment() { + // code fragment: expr(a++) + // generate: expr( (t1 = a, t2 = t1, t2.inc(), t1) ) + assert operationReference != null; + TemporaryVariable t1 = declareTemporary(baseExpression); + TemporaryVariable t2 = declareTemporary(t1.nameReference()); + JsExpression methodCall = overloadedMethodInvocation(t2.nameReference()); + JsExpression returnedValue = t1.nameReference(); + return AstUtil.comma(t1.assignmentExpression(), t2.assignmentExpression(), methodCall, returnedValue); + } + + + //TODO: should modify this for properties + @NotNull + private JsExpression variableReassignment() { + if (isPropertyAccess) { + return propertyReassignment(); + } + return localVariableReassignment(); + } + + private JsExpression localVariableReassignment() { + assert baseExpression instanceof JsNameRef : "Base expression should be an l-value"; + return AstUtil.newAssignment((JsNameRef) baseExpression, overloadedMethodInvocation(baseExpression)); + } + + @NotNull + private JsExpression propertyReassignment() { + JetExpression jetBaseExpression = getBaseExpression(); + PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext()); + JsInvocation setterCall = propertyAccessTranslator.translateAsPropertySetterCall(jetBaseExpression); + assert propertyAccessTranslator.canBePropertyGetterCall(jetBaseExpression) : "Should be a getter call"; + JsExpression overloadedMethodCallOnPropertyGetter = overloadedMethodInvocation(baseExpression); + setterCall.setArguments(Arrays.asList(overloadedMethodCallOnPropertyGetter)); + return setterCall; + } + + @NotNull + private JsExpression overloadedMethodInvocation(@NotNull JsExpression receiver) { + AstUtil.setQualifier(operationReference, receiver); + return AstUtil.newInvocation(operationReference); + } + + @NotNull + private JsExpression jsUnaryExpression() { JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken()); if (isPrefix) { return new JsPrefixOperation(operator, baseExpression); @@ -65,16 +154,14 @@ public final class UnaryOperationTranslator extends OperationTranslator { @NotNull private JsExpression translateBaseExpression() { - JetExpression baseExpression = expression.getBaseExpression(); - assert baseExpression != null : "Unary expression should have a base expression"; + JetExpression baseExpression = getBaseExpression(); return Translation.translateAsExpression(baseExpression, translationContext()); } - @NotNull - private JsExpression overloadedMethodInvocation(@NotNull JsExpression receiver, - @NotNull JsNameRef operationReference) { - AstUtil.setQualifier(operationReference, receiver); - return AstUtil.newInvocation(operationReference); + private JetExpression getBaseExpression() { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null : "Unary expression should have a base expression"; + return baseExpression; } @NotNull diff --git a/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java index 01e57d2b0cc..60c4a939d53 100644 --- a/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java +++ b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java @@ -28,4 +28,19 @@ public class OperatorOverloadingTest extends TranslationTest { public void prefixInc() throws Exception { testFooBoxIsTrue("prefixDecOverload.kt"); } + + @Test + public void prefixIncReturnsCorrectValue() throws Exception { + testFooBoxIsTrue("prefixIncReturnsCorrectValue.kt"); + } + + @Test + public void overloadedCallOnProperty() throws Exception { + testFooBoxIsTrue("overloadedCallOnProperty.kt"); + } + + @Test + public void postfixOnProperty() throws Exception { + testFooBoxIsTrue("postfixOnProperty.kt"); + } } diff --git a/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt b/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt new file mode 100644 index 00000000000..6fb191134c1 --- /dev/null +++ b/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt @@ -0,0 +1,17 @@ +namespace foo + +var a = MyInt() + +class MyInt() { + var b = 0 + + fun inc() { + b = b + 1; + } +} + + +fun box() : Boolean { + a++; + return (a.b == 1); +} \ No newline at end of file diff --git a/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt b/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt new file mode 100644 index 00000000000..2b2eff8fb5d --- /dev/null +++ b/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt @@ -0,0 +1,18 @@ +namespace foo + +var a = MyInt() + +class MyInt() { + var b = 0 + + fun inc() : MyInt { + b = b + 1; + return this; + } +} + + +fun box() : Boolean { + val d = a++; + return (a.b == 1) && (d.b == 1); +} \ No newline at end of file diff --git a/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt b/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt new file mode 100644 index 00000000000..841ece2f555 --- /dev/null +++ b/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt @@ -0,0 +1,17 @@ +namespace foo + +class MyInt() { + var b = 0 + + fun dec() : MyInt { + b = b + 1; + return this; + } +} + + + fun box() : Boolean { + var c = MyInt() + val d = --c; + return (c.b == 1); + } \ No newline at end of file