[JS IR BE] Support @JsName in bridges

This commit is contained in:
Svyatoslav Kuzmich
2019-02-12 20:46:06 +03:00
parent e09a6f0007
commit 1184c158e4
6 changed files with 49 additions and 24 deletions
@@ -14,4 +14,5 @@ object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS")
object JS_CLOSURE_BOX_CLASS_DECLARATION : IrDeclarationOriginImpl("JS_CLOSURE_BOX_CLASS_DECLARATION")
object BRIDGE_TO_EXTERNAL_FUNCTION : IrDeclarationOriginImpl("BRIDGE_TO_EXTERNAL_FUNCTION")
}
@@ -15,10 +15,11 @@ import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.asString
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
@@ -26,11 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.isInlined
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.isReal
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
// Constructs bridges for inherited generic functions
@@ -82,6 +79,11 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
continue
}
if (from.function.correspondingProperty != null && from.function.isEffectivelyExternal()) {
// TODO: Revisit bridges from external properties
continue
}
irClass.declarations.add(createBridge(function, from.function, to.function))
}
}
@@ -95,6 +97,12 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
delegateTo: IrSimpleFunction
): IrFunction {
val origin =
if (bridge.isEffectivelyExternal())
JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION
else
IrDeclarationOrigin.BRIDGE
// TODO: Support offsets for debug info
val irFunction = JsIrBuilder.buildFunction(
bridge.name,
@@ -106,7 +114,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
bridge.isExternal,
bridge.isTailrec,
bridge.isSuspend,
IrDeclarationOrigin.BRIDGE
origin
).apply {
// TODO: should dispatch receiver be copied?
@@ -180,20 +188,25 @@ class FunctionAndSignature(val function: IrSimpleFunction) {
// Currently strings are used for compatibility with a hack-based name generator
private data class Signature(
val name: Name,
val extensionReceiverType: String?,
val valueParameters: List<String?>,
val returnType: String?
val name: String,
val extensionReceiverType: String? = null,
val valueParameters: List<String?> = emptyList(),
val returnType: String? = null
)
private val signature = Signature(
function.name,
function.extensionReceiverParameter?.type?.asString(),
function.valueParameters.map { it.type.asString() },
// Return type used in signature for inline classes only because
// they are binary incompatible with supertypes and require bridges.
function.returnType.run { if (isInlined()) asString() else null }
)
private val jsName = function.getJsName()
private val signature = when {
jsName != null -> Signature(jsName)
function.isEffectivelyExternal() -> Signature(function.name.asString())
else -> Signature(
function.name.asString(),
function.extensionReceiverParameter?.type?.asString(),
function.valueParameters.map { it.type.asString() },
// Return type used in signature for inline classes only because
// they are binary incompatible with supertypes and require bridges.
function.returnType.run { if (isInlined()) asString() else null }
)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -106,6 +107,10 @@ class SimpleNameGenerator : NameGenerator {
return@getOrPut context.currentScope.declareName(jsName)
}
if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
return@getOrPut context.staticContext.rootScope.declareName(declaration.name.identifier)
}
if (declaration.isEffectivelyExternal()) {
// TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet
val descriptorName = when (descriptor) {
+3 -1
View File
@@ -54,7 +54,9 @@ fun box(): String {
val dd: dynamic = E()
assertEquals("D.foo(42)", dd.foo(42))
assertEquals("D.foo(99)", dd.bar(99))
assertEquals("D.foo(88)", dd.`foo_za3lpa$`(88))
if (testUtils.isLegacyBackend()) {
assertEquals("D.foo(88)", dd.`foo_za3lpa$`(88))
}
return "OK"
}
+7 -2
View File
@@ -29,7 +29,9 @@ fun box(): String {
val d: dynamic = C()
assertEquals("C.foo(42)", d.foo(42))
assertEquals("C.foo(99)", d.`foo_za3lpa$`(99))
if (testUtils.isLegacyBackend()) {
assertEquals("C.foo(99)", d.`foo_za3lpa$`(99))
}
val da: A = E()
assertEquals("D.foo(55)", da.foo(55))
@@ -39,7 +41,10 @@ fun box(): String {
val dd: dynamic = E()
assertEquals("D.foo(42)", dd.foo(42))
assertEquals("D.foo(99)", dd.`foo_za3lpa$`(99))
if (testUtils.isLegacyBackend()) {
assertEquals("D.foo(99)", dd.`foo_za3lpa$`(99))
}
return "OK"
}
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1303
package foo
open class A {
open val x: Int
@@ -30,7 +29,7 @@ class B : A(), C {
override val z = 55
}
fun getPackage() = js("return JS_TESTS.foo")
fun getPackage() = js("JS_TESTS")
fun box(): String {
val a = B()