FIR: coerce to Unit when a lambda has early returns
^KT-39075 Fixed
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
83e3201677
commit
37a702b962
Vendored
+2
-2
@@ -11,7 +11,7 @@ FILE: coercionToUnitWithEarlyReturn.kt
|
|||||||
public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||||
}
|
}
|
||||||
public final fun main(x: R|A?|): 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 () {
|
when () {
|
||||||
==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> {
|
==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> {
|
||||||
^@l Unit
|
^@l Unit
|
||||||
@@ -21,5 +21,5 @@ FILE: coercionToUnitWithEarlyReturn.kt
|
|||||||
^ R|<local>/x|?.{ $subj$.R|/A.unit|() }
|
^ R|<local>/x|?.{ $subj$.R|/A.unit|() }
|
||||||
}
|
}
|
||||||
|
|
||||||
<Inapplicable(INAPPLICABLE): /foo>#(R|<local>/lambda|)
|
R|/foo|(R|<local>/lambda|)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -14,6 +14,5 @@ fun main(x: A?) {
|
|||||||
x?.unit()
|
x?.unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// lambda has a type (() -> Unit?)
|
foo(lambda)
|
||||||
<!INAPPLICABLE_CANDIDATE{LT}!><!INAPPLICABLE_CANDIDATE{PSI}!>foo<!>(lambda)<!>
|
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-7
@@ -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.buildErrorTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
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.fir.visitors.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
@@ -780,13 +781,28 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
|||||||
dataFlowAnalyzer,
|
dataFlowAnalyzer,
|
||||||
)
|
)
|
||||||
lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.toExpectedType())
|
lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.toExpectedType())
|
||||||
val returnTypes = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda)
|
|
||||||
.mapNotNull { (it as? FirExpression)?.resultType?.coneType }
|
val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda)
|
||||||
lambda.replaceReturnTypeRef(
|
val returnExpressionsExceptLast =
|
||||||
lambda.returnTypeRef.resolvedTypeFromPrototype(
|
if (returnStatements.size > 1)
|
||||||
inferenceComponents.ctx.commonSuperTypeOrNull(returnTypes) ?: session.builtinTypes.unitType.type
|
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.replaceTypeRef(
|
||||||
lambda.constructFunctionalTypeRef(
|
lambda.constructFunctionalTypeRef(
|
||||||
isSuspend = expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.isSuspendFunctionType(session) == true
|
isSuspend = expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.isSuspendFunctionType(session) == true
|
||||||
|
|||||||
Reference in New Issue
Block a user