From 803be4b0d545d322dd7d3666923b989721eca530 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 19 Jul 2012 20:40:03 +0400 Subject: [PATCH] Overloading operations via extension functions. Also inline useless TranslationUtils#zeroLiteral. Eliminate dead code. --- .../semantics/OperatorOverloadingTest.java | 16 ++++++++++ .../operation/CompareToTranslator.java | 3 +- .../OverloadedAssignmentTranslator.java | 27 +++++++++------- .../OverloadedIncrementTranslator.java | 19 +++++++----- .../translate/utils/TranslationUtils.java | 31 ------------------- .../overloadPlusAssignViaExtensionFunction.kt | 16 ++++++++++ ...rloadPlusAssignViaPlusExtensionFunction.kt | 19 ++++++++++++ .../cases/overloadPlusViaExtensionFunction.kt | 20 ++++++++++++ ...oadUnaryOperationsViaExtensionFunctions.kt | 12 +++++++ 9 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaExtensionFunction.kt create mode 100644 js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaPlusExtensionFunction.kt create mode 100644 js/js.translator/testFiles/operatorOverloading/cases/overloadPlusViaExtensionFunction.kt create mode 100644 js/js.translator/testFiles/operatorOverloading/cases/overloadUnaryOperationsViaExtensionFunctions.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/OperatorOverloadingTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/OperatorOverloadingTest.java index 9b2a0c962b0..eaf572d7fe0 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/OperatorOverloadingTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/OperatorOverloadingTest.java @@ -103,4 +103,20 @@ public final class OperatorOverloadingTest extends SingleFileTranslationTest { public void testOverloadPlusAssignArrayList() throws Exception { 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(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java index 04e1ea961d2..0f5df8409b1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java @@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.k2js.translate.context.TranslationContext; 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.JsDescriptorUtils.isCompareTo; @@ -69,6 +68,6 @@ public final class CompareToTranslator extends AbstractTranslator { private JsExpression translate() { JsBinaryOperator correspondingOperator = OperatorTable.getBinaryOperator(getOperationToken(expression)); JsExpression methodCall = BinaryOperationTranslator.translateAsOverloadedCall(expression, context()); - return new JsBinaryOperation(correspondingOperator, methodCall, TranslationUtils.zeroLiteral(context())); + return new JsBinaryOperation(correspondingOperator, methodCall, context().program().getNumberLiteral(0)); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedAssignmentTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedAssignmentTranslator.java index 44ed0e2ed6a..20a2771f517 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedAssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedAssignmentTranslator.java @@ -17,14 +17,12 @@ package org.jetbrains.k2js.translate.operation; 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.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.k2js.translate.context.TranslationContext; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodReferenceForOverloadedOperation; +import org.jetbrains.k2js.translate.reference.CallBuilder; +import org.jetbrains.k2js.translate.utils.BindingUtils; /** * @author Pavel Talanov @@ -33,17 +31,20 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator { @NotNull public static JsExpression doTranslate(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return (new OverloadedAssignmentTranslator(expression, context)).translate(); } @NotNull - private final JsNameRef operationReference; + private final FunctionDescriptor operationDescriptor; private OverloadedAssignmentTranslator(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { super(expression, context); - this.operationReference = getMethodReferenceForOverloadedOperation(context, expression); + FunctionDescriptor functionDescriptor = + BindingUtils.getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); + assert functionDescriptor != null : ""; + this.operationDescriptor = functionDescriptor; } @NotNull @@ -61,8 +62,10 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator { @NotNull private JsExpression overloadedMethodInvocation() { - setQualifier(operationReference, accessTranslator.translateAsGet()); - return AstUtil.newInvocation(operationReference, right); + return CallBuilder.build(context()) + .descriptor(operationDescriptor) + .receiver(accessTranslator.translateAsGet()) + .args(right) + .translate(); } - } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedIncrementTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedIncrementTranslator.java index 16c3eb01550..41ca1939574 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedIncrementTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/OverloadedIncrementTranslator.java @@ -17,14 +17,13 @@ package org.jetbrains.k2js.translate.operation; 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.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetUnaryExpression; 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.TranslationUtils.getMethodReferenceForOverloadedOperation; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; /** * @author Pavel Talanov @@ -32,20 +31,24 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodRefer public final class OverloadedIncrementTranslator extends IncrementTranslator { @NotNull - private final JsNameRef operationReference; + private final FunctionDescriptor operationDescriptor; /*package*/ OverloadedIncrementTranslator(@NotNull JetUnaryExpression expression, @NotNull TranslationContext 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 @NotNull protected JsExpression operationExpression(@NotNull JsExpression receiver) { - setQualifier(operationReference, receiver); - return AstUtil.newInvocation(operationReference); + return CallBuilder.build(context()) + .receiver(receiver) + .descriptor(operationDescriptor) + .translate(); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index 5068c1e0338..e09bb63c716 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -84,17 +84,6 @@ public final class TranslationUtils { 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 public static List translateArgumentList(@NotNull TranslationContext context, @NotNull List jetArguments) { @@ -213,22 +202,6 @@ public final class TranslationUtils { 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 public static JsExpression resolveThisObjectForResolvedCall(@NotNull ResolvedCall call, @NotNull TranslationContext context) { @@ -240,10 +213,6 @@ public final class TranslationUtils { 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 statements, String moduleId) { statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"), diff --git a/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaExtensionFunction.kt b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaExtensionFunction.kt new file mode 100644 index 00000000000..2720b4c31fc --- /dev/null +++ b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaExtensionFunction.kt @@ -0,0 +1,16 @@ +package foo + +import java.util.* + +fun ArrayList.plusAssign(other: Collection) { + addAll(other) +} + +fun box(): Boolean { + var v1 = ArrayList() + val v2 = ArrayList() + v1.add("foo") + v2.add("bar") + v1 += v2 + return (v1.size() == 2 && v1[0] == "foo" && v1[1] == "bar") +} diff --git a/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaPlusExtensionFunction.kt b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaPlusExtensionFunction.kt new file mode 100644 index 00000000000..209b1d5ba10 --- /dev/null +++ b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusAssignViaPlusExtensionFunction.kt @@ -0,0 +1,19 @@ +package foo + +import java.util.* + +fun ArrayList.plus(other: Collection): List { + val c = ArrayList() + c.addAll(this) + c.addAll(other) + return c +} + +fun box(): Boolean { + var v1 = ArrayList() + val v2 = ArrayList() + v1.add("foo") + v2.add("bar") + v1 += v2 + return (v1.size() == 2 && v1[0] == "foo" && v1[1] == "bar") +} diff --git a/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusViaExtensionFunction.kt b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusViaExtensionFunction.kt new file mode 100644 index 00000000000..8062301d277 --- /dev/null +++ b/js/js.translator/testFiles/operatorOverloading/cases/overloadPlusViaExtensionFunction.kt @@ -0,0 +1,20 @@ +package foo + +import java.util.* + +fun ArrayList.plus(other: Collection): List { + val c = ArrayList() + c.addAll(this) + c.addAll(other) + return c +} + +fun box(): Boolean { + var v1 = ArrayList() + v1.add("foo") + val v2 = ArrayList() + v2.add("bar") + val v = v1 + v2 + + return (v.size() == 2 && v[0] == "foo" && v[1] == "bar") +} diff --git a/js/js.translator/testFiles/operatorOverloading/cases/overloadUnaryOperationsViaExtensionFunctions.kt b/js/js.translator/testFiles/operatorOverloading/cases/overloadUnaryOperationsViaExtensionFunctions.kt new file mode 100644 index 00000000000..c4d11c822ee --- /dev/null +++ b/js/js.translator/testFiles/operatorOverloading/cases/overloadUnaryOperationsViaExtensionFunctions.kt @@ -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) +}