[FIR] Always expand a type before checking it in FirConstChecks

The issue appeared when we analyzed some typealias.
1. The typealias itself could be valid, but it could point
to an invalid type.
2. The typealias could point, for example, to an unsigned
type that must be handled in a special way

#KT-59894
This commit is contained in:
Ivan Kylchik
2023-11-15 17:25:19 +01:00
committed by Space Team
parent ab1ce759a3
commit 5dbe81fd7f
9 changed files with 96 additions and 16 deletions
@@ -6901,6 +6901,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt");
}
@Test
@TestMetadata("typeAliasToUnsigned.kt")
public void testTypeAliasToUnsigned() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt");
}
@Test
@TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("unresolvedReference.kt")
public void testUnresolvedReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt");
}
@Test
@TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception {
@@ -6901,6 +6901,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt");
}
@Test
@TestMetadata("typeAliasToUnsigned.kt")
public void testTypeAliasToUnsigned() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt");
}
@Test
@TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("unresolvedReference.kt")
public void testUnresolvedReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt");
}
@Test
@TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception {
@@ -6895,6 +6895,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt");
}
@Test
@TestMetadata("typeAliasToUnsigned.kt")
public void testTypeAliasToUnsigned() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt");
}
@Test
@TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6907,6 +6913,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("unresolvedReference.kt")
public void testUnresolvedReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt");
}
@Test
@TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception {
@@ -6901,6 +6901,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt");
}
@Test
@TestMetadata("typeAliasToUnsigned.kt")
public void testTypeAliasToUnsigned() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt");
}
@Test
@TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("unresolvedReference.kt")
public void testUnresolvedReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt");
}
@Test
@TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception {
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -48,6 +49,8 @@ internal fun checkConstantArguments(
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session)
}
fun FirExpression.getExpandedType() = resolvedType.fullyExpandedType(session)
when {
expression is FirNamedArgumentExpression -> {
checkConstantArguments(expression.expression, session)
@@ -93,19 +96,19 @@ internal fun checkConstantArguments(
return ConstantArgumentKind.NOT_CONST
}
for (exp in (expression as FirCall).arguments) {
if (exp is FirResolvedQualifier || expression.isForbiddenComplexConstant(session) || exp.resolvedType.isUnsignedType) {
if (exp is FirResolvedQualifier || expression.isForbiddenComplexConstant(session) || exp.getExpandedType().isUnsignedType) {
return ConstantArgumentKind.NOT_CONST
}
checkConstantArguments(exp, session)?.let { return it }
}
}
expression is FirGetClassCall -> {
var coneType = (expression as? FirCall)?.argument?.resolvedType
var coneType = (expression as? FirCall)?.argument?.getExpandedType()
if (coneType is ConeErrorType)
return ConstantArgumentKind.NOT_CONST
while (coneType?.fullyExpandedClassId(session) == StandardClassIds.Array)
while (coneType?.classId == StandardClassIds.Array)
coneType = (coneType.lowerBoundIfFlexible().typeArguments.first() as? ConeKotlinTypeProjection)?.type ?: break
return when {
@@ -134,7 +137,7 @@ internal fun checkConstantArguments(
}
expressionSymbol is FirConstructorSymbol -> {
if (expression is FirCallableReferenceAccess) return null
if (expression.resolvedType.isUnsignedType) {
if (expression.getExpandedType().isUnsignedType) {
(expression as FirFunctionCall).arguments.forEach { argumentExpression ->
checkConstantArguments(argumentExpression, session)?.let { return it }
}
@@ -147,7 +150,7 @@ internal fun checkConstantArguments(
if (calleeReference is FirErrorNamedReference) {
return null
}
if (expression.resolvedType.fullyExpandedClassId(session) == StandardClassIds.KClass) {
if (expression.getExpandedType().classId == StandardClassIds.KClass) {
return ConstantArgumentKind.NOT_KCLASS_LITERAL
}
@@ -160,7 +163,7 @@ internal fun checkConstantArguments(
for (exp in expression.arguments.plus(expression.dispatchReceiver).plus(expression.extensionReceiver)) {
if (exp == null) continue
val expClassId = exp.resolvedType.lowerBoundIfFlexible().fullyExpandedClassId(session)
val expClassId = exp.getExpandedType().lowerBoundIfFlexible().fullyExpandedClassId(session)
// TODO, KT-59823: add annotation for allowed constant types
if (expClassId !in StandardClassIds.constantAllowedTypes) {
return ConstantArgumentKind.NOT_CONST
@@ -172,7 +175,7 @@ internal fun checkConstantArguments(
return null
}
expression is FirQualifiedAccessExpression -> {
val expressionType = expression.resolvedType
val expressionType = expression.getExpandedType()
if (expressionType.isReflectFunctionType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(
session
)
@@ -190,7 +193,7 @@ internal fun checkConstantArguments(
return checkConstantArguments(receiver, session)
}
propertySymbol.isLocal -> return ConstantArgumentKind.NOT_CONST
expressionType.fullyExpandedClassId(session) == StandardClassIds.KClass -> return ConstantArgumentKind.NOT_KCLASS_LITERAL
expressionType.classId == StandardClassIds.KClass -> return ConstantArgumentKind.NOT_KCLASS_LITERAL
}
return when (property.initializer) {
is FirConstExpression<*> -> when {
@@ -213,16 +216,17 @@ private fun FirExpression.isForbiddenComplexConstant(session: FirSession): Boole
val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(
LanguageFeature.IntrinsicConstEvaluation
)
return !intrinsicConstEvaluation && forbidComplexBooleanExpressions && isComplexBooleanConstant
return !intrinsicConstEvaluation && forbidComplexBooleanExpressions && isComplexBooleanConstant(session)
}
private val FirExpression.isComplexBooleanConstant
get(): Boolean = when {
!resolvedType.isBoolean -> false
private fun FirExpression.isComplexBooleanConstant(session: FirSession): Boolean {
return when {
!resolvedType.fullyExpandedType(session).isBoolean -> false
this is FirConstExpression<*> -> false
usesVariableAsConstant -> false
else -> true
}
}
/**
* See: org.jetbranis.kotlin.resolve.constants.CompileTimeConstant.Parameters.usesVariableAsConstant
@@ -254,8 +258,7 @@ private fun FirFunctionCall.isCompileTimeBuiltinCall(session: FirSession): Boole
val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
if (!symbol.fromKotlin()) return false
val coneType = this.dispatchReceiver?.resolvedType
val receiverClassId = coneType?.fullyExpandedClassId(session)
val receiverClassId = this.dispatchReceiver?.resolvedType?.fullyExpandedClassId(session)
if (receiverClassId in StandardClassIds.unsignedTypes) return false
+2 -2
View File
@@ -73,7 +73,7 @@ fun throwsSpreadArrayOfUnresolved() {}
typealias UEAlias = <!UNRESOLVED_REFERENCE!>UE<!>
@Throws(UEAlias::class)
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
fun throwsTypealiasToUnresolved() {}
interface Base0 {
@@ -313,7 +313,7 @@ suspend fun suspendThrowsSpreadLiteralWithUnresolved() {}
@Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
suspend fun suspendThrowsSpreadArrayOfUnresolved() {}
@Throws(UEAlias::class)
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
suspend fun suspendThrowsTypealiasToUnresolved() {}
@Throws(<!ARGUMENT_TYPE_MISMATCH!>Orphan::class<!>)
@@ -0,0 +1,8 @@
// FIR_IDENTICAL
// WITH_STDLIB
typealias UI = UInt
const val a: UI = 1u
const val b: UI = a
const val c = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>a == b<!>
@@ -0,0 +1,9 @@
// FIR_IDENTICAL
import kotlin.reflect.KClass
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
typealias UEAlias = <!UNRESOLVED_REFERENCE!>UE<!>
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
fun throwsTypealiasToUnresolved() {}
@@ -6901,6 +6901,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt");
}
@Test
@TestMetadata("typeAliasToUnsigned.kt")
public void testTypeAliasToUnsigned() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt");
}
@Test
@TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("unresolvedReference.kt")
public void testUnresolvedReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt");
}
@Test
@TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception {