From 7e43a0d9efb7abd5506c71dacd2097500fc2c26a Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 27 Aug 2019 11:22:51 +0300 Subject: [PATCH] [FIR] Add boolean constant folding for DFA --- .../kotlin/fir/resolve/dfa/Condition.kt | 2 + .../resolve/dfa/FirDataFlowAnalyzerImpl.kt | 48 +- .../smartcasts/equalsToBoolean.cfg.dot | 440 ++++++++++++++++++ .../resolve/smartcasts/equalsToBoolean.kt | 68 +++ .../resolve/smartcasts/equalsToBoolean.txt | 96 ++++ .../fir/FirCfgBuildingTestGenerated.java | 5 + 6 files changed, 646 insertions(+), 13 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.cfg.dot create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt index 6d9f660e07a..4f95cdbd803 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt @@ -19,6 +19,8 @@ enum class ConditionValue(val token: String) { } } +fun Boolean.toConditionValue(): ConditionValue = if (this) ConditionValue.True else ConditionValue.False + enum class ConditionOperator(val token: String) { Eq("=="), NotEq("!="); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt index defa391e7ad..4eed06bdb1d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt @@ -184,9 +184,9 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF when { leftConst?.kind == IrConstKind.Null -> processEqNull(node, rightOperand, operation) rightConst?.kind == IrConstKind.Null -> processEqNull(node, leftOperand, operation) + leftConst != null -> processEqWithConst(node, rightOperand, leftConst, operation) + rightConst != null -> processEqWithConst(node, leftOperand, rightConst, operation) operation != FirOperation.EQ && operation != FirOperation.IDENTITY -> return - leftConst != null -> processEqWithConst(node, rightOperand) - rightConst != null -> processEqWithConst(node, leftOperand) else -> processEq(node, leftOperand, rightOperand, operation) } } @@ -196,19 +196,41 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF } } - private fun processEqWithConst(node: OperatorCallNode, operand: FirExpression) { - val operandVariables = getRealVariablesForSafeCallChain(operand).takeIf { it.isNotEmpty() } ?: return + private fun processEqWithConst(node: OperatorCallNode, operand: FirExpression, const: FirConstExpression<*>, operation: FirOperation) { + val isEq = when (operation) { + FirOperation.EQ, FirOperation.IDENTITY -> true + FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> false + else -> return + } + val expressionVariable = getVariable(node.fir) var flow = node.flow - operandVariables.forEach { operandVariable -> - flow = flow.addNotApprovedFact( - expressionVariable, UnapprovedFirDataFlowInfo( - eq(True), - operandVariable, - FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) + + // not null for comparisons with constants + getRealVariablesForSafeCallChain(operand).takeIf { it.isNotEmpty() }?.let { operandVariables -> + operandVariables.forEach { operandVariable -> + flow = flow.addNotApprovedFact( + expressionVariable, UnapprovedFirDataFlowInfo( + eq(isEq.toConditionValue()), + operandVariable, + FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) + ) ) - ) + } } + + // propagating facts for (... == true) and (... == false) + variableStorage[operand]?.let { operandVariable -> + if (const.kind != IrConstKind.Boolean) return@let + + val constValue = (const.value as Boolean) + val shouldInvert = isEq xor constValue + + flow.notApprovedFacts[operandVariable].forEach { info -> + flow = flow.addNotApprovedFact(expressionVariable, info.let { if (shouldInvert) it.invert() else it }) + } + } + node.flow = flow } @@ -217,8 +239,8 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val rightType = rightOperand.typeRef.coneTypeSafe() ?: return when { leftType.isMarkedNullable && rightType.isMarkedNullable -> return - leftType.isMarkedNullable -> processEqWithConst(node, leftOperand) - rightType.isMarkedNullable -> processEqWithConst(node, rightOperand) + leftType.isMarkedNullable -> processEqNull(node, leftOperand, FirOperation.NOT_EQ) + rightType.isMarkedNullable -> processEqNull(node, rightOperand, FirOperation.NOT_EQ) } // TODO: process EQUALITY } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.cfg.dot b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.cfg.dot new file mode 100644 index 00000000000..7cd2da2c0a2 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.cfg.dot @@ -0,0 +1,440 @@ +digraph equalsToBoolean_kt { +subgraph foo { + 0 [shape=box label="Enter function foo"]; + 1 [shape=box label="Exit function foo"]; + + 0 -> {1}; +} + +subgraph val_b { + 2 [shape=box label="Enter property"]; + 3 [shape=box label="Exit property"]; + + 2 -> {3}; +} + +subgraph test_1 { + 4 [shape=box label="Enter function test_1"]; + 5 [shape=box label="Enter block"]; + 6 [shape=box label="Enter when"]; + 7 [shape=box label="Enter when branch condition "]; + 8 [shape=box label="Access variable R|/b|"]; + 9 [shape=box label="Const: Boolean(true)"]; + 10 [shape=box label="Operator =="]; + 11 [shape=box label="Const: Boolean(true)"]; + 12 [shape=box label="Operator =="]; + 13 [shape=box label="Exit when branch condition"]; + 14 [shape=box label="Enter block"]; + 15 [shape=box label="Access variable R|/b|"]; + 16 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 17 [shape=box label="Exit block"]; + 18 [shape=box label="Exit when branch result"]; + 19 [shape=box label="Enter when branch condition else"]; + 20 [shape=box label="Exit when branch condition"]; + 21 [shape=box label="Enter block"]; + 22 [shape=box label="Access variable R|/b|"]; + 23 [shape=box label="Function call: R|/b|.#()"]; + 24 [shape=box label="Exit block"]; + 25 [shape=box label="Exit when branch result"]; + 26 [shape=box label="Exit when"]; + 27 [shape=box label="Exit block"]; + 28 [shape=box label="Exit function test_1"]; + + 4 -> {5}; + 5 -> {6}; + 6 -> {7}; + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + 10 -> {11}; + 11 -> {12}; + 12 -> {13}; + 13 -> {14 19}; + 14 -> {15}; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {26}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; +} + +subgraph test_2 { + 29 [shape=box label="Enter function test_2"]; + 30 [shape=box label="Enter block"]; + 31 [shape=box label="Enter when"]; + 32 [shape=box label="Enter when branch condition "]; + 33 [shape=box label="Access variable R|/b|"]; + 34 [shape=box label="Const: Boolean(true)"]; + 35 [shape=box label="Operator =="]; + 36 [shape=box label="Const: Boolean(true)"]; + 37 [shape=box label="Operator !="]; + 38 [shape=box label="Exit when branch condition"]; + 39 [shape=box label="Enter block"]; + 40 [shape=box label="Access variable R|/b|"]; + 41 [shape=box label="Function call: R|/b|.#()"]; + 42 [shape=box label="Exit block"]; + 43 [shape=box label="Exit when branch result"]; + 44 [shape=box label="Enter when branch condition else"]; + 45 [shape=box label="Exit when branch condition"]; + 46 [shape=box label="Enter block"]; + 47 [shape=box label="Access variable R|/b|"]; + 48 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 49 [shape=box label="Exit block"]; + 50 [shape=box label="Exit when branch result"]; + 51 [shape=box label="Exit when"]; + 52 [shape=box label="Exit block"]; + 53 [shape=box label="Exit function test_2"]; + + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + 33 -> {34}; + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 38 -> {39 44}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {51}; + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {52}; + 52 -> {53}; +} + +subgraph test_3 { + 54 [shape=box label="Enter function test_3"]; + 55 [shape=box label="Enter block"]; + 56 [shape=box label="Enter when"]; + 57 [shape=box label="Enter when branch condition "]; + 58 [shape=box label="Access variable R|/b|"]; + 59 [shape=box label="Const: Boolean(true)"]; + 60 [shape=box label="Operator =="]; + 61 [shape=box label="Const: Boolean(false)"]; + 62 [shape=box label="Operator =="]; + 63 [shape=box label="Exit when branch condition"]; + 64 [shape=box label="Enter block"]; + 65 [shape=box label="Access variable R|/b|"]; + 66 [shape=box label="Function call: R|/b|.#()"]; + 67 [shape=box label="Exit block"]; + 68 [shape=box label="Exit when branch result"]; + 69 [shape=box label="Enter when branch condition else"]; + 70 [shape=box label="Exit when branch condition"]; + 71 [shape=box label="Enter block"]; + 72 [shape=box label="Access variable R|/b|"]; + 73 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 74 [shape=box label="Exit block"]; + 75 [shape=box label="Exit when branch result"]; + 76 [shape=box label="Exit when"]; + 77 [shape=box label="Exit block"]; + 78 [shape=box label="Exit function test_3"]; + + 54 -> {55}; + 55 -> {56}; + 56 -> {57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {63}; + 63 -> {64 69}; + 64 -> {65}; + 65 -> {66}; + 66 -> {67}; + 67 -> {68}; + 68 -> {76}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {77}; + 77 -> {78}; +} + +subgraph test_4 { + 79 [shape=box label="Enter function test_4"]; + 80 [shape=box label="Enter block"]; + 81 [shape=box label="Enter when"]; + 82 [shape=box label="Enter when branch condition "]; + 83 [shape=box label="Access variable R|/b|"]; + 84 [shape=box label="Const: Boolean(true)"]; + 85 [shape=box label="Operator =="]; + 86 [shape=box label="Const: Boolean(false)"]; + 87 [shape=box label="Operator !="]; + 88 [shape=box label="Exit when branch condition"]; + 89 [shape=box label="Enter block"]; + 90 [shape=box label="Access variable R|/b|"]; + 91 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 92 [shape=box label="Exit block"]; + 93 [shape=box label="Exit when branch result"]; + 94 [shape=box label="Enter when branch condition else"]; + 95 [shape=box label="Exit when branch condition"]; + 96 [shape=box label="Enter block"]; + 97 [shape=box label="Access variable R|/b|"]; + 98 [shape=box label="Function call: R|/b|.#()"]; + 99 [shape=box label="Exit block"]; + 100 [shape=box label="Exit when branch result"]; + 101 [shape=box label="Exit when"]; + 102 [shape=box label="Exit block"]; + 103 [shape=box label="Exit function test_4"]; + + 79 -> {80}; + 80 -> {81}; + 81 -> {82}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {88}; + 88 -> {89 94}; + 89 -> {90}; + 90 -> {91}; + 91 -> {92}; + 92 -> {93}; + 93 -> {101}; + 94 -> {95}; + 95 -> {96}; + 96 -> {97}; + 97 -> {98}; + 98 -> {99}; + 99 -> {100}; + 100 -> {101}; + 101 -> {102}; + 102 -> {103}; +} + +subgraph test_5 { + 104 [shape=box label="Enter function test_5"]; + 105 [shape=box label="Enter block"]; + 106 [shape=box label="Enter when"]; + 107 [shape=box label="Enter when branch condition "]; + 108 [shape=box label="Access variable R|/b|"]; + 109 [shape=box label="Const: Boolean(true)"]; + 110 [shape=box label="Operator !="]; + 111 [shape=box label="Const: Boolean(true)"]; + 112 [shape=box label="Operator =="]; + 113 [shape=box label="Exit when branch condition"]; + 114 [shape=box label="Enter block"]; + 115 [shape=box label="Access variable R|/b|"]; + 116 [shape=box label="Function call: R|/b|.#()"]; + 117 [shape=box label="Exit block"]; + 118 [shape=box label="Exit when branch result"]; + 119 [shape=box label="Enter when branch condition else"]; + 120 [shape=box label="Exit when branch condition"]; + 121 [shape=box label="Enter block"]; + 122 [shape=box label="Access variable R|/b|"]; + 123 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 124 [shape=box label="Exit block"]; + 125 [shape=box label="Exit when branch result"]; + 126 [shape=box label="Exit when"]; + 127 [shape=box label="Exit block"]; + 128 [shape=box label="Exit function test_5"]; + + 104 -> {105}; + 105 -> {106}; + 106 -> {107}; + 107 -> {108}; + 108 -> {109}; + 109 -> {110}; + 110 -> {111}; + 111 -> {112}; + 112 -> {113}; + 113 -> {114 119}; + 114 -> {115}; + 115 -> {116}; + 116 -> {117}; + 117 -> {118}; + 118 -> {126}; + 119 -> {120}; + 120 -> {121}; + 121 -> {122}; + 122 -> {123}; + 123 -> {124}; + 124 -> {125}; + 125 -> {126}; + 126 -> {127}; + 127 -> {128}; +} + +subgraph test_6 { + 129 [shape=box label="Enter function test_6"]; + 130 [shape=box label="Enter block"]; + 131 [shape=box label="Enter when"]; + 132 [shape=box label="Enter when branch condition "]; + 133 [shape=box label="Access variable R|/b|"]; + 134 [shape=box label="Const: Boolean(true)"]; + 135 [shape=box label="Operator !="]; + 136 [shape=box label="Const: Boolean(true)"]; + 137 [shape=box label="Operator !="]; + 138 [shape=box label="Exit when branch condition"]; + 139 [shape=box label="Enter block"]; + 140 [shape=box label="Access variable R|/b|"]; + 141 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 142 [shape=box label="Exit block"]; + 143 [shape=box label="Exit when branch result"]; + 144 [shape=box label="Enter when branch condition else"]; + 145 [shape=box label="Exit when branch condition"]; + 146 [shape=box label="Enter block"]; + 147 [shape=box label="Access variable R|/b|"]; + 148 [shape=box label="Function call: R|/b|.#()"]; + 149 [shape=box label="Exit block"]; + 150 [shape=box label="Exit when branch result"]; + 151 [shape=box label="Exit when"]; + 152 [shape=box label="Exit block"]; + 153 [shape=box label="Exit function test_6"]; + + 129 -> {130}; + 130 -> {131}; + 131 -> {132}; + 132 -> {133}; + 133 -> {134}; + 134 -> {135}; + 135 -> {136}; + 136 -> {137}; + 137 -> {138}; + 138 -> {139 144}; + 139 -> {140}; + 140 -> {141}; + 141 -> {142}; + 142 -> {143}; + 143 -> {151}; + 144 -> {145}; + 145 -> {146}; + 146 -> {147}; + 147 -> {148}; + 148 -> {149}; + 149 -> {150}; + 150 -> {151}; + 151 -> {152}; + 152 -> {153}; +} + +subgraph test_7 { + 154 [shape=box label="Enter function test_7"]; + 155 [shape=box label="Enter block"]; + 156 [shape=box label="Enter when"]; + 157 [shape=box label="Enter when branch condition "]; + 158 [shape=box label="Access variable R|/b|"]; + 159 [shape=box label="Const: Boolean(true)"]; + 160 [shape=box label="Operator !="]; + 161 [shape=box label="Const: Boolean(false)"]; + 162 [shape=box label="Operator =="]; + 163 [shape=box label="Exit when branch condition"]; + 164 [shape=box label="Enter block"]; + 165 [shape=box label="Access variable R|/b|"]; + 166 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 167 [shape=box label="Exit block"]; + 168 [shape=box label="Exit when branch result"]; + 169 [shape=box label="Enter when branch condition else"]; + 170 [shape=box label="Exit when branch condition"]; + 171 [shape=box label="Enter block"]; + 172 [shape=box label="Access variable R|/b|"]; + 173 [shape=box label="Function call: R|/b|.#()"]; + 174 [shape=box label="Exit block"]; + 175 [shape=box label="Exit when branch result"]; + 176 [shape=box label="Exit when"]; + 177 [shape=box label="Exit block"]; + 178 [shape=box label="Exit function test_7"]; + + 154 -> {155}; + 155 -> {156}; + 156 -> {157}; + 157 -> {158}; + 158 -> {159}; + 159 -> {160}; + 160 -> {161}; + 161 -> {162}; + 162 -> {163}; + 163 -> {164 169}; + 164 -> {165}; + 165 -> {166}; + 166 -> {167}; + 167 -> {168}; + 168 -> {176}; + 169 -> {170}; + 170 -> {171}; + 171 -> {172}; + 172 -> {173}; + 173 -> {174}; + 174 -> {175}; + 175 -> {176}; + 176 -> {177}; + 177 -> {178}; +} + +subgraph test_8 { + 179 [shape=box label="Enter function test_8"]; + 180 [shape=box label="Enter block"]; + 181 [shape=box label="Enter when"]; + 182 [shape=box label="Enter when branch condition "]; + 183 [shape=box label="Access variable R|/b|"]; + 184 [shape=box label="Const: Boolean(true)"]; + 185 [shape=box label="Operator !="]; + 186 [shape=box label="Const: Boolean(false)"]; + 187 [shape=box label="Operator !="]; + 188 [shape=box label="Exit when branch condition"]; + 189 [shape=box label="Enter block"]; + 190 [shape=box label="Access variable R|/b|"]; + 191 [shape=box label="Function call: R|/b|.#()"]; + 192 [shape=box label="Exit block"]; + 193 [shape=box label="Exit when branch result"]; + 194 [shape=box label="Enter when branch condition else"]; + 195 [shape=box label="Exit when branch condition"]; + 196 [shape=box label="Enter block"]; + 197 [shape=box label="Access variable R|/b|"]; + 198 [shape=box label="Function call: R|/b|.R|kotlin/Boolean.not|()"]; + 199 [shape=box label="Exit block"]; + 200 [shape=box label="Exit when branch result"]; + 201 [shape=box label="Exit when"]; + 202 [shape=box label="Exit block"]; + 203 [shape=box label="Exit function test_8"]; + + 179 -> {180}; + 180 -> {181}; + 181 -> {182}; + 182 -> {183}; + 183 -> {184}; + 184 -> {185}; + 185 -> {186}; + 186 -> {187}; + 187 -> {188}; + 188 -> {189 194}; + 189 -> {190}; + 190 -> {191}; + 191 -> {192}; + 192 -> {193}; + 193 -> {201}; + 194 -> {195}; + 195 -> {196}; + 196 -> {197}; + 197 -> {198}; + 198 -> {199}; + 199 -> {200}; + 200 -> {201}; + 201 -> {202}; + 202 -> {203}; +} + +} diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.kt b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.kt new file mode 100644 index 00000000000..05614a38909 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.kt @@ -0,0 +1,68 @@ +interface A { + fun foo() + val b: Boolean +} + +fun test_1(b: Boolean?) { + if ((b == true) == true) { + b.not() // OK + } else { + b.not() // Bad + } +} + +fun test_2(b: Boolean?) { + if ((b == true) != true) { + b.not() // Bad + } else { + b.not() // OK + } +} + +fun test_3(b: Boolean?) { + if ((b == true) == false) { + b.not() // Bad + } else { + b.not() // OK + } +} + +fun test_4(b: Boolean?) { + if ((b == true) != false) { + b.not() // OK + } else { + b.not() // Bad + } +} + +fun test_5(b: Boolean?) { + if ((b != true) == true) { + b.not() // Bad + } else { + b.not() // OK + } +} + +fun test_6(b: Boolean?) { + if ((b != true) != true) { + b.not() // OK + } else { + b.not() // Bad + } +} + +fun test_7(b: Boolean?) { + if ((b != true) == false) { + b.not() // OK + } else { + b.not() // Bad + } +} + +fun test_8(b: Boolean?) { + if ((b != true) != false) { + b.not() // Bad + } else { + b.not() // OK + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.txt b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.txt new file mode 100644 index 00000000000..543533b04fb --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.txt @@ -0,0 +1,96 @@ +FILE: equalsToBoolean.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + public abstract val b: R|kotlin/Boolean| + public get(): R|kotlin/Boolean| + + } + public final fun test_1(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + ==(==(R|/b|, Boolean(true)), Boolean(true)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + R|/b|.#() + } + } + + } + public final fun test_2(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + !=(==(R|/b|, Boolean(true)), Boolean(true)) -> { + R|/b|.#() + } + else -> { + R|/b|.R|kotlin/Boolean.not|() + } + } + + } + public final fun test_3(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + ==(==(R|/b|, Boolean(true)), Boolean(false)) -> { + R|/b|.#() + } + else -> { + R|/b|.R|kotlin/Boolean.not|() + } + } + + } + public final fun test_4(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + !=(==(R|/b|, Boolean(true)), Boolean(false)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + R|/b|.#() + } + } + + } + public final fun test_5(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + ==(!=(R|/b|, Boolean(true)), Boolean(true)) -> { + R|/b|.#() + } + else -> { + R|/b|.R|kotlin/Boolean.not|() + } + } + + } + public final fun test_6(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + !=(!=(R|/b|, Boolean(true)), Boolean(true)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + R|/b|.#() + } + } + + } + public final fun test_7(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + ==(!=(R|/b|, Boolean(true)), Boolean(false)) -> { + R|/b|.R|kotlin/Boolean.not|() + } + else -> { + R|/b|.#() + } + } + + } + public final fun test_8(b: R|kotlin/Boolean?|): R|kotlin/Unit| { + when () { + !=(!=(R|/b|, Boolean(true)), Boolean(false)) -> { + R|/b|.#() + } + else -> { + R|/b|.R|kotlin/Boolean.not|() + } + } + + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java index b885b01b970..41b54ad6103 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java @@ -119,6 +119,11 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest { runTest("compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt"); } + @TestMetadata("equalsToBoolean.kt") + public void testEqualsToBoolean() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/equalsToBoolean.kt"); + } + @TestMetadata("inPlaceLambdas.kt") public void testInPlaceLambdas() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/inPlaceLambdas.kt");