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
This commit is contained in:
Zalim Bashorov
2013-06-04 16:06:41 +04:00
parent 60a2f4ef08
commit 2bae647412
5 changed files with 32 additions and 14 deletions
@@ -45,4 +45,8 @@ public final class EqualsTest extends AbstractExpressionTest {
public void testKt2370() throws Exception {
fooBoxTest();
}
public void testEqualsNullOrUndefined() throws Exception {
checkFooBoxIsOk();
}
}
@@ -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
@@ -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
@@ -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<JsExpression> translateArgumentList(@NotNull TranslationContext context,
@NotNull List<? extends ValueArgument> jetArguments) {
@@ -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"
}