JS: don't translate RHS of overloaded assignment operators twice. It can break compilation in some cases, for example, when there are lambdas in RHS.

Fix #KT-12808 #KT-12807
This commit is contained in:
Alexey Andreev
2016-07-08 15:15:34 +03:00
parent 996c1b6f87
commit cb2c8edaf9
5 changed files with 57 additions and 16 deletions
@@ -120,4 +120,8 @@ public final class OperatorOverloadingTest extends SingleFileTranslationTest {
public void testOverloadUnaryOperationsViaExtensionFunctions() throws Exception {
fooBoxTest();
}
public void testLambdaRhs() throws Exception {
checkFooBoxIsOk();
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsBlock;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,7 +36,6 @@ import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.isVariableRea
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getSimpleName;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.isAssignment;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateRightExpression;
public abstract class AssignmentTranslator extends AbstractTranslator {
@@ -56,10 +54,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
@NotNull
protected final KtBinaryExpression expression;
protected final AccessTranslator accessTranslator;
protected final boolean isVariableReassignment;
@NotNull
protected final JsExpression right;
protected AssignmentTranslator(@NotNull KtBinaryExpression expression,
@NotNull TranslationContext context) {
@@ -68,19 +63,16 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
KtExpression left = expression.getLeft();
assert left != null : "No left-hand side: " + expression.getText();
}
JsBlock rightBlock = new JsBlock();
this.right = translateRightExpression(context, expression, rightBlock);
if (isReferenceToBackingFieldFromConstructor(left, context)) {
protected final AccessTranslator createAccessTranslator(KtExpression left, boolean forceOrderOfEvaluation) {
if (isReferenceToBackingFieldFromConstructor(left, context())) {
KtSimpleNameExpression simpleName = getSimpleName(left);
assert simpleName != null;
this.accessTranslator = BackingFieldAccessTranslator.newInstance(simpleName, context);
return BackingFieldAccessTranslator.newInstance(simpleName, context());
} else {
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context(), !rightBlock.isEmpty());
return AccessTranslationUtils.getAccessTranslator(left, context(), forceOrderOfEvaluation);
}
context.addStatementsToCurrentBlockFrom(rightBlock);
}
private static boolean isReferenceToBackingFieldFromConstructor(
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.js.translate.operation;
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.JsBlock;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.psi.KtBinaryExpression;
@@ -29,9 +31,11 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.isAssignment;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.isSimpleNameExpressionNotDelegatedLocalVar;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateRightExpression;
public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
private JsExpression right;
private AccessTranslator accessTranslator;
@NotNull
public static JsExpression doTranslate(@NotNull KtBinaryExpression expression,
@@ -42,6 +46,11 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
private IntrinsicAssignmentTranslator(@NotNull KtBinaryExpression expression,
@NotNull TranslationContext context) {
super(expression, context);
JsBlock rightBlock = new JsBlock();
right = translateRightExpression(context, expression, rightBlock);
accessTranslator = createAccessTranslator(expression.getLeft(), !rightBlock.isEmpty());
context.addStatementsToCurrentBlockFrom(rightBlock);
}
@NotNull
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsBlock;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
@@ -26,6 +27,7 @@ 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,
@@ -52,11 +54,18 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
@NotNull
private JsExpression reassignment() {
return accessTranslator.translateAsSet(overloadedMethodInvocation());
JsExpression newValue = overloadedMethodInvocation();
return createAccessTranslator(expression.getLeft(), forceOrderOfEvaluation).translateAsSet(newValue);
}
@NotNull
private JsExpression overloadedMethodInvocation() {
return CallTranslator.translate(context(), resolvedCall, accessTranslator.translateAsGet());
JsBlock innerBlock = new JsBlock();
TranslationContext innerContext = context().innerBlock(innerBlock);
JsExpression oldValue = createAccessTranslator(expression.getLeft(), false).translateAsGet();
JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue);
forceOrderOfEvaluation = !innerBlock.isEmpty();
context().addStatementsToCurrentBlockFrom(innerBlock);
return result;
}
}
@@ -0,0 +1,27 @@
package foo
var global = ""
fun log(message: String) {
global += message
}
fun test1(): String {
val list = mutableListOf<(Int) -> Unit>()
var result = ""
list += { log("<$it>") }
list += { result += "($it)" }
list += { result += "[$it]"; result += "{$it}" }
for(f in list) f(1)
return result
}
fun box(): String {
assertEquals("(1)[1]{1}", test1())
assertEquals(global, "<1>")
return "OK"
}