FIR: Do not assume indexed assignment is always Unit-coerced

There are three cases where FirUnitExpression might be:
- Empty lambda (not our case)
- Explicit return with no expression (run { return@run })
- Indexed assignment `a[0] = 1`

In the second case, we've got a convention that this should
unconditionally turn the lambda's return type to Unit (see KT-67867)
So, we coerce-to-unit any last expression independently of its type.

But we shouldn't do the same for the third case

^KT-74474 Fixed
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt
index 6f5a443..8bbda90 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt
@@ -59,8 +59,8 @@
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.contract
 
-fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection<FirExpression>): Boolean =
-    isLambda && returnStatements.any { it is FirUnitExpression }
+fun FirAnonymousFunction.lambdaWithExplicitEmptyReturns(returnStatements: Collection<FirExpression>): Boolean =
+    isLambda && returnStatements.any { it is FirUnitExpression && it.source?.kind == KtFakeSourceElementKind.ImplicitUnit.Return }
 
 /**
  * Infers the return type of an anonymous function from return expressions in its body.
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt
index 8b2b797..893b87e 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt
@@ -18,7 +18,7 @@
 import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError
 import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition
 import org.jetbrains.kotlin.fir.resolve.isImplicitUnitForEmptyLambda
-import org.jetbrains.kotlin.fir.resolve.shouldReturnUnit
+import org.jetbrains.kotlin.fir.resolve.lambdaWithExplicitEmptyReturns
 import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
 import org.jetbrains.kotlin.fir.types.*
@@ -234,7 +234,8 @@
         val returnTypeRef = lambda.anonymousFunction.returnTypeRef.let {
             it as? FirResolvedTypeRef ?: it.resolvedTypeFromPrototype(substituteAlreadyFixedVariables(lambda.returnType))
         }
-        val isUnitLambda = returnTypeRef.coneType.isUnitOrFlexibleUnit || lambda.anonymousFunction.shouldReturnUnit(returnArguments)
+        val isLastExpressionCoercedToUnit =
+            returnTypeRef.coneType.isUnitOrFlexibleUnit || lambda.anonymousFunction.lambdaWithExplicitEmptyReturns(returnArguments)
 
         for (atom in returnAtoms) {
             val expression = atom.expression
@@ -250,7 +251,7 @@
             //    }
             //  Things get even weirder if T has an upper bound incompatible with Unit.
             val haveSubsystem = c.addSubsystemFromAtom(atom)
-            if (isLastExpression && isUnitLambda) {
+            if (isLastExpression && isLastExpressionCoercedToUnit) {
                 // That "if" is necessary because otherwise we would force a lambda return type
                 // to be inferred from completed last expression.
                 // See `test1` at testData/diagnostics/tests/inference/coercionToUnit/afterBareReturn.kt
diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambda.fir.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambda.fir.kt
index 911fd62..4e3bfcb 100644
--- a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambda.fir.kt
+++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambda.fir.kt
@@ -3,7 +3,7 @@
 
 fun foo(x: () -> String) {}
 fun main(a: Array<String>) {
-    foo <!ARGUMENT_TYPE_MISMATCH!>{
-        a[0] = ""
-    }<!>
+    foo {
+        <!RETURN_TYPE_MISMATCH!>a[0] = ""<!>
+    }
 }
diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.fir.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.fir.kt
index 8e334f4..36837bd 100644
--- a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.fir.kt
+++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.fir.kt
@@ -1,4 +1,4 @@
-// RUN_PIPELINE_TILL: BACKEND
+// RUN_PIPELINE_TILL: FRONTEND
 // ISSUE: KT-74478
 
 fun foo(x: () -> String) {}
@@ -6,6 +6,6 @@
 fun bar(a: MutableList<String>, b: Boolean) {
     foo {
         if (b) return@foo ""
-        a[0] = "" // should be an error here
+        <!RETURN_TYPE_MISMATCH!>a[0] = ""<!> // should be an error here
     }
 }
diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.kt
index 0900340..8c1e32b 100644
--- a/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.kt
+++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/lastStatementInNonUnitLambdaWithRegularReturn.kt
@@ -1,4 +1,4 @@
-// RUN_PIPELINE_TILL: BACKEND
+// RUN_PIPELINE_TILL: FRONTEND
 // ISSUE: KT-74478
 
 fun foo(x: () -> String) {}