[K/JS] Use declared upper-bound types for parameters inside inlined functions body, instead of the provided types
This commit is contained in:
+23
-7
@@ -6,10 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower.inline
|
||||
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.ir.isPure
|
||||
import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
||||
@@ -90,7 +87,8 @@ class FunctionInlining(
|
||||
private val inlinePureArguments: Boolean = true,
|
||||
private val regenerateInlinedAnonymousObjects: Boolean = false,
|
||||
private val inlineArgumentsWithTheirOriginalTypeAndOffset: Boolean = false,
|
||||
private val allowExternalInlining: Boolean = false
|
||||
private val allowExternalInlining: Boolean = false,
|
||||
private val useTypeParameterUpperBound: Boolean = false
|
||||
) : IrElementTransformerVoidWithContext(), BodyLoweringPass {
|
||||
private var containerScope: ScopeWithIr? = null
|
||||
|
||||
@@ -746,7 +744,8 @@ class FunctionInlining(
|
||||
// We take type parameter from copied callee and not from original because we need an actual copy. Without this copy,
|
||||
// in case of recursive call, we can get a situation there the same type parameter will be mapped on different type arguments.
|
||||
// (see compiler/testData/codegen/boxInline/complex/use.kt test file)
|
||||
return copy.typeParameters[typeClassifier.index].defaultType.substituteSuperTypes()
|
||||
val newTypeParameter = copy.typeParameters[typeClassifier.index].defaultType.substituteSuperTypes()
|
||||
return if (useTypeParameterUpperBound) typeClassifier.firstRealUpperBound() else newTypeParameter
|
||||
}
|
||||
|
||||
return when (this) {
|
||||
@@ -755,12 +754,29 @@ class FunctionInlining(
|
||||
copy.extensionReceiverParameter -> original.extensionReceiverParameter?.getTypeIfFromTypeParameter()
|
||||
?: copy.extensionReceiverParameter!!.type
|
||||
else -> copy.valueParameters.first { it == this }.let { valueParameter ->
|
||||
original.valueParameters[valueParameter.index].getTypeIfFromTypeParameter()
|
||||
original.valueParameters.getOrNull(valueParameter.index)?.getTypeIfFromTypeParameter()
|
||||
?: valueParameter.type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrTypeParameter?.firstRealUpperBound(): IrType {
|
||||
val queue = this?.superTypes?.toMutableList() ?: mutableListOf()
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val superType = queue.removeFirst()
|
||||
val superTypeClassifier = superType.classifierOrNull?.owner ?: continue
|
||||
|
||||
if (superTypeClassifier is IrTypeParameter) {
|
||||
queue.addAll(superTypeClassifier.superTypes)
|
||||
} else {
|
||||
return superType
|
||||
}
|
||||
}
|
||||
|
||||
return context.irBuiltIns.anyNType
|
||||
}
|
||||
|
||||
private fun evaluateArguments(callSite: IrFunctionAccessExpression, callee: IrFunction): List<IrStatement> {
|
||||
val arguments = buildParameterToArgument(callSite, callee)
|
||||
val evaluationStatements = mutableListOf<IrVariable>()
|
||||
|
||||
@@ -280,7 +280,17 @@ private val saveInlineFunctionsBeforeInlining = makeDeclarationTransformerPhase(
|
||||
)
|
||||
|
||||
private val functionInliningPhase = makeBodyLoweringPhase(
|
||||
{ FunctionInlining(it, JsInlineFunctionResolver(it), it.innerClassesSupport, allowExternalInlining = true) },
|
||||
{
|
||||
FunctionInlining(
|
||||
it,
|
||||
JsInlineFunctionResolver(it),
|
||||
it.innerClassesSupport,
|
||||
allowExternalInlining = true,
|
||||
useTypeParameterUpperBound = true,
|
||||
alwaysCreateTemporaryVariablesForArguments = true,
|
||||
inlineArgumentsWithTheirOriginalTypeAndOffset = true
|
||||
)
|
||||
},
|
||||
name = "FunctionInliningPhase",
|
||||
description = "Perform function inlining",
|
||||
prerequisite = setOf(saveInlineFunctionsBeforeInlining)
|
||||
|
||||
@@ -8,20 +8,14 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
|
||||
+4
-1
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassBackingField
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassBoxing
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassUnboxing
|
||||
|
||||
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
|
||||
|
||||
@@ -179,6 +181,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val inlineClass = icUtils.getInlinedClass(call.getTypeArgument(0)!!)!!
|
||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||
JsNew(context.getNameForConstructor(constructor).makeRef(), listOf(arg))
|
||||
.apply { isInlineClassBoxing = true }
|
||||
}
|
||||
|
||||
add(intrinsics.jsUnboxIntrinsic) { call, context ->
|
||||
@@ -186,7 +189,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val inlineClass = icUtils.getInlinedClass(call.getTypeArgument(1)!!)!!
|
||||
val field = getInlineClassBackingField(inlineClass)
|
||||
val fieldName = context.getNameForField(field)
|
||||
JsNameRef(fieldName, arg)
|
||||
JsNameRef(fieldName, arg).apply { isInlineClassUnboxing = true }
|
||||
}
|
||||
|
||||
add(intrinsics.jsCall) { call, context: JsGenerationContext ->
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
||||
// WITH_COROUTINES
|
||||
// CHECK_BYTECODE_LISTING
|
||||
// FIR_IDENTICAL
|
||||
// CHECK_NEW_COUNT: function=suspendHere count=0
|
||||
// CHECK_NEW_COUNT: function=suspendHere count=0 TARGET_BACKENDS=JS
|
||||
// FIXME: Coroutine inlining
|
||||
// CHECK_NEW_COUNT: function=complexSuspend count=0 TARGET_BACKENDS=JS
|
||||
import helpers.*
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_STDLIB
|
||||
// WORKS_WHEN_VALUE_CLASS
|
||||
// LANGUAGE: +ValueClasses
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// TARGET_BACKEND: JS_IR_ES6
|
||||
|
||||
interface Foo {
|
||||
fun foo(): String
|
||||
fun bar(): String
|
||||
}
|
||||
|
||||
value class Value(val x: Int) : Foo, Comparable<Value> {
|
||||
override fun foo() = "FOO $x"
|
||||
|
||||
override fun bar() = "BAR $x"
|
||||
|
||||
override fun compareTo(other: Value) = x.compareTo(other.x)
|
||||
}
|
||||
|
||||
inline fun <T> foo(a: T, b: T): String where T: Foo, T: Comparable<T> {
|
||||
return if (a > b) a.foo() else b.foo()
|
||||
}
|
||||
|
||||
inline fun <T> bar(a: T, b: T): String where T: Comparable<T>, T: Foo {
|
||||
return if (a > b) a.bar() else b.bar()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (foo(Value(1), Value(2)) != "FOO 2") return "Fail"
|
||||
if (bar(Value(2), Value(1)) != "BAR 2") return "Fail"
|
||||
return "OK"
|
||||
}
|
||||
-2
@@ -2,8 +2,6 @@
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WORKS_WHEN_VALUE_CLASS
|
||||
// LANGUAGE: +ValueClasses
|
||||
|
||||
|
||||
Vendored
-2
@@ -2,8 +2,6 @@
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WORKS_WHEN_VALUE_CLASS
|
||||
// LANGUAGE: +ValueClasses, +GenericInlineClassParameter
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ fun box() {
|
||||
// a.kt:6 exclamate: s="Jesse":kotlin.String
|
||||
// test.kt:52 box: jesse="Jesse":kotlin.String, walter1="Walter!":kotlin.String, jesse1="Jesse!":kotlin.String
|
||||
// a.kt:6 exclamate: s="Jesse!":kotlin.String
|
||||
// a.kt:19 box: jesse="Jesse":kotlin.String, walter1="Walter!":kotlin.String, jesse1="Jesse!":kotlin.String
|
||||
// a.kt:22 value:
|
||||
// test.kt:63 box: jesse="Jesse":kotlin.String, walter1="Walter!":kotlin.String, jesse1="Jesse!":kotlin.String
|
||||
// test.kt:59 localFun: hello="hello":kotlin.String, world="world":kotlin.String
|
||||
|
||||
@@ -47,6 +47,7 @@ fun box(): String {
|
||||
// test.kt:30 box
|
||||
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:16 box
|
||||
// test.kt:17 box
|
||||
// test.kt:7 box
|
||||
// test.kt:30 box
|
||||
|
||||
@@ -25,4 +25,4 @@ inline fun bar(i: Int = 1) {
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:4 box
|
||||
// test.kt:9 foo
|
||||
// test.kt:6 box
|
||||
// test.kt:6 box
|
||||
|
||||
@@ -22,6 +22,6 @@ fun g() {}
|
||||
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:3 box
|
||||
// test.kt:8 box
|
||||
// test.kt:4 box
|
||||
// test.kt:11 g
|
||||
// test.kt:5 box
|
||||
@@ -79,6 +79,9 @@ var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = nul
|
||||
|
||||
var HasMetadata.synthetic: Boolean by MetadataProperty(default = false)
|
||||
|
||||
var HasMetadata.isInlineClassBoxing: Boolean by MetadataProperty(default = false)
|
||||
var HasMetadata.isInlineClassUnboxing: Boolean by MetadataProperty(default = false)
|
||||
|
||||
var HasMetadata.sideEffects: SideEffectKind by MetadataProperty(default = SideEffectKind.AFFECTS_STATE)
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.inline.clean
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression.JsExpressionHasArguments
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassBoxing
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassUnboxing
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isJsCall
|
||||
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
||||
|
||||
// Replaces box(unbox(value)) and unbox(box(value)) with value
|
||||
class BoxingUnboxingElimination(private val root: JsBlock) {
|
||||
private var changed = false
|
||||
|
||||
fun apply(): Boolean {
|
||||
val visitor = object : JsVisitorWithContextImpl() {
|
||||
override fun endVisit(x: JsInvocation, ctx: JsContext<JsNode>) {
|
||||
super.endVisit(x, ctx)
|
||||
tryEliminate(x, ctx)
|
||||
}
|
||||
|
||||
override fun endVisit(x: JsNew, ctx: JsContext<JsNode>) {
|
||||
super.endVisit(x, ctx)
|
||||
tryEliminate(x, ctx)
|
||||
}
|
||||
|
||||
|
||||
override fun endVisit(x: JsNameRef, ctx: JsContext<JsNode>) {
|
||||
super.endVisit(x, ctx)
|
||||
tryEliminate(x, ctx)
|
||||
}
|
||||
|
||||
override fun endVisit(x: JsArrayAccess, ctx: JsContext<*>) {
|
||||
super.endVisit(x, ctx)
|
||||
}
|
||||
|
||||
override fun visit(x: JsFunction, ctx: JsContext<JsNode>) = false
|
||||
|
||||
private fun tryEliminate(expression: JsExpression, ctx: JsContext<JsNode>) {
|
||||
if (!expression.isInlineClassBoxing && !expression.isInlineClassUnboxing) return
|
||||
|
||||
val firstArg = expression.arguments.first()
|
||||
|
||||
if (!firstArg.isInlineClassBoxing && !firstArg.isInlineClassUnboxing) return
|
||||
|
||||
if (firstArg.isInlineClassBoxing != expression.isInlineClassBoxing) {
|
||||
ctx.replaceMe(firstArg.arguments.first())
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
private val JsExpression.arguments: List<JsExpression>
|
||||
get() = when (this) {
|
||||
is JsExpressionHasArguments -> arguments
|
||||
is JsNameRef -> listOfNotNull(qualifier)
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
visitor.accept(root)
|
||||
|
||||
return changed
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ class FunctionPostProcessor(val root: JsFunction) {
|
||||
{ DeadCodeElimination(root.body).apply() },
|
||||
{ RedundantVariableDeclarationElimination(root.body).apply() },
|
||||
{ RedundantStatementElimination(root).apply() },
|
||||
{ CoroutineStateElimination(root.body).apply() }
|
||||
{ CoroutineStateElimination(root.body).apply() },
|
||||
{ BoxingUnboxingElimination(root.body).apply() }
|
||||
)
|
||||
// TODO: reduce to A || B, A && B if possible
|
||||
|
||||
|
||||
@@ -1692,6 +1692,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/dynamic/iterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaParameterInlining.kt")
|
||||
public void testLambdaParameterInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/box/dynamic/lambdaParameterInlining.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nameClashing.kt")
|
||||
public void testNameClashing() throws Exception {
|
||||
|
||||
+6
@@ -1762,6 +1762,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
||||
runTest("js/js.translator/testData/box/dynamic/iterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaParameterInlining.kt")
|
||||
public void testLambdaParameterInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/box/dynamic/lambdaParameterInlining.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("operationsWithAssignment.kt")
|
||||
public void testOperationsWithAssignment() throws Exception {
|
||||
|
||||
+6
@@ -18570,6 +18570,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986Generic.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withInlineFunctionWithMultipleConstraints.kt")
|
||||
public void testWithInlineFunctionWithMultipleConstraints() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/withInlineFunctionWithMultipleConstraints.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/inlineClasses/callableReferences/let")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+6
@@ -1762,6 +1762,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
runTest("js/js.translator/testData/box/dynamic/iterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaParameterInlining.kt")
|
||||
public void testLambdaParameterInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/box/dynamic/lambdaParameterInlining.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("operationsWithAssignment.kt")
|
||||
public void testOperationsWithAssignment() throws Exception {
|
||||
|
||||
+6
@@ -1762,6 +1762,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/dynamic/iterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaParameterInlining.kt")
|
||||
public void testLambdaParameterInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/box/dynamic/lambdaParameterInlining.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("operationsWithAssignment.kt")
|
||||
public void testOperationsWithAssignment() throws Exception {
|
||||
|
||||
+6
@@ -18570,6 +18570,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986Generic.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withInlineFunctionWithMultipleConstraints.kt")
|
||||
public void testWithInlineFunctionWithMultipleConstraints() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/withInlineFunctionWithMultipleConstraints.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/inlineClasses/callableReferences/let")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+6
@@ -18570,6 +18570,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986Generic.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withInlineFunctionWithMultipleConstraints.kt")
|
||||
public void testWithInlineFunctionWithMultipleConstraints() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/withInlineFunctionWithMultipleConstraints.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/inlineClasses/callableReferences/let")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1288
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
@JsExport
|
||||
interface I {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1282
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
fun box(): String {
|
||||
val a = 'Q'.foo()
|
||||
if (a != "number") return "fail1: $a"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1289
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
@JsExport
|
||||
open class A {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1283
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
fun foo(x: Any): String {
|
||||
return when (x) {
|
||||
is Char -> "char: ${x.toInt()}"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
fun demo(x: dynamic, a: Array<out dynamic>): Boolean? {
|
||||
return a.any { y: Any ->
|
||||
val newX: Any = x.unsafeCast<Any>()
|
||||
y == newX
|
||||
}
|
||||
}
|
||||
|
||||
data class X(val x: Int)
|
||||
|
||||
fun box(): String {
|
||||
|
||||
if (demo(X(1), arrayOf(X(1))) != true) return "fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -317,8 +317,7 @@ fun testCompareDifferentInstancesInSmartCast() {
|
||||
fun testCompareDifferentInstncesInInlineTemplate() {
|
||||
inline fun <reified T, reified S> myEq(x: T, y: S) = x == y
|
||||
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=testCompareDifferentInstncesInInlineTemplate$caseJsEq function=equals
|
||||
// CHECK_NEW_COUNT: function=testCompareDifferentInstncesInInlineTemplate$caseJsEq count=0
|
||||
// CHECK_NEW_COUNT: function=testCompareDifferentInstncesInInlineTemplate$caseJsEq count=8
|
||||
fun caseJsEq() {
|
||||
assertTrue(myEq(ClassInt(1), ClassInt(1)))
|
||||
assertTrue(myEq(ClassString("foo"), ClassString("foo")))
|
||||
|
||||
+1
-2
@@ -2,8 +2,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_NOT_CALLED: isTypeOfOrNull
|
||||
// CHECK_NULLS_COUNT: function=box count=10 TARGET_BACKENDS=JS
|
||||
// CHECK_NULLS_COUNT: function=box count=6 IGNORED_BACKENDS=JS
|
||||
// CHECK_NULLS_COUNT: function=box count=10
|
||||
|
||||
inline
|
||||
fun <reified T> Any?.isTypeOfOrNull() = this is T?
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1281
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
fun box(): String {
|
||||
val a = CharArray(1)
|
||||
|
||||
+2
-1
@@ -15,4 +15,5 @@ suspend fun bar(): Unit {
|
||||
}
|
||||
|
||||
// LINES(JS): 39 4 4 4 7 5 5 45 45 5 93 45 5 5 6 4 4 4 9 15 9 9 9 * 9 15 10 10 11 11 11 11 11 * 11 12 12 13 13 13 13 13 13 13 14 14 * 9 15 9 9 9 9
|
||||
// LINES(JS_IR): 4 4 * 93 93 45 45 7 7 6 9 9 * 9 * 9 * 10 10 * 11 * 11 12 12 * 13 * 13 14 14 15 15
|
||||
// LINES(JS_IR): 4 4 * 93 93 3 45 45 7 7 6 9 9 * 9 * 9 * 10 10 * 11 * 11 12 12 * 13 * 13 14 14 15 15
|
||||
|
||||
|
||||
@@ -33,4 +33,4 @@ inline operator fun P.component1() = a
|
||||
inline operator fun P.component2() = b
|
||||
|
||||
// LINES(JS): 15 22 17 17 31 18 18 33 20 20 21 21 22 22 3 23 9 9 9 9 4 9 9 9 6 6 31 7 7 33 11 11 12 12 15 15 25 27 26 26 29 29 29 * 31 31 31 33 33 33 * 1 * 1
|
||||
// LINES(JS_IR): 1 1 1 1 1 1 1 1 * 3 3 9 9 4 9 * 6 31 * 7 33 11 11 12 12 15 15 25 25 26 26 29 29 29 29 29 29 29 29 29 29 29 29 31 31 31 31 33 33 33 33 15 16 15 * 17 31 * 18 33 20 20 21 21 22 22 * 1
|
||||
// LINES(JS_IR): 1 1 1 1 1 1 1 1 * 3 3 9 9 4 9 * 6 31 9 * 7 33 9 11 11 12 12 15 15 25 25 26 26 29 29 29 29 29 29 29 29 29 29 29 29 31 31 31 31 33 33 33 33 15 16 15 * 17 31 16 * 18 33 16 20 20 21 21 22 22 * 1
|
||||
|
||||
+3
-2
@@ -17,5 +17,6 @@ fun box() {
|
||||
}
|
||||
}
|
||||
|
||||
// LINES(JS): 1 18 2 2 10 2 2 2 2 2 2 3 3 6 6 6 6 7 7 10 10 10 10 10 10 11 11 14 14 15 15 15 15 16 16
|
||||
// LINES(JS_IR): 1 1 * 2 2 2 2 2 2 2 2 3 3 6 6 6 6 6 6 6 7 7 10 10 10 10 11 11 14 15 15 15 15 15 15 15 15 16 16
|
||||
// LINES(JS): 1 18 2 2 10 2 2 2 2 2 2 3 3 6 6 6 6 7 7 10 10 10 10 10 10 11 11 14 14 15 15 15 15 16 16
|
||||
// LINES(JS_IR): 1 1 * 2 2 2 2 2 2 2 2 3 3 6 6 6 6 6 6 6 7 7 10 10 10 10 11 11 14 15 15 15 15 15 15 15 15 16 16
|
||||
|
||||
|
||||
@@ -10,4 +10,4 @@ fun bar() {
|
||||
}
|
||||
|
||||
// LINES(JS): 1 1 1 1 1 6 2 2 3 3 4 4 8 10 2 2 9 2 3 3 4 4
|
||||
// LINES(JS_IR): 1 1 2 3 3 3 4 4 8 8 * 2 3 3 3 4 4
|
||||
// LINES(JS_IR): 1 1 2 3 3 3 4 4 8 8 * 2 9 2 3 3 3 4 4
|
||||
@@ -22,5 +22,5 @@ fun box() {
|
||||
foo("42")
|
||||
}
|
||||
|
||||
// LINES(JS): 6 20 23 7 7 21 7 8 8 21 8 7 7 22 7 8 8 22 8
|
||||
// LINES(JS_IR): 20 20 * 7 7 8 8 * 7 7 8 8
|
||||
// LINES(JS): 6 20 23 7 7 21 7 8 8 21 8 7 7 22 7 8 8 22 8
|
||||
// LINES(JS_IR): 20 20 * 7 7 8 7 8 8 * 7 7 8 7 8 8
|
||||
@@ -1110,7 +1110,7 @@ public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1126,7 +1126,7 @@ public actual fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1142,7 +1142,7 @@ public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1158,7 +1158,7 @@ public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: I
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1174,7 +1174,7 @@ public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int =
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1190,7 +1190,7 @@ public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1206,7 +1206,7 @@ public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: I
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1222,7 +1222,7 @@ public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex:
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1238,7 +1238,8 @@ public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toInde
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
// We need to call [Char.code] here to eliminate Char-boxing with the new JS function inlining logic
|
||||
nativeFill(element.code, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1140,7 +1140,7 @@ public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1156,7 +1156,7 @@ public actual fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1172,7 +1172,7 @@ public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,7 +1188,7 @@ public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: I
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1204,7 +1204,7 @@ public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int =
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1220,7 +1220,7 @@ public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1236,7 +1236,7 @@ public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: I
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1252,7 +1252,7 @@ public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex:
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1268,7 +1268,8 @@ public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toInde
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
public actual fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
// We need to call [Char.code] here to eliminate Char-boxing with the new JS function inlining logic
|
||||
nativeFill(element.code, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1623,9 +1623,20 @@ object ArrayOps : TemplateGroupBase() {
|
||||
body {
|
||||
"""
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
nativeFill(element, fromIndex, toIndex);
|
||||
nativeFill(element, fromIndex, toIndex)
|
||||
"""
|
||||
}
|
||||
specialFor(ArraysOfPrimitives) {
|
||||
if (primitive == PrimitiveType.Char) {
|
||||
body {
|
||||
"""
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
// We need to call [Char.code] here to eliminate Char-boxing with the new JS function inlining logic
|
||||
nativeFill(element.code, fromIndex, toIndex)
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
on(Platform.Native) {
|
||||
suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||
|
||||
Reference in New Issue
Block a user