[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:
+12
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
+17
-14
@@ -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
@@ -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<!>)
|
||||
|
||||
+8
@@ -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<!>
|
||||
+9
@@ -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() {}
|
||||
Generated
+12
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user