[FIR] Implement checker for exhaustive when's in expression position

This commit is contained in:
Dmitriy Novozhilov
2021-02-04 15:41:57 +03:00
parent 3f715e671d
commit 8dd9d98129
103 changed files with 919 additions and 617 deletions
@@ -0,0 +1,55 @@
FILE: missingBooleanBranch.kt
public final fun test_1(cond: R|kotlin/Boolean|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
}
lval y: R|kotlin/Unit| = when (R|<local>/cond|) {
==($subj$, Boolean(false)) -> {
Int(2)
}
}
lval z: R|kotlin/Int| = when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
==($subj$, Boolean(false)) -> {
Int(2)
}
}
}
public final fun test_2(cond: R|kotlin/Boolean?|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
==($subj$, Boolean(false)) -> {
Int(2)
}
}
lval x: R|kotlin/Int| = when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
==($subj$, Boolean(false)) -> {
Int(2)
}
==($subj$, Null(null)) -> {
Int(3)
}
}
}
public final fun test_3(cond: R|kotlin/Boolean|): R|kotlin/Unit| {
when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
}
}
@@ -0,0 +1,33 @@
fun test_1(cond: Boolean) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (cond) {
true -> 1
}
val y = <!NO_ELSE_IN_WHEN!>when<!> (cond) {
false -> 2
}
val z = when (cond) {
true -> 1
false -> 2
}
}
fun test_2(cond: Boolean?) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (cond) {
true -> 1
false -> 2
}
val x = when (cond) {
true -> 1
false -> 2
null -> 3
}
}
fun test_3(cond: Boolean) {
when (cond) {
true -> 1
}
}
@@ -0,0 +1,41 @@
FILE: missingElse.kt
public final fun test(a: R|kotlin/Any|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/a|) {
($subj$ is R|kotlin/Int|) -> {
Int(1)
}
($subj$ is R|kotlin/String|) -> {
Int(2)
}
}
lval y: R|kotlin/Int| = when (R|<local>/a|) {
else -> {
Int(1)
}
}
lval z: R|kotlin/Int| = when (R|<local>/a|) {
($subj$ is R|kotlin/Int|) -> {
Int(1)
}
($subj$ is R|kotlin/String|) -> {
Int(2)
}
else -> {
Int(3)
}
}
}
public final fun test_2(a: R|kotlin/Any|): R|kotlin/Unit| {
when (R|<local>/a|) {
($subj$ is R|kotlin/String|) -> {
Int(1)
}
($subj$ is R|kotlin/Int|) -> {
Int(2)
}
}
}
@@ -0,0 +1,23 @@
fun test(a: Any) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (a) {
is Int -> 1
is String -> 2
}
val y = when (a) {
else -> 1
}
val z = when (a) {
is Int -> 1
is String -> 2
else -> 3
}
}
fun test_2(a: Any) {
when (a) {
is String -> 1
is Int -> 2
}
}
@@ -0,0 +1,63 @@
FILE: missingEnumEntry.kt
public final enum class SomeEnum : R|kotlin/Enum<SomeEnum>| {
private constructor(): R|SomeEnum| {
super<R|kotlin/Enum<SomeEnum>|>()
}
public final static enum entry A: R|SomeEnum|
public final static enum entry B: R|SomeEnum|
public final static fun values(): R|kotlin/Array<SomeEnum>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|SomeEnum| {
}
}
public final fun test_1(enum: R|SomeEnum|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/enum|) {
==($subj$, Q|SomeEnum|.R|/SomeEnum.A|) -> {
Int(1)
}
}
lval y: R|kotlin/Int| = when (R|<local>/enum|) {
==($subj$, Q|SomeEnum|.R|/SomeEnum.A|) -> {
Int(1)
}
==($subj$, Q|SomeEnum|.R|/SomeEnum.B|) -> {
Int(2)
}
}
}
public final fun test_2(enum: R|SomeEnum?|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/enum|) {
==($subj$, Q|SomeEnum|.R|/SomeEnum.A|) -> {
Int(1)
}
==($subj$, Q|SomeEnum|.R|/SomeEnum.B|) -> {
Int(2)
}
}
lval y: R|kotlin/Int| = when (R|<local>/enum|) {
==($subj$, Q|SomeEnum|.R|/SomeEnum.A|) -> {
Int(1)
}
==($subj$, Q|SomeEnum|.R|/SomeEnum.B|) -> {
Int(2)
}
==($subj$, Null(null)) -> {
Int(3)
}
}
}
public final fun test_3(enum: R|SomeEnum|): R|kotlin/Unit| {
when (R|<local>/enum|) {
==($subj$, Q|SomeEnum|.R|/SomeEnum.A|) -> {
Int(1)
}
}
}
@@ -0,0 +1,33 @@
enum class SomeEnum {
A, B
}
fun test_1(enum: SomeEnum) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (enum) {
SomeEnum.A -> 1
}
val y = when (enum) {
SomeEnum.A -> 1
SomeEnum.B -> 2
}
}
fun test_2(enum: SomeEnum?) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (enum) {
SomeEnum.A -> 1
SomeEnum.B -> 2
}
val y = when (enum) {
SomeEnum.A -> 1
SomeEnum.B -> 2
null -> 3
}
}
fun test_3(enum: SomeEnum) {
when (enum) {
SomeEnum.A -> 1
}
}
@@ -0,0 +1,84 @@
FILE: a.kt
public sealed class Base : R|kotlin/Any| {
private constructor(): R|Base| {
super<R|kotlin/Any|>()
}
}
public final class A : R|Base| {
public constructor(): R|A| {
super<R|Base|>()
}
}
FILE: b.kt
public final object B : R|Base| {
private constructor(): R|B| {
super<R|Base|>()
}
}
FILE: c.kt
public final fun test_1(base: R|Base|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
}
lval y: R|kotlin/Unit| = when (R|<local>/base|) {
==($subj$, Q|B|) -> {
Int(1)
}
}
lval z: R|kotlin/Int| = when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
==($subj$, Q|B|) -> {
Int(2)
}
}
}
public final fun test_2(base: R|Base?|): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
($subj$ is R|B|) -> {
Int(2)
}
}
lval y: R|kotlin/Unit| = when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
==($subj$, Q|B|) -> {
Int(2)
}
}
lval z: R|kotlin/Int| = when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
==($subj$, Q|B|) -> {
Int(2)
}
==($subj$, Null(null)) -> {
Int(3)
}
}
}
public final fun test_3(base: R|Base|): R|kotlin/Unit| {
when (R|<local>/base|) {
($subj$ is R|A|) -> {
Int(1)
}
}
}
@@ -0,0 +1,50 @@
// FILE: a.kt
sealed class Base
class A : Base
// FILE: b.kt
object B : Base()
// FILE: c.kt
fun test_1(base: Base) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is A -> 1
}
val y = <!NO_ELSE_IN_WHEN!>when<!> (base) {
B -> 1
}
val z = when (base) {
is A -> 1
B -> 2
}
}
fun test_2(base: Base?) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is A -> 1
is B -> 2
}
val y = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is A -> 1
B -> 2
}
val z = when (base) {
is A -> 1
B -> 2
null -> 3
}
}
fun test_3(base: Base) {
when (base) {
is A -> 1
}
}