Fix KT-71751
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
index fe6f09a..5cc7450 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
@@ -5,10 +5,12 @@
 
 package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
 
+import org.jetbrains.kotlin.config.LanguageFeature
 import org.jetbrains.kotlin.fir.FirTargetElement
 import org.jetbrains.kotlin.fir.expressions.*
 import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
 import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
+import org.jetbrains.kotlin.fir.languageVersionSettings
 import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
 import org.jetbrains.kotlin.fir.resolve.ResolutionMode
 import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
@@ -237,10 +239,15 @@
         val mayBeCoercionToUnitApplied = (data as? ResolutionMode.WithExpectedType)?.mayBeCoercionToUnitApplied == true
 
         val resolutionModeForLhs =
-            if (mayBeCoercionToUnitApplied && expectedType?.isUnitOrFlexibleUnit == true)
-                withExpectedType(expectedType, mayBeCoercionToUnitApplied = true)
-            else
-                withExpectedType(expectedType?.withNullability(nullable = true, session.typeContext))
+            when {
+                // In general, it feels ok to use Dependent mode for elvis LHS, but we still do that for LV == 2.0
+                session.languageVersionSettings.supportsFeature(LanguageFeature.ElvisInferenceImprovementsIn21) ->
+                    ResolutionMode.ContextDependent
+
+                mayBeCoercionToUnitApplied && expectedType?.isUnitOrFlexibleUnit == true ->
+                    withExpectedType(expectedType, mayBeCoercionToUnitApplied = true)
+                else -> withExpectedType(expectedType?.withNullability(nullable = true, session.typeContext))
+            }
         dataFlowAnalyzer.enterElvis(elvisExpression)
         elvisExpression.transformLhs(transformer, resolutionModeForLhs)
         dataFlowAnalyzer.exitElvisLhs(elvisExpression)
diff --git a/compiler/testData/codegen/box/unit/unitCoercionWithElvis.kt b/compiler/testData/codegen/box/unit/unitCoercionWithElvis.kt
index 9d79fda..90c061d 100644
--- a/compiler/testData/codegen/box/unit/unitCoercionWithElvis.kt
+++ b/compiler/testData/codegen/box/unit/unitCoercionWithElvis.kt
@@ -1,6 +1,5 @@
 // WITH_STDLIB
 // ISSUE: KT-71751
