diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 642c01e066c..cccf5729183 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -163,6 +163,16 @@ abstract class FirDataFlowAnalyzer( return graph } + // ----------------------------------- Delegate ----------------------------------- + + fun enterDelegateExpression() { + graphBuilder.enterDelegateExpression() + } + + fun exitDelegateExpression() { + graphBuilder.exitDelegateExpression() + } + // ----------------------------------- Block ----------------------------------- fun enterBlock(block: FirBlock) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 9f17dca3920..12425fe76b4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -58,6 +58,7 @@ class ControlFlowGraphBuilder { private set private var idCounter: Int = 0 + private val shouldPassFlowFromInplaceLambda: Stack = stackOf(true) fun createId(): Int = idCounter++ @@ -142,7 +143,7 @@ class ControlFlowGraphBuilder { } if (postponedExitNode != null) { CFGNode.addEdge(lastNodes.pop(), postponedExitNode, propagateDeadness = true, kind = EdgeKind.Cfg) - if (invocationKind == InvocationKind.EXACTLY_ONCE) { + if (invocationKind == InvocationKind.EXACTLY_ONCE && shouldPassFlowFromInplaceLambda.top()) { exitsFromCompletedPostponedAnonymousFunctions += postponedExitNode } } @@ -262,6 +263,16 @@ class ControlFlowGraphBuilder { return topLevelVariableExitNode to graphs.pop() } + // ----------------------------------- Delegate ----------------------------------- + + fun enterDelegateExpression() { + shouldPassFlowFromInplaceLambda.push(false) + } + + fun exitDelegateExpression() { + shouldPassFlowFromInplaceLambda.pop() + } + // ----------------------------------- Operator call ----------------------------------- fun exitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall): TypeOperatorCallNode { @@ -639,6 +650,7 @@ class ControlFlowGraphBuilder { node: CFGNode<*>, callCompleted: Boolean ): Pair { + if (!shouldPassFlowFromInplaceLambda.top()) return EdgeKind.Simple to null var kind = EdgeKind.Simple if (!callCompleted || exitsFromCompletedPostponedAnonymousFunctions.isEmpty()) { return EdgeKind.Simple to null diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index da71b3077ed..914aea5c216 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -161,18 +161,23 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) wrappedDelegateExpression: FirWrappedDelegateExpression, data: ResolutionMode, ): CompositeTransformResult { - val delegateProvider = wrappedDelegateExpression.delegateProvider.transformSingle(transformer, ResolutionMode.ContextDependent) - when (val calleeReference = (delegateProvider as FirResolvable).calleeReference) { - is FirResolvedNamedReference -> return delegateProvider.compose() - is FirNamedReferenceWithCandidate -> { - val candidate = calleeReference.candidate - if (!candidate.system.hasContradiction) { - return delegateProvider.compose() + dataFlowAnalyzer.enterDelegateExpression() + try { + val delegateProvider = wrappedDelegateExpression.delegateProvider.transformSingle(transformer, ResolutionMode.ContextDependent) + when (val calleeReference = (delegateProvider as FirResolvable).calleeReference) { + is FirResolvedNamedReference -> return delegateProvider.compose() + is FirNamedReferenceWithCandidate -> { + val candidate = calleeReference.candidate + if (!candidate.system.hasContradiction) { + return delegateProvider.compose() + } } } - } - return wrappedDelegateExpression.expression.transform(transformer, ResolutionMode.ContextDependent) + return wrappedDelegateExpression.expression.transform(transformer, ResolutionMode.ContextDependent) + } finally { + dataFlowAnalyzer.exitDelegateExpression() + } } private fun transformLocalVariable(variable: FirProperty): CompositeTransformResult { diff --git a/compiler/fir/resolve/testData/resolve/cfg/postponedLambdaInConstructor.dot b/compiler/fir/resolve/testData/resolve/cfg/postponedLambdaInConstructor.dot index 429615626db..351cbc05efe 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/postponedLambdaInConstructor.dot +++ b/compiler/fir/resolve/testData/resolve/cfg/postponedLambdaInConstructor.dot @@ -27,8 +27,9 @@ digraph postponedLambdaInConstructor_kt { } 10 [label="Postponed exit from lambda"]; 11 [label="Function call: R|/s|.R|kotlin/let| kotlin/String|>(...)"]; - 12 [label="Delegated constructor call: super(...)"]; - 13 [label="Exit function " style="filled" fillcolor=red]; + 12 [label="Call arguments union" style="filled" fillcolor=yellow]; + 13 [label="Delegated constructor call: super(...)"]; + 14 [label="Exit function " style="filled" fillcolor=red]; } 3 -> {4}; @@ -39,46 +40,48 @@ digraph postponedLambdaInConstructor_kt { 7 -> {8 8} [color=green]; 8 -> {9}; 9 -> {10} [color=green]; + 9 -> {12} [color=red]; 10 -> {11}; 11 -> {12}; 12 -> {13}; + 13 -> {14}; subgraph cluster_3 { color=red - 14 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; - 15 [label="Access variable R|/it|"]; - 16 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + 15 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + 16 [label="Access variable R|/it|"]; + 17 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; } - 14 -> {15}; 15 -> {16}; + 16 -> {17}; subgraph cluster_4 { color=red - 17 [label="Enter function getter" style="filled" fillcolor=red]; - 18 [label="Exit function getter" style="filled" fillcolor=red]; + 18 [label="Enter function getter" style="filled" fillcolor=red]; + 19 [label="Exit function getter" style="filled" fillcolor=red]; } - 17 -> {18}; + 18 -> {19}; subgraph cluster_5 { color=red - 19 [label="Enter property" style="filled" fillcolor=red]; - 20 [label="Access variable R|/s|"]; - 21 [label="Exit property" style="filled" fillcolor=red]; + 20 [label="Enter property" style="filled" fillcolor=red]; + 21 [label="Access variable R|/s|"]; + 22 [label="Exit property" style="filled" fillcolor=red]; } - 19 -> {20}; 20 -> {21}; + 21 -> {22}; subgraph cluster_6 { color=red - 22 [label="Enter function foo" style="filled" fillcolor=red]; - 23 [label="Function call: this@R|/B|.R|/B.foo|()"]; - 24 [label="Exit function foo" style="filled" fillcolor=red]; + 23 [label="Enter function foo" style="filled" fillcolor=red]; + 24 [label="Function call: this@R|/B|.R|/B.foo|()"]; + 25 [label="Exit function foo" style="filled" fillcolor=red]; } - 22 -> {23}; 23 -> {24}; + 24 -> {25}; }