JVM_IR: make CallableReferenceLowering a bit shorter
This commit is contained in:
+86
-222
@@ -31,21 +31,15 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
|||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
|
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
|
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isPrimaryInlineClassConstructor
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
|
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
@@ -88,13 +82,11 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
if (callee.isInlineFunctionCall(context)) {
|
if (callee.isInlineFunctionCall(context)) {
|
||||||
//TODO: more wise filtering
|
//TODO: more wise filtering
|
||||||
callee.valueParameters.forEach { valueParameter ->
|
for (valueParameter in callee.valueParameters) {
|
||||||
if (valueParameter.isInlineParameter()) {
|
if (valueParameter.isInlineParameter()) {
|
||||||
expression.getValueArgument(valueParameter.index)?.let {
|
expression.getValueArgument(valueParameter.index)?.let {
|
||||||
if (isInlineIrExpression(it)) {
|
if (isInlineIrExpression(it)) {
|
||||||
(it as IrBlock).statements.filterIsInstance<IrFunctionReference>().forEach { reference ->
|
inlineLambdaReferences += (it as IrBlock).statements.filterIsInstance<IrFunctionReference>()
|
||||||
inlineLambdaReferences.add(reference)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +95,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
|
|
||||||
val argumentsCount = expression.valueArgumentsCount
|
val argumentsCount = expression.valueArgumentsCount
|
||||||
// Change calls to FunctionN with large N to varargs calls.
|
// Change calls to FunctionN with large N to varargs calls.
|
||||||
val newCall = if (argumentsCount > MAX_ARGCOUNT_WITHOUT_VARARG &&
|
val newCall = if (argumentsCount >= FunctionInvokeDescriptor.Factory.BIG_ARITY &&
|
||||||
callee.parentAsClass.defaultType.isFunctionOrKFunction()
|
callee.parentAsClass.defaultType.isFunctionOrKFunction()
|
||||||
) {
|
) {
|
||||||
val vararg = IrVarargImpl(
|
val vararg = IrVarargImpl(
|
||||||
@@ -145,8 +137,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
|
|
||||||
val currentDeclarationParent = allScopes.map { it.irElement }.last { it is IrDeclarationParent } as IrDeclarationParent
|
val currentDeclarationParent = allScopes.map { it.irElement }.last { it is IrDeclarationParent } as IrDeclarationParent
|
||||||
val loweredFunctionReference = FunctionReferenceBuilder(currentDeclarationParent, expression).build()
|
val loweredFunctionReference = FunctionReferenceBuilder(currentDeclarationParent, expression).build()
|
||||||
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).irBlock(expression) {
|
||||||
return irBuilder.irBlock(expression) {
|
|
||||||
+loweredFunctionReference.functionReferenceClass
|
+loweredFunctionReference.functionReferenceClass
|
||||||
+irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply {
|
+irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply {
|
||||||
expression.getArguments().forEachIndexed { index, argument ->
|
expression.getArguments().forEachIndexed { index, argument ->
|
||||||
@@ -158,6 +149,14 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val arrayGetFun by lazy {
|
||||||
|
context.irBuiltIns.arrayClass.owner.functions.find { it.name.asString() == "get" }!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private val arraySizeProperty by lazy {
|
||||||
|
context.irBuiltIns.arrayClass.owner.properties.find { it.name.toString() == "size" }!!
|
||||||
|
}
|
||||||
|
|
||||||
private class BuiltFunctionReference(
|
private class BuiltFunctionReference(
|
||||||
val functionReferenceClass: IrClass,
|
val functionReferenceClass: IrClass,
|
||||||
val functionReferenceConstructor: IrConstructor
|
val functionReferenceConstructor: IrConstructor
|
||||||
@@ -182,7 +181,6 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var functionReferenceClass: IrClass
|
private lateinit var functionReferenceClass: IrClass
|
||||||
private lateinit var functionReferenceThis: IrValueParameterSymbol
|
|
||||||
private lateinit var argumentToFieldMap: Map<IrValueParameter, IrField>
|
private lateinit var argumentToFieldMap: Map<IrValueParameter, IrField>
|
||||||
|
|
||||||
private val isLambda = irFunctionReference.origin == IrStatementOrigin.LAMBDA
|
private val isLambda = irFunctionReference.origin == IrStatementOrigin.LAMBDA
|
||||||
@@ -196,13 +194,12 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
val functionReferenceClassSuperTypes: MutableList<IrType> = mutableListOf(functionReferenceOrLambda.owner.defaultType)
|
val functionReferenceClassSuperTypes: MutableList<IrType> = mutableListOf(functionReferenceOrLambda.owner.defaultType)
|
||||||
|
|
||||||
val numberOfParameters = unboundCalleeParameters.size
|
val numberOfParameters = unboundCalleeParameters.size
|
||||||
useVararg = (numberOfParameters > MAX_ARGCOUNT_WITHOUT_VARARG)
|
useVararg = (numberOfParameters >= FunctionInvokeDescriptor.Factory.BIG_ARITY)
|
||||||
|
|
||||||
val functionClassSymbol = if (useVararg)
|
val functionClassSymbol = if (useVararg)
|
||||||
context.ir.symbols.functionN
|
context.ir.symbols.functionN
|
||||||
else
|
else
|
||||||
context.ir.symbols.getJvmFunctionClass(numberOfParameters)
|
context.ir.symbols.getJvmFunctionClass(numberOfParameters)
|
||||||
val functionClass = functionClassSymbol.owner
|
|
||||||
val functionParameterTypes = unboundCalleeParameters.map { it.type }
|
val functionParameterTypes = unboundCalleeParameters.map { it.type }
|
||||||
val functionClassTypeParameters = if (useVararg)
|
val functionClassTypeParameters = if (useVararg)
|
||||||
listOf(returnType)
|
listOf(returnType)
|
||||||
@@ -236,88 +233,53 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
setSourceRange(irFunctionReference)
|
setSourceRange(irFunctionReference)
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||||
name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName
|
name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName
|
||||||
kind = ClassKind.CLASS
|
|
||||||
visibility = Visibilities.PUBLIC
|
|
||||||
modality = Modality.FINAL
|
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = referenceParent
|
parent = referenceParent
|
||||||
superTypes.addAll(functionReferenceClassSuperTypes)
|
superTypes.addAll(functionReferenceClassSuperTypes)
|
||||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
|
|
||||||
|
|
||||||
argumentToFieldMap = boundCalleeParameters.associate {
|
argumentToFieldMap = boundCalleeParameters.associate {
|
||||||
it to buildField(it.name.safeName(), it.type)
|
it to buildField(it.name.safeName(), it.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
val constructor = createConstructor()
|
val constructor = createConstructor()
|
||||||
functionReferenceClass.declarations.add(constructor)
|
createInvokeMethod(functionClassSymbol.owner.functions.find { it.name.asString() == "invoke" }!!)
|
||||||
|
|
||||||
val superInvokeFunction = functionClass.functions.find { it.name.asString() == "invoke" }!!
|
|
||||||
val invokeMethod = createInvokeMethod(superInvokeFunction)
|
|
||||||
functionReferenceClass.declarations.add(invokeMethod)
|
|
||||||
|
|
||||||
if (!isLambda) {
|
if (!isLambda) {
|
||||||
val getSignatureMethod =
|
createGetSignatureMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getSignature"}!!)
|
||||||
createGetSignatureMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getSignature"}!!)
|
createGetNameMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getName" }!!)
|
||||||
val getNameMethod =
|
createGetOwnerMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getOwner" }!!)
|
||||||
createGetNameMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getName" }!!)
|
if (suspendFunctionClass != null) {
|
||||||
val getOwnerMethod =
|
createInvokeMethod(suspendFunctionClass.functions.find { it.name.asString() == "invoke" }!!)
|
||||||
createGetOwnerMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getOwner" }!!)
|
}
|
||||||
|
|
||||||
val suspendInvokeMethod =
|
|
||||||
if (suspendFunctionClass != null) {
|
|
||||||
val suspendInvokeFunction =
|
|
||||||
suspendFunctionClass.functions.find { it.name.asString() == "invoke" }!!
|
|
||||||
createInvokeMethod(suspendInvokeFunction)
|
|
||||||
} else null
|
|
||||||
|
|
||||||
functionReferenceClass.declarations.add(getSignatureMethod)
|
|
||||||
functionReferenceClass.declarations.add(getNameMethod)
|
|
||||||
functionReferenceClass.declarations.add(getOwnerMethod)
|
|
||||||
suspendInvokeMethod?.let { functionReferenceClass.declarations.add(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return BuiltFunctionReference(functionReferenceClass, constructor)
|
return BuiltFunctionReference(functionReferenceClass, constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createConstructor(): IrConstructor =
|
private fun createConstructor(): IrConstructor =
|
||||||
buildConstructor {
|
functionReferenceClass.addConstructor {
|
||||||
setSourceRange(irFunctionReference)
|
setSourceRange(irFunctionReference)
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||||
visibility = Visibilities.PUBLIC
|
visibility = Visibilities.PUBLIC
|
||||||
returnType = functionReferenceClass.defaultType
|
returnType = functionReferenceClass.defaultType
|
||||||
isPrimary = true
|
isPrimary = true
|
||||||
}.apply {
|
}.apply {
|
||||||
val constructor = this
|
for (param in boundCalleeParameters) {
|
||||||
parent = functionReferenceClass
|
valueParameters += param.copyTo(
|
||||||
|
this,
|
||||||
val boundArgsSet = boundCalleeParameters.toSet()
|
index = valueParameters.size,
|
||||||
for (param in callee.explicitParameters) {
|
type = param.type.substitute(typeArgumentsMap)
|
||||||
if (param in boundArgsSet) {
|
)
|
||||||
val newParam = param.copyTo(
|
|
||||||
constructor,
|
|
||||||
index = valueParameters.size,
|
|
||||||
type = param.type.substitute(typeArgumentsMap)
|
|
||||||
)
|
|
||||||
valueParameters.add(newParam)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val kFunctionRefConstructorSymbol =
|
val kFunctionRefConstructorSymbol =
|
||||||
functionReferenceOrLambda.constructors.filter { it.owner.valueParameters.size == if (isLambda) 1 else 2 }.single()
|
functionReferenceOrLambda.constructors.filter { it.owner.valueParameters.size == if (isLambda) 1 else 2 }.single()
|
||||||
|
|
||||||
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
|
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||||
body = irBuilder.irBlockBody {
|
+irDelegatingConstructorCall(kFunctionRefConstructorSymbol.owner).apply {
|
||||||
+IrDelegatingConstructorCallImpl(
|
putValueArgument(0, irInt(unboundCalleeParameters.size))
|
||||||
startOffset, endOffset, context.irBuiltIns.unitType,
|
|
||||||
kFunctionRefConstructorSymbol, kFunctionRefConstructorSymbol.descriptor
|
|
||||||
).apply {
|
|
||||||
val const =
|
|
||||||
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, unboundCalleeParameters.size)
|
|
||||||
putValueArgument(0, const)
|
|
||||||
|
|
||||||
if (!isLambda) {
|
if (!isLambda) {
|
||||||
val irReceiver = valueParameters.firstOrNull()
|
val irReceiver = valueParameters.firstOrNull()
|
||||||
val receiver = boundCalleeParameters.singleOrNull()
|
val receiver = boundCalleeParameters.singleOrNull()
|
||||||
@@ -333,7 +295,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
//TODO don't write receiver again: use it from base class
|
//TODO don't write receiver again: use it from base class
|
||||||
boundCalleeParameters.forEachIndexed { index, it ->
|
boundCalleeParameters.forEachIndexed { index, it ->
|
||||||
+irSetField(
|
+irSetField(
|
||||||
irGet(functionReferenceThis.owner),
|
irGet(functionReferenceClass.thisReceiver!!),
|
||||||
argumentToFieldMap[it]!!,
|
argumentToFieldMap[it]!!,
|
||||||
irGet(valueParameters[index])
|
irGet(valueParameters[index])
|
||||||
)
|
)
|
||||||
@@ -342,61 +304,27 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.invokeInlineClassConstructor(irConstructor: IrConstructor): IrBody {
|
|
||||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
|
||||||
val param = irConstructor.valueParameters[0].copyTo(this)
|
|
||||||
valueParameters.add(param)
|
|
||||||
val from = irConstructor.valueParameters[0].type
|
|
||||||
val to = irConstructor.returnType
|
|
||||||
val call = irBuilder.irCall(context.ir.symbols.unsafeCoerceIntrinsicSymbol, to, listOf(from, to)).apply {
|
|
||||||
putValueArgument(0, irBuilder.irGet(param))
|
|
||||||
}
|
|
||||||
return irBuilder.irExprBody(call)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
|
private fun createInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
|
||||||
buildFun {
|
buildOverride(superFunction, callee.returnType).apply {
|
||||||
setSourceRange(irFunctionReference)
|
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
|
||||||
name = Name.identifier("invoke")
|
|
||||||
visibility = Visibilities.PUBLIC
|
|
||||||
returnType = callee.returnType
|
|
||||||
isSuspend = superFunction.isSuspend
|
|
||||||
}.apply {
|
|
||||||
val function = this
|
|
||||||
parent = functionReferenceClass
|
|
||||||
overriddenSymbols.add(superFunction.symbol)
|
|
||||||
annotations.addAll(callee.annotations)
|
annotations.addAll(callee.annotations)
|
||||||
|
|
||||||
dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function)
|
|
||||||
|
|
||||||
if (callee.isPrimaryInlineClassConstructor) {
|
|
||||||
body = invokeInlineClassConstructor(callee as IrConstructor)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
val unboundArgsSet = unboundCalleeParameters.toSet()
|
val unboundArgsSet = unboundCalleeParameters.toSet()
|
||||||
if (useVararg) {
|
if (useVararg) {
|
||||||
valueParameters.add(superFunction.valueParameters[0].copyTo(function))
|
valueParameters.add(superFunction.valueParameters[0].copyTo(this))
|
||||||
} else {
|
} else {
|
||||||
for (param in callee.explicitParameters) {
|
for (param in unboundCalleeParameters) {
|
||||||
if (param in unboundArgsSet) {
|
valueParameters += param.copyTo(
|
||||||
val newParam = param.copyTo(
|
this,
|
||||||
function,
|
index = valueParameters.size,
|
||||||
index = valueParameters.size,
|
type = param.type.substitute(typeArgumentsMap)
|
||||||
type = param.type.substitute(typeArgumentsMap)
|
)
|
||||||
)
|
|
||||||
valueParameters.add(newParam)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
|
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
||||||
val arrayGetFun = context.irBuiltIns.arrayClass.owner.functions.find { it.name.asString() == "get" }!!
|
|
||||||
if (useVararg) {
|
if (useVararg) {
|
||||||
val varargParam = valueParameters.single()
|
val varargParam = valueParameters.single()
|
||||||
val arraySizeProperty = context.irBuiltIns.arrayClass.owner.properties.find { it.name.toString() == "size" }!!
|
|
||||||
+irIfThen(
|
+irIfThen(
|
||||||
irNotEquals(
|
irNotEquals(
|
||||||
irCall(arraySizeProperty.getter!!).apply {
|
irCall(arraySizeProperty.getter!!).apply {
|
||||||
@@ -422,11 +350,12 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
!unboundArgsSet.contains(parameter) ->
|
!unboundArgsSet.contains(parameter) ->
|
||||||
// Bound parameter - read from field.
|
// Bound parameter - read from field.
|
||||||
irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!)
|
irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!)
|
||||||
function.isSuspend && unboundIndex == valueParameters.size ->
|
|
||||||
|
isSuspend && unboundIndex == valueParameters.size ->
|
||||||
// For suspend functions the last argument is continuation and it is implicit.
|
// For suspend functions the last argument is continuation and it is implicit.
|
||||||
|
// irCall(getContinuationSymbol, listOf(ourSymbol.descriptor.returnType!!))
|
||||||
TODO()
|
TODO()
|
||||||
// irCall(getContinuationSymbol,
|
|
||||||
// listOf(ourSymbol.descriptor.returnType!!))
|
|
||||||
useVararg -> {
|
useVararg -> {
|
||||||
val type = parameter.type
|
val type = parameter.type
|
||||||
val varargParam = valueParameters.single()
|
val varargParam = valueParameters.single()
|
||||||
@@ -446,14 +375,12 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
+irGet(argValue)
|
+irGet(argValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
|
else ->
|
||||||
irGet(valueParameters[unboundIndex++])
|
irGet(valueParameters[unboundIndex++])
|
||||||
}
|
|
||||||
}
|
}
|
||||||
putArgument(callee, parameter, argument)
|
putArgument(callee, parameter, argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!useVararg) assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -461,113 +388,56 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildField(fieldName: Name, fieldType: IrType): IrField =
|
private fun buildField(fieldName: Name, fieldType: IrType): IrField =
|
||||||
buildField {
|
functionReferenceClass.addField {
|
||||||
setSourceRange(irFunctionReference)
|
setSourceRange(irFunctionReference)
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||||
name = fieldName
|
name = fieldName
|
||||||
type = fieldType
|
type = fieldType
|
||||||
visibility = JavaVisibilities.PACKAGE_VISIBILITY
|
visibility = JavaVisibilities.PACKAGE_VISIBILITY
|
||||||
isFinal = true
|
isFinal = true
|
||||||
}.also {
|
|
||||||
it.parent = functionReferenceClass
|
|
||||||
functionReferenceClass.declarations.add(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
|
private fun buildOverride(superFunction: IrSimpleFunction, newReturnType: IrType = superFunction.returnType): IrSimpleFunction =
|
||||||
buildFun {
|
functionReferenceClass.addFunction {
|
||||||
setSourceRange(irFunctionReference)
|
setSourceRange(irFunctionReference)
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
origin = functionReferenceClass.origin
|
||||||
name = Name.identifier("getSignature")
|
name = superFunction.name
|
||||||
returnType = superFunction.returnType
|
returnType = newReturnType
|
||||||
visibility = superFunction.visibility
|
visibility = superFunction.visibility
|
||||||
modality = superFunction.modality
|
isSuspend = superFunction.isSuspend
|
||||||
}.apply {
|
}.apply {
|
||||||
val function = this
|
overriddenSymbols += superFunction.symbol
|
||||||
parent = functionReferenceClass
|
dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(this)
|
||||||
overriddenSymbols.add(superFunction.symbol)
|
|
||||||
dispatchReceiverParameter = functionReferenceClass.thisReceiver!!.copyTo(function)
|
|
||||||
|
|
||||||
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
|
|
||||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
|
||||||
+irReturn(
|
|
||||||
IrConstImpl.string(
|
|
||||||
-1, -1, context.irBuiltIns.stringType,
|
|
||||||
PropertyReferenceCodegen.getSignatureString(
|
|
||||||
irFunctionReference.symbol.descriptor, this@CallableReferenceLowering.context.state
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrFunction.originalName: Name
|
private val IrFunction.originalName: Name
|
||||||
get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name
|
get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name
|
||||||
|
|
||||||
private fun createGetNameMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
|
private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
|
||||||
buildFun {
|
val state = context.state
|
||||||
setSourceRange(irFunctionReference)
|
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
// TODO do not use descriptors
|
||||||
name = Name.identifier("getName")
|
irExprBody(irString(PropertyReferenceCodegen.getSignatureString(irFunctionReference.symbol.descriptor, state)))
|
||||||
returnType = superFunction.returnType
|
|
||||||
visibility = superFunction.visibility
|
|
||||||
modality = superFunction.modality
|
|
||||||
}.apply {
|
|
||||||
val function = this
|
|
||||||
parent = functionReferenceClass
|
|
||||||
overriddenSymbols.add(superFunction.symbol)
|
|
||||||
dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function)
|
|
||||||
|
|
||||||
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
|
|
||||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
|
||||||
+irReturn(
|
|
||||||
IrConstImpl.string(-1, -1, context.irBuiltIns.stringType, callee.originalName.asString())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
|
private fun createGetNameMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
|
||||||
buildFun {
|
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||||
setSourceRange(functionReferenceClass)
|
irExprBody(irString(callee.originalName.asString()))
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
|
||||||
name = Name.identifier("getOwner")
|
|
||||||
returnType = superFunction.returnType
|
|
||||||
visibility = superFunction.visibility
|
|
||||||
modality = superFunction.modality
|
|
||||||
}.apply {
|
|
||||||
val function = this
|
|
||||||
parent = functionReferenceClass
|
|
||||||
overriddenSymbols.add(superFunction.symbol)
|
|
||||||
dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function)
|
|
||||||
|
|
||||||
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
|
|
||||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
|
||||||
+irReturn(
|
|
||||||
generateCallableReferenceDeclarationContainer()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun IrBuilderWithScope.generateCallableReferenceDeclarationContainer(): IrExpression {
|
private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
|
||||||
val globalContext = this@CallableReferenceLowering.context
|
val globalContext = context
|
||||||
val state = globalContext.state
|
val state = globalContext.state
|
||||||
val irContainer = callee.parent
|
val irContainer = callee.parent
|
||||||
|
|
||||||
val isContainerPackage =
|
val isContainerPackage =
|
||||||
((irContainer as? IrClass)?.origin == IrDeclarationOrigin.FILE_CLASS) || irContainer is IrPackageFragment
|
((irContainer as? IrClass)?.origin == IrDeclarationOrigin.FILE_CLASS) || irContainer is IrPackageFragment
|
||||||
|
|
||||||
val type = when {
|
val type = when (irContainer) {
|
||||||
irContainer is IrClass ->
|
// TODO: getDefaultType() here is wrong and won't work for arrays
|
||||||
// TODO: getDefaultType() here is wrong and won't work for arrays
|
is IrClass -> state.typeMapper.mapType(irContainer.defaultType.toKotlinType())
|
||||||
state.typeMapper.mapType(irContainer.defaultType.toKotlinType())
|
|
||||||
|
|
||||||
// // TODO: this code is only needed for property references, which are not yet supported.
|
|
||||||
// descriptor is VariableDescriptorWithAccessors -> {
|
|
||||||
// assert(false) { "VariableDescriptorWithAccessors" }
|
|
||||||
// globalContext.state.bindingContext.get(
|
|
||||||
// CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, descriptor
|
|
||||||
// )!!
|
|
||||||
// }
|
|
||||||
|
|
||||||
else -> state.typeMapper.mapOwner(callee.descriptor)
|
else -> state.typeMapper.mapOwner(callee.descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,22 +450,20 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
CrIrType(type)
|
CrIrType(type)
|
||||||
)
|
)
|
||||||
|
|
||||||
return if (isContainerPackage) {
|
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||||
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
|
irExprBody(if (isContainerPackage) {
|
||||||
// but there's no nice API to obtain that name here yet
|
irCall(globalContext.ir.symbols.getOrCreateKotlinPackage).apply {
|
||||||
// TODO: write the referenced declaration's module name and use it in reflection
|
putValueArgument(0, clazzRef)
|
||||||
val module = IrConstImpl.string(
|
// Note that this name is not used in reflection. There should be the name of the referenced declaration's
|
||||||
-1, -1, globalContext.irBuiltIns.stringType,
|
// module instead, but there's no nice API to obtain that name here yet
|
||||||
state.moduleName
|
// TODO: write the referenced declaration's module name and use it in reflection
|
||||||
)
|
putValueArgument(1, irString(state.moduleName))
|
||||||
irCall(globalContext.ir.symbols.getOrCreateKotlinPackage).apply {
|
}
|
||||||
putValueArgument(0, clazzRef)
|
} else {
|
||||||
putValueArgument(1, module)
|
irCall(globalContext.ir.symbols.getOrCreateKotlinClass).apply {
|
||||||
}
|
putValueArgument(0, clazzRef)
|
||||||
} else {
|
}
|
||||||
irCall(globalContext.ir.symbols.getOrCreateKotlinClass).apply {
|
})
|
||||||
putValueArgument(0, clazzRef)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -607,8 +475,4 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
Name.identifier("$${name.substring(1, name.length - 1)}")
|
Name.identifier("$${name.substring(1, name.length - 1)}")
|
||||||
} else this
|
} else this
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val MAX_ARGCOUNT_WITHOUT_VARARG = 22
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
@@ -44,7 +45,7 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl
|
|||||||
val invokeFunctions = irClass.filterDeclarations<IrSimpleFunction> { it.name.toString() == "invoke" }
|
val invokeFunctions = irClass.filterDeclarations<IrSimpleFunction> { it.name.toString() == "invoke" }
|
||||||
if (invokeFunctions.isEmpty() ||
|
if (invokeFunctions.isEmpty() ||
|
||||||
invokeFunctions.any { it.valueParameters.size > 0 && it.valueParameters.last().varargElementType != null } ||
|
invokeFunctions.any { it.valueParameters.size > 0 && it.valueParameters.last().varargElementType != null } ||
|
||||||
invokeFunctions.all { it.valueParameters.size + (if (it.extensionReceiverParameter != null) 1 else 0) <= CallableReferenceLowering.MAX_ARGCOUNT_WITHOUT_VARARG }
|
invokeFunctions.all { it.valueParameters.size + (if (it.extensionReceiverParameter != null) 1 else 0) < FunctionInvokeDescriptor.Factory.BIG_ARITY }
|
||||||
) {
|
) {
|
||||||
// No need to add a new vararg invoke method
|
// No need to add a new vararg invoke method
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user