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