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 8d84636db14..d0d4df64194 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 @@ -422,6 +422,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("charInStringTemplate.kt") + public void testCharInStringTemplate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charInStringTemplate.kt"); + doTest(fileName); + } + @TestMetadata("charIsCheck.kt") public void testCharIsCheck() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/char/charIsCheck.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java index db8d4cc461f..df242d16977 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java @@ -16,16 +16,14 @@ package org.jetbrains.kotlin.js.translate.expression; -import org.jetbrains.kotlin.js.backend.ast.JsExpression; -import org.jetbrains.kotlin.js.backend.ast.JsInvocation; -import org.jetbrains.kotlin.js.backend.ast.JsNameRef; -import org.jetbrains.kotlin.js.backend.ast.JsNumberLiteral; +import org.jetbrains.kotlin.js.backend.ast.*; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt; import org.jetbrains.kotlin.js.patterns.NamePredicate; +import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.Translation; @@ -87,17 +85,23 @@ public final class StringTemplateTranslator extends AbstractTranslator { KotlinType type = context().bindingContext().getType(entryExpression); - if (translatedExpression instanceof JsNumberLiteral) { + if (type != null && KotlinBuiltIns.isCharOrNullableChar(type)) { + if (type.isMarkedNullable()) { + TemporaryVariable tmp = context().declareTemporary(translatedExpression); + append(new JsConditional(JsAstUtils.equality(tmp.assignmentExpression(), JsLiteral.NULL), + JsLiteral.NULL, + JsAstUtils.charToString(tmp.reference()))); + } + else { + append(JsAstUtils.charToString(translatedExpression)); + } + } + else if (translatedExpression instanceof JsNumberLiteral) { append(context().program().getStringLiteral(translatedExpression.toString())); - return; } - - if (type == null || type.isMarkedNullable()) { + else if (type == null || type.isMarkedNullable()) { append(TopLevelFIF.TO_STRING.apply((JsExpression) null, new SmartList<>(translatedExpression), context())); } - else if (KotlinBuiltIns.isChar(type)) { - append(JsAstUtils.charToString(translatedExpression)); - } else if (mustCallToString(type)) { append(new JsInvocation(new JsNameRef("toString", translatedExpression))); } diff --git a/js/js.translator/testData/box/char/charInStringTemplate.kt b/js/js.translator/testData/box/char/charInStringTemplate.kt new file mode 100644 index 00000000000..ffd2b3c62b6 --- /dev/null +++ b/js/js.translator/testData/box/char/charInStringTemplate.kt @@ -0,0 +1,24 @@ +package foo + +var log = "" + +fun sideEffects(c: Char?, msg: String): Char? { + log += msg + return c +} + +fun box(): String { + val name = run { "John" } // Force compiler to actually do some concatenation + assertEquals("${'$'}name = $name", "\$name = John") + + val ch1: Char? = null + assertEquals("${ch1}name = $name", "nullname = John") + + val ch2: Char? = '$' + assertEquals("${ch2}name = $name", "\$name = John") + + assertEquals("${sideEffects('$', "1")!!}${sideEffects('n', "2")}ame = $name", "\$name = John") + assertEquals(log, "12") + + return "OK" +} \ No newline at end of file