From c5e5a43f68b9f5ca9123c106a76d2b7ca7fa3b65 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 18 Sep 2017 12:35:50 +0300 Subject: [PATCH] JS: fix unit materialization in case of null check and elvis operator See KT-20287 --- .../js/test/semantics/BoxJsTestGenerated.java | 6 ++++++ .../intrinsic/operation/EqualsBOIF.kt | 8 ++++++-- .../operation/BinaryOperationTranslator.java | 3 ++- .../testData/box/coercion/unitNullCheck.kt | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 js/js.translator/testData/box/coercion/unitNullCheck.kt diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index a30b8206f44..49ad27ab878 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -893,6 +893,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("unitNullCheck.kt") + public void testUnitNullCheck() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/unitNullCheck.kt"); + doTest(fileName); + } + @TestMetadata("unitSafeCall.kt") public void testUnitSafeCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/unitSafeCall.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt index a2d4ff3d6a1..69d511b6b24 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.isDynamic +import org.jetbrains.kotlin.types.typeUtil.makeNullable import java.util.* object EqualsBOIF : BinaryOperationIntrinsicFactory { @@ -50,8 +51,12 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory { override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression { val isNegated = expression.isNegated() + val anyType = context.currentModule.builtIns.anyType if (right is JsNullLiteral || left is JsNullLiteral) { - return TranslationUtils.nullCheck(if (right is JsNullLiteral) left else right, isNegated) + val (subject, ktSubject) = if (right is JsNullLiteral) Pair(left, expression.left!!) else Pair(right, expression.right!!) + val type = context.bindingContext().getType(ktSubject) ?: anyType + val coercedSubject = TranslationUtils.coerce(context, subject, type.makeNullable()) + return TranslationUtils.nullCheck(coercedSubject, isNegated) } val ktLeft = checkNotNull(expression.left) { "No left-hand side: " + expression.text } @@ -78,7 +83,6 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory { return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right) } - val anyType = context.currentModule.builtIns.anyType val coercedLeft = TranslationUtils.coerce(context, left, anyType) val coercedRight = TranslationUtils.coerce(context, right, anyType) val result = TopLevelFIF.KOTLIN_EQUALS.apply(coercedLeft, listOf(coercedRight), context) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java index cdab0f69c03..47ab7979221 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.expressions.OperatorConventions; +import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import java.util.Collections; @@ -129,7 +130,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator { assert expressionType != null; JsExpression leftExpression = TranslationUtils.coerce( - context(), Translation.translateAsExpression(leftKtExpression, context()), expressionType); + context(), Translation.translateAsExpression(leftKtExpression, context()), TypeUtilsKt.makeNullable(expressionType)); JsBlock rightBlock = new JsBlock(); JsExpression rightExpression = TranslationUtils.coerce( diff --git a/js/js.translator/testData/box/coercion/unitNullCheck.kt b/js/js.translator/testData/box/coercion/unitNullCheck.kt new file mode 100644 index 00000000000..3885d394be1 --- /dev/null +++ b/js/js.translator/testData/box/coercion/unitNullCheck.kt @@ -0,0 +1,18 @@ +// EXPECTED_REACHABLE_NODES: 1027 +var log = "" + +fun box(): String { + foo() ?: bar() + if (foo() == null) bar() + + if (log != "foo;foo;") return "fail: $log" + return "OK" +} + +fun foo() { + log += "foo;" +} + +fun bar() { + log += "bar;" +}