From 2bae64741264ff477a76df8bf2f922701f9f09b4 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Tue, 4 Jun 2013 16:06:41 +0400 Subject: [PATCH] Make nullable check less verbose in JS-backend. For check what variable is equal null or undefined enough to compare with null (or undefined). See ECMAScript specification 11.9.1, 11.9.2, 11.9.3 --- .../k2js/test/semantics/EqualsTest.java | 4 ++++ .../operation/UnaryOperationTranslator.java | 4 ++-- .../k2js/translate/reference/CallType.java | 4 ++-- .../k2js/translate/utils/TranslationUtils.java | 16 ++++++---------- .../equals/cases/equalsNullOrUndefined.kt | 18 ++++++++++++++++++ 5 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 js/js.translator/testFiles/expression/equals/cases/equalsNullOrUndefined.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java index 2e337c0af8f..30e5d8da47e 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java @@ -45,4 +45,8 @@ public final class EqualsTest extends AbstractExpressionTest { public void testKt2370() throws Exception { fooBoxTest(); } + + public void testEqualsNullOrUndefined() throws Exception { + checkFooBoxIsOk(); + } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java index 634f1934ddd..48873acabd4 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java @@ -33,7 +33,7 @@ import static org.jetbrains.k2js.translate.general.Translation.translateAsExpres import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall; import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression; import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.notNullConditionalTestExpression; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNotNullCheck; public final class UnaryOperationTranslator { @@ -59,7 +59,7 @@ public final class UnaryOperationTranslator { @NotNull private static JsExpression translateExclExclOperator(@NotNull JetUnaryExpression expression, @NotNull TranslationContext context) { TemporaryVariable cachedValue = context.declareTemporary(translateAsExpression(getBaseExpression(expression), context)); - return new JsConditional(notNullConditionalTestExpression(cachedValue), cachedValue.reference(), context.namer().throwNPEFunctionCall()); + return new JsConditional(isNotNullCheck(cachedValue.assignmentExpression()), cachedValue.reference(), context.namer().throwNPEFunctionCall()); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java index ef7e7cf5603..13b1849df95 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java @@ -27,7 +27,7 @@ import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.notNullConditionalTestExpression; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNotNullCheck; public enum CallType { SAFE { @@ -37,7 +37,7 @@ public enum CallType { @NotNull TranslationContext context) { assert receiver != null; TemporaryVariable cachedValue = context.declareTemporary(receiver); - return new JsConditional(notNullConditionalTestExpression(cachedValue), constructor.construct(cachedValue.reference()), JsLiteral.NULL); + return new JsConditional(isNotNullCheck(cachedValue.assignmentExpression()), constructor.construct(cachedValue.reference()), JsLiteral.NULL); } }, //TODO: bang qualifier is not implemented in frontend for now 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 dd0de2b2437..c507cfafd4f 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 @@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; @@ -32,7 +31,8 @@ import java.util.ArrayList; import java.util.List; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; public final class TranslationUtils { private TranslationUtils() { @@ -64,19 +64,15 @@ public final class TranslationUtils { } @NotNull - public static JsBinaryOperation notNullConditionalTestExpression(@NotNull TemporaryVariable cachedValue) { - return and(inequality(cachedValue.assignmentExpression(), JsLiteral.NULL), - inequality(cachedValue.reference(), JsLiteral.UNDEFINED)); + public static JsBinaryOperation isNotNullCheck(@NotNull JsExpression expressionToCheck) { + return nullCheck(expressionToCheck, true); } @NotNull public static JsBinaryOperation nullCheck(@NotNull JsExpression expressionToCheck, boolean isNegated) { - JsBinaryOperator operator = isNegated ? JsBinaryOperator.REF_NEQ : JsBinaryOperator.REF_EQ; - return new JsBinaryOperation(isNegated ? JsBinaryOperator.AND : JsBinaryOperator.OR, - new JsBinaryOperation(operator, expressionToCheck, JsLiteral.NULL), - new JsBinaryOperation(operator, expressionToCheck, JsLiteral.UNDEFINED)); + JsBinaryOperator operator = isNegated ? JsBinaryOperator.NEQ : JsBinaryOperator.EQ; + return new JsBinaryOperation(operator, expressionToCheck, JsLiteral.NULL); } - @NotNull public static List translateArgumentList(@NotNull TranslationContext context, @NotNull List jetArguments) { diff --git a/js/js.translator/testFiles/expression/equals/cases/equalsNullOrUndefined.kt b/js/js.translator/testFiles/expression/equals/cases/equalsNullOrUndefined.kt new file mode 100644 index 00000000000..03dd20515b7 --- /dev/null +++ b/js/js.translator/testFiles/expression/equals/cases/equalsNullOrUndefined.kt @@ -0,0 +1,18 @@ +package foo + +fun box() : String { + val a: Int? = null + val r = a == null + if (!r || a != null) + return "wrong result on simple nullable check" + + var i = 0; + fun foo(): Int? = ++i; + if (foo() == null) + return "wrong result on nullable check with side effects" + + if (i != 1) + return "wrong affects when using nullable check with side effects" + + return "OK" +} \ No newline at end of file