From 2bce279a9eedac39876678b907066e79af83348a Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 4 Mar 2020 16:55:01 +0300 Subject: [PATCH] [FIR] Support smartcasts from lhs of boolean operator with jump in rhs --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 67 ++- .../smartcasts/booleans/booleanOperators.dot | 2 +- .../smartcasts/booleans/booleanOperators.kt | 2 +- .../smartcasts/booleans/booleanOperators.txt | 2 +- .../booleans/jumpFromRhsOfOperator.dot | 426 ++++++++++++++++++ .../booleans/jumpFromRhsOfOperator.kt | 57 +++ .../booleans/jumpFromRhsOfOperator.txt | 57 +++ .../fir/FirDiagnosticsTestGenerated.java | 5 + ...DiagnosticsWithLightTreeTestGenerated.java | 5 + 9 files changed, 595 insertions(+), 28 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.txt 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 61fa6c22b9b..2ab55a6bdea 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 @@ -778,33 +778,50 @@ abstract class FirDataFlowAnalyzer( val rightVariable = variableStorage.getOrCreateVariable(flow, binaryLogicExpression.rightOperand) val operatorVariable = variableStorage.getOrCreateVariable(flow, binaryLogicExpression) - val (conditionalFromLeft, conditionalFromRight, approvedFromRight) = logicSystem.collectInfoForBooleanOperator( - flowFromLeft, - leftVariable, - flowFromRight, - rightVariable - ) + if (!node.leftOperandNode.isDead && node.rightOperandNode.isDead) { + /* + * If there was a jump from right argument then we know that we well exit from + * boolean operator only if right operand was not executed + * + * a && return => a == false + * a || return => a == true + */ + logicSystem.approveStatementsInsideFlow( + flow, + leftVariable eq !isAnd, + shouldForkFlow = false, + shouldRemoveSynthetics = true + ) + } else { + val (conditionalFromLeft, conditionalFromRight, approvedFromRight) = logicSystem.collectInfoForBooleanOperator( + flowFromLeft, + leftVariable, + flowFromRight, + rightVariable + ) - // left && right == True - // left || right == False - val approvedIfTrue: MutableTypeStatements = mutableMapOf() - logicSystem.approveStatementsTo(approvedIfTrue, flowFromRight, leftVariable eq bothEvaluated, conditionalFromLeft) - logicSystem.approveStatementsTo(approvedIfTrue, flowFromRight, rightVariable eq bothEvaluated, conditionalFromRight) - approvedFromRight.forEach { (variable, info) -> - approvedIfTrue.addStatement(variable, info) - } - approvedIfTrue.values.forEach { info -> - flow.addImplication((operatorVariable eq bothEvaluated) implies info) - } + // left && right == True + // left || right == False + val approvedIfTrue: MutableTypeStatements = mutableMapOf() + logicSystem.approveStatementsTo(approvedIfTrue, flowFromRight, leftVariable eq bothEvaluated, conditionalFromLeft) + logicSystem.approveStatementsTo(approvedIfTrue, flowFromRight, rightVariable eq bothEvaluated, conditionalFromRight) + approvedFromRight.forEach { (variable, info) -> + approvedIfTrue.addStatement(variable, info) + } + approvedIfTrue.values.forEach { info -> + flow.addImplication((operatorVariable eq bothEvaluated) implies info) + } - // left && right == False - // left || right == True - val approvedIfFalse: MutableTypeStatements = mutableMapOf() - val leftIsFalse = logicSystem.approveOperationStatement(flowFromLeft, leftVariable eq onlyLeftEvaluated, conditionalFromLeft) - val rightIsFalse = logicSystem.approveOperationStatement(flowFromRight, rightVariable eq onlyLeftEvaluated, conditionalFromRight) - approvedIfFalse.mergeTypeStatements(logicSystem.orForTypeStatements(leftIsFalse, rightIsFalse)) - approvedIfFalse.values.forEach { info -> - flow.addImplication((operatorVariable eq onlyLeftEvaluated) implies info) + // left && right == False + // left || right == True + val approvedIfFalse: MutableTypeStatements = mutableMapOf() + val leftIsFalse = logicSystem.approveOperationStatement(flowFromLeft, leftVariable eq onlyLeftEvaluated, conditionalFromLeft) + val rightIsFalse = + logicSystem.approveOperationStatement(flowFromRight, rightVariable eq onlyLeftEvaluated, conditionalFromRight) + approvedIfFalse.mergeTypeStatements(logicSystem.orForTypeStatements(leftIsFalse, rightIsFalse)) + approvedIfFalse.values.forEach { info -> + flow.addImplication((operatorVariable eq onlyLeftEvaluated) implies info) + } } logicSystem.updateAllReceivers(flow) diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.dot b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.dot index aeaf69af8bc..6e9847652b9 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.dot +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.dot @@ -634,7 +634,7 @@ digraph booleanOperators_kt { color=blue 229 [label="Enter block"]; 230 [label="Access variable R|/x|"]; - 231 [label="Function call: R|/x|.R|/A.foo|()"]; + 231 [label="Function call: R|/x|.#()"]; 232 [label="Exit block"]; } 233 [label="Exit when branch result"]; diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.kt b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.kt index 48970dce5b7..4f293d49cd0 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.kt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.kt @@ -86,7 +86,7 @@ fun test_10(x: Any) { fun test_11(x: Any, b: Boolean) { if (false && x is A) { - x.foo() + x.foo() } } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.txt b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.txt index 9c49017c6e3..51e5605a714 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.txt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/booleanOperators.txt @@ -101,7 +101,7 @@ FILE: booleanOperators.kt public final fun test_11(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| { when () { Boolean(false) && (R|/x| is R|A|) -> { - R|/x|.R|/A.foo|() + R|/x|.#() } } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.dot b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.dot new file mode 100644 index 00000000000..9d10308af73 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.dot @@ -0,0 +1,426 @@ +digraph jumpFromRhsOfOperator_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 test_1" style="filled" fillcolor=red]; + subgraph cluster_2 { + color=blue + 3 [label="Enter ||"]; + 4 [label="Access variable R|/a|"]; + 5 [label="Const: Null(null)"]; + 6 [label="Operator !="]; + 7 [label="Exit left part of ||"]; + 8 [label="Enter right part of ||"]; + 9 [label="Function call: R|java/lang/Exception.Exception|()"]; + 10 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 11 [label="Stub" style="filled" fillcolor=gray]; + 12 [label="Exit ||"]; + } + 13 [label="Access variable R|/a|"]; + 14 [label="Function call: R|/a|.R|/A.foo|()"]; + 15 [label="Exit function test_1" style="filled" fillcolor=red]; + } + + 2 -> {3}; + 3 -> {4}; + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {12 8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {15}; + 10 -> {11} [style=dotted]; + 11 -> {12} [style=dotted]; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + + subgraph cluster_3 { + color=red + 16 [label="Enter function teat_2" style="filled" fillcolor=red]; + subgraph cluster_4 { + color=blue + 17 [label="Enter &&"]; + 18 [label="Access variable R|/a|"]; + 19 [label="Const: Null(null)"]; + 20 [label="Operator =="]; + 21 [label="Exit left part of &&"]; + 22 [label="Enter right part of &&"]; + 23 [label="Function call: R|java/lang/Exception.Exception|()"]; + 24 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 25 [label="Stub" style="filled" fillcolor=gray]; + 26 [label="Exit &&"]; + } + 27 [label="Access variable R|/a|"]; + 28 [label="Function call: R|/a|.R|/A.foo|()"]; + 29 [label="Exit function teat_2" style="filled" fillcolor=red]; + } + + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {26 22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {29}; + 24 -> {25} [style=dotted]; + 25 -> {26} [style=dotted]; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + + subgraph cluster_5 { + color=red + 30 [label="Enter function test_3" style="filled" fillcolor=red]; + subgraph cluster_6 { + color=blue + 31 [label="Enter when"]; + subgraph cluster_7 { + color=blue + 32 [label="Enter when branch condition "]; + subgraph cluster_8 { + color=blue + 33 [label="Enter ||"]; + 34 [label="Access variable R|/a|"]; + 35 [label="Const: Null(null)"]; + 36 [label="Operator !="]; + 37 [label="Exit left part of ||"]; + 38 [label="Enter right part of ||"]; + 39 [label="Function call: R|java/lang/Exception.Exception|()"]; + 40 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 41 [label="Stub" style="filled" fillcolor=gray]; + 42 [label="Exit ||"]; + } + 43 [label="Exit when branch condition"]; + } + 44 [label="Synthetic else branch"]; + 45 [label="Enter when branch result"]; + subgraph cluster_9 { + color=blue + 46 [label="Enter block"]; + 47 [label="Access variable R|/a|"]; + 48 [label="Function call: R|/a|.R|/A.foo|()"]; + 49 [label="Exit block"]; + } + 50 [label="Exit when branch result"]; + 51 [label="Exit when"]; + } + 52 [label="Access variable R|/a|"]; + 53 [label="Function call: R|/a|.R|/A.foo|()"]; + 54 [label="Exit function test_3" style="filled" fillcolor=red]; + } + + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {42 38}; + 38 -> {39}; + 39 -> {40}; + 40 -> {54}; + 40 -> {41} [style=dotted]; + 41 -> {42} [style=dotted]; + 42 -> {43}; + 43 -> {45 44}; + 44 -> {51}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + + subgraph cluster_10 { + color=red + 55 [label="Enter function test_4" style="filled" fillcolor=red]; + subgraph cluster_11 { + color=blue + 56 [label="Enter when"]; + subgraph cluster_12 { + color=blue + 57 [label="Enter when branch condition "]; + subgraph cluster_13 { + color=blue + 58 [label="Enter &&"]; + 59 [label="Access variable R|/a|"]; + 60 [label="Const: Null(null)"]; + 61 [label="Operator =="]; + 62 [label="Exit left part of &&"]; + 63 [label="Enter right part of &&"]; + 64 [label="Function call: R|java/lang/Exception.Exception|()"]; + 65 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 66 [label="Stub" style="filled" fillcolor=gray]; + 67 [label="Exit &&"]; + } + 68 [label="Exit when branch condition"]; + } + 69 [label="Synthetic else branch"]; + 70 [label="Enter when branch result"]; + subgraph cluster_14 { + color=blue + 71 [label="Enter block"]; + 72 [label="Access variable R|/a|"]; + 73 [label="Function call: R|/a|.R|/A.foo|()"]; + 74 [label="Exit block"]; + } + 75 [label="Exit when branch result"]; + 76 [label="Exit when"]; + } + 77 [label="Access variable R|/a|"]; + 78 [label="Function call: R|/a|.R|/A.foo|()"]; + 79 [label="Exit function test_4" style="filled" fillcolor=red]; + } + + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {67 63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {79}; + 65 -> {66} [style=dotted]; + 66 -> {67} [style=dotted]; + 67 -> {68}; + 68 -> {70 69}; + 69 -> {76}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 77 -> {78}; + 78 -> {79}; + + subgraph cluster_15 { + color=red + 80 [label="Enter function test_5" style="filled" fillcolor=red]; + subgraph cluster_16 { + color=blue + 81 [label="Enter ||"]; + 82 [label="Access variable R|/a|"]; + 83 [label="Const: Null(null)"]; + 84 [label="Operator =="]; + 85 [label="Exit left part of ||"]; + 86 [label="Enter right part of ||"]; + 87 [label="Function call: R|java/lang/Exception.Exception|()"]; + 88 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 89 [label="Stub" style="filled" fillcolor=gray]; + 90 [label="Exit ||"]; + } + 91 [label="Access variable R|/a|"]; + 92 [label="Function call: R|/a|.#()"]; + 93 [label="Exit function test_5" style="filled" fillcolor=red]; + } + + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {90 86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {93}; + 88 -> {89} [style=dotted]; + 89 -> {90} [style=dotted]; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + + subgraph cluster_17 { + color=red + 94 [label="Enter function teat_6" style="filled" fillcolor=red]; + subgraph cluster_18 { + color=blue + 95 [label="Enter &&"]; + 96 [label="Access variable R|/a|"]; + 97 [label="Const: Null(null)"]; + 98 [label="Operator !="]; + 99 [label="Exit left part of &&"]; + 100 [label="Enter right part of &&"]; + 101 [label="Function call: R|java/lang/Exception.Exception|()"]; + 102 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 103 [label="Stub" style="filled" fillcolor=gray]; + 104 [label="Exit &&"]; + } + 105 [label="Access variable R|/a|"]; + 106 [label="Function call: R|/a|.#()"]; + 107 [label="Exit function teat_6" style="filled" fillcolor=red]; + } + + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {104 100}; + 100 -> {101}; + 101 -> {102}; + 102 -> {107}; + 102 -> {103} [style=dotted]; + 103 -> {104} [style=dotted]; + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + + subgraph cluster_19 { + color=red + 108 [label="Enter function test_7" style="filled" fillcolor=red]; + subgraph cluster_20 { + color=blue + 109 [label="Enter when"]; + subgraph cluster_21 { + color=blue + 110 [label="Enter when branch condition "]; + subgraph cluster_22 { + color=blue + 111 [label="Enter ||"]; + 112 [label="Access variable R|/a|"]; + 113 [label="Const: Null(null)"]; + 114 [label="Operator =="]; + 115 [label="Exit left part of ||"]; + 116 [label="Enter right part of ||"]; + 117 [label="Function call: R|java/lang/Exception.Exception|()"]; + 118 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 119 [label="Stub" style="filled" fillcolor=gray]; + 120 [label="Exit ||"]; + } + 121 [label="Exit when branch condition"]; + } + 122 [label="Synthetic else branch"]; + 123 [label="Enter when branch result"]; + subgraph cluster_23 { + color=blue + 124 [label="Enter block"]; + 125 [label="Access variable R|/a|"]; + 126 [label="Function call: R|/a|.#()"]; + 127 [label="Exit block"]; + } + 128 [label="Exit when branch result"]; + 129 [label="Exit when"]; + } + 130 [label="Access variable R|/a|"]; + 131 [label="Function call: R|/a|.#()"]; + 132 [label="Exit function test_7" style="filled" fillcolor=red]; + } + + 108 -> {109}; + 109 -> {110}; + 110 -> {111}; + 111 -> {112}; + 112 -> {113}; + 113 -> {114}; + 114 -> {115}; + 115 -> {120 116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {132}; + 118 -> {119} [style=dotted]; + 119 -> {120} [style=dotted]; + 120 -> {121}; + 121 -> {123 122}; + 122 -> {129}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; + 128 -> {129}; + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; + + subgraph cluster_24 { + color=red + 133 [label="Enter function test_8" style="filled" fillcolor=red]; + subgraph cluster_25 { + color=blue + 134 [label="Enter when"]; + subgraph cluster_26 { + color=blue + 135 [label="Enter when branch condition "]; + subgraph cluster_27 { + color=blue + 136 [label="Enter &&"]; + 137 [label="Access variable R|/a|"]; + 138 [label="Const: Null(null)"]; + 139 [label="Operator !="]; + 140 [label="Exit left part of &&"]; + 141 [label="Enter right part of &&"]; + 142 [label="Function call: R|java/lang/Exception.Exception|()"]; + 143 [label="Throw: throw R|java/lang/Exception.Exception|()"]; + 144 [label="Stub" style="filled" fillcolor=gray]; + 145 [label="Exit &&"]; + } + 146 [label="Exit when branch condition"]; + } + 147 [label="Synthetic else branch"]; + 148 [label="Enter when branch result"]; + subgraph cluster_28 { + color=blue + 149 [label="Enter block"]; + 150 [label="Access variable R|/a|"]; + 151 [label="Function call: R|/a|.#()"]; + 152 [label="Exit block"]; + } + 153 [label="Exit when branch result"]; + 154 [label="Exit when"]; + } + 155 [label="Access variable R|/a|"]; + 156 [label="Function call: R|/a|.#()"]; + 157 [label="Exit function test_8" style="filled" fillcolor=red]; + } + + 133 -> {134}; + 134 -> {135}; + 135 -> {136}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139}; + 139 -> {140}; + 140 -> {145 141}; + 141 -> {142}; + 142 -> {143}; + 143 -> {157}; + 143 -> {144} [style=dotted]; + 144 -> {145} [style=dotted]; + 145 -> {146}; + 146 -> {148 147}; + 147 -> {154}; + 148 -> {149}; + 149 -> {150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {153}; + 153 -> {154}; + 154 -> {155}; + 155 -> {156}; + 156 -> {157}; + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt new file mode 100644 index 00000000000..b425f917c26 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt @@ -0,0 +1,57 @@ +// !DUMP_CFG + +interface A { + fun foo() +} + +// ------------------------- Should work ------------------------- + +fun test_1(a: A?) { + a != null || throw Exception() + a.foo() +} + +fun teat_2(a: A?) { + a == null && throw Exception() + a.foo() +} + +fun test_3(a: A?) { + if (a != null || throw Exception()) { + a.foo() + } + a.foo() +} + +fun test_4(a: A?) { + if (a == null && throw Exception()) { + a.foo() + } + a.foo() +} + +// ------------------------- Shouldn't work ------------------------- + +fun test_5(a: A?) { + a == null || throw Exception() + a.foo() +} + +fun teat_6(a: A?) { + a != null && throw Exception() + a.foo() +} + +fun test_7(a: A?) { + if (a == null || throw Exception()) { + a.foo() + } + a.foo() +} + +fun test_8(a: A?) { + if (a != null && throw Exception()) { + a.foo() + } + a.foo() +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.txt b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.txt new file mode 100644 index 00000000000..56bdb1afca4 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.txt @@ -0,0 +1,57 @@ +FILE: jumpFromRhsOfOperator.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public final fun test_1(a: R|A?|): R|kotlin/Unit| { + !=(R|/a|, Null(null)) || throw R|java/lang/Exception.Exception|() + R|/a|.R|/A.foo|() + } + public final fun teat_2(a: R|A?|): R|kotlin/Unit| { + ==(R|/a|, Null(null)) && throw R|java/lang/Exception.Exception|() + R|/a|.R|/A.foo|() + } + public final fun test_3(a: R|A?|): R|kotlin/Unit| { + when () { + !=(R|/a|, Null(null)) || throw R|java/lang/Exception.Exception|() -> { + R|/a|.R|/A.foo|() + } + } + + R|/a|.R|/A.foo|() + } + public final fun test_4(a: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/a|, Null(null)) && throw R|java/lang/Exception.Exception|() -> { + R|/a|.R|/A.foo|() + } + } + + R|/a|.R|/A.foo|() + } + public final fun test_5(a: R|A?|): R|kotlin/Unit| { + ==(R|/a|, Null(null)) || throw R|java/lang/Exception.Exception|() + R|/a|.#() + } + public final fun teat_6(a: R|A?|): R|kotlin/Unit| { + !=(R|/a|, Null(null)) && throw R|java/lang/Exception.Exception|() + R|/a|.#() + } + public final fun test_7(a: R|A?|): R|kotlin/Unit| { + when () { + ==(R|/a|, Null(null)) || throw R|java/lang/Exception.Exception|() -> { + R|/a|.#() + } + } + + R|/a|.#() + } + public final fun test_8(a: R|A?|): R|kotlin/Unit| { + when () { + !=(R|/a|, Null(null)) && throw R|java/lang/Exception.Exception|() -> { + R|/a|.#() + } + } + + R|/a|.#() + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index e5e69c49adc..ccf675847e1 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -1610,6 +1610,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { public void testEqualsToBoolean() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/booleans/equalsToBoolean.kt"); } + + @TestMetadata("jumpFromRhsOfOperator.kt") + public void testJumpFromRhsOfOperator() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt"); + } } @TestMetadata("compiler/fir/resolve/testData/resolve/smartcasts/boundSmartcasts") diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index e4cd9da2c5b..59ce8c526c5 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1610,6 +1610,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos public void testEqualsToBoolean() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/booleans/equalsToBoolean.kt"); } + + @TestMetadata("jumpFromRhsOfOperator.kt") + public void testJumpFromRhsOfOperator() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/booleans/jumpFromRhsOfOperator.kt"); + } } @TestMetadata("compiler/fir/resolve/testData/resolve/smartcasts/boundSmartcasts")