From ea0a30b15b8fc1c49a0aff30f363750ad16bbc8c Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 26 Jan 2021 11:06:29 +0300 Subject: [PATCH 1/3] Add callsInPlace to ReceiveChannel.consume Fixes #941 --- .../common/src/channels/Channels.common.kt | 7 ++++++- .../common/test/BuilderContractsTest.kt | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt index 60948f625d..e3567e3107 100644 --- a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt +++ b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt @@ -1,14 +1,16 @@ /* - * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ @file:JvmMultifileClass @file:JvmName("ChannelsKt") @file:Suppress("DEPRECATION_ERROR") +@file:OptIn(ExperimentalContracts::class) package kotlinx.coroutines.channels import kotlinx.coroutines.* import kotlinx.coroutines.selects.* +import kotlin.contracts.* import kotlin.coroutines.* import kotlin.jvm.* @@ -164,6 +166,9 @@ public fun consumesAll(vararg channels: ReceiveChannel<*>): CompletionHandler = * The operation is _terminal_. */ public inline fun ReceiveChannel.consume(block: ReceiveChannel.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } var cause: Throwable? = null try { return block() diff --git a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt index b20dd6b1d2..51828cfe5d 100644 --- a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt +++ b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt @@ -1,9 +1,10 @@ /* - * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.coroutines +import kotlinx.coroutines.channels.* import kotlinx.coroutines.selects.* import kotlin.test.* @@ -44,9 +45,18 @@ class BuilderContractsTest : TestBase() { Job().apply { complete() }.onJoin {} } consume(s) + + + val ch: Int + val i = Channel() + i.consume { + ch = 321 + } + consume(ch) } private fun consume(a: Int) { - a.hashCode() // BE codegen verification + assertNotEquals(0, a) + assertEquals(a.hashCode(), a) } -} \ No newline at end of file +} From 1b43fb6d3430f53ef843dae9bbabe86b73d456a2 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 26 Jan 2021 17:06:35 +0300 Subject: [PATCH 2/3] ~explanation --- kotlinx-coroutines-core/common/test/BuilderContractsTest.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt index 51828cfe5d..0870e3a7fd 100644 --- a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt +++ b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt @@ -56,6 +56,10 @@ class BuilderContractsTest : TestBase() { } private fun consume(a: Int) { + /* + * Verify the value is actually set correctly + * (non-zero, VerificationError is not triggered can be read) + */ assertNotEquals(0, a) assertEquals(a.hashCode(), a) } From 797f6dec5ac03b1c1d3e4e9d6ca010945a4869ff Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 26 Jan 2021 17:16:02 +0300 Subject: [PATCH 3/3] ~comma --- kotlinx-coroutines-core/common/test/BuilderContractsTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt index 0870e3a7fd..5a96c54460 100644 --- a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt +++ b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt @@ -58,7 +58,7 @@ class BuilderContractsTest : TestBase() { private fun consume(a: Int) { /* * Verify the value is actually set correctly - * (non-zero, VerificationError is not triggered can be read) + * (non-zero, VerificationError is not triggered, can be read) */ assertNotEquals(0, a) assertEquals(a.hashCode(), a)