[FIR] Add new VALID_CONST entry to the ConstantArgumentKind
This commit is contained in:
+30
-25
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user