[FIR] Replace isExhaustive flag with ExhaustivenessStatus object
This commit is contained in:
+1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||
|
||||
object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
|
||||
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
|
||||
@@ -138,7 +138,7 @@ fun FirWhenExpression.copy(
|
||||
typeRef = resultType
|
||||
this.annotations += annotations
|
||||
usedAsExpression = this@copy.usedAsExpression
|
||||
isExhaustive = this@copy.isExhaustive
|
||||
exhaustivenessStatus = this@copy.exhaustivenessStatus
|
||||
}
|
||||
|
||||
fun FirTryExpression.copy(
|
||||
|
||||
+13
-14
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyResolveComponents) : FirTransformer<Nothing?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
@@ -29,23 +28,23 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
|
||||
}
|
||||
|
||||
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||
val resultExpression = processExhaustivenessCheck(whenExpression) ?: whenExpression
|
||||
return resultExpression.compose()
|
||||
processExhaustivenessCheck(whenExpression)
|
||||
return whenExpression.compose()
|
||||
}
|
||||
|
||||
private fun processExhaustivenessCheck(whenExpression: FirWhenExpression): FirWhenExpression? {
|
||||
private fun processExhaustivenessCheck(whenExpression: FirWhenExpression) {
|
||||
if (whenExpression.branches.any { it.condition is FirElseIfTrueCondition }) {
|
||||
whenExpression.replaceIsExhaustive(true)
|
||||
return whenExpression
|
||||
whenExpression.replaceExhaustivenessStatus(ExhaustivenessStatus.Exhaustive)
|
||||
return
|
||||
}
|
||||
|
||||
val typeRef = whenExpression.subjectVariable?.returnTypeRef
|
||||
?: whenExpression.subject?.typeRef
|
||||
?: return null
|
||||
?: return
|
||||
|
||||
// TODO: add some report logic about flexible type (see WHEN_ENUM_CAN_BE_NULL_IN_JAVA diagnostic in old frontend)
|
||||
val type = typeRef.coneType.lowerBoundIfFlexible()
|
||||
val lookupTag = (type as? ConeLookupTagBasedType)?.lookupTag ?: return null
|
||||
val lookupTag = (type as? ConeLookupTagBasedType)?.lookupTag ?: return
|
||||
val nullable = type.nullability == ConeNullability.NULLABLE
|
||||
val isExhaustive = when {
|
||||
((lookupTag as? ConeClassLikeLookupTag)?.classId == bodyResolveComponents.session.builtinTypes.booleanType.id) -> {
|
||||
@@ -55,18 +54,18 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
|
||||
whenExpression.branches.isEmpty() -> false
|
||||
|
||||
else -> {
|
||||
val klass = lookupTag.toSymbol(bodyResolveComponents.session)?.fir as? FirRegularClass ?: return null
|
||||
val klass = lookupTag.toSymbol(bodyResolveComponents.session)?.fir as? FirRegularClass ?: return
|
||||
when {
|
||||
klass.classKind == ClassKind.ENUM_CLASS -> checkEnumExhaustiveness(whenExpression, klass, nullable)
|
||||
klass.modality == Modality.SEALED -> checkSealedClassExhaustiveness(whenExpression, klass, nullable)
|
||||
else -> return null
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return runIf(isExhaustive) {
|
||||
whenExpression.replaceIsExhaustive(true)
|
||||
whenExpression
|
||||
if (isExhaustive) {
|
||||
whenExpression.replaceExhaustivenessStatus(ExhaustivenessStatus.Exhaustive)
|
||||
} else {
|
||||
whenExpression.replaceExhaustivenessStatus(ExhaustivenessStatus.NotExhaustive(listOf()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract class FirWhenExpression : FirExpression(), FirResolvable {
|
||||
abstract val subject: FirExpression?
|
||||
abstract val subjectVariable: FirVariable<*>?
|
||||
abstract val branches: List<FirWhenBranch>
|
||||
abstract val isExhaustive: Boolean
|
||||
abstract val exhaustivenessStatus: ExhaustivenessStatus?
|
||||
abstract val usedAsExpression: Boolean
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitWhenExpression(this, data)
|
||||
@@ -33,7 +33,7 @@ abstract class FirWhenExpression : FirExpression(), FirResolvable {
|
||||
|
||||
abstract override fun replaceCalleeReference(newCalleeReference: FirReference)
|
||||
|
||||
abstract fun replaceIsExhaustive(newIsExhaustive: Boolean)
|
||||
abstract fun replaceExhaustivenessStatus(newExhaustivenessStatus: ExhaustivenessStatus?)
|
||||
|
||||
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirWhenExpression
|
||||
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
|
||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.expressions.ExhaustivenessStatus
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
|
||||
@@ -36,7 +37,7 @@ class FirWhenExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBui
|
||||
var subject: FirExpression? = null
|
||||
var subjectVariable: FirVariable<*>? = null
|
||||
val branches: MutableList<FirWhenBranch> = mutableListOf()
|
||||
var isExhaustive: Boolean = false
|
||||
var exhaustivenessStatus: ExhaustivenessStatus? = null
|
||||
var usedAsExpression: Boolean by kotlin.properties.Delegates.notNull<Boolean>()
|
||||
|
||||
override fun build(): FirWhenExpression {
|
||||
@@ -48,7 +49,7 @@ class FirWhenExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBui
|
||||
subject,
|
||||
subjectVariable,
|
||||
branches,
|
||||
isExhaustive,
|
||||
exhaustivenessStatus,
|
||||
usedAsExpression,
|
||||
)
|
||||
}
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.expressions.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.expressions.ExhaustivenessStatus
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
|
||||
@@ -28,7 +29,7 @@ internal class FirWhenExpressionImpl(
|
||||
override var subject: FirExpression?,
|
||||
override var subjectVariable: FirVariable<*>?,
|
||||
override val branches: MutableList<FirWhenBranch>,
|
||||
override var isExhaustive: Boolean,
|
||||
override var exhaustivenessStatus: ExhaustivenessStatus?,
|
||||
override val usedAsExpression: Boolean,
|
||||
) : FirWhenExpression() {
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||
@@ -91,7 +92,7 @@ internal class FirWhenExpressionImpl(
|
||||
calleeReference = newCalleeReference
|
||||
}
|
||||
|
||||
override fun replaceIsExhaustive(newIsExhaustive: Boolean) {
|
||||
isExhaustive = newIsExhaustive
|
||||
override fun replaceExhaustivenessStatus(newExhaustivenessStatus: ExhaustivenessStatus?) {
|
||||
exhaustivenessStatus = newExhaustivenessStatus
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
sealed class ExhaustivenessStatus {
|
||||
object Exhaustive : ExhaustivenessStatus()
|
||||
class NotExhaustive(val reasons: List<WhenMissingCase>) : ExhaustivenessStatus()
|
||||
}
|
||||
|
||||
sealed class WhenMissingCase {
|
||||
object Unknown : WhenMissingCase()
|
||||
object NullIsMissing : WhenMissingCase()
|
||||
class BooleanIsMissing(val value: Boolean) : WhenMissingCase()
|
||||
class IsTypeCheckIsMissing(val classId: ClassId) : WhenMissingCase()
|
||||
class EnumCheckIsMissing(val classId: ClassId) : WhenMissingCase()
|
||||
}
|
||||
|
||||
val FirWhenExpression.isExhaustive: Boolean
|
||||
get() = exhaustivenessStatus == ExhaustivenessStatus.Exhaustive
|
||||
+1
-1
@@ -219,7 +219,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
|
||||
}
|
||||
|
||||
builder(whenExpression) {
|
||||
defaultFalse("isExhaustive")
|
||||
defaultNull("exhaustivenessStatus")
|
||||
default("calleeReference", "FirStubReference")
|
||||
useTypes(stubReferenceType)
|
||||
}
|
||||
|
||||
+1
-1
@@ -587,7 +587,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
+field("subject", expression, nullable = true).withTransform()
|
||||
+field("subjectVariable", variable.withArgs("F" to "*"), nullable = true)
|
||||
+fieldList("branches", whenBranch).withTransform()
|
||||
+booleanField("isExhaustive", withReplace = true)
|
||||
+field("exhaustivenessStatus", exhaustivenessStatusType, nullable = true, withReplace = true)
|
||||
+booleanField("usedAsExpression")
|
||||
needTransformOtherChildren()
|
||||
}
|
||||
|
||||
@@ -84,3 +84,5 @@ val firImplementationDetailType = generatedType("FirImplementationDetail")
|
||||
val declarationOriginType = generatedType("declarations", "FirDeclarationOrigin")
|
||||
val declarationAttributesType = generatedType("declarations", "FirDeclarationAttributes")
|
||||
val annotationResolveStatusType = generatedType("expressions", "FirAnnotationResolveStatus")
|
||||
|
||||
val exhaustivenessStatusType = generatedType("expressions", "ExhaustivenessStatus")
|
||||
|
||||
Reference in New Issue
Block a user