From e098de5e3311dbf1fd7878e0591e9006fec9011a Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Wed, 10 May 2017 19:01:21 +0300 Subject: [PATCH] JS: fix char boxing in elvis expressions (#KT-17700 fixed) --- .../box/ranges/forInUntil/forInUntilChar.kt | 3 --- .../js/test/semantics/BoxJsTestGenerated.java | 6 ++++++ .../semantics/JsCodegenBoxTestGenerated.java | 8 +------- .../js/translate/callTranslator/CallInfo.kt | 8 +------- .../DestructuringDeclarationTranslator.java | 8 ++------ .../operation/BinaryOperationTranslator.java | 11 +++++++++-- .../reference/CallArgumentTranslator.kt | 18 +++++++++--------- .../js/translate/utils/TranslationUtils.java | 14 +++++++++++--- .../testData/box/char/charElvis.kt | 14 ++++++++++++++ 9 files changed, 53 insertions(+), 37 deletions(-) create mode 100644 js/js.translator/testData/box/char/charElvis.kt diff --git a/compiler/testData/codegen/box/ranges/forInUntil/forInUntilChar.kt b/compiler/testData/codegen/box/ranges/forInUntil/forInUntilChar.kt index 71fcc47486b..9ee13af7b5a 100644 --- a/compiler/testData/codegen/box/ranges/forInUntil/forInUntilChar.kt +++ b/compiler/testData/codegen/box/ranges/forInUntil/forInUntilChar.kt @@ -1,6 +1,3 @@ -// IGNORE_BACKEND: JS -// see KT-17700 - // WITH_RUNTIME import kotlin.test.assertEquals 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 4a84bc455b1..8d84636db14 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 @@ -410,6 +410,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("charElvis.kt") + public void testCharElvis() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charElvis.kt"); + doTest(fileName); + } + @TestMetadata("charEquals.kt") public void testCharEquals() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charEquals.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index b236cb860e7..892d3caa5e6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -15222,13 +15222,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("forInUntilChar.kt") public void testForInUntilChar() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInUntil/forInUntilChar.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("forInUntilChar0.kt") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt index 3c38def74c5..6b48752a81d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.callTranslator import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.js.backend.ast.JsBlock import org.jetbrains.kotlin.js.backend.ast.JsConditional @@ -28,7 +27,6 @@ import org.jetbrains.kotlin.js.backend.ast.JsLiteral import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForReceiver import org.jetbrains.kotlin.js.translate.utils.TranslationUtils import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -105,11 +103,7 @@ fun TranslationContext.getCallInfo( } private fun boxIfNeedeed(v: ReceiverValue?, d: ReceiverParameterDescriptor?, r: JsExpression?): JsExpression? { - if (r != null && v != null && KotlinBuiltIns.isCharOrNullableChar(v.type) && - (d == null || !KotlinBuiltIns.isCharOrNullableChar(d.type))) { - return JsAstUtils.charToBoxedChar(r) - } - return r + return r?.let { TranslationUtils.boxCastIfNeeded(it, v?.type, d?.type) } } private fun TranslationContext.getDispatchReceiver(receiverValue: ReceiverValue): JsExpression { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java index 0daec75b82a..d5eeab3fe07 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.js.translate.expression; import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.js.backend.ast.JsExpression; @@ -29,12 +28,12 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; +import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.psi.KtDestructuringDeclaration; import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.types.KotlinType; import java.util.ArrayList; import java.util.List; @@ -85,10 +84,7 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator { setInlineCallMetadata(entryInitializer, entry, entryInitCall, context()); } - KotlinType returnType = candidateDescriptor.getReturnType(); - if (returnType != null && KotlinBuiltIns.isCharOrNullableChar(returnType) && !KotlinBuiltIns.isCharOrNullableChar(descriptor.getType())) { - entryInitializer = JsAstUtils.charToBoxedChar(entryInitializer); - } + entryInitializer = TranslationUtils.boxCastIfNeeded(entryInitializer, candidateDescriptor.getReturnType(), descriptor.getType()); JsName name = context().getNameForDescriptor(descriptor); if (isVarCapturedInClosure(context().bindingContext(), descriptor)) { 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 b6c899cf4b4..da36c6c5502 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 @@ -123,10 +123,17 @@ public final class BinaryOperationTranslator extends AbstractTranslator { @NotNull private JsExpression translateElvis() { - JsExpression leftExpression = Translation.translateAsExpression(leftKtExpression, context()); + KotlinType expressionType = context().bindingContext().getType(expression); + + JsExpression leftExpression = TranslationUtils.boxCastIfNeeded(Translation.translateAsExpression(leftKtExpression, context()), + context().bindingContext().getType(leftKtExpression), + expressionType); JsBlock rightBlock = new JsBlock(); - JsExpression rightExpression = Translation.translateAsExpression(rightKtExpression, context(), rightBlock); + JsExpression rightExpression = + TranslationUtils.boxCastIfNeeded(Translation.translateAsExpression(rightKtExpression, context(), rightBlock), + context().bindingContext().getType(rightKtExpression), + expressionType); if (rightBlock.isEmpty()) { return TranslationUtils.notNullConditional(leftExpression, rightExpression, context()); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index 8f2ebfb3988..5e39ed2fb98 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.js.translate.reference import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn +import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -183,19 +184,18 @@ class CallArgumentTranslator private constructor( val parenthisedArgumentExpression = arg.getArgumentExpression() val param = argsToParameters[arg]!!.original - val parameterType = param.varargElementType ?: param.type + val parameterType = if (resolvedCall.call.callType == Call.CallType.INVOKE) { + DefaultBuiltIns.Instance.anyType + } + else { + param.varargElementType ?: param.type + } + val argType = context.bindingContext().getType(parenthisedArgumentExpression!!) val argJs = Translation.translateAsExpression(parenthisedArgumentExpression, argumentContext) - val jsExpr = if (argType != null && KotlinBuiltIns.isCharOrNullableChar(argType) && - (!KotlinBuiltIns.isCharOrNullableChar(parameterType) || resolvedCall.call.callType == Call.CallType.INVOKE)) { - JsAstUtils.charToBoxedChar(argJs) - } - else { - argJs - } - arg to jsExpr + arg to TranslationUtils.boxCastIfNeeded(argJs, argType, parameterType) } val resolvedOrder = resolvedCall.valueArgumentsByIndex.orEmpty() diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 8692089fea6..bf18e95ffd7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -200,9 +200,7 @@ public final class TranslationUtils { KotlinType propertyType = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, declaration).getType(); KotlinType initType = context.bindingContext().getType(initializer); - if (initType != null && KotlinBuiltIns.isCharOrNullableChar(initType) && !KotlinBuiltIns.isCharOrNullableChar(propertyType)) { - jsInitExpression = JsAstUtils.charToBoxedChar(jsInitExpression); - } + jsInitExpression = boxCastIfNeeded(jsInitExpression, initType, propertyType); } return jsInitExpression; } @@ -402,4 +400,14 @@ public final class TranslationUtils { public static boolean shouldBoxReturnValue(CallableDescriptor c) { return overridesReturnAny(c) || c instanceof CallableMemberDescriptor && ModalityKt.isOverridable((CallableMemberDescriptor)c); } + + @NotNull + public static JsExpression boxCastIfNeeded(@NotNull JsExpression e, @Nullable KotlinType castFrom, @Nullable KotlinType castTo) { + if (castFrom != null && KotlinBuiltIns.isCharOrNullableChar(castFrom) && + castTo != null && !KotlinBuiltIns.isCharOrNullableChar(castTo) + ) { + return JsAstUtils.charToBoxedChar(e); + } + return e; + } } diff --git a/js/js.translator/testData/box/char/charElvis.kt b/js/js.translator/testData/box/char/charElvis.kt new file mode 100644 index 00000000000..74560cc3a4a --- /dev/null +++ b/js/js.translator/testData/box/char/charElvis.kt @@ -0,0 +1,14 @@ +package foo + +fun box(): String { + + assertEquals("1", "" + ('1' ?: return "fail1")) + assertEquals("2", "" + (null ?: '2')) + val c3: Char? = '3' + assertEquals("3", "" + (c3 ?: return "fail3")) + + val c4: Char? = null + assertEquals("4", "" + (c4 ?: "4")) + + return "OK" +} \ No newline at end of file