[FIR] Move const check utils functions into FirConstCheckVisitor
This is the first step of moving all const check code into a visitor class.
This commit is contained in:
+33
-20
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers
|
|||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
|
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -40,8 +42,13 @@ internal fun checkConstantArguments(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
): ConstantArgumentKind {
|
): ConstantArgumentKind {
|
||||||
if (expression == null) return ConstantArgumentKind.VALID_CONST
|
if (expression == null) return ConstantArgumentKind.VALID_CONST
|
||||||
|
|
||||||
|
val firConstCheckVisitor = FirConstCheckVisitor()
|
||||||
|
|
||||||
val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true)
|
val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true)
|
||||||
val classKindOfParent = (expressionSymbol?.getReferencedClassSymbol(session) as? FirRegularClassSymbol)?.classKind
|
val classKindOfParent = with(firConstCheckVisitor) {
|
||||||
|
(expressionSymbol?.getReferencedClassSymbol(session) as? FirRegularClassSymbol)?.classKind
|
||||||
|
}
|
||||||
val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(LanguageFeature.IntrinsicConstEvaluation)
|
val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(LanguageFeature.IntrinsicConstEvaluation)
|
||||||
|
|
||||||
fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
|
fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
|
||||||
@@ -163,7 +170,7 @@ internal fun checkConstantArguments(
|
|||||||
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
|
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
|
||||||
val symbol = calleeReference.resolvedSymbol as? FirNamedFunctionSymbol ?: return ConstantArgumentKind.NOT_CONST
|
val symbol = calleeReference.resolvedSymbol as? FirNamedFunctionSymbol ?: return ConstantArgumentKind.NOT_CONST
|
||||||
|
|
||||||
if (!symbol.canBeEvaluated() && !expression.isCompileTimeBuiltinCall(session)) {
|
if (!symbol.canBeEvaluated() && !with(firConstCheckVisitor) { expression.isCompileTimeBuiltinCall(session) }) {
|
||||||
return ConstantArgumentKind.NOT_CONST
|
return ConstantArgumentKind.NOT_CONST
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +199,7 @@ internal fun checkConstantArguments(
|
|||||||
val propertySymbol = expressionSymbol as? FirPropertySymbol ?: return ConstantArgumentKind.NOT_CONST
|
val propertySymbol = expressionSymbol as? FirPropertySymbol ?: return ConstantArgumentKind.NOT_CONST
|
||||||
|
|
||||||
when {
|
when {
|
||||||
propertySymbol.unwrapFakeOverrides().canBeEvaluated() || propertySymbol.isCompileTimeBuiltinProperty(session) -> {
|
propertySymbol.unwrapFakeOverrides().canBeEvaluated() || with(firConstCheckVisitor) { propertySymbol.isCompileTimeBuiltinProperty(session) } -> {
|
||||||
val receiver = listOf(expression.dispatchReceiver, expression.extensionReceiver).single { it != null }!!
|
val receiver = listOf(expression.dispatchReceiver, expression.extensionReceiver).single { it != null }!!
|
||||||
return checkConstantArguments(receiver, session)
|
return checkConstantArguments(receiver, session)
|
||||||
}
|
}
|
||||||
@@ -215,6 +222,22 @@ internal fun checkConstantArguments(
|
|||||||
return ConstantArgumentKind.VALID_CONST
|
return ConstantArgumentKind.VALID_CONST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal enum class ConstantArgumentKind {
|
||||||
|
VALID_CONST,
|
||||||
|
NOT_CONST,
|
||||||
|
ENUM_NOT_CONST,
|
||||||
|
NOT_KCLASS_LITERAL,
|
||||||
|
NOT_CONST_VAL_IN_CONST_EXPRESSION,
|
||||||
|
KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR;
|
||||||
|
|
||||||
|
inline fun ifNotValidConst(action: (ConstantArgumentKind) -> Unit) {
|
||||||
|
if (this != VALID_CONST) {
|
||||||
|
action(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FirConstCheckVisitor() : FirVisitor<ConstantArgumentKind, Nothing?>() {
|
||||||
private val compileTimeFunctions = setOf(
|
private val compileTimeFunctions = setOf(
|
||||||
*OperatorNameConventions.BINARY_OPERATION_NAMES.toTypedArray(), *OperatorNameConventions.UNARY_OPERATION_NAMES.toTypedArray(),
|
*OperatorNameConventions.BINARY_OPERATION_NAMES.toTypedArray(), *OperatorNameConventions.UNARY_OPERATION_NAMES.toTypedArray(),
|
||||||
OperatorNameConventions.SHL, OperatorNameConventions.SHR, OperatorNameConventions.USHR,
|
OperatorNameConventions.SHL, OperatorNameConventions.SHR, OperatorNameConventions.USHR,
|
||||||
@@ -228,7 +251,11 @@ private val compileTimeConversionFunctions = listOf(
|
|||||||
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
|
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
|
||||||
).mapTo(hashSetOf()) { Name.identifier(it) }
|
).mapTo(hashSetOf()) { Name.identifier(it) }
|
||||||
|
|
||||||
private fun FirFunctionCall.isCompileTimeBuiltinCall(session: FirSession): Boolean {
|
override fun visitElement(element: FirElement, data: Nothing?): ConstantArgumentKind {
|
||||||
|
return ConstantArgumentKind.NOT_CONST
|
||||||
|
}
|
||||||
|
|
||||||
|
fun FirFunctionCall.isCompileTimeBuiltinCall(session: FirSession): Boolean {
|
||||||
val calleeReference = this.calleeReference
|
val calleeReference = this.calleeReference
|
||||||
if (calleeReference !is FirResolvedNamedReference) return false
|
if (calleeReference !is FirResolvedNamedReference) return false
|
||||||
|
|
||||||
@@ -252,7 +279,7 @@ private fun FirFunctionCall.isCompileTimeBuiltinCall(session: FirSession): Boole
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirPropertySymbol.isCompileTimeBuiltinProperty(session: FirSession): Boolean {
|
fun FirPropertySymbol.isCompileTimeBuiltinProperty(session: FirSession): Boolean {
|
||||||
val receiverType = dispatchReceiverType ?: receiverParameter?.typeRef?.coneTypeSafe<ConeKotlinType>() ?: return false
|
val receiverType = dispatchReceiverType ?: receiverParameter?.typeRef?.coneTypeSafe<ConeKotlinType>() ?: return false
|
||||||
val receiverClassId = receiverType.fullyExpandedClassId(session) ?: return false
|
val receiverClassId = receiverType.fullyExpandedClassId(session) ?: return false
|
||||||
return when (name.asString()) {
|
return when (name.asString()) {
|
||||||
@@ -266,23 +293,9 @@ private fun FirCallableSymbol<*>?.fromKotlin(): Boolean {
|
|||||||
return this?.callableId?.packageName?.asString() == "kotlin"
|
return this?.callableId?.packageName?.asString() == "kotlin"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirCallableSymbol<*>?.getReferencedClassSymbol(session: FirSession): FirBasedSymbol<*>? =
|
fun FirCallableSymbol<*>?.getReferencedClassSymbol(session: FirSession): FirBasedSymbol<*>? =
|
||||||
this?.resolvedReturnTypeRef
|
this?.resolvedReturnTypeRef
|
||||||
?.coneTypeSafe<ConeLookupTagBasedType>()
|
?.coneTypeSafe<ConeLookupTagBasedType>()
|
||||||
?.lookupTag
|
?.lookupTag
|
||||||
?.toSymbol(session)
|
?.toSymbol(session)
|
||||||
|
|
||||||
internal enum class ConstantArgumentKind {
|
|
||||||
VALID_CONST,
|
|
||||||
NOT_CONST,
|
|
||||||
ENUM_NOT_CONST,
|
|
||||||
NOT_KCLASS_LITERAL,
|
|
||||||
NOT_CONST_VAL_IN_CONST_EXPRESSION,
|
|
||||||
KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR;
|
|
||||||
|
|
||||||
inline fun ifNotValidConst(action: (ConstantArgumentKind) -> Unit) {
|
|
||||||
if (this != VALID_CONST) {
|
|
||||||
action(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user