diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index ce6eca651a4..168f47cd3ca 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -52,6 +52,8 @@ val IrDeclaration.parentsWithSelf: Sequence val IrDeclaration.parents: Sequence 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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 11fe9591939..1b4c3d3e508 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt index 0407b6e994c..bacdf4bc601 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt @@ -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() 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 { @@ -145,13 +158,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP // KFunctionN, 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(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(getterFunction) + val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) { + val statements = mutableListOf(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, IrValueSymbol> ): List { @@ -304,16 +318,16 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP val statements = mutableListOf() val returnValue: IrExpression val returnStatements: List - if (getterFunction.valueParameters.isEmpty()) { + if (factoryFunction.valueParameters.isEmpty()) { // compose cache for 'direct' closure // if ($cache$ === null) { // $cache$ = // } // - 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 { val result = mutableListOf() @@ -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() - 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 } } \ No newline at end of file