diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/MiscTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/MiscTest.java index d3be26a1a43..c052679f13d 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/MiscTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/MiscTest.java @@ -117,4 +117,8 @@ public final class MiscTest extends AbstractExpressionTest { public void testWhenReturnedWithoutBlock() throws Exception { checkFooBoxIsTrue("whenReturnedWithoutBlock.kt"); } + + public void testElvis() throws Exception { + checkFooBoxIsTrue("elvis.kt"); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java index 3f8b5a4b451..bf1f191349c 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java @@ -18,6 +18,7 @@ package org.jetbrains.k2js.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.JsConditional; import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,6 +33,7 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic; import org.jetbrains.k2js.translate.reference.CallBuilder; import org.jetbrains.k2js.translate.reference.CallType; +import org.jetbrains.k2js.translate.utils.JsAstUtils; import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssignmentOperator; import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall; @@ -71,11 +73,14 @@ public final class BinaryOperationTranslator extends AbstractTranslator { super(context); this.expression = expression; this.operationDescriptor = - getFunctionDescriptorForOperationExpression(bindingContext(), expression); + getFunctionDescriptorForOperationExpression(bindingContext(), expression); } @NotNull private JsExpression translate() { + if (isElvisOperator(expression)) { + return translateAsElvisOperator(expression); + } if (isAssignmentOperator(expression)) { return AssignmentTranslator.translate(expression, context()); } @@ -86,13 +91,26 @@ public final class BinaryOperationTranslator extends AbstractTranslator { return CompareToTranslator.translate(expression, context()); } assert operationDescriptor != null : - "Overloadable operations must have not null descriptor"; + "Overloadable operations must have not null descriptor"; if (isEquals(operationDescriptor)) { return translateAsEqualsCall(); } return translateAsOverloadedBinaryOperation(); } + private static boolean isElvisOperator(@NotNull JetBinaryExpression expression) { + return getOperationToken(expression).equals(JetTokens.ELVIS); + } + + //TODO: use some generic mechanism + @NotNull + private JsExpression translateAsElvisOperator(@NotNull JetBinaryExpression expression) { + JsExpression translatedLeft = translateLeftExpression(context(), expression); + JsExpression translatedRight = translateRightExpression(context(), expression); + JsBinaryOperation leftIsNotNull = JsAstUtils.inequality(translatedLeft, program().getNullLiteral()); + return new JsConditional(leftIsNotNull, translatedLeft, translatedRight); + } + private boolean isNotOverloadable() { return operationDescriptor == null; } @@ -120,9 +138,9 @@ public final class BinaryOperationTranslator extends AbstractTranslator { private JsExpression translateAsOverloadedBinaryOperation() { CallBuilder callBuilder = setReceiverAndArguments(); ResolvedCall resolvedCall1 = - getResolvedCall(bindingContext(), expression.getOperationReference()); + getResolvedCall(bindingContext(), expression.getOperationReference()); JsExpression result = callBuilder.resolvedCall(resolvedCall1) - .type(CallType.NORMAL).translate(); + .type(CallType.NORMAL).translate(); return mayBeWrapWithNegation(result); } @@ -150,5 +168,4 @@ public final class BinaryOperationTranslator extends AbstractTranslator { return result; } } - } diff --git a/js/js.translator/testFiles/expression/misc/cases/elvis.kt b/js/js.translator/testFiles/expression/misc/cases/elvis.kt new file mode 100644 index 00000000000..0f130c6039f --- /dev/null +++ b/js/js.translator/testFiles/expression/misc/cases/elvis.kt @@ -0,0 +1,21 @@ +package foo + +fun box() : Boolean { + if (f(null) != false) { + return false; + } + if (f(2) != true) { + return false; + } + if (f(1) != false) { + return true; + } + return true +} + +fun Int.isEven() = (this % 2) == 0 + +fun f(a : Int?) : Boolean { + return a?.isEven() ?: false + +} \ No newline at end of file