diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index c9b82eb14a5..6c6d98ecafc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -69,6 +69,7 @@ class FirCallResolver( qualifiedResolver.reset() @Suppress("NAME_SHADOWING") val functionCall = functionCall.transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) + .also { dataFlowAnalyzer.enterQualifiedAccessExpression(functionCall) } .transformArguments(transformer, ResolutionMode.ContextDependent) val name = functionCall.calleeReference.name 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 d8bda115f29..e13ad86652e 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 @@ -22,13 +22,11 @@ import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* import org.jetbrains.kotlin.fir.resolve.dfa.contracts.buildContractFir import org.jetbrains.kotlin.fir.resolve.dfa.contracts.createArgumentsMapping import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer +import org.jetbrains.kotlin.fir.resolve.withNullability import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.coneTypeSafe -import org.jetbrains.kotlin.fir.types.coneTypeUnsafe -import org.jetbrains.kotlin.fir.types.isMarkedNullable +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.name.FqName @@ -469,21 +467,63 @@ class FirDataFlowAnalyzer(private val components: FirAbstractBodyResolveTransfor // ----------------------------------- Resolvable call ----------------------------------- - fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) { - graphBuilder.exitQualifiedAccessExpression(qualifiedAccessExpression).mergeIncomingFlow() + private fun enterSafeCall(qualifiedAccess: FirQualifiedAccess) { + if (!qualifiedAccess.safe) return + val node = graphBuilder.enterSafeCall(qualifiedAccess).mergeIncomingFlow() + val previousNode = node.alivePreviousNodes.first() + val shouldFork: Boolean + var flow= if (previousNode is ExitSafeCallNode) { + shouldFork = false + previousNode.alivePreviousNodes.getOrNull(1)?.flow ?: node.flow + } else { + shouldFork = true + node.flow + } + qualifiedAccess.explicitReceiver?.let { + val type = it.typeRef.coneTypeSafe() + ?.takeIf { it.isMarkedNullable } + ?.withNullability(ConeNullability.NOT_NULL) + ?: return@let + + when (val variable = getOrCreateVariable(it)) { + is RealDataFlowVariable -> { + if (shouldFork) { + flow = logicSystem.forkFlow(flow) + } + logicSystem.addApprovedInfo(flow, variable, FirDataFlowInfo(setOf(type), emptySet())) + } + is SyntheticDataFlowVariable -> { + flow = logicSystem.approveFactsInsideFlow(variable, NotEqNull, flow, shouldFork, true) + } + } + } + + node.flow = flow } - fun enterFunctionCall(functionCall: FirFunctionCall) { - // TODO: add processing in-place lambdas + private fun exitSafeCall(qualifiedAccess: FirQualifiedAccess) { + if (!qualifiedAccess.safe) return + graphBuilder.exitSafeCall(qualifiedAccess).mergeIncomingFlow() + } + + fun enterQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) { + enterSafeCall(qualifiedAccessExpression) + } + + fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) { + graphBuilder.exitQualifiedAccessExpression(qualifiedAccessExpression).mergeIncomingFlow() + exitSafeCall(qualifiedAccessExpression) } fun exitFunctionCall(functionCall: FirFunctionCall) { val node = graphBuilder.exitFunctionCall(functionCall).mergeIncomingFlow() if (functionCall.isBooleanNot()) { exitBooleanNot(functionCall, node) - return } processConditionalContract(functionCall) + if (functionCall.safe) { + exitSafeCall(functionCall) + } } private fun processConditionalContract(functionCall: FirFunctionCall) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt index c837f7954d4..17ccad0a297 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt @@ -159,6 +159,9 @@ class VariableAssignmentNode(owner: ControlFlowGraph, override val fir: FirVaria class EnterContractNode(owner: ControlFlowGraph, override val fir: FirFunctionCall, level: Int) : CFGNode(owner, level), EnterNode class ExitContractNode(owner: ControlFlowGraph, override val fir: FirFunctionCall, level: Int) : CFGNode(owner, level), ExitNode +class EnterSafeCallNode(owner: ControlFlowGraph, override val fir: FirQualifiedAccess, level: Int) : CFGNode(owner, level) +class ExitSafeCallNode(owner: ControlFlowGraph, override val fir: FirQualifiedAccess, level: Int) : CFGNode(owner, level) + // ----------------------------------- Other ----------------------------------- class AnnotationEnterNode(owner: ControlFlowGraph, override val fir: FirAnnotationCall, level: Int) : CFGNode(owner, level), EnterNode 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 d1fb3a71234..9c54a9faec6 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 @@ -43,6 +43,8 @@ class ControlFlowGraphBuilder { private val initBlockExitNodes: Stack = stackOf() + private val exitSafeCallNodes: Stack = stackOf() + var levelCounter: Int = 0 private set @@ -572,6 +574,25 @@ class ControlFlowGraphBuilder { } } + // ----------------------------------- Safe calls ----------------------------------- + + fun enterSafeCall(qualifiedAccess: FirQualifiedAccess): EnterSafeCallNode { + val lastNode = lastNodes.pop() + val enterNode = createEnterSafeCallNode(qualifiedAccess) + lastNodes.push(enterNode) + val exitNode = createExitSafeCallNode(qualifiedAccess) + exitSafeCallNodes.push(exitNode) + addEdge(lastNode, enterNode) + addEdge(lastNode, exitNode) + return enterNode + } + + fun exitSafeCall(qualifiedAccess: FirQualifiedAccess): ExitSafeCallNode { + return exitSafeCallNodes.pop().also { + addNewSimpleNode(it) + } + } + // ------------------------------------------------------------------------------------------------------------------------- private fun CFGNode<*>.markAsDeadIfNecessary() { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt index e3df5036791..1e1ea0329b8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt @@ -170,4 +170,10 @@ fun ControlFlowGraphBuilder.createBinaryAndEnterRightOperandNode(fir: FirBinaryL BinaryAndEnterRightOperandNode(graph, fir, levelCounter) fun ControlFlowGraphBuilder.createBinaryOrEnterRightOperandNode(fir: FirBinaryLogicExpression): BinaryOrEnterRightOperandNode = - BinaryOrEnterRightOperandNode(graph, fir, levelCounter) \ No newline at end of file + BinaryOrEnterRightOperandNode(graph, fir, levelCounter) + +fun ControlFlowGraphBuilder.createExitSafeCallNode(fir: FirQualifiedAccess): ExitSafeCallNode = + ExitSafeCallNode(graph, fir, levelCounter) + +fun ControlFlowGraphBuilder.createEnterSafeCallNode(fir: FirQualifiedAccess): EnterSafeCallNode = + EnterSafeCallNode(graph, fir, levelCounter) \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt index 187a8371528..038ed621319 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt @@ -149,6 +149,9 @@ fun CFGNode<*>.render(): String = is EnterContractNode -> "Enter contract" is ExitContractNode -> "Exit contract" + is EnterSafeCallNode -> "Enter safe call" + is ExitSafeCallNode -> "Exit safe call" + else -> TODO(this@render.toString()) } ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 003effb4a13..95e43a356e9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl -import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionWithSmartcastImpl import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl import org.jetbrains.kotlin.fir.expressions.impl.FirVariableAssignmentImpl import org.jetbrains.kotlin.fir.references.FirDelegateFieldReference @@ -23,7 +22,6 @@ import org.jetbrains.kotlin.fir.references.impl.FirExplicitThisReference import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* -import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.diagnostics.FirOperatorAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.FirVariableExpectedError @@ -121,6 +119,7 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : } } if (result is FirQualifiedAccessExpression) { + dataFlowAnalyzer.enterQualifiedAccessExpression(result) result = components.transformQualifiedAccessUsingSmartcastInfo(result) dataFlowAnalyzer.exitQualifiedAccessExpression(result) } @@ -131,7 +130,6 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : if (functionCall.calleeReference is FirResolvedNamedReference && functionCall.resultType is FirImplicitTypeRef) { storeTypeFromCallee(functionCall) } - dataFlowAnalyzer.enterFunctionCall(functionCall) if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose() functionCall.transform(InvocationKindTransformer, null) functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent) diff --git a/compiler/fir/resolve/testData/resolve/cfg/safeCalls.dot b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.dot new file mode 100644 index 00000000000..c16a73e091e --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.dot @@ -0,0 +1,112 @@ +digraph safeCalls_kt { + graph [splines=ortho nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function foo" style="filled" fillcolor=red]; + 1 [label="Exit function foo" style="filled" fillcolor=red]; + } + + 0 -> {1}; + + subgraph cluster_1 { + color=red + 2 [label="Enter function bar" style="filled" fillcolor=red]; + 3 [label="Exit function bar" style="filled" fillcolor=red]; + } + + 2 -> {3}; + + subgraph cluster_2 { + color=red + 4 [label="Enter function getter" style="filled" fillcolor=red]; + 5 [label="Exit function getter" style="filled" fillcolor=red]; + } + + 4 -> {5}; + + subgraph cluster_3 { + color=red + 6 [label="Enter property" style="filled" fillcolor=red]; + 7 [label="Exit property" style="filled" fillcolor=red]; + } + + 6 -> {7}; + + subgraph cluster_4 { + color=red + 8 [label="Enter function getter" style="filled" fillcolor=red]; + 9 [label="Exit function getter" style="filled" fillcolor=red]; + } + + 8 -> {9}; + + subgraph cluster_5 { + color=red + 10 [label="Enter property" style="filled" fillcolor=red]; + 11 [label="Exit property" style="filled" fillcolor=red]; + } + + 10 -> {11}; + + subgraph cluster_6 { + color=red + 12 [label="Enter function test_1" style="filled" fillcolor=red]; + subgraph cluster_7 { + color=blue + 13 [label="Enter block"]; + 14 [label="Access variable R|/x|"]; + 15 [label="Enter safe call"]; + 16 [label="Function call: R|/x|?.R|/A.foo|()"]; + 17 [label="Exit safe call"]; + 18 [label="Enter safe call"]; + 19 [label="Function call: R|/x|?.R|/A.foo|()?.R|/A.bar|()"]; + 20 [label="Exit safe call"]; + 21 [label="Exit block"]; + } + 22 [label="Exit function test_1" style="filled" fillcolor=red]; + } + + 12 -> {13}; + 13 -> {14}; + 14 -> {15 17}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18 20}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + + subgraph cluster_8 { + color=red + 23 [label="Enter function test_2" style="filled" fillcolor=red]; + subgraph cluster_9 { + color=blue + 24 [label="Enter block"]; + 25 [label="Access variable R|/x|"]; + 26 [label="Enter safe call"]; + 27 [label="Access variable R|/B.foo|"]; + 28 [label="Exit safe call"]; + 29 [label="Enter safe call"]; + 30 [label="Access variable R|/B.bar|"]; + 31 [label="Exit safe call"]; + 32 [label="Exit block"]; + } + 33 [label="Exit function test_2" style="filled" fillcolor=red]; + } + + 23 -> {24}; + 24 -> {25}; + 25 -> {26 28}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29 31}; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + +} diff --git a/compiler/fir/resolve/testData/resolve/cfg/safeCalls.kt b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.kt new file mode 100644 index 00000000000..e00f9d30b2e --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.kt @@ -0,0 +1,17 @@ +interface A { + fun foo(): A + fun bar(): A +} + +interface B { + val foo: B + val bar: B +} + +fun test_1(x: A?) { + x?.foo()?.bar() +} + +fun test_2(x: B?) { + x?.foo?.bar +} diff --git a/compiler/fir/resolve/testData/resolve/cfg/safeCalls.txt b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.txt new file mode 100644 index 00000000000..0790a8f3ce6 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/safeCalls.txt @@ -0,0 +1,21 @@ +FILE: safeCalls.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|A| + + public abstract fun bar(): R|A| + + } + public abstract interface B : R|kotlin/Any| { + public abstract val foo: R|B| + public get(): R|B| + + public abstract val bar: R|B| + public get(): R|B| + + } + public final fun test_1(x: R|A?|): R|kotlin/Unit| { + R|/x|?.R|/A.foo|()?.R|/A.bar|() + } + public final fun test_2(x: R|B?|): R|kotlin/Unit| { + R|/x|?.R|/B.foo|?.R|/B.bar| + } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/elvis.dot b/compiler/fir/resolve/testData/resolve/smartcasts/elvis.dot index 44be738ba9d..d8c2c8e4b70 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/elvis.dot +++ b/compiler/fir/resolve/testData/resolve/smartcasts/elvis.dot @@ -43,56 +43,58 @@ digraph elvis_kt { color=blue 10 [label="Enter when"]; 11 [label="Access variable R|/x|"]; - 12 [label="Access variable R|/A.b|"]; - 13 [label="Variable declaration: lval : R|kotlin/Boolean?|"]; + 12 [label="Enter safe call"]; + 13 [label="Access variable R|/A.b|"]; + 14 [label="Exit safe call"]; + 15 [label="Variable declaration: lval : R|kotlin/Boolean?|"]; subgraph cluster_8 { color=blue - 14 [label="Enter when branch condition "]; - 15 [label="Const: Null(null)"]; - 16 [label="Operator =="]; - 17 [label="Exit when branch condition"]; + 16 [label="Enter when branch condition "]; + 17 [label="Const: Null(null)"]; + 18 [label="Operator =="]; + 19 [label="Exit when branch condition"]; } subgraph cluster_9 { color=blue - 18 [label="Enter when branch condition else"]; - 19 [label="Exit when branch condition"]; + 20 [label="Enter when branch condition else"]; + 21 [label="Exit when branch condition"]; } - 20 [label="Enter when branch result"]; + 22 [label="Enter when branch result"]; subgraph cluster_10 { color=blue - 21 [label="Enter block"]; - 22 [label="Access variable R|/|"]; - 23 [label="Exit block"]; + 23 [label="Enter block"]; + 24 [label="Access variable R|/|"]; + 25 [label="Exit block"]; } - 24 [label="Exit when branch result"]; - 25 [label="Enter when branch result"]; + 26 [label="Exit when branch result"]; + 27 [label="Enter when branch result"]; subgraph cluster_11 { color=blue - 26 [label="Enter block"]; - 27 [label="Jump: ^test_1 Unit"]; - 28 [label="Stub" style="filled" fillcolor=gray]; - 29 [label="Exit block" style="filled" fillcolor=gray]; + 28 [label="Enter block"]; + 29 [label="Jump: ^test_1 Unit"]; + 30 [label="Stub" style="filled" fillcolor=gray]; + 31 [label="Exit block" style="filled" fillcolor=gray]; } - 30 [label="Exit when branch result" style="filled" fillcolor=gray]; - 31 [label="Exit when"]; + 32 [label="Exit when branch result" style="filled" fillcolor=gray]; + 33 [label="Exit when"]; } - 32 [label="Exit when branch condition"]; + 34 [label="Exit when branch condition"]; } - 33 [label="Synthetic else branch"]; - 34 [label="Enter when branch result"]; + 35 [label="Synthetic else branch"]; + 36 [label="Enter when branch result"]; subgraph cluster_12 { color=blue - 35 [label="Enter block"]; - 36 [label="Access variable R|/x|"]; - 37 [label="Function call: R|/x|.R|/A.foo|()"]; - 38 [label="Exit block"]; + 37 [label="Enter block"]; + 38 [label="Access variable R|/x|"]; + 39 [label="Function call: R|/x|.R|/A.foo|()"]; + 40 [label="Exit block"]; } - 39 [label="Exit when branch result"]; - 40 [label="Exit when"]; + 41 [label="Exit when branch result"]; + 42 [label="Exit when"]; } - 41 [label="Exit block"]; + 43 [label="Exit block"]; } - 42 [label="Exit function test_1" style="filled" fillcolor=red]; + 44 [label="Exit function test_1" style="filled" fillcolor=red]; } 6 -> {7}; @@ -100,127 +102,129 @@ digraph elvis_kt { 8 -> {9}; 9 -> {10}; 10 -> {11}; - 11 -> {12}; + 11 -> {12 14}; 12 -> {13}; 13 -> {14}; 14 -> {15}; 15 -> {16}; 16 -> {17}; - 17 -> {25 18}; + 17 -> {18}; 18 -> {19}; - 19 -> {20}; + 19 -> {27 20}; 20 -> {21}; 21 -> {22}; 22 -> {23}; 23 -> {24}; - 24 -> {31}; + 24 -> {25}; 25 -> {26}; - 26 -> {27}; - 27 -> {42}; - 27 -> {28} [style=dotted]; - 28 -> {29} [style=dotted]; + 26 -> {33}; + 27 -> {28}; + 28 -> {29}; + 29 -> {44}; 29 -> {30} [style=dotted]; 30 -> {31} [style=dotted]; - 31 -> {32}; - 32 -> {34 33}; - 33 -> {40}; - 34 -> {35}; - 35 -> {36}; + 31 -> {32} [style=dotted]; + 32 -> {33} [style=dotted]; + 33 -> {34}; + 34 -> {36 35}; + 35 -> {42}; 36 -> {37}; 37 -> {38}; 38 -> {39}; 39 -> {40}; 40 -> {41}; 41 -> {42}; + 42 -> {43}; + 43 -> {44}; subgraph cluster_13 { color=red - 43 [label="Enter function test2" style="filled" fillcolor=red]; + 45 [label="Enter function test2" style="filled" fillcolor=red]; subgraph cluster_14 { color=blue - 44 [label="Enter block"]; + 46 [label="Enter block"]; subgraph cluster_15 { color=blue - 45 [label="Enter when"]; + 47 [label="Enter when"]; subgraph cluster_16 { color=blue - 46 [label="Enter when branch condition "]; - 47 [label="Access variable R|/b|"]; - 48 [label="Type operator: b !is String"]; - 49 [label="Exit when branch condition"]; + 48 [label="Enter when branch condition "]; + 49 [label="Access variable R|/b|"]; + 50 [label="Type operator: b !is String"]; + 51 [label="Exit when branch condition"]; } - 50 [label="Synthetic else branch"]; - 51 [label="Enter when branch result"]; + 52 [label="Synthetic else branch"]; + 53 [label="Enter when branch result"]; subgraph cluster_17 { color=blue - 52 [label="Enter block"]; - 53 [label="Const: String()"]; - 54 [label="Jump: ^test2 String()"]; - 55 [label="Stub" style="filled" fillcolor=gray]; - 56 [label="Exit block" style="filled" fillcolor=gray]; + 54 [label="Enter block"]; + 55 [label="Const: String()"]; + 56 [label="Jump: ^test2 String()"]; + 57 [label="Stub" style="filled" fillcolor=gray]; + 58 [label="Exit block" style="filled" fillcolor=gray]; } - 57 [label="Exit when branch result" style="filled" fillcolor=gray]; - 58 [label="Exit when"]; + 59 [label="Exit when branch result" style="filled" fillcolor=gray]; + 60 [label="Exit when"]; } subgraph cluster_18 { color=blue - 59 [label="Enter when"]; + 61 [label="Enter when"]; subgraph cluster_19 { color=blue - 60 [label="Enter when branch condition "]; - 61 [label="Access variable R|/a|"]; - 62 [label="Type operator: a !is String?"]; - 63 [label="Exit when branch condition"]; + 62 [label="Enter when branch condition "]; + 63 [label="Access variable R|/a|"]; + 64 [label="Type operator: a !is String?"]; + 65 [label="Exit when branch condition"]; } - 64 [label="Synthetic else branch"]; - 65 [label="Enter when branch result"]; + 66 [label="Synthetic else branch"]; + 67 [label="Enter when branch result"]; subgraph cluster_20 { color=blue - 66 [label="Enter block"]; - 67 [label="Const: String()"]; - 68 [label="Jump: ^test2 String()"]; - 69 [label="Stub" style="filled" fillcolor=gray]; - 70 [label="Exit block" style="filled" fillcolor=gray]; + 68 [label="Enter block"]; + 69 [label="Const: String()"]; + 70 [label="Jump: ^test2 String()"]; + 71 [label="Stub" style="filled" fillcolor=gray]; + 72 [label="Exit block" style="filled" fillcolor=gray]; } - 71 [label="Exit when branch result" style="filled" fillcolor=gray]; - 72 [label="Exit when"]; + 73 [label="Exit when branch result" style="filled" fillcolor=gray]; + 74 [label="Exit when"]; } subgraph cluster_21 { color=blue - 73 [label="Enter when"]; - 74 [label="Access variable R|/a|"]; - 75 [label="Variable declaration: lval : R|kotlin/String?|"]; + 75 [label="Enter when"]; + 76 [label="Access variable R|/a|"]; + 77 [label="Variable declaration: lval : R|kotlin/String?|"]; subgraph cluster_22 { color=blue - 76 [label="Enter when branch condition "]; - 77 [label="Const: Null(null)"]; - 78 [label="Operator =="]; - 79 [label="Exit when branch condition"]; + 78 [label="Enter when branch condition "]; + 79 [label="Const: Null(null)"]; + 80 [label="Operator =="]; + 81 [label="Exit when branch condition"]; } subgraph cluster_23 { color=blue - 80 [label="Enter when branch condition else"]; - 81 [label="Exit when branch condition"]; + 82 [label="Enter when branch condition else"]; + 83 [label="Exit when branch condition"]; } - 82 [label="Enter when branch result"]; + 84 [label="Enter when branch result"]; subgraph cluster_24 { color=blue - 83 [label="Enter block"]; - 84 [label="Access variable R|/|"]; - 85 [label="Exit block"]; + 85 [label="Enter block"]; + 86 [label="Access variable R|/|"]; + 87 [label="Exit block"]; } - 86 [label="Exit when branch result"]; - 87 [label="Enter when branch result"]; + 88 [label="Exit when branch result"]; + 89 [label="Enter when branch result"]; subgraph cluster_25 { color=blue - 88 [label="Enter block"]; - 89 [label="Access variable R|/b|"]; - 90 [label="Exit block"]; + 90 [label="Enter block"]; + 91 [label="Access variable R|/b|"]; + 92 [label="Exit block"]; } - 91 [label="Exit when branch result"]; - 92 [label="Exit when"]; + 93 [label="Exit when branch result"]; + 94 [label="Exit when"]; } - 93 [label="Jump: ^test2 when (lval : R|kotlin/String?| = R|/a|) { + 95 [label="Jump: ^test2 when (lval : R|kotlin/String?| = R|/a|) { ==($subj$, Null(null)) -> { R|/b| } @@ -229,67 +233,67 @@ digraph elvis_kt { } } "]; - 94 [label="Stub" style="filled" fillcolor=gray]; - 95 [label="Exit block" style="filled" fillcolor=gray]; + 96 [label="Stub" style="filled" fillcolor=gray]; + 97 [label="Exit block" style="filled" fillcolor=gray]; } - 96 [label="Exit function test2" style="filled" fillcolor=red]; + 98 [label="Exit function test2" style="filled" fillcolor=red]; } - 43 -> {44}; - 44 -> {45}; 45 -> {46}; 46 -> {47}; 47 -> {48}; 48 -> {49}; - 49 -> {51 50}; - 50 -> {58}; - 51 -> {52}; - 52 -> {53}; + 49 -> {50}; + 50 -> {51}; + 51 -> {53 52}; + 52 -> {60}; 53 -> {54}; - 54 -> {96}; - 54 -> {55} [style=dotted]; - 55 -> {56} [style=dotted]; + 54 -> {55}; + 55 -> {56}; + 56 -> {98}; 56 -> {57} [style=dotted]; 57 -> {58} [style=dotted]; - 58 -> {59}; - 59 -> {60}; + 58 -> {59} [style=dotted]; + 59 -> {60} [style=dotted]; 60 -> {61}; 61 -> {62}; 62 -> {63}; - 63 -> {65 64}; - 64 -> {72}; - 65 -> {66}; - 66 -> {67}; + 63 -> {64}; + 64 -> {65}; + 65 -> {67 66}; + 66 -> {74}; 67 -> {68}; - 68 -> {96}; - 68 -> {69} [style=dotted]; - 69 -> {70} [style=dotted]; + 68 -> {69}; + 69 -> {70}; + 70 -> {98}; 70 -> {71} [style=dotted]; 71 -> {72} [style=dotted]; - 72 -> {73}; - 73 -> {74}; + 72 -> {73} [style=dotted]; + 73 -> {74} [style=dotted]; 74 -> {75}; 75 -> {76}; 76 -> {77}; 77 -> {78}; 78 -> {79}; - 79 -> {87 80}; + 79 -> {80}; 80 -> {81}; - 81 -> {82}; + 81 -> {89 82}; 82 -> {83}; 83 -> {84}; 84 -> {85}; 85 -> {86}; - 86 -> {92}; + 86 -> {87}; 87 -> {88}; - 88 -> {89}; + 88 -> {94}; 89 -> {90}; 90 -> {91}; 91 -> {92}; 92 -> {93}; - 93 -> {96}; - 93 -> {94} [style=dotted]; - 94 -> {95} [style=dotted]; + 93 -> {94}; + 94 -> {95}; + 95 -> {98}; 95 -> {96} [style=dotted]; + 96 -> {97} [style=dotted]; + 97 -> {98} [style=dotted]; } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.dot b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.dot index 6496ab55ed4..36e1c72d686 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.dot +++ b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.dot @@ -309,116 +309,124 @@ digraph nullability_kt { color=blue 100 [label="Enter when branch condition "]; 101 [label="Access variable R|/x|"]; - 102 [label="Function call: R|/x|?.R|/A.getA|()"]; - 103 [label="Const: Null(null)"]; - 104 [label="Operator =="]; - 105 [label="Exit when branch condition"]; + 102 [label="Enter safe call"]; + 103 [label="Function call: R|/x|?.R|/A.getA|()"]; + 104 [label="Exit safe call"]; + 105 [label="Const: Null(null)"]; + 106 [label="Operator =="]; + 107 [label="Exit when branch condition"]; } - 106 [label="Synthetic else branch"]; - 107 [label="Enter when branch result"]; + 108 [label="Synthetic else branch"]; + 109 [label="Enter when branch result"]; subgraph cluster_33 { color=blue - 108 [label="Enter block"]; - 109 [label="Jump: ^test_4 Unit"]; - 110 [label="Stub" style="filled" fillcolor=gray]; - 111 [label="Exit block" style="filled" fillcolor=gray]; + 110 [label="Enter block"]; + 111 [label="Jump: ^test_4 Unit"]; + 112 [label="Stub" style="filled" fillcolor=gray]; + 113 [label="Exit block" style="filled" fillcolor=gray]; } - 112 [label="Exit when branch result" style="filled" fillcolor=gray]; - 113 [label="Exit when"]; + 114 [label="Exit when branch result" style="filled" fillcolor=gray]; + 115 [label="Exit when"]; } - 114 [label="Access variable R|/x|"]; - 115 [label="Function call: R|/x|.R|/A.foo|()"]; - 116 [label="Exit block"]; + 116 [label="Access variable R|/x|"]; + 117 [label="Function call: R|/x|.R|/A.foo|()"]; + 118 [label="Exit block"]; } - 117 [label="Exit function test_4" style="filled" fillcolor=red]; + 119 [label="Exit function test_4" style="filled" fillcolor=red]; } 97 -> {98}; 98 -> {99}; 99 -> {100}; 100 -> {101}; - 101 -> {102}; + 101 -> {102 104}; 102 -> {103}; 103 -> {104}; 104 -> {105}; - 105 -> {107 106}; - 106 -> {113}; - 107 -> {108}; - 108 -> {109}; - 109 -> {117}; - 109 -> {110} [style=dotted]; - 110 -> {111} [style=dotted]; + 105 -> {106}; + 106 -> {107}; + 107 -> {109 108}; + 108 -> {115}; + 109 -> {110}; + 110 -> {111}; + 111 -> {119}; 111 -> {112} [style=dotted]; 112 -> {113} [style=dotted]; - 113 -> {114}; - 114 -> {115}; + 113 -> {114} [style=dotted]; + 114 -> {115} [style=dotted]; 115 -> {116}; 116 -> {117}; + 117 -> {118}; + 118 -> {119}; subgraph cluster_34 { color=red - 118 [label="Enter function test_5" style="filled" fillcolor=red]; + 120 [label="Enter function test_5" style="filled" fillcolor=red]; subgraph cluster_35 { color=blue - 119 [label="Enter block"]; + 121 [label="Enter block"]; subgraph cluster_36 { color=blue - 120 [label="Enter when"]; + 122 [label="Enter when"]; subgraph cluster_37 { color=blue - 121 [label="Enter when branch condition "]; - 122 [label="Access variable R|/q|"]; - 123 [label="Access variable R|/Q.data|"]; - 124 [label="Access variable R|/MyData.s|"]; - 125 [label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; - 126 [label="Const: Null(null)"]; - 127 [label="Operator !="]; - 128 [label="Exit when branch condition"]; + 123 [label="Enter when branch condition "]; + 124 [label="Access variable R|/q|"]; + 125 [label="Enter safe call"]; + 126 [label="Access variable R|/Q.data|"]; + 127 [label="Exit safe call"]; + 128 [label="Enter safe call"]; + 129 [label="Access variable R|/MyData.s|"]; + 130 [label="Exit safe call"]; + 131 [label="Enter safe call"]; + 132 [label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; + 133 [label="Exit safe call"]; + 134 [label="Const: Null(null)"]; + 135 [label="Operator !="]; + 136 [label="Exit when branch condition"]; } - 129 [label="Synthetic else branch"]; - 130 [label="Enter when branch result"]; + 137 [label="Synthetic else branch"]; + 138 [label="Enter when branch result"]; subgraph cluster_38 { color=blue - 131 [label="Enter block"]; - 132 [label="Access variable R|/q|"]; - 133 [label="Access variable R|/Q.data|"]; - 134 [label="Access variable R|/q|"]; - 135 [label="Access variable R|/Q.data|"]; - 136 [label="Access variable R|/MyData.s|"]; - 137 [label="Access variable R|/q|"]; - 138 [label="Access variable R|/Q.data|"]; - 139 [label="Access variable R|/MyData.s|"]; - 140 [label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; - 141 [label="Exit block"]; + 139 [label="Enter block"]; + 140 [label="Access variable R|/q|"]; + 141 [label="Access variable R|/Q.data|"]; + 142 [label="Access variable R|/q|"]; + 143 [label="Access variable R|/Q.data|"]; + 144 [label="Access variable R|/MyData.s|"]; + 145 [label="Access variable R|/q|"]; + 146 [label="Access variable R|/Q.data|"]; + 147 [label="Access variable R|/MyData.s|"]; + 148 [label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 149 [label="Exit block"]; } - 142 [label="Exit when branch result"]; - 143 [label="Exit when"]; + 150 [label="Exit when branch result"]; + 151 [label="Exit when"]; } - 144 [label="Exit block"]; + 152 [label="Exit block"]; } - 145 [label="Exit function test_5" style="filled" fillcolor=red]; + 153 [label="Exit function test_5" style="filled" fillcolor=red]; } - 118 -> {119}; - 119 -> {120}; 120 -> {121}; 121 -> {122}; 122 -> {123}; 123 -> {124}; - 124 -> {125}; + 124 -> {125 127}; 125 -> {126}; 126 -> {127}; - 127 -> {128}; - 128 -> {130 129}; - 129 -> {143}; - 130 -> {131}; + 127 -> {128 130}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131 133}; 131 -> {132}; 132 -> {133}; 133 -> {134}; 134 -> {135}; 135 -> {136}; - 136 -> {137}; - 137 -> {138}; + 136 -> {138 137}; + 137 -> {151}; 138 -> {139}; 139 -> {140}; 140 -> {141}; @@ -426,66 +434,7 @@ digraph nullability_kt { 142 -> {143}; 143 -> {144}; 144 -> {145}; - - subgraph cluster_39 { - color=red - 146 [label="Enter function test_6" style="filled" fillcolor=red]; - subgraph cluster_40 { - color=blue - 147 [label="Enter block"]; - subgraph cluster_41 { - color=blue - 148 [label="Enter when"]; - 149 [label="Access variable R|/q|"]; - 150 [label="Access variable R|/Q.data|"]; - 151 [label="Access variable R|/MyData.s|"]; - 152 [label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; - 153 [label="Variable declaration: lval : R|kotlin/Int?|"]; - subgraph cluster_42 { - color=blue - 154 [label="Enter when branch condition "]; - 155 [label="Const: Null(null)"]; - 156 [label="Operator =="]; - 157 [label="Exit when branch condition"]; - } - subgraph cluster_43 { - color=blue - 158 [label="Enter when branch condition else"]; - 159 [label="Exit when branch condition"]; - } - 160 [label="Enter when branch result"]; - subgraph cluster_44 { - color=blue - 161 [label="Enter block"]; - 162 [label="Access variable R|/|"]; - 163 [label="Exit block"]; - } - 164 [label="Exit when branch result"]; - 165 [label="Enter when branch result"]; - subgraph cluster_45 { - color=blue - 166 [label="Enter block"]; - 167 [label="Jump: ^test_6 Unit"]; - 168 [label="Stub" style="filled" fillcolor=gray]; - 169 [label="Exit block" style="filled" fillcolor=gray]; - } - 170 [label="Exit when branch result" style="filled" fillcolor=gray]; - 171 [label="Exit when"]; - } - 172 [label="Access variable R|/q|"]; - 173 [label="Access variable R|/Q.data|"]; - 174 [label="Access variable R|/q|"]; - 175 [label="Access variable R|/Q.data|"]; - 176 [label="Access variable R|/MyData.s|"]; - 177 [label="Access variable R|/q|"]; - 178 [label="Access variable R|/Q.data|"]; - 179 [label="Access variable R|/MyData.s|"]; - 180 [label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; - 181 [label="Exit block"]; - } - 182 [label="Exit function test_6" style="filled" fillcolor=red]; - } - + 145 -> {146}; 146 -> {147}; 147 -> {148}; 148 -> {149}; @@ -493,83 +442,104 @@ digraph nullability_kt { 150 -> {151}; 151 -> {152}; 152 -> {153}; - 153 -> {154}; + + subgraph cluster_39 { + color=red + 154 [label="Enter function test_6" style="filled" fillcolor=red]; + subgraph cluster_40 { + color=blue + 155 [label="Enter block"]; + subgraph cluster_41 { + color=blue + 156 [label="Enter when"]; + 157 [label="Access variable R|/q|"]; + 158 [label="Enter safe call"]; + 159 [label="Access variable R|/Q.data|"]; + 160 [label="Exit safe call"]; + 161 [label="Enter safe call"]; + 162 [label="Access variable R|/MyData.s|"]; + 163 [label="Exit safe call"]; + 164 [label="Enter safe call"]; + 165 [label="Function call: R|/q|?.R|/Q.data|?.R|/MyData.s|?.R|kotlin/Int.inc|()"]; + 166 [label="Exit safe call"]; + 167 [label="Variable declaration: lval : R|kotlin/Int?|"]; + subgraph cluster_42 { + color=blue + 168 [label="Enter when branch condition "]; + 169 [label="Const: Null(null)"]; + 170 [label="Operator =="]; + 171 [label="Exit when branch condition"]; + } + subgraph cluster_43 { + color=blue + 172 [label="Enter when branch condition else"]; + 173 [label="Exit when branch condition"]; + } + 174 [label="Enter when branch result"]; + subgraph cluster_44 { + color=blue + 175 [label="Enter block"]; + 176 [label="Access variable R|/|"]; + 177 [label="Exit block"]; + } + 178 [label="Exit when branch result"]; + 179 [label="Enter when branch result"]; + subgraph cluster_45 { + color=blue + 180 [label="Enter block"]; + 181 [label="Jump: ^test_6 Unit"]; + 182 [label="Stub" style="filled" fillcolor=gray]; + 183 [label="Exit block" style="filled" fillcolor=gray]; + } + 184 [label="Exit when branch result" style="filled" fillcolor=gray]; + 185 [label="Exit when"]; + } + 186 [label="Access variable R|/q|"]; + 187 [label="Access variable R|/Q.data|"]; + 188 [label="Access variable R|/q|"]; + 189 [label="Access variable R|/Q.data|"]; + 190 [label="Access variable R|/MyData.s|"]; + 191 [label="Access variable R|/q|"]; + 192 [label="Access variable R|/Q.data|"]; + 193 [label="Access variable R|/MyData.s|"]; + 194 [label="Function call: R|/q|.R|/Q.data|.R|/MyData.s|.R|kotlin/Int.inc|()"]; + 195 [label="Exit block"]; + } + 196 [label="Exit function test_6" style="filled" fillcolor=red]; + } + 154 -> {155}; 155 -> {156}; 156 -> {157}; - 157 -> {165 158}; + 157 -> {158 160}; 158 -> {159}; 159 -> {160}; - 160 -> {161}; + 160 -> {161 163}; 161 -> {162}; 162 -> {163}; - 163 -> {164}; - 164 -> {171}; + 163 -> {164 166}; + 164 -> {165}; 165 -> {166}; 166 -> {167}; - 167 -> {182}; - 167 -> {168} [style=dotted]; - 168 -> {169} [style=dotted]; - 169 -> {170} [style=dotted]; - 170 -> {171} [style=dotted]; - 171 -> {172}; + 167 -> {168}; + 168 -> {169}; + 169 -> {170}; + 170 -> {171}; + 171 -> {179 172}; 172 -> {173}; 173 -> {174}; 174 -> {175}; 175 -> {176}; 176 -> {177}; 177 -> {178}; - 178 -> {179}; + 178 -> {185}; 179 -> {180}; 180 -> {181}; - 181 -> {182}; - - subgraph cluster_46 { - color=red - 183 [label="Enter function test_7" style="filled" fillcolor=red]; - subgraph cluster_47 { - color=blue - 184 [label="Enter block"]; - subgraph cluster_48 { - color=blue - 185 [label="Enter when"]; - subgraph cluster_49 { - color=blue - 186 [label="Enter when branch condition "]; - 187 [label="Access variable R|/q|"]; - 188 [label="Function call: R|/q|?.R|/Q.fdata|()"]; - 189 [label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()"]; - 190 [label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()?.R|kotlin/Int.inc|()"]; - 191 [label="Const: Null(null)"]; - 192 [label="Operator !="]; - 193 [label="Exit when branch condition"]; - } - 194 [label="Synthetic else branch"]; - 195 [label="Enter when branch result"]; - subgraph cluster_50 { - color=blue - 196 [label="Enter block"]; - 197 [label="Access variable R|/q|"]; - 198 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 199 [label="Access variable R|/q|"]; - 200 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 201 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; - 202 [label="Access variable R|/q|"]; - 203 [label="Function call: R|/q|.R|/Q.fdata|()"]; - 204 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; - 205 [label="Function call: R|/q|.R|/Q.fdata|().#().#()"]; - 206 [label="Exit block"]; - } - 207 [label="Exit when branch result"]; - 208 [label="Exit when"]; - } - 209 [label="Exit block"]; - } - 210 [label="Exit function test_7" style="filled" fillcolor=red]; - } - - 183 -> {184}; - 184 -> {185}; + 181 -> {196}; + 181 -> {182} [style=dotted]; + 182 -> {183} [style=dotted]; + 183 -> {184} [style=dotted]; + 184 -> {185} [style=dotted]; 185 -> {186}; 186 -> {187}; 187 -> {188}; @@ -578,67 +548,83 @@ digraph nullability_kt { 190 -> {191}; 191 -> {192}; 192 -> {193}; - 193 -> {195 194}; - 194 -> {208}; + 193 -> {194}; + 194 -> {195}; 195 -> {196}; - 196 -> {197}; + + subgraph cluster_46 { + color=red + 197 [label="Enter function test_7" style="filled" fillcolor=red]; + subgraph cluster_47 { + color=blue + 198 [label="Enter block"]; + subgraph cluster_48 { + color=blue + 199 [label="Enter when"]; + subgraph cluster_49 { + color=blue + 200 [label="Enter when branch condition "]; + 201 [label="Access variable R|/q|"]; + 202 [label="Enter safe call"]; + 203 [label="Function call: R|/q|?.R|/Q.fdata|()"]; + 204 [label="Exit safe call"]; + 205 [label="Enter safe call"]; + 206 [label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()"]; + 207 [label="Exit safe call"]; + 208 [label="Enter safe call"]; + 209 [label="Function call: R|/q|?.R|/Q.fdata|()?.R|/MyData.fs|()?.R|kotlin/Int.inc|()"]; + 210 [label="Exit safe call"]; + 211 [label="Const: Null(null)"]; + 212 [label="Operator !="]; + 213 [label="Exit when branch condition"]; + } + 214 [label="Synthetic else branch"]; + 215 [label="Enter when branch result"]; + subgraph cluster_50 { + color=blue + 216 [label="Enter block"]; + 217 [label="Access variable R|/q|"]; + 218 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 219 [label="Access variable R|/q|"]; + 220 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 221 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 222 [label="Access variable R|/q|"]; + 223 [label="Function call: R|/q|.R|/Q.fdata|()"]; + 224 [label="Function call: R|/q|.R|/Q.fdata|().#()"]; + 225 [label="Function call: R|/q|.R|/Q.fdata|().#().#()"]; + 226 [label="Exit block"]; + } + 227 [label="Exit when branch result"]; + 228 [label="Exit when"]; + } + 229 [label="Exit block"]; + } + 230 [label="Exit function test_7" style="filled" fillcolor=red]; + } + 197 -> {198}; 198 -> {199}; 199 -> {200}; 200 -> {201}; - 201 -> {202}; + 201 -> {202 204}; 202 -> {203}; 203 -> {204}; - 204 -> {205}; + 204 -> {205 207}; 205 -> {206}; 206 -> {207}; - 207 -> {208}; + 207 -> {208 210}; 208 -> {209}; 209 -> {210}; - - subgraph cluster_51 { - color=red - 211 [label="Enter function test_8" style="filled" fillcolor=red]; - subgraph cluster_52 { - color=blue - 212 [label="Enter block"]; - subgraph cluster_53 { - color=blue - 213 [label="Enter when"]; - subgraph cluster_54 { - color=blue - 214 [label="Enter when branch condition "]; - 215 [label="Access variable R|/b|"]; - 216 [label="Const: Boolean(true)"]; - 217 [label="Operator =="]; - 218 [label="Exit when branch condition"]; - } - 219 [label="Synthetic else branch"]; - 220 [label="Enter when branch result"]; - subgraph cluster_55 { - color=blue - 221 [label="Enter block"]; - 222 [label="Access variable R|/b|"]; - 223 [label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; - 224 [label="Exit block"]; - } - 225 [label="Exit when branch result"]; - 226 [label="Exit when"]; - } - 227 [label="Exit block"]; - } - 228 [label="Exit function test_8" style="filled" fillcolor=red]; - } - + 210 -> {211}; 211 -> {212}; 212 -> {213}; - 213 -> {214}; - 214 -> {215}; + 213 -> {215 214}; + 214 -> {228}; 215 -> {216}; 216 -> {217}; 217 -> {218}; - 218 -> {220 219}; - 219 -> {226}; + 218 -> {219}; + 219 -> {220}; 220 -> {221}; 221 -> {222}; 222 -> {223}; @@ -647,129 +633,52 @@ digraph nullability_kt { 225 -> {226}; 226 -> {227}; 227 -> {228}; + 228 -> {229}; + 229 -> {230}; - subgraph cluster_56 { + subgraph cluster_51 { color=red - 229 [label="Enter function test_9" style="filled" fillcolor=red]; - subgraph cluster_57 { + 231 [label="Enter function test_8" style="filled" fillcolor=red]; + subgraph cluster_52 { color=blue - 230 [label="Enter block"]; - subgraph cluster_58 { + 232 [label="Enter block"]; + subgraph cluster_53 { color=blue - 231 [label="Enter when"]; - subgraph cluster_59 { + 233 [label="Enter when"]; + subgraph cluster_54 { color=blue - 232 [label="Enter when branch condition "]; - 233 [label="Access variable R|/a|"]; - 234 [label="Access variable R|/b|"]; - 235 [label="Operator =="]; - 236 [label="Exit when branch condition"]; + 234 [label="Enter when branch condition "]; + 235 [label="Access variable R|/b|"]; + 236 [label="Const: Boolean(true)"]; + 237 [label="Operator =="]; + 238 [label="Exit when branch condition"]; } - 237 [label="Synthetic else branch"]; - 238 [label="Enter when branch result"]; - subgraph cluster_60 { + 239 [label="Synthetic else branch"]; + 240 [label="Enter when branch result"]; + subgraph cluster_55 { color=blue - 239 [label="Enter block"]; - 240 [label="Access variable R|/b|"]; - 241 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 242 [label="Exit block"]; + 241 [label="Enter block"]; + 242 [label="Access variable R|/b|"]; + 243 [label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 244 [label="Exit block"]; } - 243 [label="Exit when branch result"]; - 244 [label="Exit when"]; + 245 [label="Exit when branch result"]; + 246 [label="Exit when"]; } - 245 [label="Access variable R|/b|"]; - 246 [label="Function call: R|/b|.#()"]; - subgraph cluster_61 { - color=blue - 247 [label="Enter when"]; - subgraph cluster_62 { - color=blue - 248 [label="Enter when branch condition "]; - 249 [label="Access variable R|/a|"]; - 250 [label="Access variable R|/b|"]; - 251 [label="Operator ==="]; - 252 [label="Exit when branch condition"]; - } - 253 [label="Synthetic else branch"]; - 254 [label="Enter when branch result"]; - subgraph cluster_63 { - color=blue - 255 [label="Enter block"]; - 256 [label="Access variable R|/b|"]; - 257 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 258 [label="Exit block"]; - } - 259 [label="Exit when branch result"]; - 260 [label="Exit when"]; - } - 261 [label="Access variable R|/b|"]; - 262 [label="Function call: R|/b|.#()"]; - subgraph cluster_64 { - color=blue - 263 [label="Enter when"]; - subgraph cluster_65 { - color=blue - 264 [label="Enter when branch condition "]; - 265 [label="Access variable R|/b|"]; - 266 [label="Access variable R|/a|"]; - 267 [label="Operator =="]; - 268 [label="Exit when branch condition"]; - } - 269 [label="Synthetic else branch"]; - 270 [label="Enter when branch result"]; - subgraph cluster_66 { - color=blue - 271 [label="Enter block"]; - 272 [label="Access variable R|/b|"]; - 273 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 274 [label="Exit block"]; - } - 275 [label="Exit when branch result"]; - 276 [label="Exit when"]; - } - 277 [label="Access variable R|/b|"]; - 278 [label="Function call: R|/b|.#()"]; - subgraph cluster_67 { - color=blue - 279 [label="Enter when"]; - subgraph cluster_68 { - color=blue - 280 [label="Enter when branch condition "]; - 281 [label="Access variable R|/b|"]; - 282 [label="Access variable R|/a|"]; - 283 [label="Operator ==="]; - 284 [label="Exit when branch condition"]; - } - 285 [label="Synthetic else branch"]; - 286 [label="Enter when branch result"]; - subgraph cluster_69 { - color=blue - 287 [label="Enter block"]; - 288 [label="Access variable R|/b|"]; - 289 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; - 290 [label="Exit block"]; - } - 291 [label="Exit when branch result"]; - 292 [label="Exit when"]; - } - 293 [label="Access variable R|/b|"]; - 294 [label="Function call: R|/b|.#()"]; - 295 [label="Exit block"]; + 247 [label="Exit block"]; } - 296 [label="Exit function test_9" style="filled" fillcolor=red]; + 248 [label="Exit function test_8" style="filled" fillcolor=red]; } - 229 -> {230}; - 230 -> {231}; 231 -> {232}; 232 -> {233}; 233 -> {234}; 234 -> {235}; 235 -> {236}; - 236 -> {238 237}; - 237 -> {244}; - 238 -> {239}; - 239 -> {240}; + 236 -> {237}; + 237 -> {238}; + 238 -> {240 239}; + 239 -> {246}; 240 -> {241}; 241 -> {242}; 242 -> {243}; @@ -778,16 +687,127 @@ digraph nullability_kt { 245 -> {246}; 246 -> {247}; 247 -> {248}; - 248 -> {249}; + + subgraph cluster_56 { + color=red + 249 [label="Enter function test_9" style="filled" fillcolor=red]; + subgraph cluster_57 { + color=blue + 250 [label="Enter block"]; + subgraph cluster_58 { + color=blue + 251 [label="Enter when"]; + subgraph cluster_59 { + color=blue + 252 [label="Enter when branch condition "]; + 253 [label="Access variable R|/a|"]; + 254 [label="Access variable R|/b|"]; + 255 [label="Operator =="]; + 256 [label="Exit when branch condition"]; + } + 257 [label="Synthetic else branch"]; + 258 [label="Enter when branch result"]; + subgraph cluster_60 { + color=blue + 259 [label="Enter block"]; + 260 [label="Access variable R|/b|"]; + 261 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 262 [label="Exit block"]; + } + 263 [label="Exit when branch result"]; + 264 [label="Exit when"]; + } + 265 [label="Access variable R|/b|"]; + 266 [label="Function call: R|/b|.#()"]; + subgraph cluster_61 { + color=blue + 267 [label="Enter when"]; + subgraph cluster_62 { + color=blue + 268 [label="Enter when branch condition "]; + 269 [label="Access variable R|/a|"]; + 270 [label="Access variable R|/b|"]; + 271 [label="Operator ==="]; + 272 [label="Exit when branch condition"]; + } + 273 [label="Synthetic else branch"]; + 274 [label="Enter when branch result"]; + subgraph cluster_63 { + color=blue + 275 [label="Enter block"]; + 276 [label="Access variable R|/b|"]; + 277 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 278 [label="Exit block"]; + } + 279 [label="Exit when branch result"]; + 280 [label="Exit when"]; + } + 281 [label="Access variable R|/b|"]; + 282 [label="Function call: R|/b|.#()"]; + subgraph cluster_64 { + color=blue + 283 [label="Enter when"]; + subgraph cluster_65 { + color=blue + 284 [label="Enter when branch condition "]; + 285 [label="Access variable R|/b|"]; + 286 [label="Access variable R|/a|"]; + 287 [label="Operator =="]; + 288 [label="Exit when branch condition"]; + } + 289 [label="Synthetic else branch"]; + 290 [label="Enter when branch result"]; + subgraph cluster_66 { + color=blue + 291 [label="Enter block"]; + 292 [label="Access variable R|/b|"]; + 293 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 294 [label="Exit block"]; + } + 295 [label="Exit when branch result"]; + 296 [label="Exit when"]; + } + 297 [label="Access variable R|/b|"]; + 298 [label="Function call: R|/b|.#()"]; + subgraph cluster_67 { + color=blue + 299 [label="Enter when"]; + subgraph cluster_68 { + color=blue + 300 [label="Enter when branch condition "]; + 301 [label="Access variable R|/b|"]; + 302 [label="Access variable R|/a|"]; + 303 [label="Operator ==="]; + 304 [label="Exit when branch condition"]; + } + 305 [label="Synthetic else branch"]; + 306 [label="Enter when branch result"]; + subgraph cluster_69 { + color=blue + 307 [label="Enter block"]; + 308 [label="Access variable R|/b|"]; + 309 [label="Function call: R|/b|.R|kotlin/Int.inc|()"]; + 310 [label="Exit block"]; + } + 311 [label="Exit when branch result"]; + 312 [label="Exit when"]; + } + 313 [label="Access variable R|/b|"]; + 314 [label="Function call: R|/b|.#()"]; + 315 [label="Exit block"]; + } + 316 [label="Exit function test_9" style="filled" fillcolor=red]; + } + 249 -> {250}; 250 -> {251}; 251 -> {252}; - 252 -> {254 253}; - 253 -> {260}; + 252 -> {253}; + 253 -> {254}; 254 -> {255}; 255 -> {256}; - 256 -> {257}; - 257 -> {258}; + 256 -> {258 257}; + 257 -> {264}; 258 -> {259}; 259 -> {260}; 260 -> {261}; @@ -798,12 +818,12 @@ digraph nullability_kt { 265 -> {266}; 266 -> {267}; 267 -> {268}; - 268 -> {270 269}; - 269 -> {276}; + 268 -> {269}; + 269 -> {270}; 270 -> {271}; 271 -> {272}; - 272 -> {273}; - 273 -> {274}; + 272 -> {274 273}; + 273 -> {280}; 274 -> {275}; 275 -> {276}; 276 -> {277}; @@ -814,130 +834,19 @@ digraph nullability_kt { 281 -> {282}; 282 -> {283}; 283 -> {284}; - 284 -> {286 285}; - 285 -> {292}; + 284 -> {285}; + 285 -> {286}; 286 -> {287}; 287 -> {288}; - 288 -> {289}; - 289 -> {290}; + 288 -> {290 289}; + 289 -> {296}; 290 -> {291}; 291 -> {292}; 292 -> {293}; 293 -> {294}; 294 -> {295}; 295 -> {296}; - - subgraph cluster_70 { - color=red - 297 [label="Enter function test_10" style="filled" fillcolor=red]; - subgraph cluster_71 { - color=blue - 298 [label="Enter block"]; - subgraph cluster_72 { - color=blue - 299 [label="Enter when"]; - subgraph cluster_73 { - color=blue - 300 [label="Enter when branch condition "]; - 301 [label="Access variable R|/a|"]; - 302 [label="Access variable R|/b|"]; - 303 [label="Operator =="]; - 304 [label="Exit when branch condition"]; - } - 305 [label="Synthetic else branch"]; - 306 [label="Enter when branch result"]; - subgraph cluster_74 { - color=blue - 307 [label="Enter block"]; - 308 [label="Access variable R|/b|"]; - 309 [label="Function call: R|/b|.#()"]; - 310 [label="Exit block"]; - } - 311 [label="Exit when branch result"]; - 312 [label="Exit when"]; - } - 313 [label="Access variable R|/b|"]; - 314 [label="Function call: R|/b|.#()"]; - subgraph cluster_75 { - color=blue - 315 [label="Enter when"]; - subgraph cluster_76 { - color=blue - 316 [label="Enter when branch condition "]; - 317 [label="Access variable R|/a|"]; - 318 [label="Access variable R|/b|"]; - 319 [label="Operator ==="]; - 320 [label="Exit when branch condition"]; - } - 321 [label="Synthetic else branch"]; - 322 [label="Enter when branch result"]; - subgraph cluster_77 { - color=blue - 323 [label="Enter block"]; - 324 [label="Access variable R|/b|"]; - 325 [label="Function call: R|/b|.#()"]; - 326 [label="Exit block"]; - } - 327 [label="Exit when branch result"]; - 328 [label="Exit when"]; - } - 329 [label="Access variable R|/b|"]; - 330 [label="Function call: R|/b|.#()"]; - subgraph cluster_78 { - color=blue - 331 [label="Enter when"]; - subgraph cluster_79 { - color=blue - 332 [label="Enter when branch condition "]; - 333 [label="Access variable R|/b|"]; - 334 [label="Access variable R|/a|"]; - 335 [label="Operator =="]; - 336 [label="Exit when branch condition"]; - } - 337 [label="Synthetic else branch"]; - 338 [label="Enter when branch result"]; - subgraph cluster_80 { - color=blue - 339 [label="Enter block"]; - 340 [label="Access variable R|/b|"]; - 341 [label="Function call: R|/b|.#()"]; - 342 [label="Exit block"]; - } - 343 [label="Exit when branch result"]; - 344 [label="Exit when"]; - } - 345 [label="Access variable R|/b|"]; - 346 [label="Function call: R|/b|.#()"]; - subgraph cluster_81 { - color=blue - 347 [label="Enter when"]; - subgraph cluster_82 { - color=blue - 348 [label="Enter when branch condition "]; - 349 [label="Access variable R|/b|"]; - 350 [label="Access variable R|/a|"]; - 351 [label="Operator ==="]; - 352 [label="Exit when branch condition"]; - } - 353 [label="Synthetic else branch"]; - 354 [label="Enter when branch result"]; - subgraph cluster_83 { - color=blue - 355 [label="Enter block"]; - 356 [label="Access variable R|/b|"]; - 357 [label="Function call: R|/b|.#()"]; - 358 [label="Exit block"]; - } - 359 [label="Exit when branch result"]; - 360 [label="Exit when"]; - } - 361 [label="Access variable R|/b|"]; - 362 [label="Function call: R|/b|.#()"]; - 363 [label="Exit block"]; - } - 364 [label="Exit function test_10" style="filled" fillcolor=red]; - } - + 296 -> {297}; 297 -> {298}; 298 -> {299}; 299 -> {300}; @@ -957,16 +866,127 @@ digraph nullability_kt { 313 -> {314}; 314 -> {315}; 315 -> {316}; - 316 -> {317}; + + subgraph cluster_70 { + color=red + 317 [label="Enter function test_10" style="filled" fillcolor=red]; + subgraph cluster_71 { + color=blue + 318 [label="Enter block"]; + subgraph cluster_72 { + color=blue + 319 [label="Enter when"]; + subgraph cluster_73 { + color=blue + 320 [label="Enter when branch condition "]; + 321 [label="Access variable R|/a|"]; + 322 [label="Access variable R|/b|"]; + 323 [label="Operator =="]; + 324 [label="Exit when branch condition"]; + } + 325 [label="Synthetic else branch"]; + 326 [label="Enter when branch result"]; + subgraph cluster_74 { + color=blue + 327 [label="Enter block"]; + 328 [label="Access variable R|/b|"]; + 329 [label="Function call: R|/b|.#()"]; + 330 [label="Exit block"]; + } + 331 [label="Exit when branch result"]; + 332 [label="Exit when"]; + } + 333 [label="Access variable R|/b|"]; + 334 [label="Function call: R|/b|.#()"]; + subgraph cluster_75 { + color=blue + 335 [label="Enter when"]; + subgraph cluster_76 { + color=blue + 336 [label="Enter when branch condition "]; + 337 [label="Access variable R|/a|"]; + 338 [label="Access variable R|/b|"]; + 339 [label="Operator ==="]; + 340 [label="Exit when branch condition"]; + } + 341 [label="Synthetic else branch"]; + 342 [label="Enter when branch result"]; + subgraph cluster_77 { + color=blue + 343 [label="Enter block"]; + 344 [label="Access variable R|/b|"]; + 345 [label="Function call: R|/b|.#()"]; + 346 [label="Exit block"]; + } + 347 [label="Exit when branch result"]; + 348 [label="Exit when"]; + } + 349 [label="Access variable R|/b|"]; + 350 [label="Function call: R|/b|.#()"]; + subgraph cluster_78 { + color=blue + 351 [label="Enter when"]; + subgraph cluster_79 { + color=blue + 352 [label="Enter when branch condition "]; + 353 [label="Access variable R|/b|"]; + 354 [label="Access variable R|/a|"]; + 355 [label="Operator =="]; + 356 [label="Exit when branch condition"]; + } + 357 [label="Synthetic else branch"]; + 358 [label="Enter when branch result"]; + subgraph cluster_80 { + color=blue + 359 [label="Enter block"]; + 360 [label="Access variable R|/b|"]; + 361 [label="Function call: R|/b|.#()"]; + 362 [label="Exit block"]; + } + 363 [label="Exit when branch result"]; + 364 [label="Exit when"]; + } + 365 [label="Access variable R|/b|"]; + 366 [label="Function call: R|/b|.#()"]; + subgraph cluster_81 { + color=blue + 367 [label="Enter when"]; + subgraph cluster_82 { + color=blue + 368 [label="Enter when branch condition "]; + 369 [label="Access variable R|/b|"]; + 370 [label="Access variable R|/a|"]; + 371 [label="Operator ==="]; + 372 [label="Exit when branch condition"]; + } + 373 [label="Synthetic else branch"]; + 374 [label="Enter when branch result"]; + subgraph cluster_83 { + color=blue + 375 [label="Enter block"]; + 376 [label="Access variable R|/b|"]; + 377 [label="Function call: R|/b|.#()"]; + 378 [label="Exit block"]; + } + 379 [label="Exit when branch result"]; + 380 [label="Exit when"]; + } + 381 [label="Access variable R|/b|"]; + 382 [label="Function call: R|/b|.#()"]; + 383 [label="Exit block"]; + } + 384 [label="Exit function test_10" style="filled" fillcolor=red]; + } + 317 -> {318}; 318 -> {319}; 319 -> {320}; - 320 -> {322 321}; - 321 -> {328}; + 320 -> {321}; + 321 -> {322}; 322 -> {323}; 323 -> {324}; - 324 -> {325}; - 325 -> {326}; + 324 -> {326 325}; + 325 -> {332}; 326 -> {327}; 327 -> {328}; 328 -> {329}; @@ -977,12 +997,12 @@ digraph nullability_kt { 333 -> {334}; 334 -> {335}; 335 -> {336}; - 336 -> {338 337}; - 337 -> {344}; + 336 -> {337}; + 337 -> {338}; 338 -> {339}; 339 -> {340}; - 340 -> {341}; - 341 -> {342}; + 340 -> {342 341}; + 341 -> {348}; 342 -> {343}; 343 -> {344}; 344 -> {345}; @@ -993,17 +1013,37 @@ digraph nullability_kt { 349 -> {350}; 350 -> {351}; 351 -> {352}; - 352 -> {354 353}; - 353 -> {360}; + 352 -> {353}; + 353 -> {354}; 354 -> {355}; 355 -> {356}; - 356 -> {357}; - 357 -> {358}; + 356 -> {358 357}; + 357 -> {364}; 358 -> {359}; 359 -> {360}; 360 -> {361}; 361 -> {362}; 362 -> {363}; 363 -> {364}; + 364 -> {365}; + 365 -> {366}; + 366 -> {367}; + 367 -> {368}; + 368 -> {369}; + 369 -> {370}; + 370 -> {371}; + 371 -> {372}; + 372 -> {374 373}; + 373 -> {380}; + 374 -> {375}; + 375 -> {376}; + 376 -> {377}; + 377 -> {378}; + 378 -> {379}; + 379 -> {380}; + 380 -> {381}; + 381 -> {382}; + 382 -> {383}; + 383 -> {384}; } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt index 7b44f85e9bf..1323d3e532e 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt @@ -116,4 +116,4 @@ fun test_10(a: Int?, b: Int?) { b.inc() } b.inc() -} \ No newline at end of file +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot new file mode 100644 index 00000000000..478657d9e6c --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot @@ -0,0 +1,301 @@ +digraph safeCalls_kt { + graph [splines=ortho nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function foo" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Const: String()"]; + 3 [label="Jump: ^foo String()"]; + 4 [label="Stub" style="filled" fillcolor=gray]; + 5 [label="Exit block" style="filled" fillcolor=gray]; + } + 6 [label="Exit function foo" style="filled" fillcolor=red]; + } + + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {6}; + 3 -> {4} [style=dotted]; + 4 -> {5} [style=dotted]; + 5 -> {6} [style=dotted]; + + subgraph cluster_2 { + color=red + 7 [label="Enter function let" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 8 [label="Enter block"]; + 9 [label="Exit block"]; + } + 10 [label="Exit function let" style="filled" fillcolor=red]; + } + + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + + subgraph cluster_4 { + color=red + 11 [label="Enter function test" style="filled" fillcolor=red]; + subgraph cluster_5 { + color=blue + 12 [label="Enter block"]; + 13 [label="Access variable R|/x|"]; + 14 [label="Enter safe call"]; + 15 [label="Access variable R|/x|"]; + 16 [label="Access variable R|kotlin/String.length|"]; + 17 [label="Const: Int(1)"]; + 18 [label="Operator =="]; + 19 [label="Function call: R|/x|?.R|/foo|(==(R|/x|.R|kotlin/String.length|, Int(1)))"]; + 20 [label="Exit safe call"]; + 21 [label="Access variable R|/x|"]; + 22 [label="Access variable #"]; + 23 [label="Exit block"]; + } + 24 [label="Exit function test" style="filled" fillcolor=red]; + } + + 11 -> {12}; + 12 -> {13}; + 13 -> {14 20}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + + subgraph cluster_6 { + color=red + 25 [label="Enter function bar" style="filled" fillcolor=red]; + 26 [label="Exit function bar" style="filled" fillcolor=red]; + } + + 25 -> {26}; + + subgraph cluster_7 { + color=red + 27 [label="Enter function bool" style="filled" fillcolor=red]; + 28 [label="Exit function bool" style="filled" fillcolor=red]; + } + + 27 -> {28}; + + subgraph cluster_8 { + color=red + 29 [label="Enter function id" style="filled" fillcolor=red]; + 30 [label="Exit function id" style="filled" fillcolor=red]; + } + + 29 -> {30}; + + subgraph cluster_9 { + color=red + 31 [label="Enter function test_2" style="filled" fillcolor=red]; + subgraph cluster_10 { + color=blue + 32 [label="Enter block"]; + 33 [label="Access variable R|/x|"]; + 34 [label="Type operator: x as? A"]; + 35 [label="Enter safe call"]; + 36 [label="Access variable R|/x|"]; + 37 [label="Function call: (R|/x| as? R|A|)?.R|/A.bar|(R|/x|)"]; + 38 [label="Exit safe call"]; + 39 [label="Exit block"]; + } + 40 [label="Exit function test_2" style="filled" fillcolor=red]; + } + + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35 38}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39}; + 39 -> {40}; + + subgraph cluster_11 { + color=red + 41 [label="Enter function test_3" style="filled" fillcolor=red]; + subgraph cluster_12 { + color=blue + 42 [label="Enter block"]; + 43 [label="Access variable R|/x|"]; + 44 [label="Type operator: x as? A"]; + 45 [label="Enter safe call"]; + 46 [label="Access variable R|/x|"]; + 47 [label="Function call: (R|/x| as? R|A|)?.R|/A.bar|(R|/x|)"]; + 48 [label="Exit safe call"]; + 49 [label="Enter safe call"]; + 50 [label="Access variable R|/x|"]; + 51 [label="Function call: R|/x|.R|/A.bool|()"]; + 52 [label="Function call: (R|/x| as? R|A|)?.R|/A.bar|(R|/x|)?.R|/foo|(R|/x|.R|/A.bool|())"]; + 53 [label="Exit safe call"]; + 54 [label="Enter safe call"]; + 55 [label="Function call: (R|/x| as? R|A|)?.R|/A.bar|(R|/x|)?.R|/foo|(R|/x|.R|/A.bool|())?.R|/let|( = let@fun (): R|kotlin/Unit| { + R|/x|.R|/A.bool|() +} +)"]; + 56 [label="Exit safe call"]; + 57 [label="Access variable R|/x|"]; + 58 [label="Function call: R|/x|.#()"]; + 59 [label="Exit block"]; + } + 60 [label="Exit function test_3" style="filled" fillcolor=red]; + } + + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45 48}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49 53}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54 56}; + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + + subgraph cluster_13 { + color=red + 61 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_14 { + color=blue + 62 [label="Enter block"]; + 63 [label="Access variable R|/x|"]; + 64 [label="Function call: R|/x|.R|/A.bool|()"]; + 65 [label="Exit block"]; + } + 66 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + + 61 -> {62}; + 62 -> {63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + + subgraph cluster_15 { + color=red + 67 [label="Enter function test_4" style="filled" fillcolor=red]; + subgraph cluster_16 { + color=blue + 68 [label="Enter block"]; + 69 [label="Access variable R|/x|"]; + 70 [label="Enter safe call"]; + 71 [label="Function call: R|/x|?.R|/A.id|()"]; + 72 [label="Exit safe call"]; + 73 [label="Enter safe call"]; + 74 [label="Function call: R|/x|?.R|/A.id|()?.R|/A.bool|()"]; + 75 [label="Exit safe call"]; + 76 [label="Access variable R|/x|"]; + 77 [label="Function call: R|/x|.#()"]; + 78 [label="Exit block"]; + } + 79 [label="Exit function test_4" style="filled" fillcolor=red]; + } + + 67 -> {68}; + 68 -> {69}; + 69 -> {70 72}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73 75}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + + subgraph cluster_17 { + color=red + 80 [label="Enter function boo" style="filled" fillcolor=red]; + 81 [label="Exit function boo" style="filled" fillcolor=red]; + } + + 80 -> {81}; + + subgraph cluster_18 { + color=red + 82 [label="Enter function test_5" style="filled" fillcolor=red]; + subgraph cluster_19 { + color=blue + 83 [label="Enter block"]; + 84 [label="Access variable R|/x|"]; + 85 [label="Enter safe call"]; + subgraph cluster_20 { + color=blue + 86 [label="Enter function anonymousFunction"]; + subgraph cluster_21 { + color=blue + 87 [label="Enter block"]; + 88 [label="Jump: ^ Unit"]; + 89 [label="Stub" style="filled" fillcolor=gray]; + 90 [label="Exit block" style="filled" fillcolor=gray]; + } + 91 [label="Exit function anonymousFunction"]; + } + 92 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^ Unit +} +)"]; + 93 [label="Exit safe call"]; + 94 [label="Enter safe call"]; + 95 [label="Access variable R|/x|"]; + 96 [label="Function call: R|/x|.R|/A.bool|()"]; + 97 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^ Unit +} +)?.R|/boo|(R|/x|.R|/A.bool|())"]; + 98 [label="Exit safe call"]; + 99 [label="Access variable R|/x|"]; + 100 [label="Function call: R|/x|.#()"]; + 101 [label="Exit block"]; + } + 102 [label="Exit function test_5" style="filled" fillcolor=red]; + } + + 82 -> {83}; + 83 -> {84}; + 84 -> {85 93}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {91}; + 88 -> {89} [style=dotted]; + 89 -> {90} [style=dotted]; + 90 -> {91} [style=dotted]; + 91 -> {92}; + 92 -> {93}; + 93 -> {94 98}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {101}; + 101 -> {102}; + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.kt b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.kt new file mode 100644 index 00000000000..645412705bc --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.kt @@ -0,0 +1,37 @@ +fun String.foo(b: Boolean): String = "" + +fun String.let(block: () -> Unit) {} + +fun test(x: String?) { + x?.foo(x.length == 1) + x.length +} + +interface A { + fun bar(a: A): String + fun bool(): Boolean + fun id(): A +} + +fun test_2(x: Any) { + (x as? A)?.bar(x) +} + +fun test_3(x: Any) { + (x as? A)?.bar(x)?.foo(x.bool())?.let { + x.bool() + } + x.bool() +} + +fun test_4(x: A?) { + x?.id()?.bool() + x.id() +} + +fun Any?.boo(b: Boolean) + +fun test_5(x: A?) { + x?.let { return }?.boo(x.bool()) + x.id() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt new file mode 100644 index 00000000000..e5405d796f9 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt @@ -0,0 +1,40 @@ +FILE: safeCalls.kt + public final fun R|kotlin/String|.foo(b: R|kotlin/Boolean|): R|kotlin/String| { + ^foo String() + } + public final fun R|kotlin/String|.let(block: R|() -> kotlin/Unit|): R|kotlin/Unit| { + } + public final fun test(x: R|kotlin/String?|): R|kotlin/Unit| { + R|/x|?.R|/foo|(==(R|/x|.R|kotlin/String.length|, Int(1))) + R|/x|.# + } + public abstract interface A : R|kotlin/Any| { + public abstract fun bar(a: R|A|): R|kotlin/String| + + public abstract fun bool(): R|kotlin/Boolean| + + public abstract fun id(): R|A| + + } + public final fun test_2(x: R|kotlin/Any|): R|kotlin/Unit| { + (R|/x| as? R|A|)?.R|/A.bar|(R|/x|) + } + public final fun test_3(x: R|kotlin/Any|): R|kotlin/Unit| { + (R|/x| as? R|A|)?.R|/A.bar|(R|/x|)?.R|/foo|(R|/x|.R|/A.bool|())?.R|/let|( = let@fun (): R|kotlin/Unit| { + R|/x|.R|/A.bool|() + } + ) + R|/x|.#() + } + public final fun test_4(x: R|A?|): R|kotlin/Unit| { + R|/x|?.R|/A.id|()?.R|/A.bool|() + R|/x|.#() + } + public final fun R|kotlin/Any?|.boo(b: R|kotlin/Boolean|): R|kotlin/Unit| + public final fun test_5(x: R|A?|): R|kotlin/Unit| { + R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^ Unit + } + )?.R|/boo|(R|/x|.R|/A.bool|()) + R|/x|.#() + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithCfgTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithCfgTestGenerated.java index 85f380849f0..c9fd940ed50 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithCfgTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithCfgTestGenerated.java @@ -80,6 +80,11 @@ public class FirDiagnosticsWithCfgTestGenerated extends AbstractFirDiagnosticsWi runTest("compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt"); } + @TestMetadata("safeCalls.kt") + public void testSafeCalls() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/safeCalls.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/fir/resolve/testData/resolve/cfg/simple.kt"); @@ -183,6 +188,11 @@ public class FirDiagnosticsWithCfgTestGenerated extends AbstractFirDiagnosticsWi runTest("compiler/fir/resolve/testData/resolve/smartcasts/returns.kt"); } + @TestMetadata("safeCalls.kt") + public void testSafeCalls() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.kt"); + } + @TestMetadata("simpleIf.kt") public void testSimpleIf() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/simpleIf.kt");