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