[FIR] Union CFG edges from postponed lambdas only if outer call was analyzed independently

Before this change nodes unification was called if outer call was
  completed in the FULL mode, but it may happen even if this call is
  actually a part of some other outer call
This commit is contained in:
Dmitriy Novozhilov
2023-06-28 15:19:32 +03:00
committed by Space Team
parent cf949e8760
commit fc57f48c8f
12 changed files with 674 additions and 690 deletions
@@ -82,7 +82,7 @@ class SingleCandidateResolver(
?: ResolutionMode.ContextIndependent ?: ResolutionMode.ContextIndependent
) )
return completionResult.takeIf { it.callCompleted }?.result return completionResult
} }
private fun createCandidateInfoProvider(resolutionParameters: ResolutionParameters): CandidateInfoProvider { private fun createCandidateInfoProvider(resolutionParameters: ResolutionParameters): CandidateInfoProvider {
File diff suppressed because it is too large Load Diff
@@ -84,7 +84,7 @@ FILE: flowFromInplaceLambda.kt
^ (R|<local>/x| as R|kotlin/Int|) ^ (R|<local>/x| as R|kotlin/Int|)
} }
)), (R|<local>/y| as R|kotlin/Int|), R|/exactlyOnce|<R|kotlin/Int|>(<L> = exactlyOnce@fun <anonymous>(): R|kotlin/Int| <inline=NoInline, kind=EXACTLY_ONCE> { )), (R|<local>/y| as R|kotlin/Int|), R|/exactlyOnce|<R|kotlin/Int|>(<L> = exactlyOnce@fun <anonymous>(): R|kotlin/Int| <inline=NoInline, kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Int.inc|() R|<local>/x|.<Unresolved name: inc>#()
R|<local>/y|.R|kotlin/Int.inc|() R|<local>/y|.R|kotlin/Int.inc|()
^ Int(1) ^ Int(1)
} }
@@ -98,7 +98,7 @@ FILE: flowFromInplaceLambda.kt
^ (R|<local>/x| as R|kotlin/Int|) ^ (R|<local>/x| as R|kotlin/Int|)
} }
)), (R|<local>/y| as R|kotlin/Int|), R|/atLeastOnce|<R|kotlin/Int|>(<L> = atLeastOnce@fun <anonymous>(): R|kotlin/Int| <inline=NoInline, kind=AT_LEAST_ONCE> { )), (R|<local>/y| as R|kotlin/Int|), R|/atLeastOnce|<R|kotlin/Int|>(<L> = atLeastOnce@fun <anonymous>(): R|kotlin/Int| <inline=NoInline, kind=AT_LEAST_ONCE> {
R|<local>/x|.R|kotlin/Int.inc|() R|<local>/x|.<Unresolved name: inc>#()
R|<local>/y|.R|kotlin/Int.inc|() R|<local>/y|.R|kotlin/Int.inc|()
^ Int(1) ^ Int(1)
} }
@@ -39,7 +39,7 @@ fun completedCallExactlyOnce(x: Any?, y: Any?) {
// The value of the type argument is known, so the call is complete and the data can flow. // The value of the type argument is known, so the call is complete and the data can flow.
id(exactlyOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }), id(exactlyOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }),
y as Int, y as Int,
exactlyOnce { x.inc(); y.inc(); 1 } exactlyOnce { x.<!UNRESOLVED_REFERENCE!>inc<!>(); y.inc(); 1 }
).inc() // OK ).inc() // OK
x.inc() // OK x.inc() // OK
y.inc() // OK y.inc() // OK
@@ -49,7 +49,7 @@ fun completedCallAtLeastOnce(x: Any?, y: Any?) {
select( select(
id(atLeastOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }), id(atLeastOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }),
y as Int, y as Int,
atLeastOnce { x.inc(); y.inc(); 1 } atLeastOnce { x.<!UNRESOLVED_REFERENCE!>inc<!>(); y.inc(); 1 }
).inc() // OK ).inc() // OK
x.inc() // OK x.inc() // OK
y.inc() // OK y.inc() // OK
@@ -112,8 +112,9 @@ finally {
20 -> {21}; 20 -> {21};
21 -> {22}; 21 -> {22};
22 -> {23}; 22 -> {23};
23 -> {24};
23 -> {17} [color=green style=dashed]; 23 -> {17} [color=green style=dashed];
23 -> {24} [color=green];
23 -> {31} [color=red];
24 -> {25}; 24 -> {25};
24 -> {27} [label="onUncaughtException"]; 24 -> {27} [label="onUncaughtException"];
25 -> {26}; 25 -> {26};
@@ -201,7 +202,8 @@ finally {
44 -> {45}; 44 -> {45};
45 -> {46}; 45 -> {46};
46 -> {47}; 46 -> {47};
48 -> {49}; 48 -> {49} [color=green];
48 -> {56} [color=red];
49 -> {50}; 49 -> {50};
49 -> {52} [label="onUncaughtException"]; 49 -> {52} [label="onUncaughtException"];
50 -> {51}; 50 -> {51};
@@ -323,7 +323,7 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
} }
source = info.fakeSourceForImplicitInvokeCallReceiver source = info.fakeSourceForImplicitInvokeCallReceiver
}.build().let { }.build().let {
callCompleter.completeCall(it, ResolutionMode.ReceiverResolution).result callCompleter.completeCall(it, ResolutionMode.ReceiverResolution)
}.let { }.let {
transformQualifiedAccessUsingSmartcastInfo(it) transformQualifiedAccessUsingSmartcastInfo(it)
} }
@@ -54,13 +54,10 @@ class FirCallCompleter(
val completer = ConstraintSystemCompleter(components, transformer.context) val completer = ConstraintSystemCompleter(components, transformer.context)
fun <T> completeCall(call: T, resolutionMode: ResolutionMode): T where T : FirResolvable, T : FirStatement {
data class CompletionResult<T>(val result: T, val callCompleted: Boolean)
fun <T> completeCall(call: T, resolutionMode: ResolutionMode): CompletionResult<T> where T : FirResolvable, T : FirStatement {
val typeRef = components.typeFromCallee(call) val typeRef = components.typeFromCallee(call)
val reference = call.calleeReference as? FirNamedReferenceWithCandidate ?: return CompletionResult(call, true) val reference = call.calleeReference as? FirNamedReferenceWithCandidate ?: return call
val candidate = reference.candidate val candidate = reference.candidate
val initialType = typeRef.initialTypeOfCandidate(candidate) val initialType = typeRef.initialTypeOfCandidate(candidate)
@@ -104,10 +101,10 @@ class FirCallCompleter(
null null
) )
inferenceSession.addCompletedCall(completedCall, candidate) inferenceSession.addCompletedCall(completedCall, candidate)
CompletionResult(completedCall, true) completedCall
} else { } else {
inferenceSession.addPartiallyResolvedCall(call) inferenceSession.addPartiallyResolvedCall(call)
CompletionResult(call, false) call
} }
} }
@@ -120,7 +117,7 @@ class FirCallCompleter(
inferenceSession.addPartiallyResolvedCall(call) inferenceSession.addPartiallyResolvedCall(call)
} }
CompletionResult(call, false) call
} }
ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA -> throw IllegalStateException() ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA -> throw IllegalStateException()
@@ -188,7 +188,7 @@ class FirSyntheticCallGenerator(
this.argumentList = argumentList this.argumentList = argumentList
} }
val result = components.callCompleter.completeCall(fakeCallElement, ResolutionMode.ContextIndependent).result val result = components.callCompleter.completeCall(fakeCallElement, ResolutionMode.ContextIndependent)
val completedCallableReference = result.argument as FirCallableReferenceAccess? val completedCallableReference = result.argument as FirCallableReferenceAccess?
val callCalleeReference = result.calleeReference val callCalleeReference = result.calleeReference
@@ -25,9 +25,8 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
*/ */
class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() { class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
private fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? { private fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? {
if (!functionCall.isArrayOfCall) { if (!functionCall.isArrayOfCall) return null
return null if (functionCall.calleeReference !is FirResolvedNamedReference) return null
}
return buildArrayOfCall { return buildArrayOfCall {
source = functionCall.source source = functionCall.source
annotations += functionCall.annotations annotations += functionCall.annotations
@@ -94,8 +94,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
// exhaustiveness is not yet computed there, but at the same time to compute it properly // exhaustiveness is not yet computed there, but at the same time to compute it properly
// we need having branches condition bes analyzed that is why we can't have call // we need having branches condition bes analyzed that is why we can't have call
// `whenExpression.transformSingle(whenExhaustivenessTransformer, null)` at the beginning // `whenExpression.transformSingle(whenExhaustivenessTransformer, null)` at the beginning
val callCompleted = when { if (completionNeeded) {
completionNeeded -> {
val completionResult = callCompleter.completeCall( val completionResult = callCompleter.completeCall(
whenExpression, whenExpression,
// For non-exhaustive when expressions, we should complete then as independent because below // For non-exhaustive when expressions, we should complete then as independent because below
@@ -104,14 +103,9 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
// At the same time, it all looks suspicious and inconsistent, so we hope it would be investigated at KT-55175 // At the same time, it all looks suspicious and inconsistent, so we hope it would be investigated at KT-55175
if (whenExpression.isProperlyExhaustive) data else ResolutionMode.ContextIndependent, if (whenExpression.isProperlyExhaustive) data else ResolutionMode.ContextIndependent,
) )
whenExpression = completionResult.result whenExpression = completionResult
completionResult.callCompleted
} }
else -> false dataFlowAnalyzer.exitWhenExpression(whenExpression, data.forceFullCompletion)
}
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive() whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive()
whenExpression whenExpression
} }
@@ -169,13 +163,13 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
tryExpression.transformCatches(this, ResolutionMode.ContextDependent) tryExpression.transformCatches(this, ResolutionMode.ContextDependent)
val incomplete = syntheticCallGenerator.generateCalleeForTryExpression(tryExpression, resolutionContext) val incomplete = syntheticCallGenerator.generateCalleeForTryExpression(tryExpression, resolutionContext)
var (result, callCompleted) = callCompleter.completeCall(incomplete, data) var result = callCompleter.completeCall(incomplete, data)
if (result.finallyBlock != null) { if (result.finallyBlock != null) {
dataFlowAnalyzer.enterFinallyBlock() dataFlowAnalyzer.enterFinallyBlock()
result = result.transformFinallyBlock(transformer, ResolutionMode.ContextIndependent) result = result.transformFinallyBlock(transformer, ResolutionMode.ContextIndependent)
dataFlowAnalyzer.exitFinallyBlock() dataFlowAnalyzer.exitFinallyBlock()
} }
dataFlowAnalyzer.exitTryExpression(callCompleted) dataFlowAnalyzer.exitTryExpression(data.forceFullCompletion)
return result return result
} }
@@ -262,7 +256,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
) )
elvisExpression.transformRhs(transformer, resolutionModeForRhs) elvisExpression.transformRhs(transformer, resolutionModeForRhs)
val (result, callCompleted) = callCompleter.completeCall( val result = callCompleter.completeCall(
syntheticCallGenerator.generateCalleeForElvisExpression(elvisExpression, resolutionContext), data syntheticCallGenerator.generateCalleeForElvisExpression(elvisExpression, resolutionContext), data
) )
@@ -291,7 +285,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
} }
} }
dataFlowAnalyzer.exitElvis(elvisExpression, isLhsNotNull, callCompleted) dataFlowAnalyzer.exitElvis(elvisExpression, isLhsNotNull, data.forceFullCompletion)
return result return result
} }
} }
@@ -166,7 +166,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
if (!transformedCallee.isAcceptableResolvedQualifiedAccess()) { if (!transformedCallee.isAcceptableResolvedQualifiedAccess()) {
return qualifiedAccessExpression return qualifiedAccessExpression
} }
callCompleter.completeCall(transformedCallee, data).result callCompleter.completeCall(transformedCallee, data)
} else { } else {
transformedCallee transformedCallee
} }
@@ -419,8 +419,6 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
functionCall.transformAnnotations(transformer, data) functionCall.transformAnnotations(transformer, data)
functionCall.replaceLambdaArgumentInvocationKinds(session) functionCall.replaceLambdaArgumentInvocationKinds(session)
functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent) functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent)
val (completeInference, callCompleted) =
run {
val initialExplicitReceiver = functionCall.explicitReceiver val initialExplicitReceiver = functionCall.explicitReceiver
val withTransformedArguments = if (!resolvingAugmentedAssignment) { val withTransformedArguments = if (!resolvingAugmentedAssignment) {
dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments) dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments)
@@ -444,20 +442,17 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
// name.invoke() case // name.invoke() case
callCompleter.completeCall(resultExplicitReceiver, ResolutionMode.ContextIndependent) callCompleter.completeCall(resultExplicitReceiver, ResolutionMode.ContextIndependent)
} }
callCompleter.completeCall(resultExpression, data) val completeInference = callCompleter.completeCall(resultExpression, data)
}
val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data) val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data)
if (!resolvingAugmentedAssignment) { if (!resolvingAugmentedAssignment) {
dataFlowAnalyzer.exitFunctionCall(result, callCompleted) dataFlowAnalyzer.exitFunctionCall(result, data.forceFullCompletion)
} }
addReceiversFromExtensions(result) addReceiversFromExtensions(result)
if (callCompleted) {
if (enableArrayOfCallTransformation) { if (enableArrayOfCallTransformation) {
return arrayOfCallTransformer.transformFunctionCall(result, null) return arrayOfCallTransformer.transformFunctionCall(result, null)
} }
}
return result return result
} }
@@ -970,11 +965,11 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
.transformAnnotations(transformer, ResolutionMode.ContextIndependent) .transformAnnotations(transformer, ResolutionMode.ContextIndependent)
.replaceArgumentList(checkNotNullCall.argumentList.transform(transformer, ResolutionMode.ContextDependent)) .replaceArgumentList(checkNotNullCall.argumentList.transform(transformer, ResolutionMode.ContextDependent))
val (result, callCompleted) = callCompleter.completeCall( val result = callCompleter.completeCall(
components.syntheticCallGenerator.generateCalleeForCheckNotNullCall(checkNotNullCall, resolutionContext), data components.syntheticCallGenerator.generateCalleeForCheckNotNullCall(checkNotNullCall, resolutionContext), data
) )
dataFlowAnalyzer.exitCheckNotNullCall(result, callCompleted) dataFlowAnalyzer.exitCheckNotNullCall(result, data.forceFullCompletion)
return result return result
} }
@@ -1328,8 +1323,8 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
// it seems that we may leave this code as is // it seems that we may leave this code as is
// without adding `context.withTowerDataContext(context.getTowerDataContextForConstructorResolution())` // without adding `context.withTowerDataContext(context.getTowerDataContextForConstructorResolution())`
val (result, callCompleted) = callCompleter.completeCall(resolvedCall, ResolutionMode.ContextIndependent) val result = callCompleter.completeCall(resolvedCall, ResolutionMode.ContextIndependent)
dataFlowAnalyzer.exitDelegatedConstructorCall(result, callCompleted) dataFlowAnalyzer.exitDelegatedConstructorCall(result, data.forceFullCompletion)
return result return result
} }
+2 -1
View File
@@ -706,8 +706,9 @@ digraph kt44814_kt {
191 -> {192}; 191 -> {192};
192 -> {193}; 192 -> {193};
193 -> {194}; 193 -> {194};
194 -> {195};
194 -> {182} [color=green style=dashed]; 194 -> {182} [color=green style=dashed];
194 -> {195} [color=green];
194 -> {202} [style=dotted];
195 -> {196}; 195 -> {196};
196 -> {197 201}; 196 -> {197 201};
197 -> {198}; 197 -> {198};