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");
|
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
|
@Test
|
||||||
@TestMetadata("kt1001.kt")
|
@TestMetadata("kt1001.kt")
|
||||||
public void testKt1001() throws Exception {
|
public void testKt1001() throws Exception {
|
||||||
|
|||||||
+6
@@ -5626,6 +5626,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
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
|
@Test
|
||||||
@TestMetadata("kt1001.kt")
|
@TestMetadata("kt1001.kt")
|
||||||
public void testKt1001() throws Exception {
|
public void testKt1001() throws Exception {
|
||||||
|
|||||||
+6
@@ -5626,6 +5626,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalViaExplicitThis_before.kt");
|
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
|
@Test
|
||||||
@TestMetadata("kt1001.kt")
|
@TestMetadata("kt1001.kt")
|
||||||
public void testKt1001() throws Exception {
|
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.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
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() {
|
object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker() {
|
||||||
override fun check(expression: FirLoopJump, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirLoopJump, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
@@ -36,8 +34,19 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
|||||||
|
|
||||||
when (element) {
|
when (element) {
|
||||||
expression -> {
|
expression -> {
|
||||||
if (errorPathElements.any()) {
|
if (errorPathElements.isNotEmpty()) {
|
||||||
reporter.reportOn(expression.source, FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, context)
|
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
|
return true
|
||||||
}
|
}
|
||||||
@@ -63,17 +72,7 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
|||||||
if (findPathAndCheck(element.extensionReceiver) || findPathAndCheck(element.dispatchReceiver)) {
|
if (findPathAndCheck(element.extensionReceiver) || findPathAndCheck(element.dispatchReceiver)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (element.arguments.any(::findPathAndCheck)) 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is FirCall -> {
|
is FirCall -> {
|
||||||
for (argument in element.arguments) {
|
for (argument in element.arguments) {
|
||||||
|
|||||||
@@ -938,7 +938,13 @@ class ControlFlowProcessor(
|
|||||||
// See generateInitializersForClassOrObject && generateDeclarationForLocalClassOrObjectIfNeeded
|
// See generateInitializersForClassOrObject && generateDeclarationForLocalClassOrObjectIfNeeded
|
||||||
labelExprEnclosingFunc is ConstructorDescriptor && !labelExprEnclosingFunc.isPrimary
|
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
|
false
|
||||||
} else {
|
} 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");
|
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
|
@Test
|
||||||
@TestMetadata("kt1001.kt")
|
@TestMetadata("kt1001.kt")
|
||||||
public void testKt1001() throws Exception {
|
public void testKt1001() throws Exception {
|
||||||
|
|||||||
+4
-4
@@ -6,14 +6,14 @@
|
|||||||
fun case_1(value_1: Boolean) {
|
fun case_1(value_1: Boolean) {
|
||||||
while (value_1) {
|
while (value_1) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
<!UNSUPPORTED_FEATURE!>break<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|
||||||
loop@ for (i in 0..10) {
|
loop@ for (i in 0..10) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@loop<!>
|
<!UNSUPPORTED_FEATURE!>break@loop<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
@@ -23,14 +23,14 @@ fun case_1(value_1: Boolean) {
|
|||||||
fun case_2(value_1: Boolean) {
|
fun case_2(value_1: Boolean) {
|
||||||
for (i in 0..10) {
|
for (i in 0..10) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
<!UNSUPPORTED_FEATURE!>continue<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|
||||||
loop@ while (value_1) {
|
loop@ while (value_1) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue@loop<!>
|
<!UNSUPPORTED_FEATURE!>continue@loop<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -14,14 +14,14 @@
|
|||||||
fun case_1(value_1: Boolean) {
|
fun case_1(value_1: Boolean) {
|
||||||
while (value_1) {
|
while (value_1) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
<!UNSUPPORTED_FEATURE!>break<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|
||||||
loop@ for (i in 0..10) {
|
loop@ for (i in 0..10) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@loop<!>
|
<!UNSUPPORTED_FEATURE!>break@loop<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
@@ -31,14 +31,14 @@ fun case_1(value_1: Boolean) {
|
|||||||
fun case_2(value_1: Boolean) {
|
fun case_2(value_1: Boolean) {
|
||||||
for (i in 0..10) {
|
for (i in 0..10) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
<!UNSUPPORTED_FEATURE!>continue<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|
||||||
loop@ while (value_1) {
|
loop@ while (value_1) {
|
||||||
funWithExactlyOnceCallsInPlace {
|
funWithExactlyOnceCallsInPlace {
|
||||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue@loop<!>
|
<!UNSUPPORTED_FEATURE!>continue@loop<!>
|
||||||
}
|
}
|
||||||
println("1")
|
println("1")
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.fir.checkers
|
|||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||||
import org.jetbrains.kotlin.diagnostics.*
|
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.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
|
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.moduleData
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
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.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.name.*
|
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.findTypeSerializerOrContextUnchecked
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.fir.services.serializablePropertiesProvider
|
import org.jetbrains.kotlinx.serialization.compiler.fir.services.serializablePropertiesProvider
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.fir.services.versionReader
|
import org.jetbrains.kotlinx.serialization.compiler.fir.services.versionReader
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
|
||||||
object FirSerializationPluginClassChecker : FirClassChecker() {
|
object FirSerializationPluginClassChecker : FirClassChecker() {
|
||||||
private val JAVA_SERIALIZABLE_ID = ClassId.topLevel(FqName("java.io.Serializable"))
|
private val JAVA_SERIALIZABLE_ID = ClassId.topLevel(FqName("java.io.Serializable"))
|
||||||
|
|||||||
Reference in New Issue
Block a user