[FIR] Report more occurrences of NON_LOCAL_RETURN_NOT_ALLOWED

When an inline lambda is invoked or passed to another inline function,
make sure non-local returns are allowed by all surrounding declarations.
Otherwise, NON_LOCAL_RETURN_NOT_ALLOWED must be reported.

^KT-59884 Fixed
^KT-55319 Fixed
This commit is contained in:
Brian Norman
2023-10-31 11:25:39 -05:00
committed by Space Team
parent b3d33aee19
commit 3327bed5bd
19 changed files with 84 additions and 188 deletions
@@ -20,11 +20,11 @@ inline fun default0(lambda: () -> String, dlambda: () -> String = { noInlineFun
lambda() + dlambda()
}
inline fun default1_0(lambda: () -> String, dlambda: () -> String = { <!NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE!>lambda<!>() }) {
inline fun default1_0(lambda: () -> String, dlambda: () -> String = { <!NON_LOCAL_RETURN_NOT_ALLOWED, NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE!>lambda<!>() }) {
lambda() + dlambda()
}
inline fun default1_1(lambda: () -> String, noinline dlambda: () -> String = { lambda() }) {
inline fun default1_1(lambda: () -> String, noinline dlambda: () -> String = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>lambda<!>() }) {
lambda() + dlambda()
}
@@ -41,7 +41,7 @@ inline fun default1_3(noinline lambda: () -> String, noinline dlambda: () -> Str
}
inline fun default2_1(lambda: () -> String, noinline dlambda: () -> String = { inlineFun(lambda) }) {
inline fun default2_1(lambda: () -> String, noinline dlambda: () -> String = { inlineFun(<!NON_LOCAL_RETURN_NOT_ALLOWED!>lambda<!>) }) {
lambda() + dlambda()
}
@@ -1,23 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
val s = object {
val z = p()
fun a() {
p()
}
}
}
inline fun <R> inlineFun(p: () -> R) {
val s = object {
val z = p()
fun a() {
p()
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
@@ -1,48 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
val s = object {
val z = p();
init {
doCall {
p()
}
}
fun a() {
doCall {
p()
}
p()
}
}
}
inline fun <R> inlineFun(p: () -> R) {
val s = object {
val z = p()
init {
doCall {
p()
}
}
fun a() {
doCall {
p()
}
p()
}
}
}
inline fun <R> doCall(p: () -> R) {
p()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
@@ -1,9 +0,0 @@
inline fun testSameCaptured(lambdaWithResultCaptured: () -> Unit) : String {
doWork({lambdaWithResultCaptured()})
return "OK"
}
inline fun <R> doWork(crossinline job: ()-> R) : R {
return job()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
inline fun testSameCaptured(lambdaWithResultCaptured: () -> Unit) : String {
doWork({<!NON_LOCAL_RETURN_NOT_ALLOWED!>lambdaWithResultCaptured<!>()})
@@ -1,15 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
<!NOT_YET_SUPPORTED_IN_INLINE!>fun<!> a() {
val z = p()
}
a()
}
inline fun <R> inlineFun(p: () -> R) {
<!NOT_YET_SUPPORTED_IN_INLINE!>fun<!> a() {
p()
}
a()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
@@ -1,13 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
{
p()
}()
}
inline fun <R> inlineFun(p: () -> R) {
{
p()
}()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
@@ -1,23 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
<!NOT_YET_SUPPORTED_IN_INLINE!>class<!> A {
val z = p()
fun a() {
p()
}
}
}
inline fun <R> inlineFun(p: () -> R) {
<!NOT_YET_SUPPORTED_IN_INLINE!>class<!> A {
val z = p()
fun a() {
p()
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
inline fun <R> inlineFunOnlyLocal(crossinline p: () -> R) {
@@ -18,10 +18,10 @@ inline fun test(c: () -> Unit) {
c()
val o = object : Runnable {
override fun run() {
c()
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l = { c() }
val l = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
@@ -1,40 +0,0 @@
// !LANGUAGE: +ForbidExtensionCallsOnInlineFunctionalParameters
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE -UNUSED_PARAMETER
// SKIP_TXT
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import helpers.*
interface SuspendRunnable {
suspend fun run()
}
// Function is NOT suspend
// parameter is inline
// parameter is suspend
// Block is NOT allowed to be called inside the body of owner inline function
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
inline fun test(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>c: suspend () -> Unit<!>) {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
val o = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
val l: suspend () -> Unit = { c() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {}
suspend fun calculate() = "OK"
fun box() {
test {
calculate()
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +ForbidExtensionCallsOnInlineFunctionalParameters
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE -UNUSED_PARAMETER
// SKIP_TXT
@@ -16,10 +16,10 @@ suspend inline fun test(c: () -> Unit) {
c()
val o = object: Runnable {
override fun run() {
c()
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l = { c() }
val l = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
@@ -21,10 +21,10 @@ suspend inline fun test(c: suspend () -> Unit) {
c()
val o = object: SuspendRunnable {
override suspend fun run() {
c()
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l: suspend () -> Unit = { c() }
val l: suspend () -> Unit = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}