[JS IR] Don't concatenate string template segments with '' when possible
If concatenating with an empty string is a sure no-op, just don't do it.
This commit is contained in:
+10
-1
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||
@@ -68,7 +69,15 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, context: JsGenerationContext): JsExpression {
|
||||
// TODO revisit
|
||||
return expression.arguments.fold<IrExpression, JsExpression>(JsStringLiteral("")) { jsExpr, irExpr ->
|
||||
|
||||
val firstArgument = expression.arguments.firstOrNull()
|
||||
val (head, tail) = if (firstArgument?.type?.isString() == true) {
|
||||
Pair(firstArgument.accept(this, context), expression.arguments.asSequence().drop(1))
|
||||
} else {
|
||||
Pair(JsStringLiteral(""), expression.arguments.asSequence())
|
||||
}
|
||||
|
||||
return tail.fold(head) { jsExpr, irExpr ->
|
||||
JsBinaryOperation(
|
||||
JsBinaryOperator.ADD,
|
||||
jsExpr,
|
||||
|
||||
+25
-1
@@ -1,9 +1,33 @@
|
||||
// CHECK_STRING_LITERAL_COUNT: function=foo count=1
|
||||
fun foo(x: Int) = "foo $x"
|
||||
|
||||
// CHECK_STRING_LITERAL_COUNT: function=bar count=2 IGNORED_BACKENDS=JS
|
||||
fun bar(x: Int) = "$x bar"
|
||||
|
||||
// CHECK_STRING_LITERAL_COUNT: function=baz count=1
|
||||
fun baz(x: Int) = "${x.toString()} baz"
|
||||
|
||||
// CHECK_STRING_LITERAL_COUNT: function=beer count=2 IGNORED_BACKENDS=JS
|
||||
fun beer(x: Int?) = "$x beer"
|
||||
|
||||
// CHECK_STRING_LITERAL_COUNT: function=quux count=2 IGNORED_BACKENDS=JS
|
||||
fun quux(x: Int?) = "${x?.toString()} quux"
|
||||
|
||||
// CHECK_STRING_LITERAL_COUNT: function=test count=2
|
||||
fun test(p: String?): String {
|
||||
return "${p ?: "Default"} test"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (test(null) != "Default test") return "fail 1: ${test(null)}"
|
||||
if (test("Good") != "Good test") return "fail 1: ${test("OK")}"
|
||||
if (test("Good") != "Good test") return "fail 2: ${test("Good")}"
|
||||
if (foo(3) != "foo 3") return "fail 3: ${foo(3)}"
|
||||
if (bar(4) != "4 bar") return "fail 4: ${bar(4)}"
|
||||
if (baz(5) != "5 baz") return "fail 5: ${baz(5)}"
|
||||
if (beer(6) != "6 beer") return "fail 6: ${beer(6)}"
|
||||
if (beer(null) != "null beer") return "fail 7: ${beer(null)}"
|
||||
if (quux(8) != "8 quux") return "fail 8: ${quux(8)}"
|
||||
if (quux(null) != "null quux") return "fail 9: ${quux(null)}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -224,6 +224,8 @@ public class DirectiveTestUtils {
|
||||
|
||||
private static final DirectiveHandler COUNT_DEBUGGER = new CountNodesDirective<>("CHECK_DEBUGGER_COUNT", JsDebugger.class);
|
||||
|
||||
private static final DirectiveHandler COUNT_STRING_LITERALS = new CountNodesDirective<>("CHECK_STRING_LITERAL_COUNT", JsStringLiteral.class);
|
||||
|
||||
private static final DirectiveHandler NOT_REFERENCED = new DirectiveHandler("CHECK_NOT_REFERENCED") {
|
||||
@Override
|
||||
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||
@@ -365,6 +367,7 @@ public class DirectiveTestUtils {
|
||||
COUNT_CASES,
|
||||
COUNT_IF,
|
||||
COUNT_DEBUGGER,
|
||||
COUNT_STRING_LITERALS,
|
||||
NOT_REFERENCED,
|
||||
HAS_INLINE_METADATA,
|
||||
HAS_NO_INLINE_METADATA,
|
||||
|
||||
Reference in New Issue
Block a user