[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
@@ -13,11 +13,11 @@ fun test(x: Stmt): String =
}
fun test2(x: Stmt): String =
when (x) {
<!NO_ELSE_IN_WHEN!>when<!> (x) {
is Expr -> "expr"
}
fun test3(x: Expr): String =
when (x) {
<!NO_ELSE_IN_WHEN!>when<!> (x) {
is Stmt -> "stmt"
}
}
@@ -15,7 +15,7 @@ sealed class Base {
// No else required
}
fun bar() = when (this) {
fun bar() = <!NO_ELSE_IN_WHEN!>when<!> (this) {
is A -> 1
is B.B1 -> 2
}
@@ -31,4 +31,4 @@ sealed class Base {
A.A1 -> 2
is A.A2 -> 3
}
}
}
@@ -1,24 +0,0 @@
sealed class A
sealed class B : A()
class C : B()
class D : B()
fun test(a: A): Any {
return when (a) {
is C -> ""
is D -> ""
}
}
fun test2(a: A): Any {
return when (a) {
is B -> ""
}
}
fun test3(a: A): Any {
return when (a) {
is D -> ""
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
sealed class A
sealed class B : A()
@@ -1,47 +0,0 @@
sealed class Sealed() {
object First: Sealed()
open class NonFirst: Sealed() {
class NonSecond: NonFirst() {
object Third: Sealed()
class NonThird: Sealed() {
object Fourth: NonFirst()
class Fifth: Sealed()
}
}
object Second: Sealed()
}
}
fun foo(s: Sealed) = when(s) {
Sealed.First -> 1
is Sealed.NonFirst -> 2
Sealed.NonFirst.Second -> 4
Sealed.NonFirst.NonSecond.Third -> 6
is Sealed.NonFirst.NonSecond.NonThird -> 8
is Sealed.NonFirst.NonSecond.NonThird.Fifth -> 10
// no else required
}
fun fooWithElse(s: Sealed) = when(s) {
Sealed.First -> 1
Sealed.NonFirst.NonSecond.Third -> 6
is Sealed.NonFirst.NonSecond.NonThird.Fifth -> 10
else -> 0
}
fun fooWithoutElse(s: Sealed) = when(s) {
Sealed.First -> 1
is Sealed.NonFirst -> 2
Sealed.NonFirst.NonSecond.Third -> 6
is Sealed.NonFirst.NonSecond.NonThird -> 8
is Sealed.NonFirst.NonSecond.NonThird.Fifth -> 10
}
fun barWithoutElse(s: Sealed) = when(s) {
Sealed.First -> 1
is Sealed.NonFirst -> 2
Sealed.NonFirst.Second -> 4
is Sealed.NonFirst.NonSecond.NonThird -> 8
is Sealed.NonFirst.NonSecond.NonThird.Fifth -> 10
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
sealed class Sealed() {
object First: Sealed()
open class NonFirst: Sealed() {
@@ -1,64 +0,0 @@
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +AllowSealedInheritorsInDifferentFilesOfSamePackage
// FILE: Base.kt
sealed class Base {
class A : Base()
}
// FILE: B.kt
class B : Base()
// FILE: Container.kt
class Containter {
class C : Base()
inner class D : Base()
}
// FILE: main.kt
fun test_OK(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_1(base: Base) {
val x = when (base) {
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_2(base: Base) {
val x = when (base) {
is Base.A -> 1
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_3(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.D -> 4
}
}
fun test_error_4(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +AllowSealedInheritorsInDifferentFilesOfSamePackage
@@ -1,14 +0,0 @@
sealed class Sealed(val x: Int) {
object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) {
object Second: NonFirst(34, 2)
object Third: NonFirst(56, 3)
}
}
fun foo(s: Sealed): Int {
return when(s) {
is Sealed.NonFirst -> 0
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
sealed class Sealed(val x: Int) {
object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) {
@@ -1,14 +0,0 @@
sealed class Sealed(val x: Int) {
object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) {
object Second: NonFirst(34, 2)
object Third: NonFirst(56, 3)
}
}
fun foo(s: Sealed): Int {
return when(s) {
!is Sealed.NonFirst -> 1
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
sealed class Sealed(val x: Int) {
object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) {
@@ -1,22 +0,0 @@
sealed class Sealed(val x: Int) {
interface ITuple {
val x: Int
val y: Int
}
class Tuple(override val x: Int, override val y: Int): ITuple
object First: Sealed(12)
open class NonFirst(tuple: Tuple): Sealed(tuple.x), ITuple {
override val y: Int = tuple.y
object Second: NonFirst(Tuple(34, 2))
class Third: NonFirst(Tuple(56, 3))
}
}
fun foo(s: Sealed): Int {
return when(s) {
is Sealed.First -> 1
!is Sealed.ITuple -> 0
// else required
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
sealed class Sealed(val x: Int) {
interface ITuple {
val x: Int
@@ -7,7 +7,7 @@ sealed class Sealed {
}
fun foo(s: Sealed): Int {
return when(s) {
return <!NO_ELSE_IN_WHEN!>when<!>(s) {
is Sealed.First -> 1
!is Any -> 0
}
@@ -9,7 +9,7 @@ sealed class Tree {
is Node -> this.left.max()
}
fun maxIsClass(): Int = when(this) {
fun maxIsClass(): Int = <!NO_ELSE_IN_WHEN!>when<!>(this) {
Empty -> -1
Leaf -> 0
is Node -> this.left.max()
@@ -20,4 +20,4 @@ sealed class Tree {
is Node -> this.left.max()
else -> -1
}
}
}
@@ -1,11 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION
sealed class Sealed {
}
fun foo(s: Sealed): Int {
return when(s) {
// We do not return anything, so else branch must be here
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION
sealed class Sealed {