JS: fix char boxing in elvis expressions (#KT-17700 fixed)

This commit is contained in:
Anton Bannykh
2017-05-10 19:01:21 +03:00
parent a1e00ed9f1
commit e098de5e33
9 changed files with 53 additions and 37 deletions
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JS
// see KT-17700
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -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");
@@ -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")
@@ -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 {
@@ -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)) {
@@ -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());
@@ -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()
@@ -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;
}
}
+14
View File
@@ -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"
}