FIR2IR KT-47939 callable references to fun interface constructors

This commit is contained in:
Dmitry Petrov
2021-11-29 18:51:01 +03:00
committed by TeamCityServer
parent f55f880726
commit 11daed8b01
7 changed files with 215 additions and 45 deletions
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.Fir2IrConversionScope
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
import org.jetbrains.kotlin.fir.backend.convertWithOffsets
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
@@ -21,23 +18,18 @@ import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.FirFakeArgumentForCallableReference
import org.jetbrains.kotlin.fir.resolve.calls.ResolvedCallArgument
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
@@ -500,4 +492,101 @@ internal class AdapterGenerator(
}
return irCall
}
fun generateFunInterfaceConstructorReference(
callableReference: FirCallableReferenceAccess,
callableSymbol: FirFunctionSymbol<*>,
irReferenceType: IrType
): IrExpression =
callableReference.convertWithOffsets { startOffset: Int, endOffset: Int ->
// {
// fun <ADAPTER_FUN>(function: <FUN_TYPE>): <FUN_INTERFACE_TYPE> =
// <FUN_INTERFACE_TYPE>(function)
// ::<ADAPTER_FUN>
// }
val irAdapterFun = generateFunInterfaceConstructorAdapter(startOffset, endOffset, callableSymbol, irReferenceType)
val irAdapterRef = IrFunctionReferenceImpl(
startOffset, endOffset,
type = irReferenceType,
symbol = irAdapterFun.symbol,
typeArgumentsCount = irAdapterFun.typeParameters.size,
valueArgumentsCount = irAdapterFun.valueParameters.size,
reflectionTarget = irAdapterFun.symbol,
origin = IrStatementOrigin.FUN_INTERFACE_CONSTRUCTOR_REFERENCE
)
IrBlockImpl(
startOffset, endOffset,
irReferenceType,
IrStatementOrigin.FUN_INTERFACE_CONSTRUCTOR_REFERENCE,
listOf(
irAdapterFun,
irAdapterRef
)
)
}
private fun IrSimpleType.getArgumentTypeAt(index: Int): IrType {
val irTypeArgument = this.arguments[index] as? IrTypeProjection
?: throw AssertionError("Type projection expected at argument $index: ${this.render()}")
return irTypeArgument.type
}
private fun generateFunInterfaceConstructorAdapter(
startOffset: Int,
endOffset: Int,
callableSymbol: FirFunctionSymbol<*>,
irReferenceType: IrType
): IrSimpleFunction {
// Here irReferenceType is always kotlin.reflect.KFunction1<FUN_TYPE, FUN_INTERFACE_TYPE>
val irSimpleReferenceType = irReferenceType as? IrSimpleType
?: throw AssertionError("Class type expected: ${irReferenceType.render()}")
val irSamType = irSimpleReferenceType.getArgumentTypeAt(1)
val irFunctionType = irSimpleReferenceType.getArgumentTypeAt(0)
val functionParameter = callableSymbol.valueParameterSymbols.singleOrNull()
?: throw AssertionError("Single value parameter expected: ${callableSymbol.valueParameterSymbols}")
return irFactory.createFunction(
startOffset, endOffset,
IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR,
IrSimpleFunctionSymbolImpl(),
callableSymbol.name,
DescriptorVisibilities.LOCAL,
Modality.FINAL,
irSamType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = true,
isOperator = false,
isInfix = false,
isExpect = false,
isFakeOverride = false
).also { irAdapterFunction ->
symbolTable.enterScope(irAdapterFunction)
irAdapterFunction.dispatchReceiverParameter = null
irAdapterFunction.extensionReceiverParameter = null
val irFunctionParameter = createAdapterParameter(
irAdapterFunction,
functionParameter.name,
0,
irFunctionType,
IrDeclarationOrigin.ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE
)
irAdapterFunction.valueParameters = listOf(irFunctionParameter)
irAdapterFunction.body = irFactory.createExpressionBody(
startOffset, endOffset,
IrTypeOperatorCallImpl(
startOffset, endOffset,
irSamType, IrTypeOperator.SAM_CONVERSION, irSamType,
IrGetValueImpl(startOffset, endOffset, irFunctionParameter.symbol)
)
)
symbolTable.leaveScope(irAdapterFunction)
irAdapterFunction.parent = conversionScope.parent()!!
}
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirSamResolverImpl
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.getExpectedType
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
@@ -43,6 +44,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.render
@@ -70,10 +72,22 @@ class CallAndReferenceGenerator(
callableReferenceAccess: FirCallableReferenceAccess,
explicitReceiverExpression: IrExpression?
): IrExpression {
val type = callableReferenceAccess.typeRef.toIrType()
val callableSymbol = callableReferenceAccess.calleeReference.toResolvedCallableSymbol()
if (callableSymbol?.origin == FirDeclarationOrigin.SamConstructor) {
assert(explicitReceiverExpression == null) {
"Fun interface constructor reference should be unbound: ${explicitReceiverExpression?.dump()}"
}
return adapterGenerator.generateFunInterfaceConstructorReference(
callableReferenceAccess,
callableSymbol as FirSyntheticFunctionSymbol,
type
)
}
val symbol = callableReferenceAccess.calleeReference.toSymbolForCall(
callableReferenceAccess.dispatchReceiver, session, classifierStorage, declarationStorage, conversionScope
)
val type = callableReferenceAccess.typeRef.toIrType()
// val x by y ->
// val `x$delegate` = y
// val x get() = `x$delegate`.getValue(this, ::x)