[FIR] Properly check constructor call in FirConstCheckVisitor

This commit is contained in:
Ivan Kylchik
2023-12-21 00:13:30 +01:00
committed by Space Team
parent 1423576d1a
commit 6c3aa6568e
4 changed files with 36 additions and 37 deletions
@@ -1,5 +1,5 @@
// Should be something like TYPE_MISMATCH here
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@file:Some(return x)<!>
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@file:Some(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>return x<!>)<!>
const val x = 42
@@ -44,36 +44,7 @@ internal fun checkConstantArguments(
session: FirSession,
): ConstantArgumentKind {
if (expression == null) return ConstantArgumentKind.VALID_CONST
val firConstCheckVisitor = FirConstCheckVisitor(session)
val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true)
val classKindOfParent = with(firConstCheckVisitor) {
(expressionSymbol?.getReferencedClassSymbol() as? FirRegularClassSymbol)?.classKind
}
fun FirExpression.getExpandedType() = resolvedType.fullyExpandedType(session)
when {
expressionSymbol is FirConstructorSymbol && classKindOfParent == ClassKind.ANNOTATION_CLASS -> {
return ConstantArgumentKind.VALID_CONST
}
expressionSymbol == null -> {
return ConstantArgumentKind.VALID_CONST
}
expressionSymbol is FirConstructorSymbol -> {
if (expression is FirCallableReferenceAccess) return ConstantArgumentKind.VALID_CONST
if (expression.getExpandedType().isUnsignedType) {
(expression as FirFunctionCall).arguments.forEach { argumentExpression ->
checkConstantArguments(argumentExpression, session).ifNotValidConst { return it }
}
} else {
return ConstantArgumentKind.NOT_CONST
}
}
else -> return expression.accept(firConstCheckVisitor, null)
}
return ConstantArgumentKind.VALID_CONST
return expression.accept(FirConstCheckVisitor(session), null)
}
internal enum class ConstantArgumentKind {
@@ -276,8 +247,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
}
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
val symbol = calleeReference.resolvedSymbol as? FirNamedFunctionSymbol ?: return ConstantArgumentKind.NOT_CONST
return when (val symbol = calleeReference.resolvedSymbol) {
is FirNamedFunctionSymbol -> visitNamedFunction(functionCall, symbol)
is FirConstructorSymbol -> visitConstructorCall(functionCall, symbol)
else -> ConstantArgumentKind.NOT_CONST
}
}
private fun visitNamedFunction(functionCall: FirFunctionCall, symbol: FirNamedFunctionSymbol): ConstantArgumentKind {
if (!symbol.canBeEvaluated() && !functionCall.isCompileTimeBuiltinCall()) {
return ConstantArgumentKind.NOT_CONST
}
@@ -290,12 +267,26 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
return ConstantArgumentKind.NOT_CONST
}
exp.accept(this, data).ifNotValidConst { return it }
exp.accept(this, null).ifNotValidConst { return it }
}
return ConstantArgumentKind.VALID_CONST
}
private fun visitConstructorCall(constructorCall: FirFunctionCall, symbol: FirConstructorSymbol): ConstantArgumentKind {
val classKindOfParent = (symbol.getReferencedClassSymbol() as? FirRegularClassSymbol)?.classKind
return when {
classKindOfParent == ClassKind.ANNOTATION_CLASS -> ConstantArgumentKind.VALID_CONST
constructorCall.getExpandedType().isUnsignedType -> {
constructorCall.arguments.forEach { argumentExpression ->
argumentExpression.accept(this, null).ifNotValidConst { return it }
}
ConstantArgumentKind.VALID_CONST
}
else -> ConstantArgumentKind.NOT_CONST
}
}
override fun visitQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?
): ConstantArgumentKind {
@@ -307,6 +298,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
return ConstantArgumentKind.VALID_CONST
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: Nothing?): ConstantArgumentKind {
return ConstantArgumentKind.VALID_CONST
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Nothing?): ConstantArgumentKind {
return visitQualifiedAccessExpression(callableReferenceAccess, data)
}
// --- Utils ---
private fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session)
@@ -352,7 +351,7 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
return this?.callableId?.packageName?.asString() == "kotlin"
}
fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? =
private fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? =
this?.resolvedReturnTypeRef
?.coneTypeSafe<ConeLookupTagBasedType>()
?.lookupTag
@@ -3,14 +3,14 @@
@Target(AnnotationTarget.TYPE)
annotation class Ann(val x: Int)
class A<T: @Ann(<!ARGUMENT_TYPE_MISMATCH!>{
class A<T: @Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{
fun local() = 1
var result = local()
result += 1
result
}<!>) Any>
fun f(x: @Ann(<!ARGUMENT_TYPE_MISMATCH!>{
fun f(x: @Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{
fun local() = 1
var result = local()
result += 1
@@ -1,5 +1,5 @@
// ISSUE: KT-59110
<!WRONG_ANNOTATION_TARGET!>@Target(<!ARGUMENT_TYPE_MISMATCH!>{}<!>)<!>
<!WRONG_ANNOTATION_TARGET!>@Target(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{}<!>)<!>
interface SomeInterface {
}