-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure that non-local returns work properly in inline functions
Also, ensure that the workaround for KT-58685 still works. It turns out, it was enough to move the `return` a bit to fix the issue. Fixes #3985
- Loading branch information
1 parent
5a570e1
commit 7a80e1c
Showing
5 changed files
with
173 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
kotlinx-coroutines-core/common/test/channels/ConsumeTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* Copyright 2016-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. | ||
*/ | ||
|
||
@file:OptIn(DelicateCoroutinesApi::class) | ||
package kotlinx.coroutines.channels | ||
|
||
import kotlinx.coroutines.* | ||
import kotlin.test.* | ||
|
||
class ConsumeTest: TestBase() { | ||
|
||
/** Check that [ReceiveChannel.consume] does not suffer from KT-58685 */ | ||
@Test | ||
fun testConsumeJsMiscompilation() = runTest { | ||
val channel = Channel<Int>() | ||
assertFailsWith<IndexOutOfBoundsException> { | ||
try { | ||
channel.consume { null } ?: throw IndexOutOfBoundsException() // should throw… | ||
} catch (e: Exception) { | ||
throw e // …but instead fails here | ||
} | ||
} | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block executes successfully. */ | ||
@Test | ||
fun testConsumeClosesOnSuccess() = runTest { | ||
val channel = Channel<Int>() | ||
channel.consume { } | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block executes successfully. */ | ||
@Test | ||
fun testConsumeClosesOnFailure() = runTest { | ||
val channel = Channel<Int>() | ||
try { | ||
channel.consume { throw TestException() } | ||
} catch (e: TestException) { | ||
// Expected | ||
} | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block does an early return. */ | ||
@Test | ||
fun testConsumeClosesOnEarlyReturn() = runTest { | ||
val channel = Channel<Int>() | ||
fun f() { | ||
try { | ||
channel.consume { return } | ||
} catch (e: TestException) { | ||
// Expected | ||
} | ||
} | ||
f() | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block executes successfully. */ | ||
@Test | ||
fun testConsumeEachClosesOnSuccess() = runTest { | ||
val channel = Channel<Int>(Channel.UNLIMITED) | ||
launch { channel.close() } | ||
channel.consumeEach { fail("unreached") } | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block executes successfully. */ | ||
@Test | ||
fun testConsumeEachClosesOnFailure() = runTest { | ||
val channel = Channel<Unit>(Channel.UNLIMITED) | ||
channel.send(Unit) | ||
try { | ||
channel.consumeEach { throw TestException() } | ||
} catch (e: TestException) { | ||
// Expected | ||
} | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Checks that [ReceiveChannel.consume] closes the channel when the block does an early return. */ | ||
@Test | ||
fun testConsumeEachClosesOnEarlyReturn() = runTest { | ||
val channel = Channel<Unit>(Channel.UNLIMITED) | ||
channel.send(Unit) | ||
suspend fun f() { | ||
channel.consumeEach { | ||
return@f | ||
} | ||
} | ||
f() | ||
assertTrue(channel.isClosedForReceive) | ||
} | ||
|
||
/** Check that [BroadcastChannel.consume] does not suffer from KT-58685 */ | ||
@OptIn(ObsoleteCoroutinesApi::class) | ||
@Suppress("DEPRECATION") | ||
@Test | ||
fun testBroadcastChannelConsumeJsMiscompilation() = runTest { | ||
val channel = BroadcastChannel<Int>(1) | ||
assertFailsWith<IndexOutOfBoundsException> { | ||
try { | ||
channel.consume { null } ?: throw IndexOutOfBoundsException() // should throw… | ||
} catch (e: Exception) { | ||
throw e // …but instead fails here | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters