Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/common/src/flow/operators/Share.kt (Kotlin)

Code before:
    launch(context) {
        try {
            var state: MutableStateFlow<T>? = null
            upstream.collect { value ->
                state?.let { it.value = value } ?: run {
                    state = MutableStateFlow(value).also {
                        result.complete(Result.success(ReadonlyStateFlow(it, coroutineContext.job)))
                    }
                }
            }
            if (state == null) {
                result.complete(Result.failure(NoSuchElementException("Flow is empty")))
            }
        } catch (e: Throwable) {
            // Notify the waiter that the flow has failed
            result.completeExceptionally(e)
            // But still cancel the scope where state was (not) produced
            throw e
        }
    }
}

// -------------------------------- asFlow --------------------------------

/**
 * Represents this shared flow as a flow.
 */
@ExperimentalCoroutinesApi
public fun <T> SharedFlow<T>.asFlow(): Flow<T> =
    transform { value -> emit(value) }

// -------------------------------- asSharedFlow/asStateFlow --------------------------------

/**
 * Represents this mutable shared flow as a read-only shared flow.
 */
public fun <T> MutableSharedFlow<T>.asSharedFlow(): SharedFlow<T> =
    ReadonlySharedFlow(this, null)

/**
 * Represents this mutable state flow as a read-only state flow.
 */
public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> =
    ReadonlyStateFlow(this, null)

@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
private class ReadonlySharedFlow<T>(
    flow: SharedFlow<T>,
    @Suppress("unused")
    private val job: Job? // keeps a strong reference to the job (if present)
) : SharedFlow<T> by flow, CancellableFlow<T>, FusibleFlow<T> {

Review comment (suggestion):
Please expand the documentation:
* Differences from simple upcasting should be explained.
* The purpose is not immediately clear.
* A usage example would be nice, as it's not always obvious where to stick `asFlow()`.

Code after:
    launch(context) {
        try {
            var state: MutableStateFlow<T>? = null
            upstream.collect { value ->
                state?.let { it.value = value } ?: run {
                    state = MutableStateFlow(value).also {
                        result.complete(Result.success(ReadonlyStateFlow(it, coroutineContext.job)))
                    }
                }
            }
            if (state == null) {
                result.complete(Result.failure(NoSuchElementException("Flow is empty")))
            }
        } catch (e: Throwable) {
            // Notify the waiter that the flow has failed
            result.completeExceptionally(e)
            // But still cancel the scope where state was (not) produced
            throw e
        }
    }
}

// -------------------------------- asFlow --------------------------------

/**
 * Represents this shared flow and its subtypes as a plain flow,
 * hiding its hot flow characteristics.
 *
 * Unlike simple upcasting, the returned flow prevents casting back to the original
 * hot flow type, ensuring that implementation details remain encapsulated.
 *
 * Example:
 * ```
 * class Repository {
 *     private val _updates = MutableStateFlow("initial")
 *
 *     // Exposes Flow interface without leaking MutableStateFlow implementation
 *     val updates: Flow<String> = _updates.asFlow()
 * }
 *
 * // Usage
 * val flow = repository.updates
 * val mutableStateFlow = flow as? MutableStateFlow // null - cast prevented
 * val stateFlow = flow as? StateFlow // null - cast prevented
 * ```
 */
@ExperimentalCoroutinesApi
public fun <T> SharedFlow<T>.asFlow(): Flow<T> =
    transform { value -> emit(value) }

// -------------------------------- asSharedFlow/asStateFlow --------------------------------