From bed4c5f2f059a7be42c89dc58d2560c4f396db36 Mon Sep 17 00:00:00 2001 From: "victor.petukhov" Date: Fri, 10 Aug 2018 18:06:01 +0300 Subject: [PATCH] Add diagnostic spec tests for 'When expression' section --- .../tests-spec/testData/diagnostics/ReadMe.md | 135 ++++ .../s-16.30_when-expression/p-11/neg/1.1.kt | 24 + .../s-16.30_when-expression/p-11/neg/1.2.kt | 26 + .../s-16.30_when-expression/p-11/neg/3.1.kt | 45 ++ .../s-16.30_when-expression/p-11/neg/6.1.kt | 83 +++ .../s-16.30_when-expression/p-11/neg/7.1.kt | 54 ++ .../s-16.30_when-expression/p-11/neg/8.1.kt | 26 + .../s-16.30_when-expression/p-11/neg/8.2.kt | 109 ++++ .../s-16.30_when-expression/p-11/neg/8.3.kt | 62 ++ .../s-16.30_when-expression/p-11/pos/1.1.kt | 29 + .../s-16.30_when-expression/p-11/pos/1.2.kt | 40 ++ .../s-16.30_when-expression/p-11/pos/1.3.kt | 76 +++ .../s-16.30_when-expression/p-11/pos/3.1.kt | 21 + .../s-16.30_when-expression/p-11/pos/6.1.kt | 66 ++ .../s-16.30_when-expression/p-11/pos/7.1.kt | 24 + .../s-16.30_when-expression/p-11/pos/8.1.kt | 23 + .../s-16.30_when-expression/p-11/pos/8.2.kt | 26 + .../s-16.30_when-expression/p-11/pos/8.3.kt | 66 ++ .../s-16.30_when-expression/p-2/pos/3.1.kt | 13 + .../s-16.30_when-expression/p-2/pos/3.2.kt | 13 + .../s-16.30_when-expression/p-3/neg/1.1.kt | 31 + .../s-16.30_when-expression/p-3/neg/2.1.kt | 24 + .../s-16.30_when-expression/p-3/neg/2.2.kt | 21 + .../s-16.30_when-expression/p-3/pos/1.1.kt | 321 ++++++++++ .../s-16.30_when-expression/p-3/pos/2.1.kt | 124 ++++ .../s-16.30_when-expression/p-3/pos/2.2.kt | 21 + .../s-16.30_when-expression/p-3/pos/2.3.kt | 97 +++ .../s-16.30_when-expression/p-5/neg/1.1.kt | 32 + .../s-16.30_when-expression/p-5/pos/1.1.kt | 25 + .../s-16.30_when-expression/p-6/neg/1.1.kt | 33 + .../s-16.30_when-expression/p-6/pos/1.1.kt | 324 ++++++++++ .../s-16.30_when-expression/p-7/neg/1.1.kt | 38 ++ .../s-16.30_when-expression/p-7/neg/1.2.kt | 19 + .../s-16.30_when-expression/p-7/neg/3.1.kt | 20 + .../s-16.30_when-expression/p-7/neg/3.2.kt | 36 ++ .../s-16.30_when-expression/p-7/neg/5.1.kt | 35 ++ .../s-16.30_when-expression/p-7/neg/5.2.kt | 31 + .../s-16.30_when-expression/p-7/neg/7.1.kt | 34 ++ .../s-16.30_when-expression/p-7/pos/1.1.kt | 70 +++ .../s-16.30_when-expression/p-7/pos/1.2.kt | 60 ++ .../s-16.30_when-expression/p-7/pos/1.3.kt | 77 +++ .../s-16.30_when-expression/p-7/pos/1.4.kt | 59 ++ .../s-16.30_when-expression/p-7/pos/3.1.kt | 32 + .../s-16.30_when-expression/p-7/pos/3.2.kt | 28 + .../s-16.30_when-expression/p-7/pos/5.1.kt | 288 +++++++++ .../s-16.30_when-expression/p-7/pos/5.2.kt | 265 ++++++++ .../s-16.30_when-expression/p-7/pos/7.1.kt | 33 + .../s-16.30_when-expression/p-9/neg/1.1.kt | 156 +++++ .../s-16.30_when-expression/p-9/neg/1.2.kt | 95 +++ .../s-16.30_when-expression/p-9/neg/1.3.kt | 81 +++ .../s-16.30_when-expression/p-9/neg/1.4.kt | 175 ++++++ .../s-16.30_when-expression/p-9/pos/1.1.kt | 112 ++++ .../s-16.30_when-expression/p-9/pos/1.2.kt | 75 +++ .../s-16.30_when-expression/p-9/pos/1.3.kt | 70 +++ .../s-16.30_when-expression/p-9/pos/1.4.kt | 141 +++++ .../DiagnosticsTestSpecGenerated.java | 574 ++++++++++++++++++ 56 files changed, 4618 insertions(+) create mode 100644 compiler/tests-spec/testData/diagnostics/ReadMe.md create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/3.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/6.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/7.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/3.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/6.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/7.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/7.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.4.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/7.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.4.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.1.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.2.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.3.kt create mode 100644 compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.4.kt create mode 100644 compiler/tests-spec/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestSpecGenerated.java diff --git a/compiler/tests-spec/testData/diagnostics/ReadMe.md b/compiler/tests-spec/testData/diagnostics/ReadMe.md new file mode 100644 index 00000000000..eea162258cf --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/ReadMe.md @@ -0,0 +1,135 @@ +# Diagnostic specification tests + +Diagnostic specification tests are diagnostic tests for certain statements in the [Kotlin language specification](https://github.com/JetBrains/kotlin-spec). + +Note: diagnostic tests format specification you can see in the [diagnostic tests readme](https://github.com/JetBrains/kotlin/blob/master/compiler/testData/diagnostics/ReadMe.md). + +## Structure + +Each test relates to a specific section, paragraph, and sentence of the Kotlin language specification, and is either positive or negative. + +The folder structure is as follows: +* `s-_` + * `p-` + * `` + * `..kt` (test source code) + * `..txt` (descriptors file) + +Example test file path: `testsSpec/s-16.30_when-expression/p-2/neg/3.1.kt` + +## Positive and negative tests + +Positive tests are considered to be tests in which there is no single diagnostics with a `ERROR` severity. +Positive tests can only contain diagnostics with a `WARNING` or `INFO` severity (or not contain at all). + +In a negative test, there must be at least one diagnostic with `ERROR` severity. + +## Tests format + +### Test description + +Each test file must contain meta information in the form of a multi-line comment. + +A comment with meta information has the following format: +``` +/* + KOTLIN SPEC TEST () + + SECTION : + PARAGRAPH: + SENTENCE : + NUMBER: + DESCRIPTION: + */ +``` +Example: +``` +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION 16.30: When expression + PARAGRAPH: 3 + SENTENCE 2: Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 1 + DESCRIPTION: 'When' with not boolean condition in 'when condition' + */ +``` + +Meta-information should be placed at the beginning of the file after diagnostic directives (if any). + +### Case description + +The test can contain many cases. +Each case (if there are more than one) should be accompanied by a description. + +The case description is a single-line comment of the following format: +``` +// CASE DESCRIPTION: +``` +Example: +``` +// CASE DESCRIPTION: Checking for exhaustive 'when' (all sealed class subtypes and null value are covered). +fun case_1(expr: Expr?): String = when (expr) { + is Const -> expr.n + is Sum -> expr.e1 + expr.e2 + is Mul -> expr.m1 + expr.m2 + null -> "" +} +``` + +## Test validation + +Before running the test, the following validation is performed: +- check for correspondence to the format of the folders and file names; +- check for correspondence to the format of the meta-information in the test file; +- check for consistency between the location and name of the test file and the meta-information in it; +- checking whether the test is positive or negative using information about diagnostics severity. + +If the validation fails, you will receive exception about it. + +## Test run log + +During the test run, the following information is displayed for each test: + +``` + DIAGNOSTICS SPEC TEST +SECTION: (paragraph: ) +SENTENCE []: +TEST NUMBER: +NUMBER OF TEST CASES: +DESCRIPTION: +DIAGNOSTICS: | +``` +Example: +``` +POSITIVE DIAGNOSTICS SPEC TEST +SECTION: 16.30 When expression (paragraph: 5) +SENTENCE 1 [http://jetbrains.github.io/kotlin-spec/#when-expression:5:1]: The type of the resulting expression is the least upper bound of the types of all the entries. +TEST NUMBER: 4 +NUMBER OF TEST CASES: 9 +DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via sealed class). +DIAGNOSTICS: {WARNING=15} | {USELESS_IS_CHECK=1, IMPLICIT_CAST_TO_ANY=14} +``` + +## Statistics on specification tests + +To see statistics for existing tests you can run gradle task `printSpecTestStatistic` in the `:compiler:tests-spec`. + +Example output: +``` + +-------------------------------------------------- +SPEC TESTS STATISTIC +-------------------------------------------------- +DIAGNOSTICS: 131 tests + 16.30 WHEN-EXPRESSION: 131 tests + PARAGRAPH 2: 4 tests (neg: 2, pos: 2) + PARAGRAPH 3: 35 tests (neg: 5, pos: 30) + PARAGRAPH 4: 67 tests (neg: 11, pos: 56) + PARAGRAPH 5: 8 tests (neg: 4, pos: 4) + PARAGRAPH 6: 17 tests (neg: 8, pos: 9) +PSI: 0 tests +CODEGEN: 0 tests +-------------------------------------------------- + +``` \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.1.kt new file mode 100644 index 00000000000..4936394aebc --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.1.kt @@ -0,0 +1,24 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [1] It has an else entry; + NUMBER: 1 + DESCRIPTION: Checking for not exhaustive when without bound value when there is no else branch. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (several branches). +fun case_1(value: Int): String = when { + value == 1 -> "" + value == 2 -> "" + value == 3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (one branch). +fun case_2(value: Int): String = when { + value == 1 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (no branches). +fun case_3(): Int = when {} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.2.kt new file mode 100644 index 00000000000..51de76fb102 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.2.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [1] It has an else entry; + NUMBER: 2 + DESCRIPTION: Checking for not exhaustive when with bound value when there is no else branch. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (several branches). +fun case_1(value: Int): String = when (value) { + 1 -> "" + 2 -> "" + 3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (one branch). +fun case_2(value: Int): String = when (value) { + 1 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' (no branches). +fun case_3(value: Int): Int = when (value) {} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/3.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/3.1.kt new file mode 100644 index 00000000000..67ba826e240 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/3.1.kt @@ -0,0 +1,45 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [3] The bound expression is of type kotlin.Boolean and the conditions contain both: + NUMBER: 1 + DESCRIPTION: Checking for not exhaustive 'when' when not contains by all Boolean values or 'when' does not have bound value. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean value (with only true branch). +fun case_1(value: Boolean): String = when(value) { + true -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean value (with only false branch). +fun case_2(value: Boolean): String = when(value) { + false -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean value (no branches). +fun case_3(value: Boolean): Int = when(value) { } + +// CASE DESCRIPTION: Checking for not exhaustive 'when' without bound value on the Boolean. +fun case_4(value: Boolean): String = when { + value == true -> "" + value == false -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' with both Boolean values covered, but using variables. + DISCUSSION: maybe use const propagation here? + ISSUES: KT-25265 + */ +fun case_5(value: Boolean): String { + val trueValue = true + val falseValue = false + + return when (value) { + trueValue -> "" + falseValue -> "" + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/6.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/6.1.kt new file mode 100644 index 00000000000..8a73ce823cf --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/6.1.kt @@ -0,0 +1,83 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [6] The bound expression is of a sealed class type and all its possible subtypes are covered using type test conditions of this expression; + NUMBER: 1 + DESCRIPTION: Checking for not exhaustive 'when' when not covered by all possible subtypes or 'when' does not have bound value. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking). +fun case_1(value: _SealedClass): String = when(value) { + is _SealedChild1 -> "" + is _SealedChild2 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking with enumeration). +fun case_2(value: _SealedClass): String = when(value) { + is _SealedChild1, is _SealedChild2 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking and equality with object). +fun case_3(value: _SealedClassMixed): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + _SealedMixedChildObject1 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking and equality with object with enumeration). +fun case_4(value: _SealedClassMixed): String = when(value) { + _SealedMixedChildObject1, is _SealedMixedChild2, is _SealedMixedChild1 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking). +fun case_5(value: _SealedClassMixed): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class with several subtypes (no branches). +fun case_6(value: _SealedClassMixed): Int = when(value) { } + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class with one subtype (no branches). +fun case_7(value: _SealedClassSingleWithObject): Int = when(value) { } + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty sealed class (without subtypes). +fun case_8(value: _SealedClassEmpty): String = when (value) { } + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the not sealed class. +fun case_9(value: Number): String = when (value) { + is Byte -> "" + is Double -> "" + is Float -> "" + is Int -> "" + is Long -> "" + is Short -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the Any. + DISCUSSION: maybe make exhaustive without else? + */ +fun case_10(value: Any): String = when (value) { + is Any -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' without bound value on the Sealed class with all subtypes covered. +fun case_11(value: _SealedClass): String = when { + value is _SealedChild1 -> "" + value is _SealedChild2 -> "" + value is _SealedChild3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the sealed class (type checking). +fun case_12(value: _SealedClassMixed): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/7.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/7.1.kt new file mode 100644 index 00000000000..4667da81e0d --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/7.1.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [7] The bound expression is of an Enum classes type and all enumerated values are checked for equality using constant conditions; + NUMBER: 1 + DESCRIPTION: Checking for not exhaustive when when not covered by all enumerated values. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum (not all values). +fun case_1(value: _EnumClass): String = when(value) { + _EnumClass.EAST -> "" + _EnumClass.SOUTH -> "" + _EnumClass.NORTH -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum (not all values with enumerations). +fun case_2(value: _EnumClass): String = when(value) { + _EnumClass.EAST, _EnumClass.SOUTH, _EnumClass.NORTH -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum (one branch). +fun case_3(value: _EnumClass): String = when(value) { + _EnumClass.EAST -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum with several values (no branches). +fun case_4(value: _EnumClass): String = when(value) { } + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum with one value (no branches). +fun case_5(value: _EnumClassSingle): String = when(value) { } + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' with all Enum values covered, but using variable. + DISCUSSION: maybe use const propagation here? + ISSUES: KT-25265 + */ +fun case_6(value: _EnumClass): String { + val west = _EnumClass.WEST + + return when (value) { + _EnumClass.EAST -> "" + _EnumClass.SOUTH -> "" + _EnumClass.NORTH -> "" + west -> "" + } +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty enum class. +fun case_7(value: _EnumClassEmpty): String = when (value) { } diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.1.kt new file mode 100644 index 00000000000..ebc76ba6f89 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.1.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 1 + DESCRIPTION: Checking for not exhaustive 'when' on the nullable Boolean. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean without null-check branch. +fun case_1(value: Boolean?): String = when(value) { + true -> "" + false -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean with null-check branch, but all possible values not covered. +fun case_2(value: Boolean?): String = when(value) { + true -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Boolean without branches. +fun case_3(value: Boolean?): Int = when(value) { } diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.2.kt new file mode 100644 index 00000000000..87391877215 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.2.kt @@ -0,0 +1,109 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 2 + DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed classes (and several checks for not sealed). + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class without null-check branch. +fun case_1(value: _SealedClass?): String = when(value) { + is _SealedChild1 -> "" + is _SealedChild2 -> "" + is _SealedChild3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class with mixed checks (type and object check) and null-check branch. +fun case_2(value: _SealedClassMixed?): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + _SealedMixedChildObject1 -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class with enumeration mixed checks (type and object check) and null-check branch. +fun case_3(value: _SealedClassMixed?): String = when(value) { + null, is _SealedMixedChild1, is _SealedMixedChild2, _SealedMixedChildObject1 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class with all subtypes and objects covered without null-check branch. +fun case_4(value: _SealedClassMixed?): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" + _SealedMixedChildObject1 -> "" + _SealedMixedChildObject2 -> "" + _SealedMixedChildObject3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class without null-check branch and all subtypes covered, but objects not covered. +fun case_5(value: _SealedClassMixed?): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class without branches. +fun case_6(value: _SealedClassMixed?): Int = when(value) {} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class with null-check branch and all subtypes covered, but objects not covered. +fun case_7(value: _SealedClassMixed?): String = when(value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2-> "" + is _SealedMixedChild3 -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable sealed class without null-check branch and only object covered. +fun case_8(value: _SealedClassMixed?): String = when(value) { + _SealedMixedChildObject1 -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty nullable sealed class (without subtypes). + UNEXPECTED BEHAVIOUR: must be exhaustive + ISSUES: KT-26044 + */ +fun case_9(value: _SealedClassEmpty?): String = when (value) { + null -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the nullable Any. + DISCUSSION: maybe make exhaustive without else? + */ +fun case_10(value: Any?): String = when (value) { + is Any -> "" + null -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on opposite types. + UNEXPECTED BEHAVIOUR: must be exhaustive + ISSUES: KT-22996 + */ +fun case_11(value: _SealedClass?): String = when (value) { + is _SealedChild1, !is _SealedChild3?, is _SealedChild3? -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on opposite types. + UNEXPECTED BEHAVIOUR: must be exhaustive + ISSUES: KT-22996 + */ +fun case_12(value: _SealedClass?): String = when (value) { + is _SealedChild1, !is _SealedChild3 -> "" + is _SealedChild3? -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty sealed class (without subtypes). + DISCUSSION + ISSUES: KT-26044 + */ +fun case_13(value: _SealedClassEmpty): String = when (value) {} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.3.kt new file mode 100644 index 00000000000..0cbeddf93f8 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.3.kt @@ -0,0 +1,62 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 3 + DESCRIPTION: Checking for not exhaustive 'when' on the nullable enums. + */ + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class without null-check branch. +fun case_1(value: _EnumClass?): String = when(value) { + _EnumClass.EAST -> "" + _EnumClass.SOUTH -> "" + _EnumClass.NORTH -> "" + _EnumClass.WEST -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class with null-check branch, but all possible values not covered. +fun case_2(value: _EnumClass?): String = when(value) { + _EnumClass.EAST -> "" + _EnumClass.SOUTH -> "" + _EnumClass.NORTH -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class with null-check branch, but all possible values not covered. +fun case_3(value: _EnumClass?): String = when(value) { + _EnumClass.EAST, null, _EnumClass.SOUTH, _EnumClass.NORTH -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class without branches. +fun case_4(value: _EnumClassSingle): Int = when(value) {} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class (with only one value) without null-check branch. +fun case_5(value: _EnumClassSingle?): String = when(value) { + _EnumClassSingle.EVERYTHING -> "" +} + +// CASE DESCRIPTION: Checking for not exhaustive 'when' on the Enum class (with only one value) with null-check branch, but value not covered. +fun case_6(value: _EnumClassSingle?): String = when(value) { + null -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty nullable enum class. + UNEXPECTED BEHAVIOUR + ISSUES: KT-26044 + */ +fun case_7(value: _EnumClassEmpty?): String = when(value) { + null -> "" +} + +/* + CASE DESCRIPTION: Checking for not exhaustive 'when' on the empty enum class. + DISCUSSION + ISSUES: KT-26044 + */ +fun case_13(value: _EnumClassEmpty): String = when (value) {} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.1.kt new file mode 100644 index 00000000000..1ab682b8abb --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.1.kt @@ -0,0 +1,29 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [1] It has an else entry; + NUMBER: 1 + DESCRIPTION: Check when exhaustive via else entry (when without bound value). + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (several value check branches and 'else' branch). +fun case_1(value: Int): String = when { + value == 0 -> "" + value > 0 && value <= 10 -> "" + value > 10 && value <= 100 -> "" + value > 100 -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (value check branch and 'else' branch). +fun case_2(): String = when { + true -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (only 'else' branch). +fun case_3(): String = when { + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.2.kt new file mode 100644 index 00000000000..766e252b807 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.2.kt @@ -0,0 +1,40 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [1] It has an else entry; + NUMBER: 2 + DESCRIPTION: Check when exhaustive via else entry (when with bound value). + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (several branches). +fun case_1(value: Int): String = when (value) { + 0 -> "" + 1 -> "" + 2 -> "" + 3 -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (value check branch and 'else' branch). +fun case_2(value: Boolean): String = when (value) { + true -> "" + else -> "" +} + +/* + CASE DESCRIPTION: Checking for exhaustive 'when' with constant bound value (value check branch and 'else' branch). + NOTE: for potential bound value constant analysys. + */ +fun case_3(): String = when (true) { + true -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (only 'else' branch). +fun case_4(value: Int): String = when(value) { + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.3.kt new file mode 100644 index 00000000000..221cf208145 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.3.kt @@ -0,0 +1,76 @@ +// !WITH_ENUM_CLASSES +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [1] It has an else entry; + NUMBER: 3 + DESCRIPTION: Check when exhaustive via else entry (when with bound value, redundant else). + */ + +// CASE DESCRIPTION: Checking for redundant 'else' branch (all enum values covered). +fun case_1(value: _EnumClass): String = when (value) { + _EnumClass.EAST -> "" + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> "" + _EnumClass.WEST -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (all enum values and null value covered). +fun case_2(value: _EnumClass?): String = when (value) { + _EnumClass.EAST -> "" + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> "" + _EnumClass.WEST -> "" + null -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (both boolean value covered). +fun case_3(value: Boolean): String = when (value) { + true -> "" + false -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (both boolean value and null value covered). +fun case_4(value: Boolean?): String = when (value) { + true -> "" + false -> "" + null -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (all sealed class subtypes covered). +fun case_5(value: _SealedClass): String = when (value) { + is _SealedChild1 -> "" + is _SealedChild2 -> "" + is _SealedChild3 -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (all sealed class subtypes and null value covered). +fun case_6(value: _SealedClass?): String = when (value) { + is _SealedChild1 -> "" + is _SealedChild2 -> "" + is _SealedChild3 -> "" + null -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (sealed class itself covered). +fun case_7(value: _SealedClassSingle): String = when (value) { + is _SealedClassSingle -> "" + else -> "" +} + +// CASE DESCRIPTION: Checking for redundant 'else' branch (sealed class itself and null value covered). +fun case_8(value: _SealedClassSingle?): String = when (value) { + is _SealedClassSingle -> "" + null -> "" + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/3.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/3.1.kt new file mode 100644 index 00000000000..ecf630eeafc --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/3.1.kt @@ -0,0 +1,21 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [3] The bound expression is of type kotlin.Boolean and the conditions contain both: + NUMBER: 1 + DESCRIPTION: Check when exhaustive via boolean bound value and evaluating to value true and false. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (both boolean value covered). +fun case_1(value: Boolean): String = when (value) { + true -> "" + false -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (both boolean value as complex expression covered). +fun case_2(value: Boolean): String = when (value) { + true && false && ((true || false)) || true && !!!false && !!!true -> "" + true && false && ((true || false)) || true && !!!false -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/6.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/6.1.kt new file mode 100644 index 00000000000..9ac28683542 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/6.1.kt @@ -0,0 +1,66 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When valueession + PARAGRAPH: 11 + SENTENCE: [6] The bound valueession is of a sealed class type and all its possible subtypes are covered using type test conditions of this valueession; + NUMBER: 1 + DESCRIPTION: Check when exhaustive when possible subtypes of the sealed class are covered. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all sealed class subtypes covered). +fun case_1(value: _SealedClass): Int = when (value) { + is _SealedChild1 -> value.number + is _SealedChild2 -> value.e1 + value.e2 + is _SealedChild3 -> value.m1 + value.m2 +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (single sealed class subtypes covered). +fun case_2(value: _SealedClass): String = when (value) { + is _SealedClass -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all sealed class subtypes with methods covered). +fun case_3(value: _SealedClassWithMethods): String = when (value) { + is _SealedWithMethodsChild1 -> value.m1() + is _SealedWithMethodsChild2 -> value.m2() + is _SealedWithMethodsChild3 -> value.m3() +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all objects covered using implicit equality operator). +fun case_4(value: _SealedClassWithObjects): String = when (value) { + _SealedWithObjectsChild1 -> "" + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all subtypes and objects covered). +fun case_5(value: _SealedClassMixed): String = when (value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" + _SealedMixedChildObject1 -> "" + _SealedMixedChildObject2 -> "" + _SealedMixedChildObject3 -> "" +} + +/* + CASE DESCRIPTION: Checking for exhaustive 'when' (all subtypes and objects (using type checking operator) covered). + DISCUSSION: is it correct that objects can be checked using the type checking operator? + */ +fun case_6(value: _SealedClassMixed): String = when (value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" + is _SealedMixedChildObject1 -> "" + is _SealedMixedChildObject2 -> "" + is _SealedMixedChildObject3 -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' on the empty sealed class (without subtypes). +fun case_7(value: _SealedClassEmpty): String = when (value) { + else -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/7.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/7.1.kt new file mode 100644 index 00000000000..5acea8fb535 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/7.1.kt @@ -0,0 +1,24 @@ +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [7] The bound expression is of an Enum classes type and all enumerated values are checked for equality using constant conditions; + NUMBER: 1 + DESCRIPTION: Check when exhaustive when all enumerated values are checked. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all enum values covered). +fun case_1(dir: _EnumClass): String = when (dir) { + _EnumClass.EAST -> "" + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> "" + _EnumClass.WEST -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (single enum value covered). +fun case_2(value: _EnumClassSingle): String = when (value) { + _EnumClassSingle.EVERYTHING -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.1.kt new file mode 100644 index 00000000000..538c4189f66 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.1.kt @@ -0,0 +1,23 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 1 + DESCRIPTION: Check when exhaustive when boolean values are checked and contains a null check. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (both boolean values and null value covered). +fun case_1(value: Boolean?): String = when (value) { + true -> "" + false -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (both boolean values as complex expressions and null value covered). +fun case_2(value: Boolean?): String = when (value) { + true && false && ((true || false)) || true && !!!false && !!!true -> "" + true && false && ((true || false)) || true && !!!false -> "" + null -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.2.kt new file mode 100644 index 00000000000..61de8d6e24e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.2.kt @@ -0,0 +1,26 @@ +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 2 + DESCRIPTION: Check when exhaustive when enumerated values are checked and contains a null check. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (both enum values and null value covered). +fun case_1(dir: _EnumClass?): String = when (dir) { + _EnumClass.EAST -> "" + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> "" + _EnumClass.WEST -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (single enum value and null value covered). +fun case_2(value: _EnumClassSingle?): String = when (value) { + _EnumClassSingle.EVERYTHING -> "" + null -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.3.kt new file mode 100644 index 00000000000..89a5a6f755e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.3.kt @@ -0,0 +1,66 @@ +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 11 + SENTENCE: [8] The bound expression is of a nullable type and one of the cases above is met for its non-nullable counterpart and, in addition, there is a condition containing literal null. + NUMBER: 3 + DESCRIPTION: Check when exhaustive when possible subtypes of the sealed class are covered and contains a null check. + */ + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all sealed class subtypes and null value covered). +fun case_1(expr: _SealedClass?): Int = when (expr) { + is _SealedChild1 -> expr.number + is _SealedChild2 -> expr.e1 + expr.e2 + is _SealedChild3 -> expr.m1 + expr.m2 + null -> 0 +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (sealed class itself and null value covered). +fun case_2(expr: _SealedClass?): String = when (expr) { + is _SealedClass -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all sealed class with methods subtypes and null value covered). +fun case_3(expr: _SealedClassWithMethods?): String = when (expr) { + is _SealedWithMethodsChild1 -> expr.m1() + is _SealedWithMethodsChild2 -> expr.m2() + is _SealedWithMethodsChild3 -> expr.m3() + null -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all objects covered using implicit equality operator and null value covered). +fun case_4(expr: _SealedClassWithObjects?): String = when (expr) { + _SealedWithObjectsChild1 -> "" + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> "" + null -> "" +} + +// CASE DESCRIPTION: Checking for exhaustive 'when' (all subtypes and objects covered + null value covered). +fun case_5(value: _SealedClassMixed?): String = when (value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" + _SealedMixedChildObject1 -> "" + _SealedMixedChildObject2 -> "" + _SealedMixedChildObject3 -> "" + null -> "" +} + +/* + CASE DESCRIPTION: Checking for exhaustive 'when' (all subtypes and objects (using type checking operator) covered + null value covered). + DISCUSSION: is it correct that objects can be checked using the type checking operator? + */ +fun case_6(value: _SealedClassMixed?): String = when (value) { + is _SealedMixedChild1 -> "" + is _SealedMixedChild2 -> "" + is _SealedMixedChild3 -> "" + is _SealedMixedChildObject1 -> "" + is _SealedMixedChildObject2 -> "" + is _SealedMixedChildObject3 -> "" + null -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.1.kt new file mode 100644 index 00000000000..d026af963a0 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.1.kt @@ -0,0 +1,13 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 2 + SENTENCE: [3] When expression has two different forms: with bound value and without it. + NUMBER: 1 + DESCRIPTION: Empty 'when' with bound value. + */ + +fun case_1(value: Int) { + when (value) {} +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.2.kt new file mode 100644 index 00000000000..5fc120e3eb6 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.2.kt @@ -0,0 +1,13 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 2 + SENTENCE: [3] When expression has two different forms: with bound value and without it. + NUMBER: 2 + DESCRIPTION: Empty 'when' without bound value. + */ + +fun case_1() { + when {} +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/1.1.kt new file mode 100644 index 00000000000..6095b620c1e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/1.1.kt @@ -0,0 +1,31 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [1] When expression without bound value (the form where the expression enclosed in parantheses is absent) evaluates one of the many different expressions based on corresponding conditions present in the same when entry. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and not allowed break and continue expression (without labels) in the control structure body. + */ + +// CASE DESCRIPTION: 'When' with break expression (without label). +fun case_1(value: Int): String { + while (true) { + when { + value == 1 -> break + } + } + + return "" +} + +// CASE DESCRIPTION: 'When' with continue expression (without label). +fun case_2(value: Int): String { + while (true) { + when { + value == 1 -> continue + } + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.1.kt new file mode 100644 index 00000000000..467c1a41ee8 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.1.kt @@ -0,0 +1,24 @@ +// !WITH_BASIC_TYPES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [2] Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and with not boolean condition in 'when condition'. + */ + +fun case_1(value1: Int, value2: String, value3: _BasicTypesProvider): String { + when { + .012f / value1 -> return "" + "$value2..." -> return "" + '-' -> return "" + {} -> return "" + value3.getAny() -> return "" + -10..-1 -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.2.kt new file mode 100644 index 00000000000..958213edb67 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.2.kt @@ -0,0 +1,21 @@ +// !WITH_BASIC_TYPES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [2] Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 2 + DESCRIPTION: 'When' without bound value and not allowed comma in when entry. + */ + +fun case_1(value1: _BasicTypesProvider) { + when { + getBoolean(), value1.getBoolean() -> return + value1.getBoolean() && getBoolean(), getLong() == 1000L -> return + value1.getList(), getLong(), {}, Any(), throw Exception() -> return + } + + return +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/1.1.kt new file mode 100644 index 00000000000..f207d299944 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/1.1.kt @@ -0,0 +1,321 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST +// !WITH_BASIC_TYPES +// !WITH_CLASSES +// !WITH_FUNS + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [1] When expression without bound value (the form where the expression enclosed in parantheses is absent) evaluates one of the many different expressions based on corresponding conditions present in the same when entry. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and with different variants of expressions in the control structure body. + */ + +// CASE DESCRIPTION: 'When' with control structure body as literals. +fun case_1(value: Int) { + when { + value == 1 -> true + value == 2 -> 100 + value == 3 -> -.09f + value == 4 -> '.' + value == 5 -> "..." + value == 6 -> null + } +} + +// CASE DESCRIPTION: 'When' with control structure body as arithmetic expressions. +fun case_2(value: Int, value1: Byte, value2: _BasicTypesProvider) { + when { + value == 1 -> -.09 % 10L + value == 3 -> value1 / -5 + value == 2 -> value2.getChar(99) - 11 + 90 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as boolean expressions (logical, equality and comparison). +fun case_3(value: Int, value1: Boolean, value2: Long) { + when { + value == 1 -> value1 + value == 2 -> !value1 + value == 3 -> getBoolean() && value1 + value == 5 -> getChar(10) != 'a' + value == 6 -> getList() === getAny() + value == 7 -> value2 <= 11 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as concatenations. +fun case_4(value: Int, value1: String, value2: String) { + when { + value == 1 -> "..." + value1 + "" + "$value2" + "..." + value == 2 -> value1 + getString() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as when expression. +fun case_5(value: Int, value1: Int, value2: Boolean?) { + when { + value == 1 -> when { + value1 > 1000 -> "1" + value1 > 100 -> "2" + else -> "3" + } + value == 2 -> when { + value1 > 1000 -> "1" + value1 > 100 -> "2" + } + value == 3 -> when {} + value == 4 -> when (value2) { + true -> "1" + false -> "2" + null -> "3" + } + value == 5 -> when (value2) { + true -> "1" + false -> "2" + } + value == 6 -> when (value2) {} + } +} + +// CASE DESCRIPTION: 'When' as expression with control structure body as when expression (must be exhaustive). +fun case_6(value: Int, value1: Int, value2: Boolean?) = when { + value == 1 -> when { + value1 > 1000 -> 1 + value1 > 100 -> 2 + else -> 3 + } + else -> when (value2) { + true -> 1 + false -> 2 + null -> 3 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as if expression. +fun case_7(value: Int, value1: Int, value2: Boolean?) { + when { + value == 1 -> if (value1 > 1000) "1" + value == 2 -> if (value1 > 1000) "1" + else "2" + value == 3 -> if (value1 < 100) "1" + else if (value1 < 10) "2" + else "4" + value == 4 -> if (value2 == null) "1" + else if (value2) "2" + else if (!value2) "3" + } +} + +// CASE DESCRIPTION: 'When' as expression with control structure body as if expression (must be exhaustive). +fun case_8(value: Int, value1: Int) = when { + value == 1 -> if (value1 > 1000) "1" + else "2" + else -> if (value1 < 100) "1" + else if (value1 < 10) "2" + else "4" +} + +// CASE DESCRIPTION: 'When' with control structure body as try expression. +fun case_9(value: Int, value1: String, value2: String) = when { + value == 1 -> try { 4 } catch (e: Exception) { 5 } + value == 2 -> try { throw Exception() } catch (e: Exception) { value1 } + else -> try { throw Exception() } catch (e: Exception) { {value2} } finally { } +} + +// CASE DESCRIPTION: 'When' with control structure body as elvis operator expression. +fun case_10(value: Int, value1: String?, value2: String?) { + when { + value == 1 -> value1 ?: true + value == 2 -> value1 ?: value2 ?: true + value == 3 -> value1!! ?: true + } +} + +// CASE DESCRIPTION: 'When' with control structure body as range expression. +fun case_11(value: Int) { + when { + value == 1 -> 1..10 + value == 2 -> -100L..100L + value == 3 -> -getInt()..getLong() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as cast expression. +fun case_12(value: Int, value1: Collection, value2: Collection?) { + when { + value == 1 -> value1 as MutableList + value == 2 -> value1 as? MutableList + value == 3 -> value2 as? MutableMap + value == 4 -> (value1 as? Map) as MutableMap + } +} + +// CASE DESCRIPTION: 'When' with control structure body as prefix operator expression. +fun case_13(value: Int, value1: Int, value2: Int, value3: Boolean) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when { + value == 1 -> ++mutableValue1 + value == 2 -> --mutableValue2 + value == 3 -> !value3 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as postfix operator expression. +fun case_14(value: Int, value1: Int, value2: Int, value3: Boolean?) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when { + value == 1 -> mutableValue1++ + value == 2 -> mutableValue2-- + value == 3 -> value3!! + } +} + +// CASE DESCRIPTION: 'When' with control structure body as indexing expression. +fun case_15(value: Int, value1: List, value2: List>>>) { + when { + value == 1 -> value1[0] + value == 2 -> value2[0][-4][1][-1] + } +} + +// CASE DESCRIPTION: 'When' with control structure body as call expression. +fun case_16(value: Int, value1: _Class, value2: _Class?, value3: Int) { + fun __fun_1(): () -> Unit { return fun() { } } + + when { + value == 1 -> _funWithoutArgs() + value == 2 -> __fun_1()() + value == 3 -> value1.fun_2(value3) + value == 4 -> value2?.fun_2(value3) + value == 5 -> value2!!.fun_2(value3) + } +} + +// CASE DESCRIPTION: 'When' with control structure body as property access expression. +fun case_17(value: Int, value1: _Class, value2: _Class?) { + when { + value == 1 -> value1.prop_1 + value == 2 -> value2?.prop_1 + value == 3 -> value1::prop_1.get() + value == 4 -> value2!!::prop_3.get() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as fun literal. +fun case_18(value: Int) { + val fun_1 = fun(): Int { return 0 } + + when { + value == 1 -> fun() {} + value == 2 -> fun(): Int { return 0 } + value == 3 -> fun(): () -> Unit { return fun() {} } + value == 4 -> fun_1 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as lambda literal. +fun case_19(value: Int): () -> Any { + val lambda_1 = { 0 } + + return when { + value == 1 -> lambda_1 + value == 2 -> { { {} } } + else -> { -> (Int) + { arg: Int -> { { println(arg) } } } + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as object literal. +fun case_20(value: Int) { + val object_1 = object { + val prop_1 = 1 + } + + when { + value == 1 -> object {} + value == 2 -> object { + private fun fun_1() { } + val prop_1 = 1 + } + value == 3 -> object_1 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as this expression. +class A { + val prop_1 = 1 + val lambda_1 = { 1 } + fun fun_1(): Int { return 1 } + + fun case_21(value: Int) { + when { + value == 1 -> this + value == 2 -> ((this)) + value == 3 -> this::prop_1.get() + value == 4 -> this.prop_1 + value == 5 -> this.lambda_1() + value == 6 -> this::lambda_1.get()() + value == 7 -> this.fun_1() + value == 8 -> this::fun_1.invoke() + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as throw expression. +fun case_22(value: Int) { + when { + value == 1 -> throw Exception() + value == 2 -> throw throw throw Exception() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as return expression. +fun case_23(value: Int) { + fun r_1() { + when { + value == 1 -> return + value == 2 -> return return return + } + } + + fun r_2(): List? { + when { + value == 1 -> return listOf(0, 1, 2) + value == 2 -> return null + } + + return null + } +} + +// CASE DESCRIPTION: 'When' with control structure body as continue expression. +fun case_24(value: Int) { + loop1@ while (true) { + loop2@ while (true) { + when { + value == 1 -> continue@loop1 + value == 2 -> continue@loop2 + } + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as break expression. +fun case_25(value: Int) { + loop1@ while (true) { + loop2@ while (true) { + when { + value == 1 -> break@loop1 + value == 2 -> break@loop2 + } + } + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.1.kt new file mode 100644 index 00000000000..bf750225f67 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.1.kt @@ -0,0 +1,124 @@ +// !WITH_BASIC_TYPES +// !WITH_SEALED_CLASSES +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [2] Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and different variants of the boolean conditions (logical, equality, comparison, type checking operator, containment operator). + */ + +// CASE DESCRIPTION: 'When' with boolean expressions and else branch. +fun case_1(value1: Boolean, value2: Long): Int { + return when { + value1 -> 1 + getBoolean() && value1 -> 2 + getChar(10) != 'a' -> 3 + getList() === getAny() -> 4 + value2 <= 11 -> 5 + !value1 -> 6 + else -> 7 + } +} + +/* + CASE DESCRIPTION: 'When' with boolean expressions. + NOTE: for potential analysys on exhaustive by enum of when without bound value. + */ +fun case_2(value: _EnumClass) { + when { + value == _EnumClass.NORTH -> {} + value == _EnumClass.SOUTH -> {} + value == _EnumClass.WEST -> {} + value == _EnumClass.EAST -> {} + } +} + +/* + CASE DESCRIPTION: 'When' with boolean expressions. + NOTE: for potential analysys on exhaustive by boolean of when without bound value. + */ +fun case_3(value: Boolean) { + when { + value == true -> return + value == false -> return + } +} + +/* + CASE DESCRIPTION: 'When' with boolean literals. + NOTE: for potential mark code after true branch as unreacable. + */ +fun case_4(value1: Boolean) { + when { + false -> return + true -> return + value1 -> return + } +} + +/* + CASE DESCRIPTION: 'When' with boolean constants. + NOTE: for potential const propagation use in this case. + */ +fun case_5(value1: Boolean) { + val value2 = false + val value3 = false || !!!false || false + + when { + value3 -> return + value2 -> return + value1 -> return + } +} + +// CASE DESCRIPTION: 'When' with type checking operator. +fun case_6(value: Any) { + when { + value is Nothing -> {} + value is Int -> {} + value is Boolean -> {} + value is String -> {} + value is Number -> {} + value is Float -> {} + value is Any -> {} + } +} + +/* + CASE DESCRIPTION: 'When' with invert type checking operator. + NOTE: for potential analysys on exhaustive of when without bound value. + */ +fun case_7(value: Any) { + when { + value !is Number -> {} + value is Float -> {} + value is Number -> {} + value is Any -> {} + } +} + +/* + CASE DESCRIPTION: 'When' with type checking operator by sealed class. + NOTE: for potential analysys on exhaustive by sealed class of when without bound value. + */ +fun case_8(value: _SealedClass) { + when { + value is _SealedChild1 -> {} + value is _SealedChild2 -> {} + value is _SealedChild3 -> {} + } +} + +// CASE DESCRIPTION: 'When' with containment operator. +fun case_9(value: Int, value1: IntRange) { + when { + value in -10..100L -> {} + value in value1 -> {} + value !in listOf(0, 1, 2) -> {} + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.2.kt new file mode 100644 index 00000000000..9b259920193 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.2.kt @@ -0,0 +1,21 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [2] Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 2 + DESCRIPTION: 'When' without bound value and only one 'else' branch. + */ + +// CASE DESCRIPTION: 'When' as expression with only one 'else' branch. +fun case_1() = when { + else -> "" +} + +// CASE DESCRIPTION: 'When' as statement with only one 'else' branch. +fun case_2(): String { + when { + else -> return "" + } +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.3.kt new file mode 100644 index 00000000000..e198b5085b5 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.3.kt @@ -0,0 +1,97 @@ +// !WITH_BASIC_TYPES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 3 + SENTENCE: [2] Each entry consists of a boolean condition (or a special else condition), each of which is checked and evaluated in order of appearance. + NUMBER: 3 + DESCRIPTION: 'When' without bound value and with Nothing in condition (subtype of Boolean). + UNEXPECTED BEHAVIOUR + ISSUES: KT-25948 + */ + +// CASE DESCRIPTION: 'When' with return expression in condition. +fun case_1(value1: _BasicTypesProvider) { + when { + return -> return + return == return -> return + return return return -> return + return != 10L -> return + return || return && return -> return + } +} + +// CASE DESCRIPTION: 'When' with throw expression in condition. +fun case_2(value1: _BasicTypesProvider) { + when { + throw Exception() -> return + (throw Exception()) == (throw Exception()) -> return + (throw Exception()) && (throw Exception()) || (throw Exception()) -> return + (throw Exception()) == 10L -> return + throw throw throw throw Exception() -> return + } +} + +// CASE DESCRIPTION: 'When' with break expression in condition. +fun case_3(value1: _BasicTypesProvider) { + loop1@ while (true) { + loop2@ while (true) { + loop3@ while (true) { + when { + break@loop1 == break@loop2 -> return + break@loop2 || break@loop1 && break@loop3 -> return + break@loop2 != 10L -> return + } + } + } + } +} + +// CASE DESCRIPTION: 'When' with continue expression in condition. +fun case_4(value1: _BasicTypesProvider): String { + loop1@ while (true) { + loop2@ while (true) { + loop3@ while (true) { + when { + continue@loop1 == continue@loop2 -> return "" + continue@loop2 || continue@loop1 && continue@loop3 -> return "" + continue@loop2 != 10L -> return "" + } + } + } + } +} + +// CASE DESCRIPTION: 'When' with values of Nothing type. +fun case_6(value1: Nothing, value2: _BasicTypesProvider): String { + when { + value1 -> return "" + value2.getNothing() -> return "" + getNothing() -> return "" + value1 && (getNothing() == value2.getNothing()) -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' with mixed Nothing expression in condition. +fun case_5(value1: _BasicTypesProvider, value2: Nothing) { + loop1@ while (true) { + loop2@ while (true) { + loop3@ while (true) { + when { + continue@loop1 == throw throw throw throw Exception() -> return + (return return return return) || break@loop1 && break@loop3 -> return + continue@loop1 != 10L && (return return) == continue@loop1 -> return + return continue@loop1 -> return + (throw break@loop1) && break@loop3 -> return + (throw getNothing()) && value1.getNothing() -> return + return return return value2 -> return + getNothing() != 10L && (return return) == value2 -> return + } + } + } + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg/1.1.kt new file mode 100644 index 00000000000..0a8c8f81177 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg/1.1.kt @@ -0,0 +1,32 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 5 + SENTENCE: [1] The else entry is also special in the sense that it must be the last entry in the expression, otherwise a compiler error must be generated. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and with 'else' branch not in the last position. + */ + +// CASE DESCRIPTION: 'When' with 'else' branch in the first position. +fun case_1(value: Int): String = when { + else -> "" + value == 1 -> "" +} + +// CASE DESCRIPTION: 'When' with 'else' branch in the middle position. +fun case_2(value: Int): String = when { + value == 1 -> "" + else -> "" + value == 2 -> "" +} + +// CASE DESCRIPTION: 'When' with two 'else' branches. +fun case_3(): String { + when { + else -> return "" + else -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos/1.1.kt new file mode 100644 index 00000000000..2b51b5d5ddf --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos/1.1.kt @@ -0,0 +1,25 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 5 + SENTENCE: [1] The else entry is also special in the sense that it must be the last entry in the expression, otherwise a compiler error must be generated. + NUMBER: 1 + DESCRIPTION: 'When' without bound value and with else branch in the last position. + */ + +// CASE DESCRIPTION: 'When' with else branch as statement +fun case_1(value: Int): String { + when { + value == 1 -> return "" + value == 2 -> return "" + else -> return "" + } +} + +// CASE DESCRIPTION: 'When' with else branch as expression +fun case_2(value: Int): String = when { + value == 1 -> "" + value == 2 -> "" + else -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg/1.1.kt new file mode 100644 index 00000000000..2611ebf15f3 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg/1.1.kt @@ -0,0 +1,33 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 6 + SENTENCE: [1] When expression with bound value (the form where the expression enclosed in parantheses is present) are very similar to the form without bound value, but use different syntax for conditions. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and not allowed break and continue expression (without labels) in the control structure body. + */ + +// CASE DESCRIPTION: 'When' with break expression (without label). +fun case_1(value: Int): Int { + while (true) { + when (value) { + 1 -> return 1 + 2 -> break + } + } + + return 0 +} + +// CASE DESCRIPTION: 'When' with continue expression (without label). +fun case_2(value: Int): Int { + while (true) { + when (value) { + 1 -> continue + 2 -> return 1 + } + } + + return 0 +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos/1.1.kt new file mode 100644 index 00000000000..85b59ad0ec5 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos/1.1.kt @@ -0,0 +1,324 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_BASIC_TYPES +// !WITH_FUNS +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 6 + SENTENCE: [1] When expression with bound value (the form where the expression enclosed in parantheses is present) are very similar to the form without bound value, but use different syntax for conditions. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and with different variants of expressions in the control structure body. + */ + +// CASE DESCRIPTION: 'When' with control structure body as literals. +fun case_1(value: Int) { + when (value) { + 1 -> true + 2 -> 100 + 3 -> -.09f + 4 -> '.' + 5 -> "..." + 6 -> null + } +} + +// CASE DESCRIPTION: 'When' with control structure body as arithmetic expressions. +fun case_2(value: Int, value1: Byte, value2: _BasicTypesProvider) { + when (value) { + 1 -> -.09 % 10L + 3 -> value1 / -5 + 2 -> value2.getChar(99) - 11 + 90 + 4 -> 100 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as boolean expressions (logical, equality and comparison). +fun case_3(value: Int, value1: Boolean, value2: Long) { + when (value) { + 1 -> value1 + 2 -> !value1 + 3 -> getBoolean() && value1 + 5 -> getChar(10) != 'a' + 6 -> getList() === getAny() + 7 -> value2 <= 11 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as concatenations. +fun case_4(value: Int, value1: String, value2: String) { + when (value) { + 1 -> "..." + value1 + "" + "$value2" + "..." + 2 -> value1 + getString() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as when expression. +fun case_5(value: Int, value1: Int, value2: Boolean?) { + when (value) { + 1 -> when (value2) { + value1 > 1000 -> "1" + value1 > 100 -> "2" + else -> "3" + } + 2 -> when (value2) { + value1 > 1000 -> "1" + value1 > 100 -> "2" + } + 3 -> when (value2) {} + 4 -> when (value2) { + true -> "1" + false -> "2" + null -> "3" + } + 5 -> when (value2) { + true -> "1" + false -> "2" + } + 6 -> when (value2) {} + } +} + +// CASE DESCRIPTION: 'When' as expression with control structure body as when expression (must be exhaustive). +fun case_6(value: Int, value1: Int, value2: Boolean?) = when (value) { + 1 -> when (value2) { + value1 > 1000 -> 1 + value1 > 100 -> 2 + else -> 3 + } + else -> when (value2) { + true -> 1 + false -> 2 + null -> 3 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as if expression. +fun case_7(value: Int, value1: Int, value2: Boolean?) { + when (value) { + 1 -> if (value1 > 1000) "1" + 2 -> if (value1 > 1000) "1" + else "2" + 3 -> if (value1 < 100) "1" + else if (value1 < 10) "2" + else "4" + 4 -> if (value2 == null) "1" + else if (value2) "2" + else if (!value2) "3" + } +} + +// CASE DESCRIPTION: 'When' as expression with control structure body as if expression (must be exhaustive). +fun case_8(value: Int, value1: Int) = when (value) { + 1 -> if (value1 > 1000) "1" + else "2" + else -> if (value1 < 100) "1" + else if (value1 < 10) "2" + else "4" +} + +// CASE DESCRIPTION: 'When' with control structure body as try expression. +fun case_9(value: Int, value1: String, value2: String): Any { + return when (value) { + 1 -> try { 4 } catch (e: Exception) { 5 } + 2 -> try { throw Exception() } catch (e: Exception) { value1 } + else -> try { throw Exception() } catch (e: Exception) { {value2} } finally { } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as elvis operator expression. +fun case_10(value: Int, value1: String?, value2: String?) { + when (value) { + 1 -> value1 ?: true + 2 -> value1 ?: value2 ?: true + 3 -> value1!! ?: true + } +} + +// CASE DESCRIPTION: 'When' with control structure body as range expression. +fun case_11(value: Int) { + when (value) { + 1 -> 1..10 + 2 -> -100L..100L + 3 -> -getInt()..getLong() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as cast expression. +fun case_12(value: Int, value1: Collection, value2: Collection?) { + when (value) { + 1 -> value1 as MutableList + 2 -> value1 as? MutableList + 3 -> value2 as? MutableMap + 4 -> (value1 as? Map) as MutableMap + } +} + +// CASE DESCRIPTION: 'When' with control structure body as prefix operator expression. +fun case_13(value: Int, value1: Int, value2: Int, value3: Boolean) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + 1 -> ++mutableValue1 + 2 -> --mutableValue2 + 3 -> !value3 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as postfix operator expression. +fun case_14(value: Int, value1: Int, value2: Int, value3: Boolean?) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + 1 -> mutableValue1++ + 2 -> mutableValue2-- + 3 -> value3!! + } +} + +// CASE DESCRIPTION: 'When' with control structure body as indexing expression. +fun case_15(value: Int, value1: List, value2: List>>>) { + when (value) { + 1 -> value1[0] + 2 -> value2[0][-4][1][-1] + } +} + +// CASE DESCRIPTION: 'When' with control structure body as call expression. +fun case_16(value: Int, value1: _Class, value2: _Class?, value3: Int) { + fun __fun_1(): () -> Unit { return fun() { } } + + when (value) { + 1 -> _funWithoutArgs() + 2 -> __fun_1()() + 3 -> value1.fun_2(value3) + 4 -> value2?.fun_2(value3) + 5 -> value2!!.fun_2(value3) + } +} + +// CASE DESCRIPTION: 'When' with control structure body as property access expression. +fun case_17(value: Int, value1: _Class, value2: _Class?) { + when (value) { + 1 -> value1.prop_1 + 2 -> value2?.prop_1 + 3 -> value1::prop_1.get() + 4 -> value2!!::prop_3.get() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as fun literal. +fun case_18(value: Int) { + val fun_1 = fun(): Int { return 0 } + + when (value) { + 1 -> fun() {} + 2 -> fun(): Int { return 1 } + 3 -> fun(): () -> Unit { return fun() {} } + 4 -> fun_1 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as lambda literal. +fun case_19(value: Int): Any { + val lambda_1 = { 0 } + + return when (value) { + 1 -> lambda_1 + 2 -> { { {} } } + else -> { -> (Int) + { arg: Int -> { { println(arg) } } } + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as object literal. +fun case_20(value: Int) { + val object_1 = object { + val prop_1 = 1 + } + + when (value) { + 1 -> object {} + 2 -> object { + private fun fun_1() { } + val prop_1 = 1 + } + 3 -> object_1 + } +} + +// CASE DESCRIPTION: 'When' with control structure body as this expression. +class A { + val prop_1 = 1 + val lambda_1 = { 1 } + fun fun_1(): Int { return 1 } + + fun case_21(value: Int) { + when (value) { + 1 -> this + 2 -> ((this)) + 3 -> this::prop_1.get() + 4 -> this.prop_1 + 5 -> this.lambda_1() + 6 -> this::lambda_1.get()() + 7 -> this.fun_1() + 8 -> this::fun_1.invoke() + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as throw expression. +fun case_22(value: Int) { + when (value) { + 1 -> throw Exception() + 2 -> throw throw throw Exception() + } +} + +// CASE DESCRIPTION: 'When' with control structure body as return expression. +fun case_23(value: Int) { + fun r_1() { + when (value) { + 1 -> return + 2 -> return return return + } + } + + fun r_2(): List? { + when (value) { + 1 -> return listOf(0, 1, 2) + 2 -> return null + } + + return null + } +} + +// CASE DESCRIPTION: 'When' with control structure body as continue expression. +fun case_24(value: Int) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + 1 -> continue@loop1 + 2 -> continue@loop2 + } + } + } +} + +// CASE DESCRIPTION: 'When' with control structure body as break expression. +fun case_25(value: Int) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + 1 -> break@loop1 + 2 -> break@loop2 + } + } + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.1.kt new file mode 100644 index 00000000000..b1b0731cbc1 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.1.kt @@ -0,0 +1,38 @@ +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and type test condition (without companion object in classes), but without type checking operator. + */ + +// CASE DESCRIPTION: 'When' with custom class type test condition. +fun case_1(value: Any): String { + when (value) { + _EmptyClass -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' with Any type test condition. +fun case_2(value: Any): String { + when (value) { + Any -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' with Nothing type test condition. +fun case_3(value: Any): String { + when (value) { + Nothing -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.2.kt new file mode 100644 index 00000000000..b2783880367 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.2.kt @@ -0,0 +1,19 @@ +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 2 + DESCRIPTION: 'When' with bound value and type test condition on the non-type operand of the type checking operator. + */ + +fun case_1(value: Any, value1: Int): String { + when (value) { + is value1 -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.1.kt new file mode 100644 index 00000000000..cc5e9392e8f --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.1.kt @@ -0,0 +1,20 @@ +// !WITH_BASIC_TYPES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [3] Contains test condition: containment operator followed by an expression. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and 'when condition' with range expression, but without containment checking operator. + */ + +fun case_1(value: Int, value1: _BasicTypesProvider): String { + when (value) { + -1000L..100 -> return "" + value1.getInt()..getLong() -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.2.kt new file mode 100644 index 00000000000..088eda81cc4 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.2.kt @@ -0,0 +1,36 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [3] Contains test condition: containment operator followed by an expression. + NUMBER: 2 + DESCRIPTION: 'When' with bound value and 'when condition' with contains operator and type without defined contains operator. + */ + +// CASE DESCRIPTION: 'When' with values of types without defined contains operator. +fun case_1(value: Int, value1: _EmptyClass, value2: Int, value3: Any): String { + when (value) { + in value1 -> return "" + in value2 -> return "" + in value3 -> return "" + } + + return "" +} + +/* + CASE DESCRIPTION: 'When' with values of Nothing (all existing contains operators used here). + UNEXPECTED BEHAVIOUR + ISSUES: KT-25948 + */ +fun case_2(value: Int, value3: Nothing) { + when (value) { + in value3 -> {} + in throw Exception() -> {} + in return -> {} + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.1.kt new file mode 100644 index 00000000000..bec35f82af3 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.1.kt @@ -0,0 +1,35 @@ +// !DIAGNOSTICS: -UNUSED_VALUE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [5] Any other expression. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and non-expressions in 'when condition'. + */ + +// CASE DESCRIPTION: 'When' with cycles in when condition. +fun case_1(value: Int, value1: List): String { + when (value) { + while (false) {} -> return "" + do {} while (false) -> return "" + for (value2 in value1) {} -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' with assignments in when condition. +fun case_4(value: Int): String { + var value1: Int + var value2 = 10 + + when (value) { + value1 = 10 -> return "" + value2 %= 10 -> return "" + } + + return "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.2.kt new file mode 100644 index 00000000000..51f9f81d1a0 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.2.kt @@ -0,0 +1,31 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [5] Any other expression. + NUMBER: 2 + DESCRIPTION: 'When' with bound value and not allowed break and continue expression (without labels) in 'when condition'. + */ + +// CASE DESCRIPTION: 'When' with break expression (without label). +fun case_1(value: Int): String { + while (true) { + when (value) { + break -> return "" + } + } + + return "" +} + +// CASE DESCRIPTION: 'When' with continue expression (without label). +fun case_2(value: Int): String { + while (true) { + when (value) { + continue -> return "" + } + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/7.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/7.1.kt new file mode 100644 index 00000000000..31da9912a5e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/7.1.kt @@ -0,0 +1,34 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [7] The else condition, which works the exact same way as it would in the form without bound expression. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and with else branch not in the last position. + */ + +// CASE DESCRIPTION: 'When' with 'else' branch in the first position. +fun case_1(value: Int): String = when (value) { + else -> "" + 1 -> "" +} + +// CASE DESCRIPTION: 'When' with 'else' branch in the middle position. +fun case_2(value: Int): String = when (value) { + 1 -> "" + else -> "" + 2 -> "" +} + +// CASE DESCRIPTION: 'When' with two 'else' branches. +fun case_3(value: Int): String { + when (value) { + else -> return "" + else -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.1.kt new file mode 100644 index 00000000000..8d652369b5d --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.1.kt @@ -0,0 +1,70 @@ +// !WITH_CLASSES +// !WITH_OBJECTS + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and type test condition. + */ + +// CASE DESCRIPTION: 'When' with type test condition on the various basic types. +fun case_1(value: Any): String { + when (value) { + is Int -> return "" + is Float -> return "" + is Double -> return "" + is String -> return "" + is Char -> return "" + is Boolean -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' with type test condition on the various nullable basic types. +fun case_2(value: Any?): String = when (value) { + is Int? -> "" // if value is null then this branch will be executed + is Float -> "" + else -> "" +} + +// CASE DESCRIPTION: 'When' with 'else' branch and type test condition on Any. +fun case_3(value: Any?): String = when (value) { + is Any -> "" + else -> "" +} + +// CASE DESCRIPTION: 'When' with 'else' branch and type test condition on nullable (redundant) Any. +fun case_4(value: Any): String = when (value) { + is Any? -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types (two nullable type check). + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_5(value: Any?): String = when (value) { + is Double -> "" + is Int? -> "" // if value is null then this branch will be executed + is String -> "" + is Float? -> "" // redundant nullable type check + is Char -> "" + is Boolean -> "" + else -> "" +} + +// CASE DESCRIPTION: 'When' with type test condition on the objetcs. +fun case_6(value: Any): String { + when (value) { + is _EmptyObject -> return "" + is _ClassWithCompanionObject.Companion -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.2.kt new file mode 100644 index 00000000000..97973c96d9e --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.2.kt @@ -0,0 +1,60 @@ +// !WITH_SEALED_CLASSES +// !WITH_CLASSES +// !WITH_OBJECTS + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 2 + DESCRIPTION: 'When' with bound value and type test condition (invert type checking operator). + */ + +// CASE DESCRIPTION: 'When' in which all branches includes invert type checking operators. +fun case_1(value: _SealedClass) = when (value) { + !is _SealedChild1 -> {} + !is _SealedChild2 -> {} + !is _SealedChild3 -> {} +} + +/* + CASE DESCRIPTION: 'When' with direct and invert (with null-check) type checking operators on the same types and redundant null-check. + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_2(value: _SealedClass?): String = when (value) { + !is _SealedChild2 -> "" // including null + is _SealedChild2 -> "" + null -> "" // redundant +} + +// CASE DESCRIPTION: 'When' with direct and invert type checking operators on the same types and null-check. +fun case_3(value: _SealedClass?): String = when (value) { + !is _SealedChild2? -> "" // null isn't included + is _SealedChild2 -> "" + null -> "" +} + +/* + CASE DESCRIPTION: 'When' with direct and invert (with null-check) type checking operators on the same types. + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_4(value: _SealedClass?) { + when (value) { + !is _SealedChild2 -> {} // including null + is _SealedChild2? -> {} // redundant nullable type check + } +} + +// CASE DESCRIPTION: 'When' with direct and invert type checking operator on the objects. +fun case_5(value: Any): String { + when (value) { + is _EmptyObject -> return "" + !is _ClassWithCompanionObject.Companion -> return "" + } + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.3.kt new file mode 100644 index 00000000000..780d9cff526 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.3.kt @@ -0,0 +1,77 @@ +// !WITH_CLASSES +// !WITH_SEALED_CLASSES +// !WITH_OBJECTS + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 3 + DESCRIPTION: 'When' with bound value and enumaration of type test conditions. + */ + +// CASE DESCRIPTION: 'When' with type test condition on the various basic types. +fun case_1(value: Any) = when (value) { + is Int -> {} + is Float, is Char, is Boolean -> {} + is String -> {} + else -> {} +} + +// CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types. +fun case_2(value: Any?) = when (value) { + is Float, is Char, is _SealedClass? -> "" // if value is null then this branch will be executed + is Double, is Boolean, is _ClassWithCompanionObject.Companion -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types (two nullable type check in the different branches). + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_3(value: Any?) = when (value) { + is Float, is Char, is Int? -> "" // if value is null then this branch will be executed + is _SealedChild2, is Boolean?, is String -> "" // redundant nullable type check + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types (two nullable type check in the one branch). + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_4(value: Any?) = when (value) { + is Float, is Char?, is Int? -> "" // double nullable type check in the one branch + is _SealedChild1, is Boolean, is String -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types (two nullable type check). + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_5(value: Any?): String { + when (value) { + is Float, is Char?, is Int -> return "" + is Double, is _EmptyObject, is String -> return "" + null -> return "" // null-check redundant + else -> return "" + } +} + +/* + CASE DESCRIPTION: 'When' with 'else' branch and type test condition on the various nullable basic types (two different nullable type check in the one branch). + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_6(value: Any?): String { + when (value) { + is Float, is Char?, null, is Int -> return "" // double nullable type check in the one branch + is Double, is _EmptyObject, is String -> return "" + else -> return "" + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.4.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.4.kt new file mode 100644 index 00000000000..2ab17dc869a --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.4.kt @@ -0,0 +1,59 @@ +// !WITH_SEALED_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [1] Type test condition: type checking operator followed by type. + NUMBER: 4 + DESCRIPTION: 'When' with bound value and enumaration of type test conditions (with invert type checking operator). + */ + +// CASE DESCRIPTION: 'When' with direct and invert type checking operator in the one branch and other branch. +fun case_1(value: _SealedClass): String = when (value) { + is _SealedChild1, !is _SealedChild3 -> "" + is _SealedChild3 -> "" +} + +// CASE DESCRIPTION: 'When' with three invert type checking operator in the one branch. +fun case_2(value: _SealedClass) = when (value) { + !is _SealedChild1, !is _SealedChild2, !is _SealedChild3 -> {} +} + +// CASE DESCRIPTION: 'When' with direct (first) and invert (second) type checking operator on the some type in the one branch. +fun case_3(value: _SealedClass): String = when (value) { + is _SealedChild2, !is _SealedChild2 -> "" +} + +// CASE DESCRIPTION: 'When' with direct (second) and invert (first) type checking operator in the one branch. +fun case_4(value: _SealedClass): String = when (value) { + !is _SealedChild1, is _SealedChild1 -> "" +} + +// CASE DESCRIPTION: 'When' with direct and invert (nullable) type checking operator on the some type in the one branch. +fun case_5(value: Any?): String = when (value) { + is _SealedChild3, !is _SealedChild3? -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with direct and invert type checking operator in the one branch and other branch and double nullable type check. + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_6(value: Any?): String = when (value) { + is Boolean?, !is _SealedChild3 -> "" // double nullable type check in the one branch + is _SealedChild3 -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with direct and invert type checking operator and null-check in the one branch. + UNEXPECTED BEHAVIOUR + ISSUES: KT-22996 + */ +fun case_7(value: Any?): String = when (value) { + is Number?, null, !is _SealedChild3 -> "" // triple nullable type check in the one branch + else -> "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.1.kt new file mode 100644 index 00000000000..a6c1f0397ff --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.1.kt @@ -0,0 +1,32 @@ +// !WITH_BASIC_TYPES +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [3] Contains test condition: containment operator followed by an expression. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and containment operator. + */ + +// CASE DESCRIPTION: 'When' with range operator. +fun case_1(value: Int, value1: Int, value2: Short): String { + when (value) { + in Long.MIN_VALUE..-100 -> return "" + in -99..0 -> return "" + !in 100.toByte()..value1 -> return "" + in value1..value2 -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' on types with contains method defined. +fun case_2(value: Int, value1: List, value2: _Class) = when (value) { + in value1[0] -> "" + !in listOf(0, 1, 2, 3, 4) -> "" + !in value2.getIntArray(90) -> "" + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.2.kt new file mode 100644 index 00000000000..2e35fbab1b6 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.2.kt @@ -0,0 +1,28 @@ +// !WITH_BASIC_TYPES +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [3] Contains test condition: containment operator followed by an expression. + NUMBER: 2 + DESCRIPTION: 'When' with bound value and enumeration of the containment operators. + */ + +// CASE DESCRIPTION: 'When' with range operator. +fun case_1(value: Int, value1: Int, value2: Short): String { + when (value) { + in Long.MIN_VALUE..-100, in -99..0 -> return "" + !in 100.toByte()..value1, in value1..value2 -> return "" + } + + return "" +} + +// CASE DESCRIPTION: 'When' on types with contains method defined. +fun case_2(value: Int, value1: List, value2: _Class) = when (value) { + !in value1[0], !in listOf(0, 1, 2, 3, 4), !in value2.getIntArray(90) -> "" + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.1.kt new file mode 100644 index 00000000000..510aae7bfe1 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.1.kt @@ -0,0 +1,288 @@ +// !WITH_BASIC_TYPES +// !WITH_FUNS +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [5] Any other expression. + NUMBER: 1 + DESCRIPTION: 'When' with enumeration of the different variants of expressions in 'when condition'. + */ + +// CASE DESCRIPTION: 'When' with condition as literals. +fun case_1(value: Any?) { + when (value) { + true -> {} + 100 -> {} + -.09f -> {} + '.' -> {} + "..." -> {} + null -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as arithmetic expressions. +fun case_2(value: Number, value1: Int) { + when (value) { + -.09 % 10L -> {} + value1 / -5 -> {} + getByte(99) - 11 + 90 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as boolean expressions (logical, equality and comparison). +fun case_3(value: Boolean, value1: Boolean, value2: Long) { + when (value) { + value1 -> {} + !value1 -> {} + getBoolean() && value1 -> {} + getChar(10) != 'a' -> {} + getList() === getAny() -> {} + value2 <= 11 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as concatenations. +fun case_4(value: String, value1: String, value2: String) { + when (value) { + "..." + value1 + "" + "$value2" + "..." -> {} + value1 + getString() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as when expression. +fun case_5(value: Int, value1: Int, value2: Boolean?) { + when (value) { + when { + value1 > 1000 -> 1 + value1 > 100 -> 2 + else -> 3 + } -> {} + when (value2) { + true -> 1 + false -> 2 + null -> 3 + } -> {} + when (value2!!) { + true -> 1 + false -> 2 + } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as if expression. +fun case_6(value: Int, value1: Int) { + when (value) { + if (value1 > 1000) 1 + else 2 -> {} + if (value1 < 100) 1 + else if (value1 < 10) 2 + else 3 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as try expression. +fun case_7(value: Any, value1: String, value2: String) { + when (value) { + try { 4 } catch (e: Exception) { 5 } -> {} + try { throw Exception() } catch (e: Exception) { value1 } -> {} + try { throw Exception() } catch (e: Exception) { {value2} } finally { } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as elvis operator expression. +fun case_8(value: Int, value1: Int?, value2: Int?) { + when (value) { + value1 ?: 0 -> {} + value1 ?: value2 ?: 0 -> {} + value1!! ?: 0 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as range expression. +fun case_9(value: Any) { + when (value) { + 1..10 -> {} + -100L..100L -> {} + -getInt()..getLong() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as cast expression. +fun case_10(value: Collection, value1: Collection, value2: Collection?) { + when (value) { + value1 as MutableList -> {} + value1 as? MutableList -> {} + value2 as? MutableMap -> {} + (value1 as? Map) as MutableMap -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as prefix operator expression. +fun case_11(value: Any, value1: Int, value2: Int, value3: Boolean) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + ++mutableValue1 -> {} + --mutableValue2 -> {} + !value3 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as postfix operator expression. +fun case_12(value: Int, value1: Int, value2: Int, value3: Int?) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + mutableValue1++ -> {} + mutableValue2-- -> {} + value3!! -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as indexing expression. +fun case_13(value: Int, value1: List, value2: List>>>) { + when (value) { + value1[0] -> {} + value2[0][-4][1][-1] -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as call expression. +fun case_14(value: Any, value1: _Class, value2: _Class?, value3: Int) { + fun __fun_1(): () -> Any { return fun() { } } + + when (value) { + _funWithoutArgs() -> {} + __fun_1()() -> {} + value1.fun_2(value3) -> {} + value2?.fun_2(value3) -> {} + value2!!.fun_2(value3) -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as property access expression. +fun case_15(value: Int, value1: _Class, value2: _Class?) { + when (value) { + value1.prop_1 -> {} + value2?.prop_2 -> {} + value1::prop_1.get() -> {} + value2!!::prop_3.get() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as fun literal. +fun case_16(value: () -> Any): Any { + val fun_1 = fun() { return } + + return when (value) { + fun() {} -> {} + fun() { return } -> {} + fun(): () -> Unit { return fun() {} } -> {} + fun_1 -> {} + else -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as lambda literal. +fun case_17(value: () -> Any) { + val lambda_1 = { 0 } + + when (value) { + lambda_1 -> {} + { { {} } } -> {} + { -> (Int) + { arg: Int -> { { println(arg) } } } + } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as object literal. +fun case_18(value: Any) { + val object_1 = object { + val prop_1 = 1 + } + + when (value) { + object {} -> {} + object { + private fun fun_1() { } + val prop_1 = 1 + } -> {} + object_1 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as this expression. +class A { + val prop_1 = 1 + val lambda_1 = { 1 } + fun fun_1(): Int { return 1 } + + fun case_19(value: Any) { + when (value) { + this -> {} + ((this)) -> {} + this::prop_1.get() -> {} + this.prop_1 -> {} + this.lambda_1() -> {} + this::lambda_1.get()() -> {} + this.fun_1() -> {} + this::fun_1.invoke() -> {} + } + } +} + +// CASE DESCRIPTION: 'When' with condition as throw expression. +fun case_20(value: Nothing) { + when (value) { + throw Exception() -> {} + throw throw throw Exception() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as return expression. +fun case_21(value: Nothing) { + fun r_1() { + when (value) { + return -> 1 + return return return -> 2 + } + } + + fun r_2(): List? { + when (value) { + return listOf(0, 1, 2) -> 1 + return null -> 2 + } + } +} + +// CASE DESCRIPTION: 'When' with condition as continue expression. +fun case_22(value: Nothing) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + continue@loop1 -> 1 + continue@loop2 -> 2 + } + } + } +} + +// CASE DESCRIPTION: 'When' with condition as break expression. +fun case_23(value: Nothing) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + break@loop1 -> 1 + break@loop2 -> 2 + } + } + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.2.kt new file mode 100644 index 00000000000..09cccb2c59c --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.2.kt @@ -0,0 +1,265 @@ +// !WITH_BASIC_TYPES +// !WITH_CLASSES +// !WITH_FUNS + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [5] Any other expression. + NUMBER: 2 + DESCRIPTION: 'When' with different variants of the arithmetic expressions (additive expression and multiplicative expression) in 'when condition'. + */ + +// CASE DESCRIPTION: 'When' with condition as literals. +fun case_1(value: Any?) { + when (value) { + true, 100, -.09f -> {} + '.', "...", null -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as arithmetic expressions. +fun case_2(value: Number, value1: Int) { + when (value) { + -.09 % 10L, value1 / -5, getByte(99) - 11 + 90 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as boolean expressions (logical, equality and comparison). +fun case_3(value: Boolean, value1: Boolean, value2: Long) { + when (value) { + value1, !value1, getBoolean() && value1, getChar(10) != 'a' -> {} + getList() === getAny(), value2 <= 11 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as concatenations. +fun case_4(value: String, value1: String, value2: String) { + when (value) { + "..." + value1 + "" + "$value2" + "...", value1 + getString() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as when expression. +fun case_5(value: Int, value1: Int, value2: Boolean?) { + when (value) { + when { + value1 > 1000 -> 1 + value1 > 100 -> 2 + else -> 3 + }, when (value2) { + true -> 1 + false -> 2 + null -> 3 + }, when (value2!!) { + true -> 1 + false -> 2 + } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as if expression. +fun case_6(value: Int, value1: Int) { + when (value) { + if (value1 > 1000) 1 else 2, if (value1 < 100) 1 else if (value1 < 10) 2 else 3 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as try expression. +fun case_7(value: Any, value1: String, value2: String) { + when (value) { + try { 4 } catch (e: Exception) { 5 }, try { throw Exception() } catch (e: Exception) { value1 }, try { throw Exception() } catch (e: Exception) { {value2} } finally { } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as elvis operator expression. +fun case_8(value: Int, value1: Int?, value2: Int?) { + when (value) { + value1 ?: 0, value1 ?: value2 ?: 0, value1!! ?: 0 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as range expression. +fun case_9(value: Any) { + when (value) { + 1..10, -100L..100L, -getInt()..getLong() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as cast expression. +fun case_10(value: Collection, value1: Collection, value2: Collection?) { + when (value) { + value1 as MutableList, value1 as? MutableList -> {} + value2 as? MutableMap, (value1 as? Map) as MutableMap -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as prefix operator expression. +fun case_11(value: Any, value1: Int, value2: Int, value3: Boolean) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + ++mutableValue1, --mutableValue2, !value3 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as postfix operator expression. +fun case_12(value: Int, value1: Int, value2: Int, value3: Int?) { + var mutableValue1 = value1 + var mutableValue2 = value2 + + when (value) { + mutableValue1++, mutableValue2--, value3!! -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as indexing expression. +fun case_13(value: Int, value1: List, value2: List>>>) { + when (value) { + value1[0], value2[0][-4][1][-1] -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as call expression. +fun case_14(value: Any, value1: _Class, value2: _Class?, value3: Int) { + fun __fun_1(): () -> Unit { return fun() { } } + + when (value) { + _funWithoutArgs(), __fun_1()(), value1.fun_2(value3) -> {} + value2?.fun_2(value3), value2!!.fun_2(value3) -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as property access expression. +fun case_15(value: Int, value1: _Class, value2: _Class?) { + when (value) { + value1.prop_1, value2?.prop_2 -> {} + value1::prop_1.get(), value2!!::prop_3.get() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as fun literal. +fun case_16(value: () -> Any): Any { + val fun_1 = fun() { return } + + return when (value) { + fun() {}, fun() { return }, fun(): () -> Unit { return fun() {} }, fun_1 -> {} + else -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as lambda literal. +fun case_17(value: () -> Any) { + val lambda_1 = { 0 } + + when (value) { + lambda_1, { { {} } }, { -> (Int) + { arg: Int -> { { println(arg) } } } } -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as object literal. +fun case_18(value: Any) { + val object_1 = object { + val prop_1 = 1 + } + + when (value) { + object {}, object { + private fun fun_1() { } + val prop_1 = 1 + }, object_1 -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as this expression. +class A { + val prop_1 = 1 + val lambda_1 = { 1 } + fun fun_1(): Int { return 1 } + + fun case_19(value: Any) { + when (value) { + this, ((this)), this::prop_1.get() -> {} + this.prop_1, this.lambda_1() -> {} + this::lambda_1.get()(), this.fun_1(), this::fun_1.invoke() -> {} + } + } +} + +// CASE DESCRIPTION: 'When' with condition as throw expression. +fun case_20(value: Nothing) { + when (value) { + throw Exception(), throw throw throw Exception() -> {} + } +} + +// CASE DESCRIPTION: 'When' with condition as return expression. +fun case_21(value: Nothing) { + fun r_1() { + when (value) { + return, return return return -> 2 + } + } + + fun r_2(): List? { + when (value) { + return listOf(0, 1, 2), return null -> 2 + } + } +} + +// CASE DESCRIPTION: 'When' with condition as continue expression. +fun case_22(value: Nothing) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + continue@loop1, continue@loop2 -> 2 + } + } + } +} + +// CASE DESCRIPTION: 'When' with condition as break expression. +fun case_23(value: Nothing) { + loop1@ while (true) { + loop2@ while (true) { + when (value) { + break@loop1, break@loop2 -> 2 + } + } + } +} + +// CASE DESCRIPTION: 'When' with condition as mixed Nothing expressions. +fun case_24(value: Nothing?) = when (value) { + throw Exception(), return "" -> "" + null, return return return "", throw throw throw Exception() -> "" + else -> "" +} + +/* + CASE DESCRIPTION: 'When' with condition as mixed Nothing expressions. + DISCUSSION + ISSUES: KT-25948 + */ +fun case_25(value: Boolean) = when (value) { + true -> {} + throw Exception(), return -> {} + false, return return return, throw throw throw Exception() -> {} +} + +/* + CASE DESCRIPTION: 'When' with two labels in condition: with const value and nullable const value. + UNEXPECTED BEHAVIOUR + ISSUES: KT-26045 + */ +fun case_26(value: Int?, value1: _Class, value2: _Class?) { + when (value) { + value1.prop_1, value2?.prop_1 -> {} + 10 -> {} + } +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/7.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/7.1.kt new file mode 100644 index 00000000000..633835da7bf --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/7.1.kt @@ -0,0 +1,33 @@ +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 7 + SENTENCE: [7] The else condition, which works the exact same way as it would in the form without bound expression. + NUMBER: 1 + DESCRIPTION: 'When' with bound value and else branch. + */ + +// CASE DESCRIPTION: Simple when with bound value, with 'else' branch and expression as when condition. +fun case_1(value: Int?) = when (value) { + 0 -> "" + 1 -> "" + 2 -> "" + else -> "" +} + +// CASE DESCRIPTION: Simple when with bound value, with 'else' branch and type test as when condition. +fun case_2(value: Any) = when (value) { + is Int -> "" + is Boolean -> "" + is String -> "" + else -> "" +} + +// CASE DESCRIPTION: Simple when with bound value, with 'else' branch and range test as when condition. +fun case_2(value: Int) = when (value) { + in -10..10 -> "" + in 11..1000 -> "" + in 1000..Int.MAX_VALUE -> "" + else -> "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.1.kt new file mode 100644 index 00000000000..3c0e02a9ff7 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.1.kt @@ -0,0 +1,156 @@ +// !CHECK_TYPE +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 1 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via else branch). + */ + +// CASE DESCRIPTION: Checking all types except the correct one (custom types) in 'when' without bound value. +fun case_1(value: Int): String { + val whenValue = when { + value == 0 -> _ClassLevel2() + value > 0 && value <= 10 -> _ClassLevel3() + value > 10 && value <= 100 -> _ClassLevel4() + else -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel1>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel5>() } + checkSubtype<_ClassLevel3>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel5>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the correct one (custom types) in 'when' with bound value. +fun case_2(value: Int): String { + val whenValue = when (value) { + 0 -> _ClassLevel2() + 1 -> _ClassLevel3() + 2 -> _ClassLevel4() + else -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel1>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel5>() } + checkSubtype<_ClassLevel3>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel5>(whenValue) + + return "" +} + +/* + CASE DESCRIPTION: Checking all types except the correct one (numbers) in 'when' without bound value. + UNEXPECTED BEHAVIOUR + ISSUES: KT-25268 + */ +fun case_3(value: Int): String { + val whenValue = when { + value == 0 -> 1 + 1 + value == 1 -> 1 + 1L + value == 2 -> 1 + -.122 + value == 3 -> 1 + -.000f + value == 4 -> 1 + 10.toShort() + else -> 1 + 10.toByte() + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } // unexpected behaviour! + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) // unexpected behaviour! + + return "" +} + +/* + CASE DESCRIPTION: Checking all types except the correct one (numbers) in 'when' with bound value. + UNEXPECTED BEHAVIOUR + ISSUES: KT-25268 + */ +fun case_4(value: Int): String { + val whenValue = when (value) { + 0 -> 1 + 1 + 1 -> 1 + 1L + 2 -> 1 + -.122 + 3 -> 1 + -.000f + 4 -> 1 + 10.toShort() + else -> 1 + 10.toByte() + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _() } // unexpected behaviour! + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype(whenValue) // unexpected behaviour! + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when' without bound value. +fun case_5(value: Int): String { + val whenValue = when { + value == 0 -> 10 + value > 0 && value <= 10 -> "" + value > 10 && value <= 100 -> {{}} + else -> object {} + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when' with bound value. +fun case_6(value: Int): String { + val whenValue = when (value) { + 0 -> 10 + 1 -> "" + 2 -> {{}} + else -> object {} + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.2.kt new file mode 100644 index 00000000000..0653f4c639f --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.2.kt @@ -0,0 +1,95 @@ +// !CHECK_TYPE +// !WITH_ENUM_CLASSES +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 2 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via enum). + */ + +// CASE DESCRIPTION: Checking all types except the correct one in 'when'. +fun case_1(value: _EnumClass): String { + val whenValue = when (value) { + _EnumClass.EAST -> _ClassLevel2() + _EnumClass.NORTH -> _ClassLevel3() + _EnumClass.SOUTH -> _ClassLevel4() + _EnumClass.WEST -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel1>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel5>() } + checkSubtype<_ClassLevel3>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel5>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the correct one in 'when' with null-check branch. +fun case_2(value: _EnumClass?): String { + val whenValue = when (value) { + _EnumClass.EAST -> _ClassLevel2() + _EnumClass.NORTH -> _ClassLevel3() + _EnumClass.SOUTH -> _ClassLevel4() + _EnumClass.WEST -> _ClassLevel5() + null -> _ClassLevel6() + } + + whenValue checkType { _<_ClassLevel1>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel5>() } + whenValue checkType { _<_ClassLevel6>() } + checkSubtype<_ClassLevel3>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel5>(whenValue) + checkSubtype<_ClassLevel6>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when'. +fun case_3(value: _EnumClass): String { + val whenValue = when (value) { + _EnumClass.EAST -> 10 + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> {{}} + _EnumClass.WEST -> object {} + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: _EnumClass?): String { + val whenValue = when (value) { + _EnumClass.EAST -> 10 + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> {{}} + _EnumClass.WEST -> object {} + null -> false + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.3.kt new file mode 100644 index 00000000000..c302985e8a7 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.3.kt @@ -0,0 +1,81 @@ +// !CHECK_TYPE +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 3 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via boolean bound value). + */ + +// CASE DESCRIPTION: Checking all types except the correct one in 'when'. +fun case_1(value: Boolean): String { + val whenValue = when (value) { + true -> _ClassLevel2() + false -> _ClassLevel3() + } + + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the correct one in 'when' with null-check branch. +fun case_2(value: Boolean?): String { + val whenValue = when (value) { + true -> _ClassLevel2() + false -> _ClassLevel3() + null -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when'. +fun case_3(value: Boolean): String { + val whenValue = when (value) { + true -> 10 + false -> "" + } + + whenValue checkType { _() } + whenValue checkType { _() } + checkSubtype(whenValue) + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: Boolean?): String { + val whenValue = when (value) { + true -> 10 + false -> {{}} + null -> "" + } + + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} + + diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.4.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.4.kt new file mode 100644 index 00000000000..cfedcd3e6c9 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.4.kt @@ -0,0 +1,175 @@ +// !CHECK_TYPE +// !WITH_SEALED_CLASSES +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 4 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via sealed class). + */ + +// CASE DESCRIPTION: Checking all types except the correct one in 'when'. +fun case_1(value: _SealedClass): String { + val whenValue = when (value) { + is _SealedChild1 -> _ClassLevel2() + is _SealedChild2 -> _ClassLevel3() + is _SealedChild3 -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the correct one in 'when' with null-check branch. +fun case_2(value: _SealedClass?): String { + val whenValue = when (value) { + is _SealedChild1 -> _ClassLevel2() + is _SealedChild2 -> _ClassLevel3() + is _SealedChild3 -> _ClassLevel4() + null -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel5>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel5>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when'. +fun case_3(value: _SealedClass): String { + val whenValue = when (value) { + is _SealedChild1 -> 10 + is _SealedChild2 -> "" + is _SealedChild3 -> object {} + } + + whenValue checkType { _() } + whenValue checkType { _() } + checkSubtype(whenValue) + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the Any (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: _SealedClass?): String { + val whenValue = when (value) { + is _SealedChild1 -> 10 + is _SealedChild2 -> "" + is _SealedChild3 -> object {} + null -> {{}} + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking objects except the correct one in 'when'. +fun case_5(value: _SealedClassWithObjects): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> _ClassLevel2() + _SealedWithObjectsChild2 -> _ClassLevel3() + _SealedWithObjectsChild3 -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking objects except the correct one in 'when' with null-check branch. +fun case_6(value: _SealedClassWithObjects?): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> _ClassLevel2() + _SealedWithObjectsChild2 -> _ClassLevel3() + _SealedWithObjectsChild3 -> _ClassLevel4() + null -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel5>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel5>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking objects except the Any (implicit cast to any) in 'when'. +fun case_7(value: _SealedClassWithObjects): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> 10 + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> object {} + } + + whenValue checkType { _() } + whenValue checkType { _() } + checkSubtype(whenValue) + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking objects except the Any (implicit cast to any) in 'when' with null-check branch. +fun case_8(value: _SealedClassWithObjects?): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> 10 + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> object {} + null -> {{}} + } + + whenValue checkType { _() } + whenValue checkType { _() } + whenValue checkType { _<() -> Unit>() } + checkSubtype(whenValue) + checkSubtype(whenValue) + checkSubtype<() -> Unit>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking all types except the correct one in 'when' with 'else' branch. +fun case_9(value: _SealedClassWithObjects?): String { + val whenValue = when (value) { + is _SealedClassWithObjects -> _ClassLevel2() + else -> _ClassLevel3() + } + + whenValue checkType { _<_ClassLevel5>() } + whenValue checkType { _<_ClassLevel4>() } + whenValue checkType { _<_ClassLevel3>() } + whenValue checkType { _<_ClassLevel1>() } + checkSubtype<_ClassLevel5>(whenValue) + checkSubtype<_ClassLevel4>(whenValue) + checkSubtype<_ClassLevel3>(whenValue) + + return "" +} \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.1.kt new file mode 100644 index 00000000000..80e049e0929 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.1.kt @@ -0,0 +1,112 @@ +// !CHECK_TYPE +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 1 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via else branch). + */ + +// CASE DESCRIPTION: Checking correctness type (custom types) in 'when' without bound value. +fun case_1(value: Int): String { + val whenValue = when { + value == 0 -> _ClassLevel2() + value > 0 && value <= 10 -> _ClassLevel3() + value > 10 && value <= 100 -> _ClassLevel4() + else -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correctness type (custom types) in 'when' with bound value. +fun case_2(value: Int): String { + val whenValue = when (value) { + 0 -> _ClassLevel2() + 1 -> _ClassLevel3() + 2 -> _ClassLevel4() + else -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +/* + CASE DESCRIPTION: Checking correctness type (numbers) in 'when' without bound value. + UNEXPECTED BEHAVIOUR + ISSUES: KT-25268 + */ +fun case_3(value: Int): String { + val whenValue = when { + value == 0 -> 1 + 1 + value == 1 -> 1 + 1L + value == 2 -> 1 + -.122 + value == 3 -> 1 + -.000f + value == 4 -> 1 + 10.toShort() + else -> 1 + 10.toShort() + } + + whenValue checkType { _() } + + return "" +} + +/* + CASE DESCRIPTION: Checking correctness type (numbers) in 'when' with bound value. + UNEXPECTED BEHAVIOUR + ISSUES: KT-25268 + */ +fun case_4(value: Int): String { + val whenValue = when (value) { + 0 -> 1 + 1 + 1 -> 1 + 1L + 2 -> 1 + -.122 + 3 -> 1 + -.000f + 4 -> 1 + 10.toShort() + else -> 1 + 10.toByte() + } + + whenValue checkType { _() } + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' without bound value. +fun case_5(value: Int): String { + val whenValue = when { + value == 0 -> 10 + value > 0 && value <= 10 -> "" + value > 10 && value <= 100 -> {{}} + else -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' with bound value. +fun case_6(value: Int): String { + val whenValue = when (value) { + 0 -> 10 + 1 -> "" + 2 -> {{}} + else -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.2.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.2.kt new file mode 100644 index 00000000000..65f8561aacb --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.2.kt @@ -0,0 +1,75 @@ +// !CHECK_TYPE +// !WITH_CLASSES +// !WITH_ENUM_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 2 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via enum). + */ + +// CASE DESCRIPTION: Checking correct type in 'when'. +fun case_1(value: _EnumClass): String { + val whenValue = when (value) { + _EnumClass.EAST -> _ClassLevel2() + _EnumClass.NORTH -> _ClassLevel3() + _EnumClass.SOUTH -> _ClassLevel4() + _EnumClass.WEST -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct type in 'when' with null-check branch. +fun case_2(value: _EnumClass?): String { + val whenValue = when (value) { + _EnumClass.EAST -> _ClassLevel2() + _EnumClass.NORTH -> _ClassLevel3() + _EnumClass.SOUTH -> _ClassLevel4() + _EnumClass.WEST -> _ClassLevel5() + null -> _ClassLevel6() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when'. +fun case_3(value: _EnumClass): String { + val whenValue = when (value) { + _EnumClass.EAST -> 10 + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> {{}} + _EnumClass.WEST -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: _EnumClass?): String { + val whenValue = when (value) { + _EnumClass.EAST -> 10 + _EnumClass.NORTH -> "" + _EnumClass.SOUTH -> {{}} + _EnumClass.WEST -> object {} + null -> false + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.3.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.3.kt new file mode 100644 index 00000000000..18157af38a6 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.3.kt @@ -0,0 +1,70 @@ +// !CHECK_TYPE +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 3 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via boolean bound value). + */ + +// CASE DESCRIPTION: Checking correct type in 'when'. +fun case_1(value: Boolean): String { + val whenValue = when (value) { + true -> _ClassLevel2() + false -> _ClassLevel3() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct type in 'when' with null-check branch. +fun case_2(value: Boolean?): String { + val whenValue = when (value) { + true -> _ClassLevel2() + false -> _ClassLevel3() + null -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when'. +fun case_3(value: Boolean): String { + val whenValue = when (value) { + true -> 10 + false -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: Boolean?): String { + val whenValue = when (value) { + true -> 10 + false -> {{}} + null -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + + diff --git a/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.4.kt b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.4.kt new file mode 100644 index 00000000000..1d7a29b9796 --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.4.kt @@ -0,0 +1,141 @@ +// !CHECK_TYPE +// !WITH_SEALED_CLASSES +// !WITH_CLASSES + +/* + KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE) + + SECTION: 16.30 When expression + PARAGRAPH: 9 + SENTENCE: [1] The type of the resulting expression is the least upper bound of the types of all the entries. + NUMBER: 4 + DESCRIPTION: 'When' least upper bound of the types check (when exhaustive via sealed class). + */ + +// CASE DESCRIPTION: Checking correct type in 'when'. +fun case_1(value: _SealedClass): String { + val whenValue = when (value) { + is _SealedChild1 -> _ClassLevel2() + is _SealedChild2 -> _ClassLevel3() + is _SealedChild3 -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct type in 'when' with null-check branch. +fun case_2(value: _SealedClass?): String { + val whenValue = when (value) { + is _SealedChild1 -> _ClassLevel2() + is _SealedChild2 -> _ClassLevel3() + is _SealedChild3 -> _ClassLevel4() + null -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when'. +fun case_3(value: _SealedClass): String { + val whenValue = when (value) { + is _SealedChild1 -> 10 + is _SealedChild2 -> "" + is _SealedChild3 -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' with null-check branch. +fun case_4(value: _SealedClass?): String { + val whenValue = when (value) { + is _SealedChild1 -> 10 + is _SealedChild2 -> "" + is _SealedChild3 -> object {} + null -> {{}} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct type in 'when' (equality with objects). +fun case_5(value: _SealedClassWithObjects): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> _ClassLevel2() + _SealedWithObjectsChild2 -> _ClassLevel3() + _SealedWithObjectsChild3 -> _ClassLevel4() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct type in 'when' (equality with objects) with null-check branch. +fun case_6(value: _SealedClassWithObjects?): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> _ClassLevel2() + _SealedWithObjectsChild2 -> _ClassLevel3() + _SealedWithObjectsChild3 -> _ClassLevel4() + null -> _ClassLevel5() + } + + whenValue checkType { _<_ClassLevel2>() } + checkSubtype<_ClassLevel1>(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' (equality with objects). +fun case_7(value: _SealedClassWithObjects): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> 10 + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> object {} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking Any type (implicit cast to any) in 'when' with null-check branch (equality with objects). +fun case_8(value: _SealedClassWithObjects?): String { + val whenValue = when (value) { + _SealedWithObjectsChild1 -> 10 + _SealedWithObjectsChild2 -> "" + _SealedWithObjectsChild3 -> object {} + null -> {{}} + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} + +// CASE DESCRIPTION: Checking correct basic type (Int) in 'when' with. +fun case_9(value: _SealedClassWithObjects): String { + val whenValue = when (value) { + is _SealedClassWithObjects -> 10 + } + + whenValue checkType { _() } + checkSubtype(whenValue) + + return "" +} \ No newline at end of file diff --git a/compiler/tests-spec/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestSpecGenerated.java b/compiler/tests-spec/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestSpecGenerated.java new file mode 100644 index 00000000000..bf55d0451a3 --- /dev/null +++ b/compiler/tests-spec/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestSpecGenerated.java @@ -0,0 +1,574 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.checkers; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/tests-spec/testData/diagnostics") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInDiagnostics() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class S_16_30_when_expression extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInS_16_30_when_expression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_11 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_11() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/1.2.kt"); + } + + @TestMetadata("3.1.kt") + public void test3_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/3.1.kt"); + } + + @TestMetadata("6.1.kt") + public void test6_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/6.1.kt"); + } + + @TestMetadata("7.1.kt") + public void test7_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/7.1.kt"); + } + + @TestMetadata("8.1.kt") + public void test8_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.1.kt"); + } + + @TestMetadata("8.2.kt") + public void test8_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.2.kt"); + } + + @TestMetadata("8.3.kt") + public void test8_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg/8.3.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.2.kt"); + } + + @TestMetadata("1.3.kt") + public void test1_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/1.3.kt"); + } + + @TestMetadata("3.1.kt") + public void test3_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/3.1.kt"); + } + + @TestMetadata("6.1.kt") + public void test6_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/6.1.kt"); + } + + @TestMetadata("7.1.kt") + public void test7_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/7.1.kt"); + } + + @TestMetadata("8.1.kt") + public void test8_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.1.kt"); + } + + @TestMetadata("8.2.kt") + public void test8_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.2.kt"); + } + + @TestMetadata("8.3.kt") + public void test8_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos/8.3.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-11/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_2 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_2() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("3.1.kt") + public void test3_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.1.kt"); + } + + @TestMetadata("3.2.kt") + public void test3_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos/3.2.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-2/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_3 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_3() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/1.1.kt"); + } + + @TestMetadata("2.1.kt") + public void test2_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.1.kt"); + } + + @TestMetadata("2.2.kt") + public void test2_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg/2.2.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/1.1.kt"); + } + + @TestMetadata("2.1.kt") + public void test2_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.1.kt"); + } + + @TestMetadata("2.2.kt") + public void test2_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.2.kt"); + } + + @TestMetadata("2.3.kt") + public void test2_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos/2.3.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-3/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_5 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_5() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg/1.1.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos/1.1.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-5/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_6 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_6() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg/1.1.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos/1.1.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-6/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_7 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_7() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/1.2.kt"); + } + + @TestMetadata("3.1.kt") + public void test3_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.1.kt"); + } + + @TestMetadata("3.2.kt") + public void test3_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/3.2.kt"); + } + + @TestMetadata("5.1.kt") + public void test5_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.1.kt"); + } + + @TestMetadata("5.2.kt") + public void test5_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/5.2.kt"); + } + + @TestMetadata("7.1.kt") + public void test7_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg/7.1.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.2.kt"); + } + + @TestMetadata("1.3.kt") + public void test1_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.3.kt"); + } + + @TestMetadata("1.4.kt") + public void test1_4() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/1.4.kt"); + } + + @TestMetadata("3.1.kt") + public void test3_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.1.kt"); + } + + @TestMetadata("3.2.kt") + public void test3_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/3.2.kt"); + } + + @TestMetadata("5.1.kt") + public void test5_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.1.kt"); + } + + @TestMetadata("5.2.kt") + public void test5_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/5.2.kt"); + } + + @TestMetadata("7.1.kt") + public void test7_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos/7.1.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-7/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class P_9 extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInP_9() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Neg extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.2.kt"); + } + + @TestMetadata("1.3.kt") + public void test1_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.3.kt"); + } + + @TestMetadata("1.4.kt") + public void test1_4() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg/1.4.kt"); + } + + public void testAllFilesPresentInNeg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/neg"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Pos extends AbstractDiagnosticsTestSpec { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("1.1.kt") + public void test1_1() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.1.kt"); + } + + @TestMetadata("1.2.kt") + public void test1_2() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.2.kt"); + } + + @TestMetadata("1.3.kt") + public void test1_3() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.3.kt"); + } + + @TestMetadata("1.4.kt") + public void test1_4() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos/1.4.kt"); + } + + public void testAllFilesPresentInPos() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/s-16.30_when-expression/p-9/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + } + } + } +}