[JS IR BE] support CharSequence and String methods
This commit is contained in:
@@ -9,9 +9,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||||
@@ -219,6 +222,20 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
|
|
||||||
val jsArraySlice = unOp("slice")
|
val jsArraySlice = unOp("slice")
|
||||||
|
|
||||||
|
// TODO move to IntrinsifyCallsLowering
|
||||||
|
val doNotIntrinsifyAnnotationSymbol = context.symbolTable.referenceClass(context.getInternalClass("DoNotIntrinsify"))
|
||||||
|
|
||||||
|
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering
|
||||||
|
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
|
||||||
|
val charSequenceLengthPropertyGetterSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
|
||||||
|
val charSequenceGetFunctionSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "get"}.symbol
|
||||||
|
val charSequenceSubSequenceFunctionSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence"}.symbol
|
||||||
|
|
||||||
|
|
||||||
|
val jsCharSequenceGet = getInternalFunction("charSequenceGet")
|
||||||
|
val jsCharSequenceLength = getInternalFunction("charSequenceLength")
|
||||||
|
val jsCharSequenceSubSequence = getInternalFunction("charSequenceSubSequence")
|
||||||
|
|
||||||
// Helpers:
|
// Helpers:
|
||||||
|
|
||||||
private fun getInternalFunction(name: String) =
|
private fun getInternalFunction(name: String) =
|
||||||
|
|||||||
+11
@@ -162,6 +162,13 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
}
|
}
|
||||||
|
|
||||||
add(context.irBuiltIns.stringClass.lengthProperty, context.intrinsics.jsArrayLength, true)
|
add(context.irBuiltIns.stringClass.lengthProperty, context.intrinsics.jsArrayLength, true)
|
||||||
|
add(context.irBuiltIns.stringClass.getFunction, intrinsics.jsCharSequenceGet.owner, true)
|
||||||
|
add(context.irBuiltIns.stringClass.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence"}.symbol,
|
||||||
|
intrinsics.jsCharSequenceSubSequence.owner, true)
|
||||||
|
|
||||||
|
add(intrinsics.charSequenceLengthPropertyGetterSymbol, intrinsics.jsCharSequenceLength.owner, true)
|
||||||
|
add(intrinsics.charSequenceGetFunctionSymbol, intrinsics.jsCharSequenceGet.owner, true)
|
||||||
|
add(intrinsics.charSequenceSubSequenceFunctionSymbol, intrinsics.jsCharSequenceSubSequence.owner, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
memberToTransformer.run {
|
memberToTransformer.run {
|
||||||
@@ -352,6 +359,10 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
val symbol = call.symbol
|
val symbol = call.symbol
|
||||||
val declaration = symbol.owner
|
val declaration = symbol.owner
|
||||||
|
|
||||||
|
if (declaration.annotations.any { it.superQualifierSymbol == intrinsics.doNotIntrinsifyAnnotationSymbol }) {
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
|
||||||
if (declaration.isDynamic() || declaration.isEffectivelyExternal()) {
|
if (declaration.isDynamic() || declaration.isEffectivelyExternal()) {
|
||||||
when (call.origin) {
|
when (call.origin) {
|
||||||
IrStatementOrigin.GET_PROPERTY -> {
|
IrStatementOrigin.GET_PROPERTY -> {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val cs: CharSequence = "abcd"
|
val cs: CharSequence = "abcd"
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// COMMON_COROUTINES_TEST
|
// COMMON_COROUTINES_TEST
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// DONT_RUN_GENERATED_CODE: JS
|
// DONT_RUN_GENERATED_CODE: JS
|
||||||
|
|
||||||
fun escapeChar(c : Char) : String? = when (c) {
|
fun escapeChar(c : Char) : String? = when (c) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
fun StringBuilder.first() = this.get(0)
|
fun StringBuilder.first() = this.get(0)
|
||||||
|
|
||||||
fun foo() = StringBuilder("foo").first()
|
fun foo() = StringBuilder("foo").first()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val list = ArrayList<String>()
|
val list = ArrayList<String>()
|
||||||
list.add("0")
|
list.add("0")
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val c: Char? = '0'
|
val c: Char? = '0'
|
||||||
c!!.toInt()
|
c!!.toInt()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val s: String? = "abc"
|
val s: String? = "abc"
|
||||||
val c = s?.get(0)!! - 'b'
|
val c = s?.get(0)!! - 'b'
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
|
|
||||||
fun foo(i : Int?, a : Any?) {
|
fun foo(i : Int?, a : Any?) {
|
||||||
i?.plus(1)
|
i?.plus(1)
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
|
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
-3
@@ -1,9 +1,6 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
|
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS_IR or not
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
|
|
||||||
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
|
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun test(s: CharSequence): Int {
|
fun test(s: CharSequence): Int {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-3
@@ -1,9 +1,6 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
|
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
|
||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS_IR or not
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
|
|
||||||
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
|
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
class Thing(delegate: CharSequence) : CharSequence by delegate
|
class Thing(delegate: CharSequence) : CharSequence by delegate
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val sb = StringBuilder("OK")
|
val sb = StringBuilder("OK")
|
||||||
return "${sb.get(0)}${sb[1]}"
|
return "${sb.get(0)}${sb[1]}"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// KT-5956 java.lang.AbstractMethodError: test.Thing.subSequence(II)Ljava/lang/CharSequence
|
// KT-5956 java.lang.AbstractMethodError: test.Thing.subSequence(II)Ljava/lang/CharSequence
|
||||||
|
|
||||||
class Thing(val delegate: CharSequence) : CharSequence {
|
class Thing(val delegate: CharSequence) : CharSequence {
|
||||||
|
|||||||
+1
-2
@@ -122,8 +122,7 @@ public class GenerateRangesCodegenTestData {
|
|||||||
private static final List<String> IGNORED_FOR_JS_BACKEND = Collections.emptyList();
|
private static final List<String> IGNORED_FOR_JS_BACKEND = Collections.emptyList();
|
||||||
|
|
||||||
private static final List<String> IGNORED_FOR_JS_IR_BACKEND = Arrays.asList("inexactDownToMinValue.kt",
|
private static final List<String> IGNORED_FOR_JS_IR_BACKEND = Arrays.asList("inexactDownToMinValue.kt",
|
||||||
"inexactToMaxValue.kt",
|
"inexactToMaxValue.kt");
|
||||||
"simpleRangeWithNonConstantEnds.kt");
|
|
||||||
|
|
||||||
private static final List<String> IGNORED_FOR_NATIVE_BACKEND = Collections.emptyList();
|
private static final List<String> IGNORED_FOR_NATIVE_BACKEND = Collections.emptyList();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1230
|
// EXPECTED_REACHABLE_NODES: 1230
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1250
|
// EXPECTED_REACHABLE_NODES: 1250
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1286
|
// EXPECTED_REACHABLE_NODES: 1286
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1284
|
// EXPECTED_REACHABLE_NODES: 1284
|
||||||
// See KT-8005
|
// See KT-8005
|
||||||
package foo
|
package foo
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1300
|
// EXPECTED_REACHABLE_NODES: 1300
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1303
|
// EXPECTED_REACHABLE_NODES: 1303
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1524
|
// EXPECTED_REACHABLE_NODES: 1524
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1288
|
// EXPECTED_REACHABLE_NODES: 1288
|
||||||
var log = ""
|
var log = ""
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package kotlin.js
|
||||||
|
|
||||||
|
internal annotation class DoNotIntrinsify
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@DoNotIntrinsify
|
||||||
|
internal fun charSequenceGet(a: CharSequence, index: Int): Char {
|
||||||
|
return if (a is String) {
|
||||||
|
Char(a.asDynamic().charCodeAt(index).unsafeCast<Int>())
|
||||||
|
} else {
|
||||||
|
a[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@DoNotIntrinsify
|
||||||
|
internal fun charSequenceLength(a: CharSequence): Int {
|
||||||
|
return if (a is String) {
|
||||||
|
a.asDynamic().length.unsafeCast<Int>()
|
||||||
|
} else {
|
||||||
|
a.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@DoNotIntrinsify
|
||||||
|
internal fun charSequenceSubSequence(a: CharSequence, startIndex: Int, endIndex: Int): CharSequence {
|
||||||
|
return if (a is String) {
|
||||||
|
a.asDynamic().substring(startIndex, endIndex).unsafeCast<String>()
|
||||||
|
} else {
|
||||||
|
a.subSequence(startIndex, endIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user