JVM_IR: treat adapted references as lambdas for inlining
#KT-38536 Fixed #KT-38535 Fixed
This commit is contained in:
+1
-1
@@ -271,7 +271,7 @@ fun isInlineIrExpression(argumentExpression: IrExpression) =
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrBlock.isInlineIrBlock(): Boolean = origin.isLambda
|
fun IrBlock.isInlineIrBlock(): Boolean = origin.isLambda || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
|
||||||
|
|
||||||
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
|
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
|
||||||
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && isInline
|
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && isInline
|
||||||
|
|||||||
+2
-4
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.jvm.ir
|
|||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
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.ir.util.isLambda
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||||
@@ -40,9 +39,8 @@ internal open class IrInlineReferenceLocator(private val context: JvmBackendCont
|
|||||||
if (!isInlineIrExpression(valueArgument))
|
if (!isInlineIrExpression(valueArgument))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (valueArgument is IrBlock && valueArgument.origin.isLambda) {
|
if (valueArgument is IrBlock) {
|
||||||
val reference = valueArgument.statements.last() as IrFunctionReference
|
visitInlineLambda(valueArgument.statements.last() as IrFunctionReference, function, parameter, data!!)
|
||||||
visitInlineLambda(reference, function, parameter, data!!)
|
|
||||||
} else if (valueArgument is IrCallableReference<*>) {
|
} else if (valueArgument is IrCallableReference<*>) {
|
||||||
visitInlineReference(valueArgument)
|
visitInlineReference(valueArgument)
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-26
@@ -42,20 +42,32 @@ internal val inlineCallableReferenceToLambdaPhase = makeIrFilePhase(
|
|||||||
//
|
//
|
||||||
// foo(::smth) -> foo { a -> smth(a) }
|
// foo(::smth) -> foo { a -> smth(a) }
|
||||||
//
|
//
|
||||||
internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass,
|
internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass {
|
||||||
IrElementTransformerVoidWithContext() {
|
|
||||||
|
|
||||||
private var inlinableReferences = mutableSetOf<IrCallableReference<*>>()
|
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
inlinableReferences.addAll(IrInlineReferenceLocator.scan(context, irFile))
|
val inlinableReferences = mutableSetOf<IrCallableReference<*>>()
|
||||||
irFile.transformChildrenVoid(this)
|
irFile.accept(object : IrInlineReferenceLocator(context) {
|
||||||
}
|
override fun visitInlineReference(argument: IrCallableReference<*>) {
|
||||||
|
inlinableReferences.add(argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInlineLambda(
|
||||||
|
argument: IrFunctionReference, callee: IrFunction, parameter: IrValueParameter, scope: IrDeclaration
|
||||||
|
) {
|
||||||
|
// Obviously needs no extra wrapping.
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
irFile.transformChildrenVoid(InlineCallableReferenceToLambdaTransformer(context, inlinableReferences))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InlineCallableReferenceToLambdaTransformer(
|
||||||
|
val context: JvmBackendContext,
|
||||||
|
val inlinableReferences: Set<IrCallableReference<*>>
|
||||||
|
) : IrElementTransformerVoidWithContext() {
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
if (expression !in inlinableReferences || expression.origin.isLambda) return expression
|
if (expression !in inlinableReferences) return expression
|
||||||
return context.expandInlineFunctionReferenceToLambda(expression, expression.symbol.owner)
|
return expandInlineFunctionReferenceToLambda(expression, expression.symbol.owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||||
@@ -64,19 +76,17 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
|||||||
|
|
||||||
return if (expression.field?.owner == null) {
|
return if (expression.field?.owner == null) {
|
||||||
// Use getter if field is absent ...
|
// Use getter if field is absent ...
|
||||||
context.expandInlineFunctionReferenceToLambda(expression, expression.getter!!.owner)
|
expandInlineFunctionReferenceToLambda(expression, expression.getter!!.owner)
|
||||||
} else {
|
} else {
|
||||||
// ... else use field itself
|
// ... else use field itself
|
||||||
context.expandInlineFieldReferenceToLambda(expression, expression.field!!.owner)
|
expandInlineFieldReferenceToLambda(expression, expression.field!!.owner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JvmBackendContext.expandInlineFieldReferenceToLambda(
|
private fun expandInlineFieldReferenceToLambda(expression: IrPropertyReference, field: IrField): IrExpression {
|
||||||
expression: IrPropertyReference, field: IrField
|
val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
||||||
): IrExpression {
|
|
||||||
val irBuilder = createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
|
||||||
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
|
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
|
||||||
val function = irFactory.buildFun {
|
val function = context.irFactory.buildFun {
|
||||||
setSourceRange(expression)
|
setSourceRange(expression)
|
||||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||||
name = Name.identifier("stub_for_inline")
|
name = Name.identifier("stub_for_inline")
|
||||||
@@ -94,7 +104,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
|||||||
else -> irGet(addValueParameter("receiver", field.parentAsClass.defaultType))
|
else -> irGet(addValueParameter("receiver", field.parentAsClass.defaultType))
|
||||||
}
|
}
|
||||||
|
|
||||||
body = createIrBuilder(symbol).run {
|
body = this@InlineCallableReferenceToLambdaTransformer.context.createIrBuilder(symbol).run {
|
||||||
irExprBody(irGetField(receiver, field))
|
irExprBody(irGetField(receiver, field))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,13 +124,9 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JvmBackendContext.expandInlineFunctionReferenceToLambda(
|
private fun expandInlineFunctionReferenceToLambda(expression: IrCallableReference<*>, referencedFunction: IrFunction): IrExpression {
|
||||||
expression: IrCallableReference<*>, referencedFunction: IrFunction
|
val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
||||||
): IrExpression {
|
|
||||||
val irBuilder =
|
|
||||||
createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
|
||||||
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
|
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
|
||||||
|
|
||||||
// We find the number of parameters for constructed lambda from the type of the function reference,
|
// We find the number of parameters for constructed lambda from the type of the function reference,
|
||||||
// but the actual types have to be copied from referencedFunction; function reference argument type may be too
|
// but the actual types have to be copied from referencedFunction; function reference argument type may be too
|
||||||
// specific because of approximation. See compiler/testData/codegen/box/callableReference/function/argumentTypes.kt
|
// specific because of approximation. See compiler/testData/codegen/box/callableReference/function/argumentTypes.kt
|
||||||
@@ -136,7 +142,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val function = irFactory.buildFun {
|
val function = context.irFactory.buildFun {
|
||||||
setSourceRange(expression)
|
setSourceRange(expression)
|
||||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||||
name = Name.identifier("stub_for_inlining")
|
name = Name.identifier("stub_for_inlining")
|
||||||
@@ -152,7 +158,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body = this@InlineCallableReferenceToLambdaPhase.context.createJvmIrBuilder(
|
body = this@InlineCallableReferenceToLambdaTransformer.context.createJvmIrBuilder(
|
||||||
symbol,
|
symbol,
|
||||||
expression.startOffset,
|
expression.startOffset,
|
||||||
expression.endOffset
|
expression.endOffset
|
||||||
|
|||||||
+2
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
import org.jetbrains.kotlin.ir.util.isLambda
|
import org.jetbrains.kotlin.ir.util.isLambda
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBacke
|
|||||||
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
|
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||||
if (expression.origin.isLambda) {
|
if (expression.origin.isLambda || expression.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE) {
|
||||||
loweredLambdasToDelete.add(expression.symbol.owner)
|
loweredLambdasToDelete.add(expression.symbol.owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user