diff --git a/CHANGES.md b/CHANGES.md
index bf1c2e90d0..bdd5d7a6f7 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,25 @@
# Change log for kotlinx.coroutines
+## Version 1.3.4
+
+### Flow
+
+* Detect missing `awaitClose` calls in `callbackFlow` to make it less error-prone when used with callbacks (#1762, #1770). This change makes `callbackFlow` **different** from `channelFlow`.
+* `ReceiveChannel.asFlow` extension is introduced (#1490).
+* Enforce exception transparency invariant in `flow` builder (#1657).
+* Proper `Dispatcher` support in `Flow` reactive integrations (#1765).
+* Batch `Subscription.request` calls in `Flow` reactive integration (#766).
+* `ObservableValue.asFlow` added to JavaFx integration module (#1695).
+* `ObservableSource.asFlow` added to RxJava2 integration module (#1768).
+
+### Other changes
+
+* `kotlinx-coroutines-core` is optimized for R8, making it much smaller for Android usages (75 KB for `1.3.4` release).
+* Performance of `Dispatchers.Default` is improved (#1704, #1706).
+* Kotlin is updated to 1.3.70.
+* `CoroutineDispatcher` and `ExecutorCoroutineDispatcher` experimental coroutine context keys are introduced (#1805).
+* Performance of various `Channel` operations is improved (#1565).
+
## Version 1.3.3
### Flow
diff --git a/README.md b/README.md
index bbd8726b42..7a827a2bc9 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,10 @@
[](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[](https://www.apache.org/licenses/LICENSE-2.0)
-[ ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.3.3)
+[ ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.3.4)
Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
-This is a companion version for Kotlin `1.3.61` release.
+This is a companion version for Kotlin `1.3.70` release.
```kotlin
suspend fun main() = coroutineScope {
@@ -82,7 +82,7 @@ Add dependencies (you can also add other modules that you need):
org.jetbrains.kotlinx
kotlinx-coroutines-core
- 1.3.3
+ 1.3.4
```
@@ -90,7 +90,7 @@ And make sure that you use the latest Kotlin version:
```xml
- 1.3.61
+ 1.3.70
```
@@ -100,7 +100,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.4'
}
```
@@ -108,7 +108,7 @@ And make sure that you use the latest Kotlin version:
```groovy
buildscript {
- ext.kotlin_version = '1.3.61'
+ ext.kotlin_version = '1.3.70'
}
```
@@ -126,7 +126,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.4")
}
```
@@ -134,7 +134,7 @@ And make sure that you use the latest Kotlin version:
```groovy
plugins {
- kotlin("jvm") version "1.3.61"
+ kotlin("jvm") version "1.3.70"
}
```
@@ -145,7 +145,7 @@ Make sure that you have either `jcenter()` or `mavenCentral()` in the list of re
Core modules of `kotlinx.coroutines` are also available for
[Kotlin/JS](#js) and [Kotlin/Native](#native).
In common code that should get compiled for different platforms, add dependency to
-[`kotlinx-coroutines-core-common`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-common/1.3.3/jar)
+[`kotlinx-coroutines-core-common`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-common/1.3.4/jar)
(follow the link to get the dependency declaration snippet).
### Android
@@ -154,7 +154,7 @@ Add [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android)
module as dependency when using `kotlinx.coroutines` on Android:
```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.4'
```
This gives you access to Android [Dispatchers.Main]
@@ -164,16 +164,13 @@ threads are handled by Android runtime.
#### R8 and ProGuard
-For R8 no actions required, it will take obfuscation rules from the jar.
-
-For Proguard you need to add options from [coroutines.pro](kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro) to your rules manually.
-
-R8 is a replacement for ProGuard in Android ecosystem, it is enabled by default since Android gradle plugin 3.4.0 (3.3.0-beta also had it enabled).
+R8 and ProGuard rules are bundled into the [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android) module.
+For more details see ["Optimization" section for Android](ui/kotlinx-coroutines-android/README.md#optimization).
### JS
[Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) version of `kotlinx.coroutines` is published as
-[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.3.3/jar)
+[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.3.4/jar)
(follow the link to get the dependency declaration snippet).
You can also use [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) package via NPM.
@@ -181,7 +178,7 @@ You can also use [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotli
### Native
[Kotlin/Native](https://kotlinlang.org/docs/reference/native-overview.html) version of `kotlinx.coroutines` is published as
-[`kotlinx-coroutines-core-native`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-native/1.3.3/jar)
+[`kotlinx-coroutines-core-native`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-native/1.3.4/jar)
(follow the link to get the dependency declaration snippet).
Only single-threaded code (JS-style) on Kotlin/Native is currently supported.
@@ -203,8 +200,9 @@ to Gradle (in Preferences -> Build, Execution, Deployment -> Build Tools -> Grad
### Requirements
-* JDK >= 1.8 referred to by the `JAVA_HOME` environment variable. JDK must include JavaFX.
+* JDK >= 11 referred to by the `JAVA_HOME` environment variable.
* JDK 1.6 referred to by the `JDK_16` environment variable. It is okay to have `JDK_16` pointing to `JAVA_HOME` for external contributions.
+* JDK 1.8 referred to by the `JDK_18` environment variable. Only used by nightly stress-tests. It is okay to have `JDK_16` pointing to `JAVA_HOME` for external contributions.
## Contributions and releases
@@ -217,6 +215,12 @@ The `develop` branch is pushed to `master` during release.
* Full release procedure checklist is [here](RELEASE.md).
* Steps for contributing new integration modules are explained [here](integration/README.md#Contributing).
+* Use [Knit](https://github.com/Kotlin/kotlinx-knit/blob/master/README.md) for updates to documentation:
+ * In project root directory run `./gradlew knit`.
+ * Commit updated documents and examples together with other changes.
+* Use [Binary Compatibility Validator](https://github.com/Kotlin/binary-compatibility-validator/blob/master/README.md) for updates to public API:
+ * In project root directory run `./gradlew apiDump`.
+ * Commit updated API index together with other changes.
diff --git a/RELEASE.md b/RELEASE.md
index 22140e68c7..efb361f1e5 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -53,7 +53,8 @@ To release new `` of `kotlinx-coroutines`:
* Create a release named ``.
* Cut & paste lines from [`CHANGES.md`](CHANGES.md) into description.
-3. Build and publish documentation for web-site:
+3. Build and publish documentation for web-site
+ (make sure you have [Docker](https://www.docker.com/) installed first):
`site/deploy.sh push`
4. In [Bintray](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines) admin interface:
diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle
index 157eb88aa6..a192f2795e 100644
--- a/benchmarks/build.gradle
+++ b/benchmarks/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
sourceCompatibility = 1.8
targetCompatibility = 1.8
@@ -74,4 +74,6 @@ dependencies {
compile "org.openjdk.jmh:jmh-core:1.21"
compile 'com.typesafe.akka:akka-actor_2.12:2.5.0'
compile project(':kotlinx-coroutines-core')
+ // add jmh dependency on main
+ jmh sourceSets.main.runtimeClasspath
}
diff --git a/benchmarks/scripts/generate_plots_flow_flatten_merge.py b/benchmarks/scripts/generate_plots_flow_flatten_merge.py
new file mode 100644
index 0000000000..c7f5ebb88b
--- /dev/null
+++ b/benchmarks/scripts/generate_plots_flow_flatten_merge.py
@@ -0,0 +1,75 @@
+# To run this script run the command 'python3 scripts/generate_plots_flow_flatten_merge.py' in the /benchmarks folder
+
+
+import pandas as pd
+import sys
+import locale
+import matplotlib.pyplot as plt
+from matplotlib.ticker import FormatStrFormatter
+
+input_file = "build/reports/jmh/results.csv"
+output_file = "out/flow-flatten-merge.svg"
+# Please change the value of this variable according to the FlowFlattenMergeBenchmarkKt.ELEMENTS
+elements = 100000
+benchmark_name = "benchmarks.flow.FlowFlattenMergeBenchmark.flattenMerge"
+csv_columns = ["Benchmark", "Score", "Unit", "Param: concurrency", "Param: flowsNumberStrategy"]
+rename_columns = {"Benchmark": "benchmark", "Score" : "score", "Unit" : "unit",
+ "Param: concurrency" : "concurrency", "Param: flowsNumberStrategy" : "flows"}
+
+markers = ['.', 'v', '^', '1', '2', '8', 'p', 'P', 'x', 'D', 'd', 's']
+colours = ['red', 'gold', 'sienna', 'olivedrab', 'lightseagreen', 'navy', 'blue', 'm', 'crimson', 'yellow', 'orangered', 'slateblue', 'aqua', 'black', 'silver']
+
+def next_colour():
+ i = 0
+ while True:
+ yield colours[i % len(colours)]
+ i += 1
+
+def next_marker():
+ i = 0
+ while True:
+ yield markers[i % len(markers)]
+ i += 1
+
+def draw(data, plt):
+ plt.xscale('log', basex=2)
+ plt.gca().xaxis.set_major_formatter(FormatStrFormatter('%0.f'))
+ plt.grid(linewidth='0.5', color='lightgray')
+ if data.unit.unique()[0] != "ops/s":
+ print("Unexpected time unit: " + data.unit.unique()[0])
+ sys.exit(1)
+ plt.ylabel("elements / ms")
+ plt.xlabel('concurrency')
+ plt.xticks(data.concurrency.unique())
+
+ colour_gen = next_colour()
+ marker_gen = next_marker()
+ for flows in data.flows.unique():
+ gen_colour = next(colour_gen)
+ gen_marker = next(marker_gen)
+ res = data[(data.flows == flows)]
+# plt.plot(res.concurrency, res.score*elements/1000, label="flows={}".format(flows), color=gen_colour, marker=gen_marker)
+ plt.errorbar(x=res.concurrency, y=res.score*elements/1000, yerr=res.score_error*elements/1000, solid_capstyle='projecting',
+ label="flows={}".format(flows), capsize=4, color=gen_colour, linewidth=2.2)
+
+langlocale = locale.getdefaultlocale()[0]
+locale.setlocale(locale.LC_ALL, langlocale)
+dp = locale.localeconv()['decimal_point']
+if dp == ",":
+ csv_columns.append("Score Error (99,9%)")
+ rename_columns["Score Error (99,9%)"] = "score_error"
+elif dp == ".":
+ csv_columns.append("Score Error (99.9%)")
+ rename_columns["Score Error (99.9%)"] = "score_error"
+else:
+ print("Unexpected locale delimeter: " + dp)
+ sys.exit(1)
+data = pd.read_csv(input_file, sep=",", decimal=dp)
+data = data[csv_columns].rename(columns=rename_columns)
+data = data[(data.benchmark == benchmark_name)]
+plt.rcParams.update({'font.size': 15})
+plt.figure(figsize=(12.5, 10))
+draw(data, plt)
+plt.legend(loc='upper center', borderpad=0, bbox_to_anchor=(0.5, 1.3), ncol=2, frameon=False, borderaxespad=2, prop={'size': 15})
+plt.tight_layout(pad=12, w_pad=2, h_pad=1)
+plt.savefig(output_file, bbox_inches='tight')
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
index 2a85d0dbdd..04f7210381 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble;
@@ -160,4 +160,4 @@ public List>> play() throws Exception {
.blockingGet() ;
return finalList2 ;
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
index 7a7cb1aa4e..71c7604d0c 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble;
@@ -171,4 +171,4 @@ public List>> play() throws Exception {
return finalList2 ;
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
index a45dbdd2c5..5f93b4ee88 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
index 83c203e42f..af8696c802 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
index 3d36a0d8e7..cf6cc79b79 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
index 941e3d84ba..deeea77af9 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
@@ -147,4 +147,4 @@ private fun doWork(): Unit = Blackhole.consumeCPU(ThreadLocalRandom.current().ne
private const val WORK_MIN = 50L
private const val WORK_MAX = 100L
-private const val APPROX_BATCH_SIZE = 100000
\ No newline at end of file
+private const val APPROX_BATCH_SIZE = 100000
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
index 8b5e90aaf5..9c7f38a6f9 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt b/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
index fab052370e..b635d1ef2c 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
@@ -44,4 +44,4 @@ abstract class ParametrizedDispatcherBase : CoroutineScope {
closeable?.close()
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
index 0fc563a89e..5da5dc8920 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
@@ -1,5 +1,10 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
package benchmarks
+import benchmarks.common.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher
@@ -7,7 +12,6 @@ import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.openjdk.jmh.annotations.*
import java.util.concurrent.ForkJoinPool
-import java.util.concurrent.ThreadLocalRandom
import java.util.concurrent.TimeUnit
@Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MICROSECONDS)
@@ -50,9 +54,9 @@ open class SemaphoreBenchmark {
jobs += GlobalScope.launch {
repeat(n) {
semaphore.withPermit {
- doWork(WORK_INSIDE)
+ doGeomDistrWork(WORK_INSIDE)
}
- doWork(WORK_OUTSIDE)
+ doGeomDistrWork(WORK_OUTSIDE)
}
}
}
@@ -68,9 +72,9 @@ open class SemaphoreBenchmark {
jobs += GlobalScope.launch {
repeat(n) {
semaphore.send(Unit) // acquire
- doWork(WORK_INSIDE)
+ doGeomDistrWork(WORK_INSIDE)
semaphore.receive() // release
- doWork(WORK_OUTSIDE)
+ doGeomDistrWork(WORK_OUTSIDE)
}
}
}
@@ -83,15 +87,6 @@ enum class SemaphoreBenchDispatcherCreator(val create: (parallelism: Int) -> Cor
EXPERIMENTAL({ parallelism -> ExperimentalCoroutineDispatcher(corePoolSize = parallelism, maxPoolSize = parallelism) })
}
-private fun doWork(work: Int) {
- // We use geometric distribution here
- val p = 1.0 / work
- val r = ThreadLocalRandom.current()
- while (true) {
- if (r.nextDouble() < p) break
- }
-}
-
private const val WORK_INSIDE = 80
private const val WORK_OUTSIDE = 40
-private const val BATCH_SIZE = 1000000
\ No newline at end of file
+private const val BATCH_SIZE = 1000000
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
index 1a6e9d4036..ea9aeca94d 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
@@ -1,18 +1,15 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.akka
-import akka.actor.ActorRef
-import akka.actor.ActorSystem
-import akka.actor.Props
-import akka.actor.UntypedAbstractActor
-import com.typesafe.config.ConfigFactory
+import akka.actor.*
+import com.typesafe.config.*
import org.openjdk.jmh.annotations.*
-import scala.concurrent.Await
-import scala.concurrent.duration.Duration
-import java.util.concurrent.CountDownLatch
+import scala.concurrent.*
+import scala.concurrent.duration.*
+import java.util.concurrent.*
const val N_MESSAGES = 100_000
@@ -117,4 +114,4 @@ open class PingPongAkkaBenchmark {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
index 4e3ad6ce4d..5cfb86dda0 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
@@ -1,19 +1,15 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.akka
-import akka.actor.ActorRef
-import akka.actor.ActorSystem
-import akka.actor.Props
-import akka.actor.UntypedAbstractActor
-import com.typesafe.config.ConfigFactory
+import akka.actor.*
+import com.typesafe.config.*
import org.openjdk.jmh.annotations.*
-import scala.concurrent.Await
-import scala.concurrent.duration.Duration
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.ThreadLocalRandom
+import scala.concurrent.*
+import scala.concurrent.duration.*
+import java.util.concurrent.*
const val ROUNDS = 10_000
const val STATE_SIZE = 1024
@@ -171,4 +167,4 @@ open class StatefulActorAkkaBenchmark {
initLatch.countDown()
}
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
index f6690977a2..f3b2082ae1 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
@@ -44,4 +44,4 @@ open class FlatMapMergeBenchmark {
}
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt
new file mode 100644
index 0000000000..3fff2697cc
--- /dev/null
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package benchmarks.flow
+
+import benchmarks.common.*
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import org.openjdk.jmh.annotations.*
+import java.util.concurrent.*
+
+/**
+ * Benchmark to measure performance of [kotlinx.coroutines.flow.FlowKt.flattenMerge].
+ * In addition to that, it can be considered as a macro benchmark for the [kotlinx.coroutines.sync.Semaphore]
+ */
+@Warmup(iterations = 5, time = 1)
+@Measurement(iterations = 5, time = 1)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Benchmark)
+@Fork(1)
+open class FlowFlattenMergeBenchmark {
+ @Param
+ private var flowsNumberStrategy: FlowsNumberStrategy = FlowsNumberStrategy.`10xConcurrency flows`
+
+ @Param("1", "2", "4", "8")
+ private var concurrency: Int = 0
+
+ private lateinit var flow: Flow>
+
+ @Setup
+ fun setup() {
+ val n = flowsNumberStrategy.get(concurrency)
+ val flowElementsToProcess = ELEMENTS / n
+
+ flow = (1..n).asFlow().map {
+ flow {
+ repeat(flowElementsToProcess) {
+ doGeomDistrWork(WORK)
+ emit(it)
+ }
+ }
+ }
+ }
+
+ @Benchmark
+ fun flattenMerge() = runBlocking(Dispatchers.Default) {
+ flow.flattenMerge(concurrency = concurrency).collect()
+ }
+}
+
+enum class FlowsNumberStrategy(val get: (concurrency: Int) -> Int) {
+ `10xConcurrency flows`({ concurrency -> concurrency * 10 }),
+ `1xConcurrency flows`({ it }),
+ `100 flows`({ 100 }),
+ `500 flows`({ 500 })
+}
+
+// If you change this variable please be sure that you change variable elements in the generate_plots_flow_flatten_merge.py
+// python script as well
+private const val ELEMENTS = 100_000
+private const val WORK = 100
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
index e0bc2fcc48..0cb31056bb 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@@ -103,4 +103,4 @@ open class NumbersBenchmark {
.filter { (it + 1) % 3 == 0L }.count()
.blockingGet()
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
index f8c459fd0d..258df9b03e 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
index 84afca2439..1c469a69b9 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
index b556053b5d..9e39b43b8b 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
@@ -7,7 +7,6 @@ package benchmarks.flow.scrabble
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.openjdk.jmh.annotations.*
-import java.lang.Long.*
import java.lang.Long.max
import java.util.*
import java.util.concurrent.*
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
index 921f390dce..62cc2e5c50 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. and contributors Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
@@ -7,11 +7,9 @@ package benchmarks.flow.scrabble
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.openjdk.jmh.annotations.*
-import java.lang.Long.max
+import java.lang.Long.*
import java.util.*
import java.util.concurrent.*
-import java.util.stream.*
-import kotlin.math.*
@Warmup(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
index 434ea1e19d..32c0d4c8fa 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
index 9adc4f1f59..2283d6c3fb 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
@@ -1,14 +1,12 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
-import org.openjdk.jmh.annotations.*
import reactor.core.publisher.*
import java.lang.Long.*
import java.util.*
-import java.util.concurrent.*
import java.util.function.Function
/*@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
index 597667c1c6..0a4f69672f 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
@@ -1,9 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
index 5f4f4c2d1a..87d0e61232 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
@@ -1,11 +1,10 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
import org.openjdk.jmh.annotations.*
import java.lang.Long.*
import java.util.*
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
index 7eaa3f0a5d..7beb54cc3d 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
index e7f806760e..3012b9178a 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
index 0c731c3ba8..724a5909b9 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
@@ -164,4 +164,4 @@ private fun compute(coefficients: LongArray, start: Int, end: Int): Double {
}
return result
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
index 8435ddc262..a0de6016c4 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
@@ -53,4 +53,4 @@ open class LaunchBenchmark : ParametrizedDispatcherBase() {
stopBarrier.reset()
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
index 93667c0c2f..f829573c87 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
@@ -117,4 +117,4 @@ open class StatefulAsyncBenchmark : ParametrizedDispatcherBase() {
}
sum
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
index 6998577310..6ac97ad3e7 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
index 67548f624e..71018abcbc 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
index 2d547e2660..4c6ae7754c 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
@@ -100,4 +100,4 @@ fun CoroutineScope.pongActorCoroutine(capacity: Int = 1) =
else -> error("Cannot happen $message")
}
}
- }
\ No newline at end of file
+ }
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
index 86a9440a58..dcbda090e8 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
index fb342295a6..01691a2d77 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
index ee1ef724cb..c217fcae91 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.tailcall
@@ -95,4 +95,4 @@ class CancellableReusableChannel : SimpleChannel() {
producer = it.intercepted()
COROUTINE_SUSPENDED
}
-}
\ No newline at end of file
+}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
index 09ff7697f6..7bb962b3b8 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.tailcall
diff --git a/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt b/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt
new file mode 100644
index 0000000000..0057573bc6
--- /dev/null
+++ b/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package benchmarks.common
+
+import java.util.concurrent.*
+
+fun doGeomDistrWork(work: Int) {
+ // We use geometric distribution here. We also checked on macbook pro 13" (2017) that the resulting work times
+ // are distributed geometrically, see https://github.com/Kotlin/kotlinx.coroutines/pull/1464#discussion_r355705325
+ val p = 1.0 / work
+ val r = ThreadLocalRandom.current()
+ while (true) {
+ if (r.nextDouble() < p) break
+ }
+}
diff --git a/binary-compatibility-validator/README.md b/binary-compatibility-validator/README.md
deleted file mode 100644
index e34d6877c5..0000000000
--- a/binary-compatibility-validator/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Public API binary compatibility validator
-
-This module allows to dump and compare public binary API to ensure binary compatibility with a previous version.
-This tool is slightly adapted copy of [original Kotlin compatibility validator](https://github.com/JetBrains/kotlin/tree/master/libraries/tools/binary-compatibility-validator) by @ilya-g.
-
-To update public API dumps use:
-
-```bash
-./gradlew :binary-compatibility-validator:test -Poverwrite.output=true
-```
diff --git a/binary-compatibility-validator/build.gradle b/binary-compatibility-validator/build.gradle
deleted file mode 100644
index c6eaffdfca..0000000000
--- a/binary-compatibility-validator/build.gradle
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-configurations {
- testArtifacts
- configureKotlinJvmPlatform(testArtifacts)
-}
-
-dependencies {
- compile 'org.ow2.asm:asm-debug-all:5.0.4'
- compile 'com.google.code.gson:gson:2.6.2'
-
- testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
-
- testArtifacts project(':kotlinx-coroutines-core')
- testArtifacts project(':kotlinx-coroutines-test')
- testArtifacts project(':kotlinx-coroutines-debug')
-
- testArtifacts project(':kotlinx-coroutines-reactive')
- testArtifacts project(':kotlinx-coroutines-reactor')
- testArtifacts project(':kotlinx-coroutines-rx2')
-
- testArtifacts project(':kotlinx-coroutines-guava')
- testArtifacts project(':kotlinx-coroutines-jdk8')
- testArtifacts project(':kotlinx-coroutines-slf4j')
- testArtifacts project(path: ':kotlinx-coroutines-play-services', configuration: 'default')
-
- testArtifacts project(':kotlinx-coroutines-android')
- testArtifacts project(':kotlinx-coroutines-javafx')
- testArtifacts project(':kotlinx-coroutines-swing')
-}
-
-def testCasesDeclarationsDump = "${buildDir}/visibilities.json".toString()
-
-compileTestKotlin {
- kotlinOptions {
- freeCompilerArgs = ["-Xdump-declarations-to=$testCasesDeclarationsDump"]
- }
-}
-
-sourceSets {
- test {
- java {
- srcDir "test/cases"
- }
- }
-}
-
-test {
- dependsOn cleanCompileTestKotlin
- dependsOn configurations.testArtifacts
-
- systemProperty 'testCasesClassesDirs', sourceSets.test.output.classesDirs.asPath
- systemProperty 'testCasesDeclarations', testCasesDeclarationsDump
- systemProperty 'overwrite.output', project.properties['overwrite.output']
- jvmArgs '-ea'
-}
diff --git a/binary-compatibility-validator/resources/api.properties b/binary-compatibility-validator/resources/api.properties
deleted file mode 100644
index e15ad21a02..0000000000
--- a/binary-compatibility-validator/resources/api.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
-#
-
-module.roots=/ integration reactive ui
-module.marker=build.gradle
-module.ignore=stdlib-stubs benchmarks knit binary-compatibility-validator site publication-validator kotlinx-coroutines-bom
-
-packages.internal=kotlinx.coroutines.internal
\ No newline at end of file
diff --git a/binary-compatibility-validator/src/PublicApiDump.kt b/binary-compatibility-validator/src/PublicApiDump.kt
deleted file mode 100644
index 343df34b87..0000000000
--- a/binary-compatibility-validator/src/PublicApiDump.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import org.objectweb.asm.*
-import org.objectweb.asm.tree.*
-import java.io.*
-import java.util.jar.*
-
-fun JarFile.classEntries() = entries().asSequence().filter {
- !it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/")
-}
-
-fun getBinaryAPI(jar: JarFile, visibilityMap: Map): List =
- getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityMap)
-
-fun getBinaryAPI(
- classStreams: Sequence,
- visibilityMap: Map
-): List =
- classStreams.map {
- it.use { stream ->
- val classNode = ClassNode()
- ClassReader(stream).accept(classNode, ClassReader.SKIP_CODE)
- classNode
- }
- }.map {
- with(it) {
- val classVisibility = visibilityMap[name]
- val classAccess = AccessFlags(effectiveAccess and Opcodes.ACC_STATIC.inv())
- val supertypes = listOf(superName) - "java/lang/Object" + interfaces.sorted()
-
- val memberSignatures = (
- fields.map {
- with(it) {
- FieldBinarySignature(
- name,
- desc,
- isPublishedApi(),
- AccessFlags(access)
- )
- }
- } +
- methods.map {
- with(it) {
- MethodBinarySignature(
- name,
- desc,
- isPublishedApi(),
- AccessFlags(access)
- )
- }
- }
- ).filter {
- it.isEffectivelyPublic(classAccess, classVisibility)
- }
-
- ClassBinarySignature(
- name,
- superName,
- outerClassName,
- supertypes,
- memberSignatures,
- classAccess,
- isEffectivelyPublic(classVisibility),
- isFileOrMultipartFacade() || isDefaultImpls()
- )
- }
- }.asIterable().sortedBy { it.name }
-
-
-fun List.filterOutNonPublic(nonPublicPackages: List = emptyList()): List {
- val nonPublicPaths = nonPublicPackages.map { it.replace('.', '/') + '/' }
- val classByName = associateBy { it.name }
-
- fun ClassBinarySignature.isInNonPublicPackage() =
- nonPublicPaths.any { name.startsWith(it) }
-
- fun ClassBinarySignature.isPublicAndAccessible(): Boolean =
- isEffectivelyPublic &&
- (outerName == null || classByName[outerName]?.let { outerClass ->
- !(this.access.isProtected && outerClass.access.isFinal)
- && outerClass.isPublicAndAccessible()
- } ?: true)
-
- fun supertypes(superName: String) = generateSequence({ classByName[superName] }, { classByName[it.superName] })
-
- fun ClassBinarySignature.flattenNonPublicBases(): ClassBinarySignature {
-
- val nonPublicSupertypes = supertypes(superName).takeWhile { !it.isPublicAndAccessible() }.toList()
- if (nonPublicSupertypes.isEmpty())
- return this
-
- val inheritedStaticSignatures =
- nonPublicSupertypes.flatMap { it.memberSignatures.filter { it.access.isStatic } }
-
- // not covered the case when there is public superclass after chain of private superclasses
- return this.copy(
- memberSignatures = memberSignatures + inheritedStaticSignatures,
- supertypes = supertypes - superName
- )
- }
-
- return filter { !it.isInNonPublicPackage() && it.isPublicAndAccessible() }
- .map { it.flattenNonPublicBases() }
- .filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty() }
-}
-
-fun List.dump() = dump(to = System.out)
-
-fun List.dump(to: T): T = to.apply {
- this@dump.forEach {
- append(it.signature).appendln(" {")
- it.memberSignatures.sortedWith(MEMBER_SORT_ORDER).forEach { append("\t").appendln(it.signature) }
- appendln("}\n")
- }
-}
-
diff --git a/binary-compatibility-validator/src/asmUtils.kt b/binary-compatibility-validator/src/asmUtils.kt
deleted file mode 100644
index b14cb8d5e6..0000000000
--- a/binary-compatibility-validator/src/asmUtils.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import org.objectweb.asm.*
-import org.objectweb.asm.tree.*
-
-val ACCESS_NAMES = mapOf(
- Opcodes.ACC_PUBLIC to "public",
- Opcodes.ACC_PROTECTED to "protected",
- Opcodes.ACC_PRIVATE to "private",
- Opcodes.ACC_STATIC to "static",
- Opcodes.ACC_FINAL to "final",
- Opcodes.ACC_ABSTRACT to "abstract",
- Opcodes.ACC_SYNTHETIC to "synthetic",
- Opcodes.ACC_INTERFACE to "interface",
- Opcodes.ACC_ANNOTATION to "annotation")
-
-data class ClassBinarySignature(
- val name: String,
- val superName: String,
- val outerName: String?,
- val supertypes: List,
- val memberSignatures: List,
- val access: AccessFlags,
- val isEffectivelyPublic: Boolean,
- val isNotUsedWhenEmpty: Boolean) {
-
- val signature: String
- get() = "${access.getModifierString()} class $name" + if (supertypes.isEmpty()) "" else " : ${supertypes.joinToString()}"
-
-}
-
-
-interface MemberBinarySignature {
- val name: String
- val desc: String
- val access: AccessFlags
- val isPublishedApi: Boolean
-
- fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?)
- = access.isPublic && !(access.isProtected && classAccess.isFinal)
- && (findMemberVisibility(classVisibility)?.isPublic(isPublishedApi) ?: true)
-
- fun findMemberVisibility(classVisibility: ClassVisibility?)
- = classVisibility?.members?.get(MemberSignature(name, desc))
-
- val signature: String
-}
-
-data class MethodBinarySignature(
- override val name: String,
- override val desc: String,
- override val isPublishedApi: Boolean,
- override val access: AccessFlags) : MemberBinarySignature {
- override val signature: String
- get() = "${access.getModifierString()} fun $name $desc"
-
- override fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?)
- = super.isEffectivelyPublic(classAccess, classVisibility)
- && !isAccessOrAnnotationsMethod()
-
- private fun isAccessOrAnnotationsMethod() = access.isSynthetic && (name.startsWith("access\$") || name.endsWith("\$annotations"))
-}
-
-data class FieldBinarySignature(
- override val name: String,
- override val desc: String,
- override val isPublishedApi: Boolean,
- override val access: AccessFlags) : MemberBinarySignature {
- override val signature: String
- get() = "${access.getModifierString()} field $name $desc"
-
- override fun findMemberVisibility(classVisibility: ClassVisibility?): MemberVisibility? {
- val fieldVisibility = super.findMemberVisibility(classVisibility) ?: return null
-
- // good case for 'satisfying': fieldVisibility.satisfying { it.isLateInit() }?.let { classVisibility?.findSetterForProperty(it) }
- if (fieldVisibility.isLateInit()) {
- classVisibility?.findSetterForProperty(fieldVisibility)?.let { return it }
- }
- return fieldVisibility
- }
-}
-
-val MemberBinarySignature.kind: Int get() = when (this) {
- is FieldBinarySignature -> 1
- is MethodBinarySignature -> 2
- else -> error("Unsupported $this")
-}
-
-val MEMBER_SORT_ORDER = compareBy(
- { it.kind },
- { it.name },
- { it.desc }
-)
-
-
-data class AccessFlags(val access: Int) {
- val isPublic: Boolean get() = isPublic(access)
- val isProtected: Boolean get() = isProtected(access)
- val isStatic: Boolean get() = isStatic(access)
- val isFinal: Boolean get() = isFinal(access)
- val isSynthetic: Boolean get() = isSynthetic(access)
-
- fun getModifiers(): List = ACCESS_NAMES.entries.mapNotNull { if (access and it.key != 0) it.value else null }
- fun getModifierString(): String = getModifiers().joinToString(" ")
-}
-
-fun isPublic(access: Int) = access and Opcodes.ACC_PUBLIC != 0 || access and Opcodes.ACC_PROTECTED != 0
-fun isProtected(access: Int) = access and Opcodes.ACC_PROTECTED != 0
-fun isStatic(access: Int) = access and Opcodes.ACC_STATIC != 0
-fun isFinal(access: Int) = access and Opcodes.ACC_FINAL != 0
-fun isSynthetic(access: Int) = access and Opcodes.ACC_SYNTHETIC != 0
-
-
-fun ClassNode.isEffectivelyPublic(classVisibility: ClassVisibility?) =
- isPublic(access)
- && !isLocal()
- && !isWhenMappings()
- && (classVisibility?.isPublic(isPublishedApi()) ?: true)
-
-
-val ClassNode.innerClassNode: InnerClassNode? get() = innerClasses.singleOrNull { it.name == name }
-fun ClassNode.isLocal() = innerClassNode?.run { innerName == null && outerName == null} ?: false
-fun ClassNode.isInner() = innerClassNode != null
-fun ClassNode.isWhenMappings() = isSynthetic(access) && name.endsWith("\$WhenMappings")
-
-val ClassNode.effectiveAccess: Int get() = innerClassNode?.access ?: access
-val ClassNode.outerClassName: String? get() = innerClassNode?.outerName
-
-
-const val publishedApiAnnotationName = "kotlin/PublishedApi"
-fun ClassNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null
-fun MethodNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null
-fun FieldNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null
-
-
-private object KotlinClassKind {
- const val FILE = 2
- const val SYNTHETIC_CLASS = 3
- const val MULTIPART_FACADE = 4
-
- val FILE_OR_MULTIPART_FACADE_KINDS = listOf(FILE, MULTIPART_FACADE)
-}
-
-fun ClassNode.isFileOrMultipartFacade() = kotlinClassKind.let { it != null && it in KotlinClassKind.FILE_OR_MULTIPART_FACADE_KINDS }
-fun ClassNode.isDefaultImpls() = isInner() && name.endsWith("\$DefaultImpls") && kotlinClassKind == KotlinClassKind.SYNTHETIC_CLASS
-
-
-val ClassNode.kotlinClassKind: Int?
- get() = findAnnotation("kotlin/Metadata", false)?.get("k") as Int?
-
-fun ClassNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible)
-fun MethodNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible)
-fun FieldNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible)
-
-operator fun AnnotationNode.get(key: String): Any? = values.annotationValue(key)
-
-private fun List.annotationValue(key: String): Any? {
- for (index in (0 .. size / 2 - 1)) {
- if (this[index*2] == key)
- return this[index*2 + 1]
- }
- return null
-}
-
-private fun findAnnotation(annotationName: String, visibleAnnotations: List?, invisibleAnnotations: List?, includeInvisible: Boolean): AnnotationNode? =
- visibleAnnotations?.firstOrNull { it.refersToName(annotationName) } ?:
- if (includeInvisible) invisibleAnnotations?.firstOrNull { it.refersToName(annotationName) } else null
-
-fun AnnotationNode.refersToName(name: String) = desc.startsWith('L') && desc.endsWith(';') && desc.regionMatches(1, name, 0, name.length)
\ No newline at end of file
diff --git a/binary-compatibility-validator/src/kotlinVisibilities.kt b/binary-compatibility-validator/src/kotlinVisibilities.kt
deleted file mode 100644
index 4322140c80..0000000000
--- a/binary-compatibility-validator/src/kotlinVisibilities.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import com.google.gson.internal.*
-import com.google.gson.stream.*
-import java.io.*
-
-data class ClassVisibility(val name: String, val visibility: String?, val members: Map)
-data class MemberVisibility(val member: MemberSignature, val declaration: String?, val visibility: String?)
-data class MemberSignature(val name: String, val desc: String)
-
-private fun isPublic(visibility: String?, isPublishedApi: Boolean) = visibility == null || visibility == "public" || visibility == "protected" || (isPublishedApi && visibility == "internal")
-fun ClassVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi)
-fun MemberVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi)
-
-fun MemberVisibility.isLateInit() = declaration != null && "lateinit var " in declaration
-
-private val varValPrefix = Regex("va[lr]\\s+")
-fun ClassVisibility.findSetterForProperty(property: MemberVisibility): MemberVisibility? {
- // ad-hoc solution:
- val declaration = property.declaration ?: return null
- val match = varValPrefix.find(declaration) ?: return null
- val name = declaration.substring(match.range.endInclusive + 1).substringBefore(':')
- val setterName = ""
- return members.values.find { it.declaration?.contains(setterName) ?: false }
-}
-
-fun readKotlinVisibilities(declarationFile: File): Map {
- val result = mutableListOf()
- declarationFile.bufferedReader().use { reader ->
- val jsonReader = JsonReader(reader)
- jsonReader.beginArray()
- while (jsonReader.hasNext()) {
- val classObject = Streams.parse(jsonReader).asJsonObject
- result += with (classObject) {
- val name = getAsJsonPrimitive("class").asString
- val visibility = getAsJsonPrimitive("visibility")?.asString
- val members = getAsJsonArray("members").map { it ->
- with(it.asJsonObject) {
- val name = getAsJsonPrimitive("name").asString
- val desc = getAsJsonPrimitive("desc").asString
- val declaration = getAsJsonPrimitive("declaration")?.asString
- val visibility = getAsJsonPrimitive("visibility")?.asString
- MemberVisibility(MemberSignature(name, desc), declaration, visibility)
- }
- }
- ClassVisibility(name, visibility, members.associateByTo(hashMapOf()) { it.member })
- }
- }
- jsonReader.endArray()
- }
-
- return result.associateByTo(hashMapOf()) { it.name }
-}
diff --git a/binary-compatibility-validator/test/CasesPublicAPITest.kt b/binary-compatibility-validator/test/CasesPublicAPITest.kt
deleted file mode 100644
index f0212e70a9..0000000000
--- a/binary-compatibility-validator/test/CasesPublicAPITest.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import org.junit.*
-import org.junit.rules.*
-import java.io.*
-
-class CasesPublicAPITest {
-
- companion object {
- val visibilities by lazy { readKotlinVisibilities(File(System.getProperty("testCasesDeclarations")!!)) }
-
- val baseClassPaths: List =
- System.getProperty("testCasesClassesDirs")
- .let { requireNotNull(it) { "Specify testCasesClassesDirs with a system property" } }
- .split(File.pathSeparator)
- .map { File(it, "cases").canonicalFile }
- val baseOutputPath = File("test/cases")
- }
-
- @Rule
- @JvmField
- val testName = TestName()
-
- @Test
- fun companions() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun inline() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun interfaces() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun internal() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun java() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun localClasses() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun nestedClasses() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun private() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun protected() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun public() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun special() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
- @Test
- fun whenMappings() {
- snapshotAPIAndCompare(testName.methodName)
- }
-
-
- private fun snapshotAPIAndCompare(testClassRelativePath: String) {
- val testClassPaths = baseClassPaths.map { it.resolve(testClassRelativePath) }
- val testClasses = testClassPaths.flatMap { it.listFiles().orEmpty().asIterable() }
- check(testClasses.isNotEmpty()) { "No class files are found in paths: $testClassPaths" }
- val testClassStreams = testClasses.asSequence().filter { it.name.endsWith(".class") }.map { it.inputStream() }
- val api = getBinaryAPI(testClassStreams, visibilities).filterOutNonPublic()
- val target = baseOutputPath.resolve(testClassRelativePath).resolve(testName.methodName + ".txt")
- api.dumpAndCompareWith(target)
- }
-}
diff --git a/binary-compatibility-validator/test/PublicApiTest.kt b/binary-compatibility-validator/test/PublicApiTest.kt
deleted file mode 100644
index fb4f55cc17..0000000000
--- a/binary-compatibility-validator/test/PublicApiTest.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import org.junit.*
-import org.junit.runner.*
-import org.junit.runners.*
-import java.io.*
-import java.util.*
-import java.util.jar.*
-import kotlin.collections.ArrayList
-
-@RunWith(Parameterized::class)
-class PublicApiTest(
- private val rootDir: String,
- private val moduleName: String
-) {
- companion object {
- private val apiProps = ClassLoader.getSystemClassLoader()
- .getResource("api.properties").openStream().use { Properties().apply { load(it) } }
- private val nonPublicPackages = apiProps.getProperty("packages.internal")!!.split(" ")
-
- @Parameterized.Parameters(name = "{1}")
- @JvmStatic
- fun modules(): List> {
- val moduleRoots = apiProps.getProperty("module.roots").split(" ")
- val moduleMarker = apiProps.getProperty("module.marker")!!
- val moduleIgnore = apiProps.getProperty("module.ignore")!!.split(" ").toSet()
- val modules = ArrayList>()
- for (rootDir in moduleRoots) {
- File("../$rootDir").listFiles( FileFilter { it.isDirectory })?.forEach { dir ->
- if (dir.name !in moduleIgnore && File(dir, moduleMarker).exists()) {
- modules += arrayOf(rootDir, dir.name)
- }
- }
- }
- return modules
- }
- }
-
- @Test
- fun testApi() {
- val libsDir = File("../$rootDir/$moduleName/build/libs").absoluteFile.normalize()
- val jarPath = getJarPath(libsDir)
- val kotlinJvmMappingsFiles = listOf(libsDir.resolve("../visibilities.json"))
- val visibilities =
- kotlinJvmMappingsFiles
- .map { readKotlinVisibilities(it) }
- .reduce { m1, m2 -> m1 + m2 }
- JarFile(jarPath).use { jarFile ->
- val api = getBinaryAPI(jarFile, visibilities).filterOutNonPublic(nonPublicPackages)
- api.dumpAndCompareWith(File("reference-public-api").resolve("$moduleName.txt"))
- // check for atomicfu leaks
- jarFile.checkForAtomicFu()
- }
- }
-
- private fun getJarPath(libsDir: File): File {
- val regex = Regex("$moduleName-.+\\.jar")
- var files = (libsDir.listFiles() ?: throw Exception("Cannot list files in $libsDir"))
- .filter { it.name.let {
- it matches regex
- && !it.endsWith("-sources.jar")
- && !it.endsWith("-javadoc.jar")
- && !it.endsWith("-tests.jar")}
- && !it.name.contains("-metadata-")}
- if (files.size > 1) // maybe multiplatform?
- files = files.filter { it.name.startsWith("$moduleName-jvm-") }
- return files.singleOrNull() ?:
- error("No single file matching $regex in $libsDir:\n${files.joinToString("\n")}")
- }
-}
-
-private val ATOMIC_FU_REF = "Lkotlinx/atomicfu/".toByteArray()
-
-private fun JarFile.checkForAtomicFu() {
- val foundClasses = mutableListOf()
- for (e in entries()) {
- if (!e.name.endsWith(".class")) continue
- val bytes = getInputStream(e).use { it.readBytes() }
- loop@for (i in 0 until bytes.size - ATOMIC_FU_REF.size) {
- for (j in 0 until ATOMIC_FU_REF.size) {
- if (bytes[i + j] != ATOMIC_FU_REF[j]) continue@loop
- }
- foundClasses += e.name // report error at the end with all class names
- break@loop
- }
- }
- if (foundClasses.isNotEmpty()) {
- error("Found references to atomicfu in jar file $name in the following class files: ${
- foundClasses.joinToString("") { "\n\t\t" + it }
- }")
- }
-}
diff --git a/binary-compatibility-validator/test/cases/companions/companions.kt b/binary-compatibility-validator/test/cases/companions/companions.kt
deleted file mode 100644
index ef59c6febb..0000000000
--- a/binary-compatibility-validator/test/cases/companions/companions.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.companions
-
-
-object PublicClasses {
- class PublicCompanion {
- companion object
- }
-
- class ProtectedCompanion {
- protected companion object
- }
-
- abstract class AbstractProtectedCompanion {
- protected companion object
- }
-
- class InternalCompanion {
- internal companion object
- }
-
- class PrivateCompanion {
- private companion object
- }
-}
-
-object PublicInterfaces {
- interface PublicCompanion {
- companion object
- }
-
- interface PrivateCompanion {
- private companion object
- }
-}
-
-
-
-object InternalClasses {
- internal class PublicCompanion {
- companion object
- }
-
- internal class ProtectedCompanion {
- protected companion object
- }
-
- internal abstract class AbstractProtectedCompanion {
- protected companion object
- }
-
- internal class InternalCompanion {
- internal companion object
- }
-
- internal class PrivateCompanion {
- private companion object
- }
-}
-
-object InternalInterfaces {
- internal interface PublicCompanion {
- companion object
- }
-
- internal interface PrivateCompanion {
- private companion object
- }
-}
-
-
-object PrivateClasses {
- private class PublicCompanion {
- companion object
- }
-
- private class ProtectedCompanion {
- protected companion object
- }
-
- private abstract class AbstractProtectedCompanion {
- protected companion object
- }
-
- private class InternalCompanion {
- internal companion object
- }
-
- private class PrivateCompanion {
- private companion object
- }
-}
-
-object PrivateInterfaces {
- private interface PublicCompanion {
- companion object
- }
-
- private interface PrivateCompanion {
- private companion object
- }
-}
-
diff --git a/binary-compatibility-validator/test/cases/companions/companions.txt b/binary-compatibility-validator/test/cases/companions/companions.txt
deleted file mode 100644
index 691907ba0d..0000000000
--- a/binary-compatibility-validator/test/cases/companions/companions.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-public final class cases/companions/InternalClasses {
- public static final field INSTANCE Lcases/companions/InternalClasses;
-}
-
-public final class cases/companions/InternalInterfaces {
- public static final field INSTANCE Lcases/companions/InternalInterfaces;
-}
-
-public final class cases/companions/PrivateClasses {
- public static final field INSTANCE Lcases/companions/PrivateClasses;
-}
-
-public final class cases/companions/PrivateInterfaces {
- public static final field INSTANCE Lcases/companions/PrivateInterfaces;
-}
-
-public final class cases/companions/PublicClasses {
- public static final field INSTANCE Lcases/companions/PublicClasses;
-}
-
-public abstract class cases/companions/PublicClasses$AbstractProtectedCompanion {
- public static final field Companion Lcases/companions/PublicClasses$AbstractProtectedCompanion$Companion;
- public fun ()V
-}
-
-protected final class cases/companions/PublicClasses$AbstractProtectedCompanion$Companion {
-}
-
-public final class cases/companions/PublicClasses$InternalCompanion {
- public static final field Companion Lcases/companions/PublicClasses$InternalCompanion$Companion;
- public fun ()V
-}
-
-public final class cases/companions/PublicClasses$PrivateCompanion {
- public static final field Companion Lcases/companions/PublicClasses$PrivateCompanion$Companion;
- public fun ()V
-}
-
-public final class cases/companions/PublicClasses$ProtectedCompanion {
- public static final field Companion Lcases/companions/PublicClasses$ProtectedCompanion$Companion;
- public fun ()V
-}
-
-public final class cases/companions/PublicClasses$PublicCompanion {
- public static final field Companion Lcases/companions/PublicClasses$PublicCompanion$Companion;
- public fun ()V
-}
-
-public final class cases/companions/PublicClasses$PublicCompanion$Companion {
-}
-
-public final class cases/companions/PublicInterfaces {
- public static final field INSTANCE Lcases/companions/PublicInterfaces;
-}
-
-public abstract interface class cases/companions/PublicInterfaces$PrivateCompanion {
- public static final field Companion Lcases/companions/PublicInterfaces$PrivateCompanion$Companion;
-}
-
-public abstract interface class cases/companions/PublicInterfaces$PublicCompanion {
- public static final field Companion Lcases/companions/PublicInterfaces$PublicCompanion$Companion;
-}
-
-public final class cases/companions/PublicInterfaces$PublicCompanion$Companion {
-}
-
diff --git a/binary-compatibility-validator/test/cases/inline/inline.txt b/binary-compatibility-validator/test/cases/inline/inline.txt
deleted file mode 100644
index 4961dbcfd4..0000000000
--- a/binary-compatibility-validator/test/cases/inline/inline.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-public final class cases/inline/InlineExposedKt {
- public static final fun exposedForInline ()V
-}
-
-public final class cases/inline/InternalClassExposed {
- public fun ()V
- public final fun funExposed ()V
-}
-
diff --git a/binary-compatibility-validator/test/cases/inline/inlineExposed.kt b/binary-compatibility-validator/test/cases/inline/inlineExposed.kt
deleted file mode 100644
index 2e017b3832..0000000000
--- a/binary-compatibility-validator/test/cases/inline/inlineExposed.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.inline
-
-@PublishedApi
-internal fun exposedForInline() {}
-
-@PublishedApi
-internal class InternalClassExposed
- @PublishedApi
- internal constructor() {
-
- @PublishedApi
- internal fun funExposed() {}
-
- // TODO: Cover unsupported cases: requires correctly reflecting annotations from properties
- /*
- @PublishedApi
- internal var propertyExposed: String? = null
-
- @JvmField
- @PublishedApi
- internal var fieldExposed: String? = null
- */
-
-}
diff --git a/binary-compatibility-validator/test/cases/inline/inlineOnly.kt b/binary-compatibility-validator/test/cases/inline/inlineOnly.kt
deleted file mode 100644
index 9c1f01eb0e..0000000000
--- a/binary-compatibility-validator/test/cases/inline/inlineOnly.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.inline
-
-@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
-@kotlin.internal.InlineOnly
-public inline fun inlineOnly(f: () -> Unit) = f()
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/interfaces/interfaceWithEmptyImpls.kt b/binary-compatibility-validator/test/cases/interfaces/interfaceWithEmptyImpls.kt
deleted file mode 100644
index 96a1628c82..0000000000
--- a/binary-compatibility-validator/test/cases/interfaces/interfaceWithEmptyImpls.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.interfaces
-
-public interface EmptyImpls {
- @SinceKotlin("1.1")
- val property: String
-}
diff --git a/binary-compatibility-validator/test/cases/interfaces/interfaceWithImpls.kt b/binary-compatibility-validator/test/cases/interfaces/interfaceWithImpls.kt
deleted file mode 100644
index d2e4ad0c36..0000000000
--- a/binary-compatibility-validator/test/cases/interfaces/interfaceWithImpls.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.interfaces
-
-public interface BaseWithImpl {
- fun foo() = 42
-}
-
-public interface DerivedWithImpl : BaseWithImpl {
- override fun foo(): Int {
- return super.foo() + 1
- }
-}
-
-public interface DerivedWithoutImpl : BaseWithImpl
-
diff --git a/binary-compatibility-validator/test/cases/interfaces/interfaces.txt b/binary-compatibility-validator/test/cases/interfaces/interfaces.txt
deleted file mode 100644
index 4f37b42f3a..0000000000
--- a/binary-compatibility-validator/test/cases/interfaces/interfaces.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-public abstract interface class cases/interfaces/BaseWithImpl {
- public abstract fun foo ()I
-}
-
-public final class cases/interfaces/BaseWithImpl$DefaultImpls {
- public static fun foo (Lcases/interfaces/BaseWithImpl;)I
-}
-
-public abstract interface class cases/interfaces/DerivedWithImpl : cases/interfaces/BaseWithImpl {
- public abstract fun foo ()I
-}
-
-public final class cases/interfaces/DerivedWithImpl$DefaultImpls {
- public static fun foo (Lcases/interfaces/DerivedWithImpl;)I
-}
-
-public abstract interface class cases/interfaces/DerivedWithoutImpl : cases/interfaces/BaseWithImpl {
-}
-
-public final class cases/interfaces/DerivedWithoutImpl$DefaultImpls {
- public static fun foo (Lcases/interfaces/DerivedWithoutImpl;)I
-}
-
-public abstract interface class cases/interfaces/EmptyImpls {
- public abstract fun getProperty ()Ljava/lang/String;
-}
-
diff --git a/binary-compatibility-validator/test/cases/internal/internal.txt b/binary-compatibility-validator/test/cases/internal/internal.txt
deleted file mode 100644
index 2ebfa3aff3..0000000000
--- a/binary-compatibility-validator/test/cases/internal/internal.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-public final class cases/internal/PublicClass {
-}
-
diff --git a/binary-compatibility-validator/test/cases/internal/internalClass.kt b/binary-compatibility-validator/test/cases/internal/internalClass.kt
deleted file mode 100644
index 2410b65791..0000000000
--- a/binary-compatibility-validator/test/cases/internal/internalClass.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.internal
-
-internal class InternalClass {
- public val property = 1
-
- public fun function() = property
-}
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/internal/internalMultifile1.kt b/binary-compatibility-validator/test/cases/internal/internalMultifile1.kt
deleted file mode 100644
index b4622b3afd..0000000000
--- a/binary-compatibility-validator/test/cases/internal/internalMultifile1.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.internal
-
-internal fun internalFun1() = internalVal
diff --git a/binary-compatibility-validator/test/cases/internal/internalMultifile2.kt b/binary-compatibility-validator/test/cases/internal/internalMultifile2.kt
deleted file mode 100644
index c375c01e16..0000000000
--- a/binary-compatibility-validator/test/cases/internal/internalMultifile2.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.internal
-
-internal val internalVal = "Internal"
diff --git a/binary-compatibility-validator/test/cases/internal/internalPart.kt b/binary-compatibility-validator/test/cases/internal/internalPart.kt
deleted file mode 100644
index b95ba6830e..0000000000
--- a/binary-compatibility-validator/test/cases/internal/internalPart.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.internal
-
-internal fun internalFun() {
-
-}
-
-// TODO: var, val, const
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/internal/publicClassInternalMember.kt b/binary-compatibility-validator/test/cases/internal/publicClassInternalMember.kt
deleted file mode 100644
index 11aac7c5cb..0000000000
--- a/binary-compatibility-validator/test/cases/internal/publicClassInternalMember.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.internal
-
-public class PublicClass internal constructor() {
-
- internal val property = 1
-
- internal fun function() = property
-
-}
diff --git a/binary-compatibility-validator/test/cases/java/Facade.java b/binary-compatibility-validator/test/cases/java/Facade.java
deleted file mode 100644
index d11c16cd7f..0000000000
--- a/binary-compatibility-validator/test/cases/java/Facade.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.java;
-
-class Part1 {
- public static void publicMethod(int param) { }
-
- public static class Part2 extends Part1 {
- public static void publicMethod(String param) { }
- }
-}
-
-
-public class Facade extends Part1.Part2 { }
diff --git a/binary-compatibility-validator/test/cases/java/java.txt b/binary-compatibility-validator/test/cases/java/java.txt
deleted file mode 100644
index 75bfd3179f..0000000000
--- a/binary-compatibility-validator/test/cases/java/java.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-public class cases/java/Facade {
- public fun ()V
- public static fun publicMethod (I)V
- public static fun publicMethod (Ljava/lang/String;)V
-}
-
diff --git a/binary-compatibility-validator/test/cases/localClasses/fromStdlib.kt b/binary-compatibility-validator/test/cases/localClasses/fromStdlib.kt
deleted file mode 100644
index 29f6994ec3..0000000000
--- a/binary-compatibility-validator/test/cases/localClasses/fromStdlib.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.localClasses
-
-private val COMPARER = compareBy { it.length }
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/localClasses/lambdas.kt b/binary-compatibility-validator/test/cases/localClasses/lambdas.kt
deleted file mode 100644
index a99c4497ff..0000000000
--- a/binary-compatibility-validator/test/cases/localClasses/lambdas.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.localClasses
-
-
-class L {
- internal fun a(lambda: () -> Unit) = lambda()
-
- @Suppress("NOTHING_TO_INLINE")
- internal inline fun inlineLambda() {
- a {
- println("OK")
- }
- }
-}
-
-fun box() {
- L().inlineLambda()
-}
-
-
-// TODO: inline lambda from stdlib
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/localClasses/localClasses.kt b/binary-compatibility-validator/test/cases/localClasses/localClasses.kt
deleted file mode 100644
index 1af4b77df9..0000000000
--- a/binary-compatibility-validator/test/cases/localClasses/localClasses.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.localClasses
-
-class A {
- fun a() : String {
- class B() {
- fun s() : String = "OK"
-
- inner class C {}
-
- }
- return B().s()
- }
-}
-
-
-class B {
- fun a(p: String) : String {
- class B() {
- fun s() : String = p
- }
- return B().s()
- }
-}
diff --git a/binary-compatibility-validator/test/cases/localClasses/localClasses.txt b/binary-compatibility-validator/test/cases/localClasses/localClasses.txt
deleted file mode 100644
index da0d668ced..0000000000
--- a/binary-compatibility-validator/test/cases/localClasses/localClasses.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-public final class cases/localClasses/A {
- public fun ()V
- public final fun a ()Ljava/lang/String;
-}
-
-public final class cases/localClasses/B {
- public fun ()V
- public final fun a (Ljava/lang/String;)Ljava/lang/String;
-}
-
-public final class cases/localClasses/L {
- public fun ()V
-}
-
-public final class cases/localClasses/LambdasKt {
- public static final fun box ()V
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/internalClass.kt b/binary-compatibility-validator/test/cases/nestedClasses/internalClass.kt
deleted file mode 100644
index 7af2dda914..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/internalClass.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-internal class InternalClass {
- public object ObjPublic
- internal object ObjInternal
- protected object ObjProtected
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- protected class NestedProtected
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- protected interface NestedProtectedInterface
- private interface NestedPrivateInterface
-
- public inner class InnerPublic
- internal inner class InnerInternal
- protected inner class InnerProtected
- private inner class InnerPrivate
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/internalInterface.kt b/binary-compatibility-validator/test/cases/nestedClasses/internalInterface.kt
deleted file mode 100644
index a0affc53a6..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/internalInterface.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-internal interface InternalInterface {
- public object ObjPublic
- private object ObjPrivate
-
- public class NestedPublic
- private class NestedPrivate
-
- public interface NestedPublicInterface
- private interface NestedPrivateInterface
-
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/internalObject.kt b/binary-compatibility-validator/test/cases/nestedClasses/internalObject.kt
deleted file mode 100644
index ca3fd8344b..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/internalObject.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-internal object InternalObject {
-
- public object ObjPublic
- internal object ObjInternal
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- private interface NestedPrivateInterface
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/nestedClasses.txt b/binary-compatibility-validator/test/cases/nestedClasses/nestedClasses.txt
deleted file mode 100644
index 4ba38c780f..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/nestedClasses.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-public abstract class cases/nestedClasses/PublicAbstractClass {
- public fun ()V
-}
-
-protected final class cases/nestedClasses/PublicAbstractClass$InnerProtected {
- public fun (Lcases/nestedClasses/PublicAbstractClass;)V
-}
-
-protected final class cases/nestedClasses/PublicAbstractClass$NestedProtected {
- public fun ()V
-}
-
-protected abstract interface class cases/nestedClasses/PublicAbstractClass$NestedProtectedInterface {
-}
-
-protected final class cases/nestedClasses/PublicAbstractClass$ObjProtected {
- public static final field INSTANCE Lcases/nestedClasses/PublicAbstractClass$ObjProtected;
-}
-
-public final class cases/nestedClasses/PublicClass {
- public fun ()V
-}
-
-public final class cases/nestedClasses/PublicClass$InnerPublic {
- public fun (Lcases/nestedClasses/PublicClass;)V
-}
-
-public final class cases/nestedClasses/PublicClass$NestedPublic {
- public fun ()V
-}
-
-public abstract interface class cases/nestedClasses/PublicClass$NestedPublicInterface {
-}
-
-public final class cases/nestedClasses/PublicClass$ObjPublic {
- public static final field INSTANCE Lcases/nestedClasses/PublicClass$ObjPublic;
-}
-
-public abstract interface class cases/nestedClasses/PublicInterface {
-}
-
-public final class cases/nestedClasses/PublicInterface$NestedPublic {
- public fun ()V
-}
-
-public abstract interface class cases/nestedClasses/PublicInterface$NestedPublicInterface {
-}
-
-public final class cases/nestedClasses/PublicInterface$ObjPublic {
- public static final field INSTANCE Lcases/nestedClasses/PublicInterface$ObjPublic;
-}
-
-public final class cases/nestedClasses/PublicObject {
- public static final field INSTANCE Lcases/nestedClasses/PublicObject;
-}
-
-public final class cases/nestedClasses/PublicObject$NestedPublic {
- public fun ()V
-}
-
-public abstract interface class cases/nestedClasses/PublicObject$NestedPublicInterface {
-}
-
-public final class cases/nestedClasses/PublicObject$ObjPublic {
- public static final field INSTANCE Lcases/nestedClasses/PublicObject$ObjPublic;
-}
-
-public class cases/nestedClasses/PublicOpenClass {
- public fun ()V
-}
-
-protected final class cases/nestedClasses/PublicOpenClass$InnerProtected {
- public fun (Lcases/nestedClasses/PublicOpenClass;)V
-}
-
-protected final class cases/nestedClasses/PublicOpenClass$NestedProtected {
- public fun ()V
-}
-
-protected abstract interface class cases/nestedClasses/PublicOpenClass$NestedProtectedInterface {
-}
-
-protected final class cases/nestedClasses/PublicOpenClass$ObjProtected {
- public static final field INSTANCE Lcases/nestedClasses/PublicOpenClass$ObjProtected;
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/privateClass.kt b/binary-compatibility-validator/test/cases/nestedClasses/privateClass.kt
deleted file mode 100644
index 1e1fa8a8e3..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/privateClass.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-private class PrivateClass {
- public object ObjPublic
- internal object ObjInternal
- protected object ObjProtected
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- protected class NestedProtected
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- protected interface NestedProtectedInterface
- private interface NestedPrivateInterface
-
- public inner class InnerPublic
- internal inner class InnerInternal
- protected inner class InnerProtected
- private inner class InnerPrivate
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/privateInterface.kt b/binary-compatibility-validator/test/cases/nestedClasses/privateInterface.kt
deleted file mode 100644
index 8c936a1fdb..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/privateInterface.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-private interface PrivateInterface {
- public object ObjPublic
- private object ObjPrivate
-
- public class NestedPublic
- private class NestedPrivate
-
- public interface NestedPublicInterface
- private interface NestedPrivateInterface
-
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/privateObject.kt b/binary-compatibility-validator/test/cases/nestedClasses/privateObject.kt
deleted file mode 100644
index 4251d25e78..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/privateObject.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-private object PrivateObject {
-
- public object ObjPublic
- internal object ObjInternal
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- private interface NestedPrivateInterface
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/publicAbstractClass.kt b/binary-compatibility-validator/test/cases/nestedClasses/publicAbstractClass.kt
deleted file mode 100644
index 1da59a5b02..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/publicAbstractClass.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-public abstract class PublicAbstractClass {
- protected object ObjProtected
-
- protected class NestedProtected
-
- protected interface NestedProtectedInterface
-
- protected inner class InnerProtected
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/publicClass.kt b/binary-compatibility-validator/test/cases/nestedClasses/publicClass.kt
deleted file mode 100644
index 64f487d970..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/publicClass.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-public class PublicClass {
- public object ObjPublic
- internal object ObjInternal
- protected object ObjProtected
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- protected class NestedProtected
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- protected interface NestedProtectedInterface
- private interface NestedPrivateInterface
-
- public inner class InnerPublic
- internal inner class InnerInternal
- protected inner class InnerProtected
- private inner class InnerPrivate
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/publicInterface.kt b/binary-compatibility-validator/test/cases/nestedClasses/publicInterface.kt
deleted file mode 100644
index 3ee24f549a..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/publicInterface.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-public interface PublicInterface {
- public object ObjPublic
- private object ObjPrivate
-
- public class NestedPublic
- private class NestedPrivate
-
- public interface NestedPublicInterface
- private interface NestedPrivateInterface
-
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/publicObject.kt b/binary-compatibility-validator/test/cases/nestedClasses/publicObject.kt
deleted file mode 100644
index 6ce2bcdd04..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/publicObject.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-public object PublicObject {
-
- public object ObjPublic
- internal object ObjInternal
- private object ObjPrivate
-
- public class NestedPublic
- internal class NestedInternal
- private class NestedPrivate
-
- public interface NestedPublicInterface
- internal interface NestedInternalInterface
- private interface NestedPrivateInterface
-}
-
diff --git a/binary-compatibility-validator/test/cases/nestedClasses/publicOpenClass.kt b/binary-compatibility-validator/test/cases/nestedClasses/publicOpenClass.kt
deleted file mode 100644
index 1c9edef504..0000000000
--- a/binary-compatibility-validator/test/cases/nestedClasses/publicOpenClass.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.nestedClasses
-
-public open class PublicOpenClass {
- protected object ObjProtected
-
- protected class NestedProtected
-
- protected interface NestedProtectedInterface
-
- protected inner class InnerProtected
-}
-
diff --git a/binary-compatibility-validator/test/cases/private/private.txt b/binary-compatibility-validator/test/cases/private/private.txt
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/binary-compatibility-validator/test/cases/private/privateClassMembers.kt b/binary-compatibility-validator/test/cases/private/privateClassMembers.kt
deleted file mode 100644
index 92dd618372..0000000000
--- a/binary-compatibility-validator/test/cases/private/privateClassMembers.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.private
-
-private open class PrivateClass public constructor() {
- internal val internalVal = 1
-
- protected fun protectedFun() = internalVal
-}
diff --git a/binary-compatibility-validator/test/cases/private/privateMultifile1.kt b/binary-compatibility-validator/test/cases/private/privateMultifile1.kt
deleted file mode 100644
index 8f7535f869..0000000000
--- a/binary-compatibility-validator/test/cases/private/privateMultifile1.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.private
-
-private val privateVal: Any? = 1
-private var privateVar: Any? = 1
-
-
diff --git a/binary-compatibility-validator/test/cases/private/privateMultifile2.kt b/binary-compatibility-validator/test/cases/private/privateMultifile2.kt
deleted file mode 100644
index ee0a08049c..0000000000
--- a/binary-compatibility-validator/test/cases/private/privateMultifile2.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.private
-
-
-// const
-private const val privateConst: Int = 4
-
-// fun
-@Suppress("UNUSED_PARAMETER")
-private fun privateFun(x: Any) {}
-
-
-private class PrivateClassInMultifile {
- internal fun accessUsage() {
- privateFun(privateConst)
- }
-
-}
diff --git a/binary-compatibility-validator/test/cases/private/privatePart.kt b/binary-compatibility-validator/test/cases/private/privatePart.kt
deleted file mode 100644
index 93d4ec14a0..0000000000
--- a/binary-compatibility-validator/test/cases/private/privatePart.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.private
-
-// properties
-private val privateVal: Any? = 1
-private var privateVar: Any? = 1
-
-// constants
-
-private const val privateConst: Int = 4
-
-// fun
-
-@Suppress("UNUSED_PARAMETER")
-private fun privateFun(a: Any?) = privateConst
-
-// access
-private class PrivateClassInPart {
- internal fun accessUsage() {
- privateFun(privateVal)
- privateFun(privateVar)
- privateFun(privateConst)
- }
-
-}
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/protected/protected.txt b/binary-compatibility-validator/test/cases/protected/protected.txt
deleted file mode 100644
index 3c28d7e163..0000000000
--- a/binary-compatibility-validator/test/cases/protected/protected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-public abstract class cases/protected/PublicAbstractClass {
- protected fun ()V
- protected abstract fun getProtectedVal ()I
- protected abstract fun getProtectedVar ()Ljava/lang/Object;
- protected abstract fun protectedFun ()V
- protected abstract fun setProtectedVar (Ljava/lang/Object;)V
-}
-
-public final class cases/protected/PublicFinalClass {
-}
-
-public class cases/protected/PublicOpenClass {
- protected fun ()V
- protected final fun getProtectedVal ()I
- protected final fun getProtectedVar ()I
- protected final fun protectedFun ()I
- protected final fun setProtectedVar (I)V
-}
-
diff --git a/binary-compatibility-validator/test/cases/protected/protectedInAbstract.kt b/binary-compatibility-validator/test/cases/protected/protectedInAbstract.kt
deleted file mode 100644
index ab4e26fef6..0000000000
--- a/binary-compatibility-validator/test/cases/protected/protectedInAbstract.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.protected
-
-public abstract class PublicAbstractClass protected constructor() {
- protected abstract val protectedVal: Int
- protected abstract var protectedVar: Any?
-
- protected abstract fun protectedFun()
-}
diff --git a/binary-compatibility-validator/test/cases/protected/protectedInFinal.kt b/binary-compatibility-validator/test/cases/protected/protectedInFinal.kt
deleted file mode 100644
index 419e3f420c..0000000000
--- a/binary-compatibility-validator/test/cases/protected/protectedInFinal.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.protected
-
-public class PublicFinalClass protected constructor() {
- protected val protectedVal = 1
- protected var protectedVar = 2
-
- protected fun protectedFun() = protectedVal
-}
diff --git a/binary-compatibility-validator/test/cases/protected/protectedInOpen.kt b/binary-compatibility-validator/test/cases/protected/protectedInOpen.kt
deleted file mode 100644
index ee6868354f..0000000000
--- a/binary-compatibility-validator/test/cases/protected/protectedInOpen.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.protected
-
-public open class PublicOpenClass protected constructor() {
- protected val protectedVal = 1
- protected var protectedVar = 2
-
- protected fun protectedFun() = protectedVal
-}
diff --git a/binary-compatibility-validator/test/cases/public/public.txt b/binary-compatibility-validator/test/cases/public/public.txt
deleted file mode 100644
index c9dd5dd2b7..0000000000
--- a/binary-compatibility-validator/test/cases/public/public.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-public final class cases/public/MultifileKt {
- public static final fun getPublicVal ()Ljava/lang/String;
- public static final fun publicFun1 ()Ljava/lang/String;
-}
-
-public final class cases/public/PublicPartKt {
- public static final fun publicFun ()V
-}
-
diff --git a/binary-compatibility-validator/test/cases/public/publicMultifile1.kt b/binary-compatibility-validator/test/cases/public/publicMultifile1.kt
deleted file mode 100644
index ccc6823c3e..0000000000
--- a/binary-compatibility-validator/test/cases/public/publicMultifile1.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.public
-
-public fun publicFun1() = publicVal
diff --git a/binary-compatibility-validator/test/cases/public/publicMultifile2.kt b/binary-compatibility-validator/test/cases/public/publicMultifile2.kt
deleted file mode 100644
index 174bd43d39..0000000000
--- a/binary-compatibility-validator/test/cases/public/publicMultifile2.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:JvmName("MultifileKt")
-@file:JvmMultifileClass
-package cases.public
-
-public val publicVal = "Public"
diff --git a/binary-compatibility-validator/test/cases/public/publicPart.kt b/binary-compatibility-validator/test/cases/public/publicPart.kt
deleted file mode 100644
index 3ad78362d1..0000000000
--- a/binary-compatibility-validator/test/cases/public/publicPart.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.public
-
-public fun publicFun() {
-
-}
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/special/hidden.kt b/binary-compatibility-validator/test/cases/special/hidden.kt
deleted file mode 100644
index cb389b8d0d..0000000000
--- a/binary-compatibility-validator/test/cases/special/hidden.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.special
-
-@Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
-public class HiddenClass
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- public constructor() {
-
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- val hiddenVal = 1
-
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- var hiddenVar = 2
-
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- fun hiddenFun() {}
-
- public var varWithHiddenAccessors: String = ""
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- get
- @Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
- set
-}
-
-@Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
-fun hiddenTopLevelFun() {}
diff --git a/binary-compatibility-validator/test/cases/special/internalLateinitMember.kt b/binary-compatibility-validator/test/cases/special/internalLateinitMember.kt
deleted file mode 100644
index e9819fa4e8..0000000000
--- a/binary-compatibility-validator/test/cases/special/internalLateinitMember.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.special
-
-public class ClassWithLateInitMembers internal constructor() {
-
- public lateinit var publicLateInitWithInternalSet: String
- internal set
-
- internal lateinit var internalLateInit: String
-
-}
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/special/jvmField.kt b/binary-compatibility-validator/test/cases/special/jvmField.kt
deleted file mode 100644
index 9a8c911711..0000000000
--- a/binary-compatibility-validator/test/cases/special/jvmField.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.special
-
-public open class JvmFieldsClass {
- @JvmField
- public var publicField = "x"
-
- @JvmField
- internal var internalField = "y"
-
- @JvmField
- protected var protectedField = "y"
-
- public companion object JvmFieldsCompanion {
- @JvmField
- public var publicСField = "x"
-
- @JvmField
- internal var internalСField = "y"
-
- @JvmField
- protected var protectedСField = "y"
-
- public const val publicConst = 1
- internal const val internalConst = 2
- protected const val protectedConst = 3
- private const val privateConst = 4
- }
-}
-
-public object JvmFieldsObject {
- @JvmField
- public var publicField = "x"
-
- @JvmField
- internal var internalField = "y"
-
- public const val publicConst = 1
- internal const val internalConst = 2
- private const val privateConst = 4
-}
-
-
-@JvmField
-public var publicField = "x"
-
-@JvmField
-internal var internalField = "y"
-
-public const val publicConst = 1
-internal const val internalConst = 2
-private const val privateConst = 4
diff --git a/binary-compatibility-validator/test/cases/special/jvmNames.kt b/binary-compatibility-validator/test/cases/special/jvmNames.kt
deleted file mode 100644
index e304de01fe..0000000000
--- a/binary-compatibility-validator/test/cases/special/jvmNames.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.special
-
-@JvmName("internalFun")
-internal fun internalRenamedFun() {}
-
-internal var internalVar: Int = 1
- @JvmName("internalVarGetter")
- get
- @JvmName("internalVarSetter")
- set
-
-@JvmName("publicFun")
-public fun publicRenamedFun() {}
-
-public var publicVar: Int = 1
- @JvmName("publicVarGetter")
- get
- @JvmName("publicVarSetter")
- set
-
-
-
diff --git a/binary-compatibility-validator/test/cases/special/jvmOverloads.kt b/binary-compatibility-validator/test/cases/special/jvmOverloads.kt
deleted file mode 100644
index 8f238138a2..0000000000
--- a/binary-compatibility-validator/test/cases/special/jvmOverloads.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("UNUSED_PARAMETER")
-
-package cases.special
-
-
-@JvmOverloads
-public fun publicFunWithOverloads(a: Int = 0, b: String? = null) {}
-
-@JvmOverloads
-internal fun internalFunWithOverloads(a: Int = 0, b: String? = null) {}
-
-public class ClassWithOverloads
- @JvmOverloads
- internal constructor(val a: Int = 0, val b: String? = null) {
-
- @JvmOverloads
- internal fun internalFunWithOverloads(a: Int = 0, b: String? = null) {}
-
-}
\ No newline at end of file
diff --git a/binary-compatibility-validator/test/cases/special/special.txt b/binary-compatibility-validator/test/cases/special/special.txt
deleted file mode 100644
index 40c074d245..0000000000
--- a/binary-compatibility-validator/test/cases/special/special.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-public final class cases/special/ClassWithLateInitMembers {
- public final fun getPublicLateInitWithInternalSet ()Ljava/lang/String;
-}
-
-public final class cases/special/ClassWithOverloads {
- public final fun getA ()I
- public final fun getB ()Ljava/lang/String;
-}
-
-public final class cases/special/HiddenClass {
- public synthetic fun ()V
- public final synthetic fun getHiddenVal ()I
- public final synthetic fun getHiddenVar ()I
- public final synthetic fun getVarWithHiddenAccessors ()Ljava/lang/String;
- public final synthetic fun hiddenFun ()V
- public final synthetic fun setHiddenVar (I)V
- public final synthetic fun setVarWithHiddenAccessors (Ljava/lang/String;)V
-}
-
-public final class cases/special/HiddenKt {
- public static final synthetic fun hiddenTopLevelFun ()V
-}
-
-public final class cases/special/JvmFieldKt {
- public static final field publicConst I
- public static field publicField Ljava/lang/String;
-}
-
-public class cases/special/JvmFieldsClass {
- public static final field JvmFieldsCompanion Lcases/special/JvmFieldsClass$JvmFieldsCompanion;
- protected static final field protectedConst I
- protected field protectedField Ljava/lang/String;
- protected static field protectedСField Ljava/lang/String;
- public static final field publicConst I
- public field publicField Ljava/lang/String;
- public static field publicСField Ljava/lang/String;
- public fun ()V
-}
-
-public final class cases/special/JvmFieldsClass$JvmFieldsCompanion {
-}
-
-public final class cases/special/JvmFieldsObject {
- public static final field INSTANCE Lcases/special/JvmFieldsObject;
- public static final field publicConst I
- public static field publicField Ljava/lang/String;
-}
-
-public final class cases/special/JvmNamesKt {
- public static final fun publicFun ()V
- public static final fun publicVarGetter ()I
- public static final fun publicVarSetter (I)V
-}
-
-public final class cases/special/JvmOverloadsKt {
- public static final fun publicFunWithOverloads ()V
- public static final fun publicFunWithOverloads (I)V
- public static final fun publicFunWithOverloads (ILjava/lang/String;)V
- public static synthetic fun publicFunWithOverloads$default (ILjava/lang/String;ILjava/lang/Object;)V
-}
-
diff --git a/binary-compatibility-validator/test/cases/whenMappings/enumWhen.kt b/binary-compatibility-validator/test/cases/whenMappings/enumWhen.kt
deleted file mode 100644
index ff3a1d01b5..0000000000
--- a/binary-compatibility-validator/test/cases/whenMappings/enumWhen.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.whenMappings
-
-enum class SampleEnum {
- A,
- B,
- C
-}
-
-fun SampleEnum.deacronimize() = when (this) {
- SampleEnum.A -> "Apple"
- SampleEnum.B -> "Biscuit"
- SampleEnum.C -> "Cinnamon"
-}
-
-
-inline fun SampleEnum.switch(thenA: () -> Unit, thenB: () -> Unit, thenC: () -> Unit) = when (this) {
- SampleEnum.C -> thenC()
- SampleEnum.B -> thenB()
- SampleEnum.A -> thenA()
-}
diff --git a/binary-compatibility-validator/test/cases/whenMappings/sealedClassWhen.kt b/binary-compatibility-validator/test/cases/whenMappings/sealedClassWhen.kt
deleted file mode 100644
index 5cd80b5d8d..0000000000
--- a/binary-compatibility-validator/test/cases/whenMappings/sealedClassWhen.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package cases.whenMappings
-
-sealed class SampleSealed {
- class A : SampleSealed()
- class B : SampleSealed()
- class C : SampleSealed()
-}
-
-fun SampleSealed.deacronimize() = when (this) {
- is SampleSealed.A -> "Apple"
- is SampleSealed.B -> "Biscuit"
- is SampleSealed.C -> "Cinnamon"
-}
-
-
-inline fun SampleSealed.switch(thenA: () -> Unit, thenB: () -> Unit, thenC: () -> Unit) = when (this) {
- is SampleSealed.C -> thenC()
- is SampleSealed.B -> thenB()
- is SampleSealed.A -> thenA()
-}
diff --git a/binary-compatibility-validator/test/cases/whenMappings/whenMappings.txt b/binary-compatibility-validator/test/cases/whenMappings/whenMappings.txt
deleted file mode 100644
index 1975cf1364..0000000000
--- a/binary-compatibility-validator/test/cases/whenMappings/whenMappings.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-public final class cases/whenMappings/EnumWhenKt {
- public static final fun deacronimize (Lcases/whenMappings/SampleEnum;)Ljava/lang/String;
- public static final fun switch (Lcases/whenMappings/SampleEnum;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
-}
-
-public final class cases/whenMappings/SampleEnum : java/lang/Enum {
- public static final field A Lcases/whenMappings/SampleEnum;
- public static final field B Lcases/whenMappings/SampleEnum;
- public static final field C Lcases/whenMappings/SampleEnum;
- public static fun valueOf (Ljava/lang/String;)Lcases/whenMappings/SampleEnum;
- public static fun values ()[Lcases/whenMappings/SampleEnum;
-}
-
-public abstract class cases/whenMappings/SampleSealed {
-}
-
-public final class cases/whenMappings/SampleSealed$A : cases/whenMappings/SampleSealed {
- public fun ()V
-}
-
-public final class cases/whenMappings/SampleSealed$B : cases/whenMappings/SampleSealed {
- public fun ()V
-}
-
-public final class cases/whenMappings/SampleSealed$C : cases/whenMappings/SampleSealed {
- public fun ()V
-}
-
-public final class cases/whenMappings/SealedClassWhenKt {
- public static final fun deacronimize (Lcases/whenMappings/SampleSealed;)Ljava/lang/String;
- public static final fun switch (Lcases/whenMappings/SampleSealed;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
-}
-
diff --git a/binary-compatibility-validator/test/utils.kt b/binary-compatibility-validator/test/utils.kt
deleted file mode 100644
index c7844108b1..0000000000
--- a/binary-compatibility-validator/test/utils.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.tools
-
-import java.io.*
-import kotlin.test.*
-
-private val OVERWRITE_EXPECTED_OUTPUT =
- System.getProperty("overwrite.output")?.toBoolean() ?: false // use -Doverwrite.output=true
-
-fun List.dumpAndCompareWith(to: File) {
- if (!to.exists()) {
- to.parentFile?.mkdirs()
- to.bufferedWriter().use { dump(to = it) }
- fail("Expected data file did not exist. Generated: $to")
- } else {
- val actual = dump(to = StringBuilder())
- assertEqualsToFile(to, actual)
- }
-}
-
-private fun assertEqualsToFile(to: File, actual: CharSequence) {
- val actualText = actual.trimTrailingWhitespacesAndAddNewlineAtEOF()
- val expectedText = to.readText().trimTrailingWhitespacesAndAddNewlineAtEOF()
- if (expectedText == actualText) return // Ok
- // Difference
- if (OVERWRITE_EXPECTED_OUTPUT) {
- to.writeText(actualText)
- println("Generated: $to")
- return // make test pass when overwriting output
- }
- // Fail on difference
- assertEquals(
- expectedText,
- actualText,
- "Actual data differs from file content: ${to.name}\nTo overwrite the expected API rerun with -Doverwrite.output=true parameter\n"
- )
-}
-
-private fun CharSequence.trimTrailingWhitespacesAndAddNewlineAtEOF(): String =
- this.lineSequence().map { it.trimEnd() }.joinToString(separator = "\n").let {
- if (it.endsWith("\n")) it else it + "\n"
- }
-
-
-private val UPPER_CASE_CHARS = Regex("[A-Z]+")
diff --git a/build.gradle b/build.gradle
index 8fd5441e5e..b6d0483afe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.kotlin.konan.target.HostManager
@@ -8,8 +8,8 @@ apply from: rootProject.file("gradle/experimental.gradle")
def rootModule = "kotlinx.coroutines"
def coreModule = "kotlinx-coroutines-core"
// Not applicable for Kotlin plugin
-def sourceless = ['kotlinx.coroutines', 'site', 'kotlinx-coroutines-bom']
-def internal = ['kotlinx.coroutines', 'site', 'benchmarks', 'knit', 'js-stub', 'stdlib-stubs', 'binary-compatibility-validator']
+def sourceless = ['kotlinx.coroutines', 'site', 'kotlinx-coroutines-bom', 'publication-validator']
+def internal = ['kotlinx.coroutines', 'site', 'benchmarks', 'js-stub', 'stdlib-stubs', 'publication-validator']
// Not published
def unpublished = internal + ['example-frontend-js', 'android-unit-tests']
@@ -41,7 +41,16 @@ buildscript {
}
}
- if (build_snapshot_train || atomicfu_version.endsWith("-SNAPSHOT")) {
+ // Determine if any project dependency is using a snapshot version
+ ext.using_snapshot_version = build_snapshot_train
+ 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
+ }
+ }
+
+ if (using_snapshot_version) {
repositories {
mavenLocal()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
@@ -51,7 +60,13 @@ buildscript {
repositories {
jcenter()
maven { url "https://kotlin.bintray.com/kotlinx" }
- maven { url "https://kotlin.bintray.com/kotlin-dev" }
+ maven {
+ url "https://kotlin.bintray.com/kotlin-dev"
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: ""
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
+ }
+ }
maven { url "https://kotlin.bintray.com/kotlin-eap" }
maven { url "https://jetbrains.bintray.com/kotlin-native-dependencies" }
maven { url "https://plugins.gradle.org/m2/" }
@@ -61,7 +76,10 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
+ classpath "org.jetbrains.kotlinx:kotlinx-knit:$knit_version"
classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version"
+ classpath "org.openjfx:javafx-plugin:$javafx_plugin_version"
+ classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$binary_compatibility_validator_version"
// JMH plugins
classpath "com.github.jengelman.gradle.plugins:shadow:5.1.0"
@@ -95,7 +113,7 @@ allprojects {
kotlin_version = rootProject.properties['kotlin_snapshot_version']
}
- if (build_snapshot_train || atomicfu_version.endsWith("-SNAPSHOT")) {
+ if (using_snapshot_version) {
repositories {
mavenLocal()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
@@ -113,46 +131,59 @@ allprojects {
}
}
+apply plugin: "binary-compatibility-validator"
+apiValidation {
+ ignoredProjects += unpublished + ["kotlinx-coroutines-bom"]
+ ignoredPackages += "kotlinx.coroutines.internal"
+}
+
+// Configure repositories
allprojects {
- apply plugin: 'kotlinx-atomicfu' // it also adds all the necessary dependencies
- def projectName = it.name
+ String projectName = it.name
repositories {
/*
* google should be first in the repository list because some of the play services
* transitive dependencies was removed from jcenter, thus breaking gradle dependency resolution
*/
- if (projectName == "kotlinx-coroutines-play-services") {
- google()
- }
+ google()
jcenter()
- maven { url "https://kotlin.bintray.com/kotlin-dev" }
+ maven {
+ url "https://kotlin.bintray.com/kotlin-dev"
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: ""
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
+ }
+ }
maven { url "https://kotlin.bintray.com/kotlin-eap" }
maven { url "https://kotlin.bintray.com/kotlinx" }
}
+}
- if (projectName == rootModule || projectName == coreModule) return
-
- // Add dependency to core source sets. Core is configured in kx-core/build.gradle
+// Add dependency to core source sets. Core is configured in kx-core/build.gradle
+configure(subprojects.findAll { !sourceless.contains(it.name) && it.name != coreModule }) {
evaluationDependsOn(":$coreModule")
- if (sourceless.contains(projectName)) return
-
def platform = platformOf(it)
apply from: rootProject.file("gradle/compile-${platform}.gradle")
-
dependencies {
// See comment below for rationale, it will be replaced with "project" dependency
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version"
-
// the only way IDEA can resolve test classes
testCompile project(":$coreModule").kotlin.targets.jvm.compilations.test.output.allOutputs
}
+}
+
+// Configure subprojects with Kotlin sources
+configure(subprojects.findAll { !sourceless.contains(it.name) }) {
+ // Use atomicfu plugin, it also adds all the necessary dependencies
+ apply plugin: 'kotlinx-atomicfu'
+ // 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 += "-progressive"
kotlinOptions.freeCompilerArgs += "-XXLanguage:+InlineClasses"
- // Binary compatibility support
- kotlinOptions.freeCompilerArgs += ["-Xdump-declarations-to=${buildDir}/visibilities.json"]
+ // Remove null assertions to get smaller bytecode on Android
+ kotlinOptions.freeCompilerArgs += ["-Xno-param-assertions", "-Xno-receiver-assertions", "-Xno-call-assertions"]
}
}
@@ -166,6 +197,8 @@ if (build_snapshot_train) {
exclude '**/*scheduling*'
exclude '**/*Timeout*'
exclude '**/*definitely/not/kotlinx*'
+ // Disable because of KT-11567 in 1.4
+ exclude '**/*CasesPublicAPITest*'
}
}
@@ -228,7 +261,7 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
tasks.withType(dokka.getClass()) {
externalDocumentationLink {
url = new URL(core_docs_url)
- packageListUrl = new URL("file://$core_docs_file")
+ packageListUrl = new File(core_docs_file).toURI().toURL()
}
}
}
@@ -238,9 +271,38 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
// Report Kotlin compiler version when building project
println("Using Kotlin compiler version: $org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION")
+// --------------- Publish only from under JDK11+ ---------------
+task checkJdkForPublish {
+ doFirst {
+ String javaVersion = System.properties["java.version"]
+ int i = javaVersion.indexOf('.')
+ int javaVersionMajor = (i < 0 ? javaVersion : javaVersion.substring(0, i)).toInteger()
+ if (javaVersionMajor < 11) {
+ throw new GradleException("Project can be build for publishing only under JDK 11+, but found ${javaVersion}")
+ }
+ }
+}
+
// --------------- Configure sub-projects that are published ---------------
-task deploy(dependsOn: getTasksByName("publish", true) + getTasksByName("publishNpm", true))
+def publishTasks = getTasksByName("publish", true) + getTasksByName("publishNpm", true)
+
+publishTasks.each {
+ it.dependsOn checkJdkForPublish
+}
+
+task deploy(dependsOn: publishTasks)
apply plugin: 'base'
clean.dependsOn gradle.includedBuilds.collect { it.task(':clean') }
+
+// --------------- Knit configuration ---------------
+
+apply plugin: 'kotlinx-knit'
+
+knit {
+ siteRoot = "https://kotlin.github.io/kotlinx.coroutines"
+ moduleRoots = [".", "integration", "reactive", "ui"]
+}
+
+knitPrepare.dependsOn getTasksByName("dokka", true)
\ No newline at end of file
diff --git a/docs/basics.md b/docs/basics.md
index 6c3c0caa78..c5e931c58a 100644
--- a/docs/basics.md
+++ b/docs/basics.md
@@ -1,20 +1,4 @@
-
-
-
+
**Table of contents**
@@ -30,8 +14,7 @@ class BasicsGuideTest {
* [Coroutines ARE light-weight](#coroutines-are-light-weight)
* [Global coroutines are like daemon threads](#global-coroutines-are-like-daemon-threads)
-
-
+
## Coroutine Basics
@@ -142,7 +125,7 @@ fun main() = runBlocking { // start main coroutine
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt).
+> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
@@ -396,7 +379,7 @@ fun main() = runBlocking {
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt).
+> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt).
You can run and see that it prints three lines and terminates:
diff --git a/docs/cancellation-and-timeouts.md b/docs/cancellation-and-timeouts.md
index ef4a9c9e09..b51c45c941 100644
--- a/docs/cancellation-and-timeouts.md
+++ b/docs/cancellation-and-timeouts.md
@@ -1,20 +1,5 @@
-
-// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
-package kotlinx.coroutines.guide.$$1$$2
--->
-
-
**Table of contents**
@@ -27,7 +12,7 @@ class CancellationTimeOutsGuideTest {
* [Run non-cancellable block](#run-non-cancellable-block)
* [Timeout](#timeout)
-
+
## Cancellation and Timeouts
diff --git a/docs/channels.md b/docs/channels.md
index 5550759702..1d41774971 100644
--- a/docs/channels.md
+++ b/docs/channels.md
@@ -1,20 +1,5 @@
-
-// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
-package kotlinx.coroutines.guide.$$1$$2
--->
-
-
**Table of contents**
@@ -31,7 +16,7 @@ class ChannelsGuideTest {
* [Channels are fair](#channels-are-fair)
* [Ticker channels](#ticker-channels)
-
+
## Channels
diff --git a/docs/compatibility.md b/docs/compatibility.md
index e56fc1be15..8dafae7293 100644
--- a/docs/compatibility.md
+++ b/docs/compatibility.md
@@ -1,9 +1,3 @@
-
-
* [Compatibility](#compatibility)
@@ -19,7 +13,7 @@
* [Gradle](#gradle)
* [Maven](#maven)
-
+
## Compatibility
This document describes the compatibility policy of `kotlinx.coroutines` library since version 1.0.0 and semantics of compatibility-specific annotations.
diff --git a/docs/composing-suspending-functions.md b/docs/composing-suspending-functions.md
index 0cd02762ee..6a95d7585e 100644
--- a/docs/composing-suspending-functions.md
+++ b/docs/composing-suspending-functions.md
@@ -1,20 +1,4 @@
-
-
-
+
**Table of contents**
@@ -27,7 +11,7 @@ class ComposingGuideTest {
* [Async-style functions](#async-style-functions)
* [Structured concurrency with async](#structured-concurrency-with-async)
-
+
## Composing Suspending Functions
diff --git a/docs/coroutine-context-and-dispatchers.md b/docs/coroutine-context-and-dispatchers.md
index 558b039744..e379842443 100644
--- a/docs/coroutine-context-and-dispatchers.md
+++ b/docs/coroutine-context-and-dispatchers.md
@@ -1,20 +1,4 @@
-
-
-
+
**Table of contents**
@@ -33,7 +17,7 @@ class DispatchersGuideTest {
* [Coroutine scope](#coroutine-scope)
* [Thread-local data](#thread-local-data)
-
+
## Coroutine Context and Dispatchers
diff --git a/docs/debugging.md b/docs/debugging.md
index e2c7ec1e07..6c846f235d 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -8,11 +8,12 @@
* [Stacktrace recovery machinery](#stacktrace-recovery-machinery)
* [Debug agent](#debug-agent)
* [Debug agent and Android](#debug-agent-and-android)
+* [Android optimization](#android-optimization)
-
-
+
## Debugging coroutines
+
Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
and debug agent.
@@ -87,6 +88,14 @@ java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/Mana
at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
-->
+## Android optimization
+
+In optimized (release) builds with R8 version 1.6.0 or later both
+[Debugging mode](../../docs/debugging.md#debug-mode) and
+[Stacktrace recovery](../../docs/debugging.md#stacktrace-recovery)
+are permanently turned off.
+For more details see ["Optimization" section for Android](../ui/kotlinx-coroutines-android/README.md#optimization).
+
[DEBUG_PROPERTY_NAME]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-d-e-b-u-g_-p-r-o-p-e-r-t-y_-n-a-m-e.html
diff --git a/docs/exception-handling.md b/docs/exception-handling.md
index 178f528ae2..08e63ea994 100644
--- a/docs/exception-handling.md
+++ b/docs/exception-handling.md
@@ -1,20 +1,5 @@
-
-// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
-package kotlinx.coroutines.guide.$$1$$2
--->
-
-
**Table of contents**
@@ -29,7 +14,7 @@ class ExceptionsGuideTest {
* [Supervision scope](#supervision-scope)
* [Exceptions in supervised coroutines](#exceptions-in-supervised-coroutines)
-
+
## Exception Handling
@@ -260,7 +245,6 @@ to leak to its exception handler.
diff --git a/docs/flow.md b/docs/flow.md
index ce4e80f1bb..705f338b20 100644
--- a/docs/flow.md
+++ b/docs/flow.md
@@ -1,20 +1,4 @@
-
-
-
+
**Table of contents**
@@ -60,7 +44,7 @@ class FlowGuideTest {
* [Launching flow](#launching-flow)
* [Flow and Reactive Streams](#flow-and-reactive-streams)
-
+
## Asynchronous Flow
diff --git a/docs/knit.code.include b/docs/knit.code.include
new file mode 100644
index 0000000000..42f2b50e81
--- /dev/null
+++ b/docs/knit.code.include
@@ -0,0 +1,6 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// This file was automatically generated from ${file.name} by Knit tool. Do not edit.
+package ${knit.package}.${knit.name}
\ No newline at end of file
diff --git a/docs/knit.properties b/docs/knit.properties
new file mode 100644
index 0000000000..ab2508a114
--- /dev/null
+++ b/docs/knit.properties
@@ -0,0 +1,22 @@
+#
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+knit.package=kotlinx.coroutines.guide
+knit.dir=../kotlinx-coroutines-core/jvm/test/guide/
+knit.pattern=example-[a-zA-Z0-9-]+-##\\.kt
+knit.include=knit.code.include
+
+test.package=kotlinx.coroutines.guide.test
+test.dir=../kotlinx-coroutines-core/jvm/test/guide/test/
+test.template=knit.test.template
+
+# Various test validation modes and their corresponding methods from TestUtil
+test.mode.=verifyLines
+test.mode.STARTS_WITH=verifyLinesStartWith
+test.mode.ARBITRARY_TIME=verifyLinesArbitraryTime
+test.mode.FLEXIBLE_TIME=verifyLinesFlexibleTime
+test.mode.FLEXIBLE_THREAD=verifyLinesFlexibleThread
+test.mode.LINES_START_UNORDERED=verifyLinesStartUnordered
+test.mode.LINES_START=verifyLinesStart
+test.mode.EXCEPTION=verifyExceptions
\ No newline at end of file
diff --git a/docs/knit.test.template b/docs/knit.test.template
new file mode 100644
index 0000000000..a912555a43
--- /dev/null
+++ b/docs/knit.test.template
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// This file was automatically generated from ${file.name} by Knit tool. Do not edit.
+package ${test.package}
+
+import org.junit.Test
+
+class ${test.name} {
+<#list cases as case><#assign method = test["mode.${case.param}"]!"custom">
+ @Test
+ fun test${case.name}() {
+ test("${case.name}") { ${case.knit.package}.${case.knit.name}.main() }<#if method != "custom">.${method}(
+<#list case.lines as line>
+ "${line?j_string}"<#sep>,#sep>
+#list>
+ )
+<#else>.also { lines ->
+ check(${case.param})
+ }
+#if>
+ }
+<#sep>
+
+#list>
+}
\ No newline at end of file
diff --git a/docs/select-expression.md b/docs/select-expression.md
index f36fa09b6b..5809e7b93e 100644
--- a/docs/select-expression.md
+++ b/docs/select-expression.md
@@ -1,21 +1,4 @@
-
-
-
-
+
**Table of contents**
@@ -28,9 +11,7 @@ class SelectGuideTest {
* [Selecting deferred values](#selecting-deferred-values)
* [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
-
-
-
+
## Select Expression (experimental)
diff --git a/docs/shared-mutable-state-and-concurrency.md b/docs/shared-mutable-state-and-concurrency.md
index 30d7334e6c..1a3c406472 100644
--- a/docs/shared-mutable-state-and-concurrency.md
+++ b/docs/shared-mutable-state-and-concurrency.md
@@ -1,20 +1,5 @@
-
-
-
+
+
**Table of contents**
@@ -28,7 +13,7 @@ class SharedStateGuideTest {
* [Mutual exclusion](#mutual-exclusion)
* [Actors](#actors)
-
+
## Shared mutable state and concurrency
diff --git a/gradle.properties b/gradle.properties
index b87d2b009f..53a8de2687 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,22 +1,32 @@
#
-# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
# Kotlin
-version=1.3.3-SNAPSHOT
+version=1.3.4-SNAPSHOT
group=org.jetbrains.kotlinx
-kotlin_version=1.3.61
+kotlin_version=1.3.70
# Dependencies
junit_version=4.12
-atomicfu_version=0.14.1
+atomicfu_version=0.14.2
+knit_version=0.1.3
html_version=0.6.8
-lincheck_version=2.0
+lincheck_version=2.5.3
dokka_version=0.9.16-rdev-2-mpp-hacks
byte_buddy_version=1.9.3
reactor_vesion=3.2.5.RELEASE
reactive_streams_version=1.0.2
rxjava2_version=2.2.8
+javafx_version=11.0.2
+javafx_plugin_version=0.0.8
+binary_compatibility_validator_version=0.1.1
+
+# Android versions
+android_version=4.1.1.4
+android_support_version=26.1.0
+robolectric_version=4.0.2
+baksmali_version=2.2.7
# JS
gradle_node_version=1.2.0
@@ -30,3 +40,6 @@ source_map_support_version=0.5.3
# Settings
kotlin.incremental.multiplatform=true
kotlin.native.ignoreDisabledTargets=true
+
+# Site deneration
+jekyll_version=4.0
diff --git a/gradle/compile-common.gradle b/gradle/compile-common.gradle
index ebad56a312..403c3345d0 100644
--- a/gradle/compile-common.gradle
+++ b/gradle/compile-common.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
kotlin.sourceSets {
diff --git a/gradle/compile-js-multiplatform.gradle b/gradle/compile-js-multiplatform.gradle
index a9a4ea29c6..a7da5c6377 100644
--- a/gradle/compile-js-multiplatform.gradle
+++ b/gradle/compile-js-multiplatform.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply from: rootProject.file('gradle/node-js.gradle')
diff --git a/gradle/compile-js.gradle b/gradle/compile-js.gradle
index 4b1e3bde7f..d0697cfd3a 100644
--- a/gradle/compile-js.gradle
+++ b/gradle/compile-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Platform-specific configuration to compile JS modules
diff --git a/gradle/compile-jvm-multiplatform.gradle b/gradle/compile-jvm-multiplatform.gradle
index f6d76fcada..b226c97a57 100644
--- a/gradle/compile-jvm-multiplatform.gradle
+++ b/gradle/compile-jvm-multiplatform.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
sourceCompatibility = 1.6
diff --git a/gradle/compile-jvm.gradle b/gradle/compile-jvm.gradle
index 3ab25456f8..261136bc87 100644
--- a/gradle/compile-jvm.gradle
+++ b/gradle/compile-jvm.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Platform-specific configuration to compile JVM modules
diff --git a/gradle/compile-native-multiplatform.gradle b/gradle/compile-native-multiplatform.gradle
index a51057ee3e..378e4f5f98 100644
--- a/gradle/compile-native-multiplatform.gradle
+++ b/gradle/compile-native-multiplatform.gradle
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
project.ext.nativeMainSets = []
project.ext.nativeTestSets = []
diff --git a/gradle/dokka.gradle b/gradle/dokka.gradle
index 99201a9f28..bc22189e14 100644
--- a/gradle/dokka.gradle
+++ b/gradle/dokka.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * 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
diff --git a/gradle/experimental.gradle b/gradle/experimental.gradle
index 51bda6c595..b045a1f630 100644
--- a/gradle/experimental.gradle
+++ b/gradle/experimental.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// For new mpp
diff --git a/gradle/maven-central.gradle b/gradle/maven-central.gradle
index 4f9df6ab75..eef7993921 100644
--- a/gradle/maven-central.gradle
+++ b/gradle/maven-central.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// --------------- pom configuration ---------------
diff --git a/gradle/node-js.gradle b/gradle/node-js.gradle
index 208f4ad293..d4bd86ca56 100644
--- a/gradle/node-js.gradle
+++ b/gradle/node-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'com.moowork.node'
diff --git a/gradle/publish-bintray.gradle b/gradle/publish-bintray.gradle
index 9062896b58..c8dd8f12b5 100644
--- a/gradle/publish-bintray.gradle
+++ b/gradle/publish-bintray.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Configures publishing of Maven artifacts to Bintray
diff --git a/gradle/publish-npm-js.gradle b/gradle/publish-npm-js.gradle
index a2991db492..f471c48047 100644
--- a/gradle/publish-npm-js.gradle
+++ b/gradle/publish-npm-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
def prop(name, defVal) {
diff --git a/gradle/targets.gradle b/gradle/targets.gradle
index d4e560fd5a..08f3d989aa 100644
--- a/gradle/targets.gradle
+++ b/gradle/targets.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
/*
diff --git a/gradle/test-mocha-js.gradle b/gradle/test-mocha-js.gradle
index af9d892b07..464898e584 100644
--- a/gradle/test-mocha-js.gradle
+++ b/gradle/test-mocha-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// -- Testing with Mocha under Node
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c141e3345e..7068436015 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
#
-# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
distributionBase=GRADLE_USER_HOME
diff --git a/integration/README.md b/integration/README.md
index 44f270c059..89100179a8 100644
--- a/integration/README.md
+++ b/integration/README.md
@@ -23,5 +23,6 @@ Follow the following simple guidelines when contributing integration with your f
* List of modules in this document.
* List of modules in top-level [`settings.gradle`](../settings.gradle).
* List of modules at the root of documentation site in [`site/docs/index.md`](../site/docs/index.md).
+ * List of integrations in the root [README.md](../README.md).
* Update links to documentation website as explained [here](../knit/README.md#usage).
* Squash your contribution to a single commit and create pull request to `develop` branch.
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-guava.txt b/integration/kotlinx-coroutines-guava/api/kotlinx-coroutines-guava.api
similarity index 100%
rename from binary-compatibility-validator/reference-public-api/kotlinx-coroutines-guava.txt
rename to integration/kotlinx-coroutines-guava/api/kotlinx-coroutines-guava.api
diff --git a/integration/kotlinx-coroutines-guava/build.gradle b/integration/kotlinx-coroutines-guava/build.gradle
index 9e44b99864..16bdea50fd 100644
--- a/integration/kotlinx-coroutines-guava/build.gradle
+++ b/integration/kotlinx-coroutines-guava/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
ext.guava_version = '28.0-jre'
@@ -13,4 +13,4 @@ tasks.withType(dokka.getClass()) {
url = new URL("https://google.github.io/guava/releases/$guava_version/api/docs/")
packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
}
-}
\ No newline at end of file
+}
diff --git a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
index e502ff464f..974e246283 100644
--- a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
+++ b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.guava
diff --git a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
index 80cc22a7bb..a9a7f7ba9d 100644
--- a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
+++ b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
@@ -6,12 +6,11 @@ package kotlinx.coroutines.guava
import com.google.common.util.concurrent.*
import kotlinx.coroutines.*
-import org.hamcrest.core.*
import org.junit.*
-import org.junit.Assert.*
import org.junit.Test
import java.util.concurrent.*
import java.util.concurrent.CancellationException
+import kotlin.test.*
class ListenableFutureTest : TestBase() {
@Before
@@ -27,7 +26,7 @@ class ListenableFutureTest : TestBase() {
"O"
}).await() + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -64,7 +63,7 @@ class ListenableFutureTest : TestBase() {
val future = GlobalScope.future {
toAwait.await() + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -75,7 +74,7 @@ class ListenableFutureTest : TestBase() {
}
assertFalse(future.isDone)
toAwait.set("O")
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -86,11 +85,11 @@ class ListenableFutureTest : TestBase() {
try {
toAwait.await()
} catch (e: RuntimeException) {
- assertThat(e, IsInstanceOf(IllegalArgumentException::class.java))
+ assertTrue(e is IllegalArgumentException)
e.message!!
} + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -100,13 +99,13 @@ class ListenableFutureTest : TestBase() {
try {
toAwait.await()
} catch (e: RuntimeException) {
- assertThat(e, IsInstanceOf(IllegalArgumentException::class.java))
+ assertTrue(e is IllegalArgumentException)
e.message!!
} + "K"
}
assertFalse(future.isDone)
toAwait.setException(IllegalArgumentException("O"))
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -122,8 +121,8 @@ class ListenableFutureTest : TestBase() {
future.get()
fail("'get' should've throw an exception")
} catch (e: ExecutionException) {
- assertThat(e.cause, IsInstanceOf(IllegalStateException::class.java))
- assertThat(e.cause!!.message, IsEqual("OK"))
+ assertTrue(e.cause is IllegalStateException)
+ assertEquals("OK", e.cause!!.message)
}
}
@@ -134,7 +133,7 @@ class ListenableFutureTest : TestBase() {
GlobalScope.future(start = CoroutineStart.LAZY) {}
}
- assertThat(e.message, IsEqual("LAZY start is not supported"))
+ assertEquals("LAZY start is not supported", e.message)
finish(2)
}
@@ -147,7 +146,7 @@ class ListenableFutureTest : TestBase() {
}
expect(3)
val future = deferred.asListenableFuture()
- assertThat(future.await(), IsEqual("OK"))
+ assertEquals("OK", future.await())
finish(4)
}
@@ -160,7 +159,7 @@ class ListenableFutureTest : TestBase() {
}
expect(2)
val future = deferred.asListenableFuture()
- assertThat(future.await(), IsEqual("OK")) // await yields main thread to deferred coroutine
+ assertEquals("OK", future.await()) // await yields main thread to deferred coroutine
finish(4)
}
@@ -370,9 +369,7 @@ class ListenableFutureTest : TestBase() {
assertTrue(asFutureAsDeferred.isCompleted)
// By documentation, join() shouldn't throw when asDeferred is already complete.
asFutureAsDeferred.join()
- assertThat(
- asFutureAsDeferred.getCompletionExceptionOrNull(),
- IsInstanceOf(CancellationException::class.java))
+ assertTrue(asFutureAsDeferred.getCompletionExceptionOrNull() is CancellationException)
}
@Test
@@ -395,9 +392,7 @@ class ListenableFutureTest : TestBase() {
assertTrue(asDeferred.isCompleted)
// By documentation, join() shouldn't throw when asDeferred is already complete.
asDeferred.join()
- assertThat(
- asDeferred.getCompletionExceptionOrNull(),
- IsInstanceOf(CancellationException::class.java))
+ assertTrue(asDeferred.getCompletionExceptionOrNull() is CancellationException)
}
@Test
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-jdk8.txt b/integration/kotlinx-coroutines-jdk8/api/kotlinx-coroutines-jdk8.api
similarity index 100%
rename from binary-compatibility-validator/reference-public-api/kotlinx-coroutines-jdk8.txt
rename to integration/kotlinx-coroutines-jdk8/api/kotlinx-coroutines-jdk8.api
diff --git a/integration/kotlinx-coroutines-jdk8/build.gradle b/integration/kotlinx-coroutines-jdk8/build.gradle
index 3b17101f53..099159292e 100644
--- a/integration/kotlinx-coroutines-jdk8/build.gradle
+++ b/integration/kotlinx-coroutines-jdk8/build.gradle
@@ -1,4 +1,4 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
diff --git a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
index 16829a8018..3cd848f2cf 100644
--- a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.future
diff --git a/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt b/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
index 1b5e479fd4..641a83a682 100644
--- a/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.stream
diff --git a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
index 031ac61fd9..1673116fac 100644
--- a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.time
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/AsFutureTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/AsFutureTest.kt
index 72a1228b95..743816fa85 100644
--- a/integration/kotlinx-coroutines-jdk8/test/future/AsFutureTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/future/AsFutureTest.kt
@@ -5,10 +5,10 @@
package kotlinx.coroutines.future
import kotlinx.coroutines.*
-import org.junit.*
-import org.junit.Assert.*
+import org.junit.Test
import java.util.concurrent.*
import java.util.concurrent.CancellationException
+import kotlin.test.*
class AsFutureTest : TestBase() {
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/FutureExceptionsTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/FutureExceptionsTest.kt
index 86b60e5ff4..0c919b1846 100644
--- a/integration/kotlinx-coroutines-jdk8/test/future/FutureExceptionsTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/future/FutureExceptionsTest.kt
@@ -5,10 +5,10 @@
package kotlinx.coroutines.future
import kotlinx.coroutines.*
-import org.junit.*
-import org.junit.Assert.*
+import org.junit.Test
import java.io.*
import java.util.concurrent.*
+import kotlin.test.*
class FutureExceptionsTest : TestBase() {
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
index 4649645efb..f75c96746c 100644
--- a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
@@ -6,9 +6,8 @@ package kotlinx.coroutines.future
import kotlinx.coroutines.*
import kotlinx.coroutines.CancellationException
-import org.hamcrest.core.*
import org.junit.*
-import org.junit.Assert.*
+import org.junit.Test
import java.util.concurrent.*
import java.util.concurrent.atomic.*
import java.util.concurrent.locks.*
@@ -16,6 +15,7 @@ import java.util.function.*
import kotlin.concurrent.*
import kotlin.coroutines.*
import kotlin.reflect.*
+import kotlin.test.*
class FutureTest : TestBase() {
@Before
@@ -30,7 +30,7 @@ class FutureTest : TestBase() {
"O"
}.await() + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -40,7 +40,7 @@ class FutureTest : TestBase() {
val future = GlobalScope.future {
toAwait.await() + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -51,7 +51,7 @@ class FutureTest : TestBase() {
val future = GlobalScope.future {
toAwait.await() + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -62,7 +62,7 @@ class FutureTest : TestBase() {
}
assertFalse(future.isDone)
toAwait.complete("O")
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -74,7 +74,7 @@ class FutureTest : TestBase() {
}
assertFalse(future.isDone)
completable.complete("O")
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -88,7 +88,7 @@ class FutureTest : TestBase() {
e.message!!
} + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -104,7 +104,7 @@ class FutureTest : TestBase() {
e.message!!
} + "K"
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -125,7 +125,7 @@ class FutureTest : TestBase() {
assertFalse(future.isDone)
toAwait.completeExceptionally(TestException("O"))
yield() // to future coroutine
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
finish(5)
}
@@ -142,7 +142,7 @@ class FutureTest : TestBase() {
}
assertFalse(future.isDone)
completable.completeExceptionally(TestException("O"))
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
@@ -158,7 +158,7 @@ class FutureTest : TestBase() {
fail("'get' should've throw an exception")
} catch (e: ExecutionException) {
assertTrue(e.cause is IllegalStateException)
- assertThat(e.cause!!.message, IsEqual("OK"))
+ assertEquals("OK", e.cause!!.message)
}
}
@@ -191,22 +191,22 @@ class FutureTest : TestBase() {
it()
depth.andDecrement
}) {
- assertEquals("Part before first suspension must be wrapped", 1, depth.get())
+ assertEquals(1, depth.get(), "Part before first suspension must be wrapped")
val result =
CompletableFuture.supplyAsync {
while (depth.get() > 0);
- assertEquals("Part inside suspension point should not be wrapped", 0, depth.get())
+ assertEquals(0, depth.get(), "Part inside suspension point should not be wrapped")
"OK"
}.await()
- assertEquals("Part after first suspension should be wrapped", 1, depth.get())
+ assertEquals(1, depth.get(), "Part after first suspension should be wrapped")
CompletableFuture.supplyAsync {
while (depth.get() > 0);
- assertEquals("Part inside suspension point should not be wrapped", 0, depth.get())
+ assertEquals(0, depth.get(), "Part inside suspension point should not be wrapped")
"ignored"
}.await()
result
}
- assertThat(future.get(), IsEqual("OK"))
+ assertEquals("OK", future.get())
}
@Test
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-play-services.txt b/integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api
similarity index 100%
rename from binary-compatibility-validator/reference-public-api/kotlinx-coroutines-play-services.txt
rename to integration/kotlinx-coroutines-play-services/api/kotlinx-coroutines-play-services.api
diff --git a/integration/kotlinx-coroutines-play-services/build.gradle b/integration/kotlinx-coroutines-play-services/build.gradle
index 61201faeb7..eb554866ed 100644
--- a/integration/kotlinx-coroutines-play-services/build.gradle
+++ b/integration/kotlinx-coroutines-play-services/build.gradle
@@ -1,32 +1,43 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.gradle.api.artifacts.transform.*
+
import java.nio.file.Files
-import java.nio.file.NoSuchFileException
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
ext.tasks_version = '16.0.1'
-def attr = Attribute.of("artifactType", String.class)
-configurations {
- aar {
- attributes { attribute(attr, ArtifactTypeDefinition.JAR_TYPE) }
- sourceSets.main.compileClasspath += it
- sourceSets.test.compileClasspath += it
- sourceSets.test.runtimeClasspath += it
+def artifactType = Attribute.of("artifactType", String)
+def unpackedAar = Attribute.of("unpackedAar", Boolean)
+
+configurations.all {
+ afterEvaluate {
+ if (canBeResolved) {
+ attributes.attribute(unpackedAar, true) // request all AARs to be unpacked
+ }
}
}
dependencies {
- registerTransform {
- from.attribute(attr, "aar")
- to.attribute(attr, "jar")
- artifactTransform(ExtractJars.class)
+ attributesSchema {
+ attribute(unpackedAar)
+ }
+
+ artifactTypes {
+ aar {
+ attributes.attribute(unpackedAar, false)
+ }
}
- aar("com.google.android.gms:play-services-tasks:$tasks_version") {
+ registerTransform(UnpackAar) {
+ from.attribute(unpackedAar, false).attribute(artifactType, "aar")
+ to.attribute(unpackedAar, true).attribute(artifactType, "jar")
+ }
+
+ api("com.google.android.gms:play-services-tasks:$tasks_version") {
exclude group: 'com.android.support'
}
}
@@ -37,48 +48,32 @@ tasks.withType(dokka.getClass()) {
// This is workaround for missing package list in Google API
packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
}
-
- afterEvaluate {
- classpath += project.configurations.aar.files
- }
}
-class ExtractJars extends ArtifactTransform {
- @Override
- List transform(File input) {
- unzip(input)
-
- List jars = new ArrayList<>()
- outputDirectory.traverse(nameFilter: ~/.*\.jar/) { jars += it }
+abstract class UnpackAar implements TransformAction {
+ @InputArtifact
+ abstract Provider getInputArtifact()
- return jars
- }
-
- private void unzip(File zipFile) {
- ZipFile zip
+ @Override
+ void transform(TransformOutputs outputs) {
+ ZipFile zip = new ZipFile(inputArtifact.get().asFile)
try {
- zip = new ZipFile(zipFile)
for (entry in zip.entries()) {
- unzipEntryTo(zip, entry)
+ if (!entry.isDirectory() && entry.name.endsWith(".jar")) {
+ unzipEntryTo(zip, entry, outputs.file(entry.name))
+ }
}
} finally {
- if (zip != null) zip.close()
+ zip.close()
}
}
- private void unzipEntryTo(ZipFile zip, ZipEntry entry) {
- File output = new File(outputDirectory, entry.name)
- if (entry.isDirectory()) {
- output.mkdirs()
- } else {
- InputStream stream
- try {
- stream = zip.getInputStream(entry)
- Files.copy(stream, output.toPath())
- } catch (NoSuchFileException ignored) {
- } finally {
- if (stream != null) stream.close()
- }
+ private static void unzipEntryTo(ZipFile zip, ZipEntry entry, File output) {
+ InputStream stream = zip.getInputStream(entry)
+ try {
+ Files.copy(stream, output.toPath())
+ } finally {
+ stream.close()
}
}
}
diff --git a/integration/kotlinx-coroutines-play-services/src/Tasks.kt b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
index 4952daa7c4..f9b9a60419 100644
--- a/integration/kotlinx-coroutines-play-services/src/Tasks.kt
+++ b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("RedundantVisibilityModifier")
diff --git a/integration/kotlinx-coroutines-play-services/test/TaskTest.kt b/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
index b87a295449..0f125ac98c 100644
--- a/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
+++ b/integration/kotlinx-coroutines-play-services/test/TaskTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.tasks
@@ -61,7 +61,7 @@ class TaskTest : TestBase() {
@Test
fun testThrowingAsTask() {
- val deferred = GlobalScope.async {
+ val deferred = GlobalScope.async {
throw TestException("Fail")
}
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-slf4j.txt b/integration/kotlinx-coroutines-slf4j/api/kotlinx-coroutines-slf4j.api
similarity index 100%
rename from binary-compatibility-validator/reference-public-api/kotlinx-coroutines-slf4j.txt
rename to integration/kotlinx-coroutines-slf4j/api/kotlinx-coroutines-slf4j.api
diff --git a/integration/kotlinx-coroutines-slf4j/build.gradle b/integration/kotlinx-coroutines-slf4j/build.gradle
index 161a0b845a..05accb75d3 100644
--- a/integration/kotlinx-coroutines-slf4j/build.gradle
+++ b/integration/kotlinx-coroutines-slf4j/build.gradle
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
dependencies {
compile 'org.slf4j:slf4j-api:1.7.25'
testCompile 'io.github.microutils:kotlin-logging:1.5.4'
@@ -10,4 +14,4 @@ tasks.withType(dokka.getClass()) {
packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
url = new URL("https://www.slf4j.org/apidocs/")
}
-}
\ No newline at end of file
+}
diff --git a/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt b/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
index c9b1dd9a88..6dbcef6ebe 100644
--- a/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
+++ b/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.slf4j
diff --git a/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt b/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt
index f3ed957bfb..7d18359c5d 100644
--- a/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt
+++ b/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt
@@ -28,7 +28,7 @@ class MDCContextTest : TestBase() {
MDC.put("myKey", "myValue")
// Standalone launch
GlobalScope.launch {
- assertEquals(null, MDC.get("myKey"))
+ assertNull(MDC.get("myKey"))
expect(2)
}.join()
finish(3)
@@ -92,7 +92,7 @@ class MDCContextTest : TestBase() {
@Test
fun testContextMayBeEmpty() {
runBlocking(MDCContext()) {
- assertEquals(null, MDC.get("myKey"))
+ assertNull(MDC.get("myKey"))
}
}
diff --git a/js/example-frontend-js/build.gradle b/js/example-frontend-js/build.gradle
index 52b8bb97de..ff62455494 100644
--- a/js/example-frontend-js/build.gradle
+++ b/js/example-frontend-js/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'kotlin-dce-js'
diff --git a/js/example-frontend-js/npm/webpack.config.js b/js/example-frontend-js/npm/webpack.config.js
index 2124d875eb..a208d047b3 100644
--- a/js/example-frontend-js/npm/webpack.config.js
+++ b/js/example-frontend-js/npm/webpack.config.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// This script is copied to "build" directory and run from there
@@ -50,4 +50,4 @@ module.exports = {
sourceMap: true
})
]
-};
\ No newline at end of file
+};
diff --git a/js/example-frontend-js/src/ExampleMain.kt b/js/example-frontend-js/src/ExampleMain.kt
index e3952a238e..f3e8c081b1 100644
--- a/js/example-frontend-js/src/ExampleMain.kt
+++ b/js/example-frontend-js/src/ExampleMain.kt
@@ -1,21 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-/*
- * Copyright 2016-2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import kotlinx.coroutines.*
diff --git a/js/example-frontend-js/src/main/web/main.js b/js/example-frontend-js/src/main/web/main.js
index c0cb691db5..d2440ffaef 100644
--- a/js/example-frontend-js/src/main/web/main.js
+++ b/js/example-frontend-js/src/main/web/main.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// ------ Main bundle for example application ------
diff --git a/js/example-frontend-js/src/main/web/style.css b/js/example-frontend-js/src/main/web/style.css
index 29dc9ff82f..31d0ebc058 100644
--- a/js/example-frontend-js/src/main/web/style.css
+++ b/js/example-frontend-js/src/main/web/style.css
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
#scene {
@@ -16,4 +16,4 @@
position: absolute;
background: #ffa450;
border-radius: 50%;
-}
\ No newline at end of file
+}
diff --git a/js/js-stub/build.gradle b/js/js-stub/build.gradle
index 20067b7c6b..b2ca0398d9 100644
--- a/js/js-stub/build.gradle
+++ b/js/js-stub/build.gradle
@@ -1,9 +1,9 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
compileKotlin {
kotlinOptions {
freeCompilerArgs += "-Xallow-kotlin-package"
}
-}
\ No newline at end of file
+}
diff --git a/js/js-stub/src/Performance.kt b/js/js-stub/src/Performance.kt
index 4c63ed0039..353a08fff8 100644
--- a/js/js-stub/src/Performance.kt
+++ b/js/js-stub/src/Performance.kt
@@ -1,9 +1,9 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 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 {
abstract fun now(): Double
-}
\ No newline at end of file
+}
diff --git a/js/js-stub/src/Promise.kt b/js/js-stub/src/Promise.kt
index a7d501a6e5..7413a872be 100644
--- a/js/js-stub/src/Promise.kt
+++ b/js/js-stub/src/Promise.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin.js
-public open class Promise
\ No newline at end of file
+public open class Promise
diff --git a/js/js-stub/src/Window.kt b/js/js-stub/src/Window.kt
index 82c6fcfdb1..f54ed0d7bb 100644
--- a/js/js-stub/src/Window.kt
+++ b/js/js-stub/src/Window.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 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
\ No newline at end of file
+public abstract class Window
diff --git a/knit/README.md b/knit/README.md
deleted file mode 100644
index ca0560fa6c..0000000000
--- a/knit/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Knit
-
-This is a very simple tool that produces Kotlin source example files from a markdown document that includes
-snippets of Kotlin code in its body. It is used to produce examples for
-[coroutines guide](../docs/coroutines-guide.md) and other markdown documents.
-It also includes links to the documentation web site into the documents.
-
-## Usage
-
-* In project root directory do:
- * Run `./gradlew knit`
-* Commit updated documents and examples
-
diff --git a/knit/build.gradle b/knit/build.gradle
deleted file mode 100644
index 0410d5d268..0000000000
--- a/knit/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-apply plugin: "application"
-
-sourceSets {
- main.kotlin.srcDirs = ['src']
- main.java.srcDirs = ['src']
- main.resources.srcDirs = ['resources']
-}
-
-FileTree mdFiles = fileTree(project.rootDir) {
- include '**/*.md'
- exclude '**/build/**'
- exclude '**/.gradle/**'
- exclude '**/node_modules/**'
-}
-
-mainClassName = "KnitKt"
-
-run.dependsOn rootProject.getTasksByName("dokka", true)
-run.args = mdFiles
-run.workingDir = project.rootDir
-
-task knit(dependsOn: run)
diff --git a/knit/resources/knit.properties b/knit/resources/knit.properties
deleted file mode 100644
index 146c182339..0000000000
--- a/knit/resources/knit.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
-#
-
-site.root=https://kotlin.github.io/kotlinx.coroutines
-
-module.roots=. integration reactive ui
-module.marker=build.gradle
-module.docs=build/dokka
\ No newline at end of file
diff --git a/knit/src/Knit.kt b/knit/src/Knit.kt
deleted file mode 100644
index 30dd678fd1..0000000000
--- a/knit/src/Knit.kt
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-import java.io.*
-import java.util.*
-import kotlin.properties.*
-
-// --- props in knit.properties
-
-val knitProperties = ClassLoader.getSystemClassLoader()
- .getResource("knit.properties").openStream().use { Properties().apply { load(it) } }
-
-val siteRoot = knitProperties.getProperty("site.root")!!
-val moduleRoots = knitProperties.getProperty("module.roots").split(" ")
-val moduleMarker = knitProperties.getProperty("module.marker")!!
-val moduleDocs = knitProperties.getProperty("module.docs")!!
-
-// --- markdown syntax
-
-const val DIRECTIVE_START = ""
-
-const val TOC_DIRECTIVE = "TOC"
-const val TOC_REF_DIRECTIVE = "TOC_REF"
-const val KNIT_DIRECTIVE = "KNIT"
-const val INCLUDE_DIRECTIVE = "INCLUDE"
-const val CLEAR_DIRECTIVE = "CLEAR"
-const val TEST_DIRECTIVE = "TEST"
-
-const val KNIT_AUTONUMBER_PLACEHOLDER = '#'
-const val KNIT_AUTONUMBER_REGEX = "([0-9a-z]+)"
-
-const val TEST_OUT_DIRECTIVE = "TEST_OUT"
-
-const val MODULE_DIRECTIVE = "MODULE"
-const val INDEX_DIRECTIVE = "INDEX"
-
-const val CODE_START = "```kotlin"
-const val CODE_END = "```"
-
-const val SAMPLE_START = "//sampleStart"
-const val SAMPLE_END = "//sampleEnd"
-
-const val TEST_START = "```text"
-const val TEST_END = "```"
-
-const val SECTION_START = "##"
-
-const val PACKAGE_PREFIX = "package "
-const val STARTS_WITH_PREDICATE = "STARTS_WITH"
-const val ARBITRARY_TIME_PREDICATE = "ARBITRARY_TIME"
-const val FLEXIBLE_TIME_PREDICATE = "FLEXIBLE_TIME"
-const val FLEXIBLE_THREAD_PREDICATE = "FLEXIBLE_THREAD"
-const val LINES_START_UNORDERED_PREDICATE = "LINES_START_UNORDERED"
-const val EXCEPTION_MODE = "EXCEPTION"
-const val LINES_START_PREDICATE = "LINES_START"
-
-val API_REF_REGEX = Regex("(^|[ \\](])\\[([A-Za-z0-9_().]+)]($|[^\\[(])")
-val LINK_DEF_REGEX = Regex("^\\[([A-Za-z0-9_().]+)]: .*")
-
-val tocRefMap = HashMap>()
-val fileSet = HashSet()
-val fileQueue = ArrayDeque()
-
-fun main(args: Array) {
- if (args.isEmpty()) {
- println("Usage: Knit ")
- return
- }
- args.map { File(it) }.toCollection(fileQueue)
- fileQueue.toCollection(fileSet)
- while (!fileQueue.isEmpty()) {
- if (!knit(fileQueue.removeFirst())) System.exit(1) // abort on first error with error exit code
- }
-}
-
-fun knit(markdownFile: File): Boolean {
- println("*** Reading $markdownFile")
- val tocLines = arrayListOf()
- var knitRegex: Regex? = null
- var knitAutonumberGroup = 0
- var knitAutonumberDigits = 0
- var knitAutonumberIndex = 1
- val includes = arrayListOf()
- val codeLines = arrayListOf()
- val testLines = arrayListOf()
- var testOut: String? = null
- val testOutLines = arrayListOf()
- var lastPgk: String? = null
- val files = mutableSetOf()
- val allApiRefs = arrayListOf()
- val remainingApiRefNames = mutableSetOf()
- var moduleName: String by Delegates.notNull()
- var docsRoot: String by Delegates.notNull()
- var retryKnitLater = false
- val tocRefs = ArrayList().also { tocRefMap[markdownFile] = it }
- // read markdown file
- val markdown = markdownFile.withMarkdownTextReader {
- mainLoop@ while (true) {
- val inLine = readLine() ?: break
- val directive = directive(inLine)
- if (directive != null && markdownPart == MarkdownPart.TOC) {
- markdownPart = MarkdownPart.POST_TOC
- postTocText += inLine
- }
- when (directive?.name) {
- TOC_DIRECTIVE -> {
- requireSingleLine(directive)
- require(directive.param.isEmpty()) { "$TOC_DIRECTIVE directive must not have parameters" }
- require(markdownPart == MarkdownPart.PRE_TOC) { "Only one TOC directive is supported" }
- markdownPart = MarkdownPart.TOC
- }
- TOC_REF_DIRECTIVE -> {
- requireSingleLine(directive)
- require(!directive.param.isEmpty()) { "$TOC_REF_DIRECTIVE directive must include reference file path" }
- val refPath = directive.param
- val refFile = File(markdownFile.parent, refPath.replace('/', File.separatorChar))
- require(fileSet.contains(refFile)) { "Referenced file $refFile is missing from the processed file set" }
- val toc = tocRefMap[refFile]
- if (toc == null) {
- retryKnitLater = true // put this file at the end of the queue and retry later
- } else {
- val lines = toc.map { (levelPrefix, name, ref) ->
- "$levelPrefix [$name]($refPath#$ref)"
- }
- if (!replaceUntilNextDirective(lines)) error("Unexpected end of file after $TOC_REF_DIRECTIVE")
- }
- }
- KNIT_DIRECTIVE -> {
- requireSingleLine(directive)
- require(!directive.param.isEmpty()) { "$KNIT_DIRECTIVE directive must include regex parameter" }
- require(knitRegex == null) { "Only one KNIT directive is supported"}
- var str = directive.param
- val i = str.indexOf(KNIT_AUTONUMBER_PLACEHOLDER)
- if (i >= 0) {
- val j = str.lastIndexOf(KNIT_AUTONUMBER_PLACEHOLDER)
- knitAutonumberDigits = j - i + 1
- require(str.substring(i, j + 1) == KNIT_AUTONUMBER_PLACEHOLDER.toString().repeat(knitAutonumberDigits)) {
- "$KNIT_DIRECTIVE can only use a contiguous range of '$KNIT_AUTONUMBER_PLACEHOLDER' for auto-numbering"
- }
- knitAutonumberGroup = str.substring(0, i).count { it == '(' } + 2 // note: it does not understand escaped open braces
- str = str.substring(0, i) + KNIT_AUTONUMBER_REGEX + str.substring(j + 1)
- }
- knitRegex = Regex("\\((" + str + ")\\)")
- continue@mainLoop
- }
- INCLUDE_DIRECTIVE -> {
- if (directive.param.isEmpty()) {
- require(!directive.singleLine) { "$INCLUDE_DIRECTIVE directive without parameters must not be single line" }
- readUntilTo(DIRECTIVE_END, codeLines)
- } else {
- val include = Include(Regex(directive.param))
- if (directive.singleLine) {
- include.lines += codeLines
- codeLines.clear()
- } else {
- readUntilTo(DIRECTIVE_END, include.lines)
- }
- includes += include
- }
- continue@mainLoop
- }
- CLEAR_DIRECTIVE -> {
- requireSingleLine(directive)
- require(directive.param.isEmpty()) { "$CLEAR_DIRECTIVE directive must not have parameters" }
- codeLines.clear()
- continue@mainLoop
- }
- TEST_OUT_DIRECTIVE -> {
- require(!directive.param.isEmpty()) { "$TEST_OUT_DIRECTIVE directive must include file name parameter" }
- flushTestOut(markdownFile.parentFile, testOut, testOutLines)
- testOut = directive.param
- readUntil(DIRECTIVE_END).forEach { testOutLines += it }
- }
- TEST_DIRECTIVE -> {
- require(lastPgk != null) { "'$PACKAGE_PREFIX' prefix was not found in emitted code"}
- require(testOut != null) { "$TEST_OUT_DIRECTIVE directive was not specified" }
- val predicate = directive.param
- if (testLines.isEmpty()) {
- if (directive.singleLine) {
- require(!predicate.isEmpty()) { "$TEST_OUT_DIRECTIVE must be preceded by $TEST_START block or contain test predicate"}
- } else
- testLines += readUntil(DIRECTIVE_END)
- } else {
- requireSingleLine(directive)
- }
- makeTest(testOutLines, lastPgk!!, testLines, predicate)
- testLines.clear()
- }
- MODULE_DIRECTIVE -> {
- requireSingleLine(directive)
- moduleName = directive.param
- docsRoot = findModuleRootDir(moduleName) + "/" + moduleDocs + "/" + moduleName
- }
- INDEX_DIRECTIVE -> {
- requireSingleLine(directive)
- val indexLines = processApiIndex("$siteRoot/$moduleName", docsRoot, directive.param, remainingApiRefNames)
- ?: throw IllegalArgumentException("Failed to load index for ${directive.param}")
- if (!replaceUntilNextDirective(indexLines)) error("Unexpected end of file after $INDEX_DIRECTIVE")
- }
- }
- if (inLine.startsWith(CODE_START)) {
- require(testOut == null || testLines.isEmpty()) { "Previous test was not emitted with $TEST_DIRECTIVE" }
- codeLines += ""
- readUntilTo(CODE_END, codeLines) { line ->
- !line.startsWith(SAMPLE_START) && !line.startsWith(SAMPLE_END)
- }
- continue@mainLoop
- }
- if (inLine.startsWith(TEST_START)) {
- require(testOut == null || testLines.isEmpty()) { "Previous test was not emitted with $TEST_DIRECTIVE" }
- readUntilTo(TEST_END, testLines)
- continue@mainLoop
- }
- if (inLine.startsWith(SECTION_START) && markdownPart == MarkdownPart.POST_TOC) {
- val i = inLine.indexOf(' ')
- require(i >= 2) { "Invalid section start" }
- val name = inLine.substring(i + 1).trim()
- val levelPrefix = " ".repeat(i - 2) + "*"
- val sectionRef = makeSectionRef(name)
- tocLines += "$levelPrefix [$name](#$sectionRef)"
- tocRefs += TocRef(levelPrefix, name, sectionRef)
- continue@mainLoop
- }
- val linkDefMatch = LINK_DEF_REGEX.matchEntire(inLine)
- if (linkDefMatch != null) {
- val name = linkDefMatch.groups[1]!!.value
- remainingApiRefNames -= name
- } else {
- for (match in API_REF_REGEX.findAll(inLine)) {
- val apiRef = ApiRef(lineNumber, match.groups[2]!!.value)
- allApiRefs += apiRef
- remainingApiRefNames += apiRef.name
- }
- }
- knitRegex?.find(inLine)?.let knitRegexMatch@{ knitMatch ->
- val fileName = knitMatch.groups[1]!!.value
- if (knitAutonumberDigits != 0) {
- val numGroup = knitMatch.groups[knitAutonumberGroup]!!
- val num = knitAutonumberIndex.toString().padStart(knitAutonumberDigits, '0')
- if (numGroup.value != num) { // update and retry with this line if a different number
- val r = numGroup.range
- val newLine = inLine.substring(0, r.first) + num + inLine.substring(r.last + 1)
- updateLineAndRetry(newLine)
- return@knitRegexMatch
- }
- }
- knitAutonumberIndex++
- val file = File(markdownFile.parentFile, fileName)
- require(files.add(file)) { "Duplicate file: $file"}
- println("Knitting $file ...")
- val outLines = arrayListOf()
- for (include in includes) {
- val includeMatch = include.regex.matchEntire(fileName) ?: continue
- include.lines.forEach { includeLine ->
- val line = makeReplacements(includeLine, includeMatch)
- if (line.startsWith(PACKAGE_PREFIX))
- lastPgk = line.substring(PACKAGE_PREFIX.length).trim()
- outLines += line
- }
- }
- for (code in codeLines) {
- outLines += code.replace("System.currentTimeMillis()", "currentTimeMillis()")
- }
- codeLines.clear()
- writeLinesIfNeeded(file, outLines)
- }
- }
- } ?: return false // false when failed
- // bailout if retry was requested
- if (retryKnitLater) {
- fileQueue.add(markdownFile)
- return true
- }
- // update markdown file with toc
- val newLines = buildList {
- addAll(markdown.preTocText)
- if (!tocLines.isEmpty()) {
- add("")
- addAll(tocLines)
- add("")
- }
- addAll(markdown.postTocText)
- }
- if (newLines != markdown.inText) writeLines(markdownFile, newLines)
- // check apiRefs
- for (apiRef in allApiRefs) {
- if (apiRef.name in remainingApiRefNames) {
- println("WARNING: $markdownFile: ${apiRef.line}: Broken reference to [${apiRef.name}]")
- }
- }
- // write test output
- flushTestOut(markdownFile.parentFile, testOut, testOutLines)
- return true
-}
-
-data class TocRef(val levelPrefix: String, val name: String, val ref: String)
-
-fun makeTest(testOutLines: MutableList, pgk: String, test: List, predicate: String) {
- val funName = buildString {
- var cap = true
- for (c in pgk) {
- if (c == '.') {
- cap = true
- } else {
- append(if (cap) c.toUpperCase() else c)
- cap = false
- }
- }
- }
- testOutLines += ""
- testOutLines += " @Test"
- testOutLines += " fun test$funName() {"
- val prefix = " test(\"$funName\") { $pgk.main() }"
- when (predicate) {
- "" -> makeTestLines(testOutLines, prefix, "verifyLines", test)
- STARTS_WITH_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesStartWith", test)
- ARBITRARY_TIME_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesArbitraryTime", test)
- FLEXIBLE_TIME_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesFlexibleTime", test)
- FLEXIBLE_THREAD_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesFlexibleThread", test)
- LINES_START_UNORDERED_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesStartUnordered", test)
- EXCEPTION_MODE -> makeTestLines(testOutLines, prefix, "verifyExceptions", test)
- LINES_START_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesStart", test)
- else -> {
- testOutLines += "$prefix.also { lines ->"
- testOutLines += " check($predicate)"
- testOutLines += " }"
- }
- }
- testOutLines += " }"
-}
-
-private fun makeTestLines(testOutLines: MutableList, prefix: String, method: String, test: List) {
- testOutLines += "$prefix.$method("
- for ((index, testLine) in test.withIndex()) {
- val commaOpt = if (index < test.size - 1) "," else ""
- val escapedLine = testLine.replace("\"", "\\\"")
- testOutLines += " \"$escapedLine\"$commaOpt"
- }
- testOutLines += " )"
-}
-
-private fun makeReplacements(line: String, match: MatchResult): String {
- var result = line
- for ((id, group) in match.groups.withIndex()) {
- if (group != null)
- result = result.replace("\$\$$id", group.value)
- }
- return result
-}
-
-private fun flushTestOut(parentDir: File?, testOut: String?, testOutLines: MutableList) {
- if (testOut == null) return
- val file = File(parentDir, testOut)
- testOutLines += "}"
- writeLinesIfNeeded(file, testOutLines)
- testOutLines.clear()
-}
-
-private fun MarkdownTextReader.readUntil(marker: String): List =
- arrayListOf().also { readUntilTo(marker, it) }
-
-private fun MarkdownTextReader.readUntilTo(marker: String, list: MutableList, linePredicate: (String) -> Boolean = { true }) {
- while (true) {
- val line = readLine() ?: break
- if (line.startsWith(marker)) break
- if (linePredicate(line)) list += line
- }
-}
-
-private inline fun buildList(block: ArrayList.() -> Unit): List {
- val result = arrayListOf()
- result.block()
- return result
-}
-
-private fun requireSingleLine(directive: Directive) {
- require(directive.singleLine) { "${directive.name} directive must end on the same line with '$DIRECTIVE_END'" }
-}
-
-fun makeSectionRef(name: String): String = name
- .replace(' ', '-')
- .replace(".", "")
- .replace(",", "")
- .replace("(", "")
- .replace(")", "")
- .replace("`", "")
- .toLowerCase()
-
-class Include(val regex: Regex, val lines: MutableList = arrayListOf())
-
-class Directive(
- val name: String,
- val param: String,
- val singleLine: Boolean
-)
-
-fun directive(line: String): Directive? {
- if (!line.startsWith(DIRECTIVE_START)) return null
- var s = line.substring(DIRECTIVE_START.length).trim()
- val singleLine = s.endsWith(DIRECTIVE_END)
- if (singleLine) s = s.substring(0, s.length - DIRECTIVE_END.length)
- val i = s.indexOf(' ')
- val name = if (i < 0) s else s.substring(0, i)
- val param = if (i < 0) "" else s.substring(i).trim()
- return Directive(name, param, singleLine)
-}
-
-class ApiRef(val line: Int, val name: String)
-
-enum class MarkdownPart { PRE_TOC, TOC, POST_TOC }
-
-class MarkdownTextReader(r: Reader) : LineNumberReader(r) {
- val inText = arrayListOf()
- val preTocText = arrayListOf()
- val postTocText = arrayListOf()
- var markdownPart: MarkdownPart = MarkdownPart.PRE_TOC
- var skip = false
- var putBackLine: String? = null
-
- val outText: MutableList get() = when (markdownPart) {
- MarkdownPart.PRE_TOC -> preTocText
- MarkdownPart.POST_TOC -> postTocText
- else -> throw IllegalStateException("Wrong state: $markdownPart")
- }
-
- override fun readLine(): String? {
- putBackLine?.let {
- putBackLine = null
- return it
- }
- val line = super.readLine() ?: return null
- inText += line
- if (!skip && markdownPart != MarkdownPart.TOC)
- outText += line
- return line
- }
-
- fun updateLineAndRetry(line: String) {
- outText.removeAt(outText.lastIndex)
- outText += line
- putBackLine = line
- }
-
- fun replaceUntilNextDirective(lines: List): Boolean {
- skip = true
- while (true) {
- val skipLine = readLine() ?: return false
- if (directive(skipLine) != null) {
- putBackLine = skipLine
- break
- }
- }
- skip = false
- outText += lines
- outText += putBackLine!!
- return true
- }
-}
-
-fun File.withLineNumberReader(factory: (Reader) -> T, block: T.() -> Unit): T? {
- val reader = factory(reader())
- reader.use {
- try {
- it.block()
- } catch (e: Exception) {
- println("ERROR: ${this@withLineNumberReader}: ${it.lineNumber}: ${e.message}")
- return null
- }
- }
- return reader
-}
-
-fun File.withMarkdownTextReader(block: MarkdownTextReader.() -> Unit): MarkdownTextReader? =
- withLineNumberReader(::MarkdownTextReader, block)
-
-fun writeLinesIfNeeded(file: File, outLines: List) {
- val oldLines = try {
- file.readLines()
- } catch (e: IOException) {
- emptyList()
- }
- if (outLines != oldLines) writeLines(file, outLines)
-}
-
-fun writeLines(file: File, lines: List) {
- println(" Writing $file ...")
- file.parentFile?.mkdirs()
- file.printWriter().use { out ->
- lines.forEach { out.println(it) }
- }
-}
-
-fun findModuleRootDir(name: String): String =
- moduleRoots
- .map { "$it/$name" }
- .firstOrNull { File("$it/$moduleMarker").exists() }
- ?: throw IllegalArgumentException("Module $name is not found in any of the module root dirs")
-
-data class ApiIndexKey(
- val docsRoot: String,
- val pkg: String
-)
-
-val apiIndexCache: MutableMap>> = HashMap()
-
-val REF_LINE_REGEX = Regex("([a-zA-z0-9.]+)")
-val INDEX_HTML = "/index.html"
-val INDEX_MD = "/index.md"
-val FUNCTIONS_SECTION_HEADER = "### Functions"
-
-fun HashMap>.putUnambiguous(key: String, value: String) {
- val oldValue = this[key]
- if (oldValue != null) {
- oldValue.add(value)
- put(key, oldValue)
- } else {
- put(key, mutableListOf(value))
- }
-}
-
-fun loadApiIndex(
- docsRoot: String,
- path: String,
- pkg: String,
- namePrefix: String = ""
-): Map>? {
- val fileName = "$docsRoot/$path$INDEX_MD"
- val visited = mutableSetOf()
- val map = HashMap>()
- var inFunctionsSection = false
- File(fileName).withLineNumberReader(::LineNumberReader) {
- while (true) {
- val line = readLine() ?: break
- if (line == FUNCTIONS_SECTION_HEADER) inFunctionsSection = true
- val result = REF_LINE_REGEX.matchEntire(line) ?: continue
- val link = result.groups[1]!!.value
- if (link.startsWith("..")) continue // ignore cross-references
- val absLink = "$path/$link"
- var name = result.groups[2]!!.value
- // a special disambiguation fix for pseudo-constructor functions
- if (inFunctionsSection && name[0] in 'A'..'Z') name += "()"
- val refName = namePrefix + name
- val fqName = "$pkg.$refName"
- // Put shorter names for extensions on 3rd party classes (prefix is FQname of those classes)
- if (namePrefix != "" && namePrefix[0] in 'a'..'z') {
- val i = namePrefix.dropLast(1).lastIndexOf('.')
- if (i >= 0) map.putUnambiguous(namePrefix.substring(i + 1) + name, absLink)
- map.putUnambiguous(name, absLink)
- }
- // Disambiguate lower-case names with leading underscore (e.g. Flow class vs flow builder ambiguity)
- if (namePrefix == "" && name[0] in 'a'..'z') {
- map.putUnambiguous("_$name", absLink)
- }
- // Always put fully qualified names
- map.putUnambiguous(refName, absLink)
- map.putUnambiguous(fqName, absLink)
- if (link.endsWith(INDEX_HTML)) {
- if (visited.add(link)) {
- val path2 = path + "/" + link.substring(0, link.length - INDEX_HTML.length)
- map += loadApiIndex(docsRoot, path2, pkg, "$refName.")
- ?: throw IllegalArgumentException("Failed to parse $docsRoot/$path2")
- }
- }
- }
- } ?: return null // return null on failure
- return map
-}
-
-fun processApiIndex(
- siteRoot: String,
- docsRoot: String,
- pkg: String,
- remainingApiRefNames: MutableSet
-): List? {
- val key = ApiIndexKey(docsRoot, pkg)
- val map = apiIndexCache.getOrPut(key, {
- print("Parsing API docs at $docsRoot/$pkg: ")
- val result = loadApiIndex(docsRoot, pkg, pkg) ?: return null // null on failure
- println("${result.size} definitions")
- result
- })
- val indexList = arrayListOf()
- val it = remainingApiRefNames.iterator()
- while (it.hasNext()) {
- val refName = it.next()
- val refLink = map[refName] ?: continue
- if (refLink.size > 1) {
- println("INFO: Ambiguous reference to [$refName]: $refLink, taking the shortest one")
- }
-
- val link = refLink.minBy { it.length }
- indexList += "[$refName]: $siteRoot/$link"
- it.remove()
- }
- return indexList
-}
diff --git a/kotlinx-coroutines-bom/build.gradle b/kotlinx-coroutines-bom/build.gradle
index d78f079e8d..25221e3609 100644
--- a/kotlinx-coroutines-bom/build.gradle
+++ b/kotlinx-coroutines-bom/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
plugins {
id 'java-platform'
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
similarity index 99%
rename from binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
rename to kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
index d8d4528eb4..d86a3d5559 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
+++ b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
@@ -151,6 +151,7 @@ public final class kotlinx/coroutines/CoroutineContextKt {
}
public abstract class kotlinx/coroutines/CoroutineDispatcher : kotlin/coroutines/AbstractCoroutineContextElement, kotlin/coroutines/ContinuationInterceptor {
+ public static final field Key Lkotlinx/coroutines/CoroutineDispatcher$Key;
public fun ()V
public abstract fun dispatch (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
public fun dispatchYield (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
@@ -163,6 +164,9 @@ public abstract class kotlinx/coroutines/CoroutineDispatcher : kotlin/coroutines
public fun toString ()Ljava/lang/String;
}
+public final class kotlinx/coroutines/CoroutineDispatcher$Key : kotlin/coroutines/AbstractCoroutineContextKey {
+}
+
public abstract interface class kotlinx/coroutines/CoroutineExceptionHandler : kotlin/coroutines/CoroutineContext$Element {
public static final field Key Lkotlinx/coroutines/CoroutineExceptionHandler$Key;
public abstract fun handleException (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)V
@@ -294,11 +298,15 @@ public final class kotlinx/coroutines/ExceptionsKt {
}
public abstract class kotlinx/coroutines/ExecutorCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher, java/io/Closeable {
+ public static final field Key Lkotlinx/coroutines/ExecutorCoroutineDispatcher$Key;
public fun ()V
public abstract fun close ()V
public abstract fun getExecutor ()Ljava/util/concurrent/Executor;
}
+public final class kotlinx/coroutines/ExecutorCoroutineDispatcher$Key : kotlin/coroutines/AbstractCoroutineContextKey {
+}
+
public final class kotlinx/coroutines/ExecutorsKt {
public static final fun asExecutor (Lkotlinx/coroutines/CoroutineDispatcher;)Ljava/util/concurrent/Executor;
public static final fun from (Ljava/util/concurrent/Executor;)Lkotlinx/coroutines/CoroutineDispatcher;
@@ -746,10 +754,10 @@ public final class kotlinx/coroutines/channels/ConflatedBroadcastChannel : kotli
public final class kotlinx/coroutines/channels/ProduceKt {
public static final fun awaitClose (Lkotlinx/coroutines/channels/ProducerScope;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun awaitClose$default (Lkotlinx/coroutines/channels/ProducerScope;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
- public static final fun produce (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/channels/ReceiveChannel;
public static final fun produce (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/channels/ReceiveChannel;
- public static synthetic fun produce$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveChannel;
+ public static final fun produce (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/channels/ReceiveChannel;
public static synthetic fun produce$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveChannel;
+ public static synthetic fun produce$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveChannel;
}
public abstract interface class kotlinx/coroutines/channels/ProducerScope : kotlinx/coroutines/CoroutineScope, kotlinx/coroutines/channels/SendChannel {
@@ -943,6 +951,7 @@ public final class kotlinx/coroutines/flow/FlowKt {
public static final fun onStart (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
public static final fun produceIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/channels/ReceiveChannel;
public static final fun publishOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
+ public static final fun receiveAsFlow (Lkotlinx/coroutines/channels/ReceiveChannel;)Lkotlinx/coroutines/flow/Flow;
public static final fun reduce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final synthetic fun retry (Lkotlinx/coroutines/flow/Flow;ILkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
public static final fun retry (Lkotlinx/coroutines/flow/Flow;JLkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -1000,7 +1009,7 @@ public final class kotlinx/coroutines/flow/internal/FlowExceptions_commonKt {
public static final fun checkIndexOverflow (I)I
}
-public final class kotlinx/coroutines/flow/internal/SafeCollectorKt {
+public final class kotlinx/coroutines/flow/internal/SafeCollector_commonKt {
public static final fun unsafeFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
}
diff --git a/kotlinx-coroutines-core/build.gradle b/kotlinx-coroutines-core/build.gradle
index 4d516962e9..547a12b4c6 100644
--- a/kotlinx-coroutines-core/build.gradle
+++ b/kotlinx-coroutines-core/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'kotlin-multiplatform'
@@ -46,9 +46,18 @@ configurations {
configureKotlinJvmPlatform(kotlinCompilerPluginClasspath)
}
+// Update module name for metadata artifact to avoid conflicts
+// see https://github.com/Kotlin/kotlinx.coroutines/issues/1797
+compileKotlinMetadata {
+ kotlinOptions {
+ freeCompilerArgs += ["-module-name", "kotlinx-coroutines-core-common"]
+ }
+}
+
kotlin.sourceSets {
jvmTest.dependencies {
- api "com.devexperts.lincheck:lincheck:$lincheck_version"
+ api "org.jetbrains.kotlinx:lincheck:$lincheck_version"
+ api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version"
api "com.esotericsoftware:kryo:4.0.0"
implementation project (":android-unit-tests")
}
@@ -99,7 +108,7 @@ task jdk16Test(type: Test, dependsOn: [compileTestKotlinJvm, checkJdk16]) {
testClassesDirs = files { jvmTest.testClassesDirs }
executable = "$System.env.JDK_16/bin/java"
exclude '**/*LFStressTest.*' // lock-freedom tests use LockFreedomTestEnvironment which needs JDK8
- exclude '**/*LCStressTest.*' // lic-check tests use LinChecker which needs JDK8
+ exclude '**/*LCStressTest.*' // lin-check tests use LinChecker which needs JDK8
exclude '**/exceptions/**' // exceptions tests check suppressed exception which needs JDK8
exclude '**/ExceptionsGuideTest.*'
}
diff --git a/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt b/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
index 18088777a5..22111f0ce2 100644
--- a/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Annotations.kt b/kotlinx-coroutines-core/common/src/Annotations.kt
index 742a7d7c66..5475c6b10e 100644
--- a/kotlinx-coroutines-core/common/src/Annotations.kt
+++ b/kotlinx-coroutines-core/common/src/Annotations.kt
@@ -1,10 +1,10 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.*
/**
* Marks declarations that are still **experimental** in coroutines API, which means that the design of the
@@ -14,7 +14,7 @@ import kotlinx.coroutines.flow.Flow
*/
@MustBeDocumented
@Retention(value = AnnotationRetention.BINARY)
-@Experimental(level = Experimental.Level.WARNING)
+@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
public annotation class ExperimentalCoroutinesApi
/**
@@ -30,7 +30,12 @@ public annotation class ExperimentalCoroutinesApi
*/
@MustBeDocumented
@Retention(value = AnnotationRetention.BINARY)
-@Experimental(level = Experimental.Level.WARNING)
+@RequiresOptIn(
+ level = RequiresOptIn.Level.WARNING,
+ message = "This declaration is in a preview state and can be changed in a backwards-incompatible manner with a best-effort migration. " +
+ "Its usage should be marked with '@kotlinx.coroutines.FlowPreview' or '@OptIn(kotlinx.coroutines.FlowPreview::class)' " +
+ "if you accept the drawback of relying on preview API"
+)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, AnnotationTarget.PROPERTY)
public annotation class FlowPreview
@@ -42,7 +47,7 @@ public annotation class FlowPreview
*/
@MustBeDocumented
@Retention(value = AnnotationRetention.BINARY)
-@Experimental(level = Experimental.Level.WARNING)
+@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
public annotation class ObsoleteCoroutinesApi
/**
@@ -51,6 +56,11 @@ public annotation class ObsoleteCoroutinesApi
* warnings and without providing any migration aids.
*/
@Retention(value = AnnotationRetention.BINARY)
-@Experimental(level = Experimental.Level.ERROR)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, AnnotationTarget.PROPERTY)
+@RequiresOptIn(
+ level = RequiresOptIn.Level.ERROR, message = "This is an internal kotlinx.coroutines API that " +
+ "should not be used from outside of kotlinx.coroutines. No compatibility guarantees are provided." +
+ "It is recommended to report your use-case of internal API to kotlinx.coroutines issue tracker, " +
+ "so stable API could be provided instead"
+)
public annotation class InternalCoroutinesApi
diff --git a/kotlinx-coroutines-core/common/src/Await.kt b/kotlinx-coroutines-core/common/src/Await.kt
index 3da0ad5ee9..dd1e1771f2 100644
--- a/kotlinx-coroutines-core/common/src/Await.kt
+++ b/kotlinx-coroutines-core/common/src/Await.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Builders.common.kt b/kotlinx-coroutines-core/common/src/Builders.common.kt
index ff5d406643..7dd1b174ee 100644
--- a/kotlinx-coroutines-core/common/src/Builders.common.kt
+++ b/kotlinx-coroutines-core/common/src/Builders.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
index d1e99529a5..fd5cd083e2 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
index f5b5900cb6..0cc9b57dec 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -9,6 +9,7 @@ import kotlinx.coroutines.internal.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.jvm.*
+import kotlin.native.concurrent.*
private const val UNDECIDED = 0
private const val SUSPENDED = 1
diff --git a/kotlinx-coroutines-core/common/src/CompletableDeferred.kt b/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
index 732d07225f..f6cf90d515 100644
--- a/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
+++ b/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/CompletableJob.kt b/kotlinx-coroutines-core/common/src/CompletableJob.kt
index 9a632276fe..4b4d16bc53 100644
--- a/kotlinx-coroutines-core/common/src/CompletableJob.kt
+++ b/kotlinx-coroutines-core/common/src/CompletableJob.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -36,4 +36,4 @@ public interface CompletableJob : Job {
* a [CancellationException] with the [exception] as a cause for the sake of diagnostic.
*/
public fun completeExceptionally(exception: Throwable): Boolean
-}
\ No newline at end of file
+}
diff --git a/kotlinx-coroutines-core/common/src/CompletedExceptionally.kt b/kotlinx-coroutines-core/common/src/CompletedExceptionally.kt
index b75d43070e..b426785bd7 100644
--- a/kotlinx-coroutines-core/common/src/CompletedExceptionally.kt
+++ b/kotlinx-coroutines-core/common/src/CompletedExceptionally.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt b/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
index 00bac305d5..bf6900087d 100644
--- a/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
+++ b/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
index a8b5686253..51374603c3 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -20,4 +20,4 @@ internal expect val DefaultDelay: Delay
// countOrElement -- pre-cached value for ThreadContext.kt
internal expect inline fun withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T
internal expect fun Continuation<*>.toDebugString(): String
-internal expect val CoroutineContext.coroutineName: String?
\ No newline at end of file
+internal expect val CoroutineContext.coroutineName: String?
diff --git a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
index 393f6cb526..a618642f72 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -30,6 +30,12 @@ import kotlin.coroutines.*
public abstract class CoroutineDispatcher :
AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
+ /** @suppress */
+ @ExperimentalStdlibApi
+ public companion object Key : AbstractCoroutineContextKey(
+ ContinuationInterceptor,
+ { it as? CoroutineDispatcher })
+
/**
* Returns `true` if the execution of the coroutine should be performed with [dispatch] method.
* The default behavior for most dispatchers is to return `true`.
diff --git a/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt b/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
index ee440b5310..cd7fd0d7ca 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineName.kt b/kotlinx-coroutines-core/common/src/CoroutineName.kt
index 4a7e9ea4f8..7f09a5897c 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineName.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineName.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
index ca387338dc..a6b79bdb5a 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineStart.kt b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
index 9e283b0db9..1272ce7c3a 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineStart.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Debug.common.kt b/kotlinx-coroutines-core/common/src/Debug.common.kt
index 3bd7aabe92..013b983a74 100644
--- a/kotlinx-coroutines-core/common/src/Debug.common.kt
+++ b/kotlinx-coroutines-core/common/src/Debug.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Deferred.kt b/kotlinx-coroutines-core/common/src/Deferred.kt
index 04152f903e..f05abbdb43 100644
--- a/kotlinx-coroutines-core/common/src/Deferred.kt
+++ b/kotlinx-coroutines-core/common/src/Deferred.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Delay.kt b/kotlinx-coroutines-core/common/src/Delay.kt
index acb924020a..3404f63611 100644
--- a/kotlinx-coroutines-core/common/src/Delay.kt
+++ b/kotlinx-coroutines-core/common/src/Delay.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Dispatchers.common.kt b/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
index 5a957e7555..dba57abc88 100644
--- a/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
+++ b/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/EventLoop.common.kt b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
index a4984b55e5..ba331e20df 100644
--- a/kotlinx-coroutines-core/common/src/EventLoop.common.kt
+++ b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -8,6 +8,7 @@ import kotlinx.atomicfu.*
import kotlinx.coroutines.internal.*
import kotlin.coroutines.*
import kotlin.jvm.*
+import kotlin.native.concurrent.*
/**
* Extended by [CoroutineDispatcher] implementations that have event loop inside and can
@@ -117,7 +118,7 @@ internal abstract class EventLoop : CoroutineDispatcher() {
protected open fun shutdown() {}
}
-@NativeThreadLocal
+@ThreadLocal
internal object ThreadLocalEventLoop {
private val ref = CommonThreadLocal()
diff --git a/kotlinx-coroutines-core/common/src/Exceptions.common.kt b/kotlinx-coroutines-core/common/src/Exceptions.common.kt
index 2c0b5ce2cd..64f8911e9d 100644
--- a/kotlinx-coroutines-core/common/src/Exceptions.common.kt
+++ b/kotlinx-coroutines-core/common/src/Exceptions.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -29,4 +29,4 @@ internal class CoroutinesInternalError(message: String, cause: Throwable) : Erro
internal expect fun Throwable.addSuppressedThrowable(other: Throwable)
// For use in tests
-internal expect val RECOVER_STACK_TRACES: Boolean
\ No newline at end of file
+internal expect val RECOVER_STACK_TRACES: Boolean
diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt
index 133e24fa69..4d4e37ee25 100644
--- a/kotlinx-coroutines-core/common/src/Job.kt
+++ b/kotlinx-coroutines-core/common/src/Job.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/JobSupport.kt b/kotlinx-coroutines-core/common/src/JobSupport.kt
index eb0d823f38..e52aaeaa8e 100644
--- a/kotlinx-coroutines-core/common/src/JobSupport.kt
+++ b/kotlinx-coroutines-core/common/src/JobSupport.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
@@ -13,6 +13,7 @@ import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.js.*
import kotlin.jvm.*
+import kotlin.native.concurrent.*
/**
* A concrete implementation of [Job]. It is optionally a child to a parent job.
diff --git a/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
index bead3c89a4..3f2ddcd69f 100644
--- a/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/NonCancellable.kt b/kotlinx-coroutines-core/common/src/NonCancellable.kt
index c48faea7f8..45803cf945 100644
--- a/kotlinx-coroutines-core/common/src/NonCancellable.kt
+++ b/kotlinx-coroutines-core/common/src/NonCancellable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Runnable.common.kt b/kotlinx-coroutines-core/common/src/Runnable.common.kt
index 6c258d854d..692c700b50 100644
--- a/kotlinx-coroutines-core/common/src/Runnable.common.kt
+++ b/kotlinx-coroutines-core/common/src/Runnable.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -18,4 +18,4 @@ public expect interface Runnable {
* Creates [Runnable] task instance.
*/
@Suppress("FunctionName")
-public expect inline fun Runnable(crossinline block: () -> Unit): Runnable
\ No newline at end of file
+public expect inline fun Runnable(crossinline block: () -> Unit): Runnable
diff --git a/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt b/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
index 7b767f5167..dbdf45ead5 100644
--- a/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
+++ b/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Supervisor.kt b/kotlinx-coroutines-core/common/src/Supervisor.kt
index 63542a9a17..1991119053 100644
--- a/kotlinx-coroutines-core/common/src/Supervisor.kt
+++ b/kotlinx-coroutines-core/common/src/Supervisor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Timeout.kt b/kotlinx-coroutines-core/common/src/Timeout.kt
index 7e6f0d0e2d..8aedba30a1 100644
--- a/kotlinx-coroutines-core/common/src/Timeout.kt
+++ b/kotlinx-coroutines-core/common/src/Timeout.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Unconfined.kt b/kotlinx-coroutines-core/common/src/Unconfined.kt
index 794ee1e181..ce03a28765 100644
--- a/kotlinx-coroutines-core/common/src/Unconfined.kt
+++ b/kotlinx-coroutines-core/common/src/Unconfined.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -37,4 +37,4 @@ internal class YieldContext : AbstractCoroutineContextElement(Key) {
@JvmField
var dispatcherWasUnconfined = false
-}
\ No newline at end of file
+}
diff --git a/kotlinx-coroutines-core/common/src/Yield.kt b/kotlinx-coroutines-core/common/src/Yield.kt
index 5d931340af..e0af04ddb7 100644
--- a/kotlinx-coroutines-core/common/src/Yield.kt
+++ b/kotlinx-coroutines-core/common/src/Yield.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
index f70164485a..8d078e49ca 100644
--- a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -11,6 +11,7 @@ import kotlinx.coroutines.intrinsics.*
import kotlinx.coroutines.selects.*
import kotlin.coroutines.*
import kotlin.jvm.*
+import kotlin.native.concurrent.*
/**
* Abstract send channel. It is a base class for all send channel implementations.
@@ -29,6 +30,7 @@ internal abstract class AbstractSendChannel : SendChannel {
/**
* Returns `true` if this channel's buffer is full.
+ * This operation should be atomic if it is invoked by [enqueueSend].
* @suppress **This is unstable API and it is subject to change.**
*/
protected abstract val isBufferFull: Boolean
@@ -139,8 +141,8 @@ internal abstract class AbstractSendChannel : SendChannel {
// ------ SendChannel ------
public final override val isClosedForSend: Boolean get() = closedForSend != null
- public final override val isFull: Boolean get() = full
- private val full: Boolean get() = queue.nextNode !is ReceiveOrClosed<*> && isBufferFull // TODO rename to `isFull`
+ public override val isFull: Boolean get() = isFullImpl
+ protected val isFullImpl: Boolean get() = queue.nextNode !is ReceiveOrClosed<*> && isBufferFull
public final override suspend fun send(element: E) {
// fast path -- try offer non-blocking
@@ -181,7 +183,7 @@ internal abstract class AbstractSendChannel : SendChannel {
private suspend fun sendSuspend(element: E): Unit = suspendAtomicCancellableCoroutineReusable sc@ { cont ->
loop@ while (true) {
- if (full) {
+ if (isFullImpl) {
val send = SendElement(element, cont)
val enqueueResult = enqueueSend(send)
when {
@@ -226,7 +228,7 @@ internal abstract class AbstractSendChannel : SendChannel {
* * ENQUEUE_FAILED -- buffer is not full (should not enqueue)
* * ReceiveOrClosed<*> -- receiver is waiting or it is closed (should not enqueue)
*/
- private fun enqueueSend(send: Send): Any? {
+ protected open fun enqueueSend(send: Send): Any? {
if (isBufferAlwaysFull) {
queue.addLastIfPrev(send) { prev ->
if (prev is ReceiveOrClosed<*>) return@enqueueSend prev
@@ -381,7 +383,7 @@ internal abstract class AbstractSendChannel : SendChannel {
private fun registerSelectSend(select: SelectInstance, element: E, block: suspend (SendChannel) -> R) {
while (true) {
if (select.isSelected) return
- if (full) {
+ if (isFullImpl) {
val node = SendSelect(element, this, select, block)
val enqueueResult = enqueueSend(node)
when {
@@ -494,6 +496,7 @@ internal abstract class AbstractChannel : AbstractSendChannel(), Channel : AbstractSendChannel(), Channel : AbstractSendChannel(), Channel): Boolean {
- val result = if (isBufferAlwaysEmpty)
- queue.addLastIfPrev(receive) { it !is Send } else
- queue.addLastIfPrevAndIf(receive, { it !is Send }, { isBufferEmpty })
+ protected open fun enqueueReceiveInternal(receive: Receive): Boolean = if (isBufferAlwaysEmpty)
+ queue.addLastIfPrev(receive) { it !is Send } else
+ queue.addLastIfPrevAndIf(receive, { it !is Send }, { isBufferEmpty })
+
+ private fun enqueueReceive(receive: Receive) = enqueueReceiveInternal(receive).also { result ->
if (result) onReceiveEnqueued()
- return result
}
public final override suspend fun receiveOrNull(): E? {
@@ -717,7 +721,7 @@ internal abstract class AbstractChannel : AbstractSendChannel(), Channel registerSelectReceiveMode(select: SelectInstance, receiveMode: Int, block: suspend (Any?) -> R) {
while (true) {
if (select.isSelected) return
- if (isEmpty) {
+ if (isEmptyImpl) {
if (enqueueReceiveSelect(select, block, receiveMode)) return
} else {
val pollResult = pollSelectInternal(select)
@@ -1057,7 +1061,7 @@ internal class Closed(
override fun toString(): String = "Closed@$hexAddress[$closeCause]"
}
-private abstract class Receive : LockFreeLinkedListNode(), ReceiveOrClosed {
+internal abstract class Receive : LockFreeLinkedListNode(), ReceiveOrClosed {
override val offerResult get() = OFFER_SUCCESS
abstract fun resumeReceiveClosed(closed: Closed<*>)
}
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
index 5f3eb32d8f..19334ea706 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -371,4 +371,4 @@ internal class ArrayBroadcastChannel(
override val bufferDebugString: String
get() = "(buffer:capacity=${buffer.size},size=$size)"
-}
\ No newline at end of file
+}
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
index da284be525..e26579eff7 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -36,34 +36,38 @@ internal open class ArrayChannel(
*/
private var buffer: Array = arrayOfNulls(min(capacity, 8))
private var head: Int = 0
- private var size = 0 // Invariant: size <= capacity
+ private val size = atomic(0) // Invariant: size <= capacity
protected final override val isBufferAlwaysEmpty: Boolean get() = false
- protected final override val isBufferEmpty: Boolean get() = lock.withLock { size == 0 }
+ protected final override val isBufferEmpty: Boolean get() = size.value == 0
protected final override val isBufferAlwaysFull: Boolean get() = false
- protected final override val isBufferFull: Boolean get() = lock.withLock { size == capacity }
+ protected final override val isBufferFull: Boolean get() = size.value == capacity
+
+ override val isFull: Boolean get() = lock.withLock { isFullImpl }
+ override val isEmpty: Boolean get() = lock.withLock { isEmptyImpl }
+ override val isClosedForReceive: Boolean get() = lock.withLock { super.isClosedForReceive }
// result is `OFFER_SUCCESS | OFFER_FAILED | Closed`
protected override fun offerInternal(element: E): Any {
var receive: ReceiveOrClosed? = null
lock.withLock {
- val size = this.size
+ val size = this.size.value
closedForSend?.let { return it }
if (size < capacity) {
// tentatively put element to buffer
- this.size = size + 1 // update size before checking queue (!!!)
+ this.size.value = size + 1 // update size before checking queue (!!!)
// check for receivers that were waiting on empty queue
if (size == 0) {
loop@ while (true) {
receive = takeFirstReceiveOrPeekClosed() ?: break@loop // break when no receivers queued
if (receive is Closed) {
- this.size = size // restore size
+ this.size.value = size // restore size
return receive!!
}
val token = receive!!.tryResumeReceive(element, null)
if (token != null) {
assert { token === RESUME_TOKEN }
- this.size = size // restore size
+ this.size.value = size // restore size
return@withLock
}
}
@@ -84,11 +88,11 @@ internal open class ArrayChannel(
protected override fun offerSelectInternal(element: E, select: SelectInstance<*>): Any {
var receive: ReceiveOrClosed? = null
lock.withLock {
- val size = this.size
+ val size = this.size.value
closedForSend?.let { return it }
if (size < capacity) {
// tentatively put element to buffer
- this.size = size + 1 // update size before checking queue (!!!)
+ this.size.value = size + 1 // update size before checking queue (!!!)
// check for receivers that were waiting on empty queue
if (size == 0) {
loop@ while (true) {
@@ -96,14 +100,14 @@ internal open class ArrayChannel(
val failure = select.performAtomicTrySelect(offerOp)
when {
failure == null -> { // offered successfully
- this.size = size // restore size
+ this.size.value = size // restore size
receive = offerOp.result
return@withLock
}
failure === OFFER_FAILED -> break@loop // cannot offer -> Ok to queue to buffer
failure === RETRY_ATOMIC -> {} // retry
failure === ALREADY_SELECTED || failure is Closed<*> -> {
- this.size = size // restore size
+ this.size.value = size // restore size
return failure
}
else -> error("performAtomicTrySelect(describeTryOffer) returned $failure")
@@ -112,7 +116,7 @@ internal open class ArrayChannel(
}
// let's try to select sending this element to buffer
if (!select.trySelect()) { // :todo: move trySelect completion outside of lock
- this.size = size // restore size
+ this.size.value = size // restore size
return ALREADY_SELECTED
}
ensureCapacity(size)
@@ -127,6 +131,10 @@ internal open class ArrayChannel(
return receive!!.offerResult
}
+ override fun enqueueSend(send: Send): Any? = lock.withLock {
+ super.enqueueSend(send)
+ }
+
// Guarded by lock
private fun ensureCapacity(currentSize: Int) {
if (currentSize >= buffer.size) {
@@ -146,12 +154,12 @@ internal open class ArrayChannel(
var resumed = false
var result: Any? = null
lock.withLock {
- val size = this.size
+ val size = this.size.value
if (size == 0) return closedForSend ?: POLL_FAILED // when nothing can be read from buffer
// size > 0: not empty -- retrieve element
result = buffer[head]
buffer[head] = null
- this.size = size - 1 // update size before checking queue (!!!)
+ this.size.value = size - 1 // update size before checking queue (!!!)
// check for senders that were waiting on full queue
var replacement: Any? = POLL_FAILED
if (size == capacity) {
@@ -167,7 +175,7 @@ internal open class ArrayChannel(
}
}
if (replacement !== POLL_FAILED && replacement !is Closed<*>) {
- this.size = size // restore size
+ this.size.value = size // restore size
buffer[(head + size) % buffer.size] = replacement
}
head = (head + 1) % buffer.size
@@ -184,12 +192,12 @@ internal open class ArrayChannel(
var success = false
var result: Any? = null
lock.withLock {
- val size = this.size
+ val size = this.size.value
if (size == 0) return closedForSend ?: POLL_FAILED
// size > 0: not empty -- retrieve element
result = buffer[head]
buffer[head] = null
- this.size = size - 1 // update size before checking queue (!!!)
+ this.size.value = size - 1 // update size before checking queue (!!!)
// check for senders that were waiting on full queue
var replacement: Any? = POLL_FAILED
if (size == capacity) {
@@ -206,7 +214,7 @@ internal open class ArrayChannel(
failure === POLL_FAILED -> break@loop // cannot poll -> Ok to take from buffer
failure === RETRY_ATOMIC -> {} // retry
failure === ALREADY_SELECTED -> {
- this.size = size // restore size
+ this.size.value = size // restore size
buffer[head] = result // restore head
return failure
}
@@ -221,12 +229,12 @@ internal open class ArrayChannel(
}
}
if (replacement !== POLL_FAILED && replacement !is Closed<*>) {
- this.size = size // restore size
+ this.size.value = size // restore size
buffer[(head + size) % buffer.size] = replacement
} else {
// failed to poll or is already closed --> let's try to select receiving this element from buffer
if (!select.trySelect()) { // :todo: move trySelect completion outside of lock
- this.size = size // restore size
+ this.size.value = size // restore size
buffer[head] = result // restore head
return ALREADY_SELECTED
}
@@ -239,16 +247,20 @@ internal open class ArrayChannel(
return result
}
+ override fun enqueueReceiveInternal(receive: Receive): Boolean = lock.withLock {
+ super.enqueueReceiveInternal(receive)
+ }
+
// Note: this function is invoked when channel is already closed
override fun onCancelIdempotent(wasClosed: Boolean) {
// clear buffer first, but do not wait for it in helpers
if (wasClosed) {
lock.withLock {
- repeat(size) {
+ repeat(size.value) {
buffer[head] = 0
head = (head + 1) % buffer.size
}
- size = 0
+ size.value = 0
}
}
// then clean all queued senders
@@ -258,5 +270,5 @@ internal open class ArrayChannel(
// ------ debug ------
override val bufferDebugString: String
- get() = "(buffer:capacity=$capacity,size=$size)"
+ get() = "(buffer:capacity=$capacity,size=${size.value})"
}
diff --git a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
index e487a53431..318283cca9 100644
--- a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
index 2981d8394e..312480f943 100644
--- a/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("FunctionName")
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index 07e05f07d9..8dff4ec2b7 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("FunctionName")
@@ -586,4 +586,4 @@ public class ClosedSendChannelException(message: String?) : IllegalStateExceptio
*
* This exception is a subclass of [NoSuchElementException] to be consistent with plain collections.
*/
-public class ClosedReceiveChannelException(message: String?) : NoSuchElementException(message)
\ No newline at end of file
+public class ClosedReceiveChannelException(message: String?) : NoSuchElementException(message)
diff --git a/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt b/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
index f824e69f8d..3f53b48c53 100644
--- a/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
index cd37bfbc2e..4a73d5d59d 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@file:JvmName("ChannelsKt")
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
index a3e72a9c1b..4990c933ec 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -10,6 +10,7 @@ import kotlinx.coroutines.internal.*
import kotlinx.coroutines.intrinsics.*
import kotlinx.coroutines.selects.*
import kotlin.jvm.*
+import kotlin.native.concurrent.*
/**
* Broadcasts the most recently sent element (aka [value]) to all [openSubscription] subscribers.
@@ -90,7 +91,7 @@ public class ConflatedBroadcastChannel() : BroadcastChannel {
*/
public val valueOrNull: E? get() = when (val state = _state.value) {
is Closed -> null
- is State<*> -> UNDEFINED.unbox(state.value)
+ is State<*> -> UNDEFINED.unbox(state.value)
else -> error("Invalid state $state")
}
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
index c04ccc4c39..399019c3ee 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
@@ -1,94 +1,140 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
-import kotlinx.coroutines.selects.*
+import kotlinx.coroutines.*
import kotlinx.coroutines.internal.*
+import kotlinx.coroutines.selects.*
+import kotlin.native.concurrent.*
/**
* Channel that buffers at most one element and conflates all subsequent `send` and `offer` invocations,
* so that the receiver always gets the most recently sent element.
- * Back-to-send sent elements are _conflated_ -- only the the most recently sent element is received,
+ * Back-to-send sent elements are _conflated_ -- only the most recently sent element is received,
* while previously sent elements **are lost**.
* Sender to this channel never suspends and [offer] always returns `true`.
*
* This channel is created by `Channel(Channel.CONFLATED)` factory function invocation.
- *
- * This implementation is fully lock-free.
*/
internal open class ConflatedChannel : AbstractChannel() {
- protected final override val isBufferAlwaysEmpty: Boolean get() = true
- protected final override val isBufferEmpty: Boolean get() = true
+ protected final override val isBufferAlwaysEmpty: Boolean get() = false
+ protected final override val isBufferEmpty: Boolean get() = value === EMPTY
protected final override val isBufferAlwaysFull: Boolean get() = false
protected final override val isBufferFull: Boolean get() = false
- override fun onClosedIdempotent(closed: LockFreeLinkedListNode) {
- @Suppress("UNCHECKED_CAST")
- (closed.prevNode as? SendBuffered)?.let { lastBuffered ->
- conflatePreviousSendBuffered(lastBuffered)
- }
- }
+ override val isEmpty: Boolean get() = lock.withLock { isEmptyImpl }
- /**
- * Queues conflated element, returns null on success or
- * returns node reference if it was already closed or is waiting for receive.
- */
- private fun sendConflated(element: E): ReceiveOrClosed<*>? {
- val node = SendBuffered(element)
- queue.addLastIfPrev(node) { prev ->
- if (prev is ReceiveOrClosed<*>) return@sendConflated prev
- true
- }
- conflatePreviousSendBuffered(node)
- return null
+ private val lock = ReentrantLock()
+
+ private var value: Any? = EMPTY
+
+ private companion object {
+ @SharedImmutable
+ private val EMPTY = Symbol("EMPTY")
}
- private fun conflatePreviousSendBuffered(node: SendBuffered) {
- // Conflate all previous SendBuffered, helping other sends to conflate
- var prev = node.prevNode
- while (prev is SendBuffered<*>) {
- if (!prev.remove()) {
- prev.helpRemove()
+ // result is `OFFER_SUCCESS | Closed`
+ protected override fun offerInternal(element: E): Any {
+ var receive: ReceiveOrClosed? = null
+ lock.withLock {
+ closedForSend?.let { return it }
+ // if there is no element written in buffer
+ if (value === EMPTY) {
+ // check for receivers that were waiting on the empty buffer
+ loop@ while(true) {
+ receive = takeFirstReceiveOrPeekClosed() ?: break@loop // break when no receivers queued
+ if (receive is Closed) {
+ return receive!!
+ }
+ val token = receive!!.tryResumeReceive(element, null)
+ if (token != null) {
+ assert { token === RESUME_TOKEN }
+ return@withLock
+ }
+ }
}
- prev = prev.prevNode
+ value = element
+ return OFFER_SUCCESS
}
+ // breaks here if offer meets receiver
+ receive!!.completeResumeReceive(element)
+ return receive!!.offerResult
}
- // result is always `OFFER_SUCCESS | Closed`
- protected override fun offerInternal(element: E): Any {
- while (true) {
- val result = super.offerInternal(element)
- when {
- result === OFFER_SUCCESS -> return OFFER_SUCCESS
- result === OFFER_FAILED -> { // try to buffer
- when (val sendResult = sendConflated(element)) {
- null -> return OFFER_SUCCESS
- is Closed<*> -> return sendResult
+ // result is `ALREADY_SELECTED | OFFER_SUCCESS | Closed`
+ protected override fun offerSelectInternal(element: E, select: SelectInstance<*>): Any {
+ var receive: ReceiveOrClosed? = null
+ lock.withLock {
+ closedForSend?.let { return it }
+ if (value === EMPTY) {
+ loop@ while(true) {
+ val offerOp = describeTryOffer(element)
+ val failure = select.performAtomicTrySelect(offerOp)
+ when {
+ failure == null -> { // offered successfully
+ receive = offerOp.result
+ return@withLock
+ }
+ failure === OFFER_FAILED -> break@loop // cannot offer -> Ok to queue to buffer
+ failure === RETRY_ATOMIC -> {} // retry
+ failure === ALREADY_SELECTED || failure is Closed<*> -> return failure
+ else -> error("performAtomicTrySelect(describeTryOffer) returned $failure")
}
- // otherwise there was receiver in queue, retry super.offerInternal
}
- result is Closed<*> -> return result
- else -> error("Invalid offerInternal result $result")
}
+ // try to select sending this element to buffer
+ if (!select.trySelect()) {
+ return ALREADY_SELECTED
+ }
+ value = element
+ return OFFER_SUCCESS
}
+ // breaks here if offer meets receiver
+ receive!!.completeResumeReceive(element)
+ return receive!!.offerResult
}
- // result is always `ALREADY_SELECTED | OFFER_SUCCESS | Closed`.
- protected override fun offerSelectInternal(element: E, select: SelectInstance<*>): Any {
- while (true) {
- val result = if (hasReceiveOrClosed)
- super.offerSelectInternal(element, select) else
- (select.performAtomicTrySelect(describeSendConflated(element)) ?: OFFER_SUCCESS)
- when {
- result === ALREADY_SELECTED -> return ALREADY_SELECTED
- result === OFFER_SUCCESS -> return OFFER_SUCCESS
- result === OFFER_FAILED -> {} // retry
- result === RETRY_ATOMIC -> {} // retry
- result is Closed<*> -> return result
- else -> error("Invalid result $result")
+ // result is `E | POLL_FAILED | Closed`
+ protected override fun pollInternal(): Any? {
+ var result: Any? = null
+ lock.withLock {
+ if (value === EMPTY) return closedForSend ?: POLL_FAILED
+ result = value
+ value = EMPTY
+ }
+ return result
+ }
+
+ // result is `E | POLL_FAILED | Closed`
+ protected override fun pollSelectInternal(select: SelectInstance<*>): Any? {
+ var result: Any? = null
+ lock.withLock {
+ if (value === EMPTY) return closedForSend ?: POLL_FAILED
+ if (!select.trySelect())
+ return ALREADY_SELECTED
+ result = value
+ value = EMPTY
+ }
+ return result
+ }
+
+ protected override fun onCancelIdempotent(wasClosed: Boolean) {
+ if (wasClosed) {
+ lock.withLock {
+ value = EMPTY
}
}
+ super.onCancelIdempotent(wasClosed)
+ }
+
+ override fun enqueueReceiveInternal(receive: Receive): Boolean = lock.withLock {
+ super.enqueueReceiveInternal(receive)
}
+
+ // ------ debug ------
+
+ override val bufferDebugString: String
+ get() = "(value=$value)"
}
diff --git a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
index d925be1c50..e66bbb2279 100644
--- a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/Produce.kt b/kotlinx-coroutines-core/common/src/channels/Produce.kt
index 68fb09a41c..24fd399bb7 100644
--- a/kotlinx-coroutines-core/common/src/channels/Produce.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Produce.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -27,7 +27,7 @@ public interface ProducerScope : CoroutineScope, SendChannel {
/**
* Suspends the current coroutine until the channel is either [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel]
- * and invokes the given [block] before resuming the coroutine.
+ * and invokes the given [block] before resuming the coroutine. This suspending function is cancellable.
*
* Note that when the producer channel is cancelled, this function resumes with a cancellation exception.
* Therefore, in case of cancellation, no code after the call to this function will be executed.
@@ -115,6 +115,7 @@ public fun CoroutineScope.produce(
public fun CoroutineScope.produce(
context: CoroutineContext = EmptyCoroutineContext,
capacity: Int = 0,
+ start: CoroutineStart = CoroutineStart.DEFAULT,
onCompletion: CompletionHandler? = null,
@BuilderInference block: suspend ProducerScope.() -> Unit
): ReceiveChannel {
@@ -122,7 +123,7 @@ public fun CoroutineScope.produce(
val newContext = newCoroutineContext(context)
val coroutine = ProducerCoroutine(newContext, channel)
if (onCompletion != null) coroutine.invokeOnCompletion(handler = onCompletion)
- coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
+ coroutine.start(start, coroutine, block)
return coroutine
}
diff --git a/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt b/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
index 98df176937..700f50908c 100644
--- a/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/flow/Builders.kt b/kotlinx-coroutines-core/common/src/flow/Builders.kt
index 49ad2922e9..4157576aae 100644
--- a/kotlinx-coroutines-core/common/src/flow/Builders.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Builders.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -11,9 +11,9 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
import kotlinx.coroutines.flow.internal.*
-import kotlinx.coroutines.flow.internal.unsafeFlow as flow
import kotlin.coroutines.*
import kotlin.jvm.*
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
/**
* Creates a flow from the given suspendable [block].
@@ -51,7 +51,12 @@ public fun flow(@BuilderInference block: suspend FlowCollector.() -> Unit
// Named anonymous object
private class SafeFlow(private val block: suspend FlowCollector.() -> Unit) : Flow {
override suspend fun collect(collector: FlowCollector) {
- SafeCollector(collector, coroutineContext).block()
+ val safeCollector = SafeCollector(collector, coroutineContext)
+ try {
+ safeCollector.block()
+ } finally {
+ safeCollector.releaseIntercepted()
+ }
}
}
@@ -259,10 +264,16 @@ public fun channelFlow(@BuilderInference block: suspend ProducerScope.()
*
* This builder ensures thread-safety and context preservation, thus the provided [ProducerScope] can be used
* from any context, e.g. from a callback-based API.
- * The resulting flow completes as soon as the code in the [block] and all its children completes.
- * Use [awaitClose] as the last statement to keep it running.
- * The [awaitClose] argument is called either when a flow consumer cancels the flow collection
- * or when a callback-based API invokes [SendChannel.close] manually.
+ * The resulting flow completes as soon as the code in the [block] completes.
+ * [awaitClose] should be used to keep the flow running, otherwise the channel will be closed immediately
+ * when block completes.
+ * [awaitClose] argument is called either when a flow consumer cancels the flow collection
+ * or when a callback-based API invokes [SendChannel.close] manually and is typically used
+ * to cleanup the resources after the completion, e.g. unregister a callback.
+ * Using [awaitClose] is mandatory in order to prevent memory leaks when the flow collection is cancelled,
+ * otherwise the callback may keep running even when the flow collector is already completed.
+ * To avoid such leaks, this method throws [IllegalStateException] if block returns, but the channel
+ * is not closed yet.
*
* A channel with the [default][Channel.BUFFERED] buffer size is used. Use the [buffer] operator on the
* resulting flow to specify a user-defined value and to control what happens when data is produced faster
@@ -277,9 +288,13 @@ public fun channelFlow(@BuilderInference block: suspend ProducerScope.()
* fun flowFrom(api: CallbackBasedApi): Flow = callbackFlow {
* val callback = object : Callback { // implementation of some callback interface
* override fun onNextValue(value: T) {
- * // Note: offer drops value when buffer is full
- * // Use either buffer(Channel.CONFLATED) or buffer(Channel.UNLIMITED) to avoid overfill
- * offer(value)
+ * // To avoid blocking you can configure channel capacity using
+ * // either buffer(Channel.CONFLATED) or buffer(Channel.UNLIMITED) to avoid overfill
+ * try {
+ * sendBlocking(value)
+ * } catch (e: Exception) {
+ * // Handle exception from the channel: failure in flow or premature closing
+ * }
* }
* override fun onApiError(cause: Throwable) {
* cancel(CancellationException("API Error", cause))
@@ -287,21 +302,20 @@ public fun channelFlow(@BuilderInference block: suspend ProducerScope.()
* override fun onCompleted() = channel.close()
* }
* api.register(callback)
- * // Suspend until either onCompleted or external cancellation are invoked
+ * /*
+ * * Suspends until either 'onCompleted'/'onApiError' from the callback is invoked
+ * * or flow collector is cancelled (e.g. by 'take(1)' or because a collector's coroutine was cancelled).
+ * * In both cases, callback will be properly unregistered.
+ * */
* awaitClose { api.unregister(callback) }
* }
* ```
- *
- * This function is an alias for [channelFlow], it has a separate name to reflect
- * the intent of the usage (integration with a callback-based API) better.
*/
-@Suppress("NOTHING_TO_INLINE")
@ExperimentalCoroutinesApi
-public inline fun callbackFlow(@BuilderInference noinline block: suspend ProducerScope.() -> Unit): Flow =
- channelFlow(block)
+public fun callbackFlow(@BuilderInference block: suspend ProducerScope.() -> Unit): Flow = CallbackFlowBuilder(block)
// ChannelFlow implementation that is the first in the chain of flow operations and introduces (builds) a flow
-private class ChannelFlowBuilder(
+private open class ChannelFlowBuilder(
private val block: suspend ProducerScope.() -> Unit,
context: CoroutineContext = EmptyCoroutineContext,
capacity: Int = BUFFERED
@@ -315,3 +329,31 @@ private class ChannelFlowBuilder(
override fun toString(): String =
"block[$block] -> ${super.toString()}"
}
+
+private class CallbackFlowBuilder(
+ private val block: suspend ProducerScope.() -> Unit,
+ context: CoroutineContext = EmptyCoroutineContext,
+ capacity: Int = BUFFERED
+) : ChannelFlowBuilder(block, context, capacity) {
+
+ override suspend fun collectTo(scope: ProducerScope) {
+ super.collectTo(scope)
+ /*
+ * We expect user either call `awaitClose` from within a block (then the channel is closed at this moment)
+ * or being closed/cancelled externally/manually. Otherwise "user forgot to call
+ * awaitClose and receives unhelpful ClosedSendChannelException exceptions" situation is detected.
+ */
+ if (!scope.isClosedForSend) {
+ throw IllegalStateException(
+ """
+ 'awaitClose { yourCallbackOrListener.cancel() }' should be used in the end of callbackFlow block.
+ Otherwise, a callback/listener may leak in case of external cancellation.
+ See callbackFlow API documentation for the details.
+ """.trimIndent()
+ )
+ }
+ }
+
+ override fun create(context: CoroutineContext, capacity: Int): ChannelFlow =
+ CallbackFlowBuilder(block, context, capacity)
+}
diff --git a/kotlinx-coroutines-core/common/src/flow/Channels.kt b/kotlinx-coroutines-core/common/src/flow/Channels.kt
index 1a572e8582..e3a64b9568 100644
--- a/kotlinx-coroutines-core/common/src/flow/Channels.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Channels.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -23,8 +23,11 @@ import kotlinx.coroutines.flow.internal.unsafeFlow as flow
* This function provides a more efficient shorthand for `channel.consumeEach { value -> emit(value) }`.
* See [consumeEach][ReceiveChannel.consumeEach].
*/
-@ExperimentalCoroutinesApi
-public suspend fun FlowCollector.emitAll(channel: ReceiveChannel) {
+@ExperimentalCoroutinesApi // since version 1.3.0
+public suspend fun FlowCollector.emitAll(channel: ReceiveChannel) =
+ emitAllImpl(channel, consume = true)
+
+private suspend fun FlowCollector.emitAllImpl(channel: ReceiveChannel, consume: Boolean) {
// Manually inlined "consumeEach" implementation that does not use iterator but works via "receiveOrClosed".
// It has smaller and more efficient spilled state which also allows to implement a manual kludge to
// fix retention of the last emitted value.
@@ -59,20 +62,43 @@ public suspend fun FlowCollector.emitAll(channel: ReceiveChannel) {
cause = e
throw e
} finally {
- channel.cancelConsumed(cause)
+ if (consume) channel.cancelConsumed(cause)
}
}
+/**
+ * Represents the given receive channel as a hot flow and [receives][ReceiveChannel.receive] from the channel
+ * in fan-out fashion every time this flow is collected. One element will be emitted to one collector only.
+ *
+ * See also [consumeAsFlow] which ensures that the resulting flow is collected just once.
+ *
+ * ### Cancellation semantics
+ *
+ * * Flow collectors are cancelled when the original channel is [closed][SendChannel.close] with an exception.
+ * * Flow collectors complete normally when the original channel is [closed][SendChannel.close] normally.
+ * * Failure or cancellation of the flow collector does not affect the channel.
+ *
+ * ### Operator fusion
+ *
+ * Adjacent applications of [flowOn], [buffer], [conflate], and [produceIn] to the result of `receiveAsFlow` are fused.
+ * In particular, [produceIn] returns the original channel.
+ * Calls to [flowOn] have generally no effect, unless [buffer] is used to explicitly request buffering.
+ */
+@ExperimentalCoroutinesApi // since version 1.4.0
+public fun ReceiveChannel.receiveAsFlow(): Flow = ChannelAsFlow(this, consume = false)
+
/**
* Represents the given receive channel as a hot flow and [consumes][ReceiveChannel.consume] the channel
* on the first collection from this flow. The resulting flow can be collected just once and throws
* [IllegalStateException] when trying to collect it more than once.
*
+ * See also [receiveAsFlow] which supports multiple collectors of the resulting flow.
+ *
* ### Cancellation semantics
*
- * 1) Flow consumer is cancelled when the original channel is cancelled.
- * 2) Flow consumer completes normally when the original channel was closed normally and then fully consumed.
- * 3) If the flow consumer fails with an exception, channel is cancelled.
+ * * Flow collector is cancelled when the original channel is [closed][SendChannel.close] with an exception.
+ * * Flow collector completes normally when the original channel is [closed][SendChannel.close] normally.
+ * * If the flow collector fails with an exception, the source channel is [cancelled][ReceiveChannel.cancel].
*
* ### Operator fusion
*
@@ -80,8 +106,8 @@ public suspend fun FlowCollector.emitAll(channel: ReceiveChannel) {
* In particular, [produceIn] returns the original channel (but throws [IllegalStateException] on repeated calls).
* Calls to [flowOn] have generally no effect, unless [buffer] is used to explicitly request buffering.
*/
-@FlowPreview
-public fun ReceiveChannel.consumeAsFlow(): Flow = ConsumeAsFlow(this)
+@ExperimentalCoroutinesApi // since version 1.3.0
+public fun ReceiveChannel.consumeAsFlow(): Flow = ChannelAsFlow(this, consume = true)
/**
* Represents an existing [channel] as [ChannelFlow] implementation.
@@ -89,21 +115,25 @@ public fun ReceiveChannel.consumeAsFlow(): Flow = ConsumeAsFlow(this)
* However, additional [buffer] calls cause a separate buffering channel to be created and that is where
* the context might play a role, because it is used by the producing coroutine.
*/
-private class ConsumeAsFlow(
+private class ChannelAsFlow(
private val channel: ReceiveChannel,
+ private val consume: Boolean,
context: CoroutineContext = EmptyCoroutineContext,
capacity: Int = Channel.OPTIONAL_CHANNEL
) : ChannelFlow(context, capacity) {
private val consumed = atomic(false)
- private fun markConsumed() =
- check(!consumed.getAndSet(true)) { "ReceiveChannel.consumeAsFlow can be collected just once" }
+ private fun markConsumed() {
+ if (consume) {
+ check(!consumed.getAndSet(true)) { "ReceiveChannel.consumeAsFlow can be collected just once" }
+ }
+ }
override fun create(context: CoroutineContext, capacity: Int): ChannelFlow =
- ConsumeAsFlow(channel, context, capacity)
+ ChannelAsFlow(channel, consume, context, capacity)
override suspend fun collectTo(scope: ProducerScope) =
- SendingCollector(scope).emitAll(channel) // use efficient channel receiving code from emitAll
+ SendingCollector(scope).emitAllImpl(channel, consume) // use efficient channel receiving code from emitAll
override fun broadcastImpl(scope: CoroutineScope, start: CoroutineStart): BroadcastChannel {
markConsumed() // fail fast on repeated attempt to collect it
@@ -121,7 +151,7 @@ private class ConsumeAsFlow(
override suspend fun collect(collector: FlowCollector) {
if (capacity == Channel.OPTIONAL_CHANNEL) {
markConsumed()
- collector.emitAll(channel) // direct
+ collector.emitAllImpl(channel, consume) // direct
} else {
super.collect(collector) // extra buffering channel, produceImpl will mark it as consumed
}
@@ -151,7 +181,7 @@ public fun BroadcastChannel