[JS IR BE] Support call super with default parameters
This commit is contained in:
@@ -241,6 +241,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
val jsArraySlice = unOp("slice")
|
||||
|
||||
val jsBind = defineJsBindIntrinsic()
|
||||
|
||||
// TODO move to IntrinsifyCallsLowering
|
||||
val doNotIntrinsifyAnnotationSymbol = context.symbolTable.referenceClass(context.getInternalClass("DoNotIntrinsify"))
|
||||
|
||||
@@ -302,6 +304,19 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
externalPackageFragment.declarations += it
|
||||
}
|
||||
|
||||
private fun defineJsBindIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
"\$jsBind\$",
|
||||
returnType = irBuiltIns.anyNType,
|
||||
parent = externalPackageFragment,
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
listOf("receiver", "target").mapIndexedTo(it.valueParameters) { i, p ->
|
||||
JsIrBuilder.buildValueParameter(p, i, irBuiltIns.anyType).also { v -> v.parent = it }
|
||||
}
|
||||
externalPackageFragment.declarations += it
|
||||
}
|
||||
|
||||
private fun defineSetJSPropertyIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
"\$setJSProperty\$",
|
||||
|
||||
@@ -182,7 +182,7 @@ private val CallableReferenceLoweringPhase = makeJsPhase(
|
||||
)
|
||||
|
||||
private val DefaultArgumentStubGeneratorPhase = makeJsPhase(
|
||||
{ context, module -> DefaultArgumentStubGenerator(context).lower(module) },
|
||||
{ context, module -> JsDefaultArgumentStubGenerator(context).lower(module) },
|
||||
name = "DefaultArgumentStubGenerator",
|
||||
description = "Generate synthetic stubs for functions with default parameter values"
|
||||
)
|
||||
@@ -200,6 +200,12 @@ private val DefaultParameterCleanerPhase = makeJsPhase(
|
||||
description = "Clean default parameters up"
|
||||
)
|
||||
|
||||
private val JsDefaultCallbackGeneratorPhase = makeJsPhase(
|
||||
{ context, module -> JsDefaultCallbackGenerator(context).lower(module) },
|
||||
name = "JsDefaultCallbackGenerator",
|
||||
description = "Build binding for super calls with default parameters"
|
||||
)
|
||||
|
||||
private val VarargLoweringPhase = makeJsPhase(
|
||||
{ context, module -> VarargLowering(context).lower(module) },
|
||||
name = "VarargLowering",
|
||||
@@ -342,6 +348,7 @@ val jsPhases = listOf(
|
||||
DefaultArgumentStubGeneratorPhase,
|
||||
DefaultParameterInjectorPhase,
|
||||
DefaultParameterCleanerPhase,
|
||||
JsDefaultCallbackGeneratorPhase,
|
||||
VarargLoweringPhase,
|
||||
PropertiesLoweringPhase,
|
||||
InitializersLoweringPhase,
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultArgumentStubGenerator
|
||||
import org.jetbrains.kotlin.backend.common.lower.DEFAULT_DISPATCH_CALL
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true) {
|
||||
|
||||
override fun needSpecialDispatch(irFunction: IrSimpleFunction) = irFunction.isOverridableOrOverrides
|
||||
|
||||
override fun IrBlockBodyBuilder.generateHandleCall(
|
||||
handlerDeclaration: IrValueParameter,
|
||||
oldIrFunction: IrFunction,
|
||||
newIrFunction: IrFunction,
|
||||
params: MutableList<IrVariable>
|
||||
): IrExpression {
|
||||
val paramCount = oldIrFunction.valueParameters.size
|
||||
val invokeFunctionN = resolveInvoke(paramCount)
|
||||
// NOTE: currently we do not have a syntax to perform super extension call
|
||||
// but in case we have such functionality in the future the logic bellow should be fixed
|
||||
return irCall(invokeFunctionN, IrStatementOrigin.INVOKE).apply {
|
||||
dispatchReceiver = irImplicitCast(irGet(handlerDeclaration), invokeFunctionN.dispatchReceiverParameter!!.type)
|
||||
assert(newIrFunction.extensionReceiverParameter == null)
|
||||
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveInvoke(paramCount: Int): IrSimpleFunction {
|
||||
assert(paramCount > 0)
|
||||
val fqn = FqName.fromSegments(listOf("kotlin", "Function$paramCount"))
|
||||
val functionKlass = context.run { symbolTable.referenceClass(getClass(fqn)) }.owner
|
||||
return functionKlass.declarations.filterIsInstance<IrSimpleFunction>().first { it.name == Name.identifier("invoke") }
|
||||
}
|
||||
}
|
||||
|
||||
val BIND_CALL = object : IrStatementOriginImpl("BIND_CALL") {}
|
||||
|
||||
class JsDefaultCallbackGenerator(val context: JsIrBackendContext): BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
if (expression.origin != DEFAULT_DISPATCH_CALL || expression.superQualifierSymbol == null) return expression
|
||||
|
||||
val binding = buildBoundSuperCall(expression)
|
||||
|
||||
expression.putValueArgument(expression.valueArgumentsCount - 1, binding)
|
||||
|
||||
return expression
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildBoundSuperCall(irCall: IrCall): IrExpression {
|
||||
|
||||
val originalFunction = context.ir.defaultParameterDeclarationsCache.entries.first { it.value == irCall.symbol.owner }.key
|
||||
|
||||
val reference = irCall.run {
|
||||
IrFunctionReferenceImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
context.irBuiltIns.anyType,
|
||||
originalFunction.symbol,
|
||||
originalFunction.descriptor,
|
||||
0,
|
||||
BIND_CALL
|
||||
)
|
||||
}
|
||||
|
||||
return irCall.run {
|
||||
IrCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
context.irBuiltIns.anyType,
|
||||
context.intrinsics.jsBind.symbol,
|
||||
context.intrinsics.jsBind.descriptor,
|
||||
BIND_CALL,
|
||||
superQualifierSymbol
|
||||
)
|
||||
}.apply {
|
||||
putValueArgument(0, irCall.dispatchReceiver?.deepCopyWithSymbols())
|
||||
putValueArgument(1, reference)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassBackingField
|
||||
@@ -201,6 +202,20 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val fieldName = context.getNameForSymbol(field.symbol)
|
||||
JsNameRef(fieldName, arg)
|
||||
}
|
||||
|
||||
add(intrinsics.jsBind) { call: IrCall, context: JsGenerationContext ->
|
||||
val receiver = call.getValueArgument(0)!!
|
||||
val reference = call.getValueArgument(1) as IrFunctionReference
|
||||
val superClass = call.superQualifierSymbol!!
|
||||
|
||||
val jsReceiver = receiver.accept(IrElementToJsExpressionTransformer(), context)
|
||||
val functionName = context.getNameForSymbol(reference.symbol)
|
||||
val superName = context.getNameForSymbol(superClass).makeRef()
|
||||
val qPrototype = JsNameRef(functionName, prototypeOf(superName))
|
||||
val bindRef = JsNameRef(Namer.BIND_FUNCTION, qPrototype)
|
||||
|
||||
JsInvocation(bindRef, jsReceiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ object Namer {
|
||||
|
||||
val CALL_FUNCTION = "call"
|
||||
val APPLY_FUNCTION = "apply"
|
||||
val BIND_FUNCTION = "bind"
|
||||
|
||||
val SLICE_FUNCTION = "slice"
|
||||
val CONCAT_FUNCTION = "concat"
|
||||
|
||||
Reference in New Issue
Block a user