提交 37a702b9 编写于 作者: J Jinseong Jeon 提交者: Dmitriy Novozhilov

FIR: coerce to Unit when a lambda has early returns

^KT-39075 Fixed
上级 83e32016
......@@ -11,7 +11,7 @@ FILE: coercionToUnitWithEarlyReturn.kt
public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
}
public final fun main(x: R|A?|): R|kotlin/Unit| {
lval lambda: R|() -> kotlin/Unit?| = l@fun <anonymous>(): R|kotlin/Unit?| {
lval lambda: R|() -> kotlin/Unit| = l@fun <anonymous>(): R|kotlin/Unit| {
when () {
==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> {
^@l Unit
......@@ -21,5 +21,5 @@ FILE: coercionToUnitWithEarlyReturn.kt
^ R|<local>/x|?.{ $subj$.R|/A.unit|() }
}
<Inapplicable(INAPPLICABLE): /foo>#(R|<local>/lambda|)
R|/foo|(R|<local>/lambda|)
}
......@@ -14,6 +14,5 @@ fun main(x: A?) {
x?.unit()
}
// lambda has a type (() -> Unit?)
<!INAPPLICABLE_CANDIDATE{LT}!><!INAPPLICABLE_CANDIDATE{PSI}!>foo<!>(lambda)<!>
foo(lambda)
}
......@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
......@@ -780,13 +781,28 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
dataFlowAnalyzer,
)
lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.toExpectedType())
val returnTypes = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda)
.mapNotNull { (it as? FirExpression)?.resultType?.coneType }
lambda.replaceReturnTypeRef(
lambda.returnTypeRef.resolvedTypeFromPrototype(
inferenceComponents.ctx.commonSuperTypeOrNull(returnTypes) ?: session.builtinTypes.unitType.type
)
)
val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda)
val returnExpressionsExceptLast =
if (returnStatements.size > 1)
returnStatements - lambda.body?.statements?.lastOrNull()
else
returnStatements
val implicitReturns = returnExpressionsExceptLast.filter {
(it as? FirExpression)?.typeRef is FirImplicitUnitTypeRef
}
val returnType =
if (implicitReturns.isNotEmpty()) {
// i.e., early return, e.g., l@{ ... return@l ... }
// Note that the last statement will be coerced to Unit if needed.
session.builtinTypes.unitType.type
} else {
// Otherwise, compute the common super type of all possible return expressions
inferenceComponents.ctx.commonSuperTypeOrNull(
returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType }
) ?: session.builtinTypes.unitType.type
}
lambda.replaceReturnTypeRef(lambda.returnTypeRef.resolvedTypeFromPrototype(returnType))
lambda.replaceTypeRef(
lambda.constructFunctionalTypeRef(
isSuspend = expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.isSuspendFunctionType(session) == true
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册