NI: add fallback strategy to get lexical scope to checking coroutine call legality
^KT-40247 Fixed ^KT-40337 Fixed
This commit is contained in:
+10
@@ -4691,6 +4691,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideTry.kt")
|
||||
public void testSuspendInvokeInsideTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideTry.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideWhen.kt")
|
||||
public void testSuspendInvokeInsideWhen() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideWhen.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/callableReference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+2
-2
@@ -64,10 +64,10 @@ fun findEnclosingSuspendFunction(context: CallCheckerContext, checkingCall: KtEl
|
||||
val scope = if (context.resolutionContext !is CallResolutionContext<*> || context.resolutionContext.call.callElement == checkingCall) {
|
||||
context.scope
|
||||
} else {
|
||||
context.trace.get(BindingContext.LEXICAL_SCOPE, checkingCall)
|
||||
context.trace.get(BindingContext.LEXICAL_SCOPE, checkingCall) ?: context.scope
|
||||
}
|
||||
|
||||
return scope?.parentsWithSelf?.firstOrNull {
|
||||
return scope.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS && it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNCHECKED_CAST
|
||||
|
||||
class Foo {
|
||||
suspend operator fun <T> invoke(body: () -> T) = null as T
|
||||
}
|
||||
|
||||
suspend fun main() {
|
||||
val retry = Foo()
|
||||
try {
|
||||
retry { 1 } // Before the fix: "Suspend function 'invoke' should be called only from a coroutine or another suspend function"
|
||||
} catch (e: Exception) { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
public suspend fun main(): kotlin.Unit
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend operator fun </*0*/ T> invoke(/*0*/ body: () -> T): T
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNCHECKED_CAST
|
||||
|
||||
internal class Demo() {
|
||||
suspend operator fun <T> invoke(name: String, block: suspend () -> T): T {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun demo(callback: suspend () -> Unit) = when {
|
||||
true -> {
|
||||
val demo = Demo()
|
||||
demo("test") { callback() } // Before the fix: "Suspend function 'invoke' should be called only from a coroutine or another suspend function"
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
public suspend fun demo(/*0*/ callback: suspend () -> kotlin.Unit): kotlin.Unit
|
||||
|
||||
internal final class Demo {
|
||||
public constructor Demo()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend operator fun </*0*/ T> invoke(/*0*/ name: kotlin.String, /*1*/ block: suspend () -> T): T
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -4698,6 +4698,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideTry.kt")
|
||||
public void testSuspendInvokeInsideTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideTry.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideWhen.kt")
|
||||
public void testSuspendInvokeInsideWhen() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideWhen.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/callableReference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+10
@@ -4693,6 +4693,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideTry.kt")
|
||||
public void testSuspendInvokeInsideTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideTry.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendInvokeInsideWhen.kt")
|
||||
public void testSuspendInvokeInsideWhen() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/coroutines/suspendInvokeInsideWhen.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/callableReference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user