[JS IR BE] Support in callable references

* default params
 * vararg
Minor refactoring
This commit is contained in:
Roman Artemev
2018-10-27 19:32:04 +03:00
committed by romanart
parent fb709cae92
commit 12848d4eff
3 changed files with 133 additions and 117 deletions
@@ -52,6 +52,8 @@ val IrDeclaration.parentsWithSelf: Sequence<IrDeclarationParent>
val IrDeclaration.parents: Sequence<IrDeclarationParent>
get() = parentsWithSelf.drop(1)
object BOUND_VALUE_PARAMETER: IrDeclarationOriginImpl("BOUND_VALUE_PARAMETER")
class LocalDeclarationsLowering(
val context: BackendContext,
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
@@ -540,7 +542,7 @@ class LocalDeclarationsLowering(
val parameterDescriptor = WrappedValueParameterDescriptor()
val p = capturedValue.owner
IrValueParameterImpl(
p.startOffset, p.endOffset, p.origin, IrValueParameterSymbolImpl(parameterDescriptor),
p.startOffset, p.endOffset, BOUND_VALUE_PARAMETER, IrValueParameterSymbolImpl(parameterDescriptor),
suggestNameForCapturedValue(p), i, p.type, null, false, false
).also {
parameterDescriptor.bind(it)
@@ -105,11 +105,7 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
UnitMaterializationLowering(this).lower(moduleFragment)
EnumClassLowering(this).runOnFilesPostfix(moduleFragment)
EnumUsageLowering(this).lower(moduleFragment)
VarargLowering(this).lower(moduleFragment)
LateinitLowering(this, true).lower(moduleFragment)
DefaultArgumentStubGenerator(this).runOnFilesPostfix(moduleFragment)
DefaultParameterInjector(this).runOnFilesPostfix(moduleFragment)
DefaultParameterCleaner(this).runOnFilesPostfix(moduleFragment)
SharedVariablesLowering(this).runOnFilesPostfix(moduleFragment)
ReturnableBlockLowering(this).lower(moduleFragment)
LocalDelegatedPropertiesLowering().lower(moduleFragment)
@@ -117,6 +113,11 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
InnerClassesLowering(this).runOnFilesPostfix(moduleFragment)
InnerClassConstructorCallsLowering(this).runOnFilesPostfix(moduleFragment)
SuspendFunctionsLowering(this).lower(moduleFragment)
CallableReferenceLowering(this).lower(moduleFragment)
DefaultArgumentStubGenerator(this).runOnFilesPostfix(moduleFragment)
DefaultParameterInjector(this).runOnFilesPostfix(moduleFragment)
DefaultParameterCleaner(this).runOnFilesPostfix(moduleFragment)
VarargLowering(this).lower(moduleFragment)
PropertiesLowering().lower(moduleFragment)
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilesPostfix(moduleFragment)
MultipleCatchesLowering(this).lower(moduleFragment)
@@ -129,7 +130,6 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
constructorRedirectorLowering.runOnFilesPostfix(moduleFragment)
}
CallableReferenceLowering(this).lower(moduleFragment)
ClassReferenceLowering(this).lower(moduleFragment)
PrimitiveCompanionLowering(this).lower(moduleFragment)
@@ -8,28 +8,36 @@ package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.lower.BOUND_VALUE_PARAMETER
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.asString
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
data class CallableReferenceKey(
val declaration: IrFunction,
val hasDispatchReference: Boolean,
val hasExtensionReceiver: Boolean
val hasDispatchReceiver: Boolean,
val hasExtensionReceiver: Boolean,
val signature: String
)
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
@@ -37,7 +45,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_GET)
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_SET)
private val callableToGetterFunction = context.callableReferencesCache
private val callableToFactoryFunction = context.callableReferencesCache
private val newDeclarations = mutableListOf<IrDeclaration>()
private val implicitDeclarationFile = context.implicitDeclarationFile
@@ -49,7 +57,12 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
}
private fun makeCallableKey(declaration: IrFunction, reference: IrCallableReference) =
CallableReferenceKey(declaration, reference.dispatchReceiver != null, reference.extensionReceiver != null)
CallableReferenceKey(
declaration,
reference.dispatchReceiver != null,
reference.extensionReceiver != null,
reference.type.asString()
)
inner class CallableReferenceLowerTransformer : IrElementTransformerVoid() {
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
@@ -57,7 +70,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val declaration = expression.symbol.owner
if (declaration.origin == JsIrBackendContext.callableClosureOrigin) return expression
val key = makeCallableKey(declaration, expression)
val factory = callableToGetterFunction.getOrPut(key) { lowerKFunctionReference(declaration, expression) }
val factory = callableToFactoryFunction.getOrPut(key) { lowerKFunctionReference(declaration, expression) }
return redirectToFunction(expression, factory)
}
@@ -65,14 +78,14 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
expression.transformChildrenVoid(this)
val declaration = expression.getter!!.owner
val key = makeCallableKey(declaration, expression)
val factory = callableToGetterFunction.getOrPut(key) { lowerKPropertyReference(declaration, expression) }
val factory = callableToFactoryFunction.getOrPut(key) { lowerKPropertyReference(declaration, expression) }
return redirectToFunction(expression, factory)
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
expression.transformChildrenVoid(this)
val key = makeCallableKey(expression.getter.owner, expression)
val factory = callableToGetterFunction.getOrPut(key) { lowerLocalKPropertyReference(expression) }
val factory = callableToFactoryFunction.getOrPut(key) { lowerLocalKPropertyReference(expression) }
return redirectToFunction(expression, factory)
}
}
@@ -97,8 +110,8 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
}
}
private fun createFunctionClosureGetterName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KReferenceGet")
private fun createPropertyClosureGetterName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KPropertyGet")
private fun createFunctionFactoryName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KFunctionFactory")
private fun createPropertyFactoryName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KPropertyFactory")
private fun createClosureInstanceName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KReferenceClosure")
private fun createHelperFunctionName(declaration: IrDeclaration, suffix: String): String {
@@ -130,7 +143,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
else -> TODO("Unexpected declaration type")
}
private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference ): IrSimpleFunction {
private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): IrSimpleFunction {
// transform
// x = Foo::bar ->
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
@@ -145,13 +158,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
val refGetFunction = buildGetFunction(declaration, functionReference, createFunctionClosureGetterName(declaration))
val refClosureFunction = buildClosureFunction(declaration, refGetFunction, functionReference)
val factoryFunction = buildFactoryFunction(declaration, functionReference, createFunctionFactoryName(declaration))
val closureFunction = buildClosureFunction(declaration, factoryFunction, functionReference, functionReference.type.arity)
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol)
val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, closureFunction.symbol)
val irVar = JsIrBuilder.buildVar(irClosureReference.type, refGetFunction, initializer = irClosureReference)
val irVar = JsIrBuilder.buildVar(irClosureReference.type, factoryFunction, initializer = irClosureReference)
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
@@ -159,12 +172,12 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration)))
}
Pair(listOf(refClosureFunction, irVar, irSetName), irVar.symbol)
Pair(listOf(closureFunction, irVar, irSetName), irVar.symbol)
}
newDeclarations += additionalDeclarations + refGetFunction
newDeclarations += additionalDeclarations + factoryFunction
return refGetFunction
return factoryFunction
}
private fun lowerKPropertyReference(getterDeclaration: IrSimpleFunction, propertyReference: IrPropertyReference): IrSimpleFunction {
@@ -187,19 +200,20 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
// return $cache$
// }
val getterName = createPropertyClosureGetterName(getterDeclaration.correspondingProperty!!)
val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference, getterName)
val arity = propertyReference.type.arity
val factoryName = createPropertyFactoryName(getterDeclaration.correspondingProperty!!)
val factoryFunction = buildFactoryFunction(propertyReference.getter!!.owner, propertyReference, factoryName)
val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction, propertyReference) }!!
val setterFunction = propertyReference.setter?.let { buildClosureFunction(it.owner, refGetFunction, propertyReference) }
val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, factoryFunction, propertyReference, arity) }!!
val setterFunction = propertyReference.setter?.let { buildClosureFunction(it.owner, factoryFunction, propertyReference, arity + 1) }
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) {
val statements = mutableListOf<IrStatement>(getterFunction)
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType(symbolTable = context.symbolTable)
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVar = JsIrBuilder.buildVar(type, refGetFunction, initializer = irGetReference)
val irVar = JsIrBuilder.buildVar(type, factoryFunction, initializer = irGetReference)
statements += irVar
@@ -228,8 +242,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, callableNameConst)
putValueArgument(
2,
JsIrBuilder.buildString(
2, JsIrBuilder.buildString(
context.irBuiltIns.stringType,
getReferenceName(getterDeclaration.correspondingProperty!!)
)
@@ -239,9 +252,9 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
Pair(statements, irVar.symbol)
}
newDeclarations += additionalDeclarations + refGetFunction
newDeclarations += additionalDeclarations + factoryFunction
return refGetFunction
return factoryFunction
}
private fun lowerLocalKPropertyReference(propertyReference: IrLocalDelegatedPropertyReference): IrSimpleFunction {
@@ -259,18 +272,19 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
// return $cache$
// }
val arity = propertyReference.type.arity
val declaration = propertyReference.delegate.owner
val getterName = createPropertyClosureGetterName(declaration)
val refGetFunction = buildGetFunction(propertyReference.getter.owner, propertyReference, getterName)
val getterFunction = buildClosureFunction(context.irBuiltIns.throwIseFun, refGetFunction, propertyReference)
val factoryName = createPropertyFactoryName(declaration)
val factoryFunction = buildFactoryFunction(propertyReference.getter.owner, propertyReference, factoryName)
val closureFunction = buildClosureFunction(context.irBuiltIns.throwIseFun, factoryFunction, propertyReference, arity)
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val statements = mutableListOf<IrStatement>(getterFunction)
val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) {
val statements = mutableListOf<IrStatement>(closureFunction)
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val getterFunctionType = context.builtIns.getFunction(closureFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType(symbolTable = context.symbolTable)
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVar = JsIrBuilder.buildVar(type, refGetFunction, initializer = irGetReference)
val irGetReference = JsIrBuilder.buildFunctionReference(type, closureFunction.symbol)
val irVar = JsIrBuilder.buildVar(type, factoryFunction, initializer = irGetReference)
val irVarSymbol = irVar.symbol
statements += irVar
@@ -290,13 +304,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
Pair(statements, irVarSymbol)
}
newDeclarations += additionalDeclarations + refGetFunction
newDeclarations += additionalDeclarations + factoryFunction
return refGetFunction
return factoryFunction
}
private fun generateGetterBodyWithGuard(
getterFunction: IrSimpleFunction,
private fun generateFactoryBodyWithGuard(
factoryFunction: IrSimpleFunction,
builder: () -> Pair<List<IrStatement>, IrValueSymbol>
): List<IrDeclaration> {
@@ -304,16 +318,16 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val statements = mutableListOf<IrStatement>()
val returnValue: IrExpression
val returnStatements: List<IrDeclaration>
if (getterFunction.valueParameters.isEmpty()) {
if (factoryFunction.valueParameters.isEmpty()) {
// compose cache for 'direct' closure
// if ($cache$ === null) {
// $cache$ = <body>
// }
//
val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
val type = getterFunction.returnType
val cacheName = "${factoryFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
val type = factoryFunction.returnType
val irNull = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
val cacheVar = JsIrBuilder.buildVar(type, getterFunction.parent, cacheName, true, initializer = irNull)
val cacheVar = JsIrBuilder.buildVar(type, factoryFunction.parent, cacheName, true, initializer = irNull)
val irCacheValue = JsIrBuilder.buildGetValue(cacheVar.symbol)
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqSymbol).apply {
@@ -337,17 +351,18 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
returnStatements = emptyList()
}
statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue, context.irBuiltIns.nothingType)
statements += JsIrBuilder.buildReturn(factoryFunction.symbol, returnValue, context.irBuiltIns.nothingType)
getterFunction.body = JsIrBuilder.buildBlockBody(statements)
factoryFunction.body = JsIrBuilder.buildBlockBody(statements)
return returnStatements
}
private fun generateSignatureForClosure(
callable: IrFunction,
getter: IrFunction,
factory: IrFunction,
closure: IrSimpleFunction,
reference: IrCallableReference
reference: IrCallableReference,
arity: Int
): List<IrValueParameter> {
val result = mutableListOf<IrValueParameter>()
@@ -357,23 +372,24 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
* }
*
* val d = D()
* val reference = d::foo <= captures dispatch receiver
* val reference = d::foo <= binds dispatch receiver
*
* is translated into
*
* function foo_get(d) { <= getter signature(d)
* function foo_get(d) { <= factory signature(d)
* return function (a, b, c) { <= result signature (a, b, c)
* return d.foo(a, b, c)
* }
* }
*/
var capturedParams = getter.valueParameters.size
var capturedParams = factory.valueParameters.size
val functionSignature = reference.type.arguments.dropLast(1).map { (it as IrTypeProjection).type }.toList()
callable.dispatchReceiverParameter?.let { dispatch ->
if (reference.dispatchReceiver == null) {
result.add(JsIrBuilder.buildValueParameter(dispatch.name, result.size, dispatch.type).also { it.parent = closure })
} else {
// do not consider implicit receiver in result signature if it was captured
// do not add dispatch receiver in result signature if it is bound
capturedParams--
}
}
@@ -387,55 +403,38 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
}
}
// pass through value parameters
for (i in capturedParams until callable.valueParameters.size) {
val param = callable.valueParameters[i]
val paramName = param.name.run { if (!isSpecial) identifier else "p$i" }
result += JsIrBuilder.buildValueParameter(paramName, result.size, param.type).also { it.parent = closure }
for ((index, param) in (result.size until arity).zip(callable.valueParameters.drop(capturedParams))) {
val type = if (index < functionSignature.size) functionSignature[index] else param.type
val paramName = param.name.run { if (!isSpecial) identifier else "p$index" }
result += JsIrBuilder.buildValueParameter(paramName, result.size, type).also { it.parent = closure }
}
return result
}
private fun buildGetFunction(declaration: IrFunction, reference: IrCallableReference, getterName: String): IrSimpleFunction {
val callableType = reference.type
var kFunctionValueParamsCount = (callableType as? IrSimpleType)?.arguments?.size?.minus(1) ?: 0
if (declaration.dispatchReceiverParameter != null && reference.dispatchReceiver == null) {
kFunctionValueParamsCount--
}
if (declaration.extensionReceiverParameter != null && reference.extensionReceiver == null) {
kFunctionValueParamsCount--
}
assert(kFunctionValueParamsCount >= 0)
private fun buildFactoryFunction(declaration: IrFunction, reference: IrCallableReference, getterName: String): IrSimpleFunction {
// The `getter` function takes only closure parameters
val receivers = mutableListOf<IrValueParameter>()
if (reference.dispatchReceiver != null) {
if (declaration.dispatchReceiverParameter != null) {
receivers += declaration.dispatchReceiverParameter!!
}
}
if (reference.extensionReceiver != null) {
if (declaration.extensionReceiverParameter != null) {
receivers += declaration.extensionReceiverParameter!!
}
reference.dispatchReceiver?.let {
// in case outer `this` for inner constructors
receivers += declaration.dispatchReceiverParameter ?: declaration.valueParameters[0]
}
val getterValueParameters = receivers + declaration.valueParameters.dropLast(kFunctionValueParamsCount)
reference.extensionReceiver?.let {
receivers += declaration.extensionReceiverParameter!!
}
val boundValueParameters = receivers + declaration.valueParameters.filter { it.origin == BOUND_VALUE_PARAMETER }
val refGetDeclaration = JsIrBuilder.buildFunction(getterName, declaration.visibility)
val factoryDeclaration = JsIrBuilder.buildFunction(getterName, declaration.visibility)
refGetDeclaration.parent = implicitDeclarationFile
refGetDeclaration.returnType = callableType
factoryDeclaration.parent = implicitDeclarationFile
factoryDeclaration.returnType = reference.type
for ((i, p) in getterValueParameters.withIndex()) {
for ((i, p) in boundValueParameters.withIndex()) {
val descriptor = WrappedValueParameterDescriptor()
refGetDeclaration.valueParameters += IrValueParameterImpl(
factoryDeclaration.valueParameters += IrValueParameterImpl(
p.startOffset,
p.endOffset,
p.origin,
@@ -448,7 +447,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
p.isNoinline
).also {
descriptor.bind(it)
it.parent = refGetDeclaration
it.parent = factoryDeclaration
}
}
@@ -457,7 +456,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
for (t in typeParameters) {
val descriptor = WrappedTypeParameterDescriptor()
refGetDeclaration.typeParameters += IrTypeParameterImpl(
factoryDeclaration.typeParameters += IrTypeParameterImpl(
t.startOffset,
t.endOffset,
t.origin,
@@ -468,62 +467,77 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
t.variance
).also {
descriptor.bind(it)
it.parent = refGetDeclaration
it.parent = factoryDeclaration
}
}
return refGetDeclaration
return factoryDeclaration
}
private val IrType.arguments get() = (this as? IrSimpleType)?.arguments ?: emptyList()
private val IrType.arity get() = arguments.size - 1
private fun buildClosureFunction(
declaration: IrFunction,
refGetFunction: IrSimpleFunction,
reference: IrCallableReference
factoryFunction: IrSimpleFunction,
reference: IrCallableReference,
arity: Int
): IrFunction {
val closureName = createClosureInstanceName(declaration)
val refClosureDeclaration =
val closureFunction =
JsIrBuilder.buildFunction(closureName, Visibilities.LOCAL, origin = JsIrBackendContext.callableClosureOrigin)
.also { it.parent = refGetFunction }
.also { it.parent = factoryFunction }
// the params which are passed to closure
val closureParamDeclarations = generateSignatureForClosure(declaration, refGetFunction, refClosureDeclaration, reference)
val closureParamSymbols = closureParamDeclarations.map { it.symbol }
val boundParamSymbols = factoryFunction.valueParameters.map { it.symbol }
val unboundParamDeclarations = generateSignatureForClosure(declaration, factoryFunction, closureFunction, reference, arity)
val unboundParamSymbols = unboundParamDeclarations.map { it.symbol }
val returnType = declaration.returnType
refClosureDeclaration.valueParameters += closureParamDeclarations
refClosureDeclaration.returnType = returnType
closureFunction.valueParameters += unboundParamDeclarations
closureFunction.returnType = returnType
val irCall = JsIrBuilder.buildCall(declaration.symbol, type = returnType)
val callTarget = context.ir.defaultParameterDeclarationsCache[declaration] ?: declaration
val irCall = JsIrBuilder.buildCall(callTarget.symbol, type = returnType)
var cp = 0
var gp = 0
if (declaration.dispatchReceiverParameter != null) {
if (callTarget.dispatchReceiverParameter != null) {
val dispatchReceiverDeclaration =
if (reference.dispatchReceiver != null) refGetFunction.valueParameters[gp++].symbol else closureParamSymbols[cp++]
if (reference.dispatchReceiver != null) boundParamSymbols[gp++] else unboundParamSymbols[cp++]
irCall.dispatchReceiver = JsIrBuilder.buildGetValue(dispatchReceiverDeclaration)
}
if (declaration.extensionReceiverParameter != null) {
if (callTarget.extensionReceiverParameter != null) {
val extensionReceiverDeclaration =
if (reference.extensionReceiver != null) refGetFunction.valueParameters[gp++].symbol else closureParamSymbols[cp++]
if (reference.extensionReceiver != null) boundParamSymbols[gp++] else unboundParamSymbols[cp++]
irCall.extensionReceiver = JsIrBuilder.buildGetValue(extensionReceiverDeclaration)
}
var j = 0
for (i in gp until refGetFunction.valueParameters.size) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(refGetFunction.valueParameters[i].symbol))
for (i in gp until boundParamSymbols.size) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(boundParamSymbols[i]))
}
for (i in cp until closureParamSymbols.size) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i]))
for (i in cp until unboundParamSymbols.size) {
val closureParam = unboundParamSymbols[i].owner
val value = JsIrBuilder.buildGetValue(unboundParamSymbols[i])
val parameter = callTarget.valueParameters[j]
val argument = if (parameter.varargElementType?.let { closureParam.type.isSubtypeOf(it) } == true) {
// fun foo(x: X, y: vararg Y): Z
// val r: (X, Y) -> Z = ::foo
IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type, parameter.varargElementType!!, listOf(value))
} else value
irCall.putValueArgument(j++, argument)
}
val irClosureReturn = JsIrBuilder.buildReturn(refClosureDeclaration.symbol, irCall, context.irBuiltIns.nothingType)
val irClosureReturn = JsIrBuilder.buildReturn(closureFunction.symbol, irCall, context.irBuiltIns.nothingType)
refClosureDeclaration.body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
closureFunction.body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
return refClosureDeclaration
return closureFunction
}
}