FIR2IR: apply SAM conversion to arguments if needed

This commit is contained in:
Jinseong Jeon
2020-05-07 23:02:44 -07:00
committed by Mikhail Glukhikh
parent 0ce16b9d8c
commit 6034fcdc46
7 changed files with 94 additions and 67 deletions
@@ -459,3 +459,10 @@ fun FirClass<*>.irOrigin(firProvider: FirProvider): IrDeclarationOrigin = when {
origin == FirDeclarationOrigin.Java -> IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB origin == FirDeclarationOrigin.Java -> IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
else -> IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else -> IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
} }
val IrType.isSamType: Boolean
get() {
val irClass = classOrNull ?: return false
val am = irClass.functions.singleOrNull { it.owner.modality == Modality.ABSTRACT }
return am != null
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.backend.generators package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrErrorCallExpression import org.jetbrains.kotlin.ir.expressions.IrErrorCallExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
@@ -325,22 +328,22 @@ internal class CallAndReferenceGenerator(
val argumentsCount = call.arguments.size val argumentsCount = call.arguments.size
if (argumentsCount <= valueArgumentsCount) { if (argumentsCount <= valueArgumentsCount) {
apply { apply {
val argumentMapping = call.argumentMapping
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
val calleeReference = when (call) { val calleeReference = when (call) {
is FirFunctionCall -> call.calleeReference is FirFunctionCall -> call.calleeReference
is FirDelegatedConstructorCall -> call.calleeReference is FirDelegatedConstructorCall -> call.calleeReference
else -> throw IllegalArgumentException("Unsupported call: ${call.render()}") else -> null
} as? FirResolvedNamedReference } as? FirResolvedNamedReference
val function = (calleeReference?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir val function = (calleeReference?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
val valueParameters = function?.valueParameters val valueParameters = function?.valueParameters
val argumentMapping = call.argumentMapping
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
if (valueParameters != null) { if (valueParameters != null) {
return applyArgumentsWithReorderingIfNeeded(argumentMapping, valueParameters) return applyArgumentsWithReorderingIfNeeded(argumentMapping, valueParameters)
} }
} }
for ((index, argument) in call.arguments.withIndex()) { for ((index, argument) in call.arguments.withIndex()) {
val argumentExpression = visitor.convertToIrExpression(argument) val argumentExpression =
visitor.convertToIrExpression(argument).applySamConversionIfNeeded(argument, valueParameters?.get(index))
putValueArgument(index, argumentExpression) putValueArgument(index, argumentExpression)
} }
} }
@@ -373,7 +376,7 @@ internal class CallAndReferenceGenerator(
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply { return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
for ((argument, parameter) in argumentMapping) { for ((argument, parameter) in argumentMapping) {
val parameterIndex = valueParameters.indexOf(parameter) val parameterIndex = valueParameters.indexOf(parameter)
val irArgument = visitor.convertToIrExpression(argument) val irArgument = visitor.convertToIrExpression(argument).applySamConversionIfNeeded(argument, parameter)
if (irArgument.hasNoSideEffects()) { if (irArgument.hasNoSideEffects()) {
putValueArgument(parameterIndex, irArgument) putValueArgument(parameterIndex, irArgument)
} else { } else {
@@ -388,7 +391,7 @@ internal class CallAndReferenceGenerator(
} }
} else { } else {
for ((argument, parameter) in argumentMapping) { for ((argument, parameter) in argumentMapping) {
val argumentExpression = visitor.convertToIrExpression(argument) val argumentExpression = visitor.convertToIrExpression(argument).applySamConversionIfNeeded(argument, parameter)
putValueArgument(valueParameters.indexOf(parameter), argumentExpression) putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
} }
return this return this
@@ -410,6 +413,21 @@ internal class CallAndReferenceGenerator(
return false return false
} }
private fun IrExpression.applySamConversionIfNeeded(
argument: FirExpression,
parameter: FirValueParameter?
): IrExpression {
if (parameter == null ||
parameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
) return this
if (argument !is FirLambdaArgumentExpression) return this
if (argument.expression !is FirAnonymousFunction) return this
if (argument.expression.typeRef == parameter.returnTypeRef) return this
val samType = parameter.returnTypeRef.toIrType()
if (!samType.isSamType) return this
return IrTypeOperatorCallImpl(this.startOffset, this.endOffset, samType, IrTypeOperator.SAM_CONVERSION, samType, this)
}
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression { private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
return when (this) { return when (this) {
is IrMemberAccessExpressionBase -> { is IrMemberAccessExpressionBase -> {
@@ -1,5 +1,4 @@
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_DCE_DRIVEN // SKIP_DCE_DRIVEN
fun interface Foo { fun interface Foo {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND_FIR: JVM_IR
fun interface FunInterface { fun interface FunInterface {
fun invoke() fun invoke()
@@ -26,7 +26,8 @@ FILE fqName:<root> fileName:/basicFunInterfaceConversion.kt
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.String declared in <root>' RETURN type=kotlin.Nothing from='public final fun test (): kotlin.String declared in <root>'
CALL 'public final fun foo (f: <root>.Foo): kotlin.String declared in <root>' type=kotlin.String origin=null CALL 'public final fun foo (f: <root>.Foo): kotlin.String declared in <root>' type=kotlin.String origin=null
f: FUN_EXPR type=kotlin.Function0<kotlin.String> origin=LAMBDA f: TYPE_OP type=<root>.Foo origin=SAM_CONVERSION typeOperand=<root>.Foo
FUN_EXPR type=kotlin.Function0<kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.String FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.String declared in <root>.test' RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.String declared in <root>.test'
@@ -139,7 +139,8 @@ FILE fqName:<root> fileName:/partialSam.kt
CALL 'public final fun runConversion (f1: <root>.Fn<kotlin.String, kotlin.Int>, f2: <root>.Fn<kotlin.Int, kotlin.String>): kotlin.Int declared in <root>.J' type=kotlin.Int origin=null CALL 'public final fun runConversion (f1: <root>.Fn<kotlin.String, kotlin.Int>, f2: <root>.Fn<kotlin.Int, kotlin.String>): kotlin.Int declared in <root>.J' type=kotlin.Int origin=null
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null $this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
f1: CALL 'public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>' type=<root>.fsi.<no name provided> origin=GET_PROPERTY f1: CALL 'public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>' type=<root>.fsi.<no name provided> origin=GET_PROPERTY
f2: FUN_EXPR type=kotlin.Function3<kotlin.String, kotlin.Int, kotlin.Int, kotlin.String> origin=LAMBDA f2: TYPE_OP type=<root>.Fn<kotlin.Int, kotlin.String> origin=SAM_CONVERSION typeOperand=<root>.Fn<kotlin.Int, kotlin.String>
FUN_EXPR type=kotlin.Function3<kotlin.String, kotlin.Int, kotlin.Int, kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (s:kotlin.String, i:kotlin.Int, ti:kotlin.Int) returnType:kotlin.String FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (s:kotlin.String, i:kotlin.Int, ti:kotlin.Int) returnType:kotlin.String
VALUE_PARAMETER name:s index:0 type:kotlin.String VALUE_PARAMETER name:s index:0 type:kotlin.String
VALUE_PARAMETER name:i index:1 type:kotlin.Int VALUE_PARAMETER name:i index:1 type:kotlin.Int
@@ -94,7 +94,8 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
$this: GET_VAR '<this>: <root>.ProducerScope<kotlin.Any> declared in <root>.asFairChannel.<anonymous>' type=<root>.ProducerScope<kotlin.Any> origin=null $this: GET_VAR '<this>: <root>.ProducerScope<kotlin.Any> declared in <root>.asFairChannel.<anonymous>' type=<root>.ProducerScope<kotlin.Any> origin=null
CALL 'public abstract fun collect (collector: <root>.FlowCollector<T of <root>.Flow>): kotlin.Unit [suspend] declared in <root>.Flow' type=kotlin.Unit origin=null CALL 'public abstract fun collect (collector: <root>.FlowCollector<T of <root>.Flow>): kotlin.Unit [suspend] declared in <root>.Flow' type=kotlin.Unit origin=null
$this: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asFairChannel' type=<root>.Flow<*> origin=null $this: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asFairChannel' type=<root>.Flow<*> origin=null
collector: FUN_EXPR type=kotlin.Function1<kotlin.Any?, kotlin.Unit> origin=LAMBDA collector: TYPE_OP type=<root>.FlowCollector<kotlin.Any?> origin=SAM_CONVERSION typeOperand=<root>.FlowCollector<kotlin.Any?>
FUN_EXPR type=kotlin.Function1<kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit
VALUE_PARAMETER name:value index:0 type:kotlin.Any? VALUE_PARAMETER name:value index:0 type:kotlin.Any?
BLOCK_BODY BLOCK_BODY
@@ -128,7 +129,8 @@ FILE fqName:<root> fileName:/castsInsideCoroutineInference.kt
BLOCK_BODY BLOCK_BODY
CALL 'public abstract fun collect (collector: <root>.FlowCollector<T of <root>.Flow>): kotlin.Unit [suspend] declared in <root>.Flow' type=kotlin.Unit origin=null CALL 'public abstract fun collect (collector: <root>.FlowCollector<T of <root>.Flow>): kotlin.Unit [suspend] declared in <root>.Flow' type=kotlin.Unit origin=null
$this: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asChannel' type=<root>.Flow<*> origin=null $this: GET_VAR 'flow: <root>.Flow<*> declared in <root>.asChannel' type=<root>.Flow<*> origin=null
collector: FUN_EXPR type=kotlin.Function1<kotlin.Any?, kotlin.Unit> origin=LAMBDA collector: TYPE_OP type=<root>.FlowCollector<kotlin.Any?> origin=SAM_CONVERSION typeOperand=<root>.FlowCollector<kotlin.Any?>
FUN_EXPR type=kotlin.Function1<kotlin.Any?, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (value:kotlin.Any?) returnType:kotlin.Unit
VALUE_PARAMETER name:value index:0 type:kotlin.Any? VALUE_PARAMETER name:value index:0 type:kotlin.Any?
BLOCK_BODY BLOCK_BODY