[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:
Ivan Kylchik
2023-12-20 20:48:16 +01:00
committed by Space Team
parent 4e8adc6693
commit 7c9e5a1a4b
@@ -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)
}
}
} }