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 { public void testKt740() throws Exception {
checkFooBoxIsTrue("KT-740.kt"); 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 * @author Pavel Talanov
* <p/> * <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 { public interface AccessTranslator {
@@ -32,6 +32,7 @@ public interface AccessTranslator {
@NotNull @NotNull
JsExpression translateAsSet(@NotNull JsExpression setTo); JsExpression translateAsSet(@NotNull JsExpression setTo);
//TODO: remove that method
@NotNull @NotNull
CachedAccessTranslator getCached(); CachedAccessTranslator getCached();
} }
@@ -19,23 +19,18 @@ package org.jetbrains.k2js.translate.reference;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
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.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression; import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.List; 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 * @author Pavel Talanov
*/ */
//TODO: inspect not clear how the class handles set and get operations differently
public class ArrayAccessTranslator extends AbstractTranslator implements AccessTranslator { public class ArrayAccessTranslator extends AbstractTranslator implements AccessTranslator {
/*package*/ /*package*/
@@ -46,16 +41,11 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull @NotNull
private final JetArrayAccessExpression expression; private final JetArrayAccessExpression expression;
@NotNull
private final FunctionDescriptor methodDescriptor;
protected ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression, protected ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
super(context); super(context);
this.expression = expression; this.expression = expression;
//TODO: that is strange
this.methodDescriptor = (FunctionDescriptor)
getDescriptorForReferenceExpression(context.bindingContext(), expression);
} }
@NotNull @NotNull
@@ -67,7 +57,7 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull @NotNull
protected JsExpression translateAsGet(@NotNull JsExpression arrayExpression, protected JsExpression translateAsGet(@NotNull JsExpression arrayExpression,
@NotNull List<JsExpression> indexExpression) { @NotNull List<JsExpression> indexExpression) {
return translateAsMethodCall(arrayExpression, indexExpression); return translateAsMethodCall(arrayExpression, indexExpression, /*isGetter = */ true);
} }
@NotNull @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) { protected JsExpression translateAsSet(@NotNull JsExpression arrayExpression, @NotNull List<JsExpression> indexExpressions, @NotNull JsExpression toSetTo) {
List<JsExpression> arguments = Lists.newArrayList(indexExpressions); List<JsExpression> arguments = Lists.newArrayList(indexExpressions);
arguments.add(toSetTo); arguments.add(toSetTo);
return translateAsMethodCall(arrayExpression, arguments); return translateAsMethodCall(arrayExpression, arguments, /*isGetter = */ false);
} }
@NotNull @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()) return CallBuilder.build(context())
.receiver(arrayExpression) .receiver(arrayExpression)
.args(arguments) .args(arguments)
.resolvedCall(getResolvedCall(bindingContext(), expression)) .resolvedCall(BindingUtils.getResolvedCallForArrayAccess(bindingContext(), expression, isGetter))
.descriptor(methodDescriptor)
.translate(); .translate();
} }
@@ -106,6 +97,6 @@ public class ArrayAccessTranslator extends AbstractTranslator implements AccessT
@NotNull @NotNull
@Override @Override
public CachedAccessTranslator getCached() { 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 @NotNull
private final List<TemporaryVariable> indexExpressions; private final List<TemporaryVariable> indexExpressions;
private CachedArrayAccessTranslator(@NotNull JetArrayAccessExpression expression, /*package*/ CachedArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
super(expression, context); super(expression, context);
arrayExpression = context.declareTemporary(translateArrayExpression()); arrayExpression = context.declareTemporary(translateArrayExpression());
indexExpressions = fromExpressionList(translateIndexExpressions(), context); 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.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 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.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; 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.*; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
/** /**
@@ -332,4 +334,16 @@ public final class BindingUtils {
assert type != null; assert type != null;
return type; 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 false;
} }
return true return true
}
fun main(args : Array<String>) {
println(box())
} }