[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 // 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 const val x = 42
@@ -44,36 +44,7 @@ internal fun checkConstantArguments(
session: FirSession, session: FirSession,
): ConstantArgumentKind { ): ConstantArgumentKind {
if (expression == null) return ConstantArgumentKind.VALID_CONST if (expression == null) return ConstantArgumentKind.VALID_CONST
return expression.accept(FirConstCheckVisitor(session), null)
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
} }
internal enum class ConstantArgumentKind { internal enum class ConstantArgumentKind {
@@ -276,8 +247,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
} }
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 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()) { if (!symbol.canBeEvaluated() && !functionCall.isCompileTimeBuiltinCall()) {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
@@ -290,12 +267,26 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
exp.accept(this, data).ifNotValidConst { return it } exp.accept(this, null).ifNotValidConst { return it }
} }
return ConstantArgumentKind.VALID_CONST 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( override fun visitQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing? qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?
): ConstantArgumentKind { ): ConstantArgumentKind {
@@ -307,6 +298,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
return ConstantArgumentKind.VALID_CONST 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 --- // --- Utils ---
private fun FirBasedSymbol<*>.canBeEvaluated(): Boolean { private fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session) 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" return this?.callableId?.packageName?.asString() == "kotlin"
} }
fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? = private fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? =
this?.resolvedReturnTypeRef this?.resolvedReturnTypeRef
?.coneTypeSafe<ConeLookupTagBasedType>() ?.coneTypeSafe<ConeLookupTagBasedType>()
?.lookupTag ?.lookupTag
@@ -3,14 +3,14 @@
@Target(AnnotationTarget.TYPE) @Target(AnnotationTarget.TYPE)
annotation class Ann(val x: Int) 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 fun local() = 1
var result = local() var result = local()
result += 1 result += 1
result result
}<!>) Any> }<!>) Any>
fun f(x: @Ann(<!ARGUMENT_TYPE_MISMATCH!>{ fun f(x: @Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{
fun local() = 1 fun local() = 1
var result = local() var result = local()
result += 1 result += 1
@@ -1,5 +1,5 @@
// ISSUE: KT-59110 // ISSUE: KT-59110
<!WRONG_ANNOTATION_TARGET!>@Target(<!ARGUMENT_TYPE_MISMATCH!>{}<!>)<!> <!WRONG_ANNOTATION_TARGET!>@Target(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{}<!>)<!>
interface SomeInterface { interface SomeInterface {
} }