PSI2IR: Support suspend conversion for function references

This commit is contained in:
Dmitry Petrov
2020-04-23 14:25:08 +03:00
parent 10cda4b54f
commit 6b9a7464f5
8 changed files with 288 additions and 16 deletions
@@ -689,7 +689,8 @@ class ExpressionCodegen(
override fun visitElement(element: IrElement, data: BlockInfo) =
throw AssertionError(
"Unexpected IR element found during code generation. Either code generation for it " +
"is not implemented, or it should have been lowered: ${element.render()}"
"is not implemented, or it should have been lowered:\n" +
element.render()
)
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
@@ -77,10 +77,12 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
val callBuilder = unwrapCallableDescriptorAndTypeArguments(resolvedCall, context.extensions.samConversion)
val callableReferenceType = getTypeInferredByFrontendOrFail(ktCallableReference)
if (resolvedCall.valueArguments.isNotEmpty() ||
requiresCoercionToUnit(resolvedDescriptor, getTypeInferredByFrontendOrFail(ktCallableReference))
requiresCoercionToUnit(resolvedDescriptor, callableReferenceType) ||
requiresSuspendConversion(resolvedDescriptor, callableReferenceType)
) {
return generateAdaptedCallableReference(ktCallableReference, callBuilder)
return generateAdaptedCallableReference(ktCallableReference, callBuilder, callableReferenceType)
}
return statementGenerator.generateCallReceiver(
@@ -91,7 +93,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
).call { dispatchReceiverValue, extensionReceiverValue ->
generateCallableReference(
ktCallableReference,
getTypeInferredByFrontendOrFail(ktCallableReference),
callableReferenceType,
callBuilder.descriptor,
callBuilder.typeArguments
).also { irCallableReference ->
@@ -106,9 +108,15 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
return KotlinBuiltIns.isUnit(ktExpectedReturnType) && !KotlinBuiltIns.isUnit(descriptor.returnType!!)
}
private fun requiresSuspendConversion(descriptor: CallableDescriptor, callableReferenceType: KotlinType): Boolean =
descriptor is FunctionDescriptor &&
!descriptor.isSuspend &&
callableReferenceType.isKSuspendFunctionType
private fun generateAdaptedCallableReference(
ktCallableReference: KtCallableReferenceExpression,
callBuilder: CallBuilder
callBuilder: CallBuilder,
callableReferenceType: KotlinType
): IrExpression {
val adapteeDescriptor = callBuilder.descriptor
if (adapteeDescriptor !is FunctionDescriptor) {
@@ -128,7 +136,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
val ktExpectedParameterTypes = ktFunctionalTypeArguments.take(ktFunctionalTypeArguments.size - 1).map { it.type }
val irAdapterFun =
createAdapterFun(startOffset, endOffset, adapteeDescriptor, ktExpectedParameterTypes, ktExpectedReturnType, callBuilder)
createAdapterFun(startOffset, endOffset, adapteeDescriptor, ktExpectedParameterTypes, ktExpectedReturnType, callBuilder, callableReferenceType)
val irCall = createAdapteeCall(startOffset, endOffset, adapteeSymbol, callBuilder, irAdapterFun)
irAdapterFun.body = IrBlockBodyImpl(startOffset, endOffset).apply {
@@ -326,9 +334,13 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
ktExpectedParameterTypes: List<KotlinType>,
ktExpectedReturnType: KotlinType,
callBuilder: CallBuilder,
callableReferenceType: KotlinType
): IrSimpleFunction {
val adapterFunctionDescriptor = WrappedSimpleFunctionDescriptor()
val hasSuspendConversion = !adapteeDescriptor.isSuspend &&
callableReferenceType.isKSuspendFunctionType
return context.symbolTable.declareSimpleFunction(
startOffset, endOffset,
IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE,
@@ -345,7 +357,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
isInline = adapteeDescriptor.isInline, // TODO ?
isExternal = false,
isTailrec = false,
isSuspend = adapteeDescriptor.isSuspend, // TODO ?
isSuspend = adapteeDescriptor.isSuspend || hasSuspendConversion,
isOperator = adapteeDescriptor.isOperator, // TODO ?
isExpect = false,
isFakeOverride = false