[FIR] Add new VALID_CONST entry to the ConstantArgumentKind

This commit is contained in:
Ivan Kylchik
2023-10-31 16:30:31 +01:00
committed by Space Team
parent c661f654ee
commit 4e8adc6693
3 changed files with 32 additions and 27 deletions
@@ -32,14 +32,14 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
fun ConeKotlinType.canBeUsedForConstVal(): Boolean = with(lowerBoundIfFlexible()) { isPrimitive || isString || isUnsignedType } fun ConeKotlinType.canBeUsedForConstVal(): Boolean = with(lowerBoundIfFlexible()) { isPrimitive || isString || isUnsignedType }
fun canBeEvaluatedAtCompileTime(expression: FirExpression?, session: FirSession): Boolean { fun canBeEvaluatedAtCompileTime(expression: FirExpression?, session: FirSession): Boolean {
return checkConstantArguments(expression, session) == null return checkConstantArguments(expression, session) == ConstantArgumentKind.VALID_CONST
} }
internal fun checkConstantArguments( internal fun checkConstantArguments(
expression: FirExpression?, expression: FirExpression?,
session: FirSession, session: FirSession,
): ConstantArgumentKind? { ): ConstantArgumentKind {
if (expression == null) return null if (expression == null) return ConstantArgumentKind.VALID_CONST
val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true) val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true)
val classKindOfParent = (expressionSymbol?.getReferencedClassSymbol(session) as? FirRegularClassSymbol)?.classKind val classKindOfParent = (expressionSymbol?.getReferencedClassSymbol(session) as? FirRegularClassSymbol)?.classKind
val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(LanguageFeature.IntrinsicConstEvaluation) val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(LanguageFeature.IntrinsicConstEvaluation)
@@ -52,7 +52,7 @@ internal fun checkConstantArguments(
when { when {
expression is FirNamedArgumentExpression -> { expression is FirNamedArgumentExpression -> {
checkConstantArguments(expression.expression, session) return checkConstantArguments(expression.expression, session)
} }
expression is FirTypeOperatorCall -> if (expression.operation == FirOperation.AS) return ConstantArgumentKind.NOT_CONST expression is FirTypeOperatorCall -> if (expression.operation == FirOperation.AS) return ConstantArgumentKind.NOT_CONST
expression is FirWhenExpression -> { expression is FirWhenExpression -> {
@@ -60,21 +60,21 @@ internal fun checkConstantArguments(
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
expression.subject?.let { subject -> checkConstantArguments(subject, session)?.let { return it } } expression.subject?.let { subject -> checkConstantArguments(subject, session).ifNotValidConst { return it } }
for (branch in expression.branches) { for (branch in expression.branches) {
checkConstantArguments(branch.condition, session)?.let { return it } checkConstantArguments(branch.condition, session).ifNotValidConst { return it }
branch.result.statements.forEach { stmt -> branch.result.statements.forEach { stmt ->
if (stmt !is FirExpression) return ConstantArgumentKind.NOT_CONST if (stmt !is FirExpression) return ConstantArgumentKind.NOT_CONST
checkConstantArguments(stmt, session)?.let { return it } checkConstantArguments(stmt, session).ifNotValidConst { return it }
} }
} }
return null return ConstantArgumentKind.VALID_CONST
} }
expression is FirConstExpression<*> expression is FirConstExpression<*>
|| expressionSymbol is FirEnumEntrySymbol || expressionSymbol is FirEnumEntrySymbol
|| expressionSymbol?.isConst == true || expressionSymbol?.isConst == true
|| expressionSymbol is FirConstructorSymbol && classKindOfParent == ClassKind.ANNOTATION_CLASS -> { || expressionSymbol is FirConstructorSymbol && classKindOfParent == ClassKind.ANNOTATION_CLASS -> {
//DO NOTHING return ConstantArgumentKind.VALID_CONST
} }
classKindOfParent == ClassKind.ENUM_CLASS -> { classKindOfParent == ClassKind.ENUM_CLASS -> {
return ConstantArgumentKind.ENUM_NOT_CONST return ConstantArgumentKind.ENUM_NOT_CONST
@@ -87,7 +87,7 @@ internal fun checkConstantArguments(
if (exp is FirResolvedQualifier || exp is FirGetClassCall) { if (exp is FirResolvedQualifier || exp is FirGetClassCall) {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
checkConstantArguments(exp, session)?.let { return it } checkConstantArguments(exp, session).ifNotValidConst { return it }
} }
} }
expression is FirEqualityOperatorCall -> { expression is FirEqualityOperatorCall -> {
@@ -103,12 +103,12 @@ internal fun checkConstantArguments(
if (exp is FirResolvedQualifier || exp is FirGetClassCall || exp.getExpandedType().isUnsignedType) { if (exp is FirResolvedQualifier || exp is FirGetClassCall || exp.getExpandedType().isUnsignedType) {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
checkConstantArguments(exp, session)?.let { return it } checkConstantArguments(exp, session).ifNotValidConst { return it }
} }
} }
expression is FirBinaryLogicExpression -> { expression is FirBinaryLogicExpression -> {
checkConstantArguments(expression.leftOperand, session)?.let { return it } checkConstantArguments(expression.leftOperand, session).ifNotValidConst { return it }
checkConstantArguments(expression.rightOperand, session)?.let { return it } checkConstantArguments(expression.rightOperand, session).ifNotValidConst { return it }
} }
expression is FirGetClassCall -> { expression is FirGetClassCall -> {
var coneType = expression.argument.getExpandedType() var coneType = expression.argument.getExpandedType()
@@ -122,21 +122,19 @@ internal fun checkConstantArguments(
return when { return when {
coneType is ConeTypeParameterType -> ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR coneType is ConeTypeParameterType -> ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
expression.argument !is FirResolvedQualifier -> ConstantArgumentKind.NOT_KCLASS_LITERAL expression.argument !is FirResolvedQualifier -> ConstantArgumentKind.NOT_KCLASS_LITERAL
else -> null else -> ConstantArgumentKind.VALID_CONST
} }
} }
expression is FirArrayLiteral -> { expression is FirArrayLiteral -> {
for (exp in expression.arguments) { for (exp in expression.arguments) {
checkConstantArguments(exp, session)?.let { checkConstantArguments(exp, session).ifNotValidConst { return it }
return it
}
} }
} }
expression is FirThisReceiverExpression -> { expression is FirThisReceiverExpression -> {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
expressionSymbol == null -> { expressionSymbol == null -> {
//DO NOTHING return ConstantArgumentKind.VALID_CONST
} }
expressionSymbol is FirFieldSymbol -> { expressionSymbol is FirFieldSymbol -> {
if (!expressionSymbol.isStatic || expressionSymbol.modality != Modality.FINAL || !expressionSymbol.hasConstantInitializer) { if (!expressionSymbol.isStatic || expressionSymbol.modality != Modality.FINAL || !expressionSymbol.hasConstantInitializer) {
@@ -144,10 +142,10 @@ internal fun checkConstantArguments(
} }
} }
expressionSymbol is FirConstructorSymbol -> { expressionSymbol is FirConstructorSymbol -> {
if (expression is FirCallableReferenceAccess) return null if (expression is FirCallableReferenceAccess) return ConstantArgumentKind.VALID_CONST
if (expression.getExpandedType().isUnsignedType) { if (expression.getExpandedType().isUnsignedType) {
(expression as FirFunctionCall).arguments.forEach { argumentExpression -> (expression as FirFunctionCall).arguments.forEach { argumentExpression ->
checkConstantArguments(argumentExpression, session)?.let { return it } checkConstantArguments(argumentExpression, session).ifNotValidConst { return it }
} }
} else { } else {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
@@ -156,7 +154,7 @@ internal fun checkConstantArguments(
expression is FirFunctionCall -> { expression is FirFunctionCall -> {
val calleeReference = expression.calleeReference val calleeReference = expression.calleeReference
if (calleeReference is FirErrorNamedReference) { if (calleeReference is FirErrorNamedReference) {
return null return ConstantArgumentKind.VALID_CONST
} }
if (expression.getExpandedType().classId == StandardClassIds.KClass) { if (expression.getExpandedType().classId == StandardClassIds.KClass) {
return ConstantArgumentKind.NOT_KCLASS_LITERAL return ConstantArgumentKind.NOT_KCLASS_LITERAL
@@ -177,10 +175,10 @@ internal fun checkConstantArguments(
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
checkConstantArguments(exp, session)?.let { return it } checkConstantArguments(exp, session).ifNotValidConst { return it }
} }
return null return ConstantArgumentKind.VALID_CONST
} }
expression is FirQualifiedAccessExpression -> { expression is FirQualifiedAccessExpression -> {
val expressionType = expression.getExpandedType() val expressionType = expression.getExpandedType()
@@ -214,7 +212,7 @@ internal fun checkConstantArguments(
} }
else -> return ConstantArgumentKind.NOT_CONST else -> return ConstantArgumentKind.NOT_CONST
} }
return null return ConstantArgumentKind.VALID_CONST
} }
private val compileTimeFunctions = setOf( private val compileTimeFunctions = setOf(
@@ -275,9 +273,16 @@ private fun FirCallableSymbol<*>?.getReferencedClassSymbol(session: FirSession):
?.toSymbol(session) ?.toSymbol(session)
internal enum class ConstantArgumentKind { internal enum class ConstantArgumentKind {
VALID_CONST,
NOT_CONST, NOT_CONST,
ENUM_NOT_CONST, ENUM_NOT_CONST,
NOT_KCLASS_LITERAL, NOT_KCLASS_LITERAL,
NOT_CONST_VAL_IN_CONST_EXPRESSION, NOT_CONST_VAL_IN_CONST_EXPRESSION,
KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR;
inline fun ifNotValidConst(action: (ConstantArgumentKind) -> Unit) {
if (this != VALID_CONST) {
action(this)
}
}
} }
@@ -64,7 +64,7 @@ object FirConstPropertyChecker : FirPropertyChecker() {
} }
val errorKind = when (checkConstantArguments(initializer, context.session)) { val errorKind = when (checkConstantArguments(initializer, context.session)) {
null -> return ConstantArgumentKind.VALID_CONST -> return
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION -> FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION -> FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION
else -> FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER else -> FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER
} }
@@ -106,7 +106,7 @@ object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
ConstantArgumentKind.NOT_KCLASS_LITERAL -> FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL ConstantArgumentKind.NOT_KCLASS_LITERAL -> FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR -> FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR -> FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION -> FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION -> FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION
null -> ConstantArgumentKind.VALID_CONST ->
//try to go deeper if we are not sure about this function call //try to go deeper if we are not sure about this function call
//to report non-constant val in not fully resolved calls //to report non-constant val in not fully resolved calls
if (expression is FirFunctionCall) checkArgumentList(expression.argumentList) if (expression is FirFunctionCall) checkArgumentList(expression.argumentList)