From 7016ce9b41346d3248939f2e8bafeee125f4f82b Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 22 Aug 2016 14:36:19 +0300 Subject: [PATCH] JS: refactor how cached access translators work. Fix cached access translator in case of arrays. Use cached access translator to translate reassignments --- .../test/semantics/EvaluationOrderTest.java | 4 ++ .../operation/IncrementTranslator.java | 26 ++------- .../OverloadedAssignmentTranslator.java | 15 +++-- .../reference/AccessTranslationUtils.java | 6 -- .../translate/reference/AccessTranslator.java | 2 +- .../reference/ArrayAccessTranslator.java | 51 +++++++---------- .../BackingFieldAccessTranslator.java | 14 +---- .../reference/CachedAccessTranslator.java | 30 ---------- ...panionObjectIntrinsicAccessTranslator.java | 19 ++----- .../reference/ReferenceAccessTranslator.java | 14 +---- .../reference/VariableAccessTranslator.java | 29 +++------- .../cases/reassignmentLhsCaching.kt | 55 +++++++++++++++++++ 12 files changed, 108 insertions(+), 157 deletions(-) delete mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CachedAccessTranslator.java create mode 100644 js/js.translator/testData/expression/evaluationOrder/cases/reassignmentLhsCaching.kt diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java index f41811107c0..82bd0e5fe23 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java @@ -136,4 +136,8 @@ public class EvaluationOrderTest extends AbstractExpressionTest { public void testCastWithBreakContinueReturn() throws Exception { checkFooBoxIsOk(); } + + public void testReassignmentLhsCaching() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java index a03bbdfa9b5..b89c96c83a2 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.js.translate.operation; -import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.JsBinaryOperation; import com.google.dart.compiler.backend.js.ast.JsBinaryOperator; import com.google.dart.compiler.backend.js.ast.JsExpression; @@ -27,20 +26,16 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; -import org.jetbrains.kotlin.js.translate.reference.CachedAccessTranslator; +import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtUnaryExpression; import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt; import org.jetbrains.kotlin.types.expressions.OperatorConventions; -import java.util.List; - -import static org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator; +import static org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils.getAccessTranslator; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.newSequence; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getBaseExpression; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.isPrefix; -import static org.jetbrains.kotlin.js.translate.utils.TemporariesUtils.temporariesInitialization; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic; // TODO: provide better increment translator logic @@ -63,23 +58,18 @@ public abstract class IncrementTranslator extends AbstractTranslator { @NotNull protected final KtUnaryExpression expression; @NotNull - protected final CachedAccessTranslator accessTranslator; + protected final AccessTranslator accessTranslator; protected IncrementTranslator(@NotNull KtUnaryExpression expression, @NotNull TranslationContext context) { super(context); this.expression = expression; KtExpression baseExpression = getBaseExpression(expression); - this.accessTranslator = getCachedAccessTranslator(baseExpression, context()); + this.accessTranslator = getAccessTranslator(baseExpression, context()).getCached(); } @NotNull protected JsExpression translateIncrementExpression() { - return withTemporariesInitialized(doTranslateIncrementExpression()); - } - - @NotNull - private JsExpression doTranslateIncrementExpression() { if (isPrefix(expression)) { return asPrefix(); } @@ -115,14 +105,6 @@ public abstract class IncrementTranslator extends AbstractTranslator { return accessTranslator.translateAsSet(overloadedMethodCallOnPropertyGetter); } - @NotNull - private JsExpression withTemporariesInitialized(@NotNull JsExpression expression) { - List temporaries = accessTranslator.declaredTemporaries(); - List expressions = Lists.newArrayList(temporariesInitialization(temporaries)); - expressions.add(expression); - return newSequence(expressions); - } - @NotNull abstract JsExpression operationExpression(@NotNull JsExpression receiver); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java index 4125566767c..02264ff4644 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java @@ -22,13 +22,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; import org.jetbrains.kotlin.js.translate.context.TranslationContext; +import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; import org.jetbrains.kotlin.psi.KtBinaryExpression; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; public final class OverloadedAssignmentTranslator extends AssignmentTranslator { - private boolean forceOrderOfEvaluation; - @NotNull public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { @@ -49,22 +48,22 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator { if (isVariableReassignment) { return reassignment(); } - return overloadedMethodInvocation(); + return overloadedMethodInvocation(createAccessTranslator(expression.getLeft(), false)); } @NotNull private JsExpression reassignment() { - JsExpression newValue = overloadedMethodInvocation(); - return createAccessTranslator(expression.getLeft(), forceOrderOfEvaluation).translateAsSet(newValue); + AccessTranslator accessTranslator = createAccessTranslator(expression.getLeft(), false).getCached(); + JsExpression newValue = overloadedMethodInvocation(accessTranslator); + return accessTranslator.translateAsSet(newValue); } @NotNull - private JsExpression overloadedMethodInvocation() { + private JsExpression overloadedMethodInvocation(AccessTranslator accessTranslator) { JsBlock innerBlock = new JsBlock(); TranslationContext innerContext = context().innerBlock(innerBlock); - JsExpression oldValue = createAccessTranslator(expression.getLeft(), false).translateAsGet(); + JsExpression oldValue = accessTranslator.translateAsGet(); JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue); - forceOrderOfEvaluation = !innerBlock.isEmpty(); context().addStatementsToCurrentBlockFrom(innerBlock); return result; } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslationUtils.java index 508bcdd93a6..cb090745940 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslationUtils.java @@ -73,12 +73,6 @@ public final class AccessTranslationUtils { return ArrayAccessTranslator.newInstance(expression, accessArrayContext); } - @NotNull - public static CachedAccessTranslator getCachedAccessTranslator(@NotNull KtExpression referenceExpression, - @NotNull TranslationContext context) { - return getAccessTranslator(referenceExpression, context).getCached(); - } - @NotNull public static JsExpression translateAsGet(@NotNull KtExpression expression, @NotNull TranslationContext context) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslator.java index b1557d56a71..e3f102af857 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/AccessTranslator.java @@ -32,5 +32,5 @@ public interface AccessTranslator { //TODO: remove that method @NotNull - CachedAccessTranslator getCached(); + AccessTranslator getCached(); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ArrayAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ArrayAccessTranslator.java index c76d873ead9..5ba6ddbba1f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ArrayAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ArrayAccessTranslator.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.Translation; @@ -33,7 +32,10 @@ import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class ArrayAccessTranslator extends AbstractTranslator implements AccessTranslator { @@ -46,8 +48,7 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT @NotNull private final KtArrayAccessExpression expression; - protected ArrayAccessTranslator(@NotNull KtArrayAccessExpression expression, - @NotNull TranslationContext context) { + private ArrayAccessTranslator(@NotNull KtArrayAccessExpression expression, @NotNull TranslationContext context) { super(context); this.expression = expression; } @@ -66,12 +67,7 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT @NotNull @Override public JsExpression translateAsSet(@NotNull JsExpression setTo) { - return translateAsSet(getArrayExpression(), setTo); - } - - @NotNull - protected JsExpression translateAsSet(@NotNull JsExpression arrayExpression, @NotNull JsExpression toSetTo) { - return translateAsMethodCall(arrayExpression, toSetTo); + return translateAsMethodCall(getArrayExpression(), setTo); } @NotNull @@ -115,50 +111,43 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT @NotNull @Override - public CachedAccessTranslator getCached() { - List temporaries = new ArrayList(); + public AccessTranslator getCached() { Map aliases = new HashMap(); - TemporaryVariable temporaryArrayExpression = context().declareTemporary(getArrayExpression()); - temporaries.add(temporaryArrayExpression); + JsExpression arrayExpression = context().cacheExpressionIfNeeded(getArrayExpression()); + aliases.put(expression.getArrayExpression(), arrayExpression); for (KtExpression ktExpression : expression.getIndexExpressions()) { - JsExpression jsExpression = Translation.translateAsExpression(ktExpression, context()); - TemporaryVariable temporaryVariable = context().declareTemporary(jsExpression); - temporaries.add(temporaryVariable); - aliases.put(ktExpression, temporaryVariable.reference()); + JsExpression jsExpression = context().cacheExpressionIfNeeded(Translation.translateAsExpression(ktExpression, context())); + aliases.put(ktExpression, jsExpression); } - return new CachedArrayAccessTranslator(expression, context().innerContextWithAliasesForExpressions(aliases), - temporaryArrayExpression, temporaries); + + return new CachedArrayAccessTranslator(expression, context().innerContextWithAliasesForExpressions(aliases), arrayExpression); } - private static class CachedArrayAccessTranslator extends ArrayAccessTranslator implements CachedAccessTranslator { + private static class CachedArrayAccessTranslator extends ArrayAccessTranslator { @NotNull - private final TemporaryVariable temporaryArrayExpression; - @NotNull - private final List declaredTemporaries; + private final JsExpression arrayExpression; protected CachedArrayAccessTranslator( @NotNull KtArrayAccessExpression expression, @NotNull TranslationContext context, - @NotNull TemporaryVariable temporaryArrayExpression, - @NotNull List temporaries + @NotNull JsExpression arrayExpression ) { super(expression, context); - this.temporaryArrayExpression = temporaryArrayExpression; - declaredTemporaries = temporaries; + this.arrayExpression = arrayExpression; } @NotNull @Override protected JsExpression getArrayExpression() { - return temporaryArrayExpression.reference(); + return arrayExpression; } @NotNull @Override - public List declaredTemporaries() { - return declaredTemporaries; + public AccessTranslator getCached() { + return this; } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/BackingFieldAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/BackingFieldAccessTranslator.java index eb45d037527..cff7ddd7eb7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/BackingFieldAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/BackingFieldAccessTranslator.java @@ -20,19 +20,15 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.PropertyDescriptor; import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptorKt; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.psi.KtSimpleNameExpression; -import java.util.Collections; -import java.util.List; - import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference; -public final class BackingFieldAccessTranslator extends AbstractTranslator implements CachedAccessTranslator { +public final class BackingFieldAccessTranslator extends AbstractTranslator implements AccessTranslator { @NotNull private final PropertyDescriptor descriptor; @@ -66,13 +62,7 @@ public final class BackingFieldAccessTranslator extends AbstractTranslator imple @NotNull @Override - public CachedAccessTranslator getCached() { + public AccessTranslator getCached() { return this; } - - @NotNull - @Override - public List declaredTemporaries() { - return Collections.emptyList(); - } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CachedAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CachedAccessTranslator.java deleted file mode 100644 index f041e11ad25..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CachedAccessTranslator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2015 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.js.translate.reference; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; - -import java.util.List; - -/** - * Represents a translator which guaranties that all expression will be computed only once. - */ -public interface CachedAccessTranslator extends AccessTranslator { - @NotNull - List declaredTemporaries(); -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CompanionObjectIntrinsicAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CompanionObjectIntrinsicAccessTranslator.java index 970015dd3e4..00fae9c14b4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CompanionObjectIntrinsicAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CompanionObjectIntrinsicAccessTranslator.java @@ -20,19 +20,15 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.intrinsic.objects.ObjectIntrinsic; import org.jetbrains.kotlin.psi.KtReferenceExpression; import org.jetbrains.kotlin.psi.KtSimpleNameExpression; -import java.util.Collections; -import java.util.List; - import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; -public class CompanionObjectIntrinsicAccessTranslator extends AbstractTranslator implements CachedAccessTranslator { +public class CompanionObjectIntrinsicAccessTranslator extends AbstractTranslator implements AccessTranslator { @NotNull /*package*/ static CompanionObjectIntrinsicAccessTranslator newInstance( @NotNull KtSimpleNameExpression expression, @@ -60,7 +56,10 @@ public class CompanionObjectIntrinsicAccessTranslator extends AbstractTranslator } @NotNull - private static JsExpression generateReferenceToCompanionObject(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) { + private static JsExpression generateReferenceToCompanionObject( + @NotNull DeclarationDescriptor descriptor, + @NotNull TranslationContext context + ) { ObjectIntrinsic objectIntrinsic = context.intrinsics().getObjectIntrinsic((ClassDescriptor) descriptor); return objectIntrinsic.apply(context); } @@ -79,13 +78,7 @@ public class CompanionObjectIntrinsicAccessTranslator extends AbstractTranslator @NotNull @Override - public CachedAccessTranslator getCached() { + public AccessTranslator getCached() { return this; } - - @NotNull - @Override - public List declaredTemporaries() { - return Collections.emptyList(); - } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceAccessTranslator.java index cdb9fb22ca5..7ce2f9f0195 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceAccessTranslator.java @@ -19,19 +19,15 @@ package org.jetbrains.kotlin.js.translate.reference; import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.psi.KtSimpleNameExpression; -import java.util.Collections; -import java.util.List; - import static org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsLocalNameReference; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; -public final class ReferenceAccessTranslator extends AbstractTranslator implements CachedAccessTranslator { +public final class ReferenceAccessTranslator extends AbstractTranslator implements AccessTranslator { @NotNull /*package*/ static ReferenceAccessTranslator newInstance(@NotNull KtSimpleNameExpression expression, @@ -63,13 +59,7 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen @NotNull @Override - public CachedAccessTranslator getCached() { + public AccessTranslator getCached() { return this; } - - @NotNull - @Override - public List declaredTemporaries() { - return Collections.emptyList(); - } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java index c5677fa7a9c..8e294ed2a8b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; -import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.psi.KtReferenceExpression; @@ -29,9 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; -import java.util.Collections; -import java.util.List; - public class VariableAccessTranslator extends AbstractTranslator implements AccessTranslator { public static VariableAccessTranslator newInstance( @NotNull TranslationContext context, @@ -74,35 +70,24 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce @NotNull @Override - public CachedAccessTranslator getCached() { - TemporaryVariable temporaryVariable = receiver == null ? null : context().declareTemporary(receiver); - return new CachedVariableAccessTranslator(context(), resolvedCall, temporaryVariable); + public AccessTranslator getCached() { + JsExpression cachedReceiver = receiver != null ? context().cacheExpressionIfNeeded(receiver) : null; + return new CachedVariableAccessTranslator(context(), resolvedCall, cachedReceiver); } - private static class CachedVariableAccessTranslator extends VariableAccessTranslator implements CachedAccessTranslator { - @Nullable - private final TemporaryVariable cachedReceiver; - + private static class CachedVariableAccessTranslator extends VariableAccessTranslator implements AccessTranslator { public CachedVariableAccessTranslator( @NotNull TranslationContext context, @NotNull ResolvedCall resolvedCall, - @Nullable TemporaryVariable cachedReceiver + @Nullable JsExpression cachedReceiver ) { - super(context, resolvedCall, cachedReceiver == null ? null : cachedReceiver.reference()); - this.cachedReceiver = cachedReceiver; + super(context, resolvedCall, cachedReceiver); } @NotNull @Override - public List declaredTemporaries() { - return cachedReceiver == null ? Collections.emptyList() : Collections.singletonList(cachedReceiver); - } - - @NotNull - @Override - public CachedAccessTranslator getCached() { + public AccessTranslator getCached() { return this; } } - } diff --git a/js/js.translator/testData/expression/evaluationOrder/cases/reassignmentLhsCaching.kt b/js/js.translator/testData/expression/evaluationOrder/cases/reassignmentLhsCaching.kt new file mode 100644 index 00000000000..7ac27ac179c --- /dev/null +++ b/js/js.translator/testData/expression/evaluationOrder/cases/reassignmentLhsCaching.kt @@ -0,0 +1,55 @@ +package foo + +var log = "" + +class A(val value: Int) { + operator fun plus(other: A): A { + log += "A.plus(${other.value});" + return A(value + other.value) + } +} + +val _array = arrayOf(A(2)) + +fun getArray(): Array { + log += "getArray();" + return _array +} + +fun getArrayIndex(): Int { + log += "getArrayIndex();" + return 0 +} + +class B(value: Int) { + var a = A(value) +} + +val _property = B(10) +val _functionResult = B(100) + +val foo: B + get() { + log += "foo;" + return _property + } + +fun bar(): B { + log += "bar();" + return _functionResult +} + +fun box(): String { + getArray()[getArrayIndex()] += A(3) + assertEquals(5, _array[0].value) + + foo.a += A(20) + assertEquals(30, _property.a.value) + + bar().a += A(200) + assertEquals(300, _functionResult.a.value) + + assertEquals("getArray();getArrayIndex();A.plus(3);foo;A.plus(20);bar();A.plus(200);", log) + + return "OK" +} \ No newline at end of file