KT-1436 Nicer compiler errors when the feature isn't supported
This commit is contained in:
committed by
teamcity
parent
e6900ec0f2
commit
1215ae0fe7
+6
@@ -5626,6 +5626,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
+6
@@ -5626,6 +5626,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
+6
@@ -5626,6 +5626,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
+14
-15
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
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 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
||||
|
||||
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 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
||||
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) {
|
||||
|
||||
@@ -938,7 +938,13 @@ class ControlFlowProcessor(
|
||||
// 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 {
|
||||
|
||||
Vendored
+39
@@ -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<!> })
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -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
|
||||
|
||||
Generated
+6
@@ -5632,6 +5632,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
+4
-4
@@ -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_1(value_1: Boolean) {
|
||||
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")
|
||||
}
|
||||
|
||||
+4
-4
@@ -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_1(value_1: Boolean) {
|
||||
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")
|
||||
}
|
||||
|
||||
+3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.fir.checkers
|
||||
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.expressions.*
|
||||
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.dependencySeria
|
||||
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"))
|
||||
|
||||
Reference in New Issue
Block a user