Skip to content

Commit 787e5d0

Browse files
committed
~fix empty input case that was covered by a different subset of tests
1 parent 7803aae commit 787e5d0

File tree

1 file changed

+8
-5
lines changed
  • kotlinx-coroutines-core/common/src/flow/internal

1 file changed

+8
-5
lines changed

kotlinx-coroutines-core/common/src/flow/internal/Combine.kt

+8-5
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import kotlinx.coroutines.internal.*
1212
import kotlin.coroutines.*
1313
import kotlin.coroutines.intrinsics.*
1414

15+
internal fun getNull(): Symbol = NULL // Workaround for JS BE bug
16+
1517
@PublishedApi
1618
internal suspend fun <R, T> FlowCollector<R>.combineInternal(
1719
flows: Array<out Flow<T>>,
1820
arrayFactory: () -> Array<T?>,
1921
transform: suspend FlowCollector<R>.(Array<T>) -> Unit
2022
): Unit = flowScope { // flow scope so any cancellation within the source flow will cancel the whole scope
2123
val size = flows.size
22-
val latestValues = Array<Any?>(size) { NULL }
24+
if (size == 0) return@flowScope // bail-out for empty input
25+
val latestValues = Array<Any?>(size) { getNull() }
2326
val isClosed = Array(size) { false }
2427
val resultChannel = Channel<Array<T>>(Channel.CONFLATED)
2528
val nonClosed = LocalAtomicInt(size)
@@ -31,11 +34,11 @@ internal suspend fun <R, T> FlowCollector<R>.combineInternal(
3134
flows[i].collect { value ->
3235
val previous = latestValues[i]
3336
latestValues[i] = value
34-
if (previous === NULL) remainingAbsentValues.decrementAndGet()
37+
if (previous === getNull()) remainingAbsentValues.decrementAndGet()
3538
if (remainingAbsentValues.value == 0) {
3639
val results = arrayFactory()
3740
for (index in 0 until size) {
38-
results[index] = NULL.unbox(latestValues[index])
41+
results[index] = getNull().unbox(latestValues[index])
3942
}
4043
// NB: here actually "stale" array can overwrite a fresh one and break linearizability
4144
resultChannel.send(results as Array<T>)
@@ -98,7 +101,7 @@ internal fun <T1, T2, R> zipImpl(flow: Flow<T1>, flow2: Flow<T2>, transform: sus
98101
flow.collect { value ->
99102
val otherValue = second.receiveOrNull() ?: return@collect
100103
withContextUndispatched(newContext, cnt) {
101-
emit(transform(NULL.unbox(value), NULL.unbox(otherValue)))
104+
emit(transform(getNull().unbox(value), getNull().unbox(otherValue)))
102105
}
103106
ensureActive()
104107
}
@@ -127,6 +130,6 @@ private suspend fun withContextUndispatched(
127130
// Channel has any type due to onReceiveOrNull. This will be fixed after receiveOrClosed
128131
private fun CoroutineScope.asChannel(flow: Flow<*>): ReceiveChannel<Any> = produce {
129132
flow.collect { value ->
130-
return@collect channel.send(value ?: NULL)
133+
return@collect channel.send(value ?: getNull())
131134
}
132135
}

0 commit comments

Comments
 (0)