[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:
committed by
Space Team
parent
cf949e8760
commit
fc57f48c8f
+1
-1
@@ -82,7 +82,7 @@ class SingleCandidateResolver(
|
||||
?: ResolutionMode.ContextIndependent
|
||||
)
|
||||
|
||||
return completionResult.takeIf { it.callCompleted }?.result
|
||||
return completionResult
|
||||
}
|
||||
|
||||
private fun createCandidateInfoProvider(resolutionParameters: ResolutionParameters): CandidateInfoProvider {
|
||||
|
||||
+608
-612
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -84,7 +84,7 @@ FILE: flowFromInplaceLambda.kt
|
||||
^ (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>/x|.R|kotlin/Int.inc|()
|
||||
R|<local>/x|.<Unresolved name: inc>#()
|
||||
R|<local>/y|.R|kotlin/Int.inc|()
|
||||
^ Int(1)
|
||||
}
|
||||
@@ -98,7 +98,7 @@ FILE: flowFromInplaceLambda.kt
|
||||
^ (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>/x|.R|kotlin/Int.inc|()
|
||||
R|<local>/x|.<Unresolved name: inc>#()
|
||||
R|<local>/y|.R|kotlin/Int.inc|()
|
||||
^ 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.
|
||||
id(exactlyOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }),
|
||||
y as Int,
|
||||
exactlyOnce { x.inc(); y.inc(); 1 }
|
||||
exactlyOnce { x.<!UNRESOLVED_REFERENCE!>inc<!>(); y.inc(); 1 }
|
||||
).inc() // OK
|
||||
x.inc() // OK
|
||||
y.inc() // OK
|
||||
@@ -49,7 +49,7 @@ fun completedCallAtLeastOnce(x: Any?, y: Any?) {
|
||||
select(
|
||||
id(atLeastOnce { y.<!UNRESOLVED_REFERENCE!>inc<!>(); x as Int }),
|
||||
y as Int,
|
||||
atLeastOnce { x.inc(); y.inc(); 1 }
|
||||
atLeastOnce { x.<!UNRESOLVED_REFERENCE!>inc<!>(); y.inc(); 1 }
|
||||
).inc() // OK
|
||||
x.inc() // OK
|
||||
y.inc() // OK
|
||||
|
||||
+4
-2
@@ -112,8 +112,9 @@ finally {
|
||||
20 -> {21};
|
||||
21 -> {22};
|
||||
22 -> {23};
|
||||
23 -> {24};
|
||||
23 -> {17} [color=green style=dashed];
|
||||
23 -> {24} [color=green];
|
||||
23 -> {31} [color=red];
|
||||
24 -> {25};
|
||||
24 -> {27} [label="onUncaughtException"];
|
||||
25 -> {26};
|
||||
@@ -201,7 +202,8 @@ finally {
|
||||
44 -> {45};
|
||||
45 -> {46};
|
||||
46 -> {47};
|
||||
48 -> {49};
|
||||
48 -> {49} [color=green];
|
||||
48 -> {56} [color=red];
|
||||
49 -> {50};
|
||||
49 -> {52} [label="onUncaughtException"];
|
||||
50 -> {51};
|
||||
|
||||
+1
-1
@@ -323,7 +323,7 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
|
||||
}
|
||||
source = info.fakeSourceForImplicitInvokeCallReceiver
|
||||
}.build().let {
|
||||
callCompleter.completeCall(it, ResolutionMode.ReceiverResolution).result
|
||||
callCompleter.completeCall(it, ResolutionMode.ReceiverResolution)
|
||||
}.let {
|
||||
transformQualifiedAccessUsingSmartcastInfo(it)
|
||||
}
|
||||
|
||||
+5
-8
@@ -54,13 +54,10 @@ class FirCallCompleter(
|
||||
|
||||
val completer = ConstraintSystemCompleter(components, transformer.context)
|
||||
|
||||
|
||||
data class CompletionResult<T>(val result: T, val callCompleted: Boolean)
|
||||
|
||||
fun <T> completeCall(call: T, resolutionMode: ResolutionMode): CompletionResult<T> where T : FirResolvable, T : FirStatement {
|
||||
fun <T> completeCall(call: T, resolutionMode: ResolutionMode): T where T : FirResolvable, T : FirStatement {
|
||||
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 initialType = typeRef.initialTypeOfCandidate(candidate)
|
||||
@@ -104,10 +101,10 @@ class FirCallCompleter(
|
||||
null
|
||||
)
|
||||
inferenceSession.addCompletedCall(completedCall, candidate)
|
||||
CompletionResult(completedCall, true)
|
||||
completedCall
|
||||
} else {
|
||||
inferenceSession.addPartiallyResolvedCall(call)
|
||||
CompletionResult(call, false)
|
||||
call
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +117,7 @@ class FirCallCompleter(
|
||||
inferenceSession.addPartiallyResolvedCall(call)
|
||||
}
|
||||
|
||||
CompletionResult(call, false)
|
||||
call
|
||||
}
|
||||
|
||||
ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA -> throw IllegalStateException()
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ class FirSyntheticCallGenerator(
|
||||
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 callCalleeReference = result.calleeReference
|
||||
|
||||
+2
-3
@@ -25,9 +25,8 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||
*/
|
||||
class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
|
||||
private fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? {
|
||||
if (!functionCall.isArrayOfCall) {
|
||||
return null
|
||||
}
|
||||
if (!functionCall.isArrayOfCall) return null
|
||||
if (functionCall.calleeReference !is FirResolvedNamedReference) return null
|
||||
return buildArrayOfCall {
|
||||
source = functionCall.source
|
||||
annotations += functionCall.annotations
|
||||
|
||||
+15
-21
@@ -94,24 +94,18 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
|
||||
// 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
|
||||
// `whenExpression.transformSingle(whenExhaustivenessTransformer, null)` at the beginning
|
||||
val callCompleted = when {
|
||||
completionNeeded -> {
|
||||
val completionResult = callCompleter.completeCall(
|
||||
whenExpression,
|
||||
// For non-exhaustive when expressions, we should complete then as independent because below
|
||||
// their type is artificially replaced with Unit, while candidate symbol's return type remains the same
|
||||
// So when combining two when's the inner one was erroneously resolved as a normal dependent exhaustive sub-expression
|
||||
// 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,
|
||||
)
|
||||
whenExpression = completionResult.result
|
||||
|
||||
completionResult.callCompleted
|
||||
}
|
||||
else -> false
|
||||
if (completionNeeded) {
|
||||
val completionResult = callCompleter.completeCall(
|
||||
whenExpression,
|
||||
// For non-exhaustive when expressions, we should complete then as independent because below
|
||||
// their type is artificially replaced with Unit, while candidate symbol's return type remains the same
|
||||
// So when combining two when's the inner one was erroneously resolved as a normal dependent exhaustive sub-expression
|
||||
// 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,
|
||||
)
|
||||
whenExpression = completionResult
|
||||
}
|
||||
|
||||
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
|
||||
dataFlowAnalyzer.exitWhenExpression(whenExpression, data.forceFullCompletion)
|
||||
whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive()
|
||||
whenExpression
|
||||
}
|
||||
@@ -169,13 +163,13 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
|
||||
tryExpression.transformCatches(this, ResolutionMode.ContextDependent)
|
||||
|
||||
val incomplete = syntheticCallGenerator.generateCalleeForTryExpression(tryExpression, resolutionContext)
|
||||
var (result, callCompleted) = callCompleter.completeCall(incomplete, data)
|
||||
var result = callCompleter.completeCall(incomplete, data)
|
||||
if (result.finallyBlock != null) {
|
||||
dataFlowAnalyzer.enterFinallyBlock()
|
||||
result = result.transformFinallyBlock(transformer, ResolutionMode.ContextIndependent)
|
||||
dataFlowAnalyzer.exitFinallyBlock()
|
||||
}
|
||||
dataFlowAnalyzer.exitTryExpression(callCompleted)
|
||||
dataFlowAnalyzer.exitTryExpression(data.forceFullCompletion)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -262,7 +256,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
|
||||
)
|
||||
elvisExpression.transformRhs(transformer, resolutionModeForRhs)
|
||||
|
||||
val (result, callCompleted) = callCompleter.completeCall(
|
||||
val result = callCompleter.completeCall(
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+31
-36
@@ -166,7 +166,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
||||
if (!transformedCallee.isAcceptableResolvedQualifiedAccess()) {
|
||||
return qualifiedAccessExpression
|
||||
}
|
||||
callCompleter.completeCall(transformedCallee, data).result
|
||||
callCompleter.completeCall(transformedCallee, data)
|
||||
} else {
|
||||
transformedCallee
|
||||
}
|
||||
@@ -419,44 +419,39 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
||||
functionCall.transformAnnotations(transformer, data)
|
||||
functionCall.replaceLambdaArgumentInvocationKinds(session)
|
||||
functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent)
|
||||
val (completeInference, callCompleted) =
|
||||
run {
|
||||
val initialExplicitReceiver = functionCall.explicitReceiver
|
||||
val withTransformedArguments = if (!resolvingAugmentedAssignment) {
|
||||
dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments)
|
||||
// In provideDelegate mode the explicitReceiver is already resolved
|
||||
// E.g. we have val some by someDelegate
|
||||
// At 1st stage of delegate inference we resolve someDelegate itself,
|
||||
// at 2nd stage in provideDelegate mode we are trying to resolve someDelegate.provideDelegate(),
|
||||
// and 'someDelegate' explicit receiver is resolved at 1st stage
|
||||
// See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression
|
||||
val withResolvedExplicitReceiver = if (provideDelegate) functionCall else transformExplicitReceiver(functionCall)
|
||||
withResolvedExplicitReceiver.also {
|
||||
it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent))
|
||||
dataFlowAnalyzer.exitCallArguments()
|
||||
}
|
||||
} else {
|
||||
functionCall
|
||||
}
|
||||
val resultExpression = callResolver.resolveCallAndSelectCandidate(withTransformedArguments)
|
||||
val resultExplicitReceiver = resultExpression.explicitReceiver?.unwrapSmartcastExpression()
|
||||
if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccessExpression) {
|
||||
// name.invoke() case
|
||||
callCompleter.completeCall(resultExplicitReceiver, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
callCompleter.completeCall(resultExpression, data)
|
||||
val initialExplicitReceiver = functionCall.explicitReceiver
|
||||
val withTransformedArguments = if (!resolvingAugmentedAssignment) {
|
||||
dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments)
|
||||
// In provideDelegate mode the explicitReceiver is already resolved
|
||||
// E.g. we have val some by someDelegate
|
||||
// At 1st stage of delegate inference we resolve someDelegate itself,
|
||||
// at 2nd stage in provideDelegate mode we are trying to resolve someDelegate.provideDelegate(),
|
||||
// and 'someDelegate' explicit receiver is resolved at 1st stage
|
||||
// See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression
|
||||
val withResolvedExplicitReceiver = if (provideDelegate) functionCall else transformExplicitReceiver(functionCall)
|
||||
withResolvedExplicitReceiver.also {
|
||||
it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent))
|
||||
dataFlowAnalyzer.exitCallArguments()
|
||||
}
|
||||
} else {
|
||||
functionCall
|
||||
}
|
||||
val resultExpression = callResolver.resolveCallAndSelectCandidate(withTransformedArguments)
|
||||
val resultExplicitReceiver = resultExpression.explicitReceiver?.unwrapSmartcastExpression()
|
||||
if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccessExpression) {
|
||||
// name.invoke() case
|
||||
callCompleter.completeCall(resultExplicitReceiver, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
val completeInference = callCompleter.completeCall(resultExpression, data)
|
||||
val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data)
|
||||
if (!resolvingAugmentedAssignment) {
|
||||
dataFlowAnalyzer.exitFunctionCall(result, callCompleted)
|
||||
dataFlowAnalyzer.exitFunctionCall(result, data.forceFullCompletion)
|
||||
}
|
||||
|
||||
addReceiversFromExtensions(result)
|
||||
|
||||
if (callCompleted) {
|
||||
if (enableArrayOfCallTransformation) {
|
||||
return arrayOfCallTransformer.transformFunctionCall(result, null)
|
||||
}
|
||||
if (enableArrayOfCallTransformation) {
|
||||
return arrayOfCallTransformer.transformFunctionCall(result, null)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -970,11 +965,11 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
||||
.transformAnnotations(transformer, ResolutionMode.ContextIndependent)
|
||||
.replaceArgumentList(checkNotNullCall.argumentList.transform(transformer, ResolutionMode.ContextDependent))
|
||||
|
||||
val (result, callCompleted) = callCompleter.completeCall(
|
||||
val result = callCompleter.completeCall(
|
||||
components.syntheticCallGenerator.generateCalleeForCheckNotNullCall(checkNotNullCall, resolutionContext), data
|
||||
)
|
||||
|
||||
dataFlowAnalyzer.exitCheckNotNullCall(result, callCompleted)
|
||||
dataFlowAnalyzer.exitCheckNotNullCall(result, data.forceFullCompletion)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1328,8 +1323,8 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
||||
|
||||
// it seems that we may leave this code as is
|
||||
// without adding `context.withTowerDataContext(context.getTowerDataContextForConstructorResolution())`
|
||||
val (result, callCompleted) = callCompleter.completeCall(resolvedCall, ResolutionMode.ContextIndependent)
|
||||
dataFlowAnalyzer.exitDelegatedConstructorCall(result, callCompleted)
|
||||
val result = callCompleter.completeCall(resolvedCall, ResolutionMode.ContextIndependent)
|
||||
dataFlowAnalyzer.exitDelegatedConstructorCall(result, data.forceFullCompletion)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -706,8 +706,9 @@ digraph kt44814_kt {
|
||||
191 -> {192};
|
||||
192 -> {193};
|
||||
193 -> {194};
|
||||
194 -> {195};
|
||||
194 -> {182} [color=green style=dashed];
|
||||
194 -> {195} [color=green];
|
||||
194 -> {202} [style=dotted];
|
||||
195 -> {196};
|
||||
196 -> {197 201};
|
||||
197 -> {198};
|
||||
|
||||
Reference in New Issue
Block a user