From 41ebe498f2168c69d9c0e06a257a3b6a716ca9be Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Wed, 22 Nov 2023 17:43:23 +0100 Subject: [PATCH] [JS IR] Explicitly cast to a string all types except specific ones ^KT-62763 Fixed --- .../js/lower/JsStringConcatenationLowering.kt | 24 +++++++++---- .../testData/box/builtins/arrayToString.kt | 2 +- .../box/builtins/stringTemplateWithValueOf.kt | 35 +++++++++---------- .../box/inlineEvaluationOrder/arrayAccess1.kt | 4 +-- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsStringConcatenationLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsStringConcatenationLowering.kt index df432b0aa16..73018e8473a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsStringConcatenationLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsStringConcatenationLowering.kt @@ -26,17 +26,27 @@ class JsStringConcatenationLowering(val context: CommonBackendContext) : FileLow } private class JsStringConcatenationTransformer(val context: CommonBackendContext) : IrElementTransformerVoid() { - private val IrType.shouldExplicitlyConvertToString: Boolean get() { - // If the type is Long or a supertype of Long, we want to call toString() on values of that type. - // See KT-39891 if (this !is IrSimpleType) return false + /** + * The type may have a valueOf() function, meaning that in string concatenation, + * the toString() function will be ignored, and the valueOf() function will be called instead. + * Therefore, we have to wrap all types except those where we are sure that they don't have the valueOf() function. + * + * Note, that we do not check for the existence of the valueOf() function + * in the class because it would complicate incremental compilation. + * + * Ignore [Long] and all its supertypes ([Any], [Comparable], [Number]) since [Long] has the valueOf() method. + * Ignore [Char] since it requires an explicit conversion to string. + */ return when (classifier.signature) { - IdSignatureValues.any, IdSignatureValues.comparable, IdSignatureValues.number, - IdSignatureValues._long, IdSignatureValues._char - -> true - else -> false + IdSignatureValues._boolean, IdSignatureValues.string, IdSignatureValues.array, + IdSignatureValues._byte, IdSignatureValues._short, IdSignatureValues._int, + IdSignatureValues.uByte, IdSignatureValues.uShort, IdSignatureValues.uInt, IdSignatureValues.uLong, + IdSignatureValues._float, IdSignatureValues._double, + -> false + else -> true } } diff --git a/js/js.translator/testData/box/builtins/arrayToString.kt b/js/js.translator/testData/box/builtins/arrayToString.kt index 60125f1703a..11c5a465447 100644 --- a/js/js.translator/testData/box/builtins/arrayToString.kt +++ b/js/js.translator/testData/box/builtins/arrayToString.kt @@ -66,7 +66,7 @@ fun box(): String { if (testUtils.isLegacyBackend()) { assertEquals("[...];1,2,3;[...];", pullLog(), "genericValueToString") } else { - assertEquals("[...];1,2,3;1,2,3;", pullLog(), "genericValueToString") + assertEquals("[...];[...];[...];", pullLog(), "genericValueToString") } anyValueToString(a) diff --git a/js/js.translator/testData/box/builtins/stringTemplateWithValueOf.kt b/js/js.translator/testData/box/builtins/stringTemplateWithValueOf.kt index dba39a66c55..6f5f588a881 100644 --- a/js/js.translator/testData/box/builtins/stringTemplateWithValueOf.kt +++ b/js/js.translator/testData/box/builtins/stringTemplateWithValueOf.kt @@ -60,28 +60,26 @@ fun testInt() { fun testLong() { val expectedMax = " 9223372036854775807 " - val expectedMaxBUG = " 9223372036854776000 " val v1 = Long.MAX_VALUE assertEquals(expectedMax, " $v1 ", "testLong - template v1") assertEquals(expectedMax, toStringTemplateAny(v1), "testLong - toStringTemplateAny(v1)") - assertEquals(expectedMaxBUG, toStringTemplateGeneric(v1), "testLong - toStringTemplateGeneric(v1)") + assertEquals(expectedMax, toStringTemplateGeneric(v1), "testLong - toStringTemplateGeneric(v1)") assertEquals(expectedMax, toStringTemplateInlineGeneric(v1), "testLong - toStringTemplateInlineGeneric(v1)") assertEquals(expectedMax, toStringTemplateInlineReifiedGeneric(v1), "testLong - toStringTemplateInlineReifiedGeneric(v1)") - assertEquals(expectedMaxBUG, TestClass(v1).asString(), "testLong - TestClass(v1).asString()") - assertEquals(expectedMaxBUG, TestClass(v1).asStringInline(), "testLong - TestClass(v1).asStringInline()") + assertEquals(expectedMax, TestClass(v1).asString(), "testLong - TestClass(v1).asString()") + assertEquals(expectedMax, TestClass(v1).asStringInline(), "testLong - TestClass(v1).asStringInline()") val expectedMin = " -9223372036854775808 " - val expectedMinBUG = " -9223372036854776000 " val v2 = Long.MIN_VALUE assertEquals(expectedMin, " $v2 ", "testLong - template v2") assertEquals(expectedMin, toStringTemplateAny(v2), "testLong - toStringTemplateAny(v2)") - assertEquals(expectedMinBUG, toStringTemplateGeneric(v2), "testLong - toStringTemplateGeneric(v2)") + assertEquals(expectedMin, toStringTemplateGeneric(v2), "testLong - toStringTemplateGeneric(v2)") assertEquals(expectedMin, toStringTemplateInlineGeneric(v2), "testLong - toStringTemplateInlineGeneric(v2)") assertEquals(expectedMin, toStringTemplateInlineReifiedGeneric(v2), "testLong - toStringTemplateInlineReifiedGeneric(v2)") - assertEquals(expectedMinBUG, TestClass(v2).asString(), "testLong - TestClass(v2).asString()") - assertEquals(expectedMinBUG, TestClass(v2).asStringInline(), "testLong - TestClass(v2).asStringInline()") + assertEquals(expectedMin, TestClass(v2).asString(), "testLong - TestClass(v2).asString()") + assertEquals(expectedMin, TestClass(v2).asStringInline(), "testLong - TestClass(v2).asStringInline()") } fun testULong() { @@ -117,11 +115,11 @@ fun testArrayInt() { assertEquals(expected, " $v ", "testArrayInt - template") assertEquals(expectedShort, toStringTemplateAny(v), "testArrayInt - toStringTemplateAny") - assertEquals(expected, toStringTemplateGeneric(v), "testArrayInt - toStringTemplateGeneric") + assertEquals(expectedShort, toStringTemplateGeneric(v), "testArrayInt - toStringTemplateGeneric") assertEquals(expectedShort, toStringTemplateInlineGeneric(v), "testArrayInt - toStringTemplateInlineGeneric") assertEquals(expectedShort, toStringTemplateInlineReifiedGeneric(v), "testArrayInt - toStringTemplateInlineReifiedGeneric") - assertEquals(expected, TestClass(v).asString(), "testArrayInt - TestClass::asString") - assertEquals(expected, TestClass(v).asStringInline(), "testArrayInt - TestClass::asStringInline") + assertEquals(expectedShort, TestClass(v).asString(), "testArrayInt - TestClass::asString") + assertEquals(expectedShort, TestClass(v).asStringInline(), "testArrayInt - TestClass::asStringInline") } fun testArrayLong() { @@ -131,11 +129,11 @@ fun testArrayLong() { assertEquals(expected, " $v ", "testArrayLong - template") assertEquals(expectedShort, toStringTemplateAny(v), "testArrayLong - toStringTemplateAny") - assertEquals(expected, toStringTemplateGeneric(v), "testArrayLong - toStringTemplateGeneric") + assertEquals(expectedShort, toStringTemplateGeneric(v), "testArrayLong - toStringTemplateGeneric") assertEquals(expectedShort, toStringTemplateInlineGeneric(v), "testArrayLong - toStringTemplateInlineGeneric") assertEquals(expectedShort, toStringTemplateInlineReifiedGeneric(v), "testArrayLong - toStringTemplateInlineReifiedGeneric") - assertEquals(expected, TestClass(v).asString(), "testArrayLong - TestClass::asString") - assertEquals(expected, TestClass(v).asStringInline(), "testArrayLong - TestClass::asStringInline") + assertEquals(expectedShort, TestClass(v).asString(), "testArrayLong - TestClass::asString") + assertEquals(expectedShort, TestClass(v).asStringInline(), "testArrayLong - TestClass::asStringInline") } class UserClass { @@ -147,16 +145,15 @@ class UserClass { fun testUserClass() { val expected = " Hello World! " - val expectedBUG = " NOT OK!!! " val v = UserClass() - assertEquals(expectedBUG, " $v ", "testUserClass - template") + assertEquals(expected, " $v ", "testUserClass - template") assertEquals(expected, toStringTemplateAny(v), "testUserClass - toStringTemplateAny(v)") - assertEquals(expectedBUG, toStringTemplateGeneric(v), "testUserClass - toStringTemplateGeneric(v)") + assertEquals(expected, toStringTemplateGeneric(v), "testUserClass - toStringTemplateGeneric(v)") assertEquals(expected, toStringTemplateInlineGeneric(v), "testUserClass - toStringTemplateInlineGeneric(v)") assertEquals(expected, toStringTemplateInlineReifiedGeneric(v), "testUserClass - toStringTemplateInlineReifiedGeneric(v)") - assertEquals(expectedBUG, TestClass(v).asString(), "testUserClass - TestClass(v).asString()") - assertEquals(expectedBUG, TestClass(v).asStringInline(), "testUserClass - TestClass(v).asStringInline()") + assertEquals(expected, TestClass(v).asString(), "testUserClass - TestClass(v).asString()") + assertEquals(expected, TestClass(v).asStringInline(), "testUserClass - TestClass(v).asStringInline()") } value class UserValueClass(val x: Int) { diff --git a/js/js.translator/testData/box/inlineEvaluationOrder/arrayAccess1.kt b/js/js.translator/testData/box/inlineEvaluationOrder/arrayAccess1.kt index 9c6b3dba08b..1c68ec63c15 100644 --- a/js/js.translator/testData/box/inlineEvaluationOrder/arrayAccess1.kt +++ b/js/js.translator/testData/box/inlineEvaluationOrder/arrayAccess1.kt @@ -3,7 +3,7 @@ package foo fun box(): String { assertEquals(2, fizz(arrayOf(1, 2))[buzz(1)]) - assertEquals("fizz(1,2);buzz(1);", pullLog()) + assertEquals("fizz([...]);buzz(1);", pullLog()) return "OK" -} \ No newline at end of file +}