Support anonymous function as inline parameters

This commit is contained in:
Mikhael Bogdanov
2019-04-08 11:21:16 +02:00
parent 2a3a9bb5fc
commit 10e3dfa980
4 changed files with 32 additions and 24 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
@@ -12,9 +13,11 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlineParameter import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlineParameter
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -150,4 +153,20 @@ class IrExpressionLambdaImpl(
} }
fun isInlineIrExpression(argumentExpression: IrExpression) = fun isInlineIrExpression(argumentExpression: IrExpression) =
argumentExpression is IrBlock && argumentExpression.origin == IrStatementOrigin.LAMBDA argumentExpression is IrBlock &&
(argumentExpression.origin == IrStatementOrigin.LAMBDA || argumentExpression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION)
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) &&
(isInline || isArrayConstructorWithLambda())
private fun IrFunction.isArrayConstructorWithLambda() =
valueParameters.size == 2 &&
this is IrConstructor &&
parentAsClass.let {
it.getPackageFragment()?.fqName?.asString() == "kotlin" &&
it.name.asString().endsWith("Array")
}
fun IrValueParameter.isInlineParameter() =
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
@@ -28,7 +28,9 @@ 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.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.codegen.isInlineParameter
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -83,7 +85,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val callee = expression.symbol.owner val callee = expression.symbol.owner
if (callee.isInlineFunction(context)) { if (callee.isInlineFunctionCall(context)) {
//TODO: more wise filtering //TODO: more wise filtering
callee.valueParameters.forEach { valueParameter -> callee.valueParameters.forEach { valueParameter ->
if (valueParameter.isInlineParameter()) { if (valueParameter.isInlineParameter()) {
@@ -589,22 +591,6 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
} }
// TODO: Move to IrUtils // TODO: Move to IrUtils
private fun IrFunction.isInlineFunction(context: JvmBackendContext) =
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) &&
(isInline || isArrayConstructorWithLambda())
private fun IrFunction.isArrayConstructorWithLambda() =
valueParameters.size == 2 &&
this is IrConstructor &&
parentAsClass.let {
it.getPackageFragment()?.fqName?.asString() == "kotlin" &&
it.name.asString().endsWith("Array")
}
private fun IrValueParameter.isInlineParameter() =
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
private fun IrType.substitute(substitutionMap: Map<IrTypeParameter, IrType>): IrType { private fun IrType.substitute(substitutionMap: Map<IrTypeParameter, IrType>): IrType {
if (this !is IrSimpleType) return this if (this !is IrSimpleType) return this
@@ -8,12 +8,16 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
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.codegen.isInlineCall import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.util.isFunction import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isNullable import org.jetbrains.kotlin.ir.util.isNullable
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -32,12 +36,12 @@ private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBacke
irFile.transformChildrenVoid(object : IrElementTransformerVoid() { irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val owner = expression.symbol.owner val owner = expression.symbol.owner
if (expression.descriptor.isInlineCall(context.state)) { if (expression.symbol.owner.isInlineFunctionCall(context)) {
owner.valueParameters.filter { owner.valueParameters.filter {
!it.isNoinline && it.type.isFunction() && !it.type.isNullable() !it.isNoinline && it.type.isFunction() && !it.type.isNullable()
}.forEach { }.forEach {
val valueArgument = expression.getValueArgument(it.index) as? IrContainerExpression ?: return@forEach val valueArgument = expression.getValueArgument(it.index) as? IrContainerExpression ?: return@forEach
if (valueArgument.origin == IrStatementOrigin.LAMBDA) { if (isInlineIrExpression(valueArgument)) {
val reference = val reference =
valueArgument.statements.firstIsInstanceOrNull<IrFunctionReference>() ?: return@forEach valueArgument.statements.firstIsInstanceOrNull<IrFunctionReference>() ?: return@forEach
loweredLambdasToDelete.add(reference.symbol.owner) loweredLambdasToDelete.add(reference.symbol.owner)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test