diff --git a/CHANGES.md b/CHANGES.md
index 656a818ea0..510c35accf 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,23 @@
# Change log for kotlinx.coroutines
+## Version 1.5.1
+
+* Atomic `update`, `getAndUpdate`, and `updateAndGet` operations of `MutableStateFlow` (#2720).
+* `Executor.asCoroutineDispatcher` implementation improvements (#2601):
+ * If the target executor is `ScheduledExecutorService`, then its `schedule` API is used for time-related coroutine operations.
+ * `RemoveOnCancelPolicy` is now part of the public contract.
+* Introduced overloads for `Task.asDeferred` and `Task.await` that accept `CancellationTokenSource` for bidirectional cancellation (#2527).
+* Reactive streams are updated to `1.0.3` (#2740).
+* `CopyableThrowable` is allowed to modify the exception message during stacktrace recovery (#1931).
+* `CoroutineDispatcher.releaseInterceptedContinuation` is now a `final` method (#2785).
+* Closing a Handler underlying `Handler.asCoroutineDispatcher` now causes the dispatched coroutines to be canceled on `Dispatchers.IO (#2778)`.
+* Kotlin is updated to 1.5.20.
+* Fixed a spurious `ClassCastException` in `releaseInterceptedContinuation` and `IllegalStateException` from `tryReleaseClaimedContinuation` (#2736, #2768).
+* Fixed inconsistent exception message during stacktrace recovery for non-suspending channel iterators (#2749).
+* Fixed linear stack usage for `CompletableFuture.asDeferred` when the target future has a long chain of listeners (#2730).
+* Any exceptions from `CoroutineDispatcher.isDispatchNeeded` are now considered as fatal and are propagated to the caller (#2733).
+* Internal `DebugProbesKt` (used in the debugger implementation) are moved from `debug` to `core` module.
+
## Version 1.5.0
Note that this is a full changelog relative to 1.4.3 version. Changelog relative to 1.5.0-RC can be found in the end.
diff --git a/README.md b/README.md
index fab386fa43..3cdce4387b 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,12 @@
[![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
-[![Download](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.5.0)](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.5.0/pom)
-[![Kotlin](https://img.shields.io/badge/kotlin-1.5.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
+[![Download](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.5.1)](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.5.1/pom)
+[![Kotlin](https://img.shields.io/badge/kotlin-1.5.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Slack channel](https://img.shields.io/badge/chat-slack-green.svg?logo=slack)](https://kotlinlang.slack.com/messages/coroutines/)
Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
-This is a companion version for the Kotlin `1.5.0` release.
+This is a companion version for the Kotlin `1.5.20` release.
```kotlin
suspend fun main() = coroutineScope {
@@ -35,7 +35,7 @@ suspend fun main() = coroutineScope {
* [select] expression support and more.
* [core/jvm](kotlinx-coroutines-core/jvm/) — additional core features available on Kotlin/JVM:
* [Dispatchers.IO] dispatcher for blocking coroutines;
- * [Executor.asCoroutineDispatcher] extension, custom thread pools, and more.
+ * [Executor.asCoroutineDispatcher][asCoroutineDispatcher] extension, custom thread pools, and more.
* [core/js](kotlinx-coroutines-core/js/) — additional core features available on Kotlin/JS:
* Integration with `Promise` via [Promise.await] and [promise] builder;
* Integration with `Window` via [Window.asCoroutineDispatcher], etc.
@@ -83,7 +83,7 @@ Add dependencies (you can also add other modules that you need):
org.jetbrains.kotlinx
kotlinx-coroutines-core
- 1.5.0
+ 1.5.1
```
@@ -91,7 +91,7 @@ And make sure that you use the latest Kotlin version:
```xml
- 1.5.0
+ 1.5.20
```
@@ -101,7 +101,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'
}
```
@@ -109,7 +109,7 @@ And make sure that you use the latest Kotlin version:
```groovy
buildscript {
- ext.kotlin_version = '1.5.0'
+ ext.kotlin_version = '1.5.20'
}
```
@@ -127,7 +127,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1")
}
```
@@ -135,7 +135,7 @@ And make sure that you use the latest Kotlin version:
```groovy
plugins {
- kotlin("jvm") version "1.5.0"
+ kotlin("jvm") version "1.5.20"
}
```
@@ -147,7 +147,7 @@ Add [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android)
module as a dependency when using `kotlinx.coroutines` on Android:
```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1'
```
This gives you access to the Android [Dispatchers.Main]
@@ -180,7 +180,7 @@ In common code that should get compiled for different platforms, you can add a d
```groovy
commonMain {
dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1")
}
}
```
@@ -192,7 +192,7 @@ Platform-specific dependencies are recommended to be used only for non-multiplat
#### JS
Kotlin/JS version of `kotlinx.coroutines` is published as
-[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.5.0/jar)
+[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.5.1/jar)
(follow the link to get the dependency declaration snippet) and as [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) NPM package.
#### Native
@@ -233,10 +233,10 @@ See [Contributing Guidelines](CONTRIBUTING.md).
[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
[Dispatchers.IO]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html
-[Executor.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.util.concurrent.-executor/as-coroutine-dispatcher.html
-[Promise.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/kotlin.js.-promise/await.html
+[asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-coroutine-dispatcher.html
+[Promise.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/await.html
[promise]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/promise.html
-[Window.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/org.w3c.dom.-window/as-coroutine-dispatcher.html
+[Window.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-coroutine-dispatcher.html
@@ -261,7 +261,7 @@ See [Contributing Guidelines](CONTRIBUTING.md).
-[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html
+[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/set-main.html
[TestCoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scope/index.html
@@ -281,23 +281,23 @@ See [Contributing Guidelines](CONTRIBUTING.md).
-[CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/await.html
+[CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/await.html
-[ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/await.html
+[ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/await.html
-[Task.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/com.google.android.gms.tasks.-task/await.html
+[Task.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/await.html
-[Publisher.collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/collect.html
-[Publisher.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-single.html
+[Publisher.collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/collect.html
+[Publisher.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/await-single.html
[kotlinx.coroutines.reactive.publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/publish.html
diff --git a/build.gradle b/build.gradle
index fc52d8cc53..e4b12ff3ad 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,16 +1,20 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
+
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.konan.target.HostManager
import org.gradle.util.VersionNumber
+import org.jetbrains.dokka.gradle.DokkaTaskPartial
+import org.jetbrains.dokka.gradle.DokkaMultiModuleTask
apply plugin: 'jdk-convention'
-apply from: rootProject.file("gradle/experimental.gradle")
+apply from: rootProject.file("gradle/opt-in.gradle")
def coreModule = "kotlinx-coroutines-core"
// Not applicable for Kotlin plugin
-def sourceless = ['kotlinx.coroutines', 'site', 'kotlinx-coroutines-bom', 'integration-testing']
-def internal = ['kotlinx.coroutines', 'site', 'benchmarks', 'js-stub', 'stdlib-stubs', 'integration-testing']
+def sourceless = ['kotlinx.coroutines', 'kotlinx-coroutines-bom', 'integration-testing']
+def internal = ['kotlinx.coroutines', 'benchmarks', 'integration-testing']
// Not published
def unpublished = internal + ['example-frontend-js', 'android-unit-tests']
@@ -32,9 +36,6 @@ buildscript {
throw new IllegalArgumentException("'kotlin_snapshot_version' should be defined when building with snapshot compiler")
}
}
- // These three flags are enabled in train builds for JVM IR compiler testing
- ext.jvm_ir_enabled = rootProject.properties['enable_jvm_ir'] != null
- ext.jvm_ir_api_check_enabled = rootProject.properties['enable_jvm_ir_api_check'] != null
ext.native_targets_enabled = rootProject.properties['disable_native_targets'] == null
// Determine if any project dependency is using a snapshot version
@@ -42,7 +43,7 @@ buildscript {
rootProject.properties.each { key, value ->
if (key.endsWith("_version") && value instanceof String && value.endsWith("-SNAPSHOT")) {
println("NOTE: USING SNAPSHOT VERSION: $key=$value")
- ext.using_snapshot_version=true
+ ext.using_snapshot_version = true
}
}
@@ -53,11 +54,10 @@ buildscript {
}
repositories {
- // Leftover until we migrated to Dokka 1.4.30
- maven { url "https://kotlin.bintray.com/kotlin-dev" }
- maven { url "https://jetbrains.bintray.com/kotlin-native-dependencies" }
+ mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
+ mavenLocal()
}
dependencies {
@@ -74,9 +74,6 @@ buildscript {
CacheRedirector.configureBuildScript(buildscript, rootProject)
}
-
-import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
-
// todo:KLUDGE: Hierarchical project structures are not fully supported in IDEA, enable only for a regular built
if (!Idea.active) {
ext.set("kotlin.mpp.enableGranularSourceSetsMetadata", "true")
@@ -127,7 +124,6 @@ apply plugin: "binary-compatibility-validator"
apiValidation {
ignoredProjects += unpublished + ["kotlinx-coroutines-bom"]
if (build_snapshot_train) {
- ignoredProjects.remove("site")
ignoredProjects.remove("example-frontend-js")
ignoredProjects.add("kotlinx-coroutines-core")
}
@@ -166,9 +162,8 @@ configure(subprojects.findAll { !sourceless.contains(it.name) }) {
// Configure options for all Kotlin compilation tasks
tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
- kotlinOptions.freeCompilerArgs += experimentalAnnotations.collect { "-Xuse-experimental=" + it }
+ kotlinOptions.freeCompilerArgs += optInAnnotations.collect { "-Xopt-in=" + it }
kotlinOptions.freeCompilerArgs += "-progressive"
- kotlinOptions.freeCompilerArgs += "-XXLanguage:+InlineClasses"
// Disable KT-36770 for RxJava2 integration
kotlinOptions.freeCompilerArgs += "-XXLanguage:-ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated"
// Remove null assertions to get smaller bytecode on Android
@@ -227,11 +222,12 @@ configure(subprojects.findAll {
}
def core_docs_url = "https://kotlin.github.io/kotlinx.coroutines/$coreModule/"
-def core_docs_file = "$projectDir/kotlinx-coroutines-core/build/dokka/kotlinx-coroutines-core/package-list"
+def core_docs_file = "$projectDir/kotlinx-coroutines-core/build/dokka/htmlPartial/package-list"
+apply plugin: "org.jetbrains.dokka"
configure(subprojects.findAll { !unpublished.contains(it.name) }) {
if (it.name != 'kotlinx-coroutines-bom') {
- apply from: rootProject.file('gradle/dokka.gradle')
+ apply from: rootProject.file('gradle/dokka.gradle.kts')
}
apply from: rootProject.file('gradle/publish.gradle')
}
@@ -239,11 +235,12 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
configure(subprojects.findAll { !unpublished.contains(it.name) }) {
if (it.name != "kotlinx-coroutines-bom") {
if (it.name != coreModule) {
- dokka.dependsOn project(":$coreModule").dokka
- tasks.withType(dokka.getClass()) {
- externalDocumentationLink {
- url = new URL(core_docs_url)
- packageListUrl = new File(core_docs_file).toURI().toURL()
+ tasks.withType(DokkaTaskPartial.class) {
+ dokkaSourceSets.configureEach {
+ externalDocumentationLink {
+ url.set(new URL(core_docs_url))
+ packageListUrl.set(new File(core_docs_file).toURI().toURL())
+ }
}
}
}
@@ -276,15 +273,43 @@ apply plugin: 'kotlinx-knit'
knit {
siteRoot = "https://kotlin.github.io/kotlinx.coroutines"
moduleRoots = [".", "integration", "reactive", "ui"]
+ moduleDocs = "build/dokka/htmlPartial"
+ dokkaMultiModuleRoot = "build/dokka/htmlMultiModule/"
}
-knitPrepare.dependsOn getTasksByName("dokka", true)
+knitPrepare.dependsOn getTasksByName("dokkaHtmlMultiModule", true)
-// Disable binary compatibility check for JVM IR compiler output by default
-if (jvm_ir_enabled) {
- subprojects { project ->
- configure(tasks.matching { it.name == "apiCheck" }) {
- enabled = enabled && jvm_ir_api_check_enabled
- }
+dependencies {
+ dokkaHtmlMultiModulePlugin("org.jetbrains.kotlinx:dokka-pathsaver-plugin:$knit_version")
+}
+
+// Opt-in for build scan in order to troubleshoot Gradle on TC
+if (hasProperty('buildScan')) {
+ buildScan {
+ termsOfServiceUrl = 'https://gradle.com/terms-of-service'
+ termsOfServiceAgree = 'yes'
}
}
+
+/*
+ * kotlinx-coroutines-core dependency leaks into test runtime classpath via kotlin-compiler-embeddable
+ * and conflicts with our own test/runtime incompatibilities (e.g. when class is moved from a main to test),
+ * so we do substitution here
+ */
+allprojects { subProject ->
+ subProject
+ .configurations
+ .matching {
+ // Excluding substituted project itself because of circular dependencies, but still do it
+ // for "*Test*" configurations
+ subProject.name != "kotlinx-coroutines-core" || it.name.contains("Test")
+ }
+ .configureEach { conf ->
+ conf.resolutionStrategy.dependencySubstitution {
+ substitute(module("org.jetbrains.kotlinx:kotlinx-coroutines-core"))
+ .using(project(":kotlinx-coroutines-core"))
+ .because("Because Kotlin compiler embeddable leaks coroutines into the runtime classpath, " +
+ "triggering all sort of incompatible class changes errors")
+ }
+ }
+}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 80214522b8..c54e226af1 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -12,13 +12,11 @@ val cacheRedirectorEnabled = System.getenv("CACHE_REDIRECTOR")?.toBoolean() == t
val buildSnapshotTrain = properties["build_snapshot_train"]?.toString()?.toBoolean() == true
repositories {
+ mavenCentral()
if (cacheRedirectorEnabled) {
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org/m2")
- maven("https://cache-redirector.jetbrains.com/dl.bintray.com/kotlin/kotlin-dev")
} else {
maven("https://plugins.gradle.org/m2")
- // Leftover until we migrated to Dokka 1.4.30
- maven("https://dl.bintray.com/kotlin/kotlin-dev")
}
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
@@ -47,4 +45,5 @@ fun version(target: String): String {
dependencies {
implementation(kotlin("gradle-plugin", version("kotlin")))
implementation("org.jetbrains.dokka:dokka-gradle-plugin:${version("dokka")}")
+ implementation("org.jetbrains.dokka:dokka-core:${version("dokka")}")
}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
index c2e859f65d..e30c3ee597 100644
--- a/buildSrc/settings.gradle.kts
+++ b/buildSrc/settings.gradle.kts
@@ -4,6 +4,7 @@
pluginManagement {
val build_snapshot_train: String? by settings
repositories {
+ maven(url = "https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev/")
val cacheRedirectorEnabled = System.getenv("CACHE_REDIRECTOR")?.toBoolean() == true
if (cacheRedirectorEnabled) {
println("Redirecting repositories for buildSrc buildscript")
diff --git a/buildSrc/src/main/kotlin/CacheRedirector.kt b/buildSrc/src/main/kotlin/CacheRedirector.kt
index 9f6efd2cdc..bcadd7364e 100644
--- a/buildSrc/src/main/kotlin/CacheRedirector.kt
+++ b/buildSrc/src/main/kotlin/CacheRedirector.kt
@@ -21,46 +21,15 @@ private val cacheRedirectorEnabled = System.getenv("CACHE_REDIRECTOR")?.toBoolea
private val mirroredUrls = listOf(
"https://cdn.azul.com/zulu/bin",
"https://clojars.org/repo",
- "https://dl.bintray.com/d10xa/maven",
- "https://dl.bintray.com/groovy/maven",
- "https://dl.bintray.com/jetbrains/maven-patched",
- "https://dl.bintray.com/jetbrains/scala-plugin-deps",
- "https://dl.bintray.com/kodein-framework/Kodein-DI",
- "https://dl.bintray.com/konsoletyper/teavm",
- "https://dl.bintray.com/kotlin/kotlin-dev",
- "https://dl.bintray.com/kotlin/kotlin-eap",
- "https://dl.bintray.com/kotlin/kotlinx.html",
- "https://dl.bintray.com/kotlin/kotlinx",
- "https://dl.bintray.com/kotlin/ktor",
- "https://dl.bintray.com/scalacenter/releases",
- "https://dl.bintray.com/scalamacros/maven",
- "https://dl.bintray.com/kotlin/exposed",
- "https://dl.bintray.com/cy6ergn0m/maven",
- "https://dl.bintray.com/kotlin/kotlin-js-wrappers",
"https://dl.google.com/android/repository",
"https://dl.google.com/dl/android/maven2",
"https://dl.google.com/dl/android/studio/ide-zips",
"https://dl.google.com/go",
"https://download.jetbrains.com",
- "https://jcenter.bintray.com",
- "https://jetbrains.bintray.com/dekaf",
- "https://jetbrains.bintray.com/intellij-jbr",
- "https://jetbrains.bintray.com/intellij-jdk",
- "https://jetbrains.bintray.com/intellij-plugin-service",
- "https://jetbrains.bintray.com/intellij-terraform",
- "https://jetbrains.bintray.com/intellij-third-party-dependencies",
- "https://jetbrains.bintray.com/jediterm",
- "https://jetbrains.bintray.com/kotlin-native-dependencies",
- "https://jetbrains.bintray.com/markdown",
- "https://jetbrains.bintray.com/teamcity-rest-client",
- "https://jetbrains.bintray.com/test-discovery",
- "https://jetbrains.bintray.com/wormhole",
"https://jitpack.io",
"https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev",
"https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap",
"https://maven.pkg.jetbrains.space/kotlin/p/kotlin/eap",
- "https://kotlin.bintray.com/dukat",
- "https://kotlin.bintray.com/kotlin-dependencies",
"https://oss.sonatype.org/content/repositories/releases",
"https://oss.sonatype.org/content/repositories/snapshots",
"https://oss.sonatype.org/content/repositories/staging",
@@ -85,10 +54,7 @@ private val mirroredUrls = listOf(
)
private val aliases = mapOf(
- "https://repo.maven.apache.org/maven2" to "https://repo1.maven.org/maven2", // Maven Central
- "https://kotlin.bintray.com/kotlin-dev" to "https://dl.bintray.com/kotlin/kotlin-dev",
- "https://kotlin.bintray.com/kotlin-eap" to "https://dl.bintray.com/kotlin/kotlin-eap",
- "https://kotlin.bintray.com/kotlinx" to "https://dl.bintray.com/kotlin/kotlinx"
+ "https://repo.maven.apache.org/maven2" to "https://repo1.maven.org/maven2" // Maven Central
)
private fun URI.toCacheRedirectorUri() = URI("https://cache-redirector.jetbrains.com/$host/$path")
diff --git a/buildSrc/src/main/kotlin/Dokka.kt b/buildSrc/src/main/kotlin/Dokka.kt
index f37aa7c151..a6b06ee1a9 100644
--- a/buildSrc/src/main/kotlin/Dokka.kt
+++ b/buildSrc/src/main/kotlin/Dokka.kt
@@ -2,13 +2,11 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-import org.gradle.api.Project
-import org.gradle.kotlin.dsl.delegateClosureOf
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink.Builder
-import org.jetbrains.dokka.gradle.DokkaTask
-import java.io.File
-import java.net.URL
+import org.gradle.api.*
+import org.gradle.kotlin.dsl.*
+import org.jetbrains.dokka.gradle.*
+import java.io.*
+import java.net.*
/**
* Package-list by external URL for documentation generation.
@@ -17,10 +15,12 @@ fun Project.externalDocumentationLink(
url: String,
packageList: File = projectDir.resolve("package.list")
) {
- tasks.withType().configureEach {
- externalDocumentationLink(delegateClosureOf {
- this.url = URL(url)
- packageListUrl = packageList.toPath().toUri().toURL()
- })
+ tasks.withType().configureEach {
+ dokkaSourceSets.configureEach {
+ externalDocumentationLink {
+ this.url.set(URL(url))
+ packageListUrl.set(packageList.toPath().toUri().toURL())
+ }
+ }
}
}
diff --git a/buildSrc/src/main/kotlin/Publishing.kt b/buildSrc/src/main/kotlin/Publishing.kt
index e0124cd966..8c6dd5de3d 100644
--- a/buildSrc/src/main/kotlin/Publishing.kt
+++ b/buildSrc/src/main/kotlin/Publishing.kt
@@ -40,12 +40,8 @@ fun MavenPom.configureMavenCentralMetadata(project: Project) {
}
fun mavenRepositoryUri(): URI {
- // TODO -SNAPSHOT detection can be made here as well
val repositoryId: String? = System.getenv("libs.repository.id")
return if (repositoryId == null) {
- // Using implicitly created staging, for MPP it's likely to be a mistake because
- // publication on TeamCity will create 3 independent staging repositories
- System.err.println("Warning: using an implicitly created staging for coroutines")
URI("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
} else {
URI("https://oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId")
diff --git a/buildSrc/src/main/kotlin/RunR8.kt b/buildSrc/src/main/kotlin/RunR8.kt
deleted file mode 100644
index b0fccf89fc..0000000000
--- a/buildSrc/src/main/kotlin/RunR8.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.JavaExec
-import org.gradle.api.tasks.OutputDirectory
-import org.gradle.api.tasks.bundling.Zip
-import org.gradle.kotlin.dsl.get
-import org.gradle.kotlin.dsl.named
-import java.io.File
-
-/*
- * Task used by our ui/android tests to test minification results
- * and keep track of size of the binary.
- * TODO move back to kotlinx-coroutines-android when it's migrated to the kts
- */
-open class RunR8 : JavaExec() {
-
- @OutputDirectory
- lateinit var outputDex: File
-
- @InputFile
- lateinit var inputConfig: File
-
- @InputFile
- val inputConfigCommon: File = File("testdata/r8-test-common.pro")
-
- @InputFiles
- val jarFile: File = project.tasks.named("jar").get().archivePath
-
- init {
- classpath = project.configurations["r8"]
- main = "com.android.tools.r8.R8"
- }
-
- override fun exec() {
- // Resolve classpath only during execution
- val arguments = mutableListOf(
- "--release",
- "--no-desugaring",
- "--output", outputDex.absolutePath,
- "--pg-conf", inputConfig.absolutePath
- )
- arguments.addAll(project.configurations["runtimeClasspath"].files.map { it.absolutePath })
- arguments.add(jarFile.absolutePath)
-
- args = arguments
-
- project.delete(outputDex)
- outputDex.mkdirs()
-
- super.exec()
- }
-}
diff --git a/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts b/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
index 5f3193428c..c7744f8702 100644
--- a/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
+++ b/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
@@ -15,12 +15,6 @@ java {
targetCompatibility = JavaVersion.VERSION_1_6
}
-if (rootProject.extra.get("jvm_ir_enabled") as Boolean) {
- kotlin.target.compilations.configureEach {
- kotlinOptions.useIR = true
- }
-}
-
dependencies {
testImplementation(kotlin("test"))
// Workaround to make addSuppressed work in tests
diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md
index 7aa51e2642..5221db922a 100644
--- a/docs/topics/cancellation-and-timeouts.md
+++ b/docs/topics/cancellation-and-timeouts.md
@@ -447,15 +447,15 @@ This example always prints zero. Resources do not leak.
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-and-join.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable.html
+[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
-
\ No newline at end of file
+
diff --git a/docs/topics/channels.md b/docs/topics/channels.md
index 9380b2bdfb..7f41eaec2b 100644
--- a/docs/topics/channels.md
+++ b/docs/topics/channels.md
@@ -626,7 +626,7 @@ delay between elements.
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[kotlin.coroutines.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/kotlin.coroutines.-coroutine-context/cancel-children.html
+[kotlin.coroutines.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-children.html
[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
@@ -640,7 +640,7 @@ delay between elements.
[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel.html
[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/ticker.html
[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/cancel.html
-[TickerMode.FIXED_DELAY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-ticker-mode/-f-i-x-e-d_-d-e-l-a-y.html
+[TickerMode.FIXED_DELAY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-ticker-mode/-f-i-x-e-d_-d-e-l-a-y/index.html
diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md
index 9c1a26a910..e244d8c218 100644
--- a/docs/topics/composing-suspending-functions.md
+++ b/docs/topics/composing-suspending-functions.md
@@ -406,7 +406,7 @@ Computation failed with ArithmeticException
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y.html
+[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y/index.html
[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/start.html
[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md
index 402db103b4..c35de0e084 100644
--- a/docs/topics/coroutine-context-and-dispatchers.md
+++ b/docs/topics/coroutine-context-and-dispatchers.md
@@ -678,8 +678,8 @@ that should be implemented.
[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
[MainScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
-[asContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/as-context-element.html
-[ensurePresent]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/ensure-present.html
+[asContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html
+[ensurePresent]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html
[ThreadContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html
diff --git a/docs/topics/debugging.md b/docs/topics/debugging.md
index d18df7f465..5ff4d549e0 100644
--- a/docs/topics/debugging.md
+++ b/docs/topics/debugging.md
@@ -63,7 +63,10 @@ Exception copy logic is straightforward:
1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
`null` can be returned from `createCopy` to opt-out specific exception from being recovered.
2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
- 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
+ 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
+ 4) If the reflective copy has a changed message (exception constructor passed a modified `message` parameter to the superclass),
+ the exception is not copied in order to preserve a human-readable message. [CopyableThrowable] does not have such a limitation
+ and allows the copy to have a `message` different from that of the original.
## Debug agent
diff --git a/docs/topics/exception-handling.md b/docs/topics/exception-handling.md
index 4cff42f357..3facd51a22 100644
--- a/docs/topics/exception-handling.md
+++ b/docs/topics/exception-handling.md
@@ -508,7 +508,7 @@ The scope is completed
[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html
diff --git a/docs/topics/flow.md b/docs/topics/flow.md
index 9dd84f3f4b..7acc4f99a8 100644
--- a/docs/topics/flow.md
+++ b/docs/topics/flow.md
@@ -1852,7 +1852,7 @@ Integration modules include conversions from and to `Flow`, integration with Rea
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
[ensureActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html
[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
@@ -1890,7 +1890,7 @@ Integration modules include conversions from and to `Flow`, integration with Rea
[catch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/catch.html
[onCompletion]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-completion.html
[launchIn]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html
-[IntRange.asFlow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/kotlin.ranges.-int-range/as-flow.html
+[IntRange.asFlow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/as-flow.html
[cancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/cancellable.html
diff --git a/gradle.properties b/gradle.properties
index 5fbf33229e..2983dd11a0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,26 +3,26 @@
#
# Kotlin
-version=1.5.0-SNAPSHOT
+version=1.5.1-SNAPSHOT
group=org.jetbrains.kotlinx
-kotlin_version=1.5.0
+kotlin_version=1.5.20
# Dependencies
junit_version=4.12
junit5_version=5.7.0
-atomicfu_version=0.16.1
-knit_version=0.2.3
+atomicfu_version=0.16.2
+knit_version=0.3.0
html_version=0.7.2
-lincheck_version=2.12
-dokka_version=0.9.16-rdev-2-mpp-hacks
+lincheck_version=2.14
+dokka_version=1.5.0
byte_buddy_version=1.10.9
reactor_version=3.4.1
-reactive_streams_version=1.0.2
+reactive_streams_version=1.0.3
rxjava2_version=2.2.8
rxjava3_version=3.0.2
javafx_version=11.0.2
javafx_plugin_version=0.0.8
-binary_compatibility_validator_version=0.5.0
+binary_compatibility_validator_version=0.6.0
blockhound_version=1.0.2.RELEASE
jna_version=5.5.0
@@ -53,6 +53,6 @@ jekyll_version=4.0
# JS IR backend sometimes crashes with out-of-memory
# TODO: Remove once KT-37187 is fixed
-org.gradle.jvmargs=-Xmx2g
+org.gradle.jvmargs=-Xmx4g
kotlin.mpp.enableCompatibilityMetadataVariant=true
diff --git a/gradle/compile-js-multiplatform.gradle b/gradle/compile-js-multiplatform.gradle
index 1e885db0c5..d6df7e403a 100644
--- a/gradle/compile-js-multiplatform.gradle
+++ b/gradle/compile-js-multiplatform.gradle
@@ -46,7 +46,7 @@ compileJsLegacy.configure {
kotlinOptions {
// drop -js suffix from outputFile
def baseName = project.name - "-js"
- outputFile = new File(outputFile.parent, baseName + ".js")
+ outputFile = new File(outputFileProperty.get().parent, baseName + ".js")
}
}
diff --git a/gradle/compile-jvm-multiplatform.gradle b/gradle/compile-jvm-multiplatform.gradle
index 1f861f800c..5e65042746 100644
--- a/gradle/compile-jvm-multiplatform.gradle
+++ b/gradle/compile-jvm-multiplatform.gradle
@@ -6,13 +6,7 @@ sourceCompatibility = 1.6
targetCompatibility = 1.6
kotlin {
- jvm {
- if (rootProject.ext.jvm_ir_enabled) {
- compilations.all {
- kotlinOptions.useIR = true
- }
- }
- }
+ jvm {}
sourceSets {
jvmTest.dependencies {
api "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
diff --git a/gradle/dokka.gradle b/gradle/dokka.gradle
deleted file mode 100644
index f0cad15442..0000000000
--- a/gradle/dokka.gradle
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-// Configures generation of JavaDoc & Dokka artifacts
-
-def makeLinkMapping(dokka, projectDir) {
- dokka.linkMapping {
- def relPath = rootProject.projectDir.toPath().relativize(projectDir.toPath())
- dir = "$projectDir/src"
- url = "https://github.com/kotlin/kotlinx.coroutines/tree/master/$relPath/src"
- suffix = "#L"
- }
-}
-
-configurations {
- dokkaStubs.extendsFrom compileOnly
- configureKotlinJvmPlatform(dokkaStubs)
-}
-
-apply plugin: 'org.jetbrains.dokka'
-
-tasks.withType(dokka.getClass()) {
- jdkVersion = 8
- includes = ['README.md']
-}
-
-dependencies {
- dokkaStubs project(":stdlib-stubs")
-}
-
-
-dokka {
- kotlinTasks { [] }
- outputFormat = 'kotlin-website'
- dependsOn(project.configurations.dokkaStubs)
-
- noStdlibLink = true
-
- externalDocumentationLink {
- packageListUrl = rootProject.projectDir.toPath().resolve("site/stdlib.package.list").toUri().toURL()
- url = new URL("https://kotlinlang.org/api/latest/jvm/stdlib/")
- }
-
- if (project.name != "kotlinx-coroutines-core") {
- dependsOn(project.configurations.compileClasspath)
- dependsOn(project.sourceSets.main.output)
- doFirst {
- // resolve classpath only during execution
- classpath = project.configurations.dokkaStubs.files + project.configurations.compileClasspath.files + project.sourceSets.main.output.files
- }
- }
-}
-
-if (project.name == "kotlinx-coroutines-core") {
- // Custom configuration for MPP modules
- dependencies {
- dokkaStubs project(":js-stub") // so that JS library reference can resolve properly
- dokkaStubs project(":kotlinx-coroutines-core")
- }
-
- dokka {
- kotlinTasks { [] }
- suppressedModifiers = ['actual']
- makeLinkMapping(it, projectDir)
- makeLinkMapping(it, project.file("js"))
- makeLinkMapping(it, project.file("jvm"))
- makeLinkMapping(it, project.file("native"))
- makeLinkMapping(it, project.file("common"))
- // source roots
- impliedPlatforms = ['JVM', 'JS', 'Native']
- sourceRoot {
- path = rootProject.file("$project.name/common/src")
- }
- sourceRoot {
- path = rootProject.file("$project.name/jvm/src")
- platforms = ['JVM']
- }
- sourceRoot {
- path = rootProject.file("$project.name/js/src")
- platforms = ['JS']
- }
- sourceRoot {
- path = rootProject.file("$project.name/native/src")
- platforms = ['Native']
- }
- doFirst {
- classpath = project.configurations.dokkaStubs.files +
- project.configurations.jvmCompileClasspath.files +
- project.kotlin.targets.jvm.compilations.main.output.allOutputs
- }
- }
-}
diff --git a/gradle/dokka.gradle.kts b/gradle/dokka.gradle.kts
new file mode 100644
index 0000000000..659890a30b
--- /dev/null
+++ b/gradle/dokka.gradle.kts
@@ -0,0 +1,75 @@
+import org.jetbrains.dokka.gradle.*
+import java.net.*
+
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// Configures generation of JavaDoc & Dokka artifacts
+apply()
+//apply()
+
+fun GradleDokkaSourceSetBuilder.makeLinkMapping(projectDir: File) {
+ sourceLink {
+ val relPath = rootProject.projectDir.toPath().relativize(projectDir.toPath())
+ localDirectory.set(projectDir.resolve("src"))
+ remoteUrl.set(URL("https://github.com/kotlin/kotlinx.coroutines/tree/master/$relPath/src"))
+ remoteLineSuffix.set("#L")
+ }
+}
+
+val knit_version: String by project
+tasks.withType(DokkaTaskPartial::class).configureEach {
+ dependencies {
+ plugins("org.jetbrains.kotlinx:dokka-pathsaver-plugin:$knit_version")
+ }
+}
+
+tasks.withType(DokkaTaskPartial::class).configureEach {
+ suppressInheritedMembers.set(true)
+ dokkaSourceSets.configureEach {
+ jdkVersion.set(11)
+ includes.from("README.md")
+ noStdlibLink.set(true)
+
+ externalDocumentationLink {
+ url.set(URL("https://kotlinlang.org/api/latest/jvm/stdlib/"))
+ packageListUrl.set(rootProject.projectDir.toPath().resolve("site/stdlib.package.list").toUri().toURL())
+ }
+
+ if (project.name != "kotlinx-coroutines-core") {
+ dependsOn(project.configurations["compileClasspath"])
+ doFirst {
+ // resolve classpath only during execution
+ classpath.from(project.configurations["compileClasspath"].files)// + project.sourceSets.main.output.files)
+ }
+ }
+ }
+}
+
+if (project.name == "kotlinx-coroutines-core") {
+ // Custom configuration for MPP modules
+ tasks.withType(DokkaTaskPartial::class).configureEach {
+ dokkaSourceSets {
+ val commonMain by getting {
+ makeLinkMapping(project.file("common"))
+ }
+
+ val nativeMain by getting {
+ makeLinkMapping(project.file("native"))
+ }
+
+ val jsMain by getting {
+ makeLinkMapping(project.file("js"))
+ }
+
+ val jvmMain by getting {
+ makeLinkMapping(project.file("jvm"))
+ }
+
+ configureEach {
+ classpath.from(project.configurations["jvmCompileClasspath"].files)
+ }
+ }
+ }
+}
diff --git a/gradle/experimental.gradle b/gradle/opt-in.gradle
similarity index 84%
rename from gradle/experimental.gradle
rename to gradle/opt-in.gradle
index 11aeb6d8a6..bcf6bebe94 100644
--- a/gradle/experimental.gradle
+++ b/gradle/opt-in.gradle
@@ -2,11 +2,10 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// For new mpp
-ext.experimentalAnnotations = [
- "kotlin.Experimental",
+ext.optInAnnotations = [
"kotlin.experimental.ExperimentalTypeInference",
"kotlin.ExperimentalMultiplatform",
+ "kotlinx.coroutines.DelicateCoroutinesApi",
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.ObsoleteCoroutinesApi",
"kotlinx.coroutines.InternalCoroutinesApi",
diff --git a/integration/kotlinx-coroutines-guava/README.md b/integration/kotlinx-coroutines-guava/README.md
index 130cf0a058..34b8e5818f 100644
--- a/integration/kotlinx-coroutines-guava/README.md
+++ b/integration/kotlinx-coroutines-guava/README.md
@@ -56,9 +56,12 @@ Integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/L
-[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/kotlinx.coroutines.-coroutine-scope/future.html
-[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/index.html
-[com.google.common.util.concurrent.ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/await.html
-[kotlinx.coroutines.Deferred.asListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/kotlinx.coroutines.-deferred/as-listenable-future.html
+[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/future.html
+[com.google.common.util.concurrent.ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/await.html
+[kotlinx.coroutines.Deferred.asListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/as-listenable-future.html
+
+
+
+[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/https://google.github.io/guava/releases/28.0-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html
diff --git a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
index 35e0aeb379..8f11e0a916 100644
--- a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
+++ b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
@@ -136,11 +136,13 @@ public fun ListenableFuture.asDeferred(): Deferred {
override fun onSuccess(result: T?) {
// Here we work with flexible types, so we unchecked cast to trick the type system
@Suppress("UNCHECKED_CAST")
- deferred.complete(result as T)
+ runCatching { deferred.complete(result as T) }
+ .onFailure { handleCoroutineException(EmptyCoroutineContext, it) }
}
override fun onFailure(t: Throwable) {
- deferred.completeExceptionally(t)
+ runCatching { deferred.completeExceptionally(t) }
+ .onFailure { handleCoroutineException(EmptyCoroutineContext, it) }
}
}, MoreExecutors.directExecutor())
diff --git a/integration/kotlinx-coroutines-guava/test/FutureAsDeferredUnhandledCompletionExceptionTest.kt b/integration/kotlinx-coroutines-guava/test/FutureAsDeferredUnhandledCompletionExceptionTest.kt
new file mode 100644
index 0000000000..d6469a947e
--- /dev/null
+++ b/integration/kotlinx-coroutines-guava/test/FutureAsDeferredUnhandledCompletionExceptionTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.guava
+
+import com.google.common.util.concurrent.*
+import kotlinx.coroutines.*
+import org.junit.*
+import org.junit.Test
+import kotlin.test.*
+
+class FutureAsDeferredUnhandledCompletionExceptionTest : TestBase() {
+
+ // This is a separate test in order to avoid interference with uncaught exception handlers in other tests
+ private val exceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
+ private lateinit var caughtException: Throwable
+
+ @Before
+ fun setUp() {
+ Thread.setDefaultUncaughtExceptionHandler { _, e -> caughtException = e }
+ }
+
+ @After
+ fun tearDown() {
+ Thread.setDefaultUncaughtExceptionHandler(exceptionHandler)
+ }
+
+ @Test
+ fun testLostExceptionOnSuccess() = runTest {
+ val future = SettableFuture.create()
+ val deferred = future.asDeferred()
+ deferred.invokeOnCompletion { throw TestException() }
+ future.set(1)
+ assertTrue { caughtException is CompletionHandlerException && caughtException.cause is TestException }
+ }
+
+ @Test
+ fun testLostExceptionOnFailure() = runTest {
+ val future = SettableFuture.create()
+ val deferred = future.asDeferred()
+ deferred.invokeOnCompletion { throw TestException() }
+ future.setException(TestException2())
+ assertTrue { caughtException is CompletionHandlerException && caughtException.cause is TestException }
+ }
+}
diff --git a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
index c463174a8d..69ba193071 100644
--- a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
+++ b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
@@ -11,6 +11,7 @@ import org.junit.Ignore
import org.junit.Test
import java.util.concurrent.*
import java.util.concurrent.CancellationException
+import java.util.concurrent.atomic.*
import kotlin.test.*
class ListenableFutureTest : TestBase() {
@@ -755,4 +756,23 @@ class ListenableFutureTest : TestBase() {
future(start = CoroutineStart.ATOMIC) { }
future(start = CoroutineStart.UNDISPATCHED) { }
}
+
+ @Test
+ fun testStackOverflow() = runTest {
+ val future = SettableFuture.create()
+ val completed = AtomicLong()
+ val count = 10000L
+ val children = ArrayList()
+ for (i in 0 until count) {
+ children += launch(Dispatchers.Default) {
+ future.asDeferred().await()
+ completed.incrementAndGet()
+ }
+ }
+ future.set(1)
+ withTimeout(60_000) {
+ children.forEach { it.join() }
+ assertEquals(count, completed.get())
+ }
+ }
}
diff --git a/integration/kotlinx-coroutines-jdk8/README.md b/integration/kotlinx-coroutines-jdk8/README.md
index aebd90f06a..35808c6f3d 100644
--- a/integration/kotlinx-coroutines-jdk8/README.md
+++ b/integration/kotlinx-coroutines-jdk8/README.md
@@ -60,9 +60,9 @@ Integration with JDK8 [CompletableFuture] (Android API level 24).
-[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/kotlinx.coroutines.-coroutine-scope/future.html
-[java.util.concurrent.CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/await.html
-[java.util.concurrent.CompletionStage.asDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/as-deferred.html
-[kotlinx.coroutines.Deferred.asCompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/kotlinx.coroutines.-deferred/as-completable-future.html
+[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/future.html
+[java.util.concurrent.CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/await.html
+[java.util.concurrent.CompletionStage.asDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/as-deferred.html
+[kotlinx.coroutines.Deferred.asCompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/as-completable-future.html
diff --git a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
index 7e9c349c66..caf2a3c359 100644
--- a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
@@ -126,13 +126,18 @@ public fun CompletionStage.asDeferred(): Deferred {
}
val result = CompletableDeferred()
whenComplete { value, exception ->
- if (exception == null) {
- // the future has completed normally
- result.complete(value)
- } else {
- // the future has completed with an exception, unwrap it consistently with fast path
- // Note: In the fast-path the implementation of CompletableFuture.get() does unwrapping
- result.completeExceptionally((exception as? CompletionException)?.cause ?: exception)
+ try {
+ if (exception == null) {
+ // the future has completed normally
+ result.complete(value)
+ } else {
+ // the future has completed with an exception, unwrap it consistently with fast path
+ // Note: In the fast-path the implementation of CompletableFuture.get() does unwrapping
+ result.completeExceptionally((exception as? CompletionException)?.cause ?: exception)
+ }
+ } catch (e: Throwable) {
+ // We come here iff the internals of Deferred threw an exception during its completion
+ handleCoroutineException(EmptyCoroutineContext, e)
}
}
result.cancelFutureOnCompletion(future)
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/FutureAsDeferredUnhandledCompletionExceptionTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/FutureAsDeferredUnhandledCompletionExceptionTest.kt
new file mode 100644
index 0000000000..bf810af7aa
--- /dev/null
+++ b/integration/kotlinx-coroutines-jdk8/test/future/FutureAsDeferredUnhandledCompletionExceptionTest.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package future
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.future.*
+import org.junit.*
+import org.junit.Test
+import java.util.concurrent.*
+import kotlin.test.*
+
+class FutureAsDeferredUnhandledCompletionExceptionTest : TestBase() {
+
+ // This is a separate test in order to avoid interference with uncaught exception handlers in other tests
+ private val exceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
+ private lateinit var caughtException: Throwable
+
+ @Before
+ fun setUp() {
+ Thread.setDefaultUncaughtExceptionHandler { _, e -> caughtException = e }
+ }
+
+ @After
+ fun tearDown() {
+ Thread.setDefaultUncaughtExceptionHandler(exceptionHandler)
+ }
+
+ @Test
+ fun testLostException() = runTest {
+ val future = CompletableFuture()
+ val deferred = future.asDeferred()
+ deferred.invokeOnCompletion { throw TestException() }
+ future.complete(1)
+ assertTrue { caughtException is CompletionHandlerException && caughtException.cause is TestException }
+ }
+}
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
index 08e5cdad93..372e79ef1d 100644
--- a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
@@ -575,4 +575,23 @@ class FutureTest : TestBase() {
future(start = CoroutineStart.ATOMIC) { }
future(start = CoroutineStart.UNDISPATCHED) { }
}
+
+ @Test
+ fun testStackOverflow() = runTest {
+ val future = CompletableFuture()
+ val completed = AtomicLong()
+ val count = 10000L
+ val children = ArrayList()
+ for (i in 0 until count) {
+ children += launch(Dispatchers.Default) {
+ future.asDeferred().await()
+ completed.incrementAndGet()
+ }
+ }
+ future.complete(1)
+ withTimeout(60_000) {
+ children.forEach { it.join() }
+ assertEquals(count, completed.get())
+ }
+ }
}
diff --git a/integration/kotlinx-coroutines-play-services/README.md b/integration/kotlinx-coroutines-play-services/README.md
index 4ee6bf427c..e5e0e613b3 100644
--- a/integration/kotlinx-coroutines-play-services/README.md
+++ b/integration/kotlinx-coroutines-play-services/README.md
@@ -6,6 +6,7 @@ Extension functions:
| **Name** | **Description**
| -------- | ---------------
+| [Task.asDeferred][asDeferred] | Converts a Task into a Deferred
| [Task.await][await] | Awaits for completion of the Task (cancellable)
| [Deferred.asTask][asTask] | Converts a deferred value to a Task
@@ -25,5 +26,14 @@ val snapshot = try {
// Do stuff
```
+If the `Task` supports cancellation via passing a `CancellationToken`, pass the corresponding `CancellationTokenSource` to `asDeferred` or `await` to support bi-directional cancellation:
+
+```kotlin
+val cancellationTokenSource = CancellationTokenSource()
+val currentLocationTask = fusedLocationProviderClient.getCurrentLocation(PRIORITY_HIGH_ACCURACY, cancellationTokenSource.token)
+val currentLocation = currentLocationTask.await(cancellationTokenSource) // cancelling `await` also cancels `currentLocationTask`, and vice versa
+```
+
+[asDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/com.google.android.gms.tasks.-task/as-deferred.html
[await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/com.google.android.gms.tasks.-task/await.html
[asTask]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/kotlinx.coroutines.-deferred/as-task.html
diff --git a/integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api b/integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api
index 9b2c4dd388..cc23e8db2e 100644
--- a/integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api
+++ b/integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api
@@ -1,6 +1,8 @@
public final class kotlinx/coroutines/tasks/TasksKt {
public static final fun asDeferred (Lcom/google/android/gms/tasks/Task;)Lkotlinx/coroutines/Deferred;
+ public static final fun asDeferred (Lcom/google/android/gms/tasks/Task;Lcom/google/android/gms/tasks/CancellationTokenSource;)Lkotlinx/coroutines/Deferred;
public static final fun asTask (Lkotlinx/coroutines/Deferred;)Lcom/google/android/gms/tasks/Task;
+ public static final fun await (Lcom/google/android/gms/tasks/Task;Lcom/google/android/gms/tasks/CancellationTokenSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun await (Lcom/google/android/gms/tasks/Task;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
diff --git a/integration/kotlinx-coroutines-play-services/src/Tasks.kt b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
index d89d1aec7c..c37ac7a02d 100644
--- a/integration/kotlinx-coroutines-play-services/src/Tasks.kt
+++ b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
@@ -6,15 +6,8 @@
package kotlinx.coroutines.tasks
-import com.google.android.gms.tasks.CancellationTokenSource
-import com.google.android.gms.tasks.RuntimeExecutionException
-import com.google.android.gms.tasks.Task
-import com.google.android.gms.tasks.TaskCompletionSource
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.suspendCancellableCoroutine
+import com.google.android.gms.tasks.*
+import kotlinx.coroutines.*
import kotlin.coroutines.*
/**
@@ -45,39 +38,85 @@ public fun Deferred.asTask(): Task {
/**
* Converts this task to an instance of [Deferred].
* If task is cancelled then resulting deferred will be cancelled as well.
+ * However, the opposite is not true: if the deferred is cancelled, the [Task] will not be cancelled.
+ * For bi-directional cancellation, an overload that accepts [CancellationTokenSource] can be used.
*/
-public fun Task.asDeferred(): Deferred {
+public fun Task.asDeferred(): Deferred = asDeferredImpl(null)
+
+/**
+ * Converts this task to an instance of [Deferred] with a [CancellationTokenSource] to control cancellation.
+ * The cancellation of this function is bi-directional:
+ * * If the given task is cancelled, the resulting deferred will be cancelled.
+ * * If the resulting deferred is cancelled, the provided [cancellationTokenSource] will be cancelled.
+ *
+ * Providing a [CancellationTokenSource] that is unrelated to the receiving [Task] is not supported and
+ * leads to an unspecified behaviour.
+ */
+@ExperimentalCoroutinesApi // Since 1.5.1, tentatively until 1.6.0
+public fun Task.asDeferred(cancellationTokenSource: CancellationTokenSource): Deferred =
+ asDeferredImpl(cancellationTokenSource)
+
+private fun Task.asDeferredImpl(cancellationTokenSource: CancellationTokenSource?): Deferred {
+ val deferred = CompletableDeferred()
if (isComplete) {
val e = exception
- return if (e == null) {
- @Suppress("UNCHECKED_CAST")
- CompletableDeferred().apply { if (isCanceled) cancel() else complete(result as T) }
+ if (e == null) {
+ if (isCanceled) {
+ deferred.cancel()
+ } else {
+ @Suppress("UNCHECKED_CAST")
+ deferred.complete(result as T)
+ }
} else {
- CompletableDeferred().apply { completeExceptionally(e) }
+ deferred.completeExceptionally(e)
+ }
+ } else {
+ addOnCompleteListener {
+ val e = it.exception
+ if (e == null) {
+ @Suppress("UNCHECKED_CAST")
+ if (it.isCanceled) deferred.cancel() else deferred.complete(it.result as T)
+ } else {
+ deferred.completeExceptionally(e)
+ }
}
}
- val result = CompletableDeferred()
- addOnCompleteListener {
- val e = it.exception
- if (e == null) {
- @Suppress("UNCHECKED_CAST")
- if (isCanceled) result.cancel() else result.complete(it.result as T)
- } else {
- result.completeExceptionally(e)
+ if (cancellationTokenSource != null) {
+ deferred.invokeOnCompletion {
+ cancellationTokenSource.cancel()
}
}
- return result
+ // Prevent casting to CompletableDeferred and manual completion.
+ return object : Deferred by deferred {}
}
/**
- * Awaits for completion of the task without blocking a thread.
+ * Awaits the completion of the task without blocking a thread.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
* stops waiting for the completion stage and immediately resumes with [CancellationException].
+ *
+ * For bi-directional cancellation, an overload that accepts [CancellationTokenSource] can be used.
+ */
+public suspend fun Task.await(): T = awaitImpl(null)
+
+/**
+ * Awaits the completion of the task that is linked to the given [CancellationTokenSource] to control cancellation.
+ *
+ * This suspending function is cancellable and cancellation is bi-directional:
+ * * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
+ * cancels the [cancellationTokenSource] and throws a [CancellationException].
+ * * If the task is cancelled, then this function will throw a [CancellationException].
+ *
+ * Providing a [CancellationTokenSource] that is unrelated to the receiving [Task] is not supported and
+ * leads to an unspecified behaviour.
*/
-public suspend fun Task.await(): T {
+@ExperimentalCoroutinesApi // Since 1.5.1, tentatively until 1.6.0
+public suspend fun Task.await(cancellationTokenSource: CancellationTokenSource): T = awaitImpl(cancellationTokenSource)
+
+private suspend fun Task.awaitImpl(cancellationTokenSource: CancellationTokenSource?): T {
// fast path
if (isComplete) {
val e = exception
@@ -95,13 +134,19 @@ public suspend fun Task.await(): T {
return suspendCancellableCoroutine { cont ->
addOnCompleteListener {
- val e = exception
+ val e = it.exception
if (e == null) {
@Suppress("UNCHECKED_CAST")
- if (isCanceled) cont.cancel() else cont.resume(result as T)
+ if (it.isCanceled) cont.cancel() else cont.resume(it.result as T)
} else {
cont.resumeWithException(e)
}
}
+
+ if (cancellationTokenSource != null) {
+ cont.invokeOnCancellation {
+ cancellationTokenSource.cancel()
+ }
+ }
}
}
diff --git a/integration/kotlinx-coroutines-play-services/test/TaskTest.kt b/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
index 0f125ac98c..b125192e93 100644
--- a/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
+++ b/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
@@ -149,5 +149,270 @@ class TaskTest : TestBase() {
}
}
+ @Test
+ fun testCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val deferred = Tasks.forResult(42).asDeferred(cancellationTokenSource)
+ assertEquals(42, deferred.await())
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testNullResultCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ assertNull(Tasks.forResult(null).asDeferred(cancellationTokenSource).await())
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testCancelledCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val deferred = Tasks.forCanceled().asDeferred(cancellationTokenSource)
+
+ assertTrue(deferred.isCancelled)
+ try {
+ deferred.await()
+ fail("deferred.await() should be cancelled")
+ } catch (e: Exception) {
+ assertTrue(e is CancellationException)
+ }
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testCancellingCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val task = TaskCompletionSource(cancellationTokenSource.token).task
+ val deferred = task.asDeferred(cancellationTokenSource)
+
+ deferred.cancel()
+ try {
+ deferred.await()
+ fail("deferred.await() should be cancelled")
+ } catch (e: Exception) {
+ assertTrue(e is CancellationException)
+ }
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testExternallyCancelledCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val task = TaskCompletionSource(cancellationTokenSource.token).task
+ val deferred = task.asDeferred(cancellationTokenSource)
+
+ cancellationTokenSource.cancel()
+
+ try {
+ deferred.await()
+ fail("deferred.await() should be cancelled")
+ } catch (e: Exception) {
+ assertTrue(e is CancellationException)
+ }
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testSeparatelyCancelledCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val task = TaskCompletionSource().task
+ task.asDeferred(cancellationTokenSource)
+
+ cancellationTokenSource.cancel()
+
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testFailedCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val deferred = Tasks.forException(TestException("something went wrong")).asDeferred(cancellationTokenSource)
+
+ assertTrue(deferred.isCancelled && deferred.isCompleted)
+ val completionException = deferred.getCompletionExceptionOrNull()!!
+ assertTrue(completionException is TestException)
+ assertEquals("something went wrong", completionException.message)
+
+ try {
+ deferred.await()
+ fail("deferred.await() should throw an exception")
+ } catch (e: Exception) {
+ assertTrue(e is TestException)
+ assertEquals("something went wrong", e.message)
+ }
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testFailingCancellableTaskAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val lock = ReentrantLock().apply { lock() }
+
+ val deferred: Deferred = Tasks.call {
+ lock.withLock { throw TestException("something went wrong") }
+ }.asDeferred(cancellationTokenSource)
+
+ assertFalse(deferred.isCompleted)
+ lock.unlock()
+
+ try {
+ deferred.await()
+ fail("deferred.await() should throw an exception")
+ } catch (e: Exception) {
+ assertTrue(e is TestException)
+ assertEquals("something went wrong", e.message)
+ assertSame(e.cause, deferred.getCompletionExceptionOrNull()) // debug mode stack augmentation
+ }
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testFastPathCompletedTaskWithCancelledTokenSourceAsDeferred() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val deferred = Tasks.forResult(42).asDeferred(cancellationTokenSource)
+ cancellationTokenSource.cancel()
+ assertEquals(42, deferred.await())
+ }
+
+ @Test
+ fun testAwaitCancellableTask() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val taskCompletionSource = TaskCompletionSource(cancellationTokenSource.token)
+
+ val deferred: Deferred = async(start = CoroutineStart.UNDISPATCHED) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ taskCompletionSource.setResult(42)
+
+ assertEquals(42, deferred.await())
+ assertTrue(deferred.isCompleted)
+ }
+
+ @Test
+ fun testFailedAwaitTask() = runTest(expected = { it is TestException }) {
+ val cancellationTokenSource = CancellationTokenSource()
+ val taskCompletionSource = TaskCompletionSource(cancellationTokenSource.token)
+
+ val deferred: Deferred = async(start = CoroutineStart.UNDISPATCHED) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ taskCompletionSource.setException(TestException("something went wrong"))
+
+ deferred.await()
+ }
+
+ @Test
+ fun testCancelledAwaitCancellableTask() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val taskCompletionSource = TaskCompletionSource(cancellationTokenSource.token)
+
+ val deferred: Deferred = async(start = CoroutineStart.UNDISPATCHED) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ // Cancel the deferred
+ deferred.cancel()
+
+ try {
+ deferred.await()
+ fail("deferred.await() should be cancelled")
+ } catch (e: Exception) {
+ assertTrue(e is CancellationException)
+ }
+
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testExternallyCancelledAwaitCancellableTask() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ val taskCompletionSource = TaskCompletionSource(cancellationTokenSource.token)
+
+ val deferred: Deferred = async(start = CoroutineStart.UNDISPATCHED) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ // Cancel the cancellation token source
+ cancellationTokenSource.cancel()
+
+ try {
+ deferred.await()
+ fail("deferred.await() should be cancelled")
+ } catch (e: Exception) {
+ assertTrue(e is CancellationException)
+ }
+
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ }
+
+ @Test
+ fun testFastPathCancellationTokenSourceCancelledAwaitCancellableTask() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ // Construct a task without the cancellation token source
+ val taskCompletionSource = TaskCompletionSource()
+
+ val deferred: Deferred = async(start = CoroutineStart.LAZY) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ cancellationTokenSource.cancel()
+
+ // Cancelling the token doesn't cancel the deferred
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ assertFalse(deferred.isCompleted)
+
+ // Cleanup
+ deferred.cancel()
+ }
+
+ @Test
+ fun testSlowPathCancellationTokenSourceCancelledAwaitCancellableTask() = runTest {
+ val cancellationTokenSource = CancellationTokenSource()
+ // Construct a task without the cancellation token source
+ val taskCompletionSource = TaskCompletionSource()
+
+ val deferred: Deferred = async(start = CoroutineStart.UNDISPATCHED) {
+ taskCompletionSource.task.await(cancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ cancellationTokenSource.cancel()
+
+ // Cancelling the token doesn't cancel the deferred
+ assertTrue(cancellationTokenSource.token.isCancellationRequested)
+ assertFalse(deferred.isCompleted)
+
+ // Cleanup
+ deferred.cancel()
+ }
+
+ @Test
+ fun testFastPathWithCompletedTaskAndCanceledTokenSourceAwaitTask() = runTest {
+ val firstCancellationTokenSource = CancellationTokenSource()
+ val secondCancellationTokenSource = CancellationTokenSource()
+ // Construct a task with a different cancellation token source
+ val taskCompletionSource = TaskCompletionSource(firstCancellationTokenSource.token)
+
+ val deferred: Deferred = async(start = CoroutineStart.LAZY) {
+ taskCompletionSource.task.await(secondCancellationTokenSource)
+ }
+
+ assertFalse(deferred.isCompleted)
+ secondCancellationTokenSource.cancel()
+
+ assertFalse(deferred.isCompleted)
+ taskCompletionSource.setResult(42)
+
+ assertEquals(42, deferred.await())
+ assertTrue(deferred.isCompleted)
+ }
+
class TestException(message: String) : Exception(message)
}
diff --git a/js/js-stub/README.md b/js/js-stub/README.md
deleted file mode 100644
index 46d18670f2..0000000000
--- a/js/js-stub/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a workaround for Dokka to generate proper references for JS modules.
\ No newline at end of file
diff --git a/js/js-stub/build.gradle.kts b/js/js-stub/build.gradle.kts
deleted file mode 100644
index 201ac43cb0..0000000000
--- a/js/js-stub/build.gradle.kts
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-tasks.named("compileKotlin") {
- kotlinOptions {
- freeCompilerArgs += "-Xallow-kotlin-package"
- }
-}
diff --git a/js/js-stub/src/Performance.kt b/js/js-stub/src/Performance.kt
deleted file mode 100644
index eefb1d749b..0000000000
--- a/js/js-stub/src/Performance.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package org.w3c.performance
-
-public abstract class Performance {
- public abstract fun now(): Double
-}
diff --git a/js/js-stub/src/Promise.kt b/js/js-stub/src/Promise.kt
deleted file mode 100644
index 243d0c9e33..0000000000
--- a/js/js-stub/src/Promise.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlin.js
-
-public open class Promise
diff --git a/js/js-stub/src/Window.kt b/js/js-stub/src/Window.kt
deleted file mode 100644
index 8b2bb8000b..0000000000
--- a/js/js-stub/src/Window.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package org.w3c.dom
-
-public abstract class Window
diff --git a/kotlinx-coroutines-core/README.md b/kotlinx-coroutines-core/README.md
index 9fdf418233..c21e5048f6 100644
--- a/kotlinx-coroutines-core/README.md
+++ b/kotlinx-coroutines-core/README.md
@@ -4,45 +4,45 @@ Core primitives to work with coroutines.
Coroutine builder functions:
-| **Name** | **Result** | **Scope** | **Description**
-| ------------- | ------------- | ---------------- | ---------------
-| [launch] | [Job] | [CoroutineScope] | Launches coroutine that does not have any result
-| [async] | [Deferred] | [CoroutineScope] | Returns a single value with the future result
-| [produce][kotlinx.coroutines.channels.produce] | [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [ProducerScope][kotlinx.coroutines.channels.ProducerScope] | Produces a stream of elements
-| [runBlocking] | `T` | [CoroutineScope] | Blocks the thread while the coroutine runs
+| **Name** | **Result** | **Scope** | **Description**
+| ---------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | ---------------
+| [launch][kotlinx.coroutines.launch] | [Job][kotlinx.coroutines.Job] | [CoroutineScope][kotlinx.coroutines.CoroutineScope] | Launches coroutine that does not have any result
+| [async][kotlinx.coroutines.async] | [Deferred][kotlinx.coroutines.Deferred] | [CoroutineScope][kotlinx.coroutines.CoroutineScope] | Returns a single value with the future result
+| [produce][kotlinx.coroutines.channels.produce] | [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [ProducerScope][kotlinx.coroutines.channels.ProducerScope] | Produces a stream of elements
+| [runBlocking][kotlinx.coroutines.runBlocking] | `T` | [CoroutineScope][kotlinx.coroutines.CoroutineScope] | Blocks the thread while the coroutine runs
Coroutine dispatchers implementing [CoroutineDispatcher]:
-| **Name** | **Description**
-| --------------------------- | ---------------
-| [Dispatchers.Default] | Confines coroutine execution to a shared pool of background threads
-| [Dispatchers.Unconfined] | Does not confine coroutine execution in any way
+| **Name** | **Description**
+| ------------------------------------------------------------------- | ---------------
+| [Dispatchers.Default][kotlinx.coroutines.Dispatchers.Default] | Confines coroutine execution to a shared pool of background threads
+| [Dispatchers.Unconfined][kotlinx.coroutines.Dispatchers.Unconfined] | Does not confine coroutine execution in any way
More context elements:
-| **Name** | **Description**
-| --------------------------- | ---------------
-| [NonCancellable] | A non-cancelable job that is always active
-| [CoroutineExceptionHandler] | Handler for uncaught exception
+| **Name** | **Description**
+| ------------------------------------------------------------------------- | ---------------
+| [NonCancellable][kotlinx.coroutines.NonCancellable] | A non-cancelable job that is always active
+| [CoroutineExceptionHandler][kotlinx.coroutines.CoroutineExceptionHandler] | Handler for uncaught exception
Synchronization primitives for coroutines:
-| **Name** | **Suspending functions** | **Description**
-| ---------- | ----------------------------------------------------------- | ---------------
-| [Mutex][kotlinx.coroutines.sync.Mutex] | [lock][kotlinx.coroutines.sync.Mutex.lock] | Mutual exclusion
+| **Name** | **Suspending functions** | **Description**
+| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------
+| [Mutex][kotlinx.coroutines.sync.Mutex] | [lock][kotlinx.coroutines.sync.Mutex.lock] | Mutual exclusion
| [Channel][kotlinx.coroutines.channels.Channel] | [send][kotlinx.coroutines.channels.SendChannel.send], [receive][kotlinx.coroutines.channels.ReceiveChannel.receive] | Communication channel (aka queue or exchanger)
Top-level suspending functions:
-| **Name** | **Description**
-| ------------------- | ---------------
-| [delay] | Non-blocking sleep
-| [yield] | Yields thread in single-threaded dispatchers
-| [withContext] | Switches to a different context
-| [withTimeout] | Set execution time-limit with exception on timeout
-| [withTimeoutOrNull] | Set execution time-limit will null result on timeout
-| [awaitAll] | Awaits for successful completion of all given jobs or exceptional completion of any
-| [joinAll] | Joins on all given jobs
+| **Name** | **Description**
+| --------------------------------------------------------- | ---------------
+| [delay][kotlinx.coroutines.delay] | Non-blocking sleep
+| [yield][kotlinx.coroutines.yield] | Yields thread in single-threaded dispatchers
+| [withContext][kotlinx.coroutines.withContext] | Switches to a different context
+| [withTimeout][kotlinx.coroutines.withTimeout] | Set execution time-limit with exception on timeout
+| [withTimeoutOrNull][kotlinx.coroutines.withTimeoutOrNull] | Set execution time-limit will null result on timeout
+| [awaitAll][kotlinx.coroutines.awaitAll] | Awaits for successful completion of all given jobs or exceptional completion of any
+| [joinAll][kotlinx.coroutines.joinAll] | Joins on all given jobs
Cancellation support for user-defined suspending functions is available with [suspendCancellableCoroutine]
helper function. [NonCancellable] job object is provided to suppress cancellation with
@@ -50,15 +50,15 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio
[Select][kotlinx.coroutines.selects.select] expression waits for the result of multiple suspending functions simultaneously:
-| **Receiver** | **Suspending function** | **Select clause** | **Non-suspending version**
-| ---------------- | --------------------------------------------- | ------------------------------------------------ | --------------------------
-| [Job] | [join][Job.join] | [onJoin][Job.onJoin] | [isCompleted][Job.isCompleted]
-| [Deferred] | [await][Deferred.await] | [onAwait][Deferred.onAwait] | [isCompleted][Job.isCompleted]
-| [SendChannel][kotlinx.coroutines.channels.SendChannel] | [send][kotlinx.coroutines.channels.SendChannel.send] | [onSend][kotlinx.coroutines.channels.SendChannel.onSend] | [trySend][kotlinx.coroutines.channels.SendChannel.trySend]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive] | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveCatching][kotlinx.coroutines.channels.ReceiveChannel.receiveCatching] | [onReceiveCatching][kotlinx.coroutines.channels.ReceiveChannel.onReceiveCatching] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
-| [Mutex][kotlinx.coroutines.sync.Mutex] | [lock][kotlinx.coroutines.sync.Mutex.lock] | [onLock][kotlinx.coroutines.sync.Mutex.onLock] | [tryLock][kotlinx.coroutines.sync.Mutex.tryLock]
-| none | [delay] | [onTimeout][kotlinx.coroutines.selects.SelectBuilder.onTimeout] | none
+| **Receiver** | **Suspending function** | **Select clause** | **Non-suspending version**
+| ------------------------------------------------------------ | --------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------
+| [Job][kotlinx.coroutines.Job] | [join][kotlinx.coroutines.Job.join] | [onJoin][kotlinx.coroutines.Job.onJoin] | [isCompleted][kotlinx.coroutines.Job.isCompleted]
+| [Deferred][kotlinx.coroutines.Deferred] | [await][kotlinx.coroutines.Deferred.await] | [onAwait][kotlinx.coroutines.Deferred.onAwait] | [isCompleted][kotlinx.coroutines.Job.isCompleted]
+| [SendChannel][kotlinx.coroutines.channels.SendChannel] | [send][kotlinx.coroutines.channels.SendChannel.send] | [onSend][kotlinx.coroutines.channels.SendChannel.onSend] | [trySend][kotlinx.coroutines.channels.SendChannel.trySend]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive] | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveCatching][kotlinx.coroutines.channels.receiveCatching] | [onReceiveCatching][kotlinx.coroutines.channels.onReceiveCatching] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
+| [Mutex][kotlinx.coroutines.sync.Mutex] | [lock][kotlinx.coroutines.sync.Mutex.lock] | [onLock][kotlinx.coroutines.sync.Mutex.onLock] | [tryLock][kotlinx.coroutines.sync.Mutex.tryLock]
+| none | [delay][kotlinx.coroutines.delay] | [onTimeout][kotlinx.coroutines.selects.SelectBuilder.onTimeout] | none
# Package kotlinx.coroutines
@@ -91,30 +91,31 @@ Obsolete and deprecated module to test coroutines. Replaced with `kotlinx-corout
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
-[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[kotlinx.coroutines.launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[kotlinx.coroutines.Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[kotlinx.coroutines.CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[kotlinx.coroutines.async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
+[kotlinx.coroutines.Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
+[kotlinx.coroutines.runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
-[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
-[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable.html
-[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
-[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
-[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
-[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
-[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
-[awaitAll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/await-all.html
-[joinAll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/join-all.html
+[kotlinx.coroutines.Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
+[kotlinx.coroutines.Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
+[kotlinx.coroutines.NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
+[kotlinx.coroutines.CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
+[kotlinx.coroutines.delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
+[kotlinx.coroutines.yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
+[kotlinx.coroutines.withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
+[kotlinx.coroutines.withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
+[kotlinx.coroutines.withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
+[kotlinx.coroutines.awaitAll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/await-all.html
+[kotlinx.coroutines.joinAll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/join-all.html
[suspendCancellableCoroutine]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html
-[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
-[Job.onJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/on-join.html
-[Job.isCompleted]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/is-completed.html
-[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
-[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
+[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
+[kotlinx.coroutines.Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
+[kotlinx.coroutines.Job.onJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/on-join.html
+[kotlinx.coroutines.Job.isCompleted]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/is-completed.html
+[kotlinx.coroutines.Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
+[kotlinx.coroutines.Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
@@ -136,13 +137,13 @@ Obsolete and deprecated module to test coroutines. Replaced with `kotlinx-corout
[kotlinx.coroutines.channels.SendChannel.trySend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/try-send.html
[kotlinx.coroutines.channels.ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
[kotlinx.coroutines.channels.ReceiveChannel.tryReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/try-receive.html
-[kotlinx.coroutines.channels.ReceiveChannel.receiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive-catching.html
-[kotlinx.coroutines.channels.ReceiveChannel.onReceiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-catching.html
+[kotlinx.coroutines.channels.receiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive-catching.html
+[kotlinx.coroutines.channels.onReceiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-catching.html
[kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
-[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
+[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/on-timeout.html
diff --git a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
index ec161ce28e..50bfb60d62 100644
--- a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
+++ b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
@@ -158,7 +158,7 @@ public abstract class kotlinx/coroutines/CoroutineDispatcher : kotlin/coroutines
public fun isDispatchNeeded (Lkotlin/coroutines/CoroutineContext;)Z
public fun minusKey (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
public final fun plus (Lkotlinx/coroutines/CoroutineDispatcher;)Lkotlinx/coroutines/CoroutineDispatcher;
- public fun releaseInterceptedContinuation (Lkotlin/coroutines/Continuation;)V
+ public final fun releaseInterceptedContinuation (Lkotlin/coroutines/Continuation;)V
public fun toString ()Ljava/lang/String;
}
@@ -1100,6 +1100,9 @@ public abstract interface class kotlinx/coroutines/flow/StateFlow : kotlinx/coro
public final class kotlinx/coroutines/flow/StateFlowKt {
public static final fun MutableStateFlow (Ljava/lang/Object;)Lkotlinx/coroutines/flow/MutableStateFlow;
+ public static final fun getAndUpdate (Lkotlinx/coroutines/flow/MutableStateFlow;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+ public static final fun update (Lkotlinx/coroutines/flow/MutableStateFlow;Lkotlin/jvm/functions/Function1;)V
+ public static final fun updateAndGet (Lkotlinx/coroutines/flow/MutableStateFlow;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}
public abstract class kotlinx/coroutines/flow/internal/ChannelFlow : kotlinx/coroutines/flow/internal/FusibleFlow {
diff --git a/kotlinx-coroutines-core/build.gradle b/kotlinx-coroutines-core/build.gradle
index 4ea81d3de3..c45ca08cef 100644
--- a/kotlinx-coroutines-core/build.gradle
+++ b/kotlinx-coroutines-core/build.gradle
@@ -3,6 +3,7 @@
*/
apply plugin: 'org.jetbrains.kotlin.multiplatform'
+apply plugin: 'org.jetbrains.dokka'
apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
apply from: rootProject.file("gradle/compile-common.gradle")
@@ -80,7 +81,7 @@ kotlin {
}
languageSettings {
progressiveMode = true
- experimentalAnnotations.each { useExperimentalAnnotation(it) }
+ optInAnnotations.each { useExperimentalAnnotation(it) }
}
}
@@ -200,12 +201,6 @@ jvmTest {
// Configure the IDEA runner for Lincheck
configureJvmForLincheck(jvmTest)
}
- // TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests
- if (rootProject.ext.jvm_ir_enabled) {
- filter {
- excludeTestsMatching('kotlinx.coroutines.exceptions.StackTraceRecovery*')
- }
- }
}
// Setup manifest for kotlinx-coroutines-core-jvm.jar
diff --git a/kotlinx-coroutines-core/common/README.md b/kotlinx-coroutines-core/common/README.md
index e8503d0d16..fcfe334c62 100644
--- a/kotlinx-coroutines-core/common/README.md
+++ b/kotlinx-coroutines-core/common/README.md
@@ -19,7 +19,7 @@ Coroutine dispatchers implementing [CoroutineDispatcher]:
| [Dispatchers.Unconfined] | Does not confine coroutine execution in any way
| [newSingleThreadContext] | Creates a single-threaded coroutine context
| [newFixedThreadPoolContext] | Creates a thread pool of a fixed size
-| [Executor.asCoroutineDispatcher][java.util.concurrent.Executor.asCoroutineDispatcher] | Extension to convert any executor
+| [Executor.asCoroutineDispatcher][asCoroutineDispatcher] | Extension to convert any executor
More context elements:
@@ -57,9 +57,9 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio
| ---------------- | --------------------------------------------- | ------------------------------------------------ | --------------------------
| [Job] | [join][Job.join] | [onJoin][Job.onJoin] | [isCompleted][Job.isCompleted]
| [Deferred] | [await][Deferred.await] | [onAwait][Deferred.onAwait] | [isCompleted][Job.isCompleted]
-| [SendChannel][kotlinx.coroutines.channels.SendChannel] | [send][kotlinx.coroutines.channels.SendChannel.send] | [onSend][kotlinx.coroutines.channels.SendChannel.onSend] | [offer][kotlinx.coroutines.channels.SendChannel.offer]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive] | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveCatching][kotlinx.coroutines.channels.ReceiveChannel.receiveCatching] | [onReceiveCatching][kotlinx.coroutines.channels.ReceiveChannel.onReceiveCatching] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
+| [SendChannel][kotlinx.coroutines.channels.SendChannel] | [send][kotlinx.coroutines.channels.SendChannel.send] | [onSend][kotlinx.coroutines.channels.SendChannel.onSend] | [trySend][kotlinx.coroutines.channels.SendChannel.trySend]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive] | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveCatching][kotlinx.coroutines.channels.ReceiveChannel.receiveCatching] | [onReceiveCatching][kotlinx.coroutines.channels.ReceiveChannel.onReceiveCatching] | [tryReceive][kotlinx.coroutines.channels.ReceiveChannel.tryReceive]
| [Mutex][kotlinx.coroutines.sync.Mutex] | [lock][kotlinx.coroutines.sync.Mutex.lock] | [onLock][kotlinx.coroutines.sync.Mutex.onLock] | [tryLock][kotlinx.coroutines.sync.Mutex.tryLock]
| none | [delay] | [onTimeout][kotlinx.coroutines.selects.SelectBuilder.onTimeout] | none
@@ -108,8 +108,8 @@ Low-level primitives for finer-grained control of coroutines.
[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html
[newFixedThreadPoolContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-fixed-thread-pool-context.html
-[java.util.concurrent.Executor.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.util.concurrent.-executor/as-coroutine-dispatcher.html
-[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable.html
+[asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-coroutine-dispatcher.html
+[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
@@ -146,16 +146,16 @@ Low-level primitives for finer-grained control of coroutines.
[kotlinx.coroutines.channels.SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
[kotlinx.coroutines.channels.ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
[kotlinx.coroutines.channels.SendChannel.onSend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/on-send.html
-[kotlinx.coroutines.channels.SendChannel.offer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/offer.html
+[kotlinx.coroutines.channels.SendChannel.trySend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/try-send.html
[kotlinx.coroutines.channels.ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
-[kotlinx.coroutines.channels.ReceiveChannel.poll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/poll.html
+[kotlinx.coroutines.channels.ReceiveChannel.tryReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/try-receive.html
[kotlinx.coroutines.channels.ReceiveChannel.receiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive-catching.html
[kotlinx.coroutines.channels.ReceiveChannel.onReceiveCatching]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-catching.html
[kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
-[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
+[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/on-timeout.html
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
index f74155eb8f..1a0169b65d 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
@@ -107,7 +107,7 @@ internal open class CancellableContinuationImpl(
}
}
- private fun isReusable(): Boolean = delegate is DispatchedContinuation<*> && delegate.isReusable(this)
+ private fun isReusable(): Boolean = resumeMode.isReusableMode && (delegate as DispatchedContinuation<*>).isReusable()
/**
* Resets cancellability state in order to [suspendCancellableCoroutineReusable] to work.
@@ -115,7 +115,7 @@ internal open class CancellableContinuationImpl(
*/
@JvmName("resetStateReusable") // Prettier stack traces
internal fun resetStateReusable(): Boolean {
- assert { resumeMode == MODE_CANCELLABLE_REUSABLE } // invalid mode for CancellableContinuationImpl
+ assert { resumeMode == MODE_CANCELLABLE_REUSABLE }
assert { parentHandle !== NonDisposableHandle }
val state = _state.value
assert { state !is NotCompleted }
@@ -164,8 +164,7 @@ internal open class CancellableContinuationImpl(
* Attempt to postpone cancellation for reusable cancellable continuation
*/
private fun cancelLater(cause: Throwable): Boolean {
- if (!resumeMode.isReusableMode) return false
- // Ensure that we are postponing cancellation to the right instance
+ // Ensure that we are postponing cancellation to the right reusable instance
if (!isReusable()) return false
val dispatched = delegate as DispatchedContinuation<*>
return dispatched.postponeCancellation(cause)
diff --git a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
index 10be4a3d9e..d5613d4110 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
@@ -99,8 +99,7 @@ public abstract class CoroutineDispatcher :
public final override fun interceptContinuation(continuation: Continuation): Continuation =
DispatchedContinuation(this, continuation)
- @InternalCoroutinesApi
- public override fun releaseInterceptedContinuation(continuation: Continuation<*>) {
+ public final override fun releaseInterceptedContinuation(continuation: Continuation<*>) {
/*
* Unconditional cast is safe here: we only return DispatchedContinuation from `interceptContinuation`,
* any ClassCastException can only indicate compiler bug
diff --git a/kotlinx-coroutines-core/common/src/Debug.common.kt b/kotlinx-coroutines-core/common/src/Debug.common.kt
index 1381ecd882..185ad295d8 100644
--- a/kotlinx-coroutines-core/common/src/Debug.common.kt
+++ b/kotlinx-coroutines-core/common/src/Debug.common.kt
@@ -32,10 +32,15 @@ public interface CopyableThrowable where T : Throwable, T : CopyableThrowable
/**
* Creates a copy of the current instance.
+ *
* For better debuggability, it is recommended to use original exception as [cause][Throwable.cause] of the resulting one.
* Stacktrace of copied exception will be overwritten by stacktrace recovery machinery by [Throwable.setStackTrace] call.
* An exception can opt-out of copying by returning `null` from this function.
* Suppressed exceptions of the original exception should not be copied in order to avoid circular exceptions.
+ *
+ * This function is allowed to create a copy with a modified [message][Throwable.message], but it should be noted
+ * that the copy can be later recovered as well and message modification code should handle this situation correctly
+ * (e.g. by also storing the original message and checking it) to produce a human-readable result.
*/
public fun createCopy(): T?
}
diff --git a/kotlinx-coroutines-core/common/src/Delay.kt b/kotlinx-coroutines-core/common/src/Delay.kt
index 53dadf9730..4543c5dda1 100644
--- a/kotlinx-coroutines-core/common/src/Delay.kt
+++ b/kotlinx-coroutines-core/common/src/Delay.kt
@@ -150,4 +150,4 @@ internal val CoroutineContext.delay: Delay get() = get(ContinuationInterceptor)
*/
@ExperimentalTime
internal fun Duration.toDelayMillis(): Long =
- if (this > Duration.ZERO) toLongMilliseconds().coerceAtLeast(1) else 0
+ if (this > Duration.ZERO) inWholeMilliseconds.coerceAtLeast(1) else 0
diff --git a/kotlinx-coroutines-core/common/src/NonCancellable.kt b/kotlinx-coroutines-core/common/src/NonCancellable.kt
index 5d3644ba91..c278109224 100644
--- a/kotlinx-coroutines-core/common/src/NonCancellable.kt
+++ b/kotlinx-coroutines-core/common/src/NonCancellable.kt
@@ -24,40 +24,45 @@ import kotlin.coroutines.*
* when the parent is cancelled, the whole parent-child relation between parent and child is severed.
* The parent will not wait for the child's completion, nor will be cancelled when the child crashed.
*/
+@Suppress("DeprecatedCallableAddReplaceWith")
public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
+
+ private const val message = "NonCancellable can be used only as an argument for 'withContext', direct usages of its API are prohibited"
+
/**
* Always returns `true`.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
- override val isActive: Boolean get() = true
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
+ override val isActive: Boolean
+ get() = true
/**
* Always returns `false`.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override val isCompleted: Boolean get() = false
/**
* Always returns `false`.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override val isCancelled: Boolean get() = false
/**
* Always returns `false`.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun start(): Boolean = false
/**
* Always throws [UnsupportedOperationException].
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override suspend fun join() {
throw UnsupportedOperationException("This job is always active")
}
@@ -66,6 +71,7 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Always throws [UnsupportedOperationException].
* @suppress **This an internal API and should not be used from general code.**
*/
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override val onJoin: SelectClause0
get() = throw UnsupportedOperationException("This job is always active")
@@ -73,14 +79,13 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Always throws [IllegalStateException].
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun getCancellationException(): CancellationException = throw IllegalStateException("This job is always active")
/**
* @suppress **This an internal API and should not be used from general code.**
*/
- @Suppress("OverridingDeprecatedMember")
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle =
NonDisposableHandle
@@ -88,7 +93,7 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Always returns no-op handle.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun invokeOnCompletion(onCancelling: Boolean, invokeImmediately: Boolean, handler: CompletionHandler): DisposableHandle =
NonDisposableHandle
@@ -96,7 +101,7 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Does nothing.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun cancel(cause: CancellationException?) {}
/**
@@ -110,7 +115,7 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Always returns [emptySequence].
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override val children: Sequence
get() = emptySequence()
@@ -118,7 +123,7 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
* Always returns [NonDisposableHandle] and does not do anything.
* @suppress **This an internal API and should not be used from general code.**
*/
- @InternalCoroutinesApi
+ @Deprecated(level = DeprecationLevel.WARNING, message = message)
override fun attachChild(child: ChildJob): ChildHandle = NonDisposableHandle
/** @suppress */
diff --git a/kotlinx-coroutines-core/common/src/Supervisor.kt b/kotlinx-coroutines-core/common/src/Supervisor.kt
index 01a8e70522..8411c5c65a 100644
--- a/kotlinx-coroutines-core/common/src/Supervisor.kt
+++ b/kotlinx-coroutines-core/common/src/Supervisor.kt
@@ -42,11 +42,15 @@ public fun SupervisorJob0(parent: Job? = null) : Job = SupervisorJob(parent)
* Creates a [CoroutineScope] with [SupervisorJob] and calls the specified suspend block with this scope.
* The provided scope inherits its [coroutineContext][CoroutineScope.coroutineContext] from the outer scope, but overrides
* context's [Job] with [SupervisorJob].
+ * This function returns as soon as the given block and all its child coroutines are completed.
*
- * A failure of a child does not cause this scope to fail and does not affect its other children,
- * so a custom policy for handling failures of its children can be implemented. See [SupervisorJob] for details.
- * A failure of the scope itself (exception thrown in the [block] or cancellation) fails the scope with all its children,
+ * Unlike [coroutineScope], a failure of a child does not cause this scope to fail and does not affect its other children,
+ * so a custom policy for handling failures of its children can be implemented. See [SupervisorJob] for additional details.
+ * A failure of the scope itself (exception thrown in the [block] or external cancellation) fails the scope with all its children,
* but does not cancel parent job.
+ *
+ * The method may throw a [CancellationException] if the current job was cancelled externally,
+ * or rethrow an exception thrown by the given [block].
*/
public suspend fun supervisorScope(block: suspend CoroutineScope.() -> R): R {
contract {
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index 8c69cbfe87..b15c4262ef 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -154,6 +154,8 @@ public interface SendChannel {
* ```
*
* See https://github.com/Kotlin/kotlinx.coroutines/issues/974 for more context.
+ *
+ * @suppress **Deprecated**.
*/
@Deprecated(
level = DeprecationLevel.WARNING,
@@ -308,6 +310,8 @@ public interface ReceiveChannel {
* The replacement `tryReceive().getOrNull()` is a default that ignores all close exceptions and
* proceeds with `null`, while `poll` throws an exception if the channel was closed with an exception.
* Replacement with the very same 'poll' semantics is `tryReceive().onClosed { if (it != null) throw it }.getOrNull()`
+ *
+ * @suppress **Deprecated**.
*/
@Deprecated(
level = DeprecationLevel.WARNING,
@@ -336,6 +340,8 @@ public interface ReceiveChannel {
* The replacement `receiveCatching().getOrNull()` is a safe default that ignores all close exceptions and
* proceeds with `null`, while `receiveOrNull` throws an exception if the channel was closed with an exception.
* Replacement with the very same `receiveOrNull` semantics is `receiveCatching().onClosed { if (it != null) throw it }.getOrNull()`.
+ *
+ * @suppress **Deprecated**
*/
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@LowPriorityInOverloadResolution
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
index e1e2b140f5..f7f60cf97d 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
@@ -123,6 +123,7 @@ internal open class ConflatedChannel(onUndeliveredElement: OnUndeliveredEleme
undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
}
+ @Suppress("UNCHECKED_CAST")
private fun updateValueLocked(element: Any?): UndeliveredElementException? {
val old = value
val undeliveredElementException = if (old === EMPTY) null else
diff --git a/kotlinx-coroutines-core/common/src/channels/Deprecated.kt b/kotlinx-coroutines-core/common/src/channels/Deprecated.kt
index 963c168c7b..2b9ed42dd1 100644
--- a/kotlinx-coroutines-core/common/src/channels/Deprecated.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Deprecated.kt
@@ -11,6 +11,7 @@ import kotlinx.coroutines.*
import kotlin.coroutines.*
import kotlin.jvm.*
+/** @suppress **/
@PublishedApi // Binary compatibility
internal fun consumesAll(vararg channels: ReceiveChannel<*>): CompletionHandler =
{ cause: Throwable? ->
@@ -28,18 +29,21 @@ internal fun consumesAll(vararg channels: ReceiveChannel<*>): CompletionHandler
exception?.let { throw it }
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.elementAt(index: Int): E = consume {
if (index < 0)
throw IndexOutOfBoundsException("ReceiveChannel doesn't contain element at index $index.")
var count = 0
for (element in this) {
+ @Suppress("UNUSED_CHANGED_VALUE") // KT-47628
if (index == count++)
return element
}
throw IndexOutOfBoundsException("ReceiveChannel doesn't contain element at index $index.")
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.elementAtOrNull(index: Int): E? =
consume {
@@ -53,6 +57,7 @@ public suspend fun ReceiveChannel.elementAtOrNull(index: Int): E? =
return null
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.first(): E =
consume {
@@ -62,6 +67,7 @@ public suspend fun ReceiveChannel.first(): E =
return iterator.next()
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.firstOrNull(): E? =
consume {
@@ -71,6 +77,7 @@ public suspend fun ReceiveChannel.firstOrNull(): E? =
return iterator.next()
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.indexOf(element: E): Int {
var index = 0
@@ -82,6 +89,7 @@ public suspend fun ReceiveChannel.indexOf(element: E): Int {
return -1
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.last(): E =
consume {
@@ -94,6 +102,7 @@ public suspend fun ReceiveChannel.last(): E =
return last
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.lastIndexOf(element: E): Int {
var lastIndex = -1
@@ -106,6 +115,7 @@ public suspend fun ReceiveChannel.lastIndexOf(element: E): Int {
return lastIndex
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.lastOrNull(): E? =
consume {
@@ -118,6 +128,7 @@ public suspend fun ReceiveChannel.lastOrNull(): E? =
return last
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.single(): E =
consume {
@@ -130,6 +141,7 @@ public suspend fun ReceiveChannel.single(): E =
return single
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.singleOrNull(): E? =
consume {
@@ -142,6 +154,7 @@ public suspend fun ReceiveChannel.singleOrNull(): E? =
return single
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public fun ReceiveChannel.drop(n: Int, context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
@@ -158,8 +171,12 @@ public fun ReceiveChannel.drop(n: Int, context: CoroutineContext = Dispat
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.dropWhile(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel =
+public fun ReceiveChannel.dropWhile(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ predicate: suspend (E) -> Boolean
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
for (e in this@dropWhile) {
if (!predicate(e)) {
@@ -173,15 +190,22 @@ public fun ReceiveChannel.dropWhile(context: CoroutineContext = Dispatche
}
@PublishedApi
-internal fun ReceiveChannel.filter(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel =
+internal fun ReceiveChannel.filter(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ predicate: suspend (E) -> Boolean
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
for (e in this@filter) {
if (predicate(e)) send(e)
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.filterIndexed(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (index: Int, E) -> Boolean): ReceiveChannel =
+public fun ReceiveChannel.filterIndexed(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ predicate: suspend (index: Int, E) -> Boolean
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
var index = 0
for (e in this@filterIndexed) {
@@ -189,8 +213,12 @@ public fun ReceiveChannel.filterIndexed(context: CoroutineContext = Dispa
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.filterNot(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel =
+public fun ReceiveChannel.filterNot(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ predicate: suspend (E) -> Boolean
+): ReceiveChannel =
filter(context) { !predicate(it) }
@PublishedApi
@@ -198,6 +226,7 @@ public fun ReceiveChannel.filterNot(context: CoroutineContext = Dispatche
internal fun ReceiveChannel.filterNotNull(): ReceiveChannel =
filter { it != null } as ReceiveChannel
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun > ReceiveChannel.filterNotNullTo(destination: C): C {
consumeEach {
@@ -206,6 +235,7 @@ public suspend fun > ReceiveChannel.fil
return destination
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun > ReceiveChannel.filterNotNullTo(destination: C): C {
consumeEach {
@@ -214,6 +244,7 @@ public suspend fun > ReceiveChannel.filterNotNul
return destination
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public fun ReceiveChannel.take(n: Int, context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
@@ -228,8 +259,12 @@ public fun ReceiveChannel.take(n: Int, context: CoroutineContext = Dispat
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.takeWhile(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel =
+public fun ReceiveChannel.takeWhile(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ predicate: suspend (E) -> Boolean
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
for (e in this@takeWhile) {
if (!predicate(e)) return@produce
@@ -253,6 +288,7 @@ internal suspend fun > ReceiveChannel.toCollec
return destination
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel>.toMap(): Map =
toMap(LinkedHashMap())
@@ -265,16 +301,22 @@ internal suspend fun > ReceiveChannel ReceiveChannel.toMutableList(): MutableList =
toCollection(ArrayList())
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.toSet(): Set =
this.toMutableSet()
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.flatMap(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> ReceiveChannel): ReceiveChannel =
+public fun ReceiveChannel.flatMap(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ transform: suspend (E) -> ReceiveChannel
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
for (e in this@flatMap) {
transform(e).toChannel(this)
@@ -282,7 +324,10 @@ public fun ReceiveChannel.flatMap(context: CoroutineContext = Dispatch
}
@PublishedApi
-internal fun ReceiveChannel.map(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> R): ReceiveChannel =
+internal fun ReceiveChannel.map(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ transform: suspend (E) -> R
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
consumeEach {
send(transform(it))
@@ -290,7 +335,10 @@ internal fun ReceiveChannel.map(context: CoroutineContext = Dispatcher
}
@PublishedApi
-internal fun ReceiveChannel.mapIndexed(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (index: Int, E) -> R): ReceiveChannel =
+internal fun ReceiveChannel.mapIndexed(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ transform: suspend (index: Int, E) -> R
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
var index = 0
for (e in this@mapIndexed) {
@@ -298,14 +346,23 @@ internal fun ReceiveChannel.mapIndexed(context: CoroutineContext = Dis
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.mapIndexedNotNull(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (index: Int, E) -> R?): ReceiveChannel =
+public fun ReceiveChannel.mapIndexedNotNull(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ transform: suspend (index: Int, E) -> R?
+): ReceiveChannel =
mapIndexed(context, transform).filterNotNull()
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
-public fun ReceiveChannel.mapNotNull(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> R?): ReceiveChannel =
+public fun ReceiveChannel.mapNotNull(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ transform: suspend (E) -> R?
+): ReceiveChannel =
map(context, transform).filterNotNull()
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public fun ReceiveChannel.withIndex(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel> =
GlobalScope.produce(context, onCompletion = consumes()) {
@@ -315,12 +372,16 @@ public fun ReceiveChannel.withIndex(context: CoroutineContext = Dispatche
}
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public fun ReceiveChannel.distinct(): ReceiveChannel =
this.distinctBy { it }
@PublishedApi
-internal fun ReceiveChannel.distinctBy(context: CoroutineContext = Dispatchers.Unconfined, selector: suspend (E) -> K): ReceiveChannel =
+internal fun ReceiveChannel.distinctBy(
+ context: CoroutineContext = Dispatchers.Unconfined,
+ selector: suspend (E) -> K
+): ReceiveChannel =
GlobalScope.produce(context, onCompletion = consumes()) {
val keys = HashSet()
for (e in this@distinctBy) {
@@ -336,12 +397,14 @@ internal fun ReceiveChannel.distinctBy(context: CoroutineContext = Dis
internal suspend fun ReceiveChannel.toMutableSet(): MutableSet =
toCollection(LinkedHashSet())
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel.any(): Boolean =
consume {
return iterator().hasNext()
}
+/** @suppress **/
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
public suspend fun ReceiveChannel