-// IGNORE_BACKEND_K2: ANY
 
 fun launch(x: () -> Unit) {
     x()
diff --git a/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.fir.kt b/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.fir.kt
deleted file mode 100644
index c9cafd5..0000000
--- a/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.fir.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-// ISSUE: KT-71751
-
-fun <R> myRun(x: () -> R): R = TODO()
-fun launch(x: () -> Unit) {}
-fun baz() {}
-
-fun main() {
-    launch {
-        // We should not run Unit-coercion for `myRun { null }`
-        myRun { null } <!USELESS_ELVIS!>?: baz()<!>
-    }
-}
diff --git a/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.kt b/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.kt
index 3da2e507..14c4637 100644
--- a/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.kt
+++ b/compiler/testData/diagnostics/tests/unitCoercion/elvisRHSRemainsNullable.kt
@@ -1,3 +1,4 @@
+// FIR_IDENTICAL
 // ISSUE: KT-71751
 
 fun <R> myRun(x: () -> R): R = TODO()
diff --git a/compiler/testData/diagnostics/tests/when/kt9972.fir.kt b/compiler/testData/diagnostics/tests/when/kt9972.fir.kt
index 4b3dde1..cea8d79 100644
--- a/compiler/testData/diagnostics/tests/when/kt9972.fir.kt
+++ b/compiler/testData/diagnostics/tests/when/kt9972.fir.kt
@@ -21,7 +21,7 @@
 
 fun test2(): Int {
     val x: String = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>when {
-                        true -> <!TYPE_MISMATCH!>Any()<!>
+                        true -> Any()
                         else -> null
                     } ?: return 0<!>
     return x.hashCode()
diff --git a/compiler/testData/ir/irText/expressions/kt30796.fir.ir.txt b/compiler/testData/ir/irText/expressions/kt30796.fir.ir.txt
deleted file mode 100644
index dcde403..0000000
--- a/compiler/testData/ir/irText/expressions/kt30796.fir.ir.txt
+++ /dev/null
@@ -1,160 +0,0 @@
-FILE fqName:<root> fileName:/kt30796.kt
-  FUN name:magic visibility:public modality:FINAL <T> () returnType:T of <root>.magic
-    TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
-    BLOCK_BODY
-      THROW type=kotlin.Nothing
-        CONSTRUCTOR_CALL 'public constructor <init> () declared in java.lang.Exception' type=java.lang.Exception origin=null
-  FUN name:test visibility:public modality:FINAL <T> (value:T of <root>.test, value2:T of <root>.test) returnType:kotlin.Unit
-    TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
-    VALUE_PARAMETER name:value index:0 type:T of <root>.test
-    VALUE_PARAMETER name:value2 index:1 type:T of <root>.test
-    BLOCK_BODY
-      VAR name:x1 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:T of <root>.test [val]
-            GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_0: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_0: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-      VAR name:x2 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:T of <root>.test [val]
-            GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_1: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: BLOCK type=kotlin.Any origin=ELVIS
-                VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:T of <root>.test [val]
-                  GET_VAR 'value2: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                WHEN type=kotlin.Any origin=null
-                  BRANCH
-                    if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                      arg0: GET_VAR 'val tmp_2: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                      arg1: CONST Null type=kotlin.Nothing? value=null
-                    then: CONST Int type=kotlin.Int value=42
-                  BRANCH
-                    if: CONST Boolean type=kotlin.Boolean value=true
-                    then: GET_VAR 'val tmp_2: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_1: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-      VAR name:x3 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Any? [val]
-            BLOCK type=kotlin.Any? origin=ELVIS
-              VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:T of <root>.test [val]
-                GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-              WHEN type=kotlin.Any? origin=null
-                BRANCH
-                  if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                    arg0: GET_VAR 'val tmp_4: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                    arg1: CONST Null type=kotlin.Nothing? value=null
-                  then: GET_VAR 'value2: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                BRANCH
-                  if: CONST Boolean type=kotlin.Boolean value=true
-                  then: GET_VAR 'val tmp_4: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_3: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_3: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-      VAR name:x4 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.Any? [val]
-            BLOCK type=kotlin.Any? origin=ELVIS
-              VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:T of <root>.test [val]
-                GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-              WHEN type=kotlin.Any? origin=null
-                BRANCH
-                  if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                    arg0: GET_VAR 'val tmp_6: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                    arg1: CONST Null type=kotlin.Nothing? value=null
-                  then: GET_VAR 'value2: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                BRANCH
-                  if: CONST Boolean type=kotlin.Boolean value=true
-                  then: GET_VAR 'val tmp_6: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_5: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_5: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-      VAR name:x5 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.Any? [val]
-            CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Any? origin=null
-              <T>: kotlin.Any?
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_7: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_7: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-      VAR name:x6 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_8 type:kotlin.Any? [val]
-            BLOCK type=kotlin.Any? origin=ELVIS
-              VAR IR_TEMPORARY_VARIABLE name:tmp_9 type:T of <root>.test [val]
-                GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-              WHEN type=kotlin.Any? origin=null
-                BRANCH
-                  if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                    arg0: GET_VAR 'val tmp_9: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                    arg1: CONST Null type=kotlin.Nothing? value=null
-                  then: CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Any? origin=null
-                    <T>: kotlin.Any?
-                BRANCH
-                  if: CONST Boolean type=kotlin.Boolean value=true
-                  then: GET_VAR 'val tmp_9: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_8: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_8: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-      VAR name:x7 type:kotlin.Any [val]
-        BLOCK type=kotlin.Any origin=ELVIS
-          VAR IR_TEMPORARY_VARIABLE name:tmp_10 type:kotlin.Any? [val]
-            BLOCK type=kotlin.Any? origin=ELVIS
-              VAR IR_TEMPORARY_VARIABLE name:tmp_11 type:kotlin.Any? [val]
-                CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Any? origin=null
-                  <T>: kotlin.Any?
-              WHEN type=kotlin.Any? origin=null
-                BRANCH
-                  if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                    arg0: GET_VAR 'val tmp_11: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                    arg1: CONST Null type=kotlin.Nothing? value=null
-                  then: GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
-                BRANCH
-                  if: CONST Boolean type=kotlin.Boolean value=true
-                  then: GET_VAR 'val tmp_11: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-          WHEN type=kotlin.Any origin=null
-            BRANCH
-              if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
-                arg0: GET_VAR 'val tmp_10: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
-                arg1: CONST Null type=kotlin.Nothing? value=null
-              then: CONST Int type=kotlin.Int value=42
-            BRANCH
-              if: CONST Boolean type=kotlin.Boolean value=true
-              then: GET_VAR 'val tmp_10: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
diff --git a/compiler/testData/ir/irText/expressions/kt30796.fir.kt.txt b/compiler/testData/ir/irText/expressions/kt30796.fir.kt.txt
deleted file mode 100644
index 4fa7d10..0000000
--- a/compiler/testData/ir/irText/expressions/kt30796.fir.kt.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-fun <T : Any?> magic(): T {
-  throw Exception()
-}
-
-fun <T : Any?> test(value: T, value2: T) {
-  val x1: Any = { // BLOCK
-    val tmp_0: T = value
-    when {
-      EQEQ(arg0 = tmp_0, arg1 = null) -> 42
-      else -> tmp_0
-    }
-  }
-  val x2: Any = { // BLOCK
-    val tmp_1: T = value
-    when {
-      EQEQ(arg0 = tmp_1, arg1 = null) -> { // BLOCK
-        val tmp_2: T = value2
-        when {
-          EQEQ(arg0 = tmp_2, arg1 = null) -> 42
-          else -> tmp_2
-        }
-      }
-      else -> tmp_1
-    }
-  }
-  val x3: Any = { // BLOCK
-    val tmp_3: Any? = { // BLOCK
-      val tmp_4: T = value
-      when {
-        EQEQ(arg0 = tmp_4, arg1 = null) -> value2
-        else -> tmp_4
-      }
-    }
-    when {
-      EQEQ(arg0 = tmp_3, arg1 = null) -> 42
-      else -> tmp_3
-    }
-  }
-  val x4: Any = { // BLOCK
-    val tmp_5: Any? = { // BLOCK
-      val tmp_6: T = value
-      when {
-        EQEQ(arg0 = tmp_6, arg1 = null) -> value2
-        else -> tmp_6
-      }
-    }
-    when {
-      EQEQ(arg0 = tmp_5, arg1 = null) -> 42
-      else -> tmp_5
-    }
-  }
-  val x5: Any = { // BLOCK
-    val tmp_7: Any? = magic<Any?>()
-    when {
-      EQEQ(arg0 = tmp_7, arg1 = null) -> 42
-      else -> tmp_7
-    }
-  }
-  val x6: Any = { // BLOCK
-    val tmp_8: Any? = { // BLOCK
-      val tmp_9: T = value
-      when {
-        EQEQ(arg0 = tmp_9, arg1 = null) -> magic<Any?>()
-        else -> tmp_9
-      }
-    }
-    when {
-      EQEQ(arg0 = tmp_8, arg1 = null) -> 42
-      else -> tmp_8
-    }
-  }
-  val x7: Any = { // BLOCK
-    val tmp_10: Any? = { // BLOCK
-      val tmp_11: Any? = magic<Any?>()
-      when {
-        EQEQ(arg0 = tmp_11, arg1 = null) -> value
-        else -> tmp_11
-      }
-    }
-    when {
-      EQEQ(arg0 = tmp_10, arg1 = null) -> 42
-      else -> tmp_10
-    }
-  }
-}
diff --git a/compiler/testData/ir/irText/expressions/kt30796.kt b/compiler/testData/ir/irText/expressions/kt30796.kt
index bfb0346..cee6817 100644
--- a/compiler/testData/ir/irText/expressions/kt30796.kt
+++ b/compiler/testData/ir/irText/expressions/kt30796.kt
@@ -1,3 +1,4 @@
+// FIR_IDENTICAL
 // IGNORE_BACKEND: JS_IR
 
 // KT-61141: throws kotlin.Exception instead of java.lang.Exception
diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
index 01db1a6..36db23a 100644
--- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
@@ -337,6 +337,7 @@
     ProhibitReturningIncorrectNullabilityValuesFromSamConstructorLambdaOfJdkInterfaces(KOTLIN_2_1, kind = BUG_FIX), // KT-57014
     ProhibitNothingAsCatchParameter(KOTLIN_2_1, kind = BUG_FIX), // KT-8322
     NullableNothingInReifiedPosition(KOTLIN_2_1, kind = UNSTABLE_FEATURE), // KT-54227, KT-67675
+    ElvisInferenceImprovementsIn21(KOTLIN_2_1, kind = OTHER), // KT-71751
 
     // It's not a fully blown LF, but mostly a way to manage potential unexpected semantic changes
     // See the single usage at org.jetbrains.kotlin.fir.types.ConeTypeApproximator.fastPathSkipApproximation