KT-1436 Nicer compiler errors when the feature isn't supported
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
index 86c64d9..5ca8020 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
@@ -5627,6 +5627,12 @@
             }
 
             @Test
+            @TestMetadata("inlinedBreakContinueFeatureDisabled.kt")
+            public void testInlinedBreakContinueFeatureDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt");
+            }
+
+            @Test
             @TestMetadata("kt1001.kt")
             public void testKt1001() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1001.kt");
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
index d18e89b..036e686 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
@@ -5627,6 +5627,12 @@
             }
 
             @Test
+            @TestMetadata("inlinedBreakContinueFeatureDisabled.kt")
+            public void testInlinedBreakContinueFeatureDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt");
+            }
+
+            @Test
             @TestMetadata("kt1001.kt")
             public void testKt1001() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1001.kt");
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
index 72eefa6..1bcf440 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
@@ -5627,6 +5627,12 @@
             }
 
             @Test
+            @TestMetadata("inlinedBreakContinueFeatureDisabled.kt")
+            public void testInlinedBreakContinueFeatureDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt");
+            }
+
+            @Test
             @TestMetadata("kt1001.kt")
             public void testKt1001() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1001.kt");
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
index 40ca7c0..8284992 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
@@ -14,8 +14,6 @@
 import org.jetbrains.kotlin.fir.declarations.*
 import org.jetbrains.kotlin.fir.expressions.*
 import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
-import org.jetbrains.kotlin.fir.resolvedSymbol
-import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
 
 object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker() {
     override fun check(expression: FirLoopJump, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -36,8 +34,19 @@
 
             when (element) {
                 expression -> {
-                    if (errorPathElements.any()) {
-                        reporter.reportOn(expression.source, FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, context)
+                    if (errorPathElements.isNotEmpty()) {
+                        val hasNonInline = errorPathElements.any {
+                            when(it) {
+                                is FirAnonymousFunction -> it.inlineStatus != InlineStatus.Inline
+                                is FirAnonymousFunctionExpression -> it.anonymousFunction.inlineStatus != InlineStatus.Inline
+                                else -> true
+                            }}
+                        if (hasNonInline) {
+                            reporter.reportOn(expression.source, FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, context)
+                        } else if (!allowInlined) {
+                            reporter.reportOn(expression.source, FirErrors.UNSUPPORTED_FEATURE,
+                                LanguageFeature.BreakContinueInInlineLambdas to context.languageVersionSettings, context)
+                        }
                     }
                     return true
                 }
@@ -63,17 +72,7 @@
                     if (findPathAndCheck(element.extensionReceiver) || findPathAndCheck(element.dispatchReceiver)) {
                         return true
                     }
-
-                    val symbol = if (allowInlined) element.calleeReference.resolvedSymbol as? FirFunctionSymbol else null
-                    element.arguments.forEachIndexed { i, argument ->
-                        val expressionToCheck =
-                            if (symbol?.resolvedStatus?.isInline == true
-                                && !symbol.valueParameterSymbols[i].run { isNoinline || isCrossinline }
-                            ) argument.tryInline() else argument
-                        if (findPathAndCheck(expressionToCheck)) {
-                            return true
-                        }
-                    }
+                    if (element.arguments.any(::findPathAndCheck)) return true
                 }
                 is FirCall -> {
                     for (argument in element.arguments) {
diff --git a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
index ed015f8..cc5b93c 100644
--- a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
+++ b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
@@ -938,7 +938,13 @@
                     // See generateInitializersForClassOrObject && generateDeclarationForLocalClassOrObjectIfNeeded
                     labelExprEnclosingFunc is ConstructorDescriptor && !labelExprEnclosingFunc.isPrimary
                 ) {
-                    trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression))
+                    val dependsOnInlineLambdas = !skipInlineFunctions &&
+                            getEnclosingFunctionDescriptor(bindingContext, jumpExpression, true) == getEnclosingFunctionDescriptor(bindingContext, jumpTarget, true)
+                    if (dependsOnInlineLambdas) {
+                        trace.report(UNSUPPORTED_FEATURE.on(jumpExpression, BreakContinueInInlineLambdas to languageVersionSettings))
+                    } else {
+                        trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression))
+                    }
                 }
                 false
             } else {
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt
new file mode 100644
index 0000000..28e8105
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt
@@ -0,0 +1,39 @@
+// FIR_IDENTICAL
+// LANGUAGE: -BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// IGNORE_ERRORS
+// WITH_STDLIB
+
+inline fun foo(block: () -> Unit) { block() }
+
+inline fun bar(block1: () -> Unit, noinline block2: () -> Unit, crossinline block3: () -> Unit = {}) {
+    block1()
+    block2()
+    block3()
+}
+
+fun test1() {
+    while (true) {
+        foo { <!UNSUPPORTED_FEATURE!>break<!> }
+        foo { <!UNSUPPORTED_FEATURE!>continue<!> }
+        foo(fun () { <!UNSUPPORTED_FEATURE!>break<!> })
+        foo(fun () { <!UNSUPPORTED_FEATURE!>continue<!> })
+    }
+}
+
+fun test2() {
+    while (true) {
+        bar({<!UNSUPPORTED_FEATURE!>break<!>}, {})
+        bar({<!UNSUPPORTED_FEATURE!>continue<!>}, {})
+
+        bar(fun () {<!UNSUPPORTED_FEATURE!>break<!>}, fun () {})
+        bar(fun () {<!UNSUPPORTED_FEATURE!>continue<!>}, fun () {})
+    }
+}
+
+fun test3() {
+    while (true) {
+        bar({}, { <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!> }, { <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!> })
+        bar({}, { <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!> }, { <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!> })
+    }
+}
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.txt
new file mode 100644
index 0000000..3d91ae6
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.txt
@@ -0,0 +1,8 @@
+package
+
+public inline fun bar(/*0*/ block1: () -> kotlin.Unit, /*1*/ noinline block2: () -> kotlin.Unit, /*2*/ crossinline block3: () -> kotlin.Unit = ...): kotlin.Unit
+public inline fun foo(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
+public fun test1(): kotlin.Unit
+public fun test2(): kotlin.Unit
+public fun test3(): kotlin.Unit
+
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
index 0615dbd..6669f71 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
@@ -5633,6 +5633,12 @@
             }
 
             @Test
+            @TestMetadata("inlinedBreakContinueFeatureDisabled.kt")
+            public void testInlinedBreakContinueFeatureDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/inlinedBreakContinueFeatureDisabled.kt");
+            }
+
+            @Test
             @TestMetadata("kt1001.kt")
             public void testKt1001() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1001.kt");
diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.fir.kt
index 3c61b57..a9d8b20 100644
--- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.fir.kt
+++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.fir.kt
@@ -6,14 +6,14 @@
 fun case_1(value_1: Boolean) {
     while (value_1) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
+            <!UNSUPPORTED_FEATURE!>break<!>
         }
         println("1")
     }
 
     loop@ for (i in 0..10) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@loop<!>
+            <!UNSUPPORTED_FEATURE!>break@loop<!>
         }
         println("1")
     }
@@ -23,14 +23,14 @@
 fun case_2(value_1: Boolean) {
     for (i in 0..10) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
+            <!UNSUPPORTED_FEATURE!>continue<!>
         }
         println("1")
     }
 
     loop@ while (value_1) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue@loop<!>
+            <!UNSUPPORTED_FEATURE!>continue@loop<!>
         }
         println("1")
     }
diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.kt
index 80cc42e..d9e8d21 100644
--- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.kt
+++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/unreachableCode/neg/1.kt
@@ -14,14 +14,14 @@
 fun case_1(value_1: Boolean) {
     while (value_1) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
+            <!UNSUPPORTED_FEATURE!>break<!>
         }
         println("1")
     }
 
     loop@ for (i in 0..10) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@loop<!>
+            <!UNSUPPORTED_FEATURE!>break@loop<!>
         }
         println("1")
     }
@@ -31,14 +31,14 @@
 fun case_2(value_1: Boolean) {
     for (i in 0..10) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
+            <!UNSUPPORTED_FEATURE!>continue<!>
         }
         println("1")
     }
 
     loop@ while (value_1) {
         funWithExactlyOnceCallsInPlace {
-            <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue@loop<!>
+            <!UNSUPPORTED_FEATURE!>continue@loop<!>
         }
         println("1")
     }
diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt
index 0550df6..0e7283b 100644
--- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt
+++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt
@@ -8,6 +8,7 @@
 import org.jetbrains.kotlin.KtSourceElement
 import org.jetbrains.kotlin.config.KotlinCompilerVersion
 import org.jetbrains.kotlin.diagnostics.*
+import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
 import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
 import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
@@ -18,6 +19,7 @@
 import org.jetbrains.kotlin.fir.moduleData
 import org.jetbrains.kotlin.fir.resolve.defaultType
 import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.*
 import org.jetbrains.kotlin.fir.types.*
 import org.jetbrains.kotlin.name.*
@@ -30,6 +32,7 @@
 import org.jetbrains.kotlinx.serialization.compiler.fir.services.findTypeSerializerOrContextUnchecked
 import org.jetbrains.kotlinx.serialization.compiler.fir.services.serializablePropertiesProvider
 import org.jetbrains.kotlinx.serialization.compiler.fir.services.versionReader
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
 
 object FirSerializationPluginClassChecker : FirClassChecker() {
     private val JAVA_SERIALIZABLE_ID = ClassId.topLevel(FqName("java.io.Serializable"))