FIR: extend suspend conversion to intersection type

This commit is contained in:
Jinseong Jeon
2020-12-04 15:54:38 -08:00
committed by TeamCityServer
parent 42ea4463ee
commit 2dfba10d84
4 changed files with 56 additions and 41 deletions
@@ -400,8 +400,8 @@ internal class AdapterGenerator(
return this
}
val expectedType = parameter?.returnTypeRef?.coneType ?: return this
// Expect the expected type to be a suspend functional type, and the argument type is not a suspend functional type.
if (!expectedType.isSuspendFunctionType(session) || argument.typeRef.coneType.isSuspendFunctionType(session)) {
// Expect the expected type to be a suspend functional type.
if (!expectedType.isSuspendFunctionType(session)) {
return this
}
val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session)
@@ -424,22 +424,17 @@ internal class AdapterGenerator(
private fun findInvokeSymbol(expectedFunctionalType: ConeClassLikeType, argument: FirExpression): IrSimpleFunctionSymbol? {
val argumentType = argument.typeRef.coneType
// To avoid any remaining exotic types, e.g., intersection type, like it(FunctionN..., SuspendFunctionN...)
if (argumentType !is ConeClassLikeType) {
return null
}
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) ?: return null
if (argumentType.isSubtypeOfFunctionalType(session, expectedFunctionalType)) {
return if (argumentType.isBuiltinFunctionalType(session)) {
argumentType.findBaseInvokeSymbol(session, scopeSession)
} else {
argumentType.findContributedInvokeSymbol(session, scopeSession, expectedFunctionalType, shouldCalculateReturnTypesOfFakeOverrides = true)
}?.let {
declarationStorage.getIrFunctionSymbol(it) as? IrSimpleFunctionSymbol
}
return if (argumentTypeWithInvoke.isBuiltinFunctionalType(session)) {
(argumentTypeWithInvoke as? ConeClassLikeType)?.findBaseInvokeSymbol(session, scopeSession)
} else {
argumentTypeWithInvoke.findContributedInvokeSymbol(
session, scopeSession, expectedFunctionalType, shouldCalculateReturnTypesOfFakeOverrides = true
)
}?.let {
declarationStorage.getIrFunctionSymbol(it) as? IrSimpleFunctionSymbol
}
return null
}
private fun createAdapterFunctionForArgument(
@@ -247,36 +247,30 @@ private fun argumentTypeWithSuspendConversion(
): ConeKotlinType? {
// TODO: should refer to LanguageVersionSettings.SuspendConversion
// To avoid any remaining exotic types, e.g., intersection type, like it(FunctionN..., SuspendFunctionN...)
if (argumentType !is ConeClassLikeType) {
return null
}
// Expect the expected type to be a suspend functional type, and the argument type is not a suspend functional type.
if (!expectedType.isSuspendFunctionType(session) || argumentType.isSuspendFunctionType(session)) {
// Expect the expected type to be a suspend functional type.
if (!expectedType.isSuspendFunctionType(session)) {
return null
}
// We want to check the argument type against non-suspend functional type.
val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session)
if (argumentType.isSubtypeOfFunctionalType(session, expectedFunctionalType)) {
return argumentType.findContributedInvokeSymbol(
session,
scopeSession,
expectedFunctionalType,
shouldCalculateReturnTypesOfFakeOverrides = false
)?.let { invokeSymbol ->
createFunctionalType(
invokeSymbol.fir.valueParameters.map { it.returnTypeRef.coneType },
null,
invokeSymbol.fir.returnTypeRef.coneType,
isSuspend = true,
isKFunctionType = argumentType.isKFunctionType(session)
)
}
}
return null
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType)
return argumentTypeWithInvoke?.findContributedInvokeSymbol(
session,
scopeSession,
expectedFunctionalType,
shouldCalculateReturnTypesOfFakeOverrides = false
)?.let { invokeSymbol ->
createFunctionalType(
invokeSymbol.fir.valueParameters.map { it.returnTypeRef.coneType },
null,
invokeSymbol.fir.returnTypeRef.coneType,
isSuspend = true,
isKFunctionType = argumentType.isKFunctionType(session)
)
}
}
fun Candidate.prepareCapturedType(argumentType: ConeKotlinType, context: ResolutionContext): ConeKotlinType {
@@ -97,6 +97,33 @@ fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFuncti
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
}
fun ConeKotlinType.findSubtypeOfNonSuspendFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
require(expectedFunctionalType.isBuiltinFunctionalType(session) && !expectedFunctionalType.isSuspendFunctionType(session))
return when (this) {
is ConeClassLikeType -> {
// Expect the argument type is not a suspend functional type.
if (isSuspendFunctionType(session) || !isSubtypeOfFunctionalType(session, expectedFunctionalType))
null
else
this
}
is ConeIntersectionType -> {
if (intersectedTypes.any { it.isSuspendFunctionType(session) })
null
else
intersectedTypes.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
}
is ConeTypeParameterType -> {
val bounds = lookupTag.typeParameterSymbol.fir.bounds.map { it.coneType }
if (bounds.any { it.isSuspendFunctionType(session) })
null
else
bounds.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
}
else -> null
}
}
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirFunctionSymbol<*>? {
require(this.isBuiltinFunctionalType(session))
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass<*>) ?: return null
@@ -3,7 +3,6 @@
// WITH_COROUTINES
// IGNORE_BACKEND: JVM, NATIVE, JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_LIGHT_ANALYSIS
import helpers.*