Saw this error streaming from one module `'when' e...
# k2-adopters
r
Saw this error streaming from one module
'when' expression must be exhaustive. Add an 'else' branch.
• I don't see any warning or lint error in AS IDE • I can confirm, the when statement is exhuastive
1
d
It would be really helpful if you share some code
r
Sure.
Copy code
when (either) {
  is Either.Success -> {

  }
  is Either.Failure -> {

  }
}
Copy code
sealed class Either<out S, out F> {
  data class Success<S, F> internal constructor(val success: S) : Either<S, F>()
  data class Failure<S, F> internal constructor(val failure: F) : Either<S, F>()
}
d
What is the type of
either
? Is it
Either<*, *>
?
r
It's basically gets wrapped in Rx Single.. Something like
Copy code
Single<Either<Object1, Object2>>
g
Are you sure that either is not nullable?
d
Copy code
sealed class Either<out S, out F> {
    data class Success<S, F> internal constructor(val success: S) : Either<S, F>()
    data class Failure<S, F> internal constructor(val failure: F) : Either<S, F>()
}

fun test(either: Either<Int, String>) {
    val x = when (either) {
        is Either.Success -> 1
        is Either.Failure -> 2
    }
}
This code compiles completely fine with 2.0.0
A side note: second type parameter for
Success
and
Failure
is redundant Such hierarchy will be much more useful
Copy code
sealed class Either<out S, out F> {
    data class Success<S>(val success: S) : Either<S, Nothing>()
    data class Failure<F>(val failure: F) : Either<Nothing, F>()
}
👍 1
Wait a minute Type of
either
is
Single<Either<Object1, Object2>>
, not
Either<Object1, Object2>
? And
Single
is not part of
Either
hierarchy? In this case the compiler is entirely correct
r
Are you sure that either is not nullable?
I can cross check - 👀 In either case, the IDE should be warning for exhaustive when statement pre kotlin 2.0.0 as well right? I don't see any AS IDE error.
g
K2 compiler is not used in IDE, so IDE may show different results comparing to compiler
👍 1
r
https://kotlinlang.slack.com/archives/C03PK0PE257/p1721030806477059?thread_ts=1721029809.291729&cid=C03PK0PE257 Sure, i will cross check once again, from my end. Even though it's wrapped in Rx Single. Subscribing to RxSingle gives EitherObject1, Object2 type Something like
Single<Either<Object1, Object2>>.subscribe { either ->
when(either) {
}
}
Code structure looks like this
Copy code
val single:Single<Either<Object1,Object2>> = if (url == null) {
        api.getSingleObject()
      } else {
        Single.just(Either.success(Object1()))
      }

single.subscribe { either ->
  when(either) {
    Either.Success -> {}
    Either.Failiure -> {}
  }
}
• I can confirm it's not null, as the
single
declaration is non-nullable. If i don't use if statements and directly use one of the calls from if block or else block it compiles well.
d
What is the signature of
api.get
?
r
it returns Single<Either<Object1, Object2>>
d
It is java method or kotlin?
r
The api.get() is in kotlin and all it's surrounding classes, however
Single
is from Rx-java a third party library, a java class
d
Still compiles fine with 2.0.0
Copy code
import rx.Single

sealed class Either<out S, out F> {
    data class Success<S, F> internal constructor(val success: S) : Either<S, F>()
    data class Failure<S, F> internal constructor(val failure: F) : Either<S, F>()

    companion object {
        fun <S, F> success(x: S): Success<S, F> = Success(x)
    }
}

class Object1
class Object2

class Api {
    fun getSingleObject(): Single<Either<Object1, Object2>> = null!!
}

fun test(api: Api, cond: Boolean) {
    val single: Single<Either<Object1, Object2>> = if (cond) {
        api.getSingleObject()
    } else {
        Single.just(Either.success(Object1()))
    }

    single.subscribe { either ->
        val x = when(either) {
            is Either.Success -> 1
            is Either.Failure -> 2
        }
    }
}
😕 1
r
Running like this
api.getSingleObject().subscribe(...)
or
Single.just(Either.success(Object1())).subscribe(..)
gets through the compiler, but not when using
single
- 😕 I understand, the code you shared mimicks the same behaviour but.. 👀
d
Please create an issue if you can provide a self-contained example of code which doesn't work (ideally if it would be working gradle project)
r
Sure
On other note - it would have been helpful, if KGP lint in Android Studio showed same error in code. Probably when K2 is enabled for IDE in future releases.
d
Yes, it will be fixed when IDE fully migrate to K2
👍 1
r
Copy code
single.subscribe { either: Either<Object1, Object2> ->
        val x = when(either) {
            is Either.Success -> 1
            is Either.Failure -> 2
        }
    }
Adding explicit type to the either in lambda, worked for us. Still believe, it's an issue - will open a ticket with reproducing or sample project. Thanks for the help.
d
Thank you too
g
I think I know why, because subscibe lambda param has platform type, so adding null check would help (or adding explicit non-nullable type) But it's indeed not how old compiler works, and platform type is fine for this case
r
Ohh, i thought by default kotlin treats platform types as non nullable. Probably, it got changed in k2 - as it became more strict towards erroring out nullability.
g
Kotlin treats platform types both as nullable and non-nullable, I honestly wouldn't expect k2 to change behaviour here
👍 1