[Wasm] Fix JsName external declarations
This commit is contained in:
+1
-5
@@ -68,11 +68,7 @@ class DeclarationGenerator(
|
||||
}
|
||||
|
||||
val wasmImportModule = declaration.getWasmImportDescriptor()
|
||||
|
||||
val jsCode = declaration.getJsFunAnnotation()
|
||||
// TODO: Why are we importing declarations by with raw declaration.name.asString() jsCode?
|
||||
?: if (declaration.isExternal && wasmImportModule == null) declaration.name.asString() else null
|
||||
|
||||
val jsCode = if (declaration.isExternal) declaration.getJsFunAnnotation() else null
|
||||
val importedName = when {
|
||||
wasmImportModule != null -> {
|
||||
check(declaration.isExternal) { "Non-external fun with @WasmImport ${declaration.fqNameWhenAvailable}"}
|
||||
|
||||
+71
-46
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
@@ -333,61 +332,87 @@ class ComplexExternalDeclarationsToTopLevelFunctionsLowering(val context: WasmBa
|
||||
/**
|
||||
* Redirect usages of complex declarations to top-level functions
|
||||
*/
|
||||
class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return transformCall(expression)
|
||||
}
|
||||
class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
private val nestedExternalToNewTopLevelFunctions = context.mapping.wasmNestedExternalToNewTopLevelFunction
|
||||
private val objectToGetInstanceFunctions = context.mapping.wasmExternalObjectToGetInstanceFunction
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return transformCall(expression)
|
||||
}
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptVoid(declarationTransformer)
|
||||
}
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
val externalGetInstance = context.mapping.wasmExternalObjectToGetInstanceFunction[expression.symbol.owner]
|
||||
return if (externalGetInstance != null) {
|
||||
IrCallImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
expression.type,
|
||||
externalGetInstance.symbol,
|
||||
valueArgumentsCount = 0,
|
||||
typeArgumentsCount = 0
|
||||
)
|
||||
private val declarationTransformer = object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
process(declaration)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (!declaration.isExternal) {
|
||||
process(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun process(container: IrDeclarationContainer) {
|
||||
container.declarations.transformFlat { member ->
|
||||
if (nestedExternalToNewTopLevelFunctions.keys.contains(member)) {
|
||||
emptyList()
|
||||
} else {
|
||||
expression
|
||||
member.acceptVoid(this)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun transformCall(call: IrFunctionAccessExpression): IrExpression {
|
||||
val oldFun = call.symbol.owner.realOverrideTarget
|
||||
val newFun: IrSimpleFunction? =
|
||||
context.mapping.wasmNestedExternalToNewTopLevelFunction[oldFun]
|
||||
override fun visitBody(body: IrBody) {
|
||||
body.transformChildrenVoid(usagesTransformer)
|
||||
}
|
||||
}
|
||||
|
||||
return if (newFun != null) {
|
||||
val newCall = irCall(call, newFun, receiversAsArguments = true)
|
||||
private val usagesTransformer = object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return transformCall(expression)
|
||||
}
|
||||
|
||||
// Add default arguments flags if needed
|
||||
val numDefaultParameters = numDefaultParametersForExternalFunction(oldFun)
|
||||
val firstDefaultFlagArgumentIdx = newFun.valueParameters.size - numDefaultParameters
|
||||
val firstOldDefaultArgumentIdx = call.valueArgumentsCount - numDefaultParameters
|
||||
repeat(numDefaultParameters) {
|
||||
val value = if (call.getValueArgument(firstOldDefaultArgumentIdx + it) == null) 1 else 0
|
||||
newCall.putValueArgument(
|
||||
firstDefaultFlagArgumentIdx + it,
|
||||
IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, value)
|
||||
)
|
||||
}
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return transformCall(expression)
|
||||
}
|
||||
|
||||
newCall
|
||||
} else {
|
||||
call
|
||||
}
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
val externalGetInstance = objectToGetInstanceFunctions[expression.symbol.owner] ?: return expression
|
||||
return IrCallImpl(
|
||||
startOffset = expression.startOffset,
|
||||
endOffset = expression.endOffset,
|
||||
type = expression.type,
|
||||
symbol = externalGetInstance.symbol,
|
||||
valueArgumentsCount = 0,
|
||||
typeArgumentsCount = 0
|
||||
)
|
||||
}
|
||||
|
||||
fun transformCall(call: IrFunctionAccessExpression): IrExpression {
|
||||
val oldFun = call.symbol.owner.realOverrideTarget
|
||||
val newFun: IrSimpleFunction = nestedExternalToNewTopLevelFunctions[oldFun] ?: return call
|
||||
|
||||
val newCall = irCall(call, newFun, receiversAsArguments = true)
|
||||
|
||||
// Add default arguments flags if needed
|
||||
val numDefaultParameters = numDefaultParametersForExternalFunction(oldFun)
|
||||
val firstDefaultFlagArgumentIdx = newFun.valueParameters.size - numDefaultParameters
|
||||
val firstOldDefaultArgumentIdx = call.valueArgumentsCount - numDefaultParameters
|
||||
repeat(numDefaultParameters) {
|
||||
val value = if (call.getValueArgument(firstOldDefaultArgumentIdx + it) == null) 1 else 0
|
||||
newCall.putValueArgument(
|
||||
firstDefaultFlagArgumentIdx + it,
|
||||
IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, value)
|
||||
)
|
||||
}
|
||||
})
|
||||
return newCall
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -53,6 +53,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
|
||||
if (declaration.getWasmImportDescriptor() != null) return null
|
||||
check(!(isExported && isExternal)) { "Exported external declarations are not supported: ${declaration.fqNameWhenAvailable}" }
|
||||
check(declaration.parent !is IrClass) { "Interop members are not supported: ${declaration.fqNameWhenAvailable}" }
|
||||
if (context.mapping.wasmNestedExternalToNewTopLevelFunction.keys.contains(declaration)) return null
|
||||
|
||||
additionalDeclarations.clear()
|
||||
currentParent = declaration.parent
|
||||
@@ -435,6 +436,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
|
||||
val result = context.irFactory.buildFun {
|
||||
name = Name.identifier("__convertKotlinClosureToJsClosure_${info.hashString}")
|
||||
returnType = context.wasmSymbols.externalInterfaceType
|
||||
isExternal = true
|
||||
}
|
||||
result.parent = currentParent
|
||||
result.addValueParameter {
|
||||
@@ -551,6 +553,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
|
||||
val result = context.irFactory.buildFun {
|
||||
name = Name.identifier("__callJsClosure_${info.hashString}")
|
||||
returnType = info.adaptedResultType
|
||||
isExternal = true
|
||||
}
|
||||
result.parent = currentParent
|
||||
result.addValueParameter {
|
||||
|
||||
@@ -55,6 +55,9 @@ const externalObj = {
|
||||
c: class { x = "(new externalObj.c()).x" }
|
||||
}
|
||||
|
||||
function jsRenamed() {
|
||||
return 'renamed'
|
||||
}
|
||||
|
||||
// FILE: externals.kt
|
||||
external interface Obj {
|
||||
@@ -112,6 +115,9 @@ external object externalObj {
|
||||
}
|
||||
}
|
||||
|
||||
@JsName("jsRenamed")
|
||||
external fun testJsName(): String
|
||||
|
||||
fun box(): String {
|
||||
val obj = createObject()
|
||||
setX(obj, 100)
|
||||
@@ -164,6 +170,7 @@ fun box(): String {
|
||||
if (10 as Any is C1) return "Fail 23"
|
||||
if (c1 as Any is C2) return "Fail 24"
|
||||
|
||||
if (testJsName() != "renamed") return "Fail 25"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user