Adjust Gradle configuration and introduce allWarningsAsErrors (#3466)

* Also, add tests that verify our disabled assertions
* Fix nullability in AgentPremain that used to work by accident (because we disabled those assertions)
* Fix all corresponding warnings


Co-authored-by: Dmitry Khalanskiy <Dmitry.Khalanskiy@jetbrains.com>
diff --git a/build.gradle b/build.gradle
index 59c2889..d5b231d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -168,18 +168,7 @@
 apply plugin: "bom-conventions"
 
 // 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(AbstractKotlinCompile).all {
-        kotlinOptions.freeCompilerArgs += OptInPreset.optInAnnotations.collect { "-Xopt-in=" + it }
-        kotlinOptions.freeCompilerArgs += "-progressive"
-        // Remove null assertions to get smaller bytecode on Android
-        kotlinOptions.freeCompilerArgs += ["-Xno-param-assertions", "-Xno-receiver-assertions", "-Xno-call-assertions"]
-    }
-}
+apply plugin: "configure-compilation-conventions"
 
 if (build_snapshot_train) {
     println "Hacking test tasks, removing stress and flaky tests"
diff --git a/buildSrc/src/main/kotlin/configure-compilation-conventions.gradle.kts b/buildSrc/src/main/kotlin/configure-compilation-conventions.gradle.kts
new file mode 100644
index 0000000..1c3f486
--- /dev/null
+++ b/buildSrc/src/main/kotlin/configure-compilation-conventions.gradle.kts
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.kotlin.gradle.tasks.*
+
+configure(subprojects) {
+    if (name in sourceless) return@configure
+    apply(plugin = "kotlinx-atomicfu")
+    val projectName = name
+    tasks.withType(KotlinCompile::class).all {
+        val isMainTaskName = name == "compileKotlin" || name == "compileKotlinJvm"
+        kotlinOptions {
+            if (isMainTaskName) {
+                allWarningsAsErrors = true
+            }
+            val newOptions =
+                listOf(
+                    "-progressive", "-Xno-param-assertions", "-Xno-receiver-assertions",
+                    "-Xno-call-assertions"
+                ) + optInAnnotations.map { "-opt-in=$it" }
+            freeCompilerArgs = freeCompilerArgs + newOptions
+        }
+    }
+}
diff --git a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
index 0fe0748..2f2fe50 100644
--- a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
@@ -2,6 +2,8 @@
  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER")
+
 package kotlinx.coroutines.channels
 
 import kotlinx.atomicfu.*
@@ -16,6 +18,7 @@
 /**
  * Abstract send channel. It is a base class for all send channel implementations.
  */
+@Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER")
 internal abstract class AbstractSendChannel<E>(
     @JvmField protected val onUndeliveredElement: OnUndeliveredElement<E>?
 ) : SendChannel<E> {
@@ -122,7 +125,12 @@
         return sendSuspend(element)
     }
 
-    @Suppress("DEPRECATION", "DEPRECATION_ERROR")
+    @Suppress("DEPRECATION_ERROR")
+    @Deprecated(
+        level = DeprecationLevel.ERROR,
+        message = "Deprecated in the favour of 'trySend' method",
+        replaceWith = ReplaceWith("trySend(element).isSuccess")
+    ) // see super()
     override fun offer(element: E): Boolean {
         // Temporary migration for offer users who rely on onUndeliveredElement
         try {
@@ -705,6 +713,11 @@
             onCancellationConstructor = onUndeliveredElementReceiveCancellationConstructor
         )
 
+    @Deprecated(
+        message = "Deprecated in favor of onReceiveCatching extension",
+        level = DeprecationLevel.ERROR,
+        replaceWith = ReplaceWith("onReceiveCatching")
+    ) // See super()
     override val onReceiveOrNull: SelectClause1<E?>
         get() = SelectClause1Impl<E?>(
             clauseObject = this,
@@ -726,7 +739,7 @@
         if (selectResult is Closed<*>) throw selectResult.receiveException
         else selectResult as E
 
-    private fun processResultSelectReceiveCatching(ignoredParam: Any?, selectResult: Any?): Any? =
+    private fun processResultSelectReceiveCatching(ignoredParam: Any?, selectResult: Any?): Any =
         if (selectResult is Closed<*>) ChannelResult.closed(selectResult.closeCause)
         else ChannelResult.success(selectResult as E)
 
@@ -735,8 +748,8 @@
         else selectResult as E
 
     private val onUndeliveredElementReceiveCancellationConstructor: OnCancellationConstructor? = onUndeliveredElement?.let {
-        { select: SelectInstance<*>, ignoredParam: Any?, element: Any? ->
-            { cause: Throwable -> if (element !is Closed<*>) onUndeliveredElement.callUndeliveredElement(element as E, select.context) }
+        { select: SelectInstance<*>, _: Any?, element: Any? ->
+            { _: Throwable -> if (element !is Closed<*>) onUndeliveredElement.callUndeliveredElement(element as E, select.context) }
         }
     }
 
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
index 93f99cf..abf18ac 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
@@ -158,9 +158,10 @@
                     // Too late, already cancelled, but we removed it from the queue and need to notify on undelivered element.
                     // The only exception is when this "send" operation is an `onSend` clause that has to be re-registered
                     // in the corresponding `select` invocation.
-                    val send = send!!
-                    if (!(send is SendElementSelectWithUndeliveredHandler<*> && send.trySelectResult == REREGISTER))
-                        send.undeliveredElement()
+                    send!!.apply {
+                        if (!(this is SendElementSelectWithUndeliveredHandler<*> && trySelectResult == REREGISTER))
+                            undeliveredElement()
+                    }
                 }
             }
             if (replacement !== POLL_FAILED && replacement !is Closed<*>) {
diff --git a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
index b1c24b4..ba39d4f 100644
--- a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
@@ -47,10 +47,11 @@
     start: CoroutineStart = CoroutineStart.LAZY
 ): BroadcastChannel<E> {
     val scope = GlobalScope + Dispatchers.Unconfined + CoroutineExceptionHandler { _, _ -> }
+    val channel = this
     // We can run this coroutine in the context that ignores all exceptions, because of `onCompletion = consume()`
     // which passes all exceptions upstream to the source ReceiveChannel
     return scope.broadcast(capacity = capacity, start = start, onCompletion = { cancelConsumed(it) }) {
-        for (e in this@broadcast) {
+        for (e in channel) {
             send(e)
         }
     }
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index 5ceb515..51c0214 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -360,6 +360,7 @@
      *
      * @suppress **Deprecated**: in favor of onReceiveCatching extension.
      */
+    @Suppress("DEPRECATION_ERROR")
     @Deprecated(
         message = "Deprecated in favor of onReceiveCatching extension",
         level = DeprecationLevel.ERROR,
diff --git a/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt b/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
index bb2bbf6..c196147 100644
--- a/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
+++ b/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
@@ -207,6 +207,7 @@
 
     // We inline it to save an entry on the stack in cases where it shows (unconfined dispatcher)
     // It is used only in Continuation<T>.resumeCancellableWith
+    @Suppress("NOTHING_TO_INLINE")
     inline fun resumeCancellableWith(
         result: Result<T>,
         noinline onCancellation: ((cause: Throwable) -> Unit)?
@@ -235,7 +236,7 @@
     }
 
     // inline here is to save us an entry on the stack for the sake of better stacktraces
-
+    @Suppress("NOTHING_TO_INLINE")
     inline fun resumeCancelled(state: Any?): Boolean {
         val job = context[Job]
         if (job != null && !job.isActive) {
@@ -247,6 +248,7 @@
         return false
     }
 
+    @Suppress("NOTHING_TO_INLINE")
     inline fun resumeUndispatchedWith(result: Result<T>) {
         withContinuationContext(continuation, countOrElement) {
             continuation.resumeWith(result)
diff --git a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
index d982f95..1de1bff 100644
--- a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
+++ b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
@@ -167,7 +167,6 @@
     }
 }
 
-@Suppress("UNCHECKED_CAST")
 internal fun <T> DispatchedTask<T>.resume(delegate: Continuation<T>, undispatched: Boolean) {
     // This resume is never cancellable. The result is always delivered to delegate continuation.
     val state = takeState()
diff --git a/kotlinx-coroutines-core/jvm/src/channels/Actor.kt b/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
index 76d8aae..e8a9152 100644
--- a/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
+++ b/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
@@ -162,7 +162,12 @@
         return super.send(element)
     }
 
-    @Suppress("DEPRECATION", "DEPRECATION_ERROR")
+    @Suppress("DEPRECATION_ERROR")
+    @Deprecated(
+        level = DeprecationLevel.ERROR,
+        message = "Deprecated in the favour of 'trySend' method",
+        replaceWith = ReplaceWith("trySend(element).isSuccess")
+    ) // See super()
     override fun offer(element: E): Boolean {
         start()
         return super.offer(element)
@@ -181,6 +186,7 @@
         return closed
     }
 
+    @Suppress("UNCHECKED_CAST")
     override val onSend: SelectClause2<E, SendChannel<E>> get() = SelectClause2Impl(
         clauseObject = this,
         regFunc = LazyActorCoroutine<*>::onSendRegFunction as RegistrationFunction,
diff --git a/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt b/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
index 4b0ce3f..fb5c5b1 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
@@ -26,6 +26,7 @@
     }.getOrNull() ?: DebugProbesImpl.enableCreationStackTraces
 
     @JvmStatic
+    @Suppress("UNUSED_PARAMETER")
     fun premain(args: String?, instrumentation: Instrumentation) {
         AgentInstallationType.isInstalledStatically = true
         instrumentation.addTransformer(DebugProbesTransformer)
@@ -36,13 +37,13 @@
 
     internal object DebugProbesTransformer : ClassFileTransformer {
         override fun transform(
-            loader: ClassLoader,
+            loader: ClassLoader?,
             className: String,
             classBeingRedefined: Class<*>?,
             protectionDomain: ProtectionDomain,
             classfileBuffer: ByteArray?
         ): ByteArray? {
-            if (className != "kotlin/coroutines/jvm/internal/DebugProbesKt") {
+            if (loader == null || className != "kotlin/coroutines/jvm/internal/DebugProbesKt") {
                return null
             }
             /*
diff --git a/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt b/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
index e87952b..0c55d92 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
@@ -98,9 +98,6 @@
     override fun limitedParallelism(parallelism: Int): CoroutineDispatcher =
         missing()
 
-    override suspend fun delay(time: Long) =
-        missing()
-
     override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle =
         missing()
 
diff --git a/kotlinx-coroutines-core/jvm/test/NoParamAssertionsTest.kt b/kotlinx-coroutines-core/jvm/test/NoParamAssertionsTest.kt
new file mode 100644
index 0000000..5e1c462
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/test/NoParamAssertionsTest.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+package kotlinx.coroutines
+
+import kotlinx.coroutines.*
+import org.junit.Test
+import kotlin.test.*
+
+
+class NoParamAssertionsTest : TestBase() {
+    // These tests verify that we haven't omitted "-Xno-param-assertions" and "-Xno-receiver-assertions"
+
+    @Test
+    fun testNoReceiverAssertion() {
+        val function: (ThreadLocal<Int>, Int) -> ThreadContextElement<Int> = ThreadLocal<Int>::asContextElement
+        @Suppress("UNCHECKED_CAST")
+        val unsafeCasted = function as ((ThreadLocal<Int>?, Int) -> ThreadContextElement<Int>)
+        unsafeCasted(null, 42)
+    }
+
+    @Test
+    fun testNoParamAssertion() {
+        val function: (ThreadLocal<Any>, Any) -> ThreadContextElement<Any> = ThreadLocal<Any>::asContextElement
+        @Suppress("UNCHECKED_CAST")
+        val unsafeCasted = function as ((ThreadLocal<Any?>?, Any?) -> ThreadContextElement<Any>)
+        unsafeCasted(ThreadLocal.withInitial { Any() }, null)
+    }
+}
diff --git a/kotlinx-coroutines-test/common/src/TestCoroutineScheduler.kt b/kotlinx-coroutines-test/common/src/TestCoroutineScheduler.kt
index e735c6d..5f7198c 100644
--- a/kotlinx-coroutines-test/common/src/TestCoroutineScheduler.kt
+++ b/kotlinx-coroutines-test/common/src/TestCoroutineScheduler.kt
@@ -97,7 +97,7 @@
             currentTime = event.time
             event
         }
-        event.dispatcher.processEvent(event.time, event.marker)
+        event.dispatcher.processEvent(event.marker)
         return true
     }
 
@@ -132,7 +132,7 @@
             val event = synchronized(lock) {
                 events.removeFirstIf { it.time <= timeMark } ?: return
             }
-            event.dispatcher.processEvent(event.time, event.marker)
+            event.dispatcher.processEvent(event.marker)
         }
     }
 
@@ -173,7 +173,7 @@
                     }
                 }
             }
-            event.dispatcher.processEvent(event.time, event.marker)
+            event.dispatcher.processEvent(event.marker)
         }
     }
 
diff --git a/kotlinx-coroutines-test/common/src/TestDispatcher.kt b/kotlinx-coroutines-test/common/src/TestDispatcher.kt
index 9616bb0..8ed8192 100644
--- a/kotlinx-coroutines-test/common/src/TestDispatcher.kt
+++ b/kotlinx-coroutines-test/common/src/TestDispatcher.kt
@@ -23,7 +23,7 @@
     public abstract val scheduler: TestCoroutineScheduler
 
     /** Notifies the dispatcher that it should process a single event marked with [marker] happening at time [time]. */
-    internal fun processEvent(time: Long, marker: Any) {
+    internal fun processEvent(marker: Any) {
         check(marker is Runnable)
         marker.run()
     }
diff --git a/kotlinx-coroutines-test/jvm/src/migration/TestBuildersDeprecated.kt b/kotlinx-coroutines-test/jvm/src/migration/TestBuildersDeprecated.kt
index eabdffb..35d237a 100644
--- a/kotlinx-coroutines-test/jvm/src/migration/TestBuildersDeprecated.kt
+++ b/kotlinx-coroutines-test/jvm/src/migration/TestBuildersDeprecated.kt
@@ -159,7 +159,7 @@
     context: CoroutineContext = EmptyCoroutineContext,
     dispatchTimeoutMs: Long = DEFAULT_DISPATCH_TIMEOUT_MS,
     testBody: suspend TestCoroutineScope.() -> Unit
-): TestResult {
+) {
     if (context[RunningInRunTest] != null)
         throw IllegalStateException("Calls to `runTest` can't be nested. Please read the docs on `TestResult` for details.")
     val testScope = TestBodyCoroutine(createTestCoroutineScope(context + RunningInRunTest))
diff --git a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineDispatcher.kt b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineDispatcher.kt
index 08f428f..40a0f5d 100644
--- a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineDispatcher.kt
+++ b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineDispatcher.kt
@@ -61,6 +61,10 @@
         scheduler.registerEvent(this, 0, block, context) { false }
 
     /** @suppress */
+    @Deprecated(
+        "Please use a dispatcher that is paused by default, like `StandardTestDispatcher`.",
+        level = DeprecationLevel.WARNING
+    )
     override suspend fun pauseDispatcher(block: suspend () -> Unit) {
         val previous = dispatchImmediately
         dispatchImmediately = false
@@ -72,11 +76,19 @@
     }
 
     /** @suppress */
+    @Deprecated(
+        "Please use a dispatcher that is paused by default, like `StandardTestDispatcher`.",
+        level = DeprecationLevel.WARNING
+    )
     override fun pauseDispatcher() {
         dispatchImmediately = false
     }
 
     /** @suppress */
+    @Deprecated(
+        "Please use a dispatcher that is paused by default, like `StandardTestDispatcher`.",
+        level = DeprecationLevel.WARNING
+    )
     override fun resumeDispatcher() {
         dispatchImmediately = true
     }
diff --git a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineExceptionHandler.kt b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineExceptionHandler.kt
index 9da521f..aeb0f35 100644
--- a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineExceptionHandler.kt
+++ b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineExceptionHandler.kt
@@ -42,6 +42,7 @@
 /**
  * An exception handler that captures uncaught exceptions in tests.
  */
+@Suppress("DEPRECATION")
 @Deprecated(
     "Deprecated for removal without a replacement. " +
         "It may be to define one's own `CoroutineExceptionHandler` if you just need to handle '" +
diff --git a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineScope.kt b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineScope.kt
index 4a2cbc5..5af83f5 100644
--- a/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineScope.kt
+++ b/kotlinx-coroutines-test/jvm/src/migration/TestCoroutineScope.kt
@@ -86,6 +86,7 @@
     /** These jobs existed before the coroutine scope was used, so it's alright if they don't get cancelled. */
     private val initialJobs = coroutineContext.activeJobs()
 
+    @Deprecated("Please call `runTest`, which automatically performs the cleanup, instead of using this function.")
     override fun cleanupTestCoroutines() {
         val delayController = coroutineContext.delayController
         val hasUnfinishedJobs = if (delayController != null) {
diff --git a/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt b/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
index 0fc743f..6a77bbf 100644
--- a/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
@@ -32,8 +32,7 @@
     private val flow: Flow<T>,
     private val context: CoroutineContext
 ) : Flux<T>() {
-    override fun subscribe(subscriber: CoreSubscriber<in T>?) {
-        if (subscriber == null) throw NullPointerException()
+    override fun subscribe(subscriber: CoreSubscriber<in T>) {
         val hasContext = !subscriber.currentContext().isEmpty
         val source = if (hasContext) flow.flowOn(subscriber.currentContext().asCoroutineContext()) else flow
         subscriber.onSubscribe(FlowSubscription(source, subscriber, context))
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt b/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
index 2e50481..39306e2 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
@@ -43,6 +43,7 @@
 ) : AbstractCoroutine<T>(parentContext, false, true) {
     override fun onCompleted(value: T) {
         try {
+            @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // KT-54201
             if (value == null) subscriber.onComplete() else subscriber.onSuccess(value)
         } catch (e: Throwable) {
             handleUndeliverableException(e, context)