[FIR] Fix smartcast after elvis with escaping lambda, ^KT-44510 Fixed

This commit is contained in:
Ivan Kochurkin
2022-04-04 22:16:36 +03:00
committed by teamcity
parent c7122c1492
commit 3566b7fe02
4 changed files with 33 additions and 27 deletions
@@ -756,32 +756,32 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted) val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted)
node.mergeIncomingFlow() node.mergeIncomingFlow()
fun FirExpression.propagateNotNullInfo() { checkNotNullCall.argument.propagateNotNullInfo(node)
val symbol = this.symbol
if (symbol != null) { unionNode?.let { unionFlowFromArguments(it) }
variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable -> }
node.flow.addTypeStatement(operandVariable typeEq any)
logicSystem.approveStatementsInsideFlow( fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) {
node.flow, val symbol = this.symbol
operandVariable notEq null, if (symbol != null) {
shouldRemoveSynthetics = true, variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable ->
shouldForkFlow = false node.flow.addTypeStatement(operandVariable typeEq any)
) logicSystem.approveStatementsInsideFlow(
} node.flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} }
when (this) { }
is FirSafeCallExpression -> receiver.propagateNotNullInfo() when (this) {
is FirTypeOperatorCall -> { is FirSafeCallExpression -> receiver.propagateNotNullInfo(node)
if (operation == FirOperation.AS || operation == FirOperation.SAFE_AS) { is FirTypeOperatorCall -> {
argument.propagateNotNullInfo() if (operation == FirOperation.AS || operation == FirOperation.SAFE_AS) {
} argument.propagateNotNullInfo(node)
} }
} }
} }
checkNotNullCall.argument.propagateNotNullInfo()
unionNode?.let { unionFlowFromArguments(it) }
} }
// ----------------------------------- When ----------------------------------- // ----------------------------------- When -----------------------------------
@@ -1459,12 +1459,16 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
} }
fun exitElvis(elvisExpression: FirElvisExpression) { fun exitElvis(elvisExpression: FirElvisExpression, isLhsNotNull: Boolean) {
val node = graphBuilder.exitElvis().mergeIncomingFlow() val node = graphBuilder.exitElvis().mergeIncomingFlow()
if (isLhsNotNull) {
elvisExpression.lhs.propagateNotNullInfo(node)
}
if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return
val lhs = elvisExpression.lhs
val rhs = elvisExpression.rhs val rhs = elvisExpression.rhs
if (rhs is FirConstExpression<*> && rhs.kind == ConstantValueKind.Boolean) { if (rhs is FirConstExpression<*> && rhs.kind == ConstantValueKind.Boolean) {
val lhs = elvisExpression.lhs
if (lhs.typeRef.coneType.classId != StandardClassIds.Boolean) return if (lhs.typeRef.coneType.classId != StandardClassIds.Boolean) return
val flow = node.flow val flow = node.flow
@@ -245,11 +245,13 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
} }
} }
var isLhsNotNull = false
if (result.rhs.typeRef.coneTypeSafe<ConeKotlinType>()?.isNothing == true) { if (result.rhs.typeRef.coneTypeSafe<ConeKotlinType>()?.isNothing == true) {
val lhsType = result.lhs.typeRef.coneTypeSafe<ConeKotlinType>() val lhsType = result.lhs.typeRef.coneTypeSafe<ConeKotlinType>()
if (lhsType != null) { if (lhsType != null) {
val newReturnType = lhsType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext) val newReturnType = lhsType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)
result.replaceTypeRef(result.typeRef.resolvedTypeFromPrototype(newReturnType)) result.replaceTypeRef(result.typeRef.resolvedTypeFromPrototype(newReturnType))
isLhsNotNull = true
} }
} }
@@ -265,7 +267,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
} }
} }
dataFlowAnalyzer.exitElvis(elvisExpression) dataFlowAnalyzer.exitElvis(elvisExpression, isLhsNotNull = isLhsNotNull)
return result return result
} }
} }
@@ -14,7 +14,7 @@ inline fun <R> callItContracted(fn: () -> R): R {
fun smartIt(p1: String?, p2: String?) { fun smartIt(p1: String?, p2: String?) {
p1 ?: callIt { return } p1 ?: callIt { return }
p1<!UNSAFE_CALL!>.<!>length p1.length
p2 ?: callItContracted { return } p2 ?: callItContracted { return }
p2.length p2.length
@@ -6,5 +6,5 @@ fun <R> callIt(fn: () -> R): R = TODO()
fun smartIt(p1: String?, p2: String?) { fun smartIt(p1: String?, p2: String?) {
p1 ?: callIt { TODO() } p1 ?: callIt { TODO() }
p1<!UNSAFE_CALL!>.<!>length // smartcast p1.length // smartcast
} }