[FIR] Report NON_EXHAUSTIVE_WHEN_STATEMENT/NO_ELSE_IN_WHEN for when's on logical types
^KT-47709 In Progress
This commit is contained in:
committed by
teamcityserver
parent
ef635f6a96
commit
a6edd852ff
Vendored
+1
-1
@@ -27,7 +27,7 @@ fun test_2(cond: Boolean?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test_3(cond: Boolean) {
|
fun test_3(cond: Boolean) {
|
||||||
when (cond) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (cond) {
|
||||||
true -> 1
|
true -> 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ fun test_2(enum: SomeEnum?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test_3(enum: SomeEnum) {
|
fun test_3(enum: SomeEnum) {
|
||||||
when (enum) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (enum) {
|
||||||
SomeEnum.A -> 1
|
SomeEnum.A -> 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -44,7 +44,7 @@ fun test_2(base: Base?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test_3(base: Base) {
|
fun test_3(base: Base) {
|
||||||
when (base) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (base) {
|
||||||
is A -> 1
|
is A -> 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ typealias TA = A<CharSequence>
|
|||||||
fun bar(): TA = TODO()
|
fun bar(): TA = TODO()
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
when (val a = bar()) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (val a = bar()) {
|
||||||
is A.B -> a.x.length
|
is A.B -> a.x.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -976,6 +976,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||||
parameter<List<WhenMissingCase>>("missingWhenCases")
|
parameter<List<WhenMissingCase>>("missingWhenCases")
|
||||||
}
|
}
|
||||||
|
val NON_EXHAUSTIVE_WHEN_STATEMENT by warning<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||||
|
parameter<String>("type")
|
||||||
|
parameter<List<WhenMissingCase>>("missingWhenCases")
|
||||||
|
}
|
||||||
val INVALID_IF_AS_EXPRESSION by error<KtIfExpression>(PositioningStrategy.IF_EXPRESSION)
|
val INVALID_IF_AS_EXPRESSION by error<KtIfExpression>(PositioningStrategy.IF_EXPRESSION)
|
||||||
val ELSE_MISPLACED_IN_WHEN by error<KtWhenEntry>(PositioningStrategy.ELSE_ENTRY)
|
val ELSE_MISPLACED_IN_WHEN by error<KtWhenEntry>(PositioningStrategy.ELSE_ENTRY)
|
||||||
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
|
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
|
||||||
|
|||||||
@@ -516,6 +516,7 @@ object FirErrors {
|
|||||||
// When expressions
|
// When expressions
|
||||||
val EXPECTED_CONDITION by error0<KtWhenCondition>()
|
val EXPECTED_CONDITION by error0<KtWhenCondition>()
|
||||||
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||||
|
val NON_EXHAUSTIVE_WHEN_STATEMENT by warning2<KtWhenExpression, String, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||||
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
||||||
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
|
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
|
||||||
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
|
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
|
||||||
|
|||||||
+51
-4
@@ -6,29 +6,76 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||||
import org.jetbrains.kotlin.fir.expressions.ExhaustivenessStatus
|
import org.jetbrains.kotlin.fir.expressions.ExhaustivenessStatus
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||||
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||||
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.fir.types.isBooleanOrNullableBoolean
|
||||||
|
|
||||||
object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
|
object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
|
||||||
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (expression.usedAsExpression && !expression.isExhaustive) {
|
reportNotExhaustive(expression, context, reporter)
|
||||||
val source = expression.source ?: return
|
reportElseMisplaced(expression, reporter, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportNotExhaustive(whenExpression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (whenExpression.isExhaustive) return
|
||||||
|
|
||||||
|
val source = whenExpression.source ?: return
|
||||||
|
|
||||||
|
if (whenExpression.usedAsExpression) {
|
||||||
if (source.isIfExpression) {
|
if (source.isIfExpression) {
|
||||||
reporter.reportOn(source, FirErrors.INVALID_IF_AS_EXPRESSION, context)
|
reporter.reportOn(source, FirErrors.INVALID_IF_AS_EXPRESSION, context)
|
||||||
return
|
return
|
||||||
} else if (source.isWhenExpression) {
|
} else if (source.isWhenExpression) {
|
||||||
val missingCases = (expression.exhaustivenessStatus as ExhaustivenessStatus.NotExhaustive).reasons
|
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, whenExpression.missingCases, context)
|
||||||
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, missingCases, context)
|
}
|
||||||
|
} else {
|
||||||
|
val subjectType = whenExpression.subject?.typeRef?.coneType ?: return
|
||||||
|
val subjectClassSymbol = subjectType.fullyExpandedType(context.session).toRegularClassSymbol(context.session) ?: return
|
||||||
|
val kind = when {
|
||||||
|
subjectClassSymbol.modality == Modality.SEALED -> AlgebraicTypeKind.Sealed
|
||||||
|
subjectClassSymbol.classKind == ClassKind.ENUM_CLASS -> AlgebraicTypeKind.Enum
|
||||||
|
subjectType.isBooleanOrNullableBoolean -> AlgebraicTypeKind.Boolean
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonExhaustiveWhenOnAlgebraicTypes)) {
|
||||||
|
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, whenExpression.missingCases, context)
|
||||||
|
} else {
|
||||||
|
reporter.reportOn(source, FirErrors.NON_EXHAUSTIVE_WHEN_STATEMENT, kind.displayName, whenExpression.missingCases, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirWhenExpression.missingCases: List<WhenMissingCase>
|
||||||
|
get() = (exhaustivenessStatus as ExhaustivenessStatus.NotExhaustive).reasons
|
||||||
|
|
||||||
|
private enum class AlgebraicTypeKind(val displayName: String) {
|
||||||
|
Sealed("sealed class/interface"),
|
||||||
|
Enum("enum"),
|
||||||
|
Boolean("Boolean")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportElseMisplaced(
|
||||||
|
expression: FirWhenExpression,
|
||||||
|
reporter: DiagnosticReporter,
|
||||||
|
context: CheckerContext
|
||||||
|
) {
|
||||||
val branchesCount = expression.branches.size
|
val branchesCount = expression.branches.size
|
||||||
for (indexedValue in expression.branches.withIndex()) {
|
for (indexedValue in expression.branches.withIndex()) {
|
||||||
val branch = indexedValue.value
|
val branch = indexedValue.value
|
||||||
|
|||||||
+7
@@ -249,6 +249,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEWER_VERSION_IN_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_EXHAUSTIVE_WHEN_STATEMENT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_OBJECT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_OBJECT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
|
||||||
@@ -1284,6 +1285,12 @@ class FirDefaultErrorMessages {
|
|||||||
map.put(EXPECTED_CONDITION, "Expected condition of type Boolean")
|
map.put(EXPECTED_CONDITION, "Expected condition of type Boolean")
|
||||||
map.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", WHEN_MISSING_CASES)
|
map.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", WHEN_MISSING_CASES)
|
||||||
map.put(INVALID_IF_AS_EXPRESSION, "'if' must have both main and 'else' branches if used as an expression")
|
map.put(INVALID_IF_AS_EXPRESSION, "'if' must have both main and 'else' branches if used as an expression")
|
||||||
|
map.put(
|
||||||
|
NON_EXHAUSTIVE_WHEN_STATEMENT,
|
||||||
|
"Non exhaustive ''when'' statements on {0} will be prohibited in 1.7, add {1}",
|
||||||
|
TO_STRING,
|
||||||
|
WHEN_MISSING_CASES
|
||||||
|
)
|
||||||
|
|
||||||
// Context tracking
|
// Context tracking
|
||||||
map.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", SYMBOL)
|
map.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", SYMBOL)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ val ConeKotlinType.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Not
|
|||||||
val ConeKotlinType.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
val ConeKotlinType.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
||||||
val ConeKotlinType.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
val ConeKotlinType.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||||
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||||
|
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Boolean))
|
||||||
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||||
val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuiltinType(StandardClassIds.primitiveTypes)
|
val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuiltinType(StandardClassIds.primitiveTypes)
|
||||||
@@ -85,9 +86,9 @@ val ConeKotlinType.isUnsignedType: Boolean get() = isUnsignedTypeOrNullableUnsig
|
|||||||
private val builtinIntegerTypes = setOf(StandardClassIds.Int, StandardClassIds.Byte, StandardClassIds.Long, StandardClassIds.Short)
|
private val builtinIntegerTypes = setOf(StandardClassIds.Int, StandardClassIds.Byte, StandardClassIds.Long, StandardClassIds.Short)
|
||||||
val ConeKotlinType.isIntegerTypeOrNullableIntegerTypeOfAnySize: Boolean get() = isAnyOfBuiltinType(builtinIntegerTypes)
|
val ConeKotlinType.isIntegerTypeOrNullableIntegerTypeOfAnySize: Boolean get() = isAnyOfBuiltinType(builtinIntegerTypes)
|
||||||
|
|
||||||
private fun ConeKotlinType.isBuiltinType(classId: ClassId, isNullable: Boolean): Boolean {
|
private fun ConeKotlinType.isBuiltinType(classId: ClassId, isNullable: Boolean?): Boolean {
|
||||||
if (this !is ConeClassLikeType) return false
|
if (this !is ConeClassLikeType) return false
|
||||||
return lookupTag.classId == classId && type.isNullable == isNullable
|
return lookupTag.classId == classId && (isNullable == null || type.isNullable == isNullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeKotlinType.isAnyOfBuiltinType(classIds: Set<ClassId>): Boolean {
|
private fun ConeKotlinType.isAnyOfBuiltinType(classIds: Set<ClassId>): Boolean {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
//FILE: foo.kt
|
|
||||||
fun main() {
|
|
||||||
val c: Type
|
|
||||||
when (<!UNINITIALIZED_VARIABLE!>c<!>) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//FILE: Type.java
|
|
||||||
public enum Type {
|
|
||||||
TYPE,
|
|
||||||
NO_TYPE;
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
//FILE: foo.kt
|
//FILE: foo.kt
|
||||||
fun main() {
|
fun main() {
|
||||||
val c: Type
|
val c: Type
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_VALUE
|
|
||||||
|
|
||||||
fun foo(f: Boolean): Int {
|
|
||||||
val i: Int
|
|
||||||
when (f) {
|
|
||||||
true -> i = 1
|
|
||||||
}
|
|
||||||
<!VAL_REASSIGNMENT!>i<!> = 3
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_VALUE
|
// !DIAGNOSTICS: -UNUSED_VALUE
|
||||||
|
|
||||||
fun foo(f: Boolean): Int {
|
fun foo(f: Boolean): Int {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ fun foo(my: My) {
|
|||||||
if (my.x != null) {
|
if (my.x != null) {
|
||||||
// my.x should be smart-cast
|
// my.x should be smart-cast
|
||||||
if (my.x) doIt()
|
if (my.x) doIt()
|
||||||
when (my.x) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (my.x) {
|
||||||
true -> doIt()
|
true -> doIt()
|
||||||
}
|
}
|
||||||
when {
|
when {
|
||||||
@@ -20,7 +20,7 @@ fun bar(x: Boolean?) {
|
|||||||
if (x != null) {
|
if (x != null) {
|
||||||
// x should be smart-cast
|
// x should be smart-cast
|
||||||
if (x) doIt()
|
if (x) doIt()
|
||||||
when (x) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (x) {
|
||||||
true -> doIt()
|
true -> doIt()
|
||||||
}
|
}
|
||||||
when {
|
when {
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ fun bar(a: Boolean, b: Boolean): Int {
|
|||||||
if (a) {
|
if (a) {
|
||||||
x = 1
|
x = 1
|
||||||
}
|
}
|
||||||
when (b) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (b) {
|
||||||
false -> <!VAL_REASSIGNMENT!>x<!> = 3
|
false -> <!VAL_REASSIGNMENT!>x<!> = 3
|
||||||
}
|
}
|
||||||
return <!UNINITIALIZED_VARIABLE!>x<!>
|
return <!UNINITIALIZED_VARIABLE!>x<!>
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ fun bar(a: Boolean, b: Boolean): Int {
|
|||||||
if (a) {
|
if (a) {
|
||||||
x = 1
|
x = 1
|
||||||
}
|
}
|
||||||
when (b) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (b) {
|
||||||
false -> x = 3
|
false -> x = 3
|
||||||
}
|
}
|
||||||
return <!UNINITIALIZED_VARIABLE!>x<!>
|
return <!UNINITIALIZED_VARIABLE!>x<!>
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
|
||||||
*
|
|
||||||
* SPEC VERSION: 0.1-152
|
|
||||||
* PRIMARY LINKS: expressions, when-expression -> paragraph 5 -> sentence 1
|
|
||||||
* expressions, when-expression, exhaustive-when-expressions -> paragraph 1 -> sentence 1
|
|
||||||
* expressions, when-expression, exhaustive-when-expressions -> paragraph 2 -> sentence 9
|
|
||||||
* expressions, when-expression -> paragraph 9 -> sentence 2
|
|
||||||
* control--and-data-flow-analysis, performing-analysis-on-the-control-flow-graph, variable-initialization-analysis -> paragraph 2 -> sentence 1
|
|
||||||
* control--and-data-flow-analysis, performing-analysis-on-the-control-flow-graph, variable-initialization-analysis -> paragraph 2 -> sentence 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Base for KT-6227
|
|
||||||
enum class X { A, B, C, D }
|
|
||||||
|
|
||||||
fun foo(arg: X): String {
|
|
||||||
var res = "XXX"
|
|
||||||
when (arg) {
|
|
||||||
X.A -> res = "A"
|
|
||||||
X.B -> res = "B"
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
/*
|
/*
|
||||||
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
||||||
*
|
*
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ object Last : S()
|
|||||||
fun use(s: String) = s
|
fun use(s: String) = s
|
||||||
|
|
||||||
fun foo(s: S) {
|
fun foo(s: S) {
|
||||||
when (s) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (s) {
|
||||||
First -> {}
|
First -> {}
|
||||||
is Derived -> use(s.s)
|
is Derived -> use(s.s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
|
||||||
*
|
|
||||||
* SPEC VERSION: 0.1-152
|
|
||||||
* PRIMARY LINKS: expressions, when-expression -> paragraph 5 -> sentence 1
|
|
||||||
* expressions, when-expression, exhaustive-when-expressions -> paragraph 1 -> sentence 1
|
|
||||||
* expressions, when-expression, exhaustive-when-expressions -> paragraph 2 -> sentence 9
|
|
||||||
* expressions, when-expression, exhaustive-when-expressions -> paragraph 2 -> sentence 10
|
|
||||||
* expressions, when-expression -> paragraph 9 -> sentence 2
|
|
||||||
* control--and-data-flow-analysis, performing-analysis-on-the-control-flow-graph, variable-initialization-analysis -> paragraph 2 -> sentence 1
|
|
||||||
* control--and-data-flow-analysis, performing-analysis-on-the-control-flow-graph, variable-initialization-analysis -> paragraph 2 -> sentence 3
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Base for KT-6227
|
|
||||||
enum class X { A, B, C, D }
|
|
||||||
|
|
||||||
fun foo(arg: X?): String {
|
|
||||||
var res = "XXX"
|
|
||||||
// Should we report something here? Probably not, null is not an enum entry
|
|
||||||
when (arg) {
|
|
||||||
X.A -> res = "A"
|
|
||||||
X.B -> res = "B"
|
|
||||||
X.C -> res = "C"
|
|
||||||
X.D -> res = "D"
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
/*
|
/*
|
||||||
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
||||||
*
|
*
|
||||||
|
|||||||
-154
@@ -1,154 +0,0 @@
|
|||||||
// !LANGUAGE: -ProhibitNonExhaustiveWhenOnLogicalTypes
|
|
||||||
|
|
||||||
enum class SomeEnum {
|
|
||||||
A, B
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Base {
|
|
||||||
class A : Base()
|
|
||||||
class B : Base()
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface IBase {
|
|
||||||
interface A : IBase
|
|
||||||
interface B : IBase
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ not null ------------------
|
|
||||||
|
|
||||||
fun test_1(x: SomeEnum) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_2(x: Base) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_3(x: IBase) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_4(x: Boolean) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ nullable ------------------
|
|
||||||
|
|
||||||
fun test_5(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
SomeEnum.B -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_6(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
is Base.B -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_7(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
is IBase.B -> ""
|
|
||||||
}
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_8(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
false -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ with else ------------------
|
|
||||||
|
|
||||||
fun test_9(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_10(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_11(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_12(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ exhaustive ------------------
|
|
||||||
|
|
||||||
fun test_13(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
SomeEnum.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_14(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
is Base.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_15(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
is IBase.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_16(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
false -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: -ProhibitNonExhaustiveWhenOnAlgebraicTypes
|
// !LANGUAGE: -ProhibitNonExhaustiveWhenOnAlgebraicTypes
|
||||||
|
|
||||||
enum class SomeEnum {
|
enum class SomeEnum {
|
||||||
|
|||||||
-154
@@ -1,154 +0,0 @@
|
|||||||
// !LANGUAGE: +ProhibitNonExhaustiveWhenOnLogicalTypes
|
|
||||||
|
|
||||||
enum class SomeEnum {
|
|
||||||
A, B
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Base {
|
|
||||||
class A : Base()
|
|
||||||
class B : Base()
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface IBase {
|
|
||||||
interface A : IBase
|
|
||||||
interface B : IBase
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ not null ------------------
|
|
||||||
|
|
||||||
fun test_1(x: SomeEnum) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_2(x: Base) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_3(x: IBase) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_4(x: Boolean) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ nullable ------------------
|
|
||||||
|
|
||||||
fun test_5(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
SomeEnum.B -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_6(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
is Base.B -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_7(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
is IBase.B -> ""
|
|
||||||
}
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_8(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
false -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ with else ------------------
|
|
||||||
|
|
||||||
fun test_9(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_10(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_11(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_12(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ exhaustive ------------------
|
|
||||||
|
|
||||||
fun test_13(x: SomeEnum?) {
|
|
||||||
when (x) {
|
|
||||||
SomeEnum.A -> ""
|
|
||||||
SomeEnum.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_14(x: Base?) {
|
|
||||||
when (x) {
|
|
||||||
is Base.A -> ""
|
|
||||||
is Base.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_15(x: IBase?) {
|
|
||||||
when (x) {
|
|
||||||
is IBase.A -> ""
|
|
||||||
is IBase.B -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_16(x: Boolean?) {
|
|
||||||
when (x) {
|
|
||||||
true -> ""
|
|
||||||
false -> ""
|
|
||||||
null -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +ProhibitNonExhaustiveWhenOnAlgebraicTypes
|
// !LANGUAGE: +ProhibitNonExhaustiveWhenOnAlgebraicTypes
|
||||||
|
|
||||||
enum class SomeEnum {
|
enum class SomeEnum {
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
fun test1() {
|
|
||||||
if (true) {
|
|
||||||
when (true) {
|
|
||||||
true -> println()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out?.println() // kotlin.Unit?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test2() {
|
|
||||||
val mlist = arrayListOf("")
|
|
||||||
if (true) {
|
|
||||||
when (true) {
|
|
||||||
true -> println()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mlist.add("") // kotlin.Boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
fun test1() {
|
fun test1() {
|
||||||
if (true) {
|
if (true) {
|
||||||
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (true) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (true) {
|
||||||
|
|||||||
Vendored
+2
-2
@@ -60,11 +60,11 @@ fun case_5(value_1: Int, value_2: Int, value_3: Boolean?) {
|
|||||||
false -> "2"
|
false -> "2"
|
||||||
null -> "3"
|
null -> "3"
|
||||||
}
|
}
|
||||||
value_1 == 5 -> when (value_3) {
|
value_1 == 5 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {
|
||||||
true -> "1"
|
true -> "1"
|
||||||
false -> "2"
|
false -> "2"
|
||||||
}
|
}
|
||||||
value_1 == 6 -> when (value_3) {}
|
value_1 == 6 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-4
@@ -51,21 +51,21 @@ fun case_5(value_1: Int, value_2: Int, value_3: Boolean?) {
|
|||||||
value_2 > 100 -> "2"
|
value_2 > 100 -> "2"
|
||||||
else -> "3"
|
else -> "3"
|
||||||
}
|
}
|
||||||
2 -> when (value_3) {
|
2 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {
|
||||||
value_2 > 1000 -> "1"
|
value_2 > 1000 -> "1"
|
||||||
value_2 > 100 -> "2"
|
value_2 > 100 -> "2"
|
||||||
}
|
}
|
||||||
3 -> when (value_3) {}
|
3 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {}
|
||||||
4 -> when (value_3) {
|
4 -> when (value_3) {
|
||||||
true -> "1"
|
true -> "1"
|
||||||
false -> "2"
|
false -> "2"
|
||||||
null -> "3"
|
null -> "3"
|
||||||
}
|
}
|
||||||
5 -> when (value_3) {
|
5 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {
|
||||||
true -> "1"
|
true -> "1"
|
||||||
false -> "2"
|
false -> "2"
|
||||||
}
|
}
|
||||||
6 -> when (value_3) {}
|
6 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ fun case_2(value_1: Number, value_2: Int) {
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
|
fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
|
||||||
when (value_1) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) {
|
||||||
value_2 -> {}
|
value_2 -> {}
|
||||||
!value_2 -> {}
|
!value_2 -> {}
|
||||||
getBoolean() && value_2 -> {}
|
getBoolean() && value_2 -> {}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -18,7 +18,7 @@ fun case_2(value_1: Number, value_2: Int) {
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
|
fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
|
||||||
when (value_1) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) {
|
||||||
value_2, !value_2, getBoolean() && value_2, getChar() != 'a' -> {}
|
value_2, !value_2, getBoolean() && value_2, getChar() != 'a' -> {}
|
||||||
getList() === getAny(), value_3 <= 11 -> {}
|
getList() === getAny(), value_3 <= 11 -> {}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
fun case_1(value_1: EnumClass?) {
|
fun case_1(value_1: EnumClass?) {
|
||||||
val value_2: Int
|
val value_2: Int
|
||||||
|
|
||||||
when (value_1) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) {
|
||||||
EnumClass.NORTH -> funWithExactlyOnceCallsInPlace { value_2 = 1 }
|
EnumClass.NORTH -> funWithExactlyOnceCallsInPlace { value_2 = 1 }
|
||||||
EnumClass.SOUTH -> funWithExactlyOnceCallsInPlace { value_2 = 2 }
|
EnumClass.SOUTH -> funWithExactlyOnceCallsInPlace { value_2 = 2 }
|
||||||
EnumClass.EAST -> funWithExactlyOnceCallsInPlace { value_2 = 4 }
|
EnumClass.EAST -> funWithExactlyOnceCallsInPlace { value_2 = 4 }
|
||||||
|
|||||||
Vendored
+1
-1
@@ -100,7 +100,7 @@ fun case_4(value_1: Number, value_2: (() -> Unit)?) {
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 5
|
// TESTCASE NUMBER: 5
|
||||||
fun case_5(value_1: Number?, value_2: String?) {
|
fun case_5(value_1: Number?, value_2: String?) {
|
||||||
when (value_2.case_5(value_1)) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_2.case_5(value_1)) {
|
||||||
true -> {
|
true -> {
|
||||||
println(value_2<!UNSAFE_CALL!>.<!>length)
|
println(value_2<!UNSAFE_CALL!>.<!>length)
|
||||||
println(value_1.toByte())
|
println(value_1.toByte())
|
||||||
|
|||||||
Vendored
+1
-1
@@ -105,7 +105,7 @@ fun case_4(value_1: Number, value_2: (() -> Unit)?) {
|
|||||||
* ISSUES: KT-26612
|
* ISSUES: KT-26612
|
||||||
*/
|
*/
|
||||||
fun case_5(value_1: Number?, value_2: String?) {
|
fun case_5(value_1: Number?, value_2: String?) {
|
||||||
when (value_2.case_5(value_1)) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_2.case_5(value_1)) {
|
||||||
true -> {
|
true -> {
|
||||||
println(value_2.length)
|
println(value_2.length)
|
||||||
println(value_1.toByte())
|
println(value_1.toByte())
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ fun case_7() {
|
|||||||
var b = a
|
var b = a
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.String")!>b<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.String")!>b<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.String")!>b<!>.length
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.String")!>b<!>.length
|
||||||
when (true) {
|
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (true) {
|
||||||
true -> b = a
|
true -> b = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
@@ -2649,6 +2649,16 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.NON_EXHAUSTIVE_WHEN_STATEMENT) { firDiagnostic ->
|
||||||
|
NonExhaustiveWhenStatementImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic.b.map { whenMissingCase ->
|
||||||
|
whenMissingCase
|
||||||
|
},
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.INVALID_IF_AS_EXPRESSION) { firDiagnostic ->
|
add(FirErrors.INVALID_IF_AS_EXPRESSION) { firDiagnostic ->
|
||||||
InvalidIfAsExpressionImpl(
|
InvalidIfAsExpressionImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
|||||||
+6
@@ -1855,6 +1855,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val missingWhenCases: List<WhenMissingCase>
|
abstract val missingWhenCases: List<WhenMissingCase>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class NonExhaustiveWhenStatement : KtFirDiagnostic<KtWhenExpression>() {
|
||||||
|
override val diagnosticClass get() = NonExhaustiveWhenStatement::class
|
||||||
|
abstract val type: String
|
||||||
|
abstract val missingWhenCases: List<WhenMissingCase>
|
||||||
|
}
|
||||||
|
|
||||||
abstract class InvalidIfAsExpression : KtFirDiagnostic<KtIfExpression>() {
|
abstract class InvalidIfAsExpression : KtFirDiagnostic<KtIfExpression>() {
|
||||||
override val diagnosticClass get() = InvalidIfAsExpression::class
|
override val diagnosticClass get() = InvalidIfAsExpression::class
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -2990,6 +2990,15 @@ internal class NoElseInWhenImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class NonExhaustiveWhenStatementImpl(
|
||||||
|
override val type: String,
|
||||||
|
override val missingWhenCases: List<WhenMissingCase>,
|
||||||
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NonExhaustiveWhenStatement(), KtAbstractFirDiagnostic<KtWhenExpression> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class InvalidIfAsExpressionImpl(
|
internal class InvalidIfAsExpressionImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user