Add build parameter to build coroutines with JVM IR compiler (#2389)

* Add build parameters to enable JVM IR and disable native targets
    * enable_jvm_ir enables JVM IR compiler
    * disable_native_targets disables native targets in train builds
    * enable_jvm_ir_api_check enables JVM IR API check (works only if enable_jvm_ir is set)

* Fix "Return type must be specified in explicit API mode" in 1.4.20
diff --git a/build.gradle b/build.gradle
index 79c7f35..938d42e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -33,6 +33,10 @@
             throw new IllegalArgumentException("'kotlin_snapshot_version' should be defined when building with snapshot compiler")
         }
     }
+    // These three flags are enabled in train builds for JVM IR compiler testing
+    ext.jvm_ir_enabled = rootProject.properties['enable_jvm_ir'] != null
+    ext.jvm_ir_api_check_enabled = rootProject.properties['enable_jvm_ir_api_check'] != null
+    ext.native_targets_enabled = rootProject.properties['disable_native_targets'] == null
 
     // Determine if any project dependency is using a snapshot version
     ext.using_snapshot_version = build_snapshot_train
@@ -323,3 +327,12 @@
 }
 
 knitPrepare.dependsOn getTasksByName("dokka", true)
+
+// Disable binary compatibility check for JVM IR compiler output by default
+if (jvm_ir_enabled) {
+    subprojects { project ->
+        configure(tasks.matching { it.name == "apiCheck" }) {
+            enabled = enabled && jvm_ir_api_check_enabled
+        }
+    }
+}
\ No newline at end of file
diff --git a/gradle/compile-jvm-multiplatform.gradle b/gradle/compile-jvm-multiplatform.gradle
index e72d305..44b0cbe 100644
--- a/gradle/compile-jvm-multiplatform.gradle
+++ b/gradle/compile-jvm-multiplatform.gradle
@@ -6,8 +6,12 @@
 targetCompatibility = 1.6
 
 kotlin {
-    targets {
-        fromPreset(presets.jvm, 'jvm')
+    jvm {
+        if (rootProject.ext.jvm_ir_enabled) {
+            compilations.all {
+                kotlinOptions.useIR = true
+            }
+        }
     }
     sourceSets {
         jvmTest.dependencies {
diff --git a/gradle/compile-jvm.gradle b/gradle/compile-jvm.gradle
index caa5c45..bd2ae14 100644
--- a/gradle/compile-jvm.gradle
+++ b/gradle/compile-jvm.gradle
@@ -9,6 +9,12 @@
 sourceCompatibility = 1.6
 targetCompatibility = 1.6
 
+if (rootProject.ext.jvm_ir_enabled) {
+    kotlin.target.compilations.all {
+        kotlinOptions.useIR = true
+    }
+}
+
 dependencies {
     testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
     // Workaround to make addSuppressed work in tests
diff --git a/kotlinx-coroutines-core/build.gradle b/kotlinx-coroutines-core/build.gradle
index f98f6a5..314eea3 100644
--- a/kotlinx-coroutines-core/build.gradle
+++ b/kotlinx-coroutines-core/build.gradle
@@ -5,8 +5,12 @@
 apply plugin: 'org.jetbrains.kotlin.multiplatform'
 apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
 apply from: rootProject.file("gradle/compile-common.gradle")
+
+if (rootProject.ext.native_targets_enabled) {
+    apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
+}
+
 apply from: rootProject.file("gradle/compile-js-multiplatform.gradle")
-apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
 apply from: rootProject.file('gradle/publish-npm-js.gradle')
 
 /* ==========================================================================
@@ -52,8 +56,11 @@
 static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } }
 
 defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] }
-defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
-defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
+
+if (rootProject.ext.native_targets_enabled) {
+    defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
+    defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
+}
 
 /* ========================================================================== */
 
@@ -129,7 +136,7 @@
 }
 
 // :KLUDGE: Idea.active: Configure platform libraries for native source sets when working in IDEA
-if (Idea.active) {
+if (Idea.active && rootProject.ext.native_targets_enabled) {
     def manager = project.ext.hostManager
     def linuxPreset = kotlin.presets.linuxX64
     def macosPreset = kotlin.presets.macosX64
@@ -183,6 +190,13 @@
         exclude '**/*StressTest.*'
     }
     systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test
+
+    // TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests
+    if (rootProject.ext.jvm_ir_enabled) {
+        filter {
+            excludeTestsMatching('kotlinx.coroutines.exceptions.StackTraceRecovery*')
+        }
+    }
 }
 
 jvmJar {
diff --git a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
index 1f4942a..caf87f1 100644
--- a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
+++ b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
@@ -23,7 +23,7 @@
  * **DO NOT CHANGE THE CONSTANT VALUE**. It is being into the user code from [suspendCancellableCoroutine].
  */
 @PublishedApi
-internal const val MODE_CANCELLABLE = 1
+internal const val MODE_CANCELLABLE: Int = 1
 
 /**
  * Cancellable dispatch mode for [suspendCancellableCoroutineReusable].
diff --git a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
index edcf123..d691c72 100644
--- a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
+++ b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
@@ -36,7 +36,7 @@
     val clauses = arrayListOf<() -> Unit>()
 
     @PublishedApi
-    internal fun handleBuilderException(e: Throwable) = instance.handleBuilderException(e)
+    internal fun handleBuilderException(e: Throwable): Unit = instance.handleBuilderException(e)
 
     @PublishedApi
     internal fun initSelectResult(): Any? {
diff --git a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
index 97f9978..d08f41b 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
@@ -11,13 +11,13 @@
 private typealias Node = LockFreeLinkedListNode
 
 @PublishedApi
-internal const val UNDECIDED = 0
+internal const val UNDECIDED: Int = 0
 
 @PublishedApi
-internal const val SUCCESS = 1
+internal const val SUCCESS: Int = 1
 
 @PublishedApi
-internal const val FAILURE = 2
+internal const val FAILURE: Int = 2
 
 @PublishedApi
 internal val CONDITION_FALSE: Any = Symbol("CONDITION_FALSE")
diff --git a/kotlinx-coroutines-debug/build.gradle b/kotlinx-coroutines-debug/build.gradle
index ab7f28c..2a11bbb 100644
--- a/kotlinx-coroutines-debug/build.gradle
+++ b/kotlinx-coroutines-debug/build.gradle
@@ -28,6 +28,16 @@
     api "net.java.dev.jna:jna-platform:$jna_version"
 }
 
+// TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests
+if (rootProject.ext.jvm_ir_enabled) {
+    tasks.named('test', Test) {
+        filter {
+//            excludeTest('kotlinx.coroutines.debug.CoroutinesDumpTest', 'testCreationStackTrace')
+            excludeTestsMatching('kotlinx.coroutines.debug.DebugProbesTest')
+        }
+    }
+}
+
 jar {
     manifest {
         attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain"