Overloading operations via extension functions.

Also inline useless TranslationUtils#zeroLiteral. Eliminate dead code.
This commit is contained in:
Pavel V. Talanov
2012-07-19 20:40:03 +04:00
parent 36184ded3b
commit 803be4b0d5
9 changed files with 110 additions and 53 deletions
@@ -103,4 +103,20 @@ public final class OperatorOverloadingTest extends SingleFileTranslationTest {
public void testOverloadPlusAssignArrayList() throws Exception { public void testOverloadPlusAssignArrayList() throws Exception {
checkFooBoxIsOk("overloadPlusAssignArrayList.kt"); checkFooBoxIsOk("overloadPlusAssignArrayList.kt");
} }
public void testOverloadPlusAssignViaExtensionFunction() throws Exception {
fooBoxTest();
}
public void testOverloadPlusViaExtensionFunction() throws Exception {
fooBoxTest();
}
public void testOverloadPlusAssignViaPlusExtensionFunction() throws Exception {
fooBoxTest();
}
public void testOverloadUnaryOperationsViaExtensionFunctions() throws Exception {
fooBoxTest();
}
} }
@@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
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.utils.TranslationUtils;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isCompareTo; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isCompareTo;
@@ -69,6 +68,6 @@ public final class CompareToTranslator extends AbstractTranslator {
private JsExpression translate() { private JsExpression translate() {
JsBinaryOperator correspondingOperator = OperatorTable.getBinaryOperator(getOperationToken(expression)); JsBinaryOperator correspondingOperator = OperatorTable.getBinaryOperator(getOperationToken(expression));
JsExpression methodCall = BinaryOperationTranslator.translateAsOverloadedCall(expression, context()); JsExpression methodCall = BinaryOperationTranslator.translateAsOverloadedCall(expression, context());
return new JsBinaryOperation(correspondingOperator, methodCall, TranslationUtils.zeroLiteral(context())); return new JsBinaryOperation(correspondingOperator, methodCall, context().program().getNumberLiteral(0));
} }
} }
@@ -17,14 +17,12 @@
package org.jetbrains.k2js.translate.operation; package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
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.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.CallBuilder;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; import org.jetbrains.k2js.translate.utils.BindingUtils;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodReferenceForOverloadedOperation;
/** /**
* @author Pavel Talanov * @author Pavel Talanov
@@ -33,17 +31,20 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
@NotNull @NotNull
public static JsExpression doTranslate(@NotNull JetBinaryExpression expression, public static JsExpression doTranslate(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
return (new OverloadedAssignmentTranslator(expression, context)).translate(); return (new OverloadedAssignmentTranslator(expression, context)).translate();
} }
@NotNull @NotNull
private final JsNameRef operationReference; private final FunctionDescriptor operationDescriptor;
private OverloadedAssignmentTranslator(@NotNull JetBinaryExpression expression, private OverloadedAssignmentTranslator(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
super(expression, context); super(expression, context);
this.operationReference = getMethodReferenceForOverloadedOperation(context, expression); FunctionDescriptor functionDescriptor =
BindingUtils.getFunctionDescriptorForOperationExpression(context.bindingContext(), expression);
assert functionDescriptor != null : "";
this.operationDescriptor = functionDescriptor;
} }
@NotNull @NotNull
@@ -61,8 +62,10 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
@NotNull @NotNull
private JsExpression overloadedMethodInvocation() { private JsExpression overloadedMethodInvocation() {
setQualifier(operationReference, accessTranslator.translateAsGet()); return CallBuilder.build(context())
return AstUtil.newInvocation(operationReference, right); .descriptor(operationDescriptor)
.receiver(accessTranslator.translateAsGet())
.args(right)
.translate();
} }
} }
@@ -17,14 +17,13 @@
package org.jetbrains.k2js.translate.operation; package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
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.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetUnaryExpression; import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.CallBuilder;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodReferenceForOverloadedOperation;
/** /**
* @author Pavel Talanov * @author Pavel Talanov
@@ -32,20 +31,24 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodRefer
public final class OverloadedIncrementTranslator extends IncrementTranslator { public final class OverloadedIncrementTranslator extends IncrementTranslator {
@NotNull @NotNull
private final JsNameRef operationReference; private final FunctionDescriptor operationDescriptor;
/*package*/ OverloadedIncrementTranslator(@NotNull JetUnaryExpression expression, /*package*/ OverloadedIncrementTranslator(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
super(expression, context); super(expression, context);
this.operationReference = getMethodReferenceForOverloadedOperation(context, expression); FunctionDescriptor functionDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression);
assert functionDescriptor != null : "Descriptor should not be null for overloaded increment expression.";
this.operationDescriptor = functionDescriptor;
} }
@Override @Override
@NotNull @NotNull
protected JsExpression operationExpression(@NotNull JsExpression receiver) { protected JsExpression operationExpression(@NotNull JsExpression receiver) {
setQualifier(operationReference, receiver); return CallBuilder.build(context())
return AstUtil.newInvocation(operationReference); .receiver(receiver)
.descriptor(operationDescriptor)
.translate();
} }
} }
@@ -84,17 +84,6 @@ public final class TranslationUtils {
return or(isNull, isUndefined); return or(isNull, isUndefined);
} }
@NotNull
public static JsBinaryOperation nullCheck(@NotNull TranslationContext context,
@NotNull JsExpression expressionToCheck, boolean shouldBeNull) {
if (shouldBeNull) {
return isNullCheck(context, expressionToCheck);
}
else {
return notNullCheck(context, expressionToCheck);
}
}
@NotNull @NotNull
public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context, public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context,
@NotNull List<? extends ValueArgument> jetArguments) { @NotNull List<? extends ValueArgument> jetArguments) {
@@ -213,22 +202,6 @@ public final class TranslationUtils {
return false; return false;
} }
@NotNull
public static JsNameRef getMethodReferenceForOverloadedOperation(@NotNull TranslationContext context,
@NotNull JetOperationExpression expression) {
FunctionDescriptor overloadedOperationDescriptor = getFunctionDescriptorForOperationExpression
(context.bindingContext(), expression);
assert overloadedOperationDescriptor != null;
JsNameRef overloadedOperationReference = context.getNameForDescriptor(overloadedOperationDescriptor).makeRef();
assert overloadedOperationReference != null;
return overloadedOperationReference;
}
@NotNull
public static JsNumberLiteral zeroLiteral(@NotNull TranslationContext context) {
return context.program().getNumberLiteral(0);
}
@Nullable @Nullable
public static JsExpression resolveThisObjectForResolvedCall(@NotNull ResolvedCall<?> call, public static JsExpression resolveThisObjectForResolvedCall(@NotNull ResolvedCall<?> call,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
@@ -240,10 +213,6 @@ public final class TranslationUtils {
return getThisObject(context, expectedThisDescriptor); return getThisObject(context, expectedThisDescriptor);
} }
public static boolean isNullLiteral(@NotNull TranslationContext context, @NotNull JsExpression expression) {
return expression.equals(context.program().getNullLiteral());
}
public static void defineModule(@NotNull TranslationContext context, @NotNull List<JsStatement> statements, public static void defineModule(@NotNull TranslationContext context, @NotNull List<JsStatement> statements,
String moduleId) { String moduleId) {
statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"), statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"),
@@ -0,0 +1,16 @@
package foo
import java.util.*
fun <T> ArrayList<T>.plusAssign(other: Collection<T>) {
addAll(other)
}
fun box(): Boolean {
var v1 = ArrayList<String>()
val v2 = ArrayList<String>()
v1.add("foo")
v2.add("bar")
v1 += v2
return (v1.size() == 2 && v1[0] == "foo" && v1[1] == "bar")
}
@@ -0,0 +1,19 @@
package foo
import java.util.*
fun <T> ArrayList<T>.plus(other: Collection<T>): List<T> {
val c = ArrayList<T>()
c.addAll(this)
c.addAll(other)
return c
}
fun box(): Boolean {
var v1 = ArrayList<String>()
val v2 = ArrayList<String>()
v1.add("foo")
v2.add("bar")
v1 += v2
return (v1.size() == 2 && v1[0] == "foo" && v1[1] == "bar")
}
@@ -0,0 +1,20 @@
package foo
import java.util.*
fun <T> ArrayList<T>.plus(other: Collection<T>): List<T> {
val c = ArrayList<T>()
c.addAll(this)
c.addAll(other)
return c
}
fun box(): Boolean {
var v1 = ArrayList<String>()
v1.add("foo")
val v2 = ArrayList<String>()
v2.add("bar")
val v = v1 + v2
return (v.size() == 2 && v[0] == "foo" && v[1] == "bar")
}
@@ -0,0 +1,12 @@
package foo
class A(val c: Int) {}
fun A.inc() = A(5)
fun A.dec() = A(10)
fun box(): Boolean {
var a = A(1)
return ((++a).c == 5 && (a++).c == 5 && (--a).c == 10 && (a--).c == 10)
}