KT-740: Make sure that assign and increment operations compute receiver only once:

- Array operations.
This commit is contained in:
unknown
2012-03-09 18:49:50 +04:00
parent 295b38bf32
commit beff2f9b1e
7 changed files with 90 additions and 25 deletions
@@ -64,4 +64,8 @@ public final class MiscTest extends AbstractExpressionTest {
public void testKt740() throws Exception {
checkFooBoxIsTrue("KT-740.kt");
}
public void testKt740_2() throws Exception {
checkFooBoxIsOk("KT-740-2.kt");
}
}
@@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author Pavel Talanov
* <p/>
* Abstract entity for language constructs that you can get/set. Also dispatches to the real implemntation.
* Abstract entity for language constructs that you can get/set.
*/
public interface AccessTranslator {
@@ -32,6 +32,7 @@ public interface AccessTranslator {
@NotNull
JsExpression translateAsSet(@NotNull JsExpression setTo);
//TODO: remove that method
@NotNull
CachedAccessTranslator getCached();
}
@@ -19,23 +19,18 @@ package org.jetbrains.k2js.translate.reference;
import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
/**
* @author Pavel Talanov
*/
//TODO: inspect not clear how the class handles set and get operations differently
public class ArrayAccessTranslator extends AbstractTranslator implements AccessTranslator {
/*package*/
@@ -46,16 +41,11 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull
private final JetArrayAccessExpression expression;
@NotNull
private final FunctionDescriptor methodDescriptor;
protected ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
@NotNull TranslationContext context) {
super(context);
this.expression = expression;
//TODO: that is strange
this.methodDescriptor = (FunctionDescriptor)
getDescriptorForReferenceExpression(context.bindingContext(), expression);
}
@NotNull
@@ -67,7 +57,7 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull
protected JsExpression translateAsGet(@NotNull JsExpression arrayExpression,
@NotNull List<JsExpression> indexExpression) {
return translateAsMethodCall(arrayExpression, indexExpression);
return translateAsMethodCall(arrayExpression, indexExpression, /*isGetter = */ true);
}
@NotNull
@@ -80,16 +70,17 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
protected JsExpression translateAsSet(@NotNull JsExpression arrayExpression, @NotNull List<JsExpression> indexExpressions, @NotNull JsExpression toSetTo) {
List<JsExpression> arguments = Lists.newArrayList(indexExpressions);
arguments.add(toSetTo);
return translateAsMethodCall(arrayExpression, arguments);
return translateAsMethodCall(arrayExpression, arguments, /*isGetter = */ false);
}
@NotNull
private JsExpression translateAsMethodCall(@NotNull JsExpression arrayExpression, @NotNull List<JsExpression> arguments) {
private JsExpression translateAsMethodCall(@NotNull JsExpression arrayExpression,
@NotNull List<JsExpression> arguments,
boolean isGetter) {
return CallBuilder.build(context())
.receiver(arrayExpression)
.args(arguments)
.resolvedCall(getResolvedCall(bindingContext(), expression))
.descriptor(methodDescriptor)
.resolvedCall(BindingUtils.getResolvedCallForArrayAccess(bindingContext(), expression, isGetter))
.translate();
}
@@ -106,6 +97,6 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull
@Override
public CachedAccessTranslator getCached() {
return null; //To change body of implemented methods use File | Settings | File Templates.
return new CachedArrayAccessTranslator(expression, context());
}
}
@@ -38,8 +38,8 @@ public final class CachedArrayAccessTranslator extends ArrayAccessTranslator imp
@NotNull
private final List<TemporaryVariable> indexExpressions;
private CachedArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
@NotNull TranslationContext context) {
/*package*/ CachedArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
@NotNull TranslationContext context) {
super(expression, context);
arrayExpression = context.declareTemporary(translateArrayExpression());
indexExpressions = fromExpressionList(translateIndexExpressions(), context);
@@ -25,13 +25,15 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
/**
@@ -332,4 +334,16 @@ public final class BindingUtils {
assert type != null;
return type;
}
@NotNull
public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
@NotNull JetArrayAccessExpression arrayAccessExpression,
boolean isGet
) {
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(isGet
? INDEXED_LVALUE_GET
: INDEXED_LVALUE_SET, arrayAccessExpression);
assert resolvedCall != null;
return resolvedCall;
}
}
@@ -0,0 +1,59 @@
package foo
var c0 = 0
var c1 = 0
var c2 = 0
class A() {
var p = 0
fun get(i : Int) : Int {
c1++
return 0
}
fun set(i : Int, value : Int) {
c2++
}
}
val a : A = A()
get() {
c0++
return $a
}
fun box() : String {
var d = a[1]
if (c0 != 1) {
return "1"
}
if (c1 != 1) {
return "2"
}
++a[1]
if (c0 != 2) {
return "3"
}
if (c1 != 2) {
return "4"
}
if (c2 != 1) {
return "5"
}
--a[1]
if (c0 != 3) {
return "6"
}
if (c1 != 3) {
return "7"
}
if (c2 != 2) {
return "8"
}
return "OK"
}
@@ -19,8 +19,4 @@ fun box() : Boolean {
return false;
}
return true
}
fun main(args : Array<String>) {
println(box())
}