[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"); 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 @Test
@TestMetadata("unaryMinusIndepWoExpType.kt") @TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception { public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt"); 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 @Test
@TestMetadata("unsignedOperations.kt") @TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception { public void testUnsignedOperations() throws Exception {
@@ -6901,6 +6901,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt"); 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 @Test
@TestMetadata("unaryMinusIndepWoExpType.kt") @TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception { public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt"); 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 @Test
@TestMetadata("unsignedOperations.kt") @TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception { public void testUnsignedOperations() throws Exception {
@@ -6895,6 +6895,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt"); 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 @Test
@TestMetadata("unaryMinusIndepWoExpType.kt") @TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception { public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6907,6 +6913,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt"); 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 @Test
@TestMetadata("unsignedOperations.kt") @TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception { public void testUnsignedOperations() throws Exception {
@@ -6901,6 +6901,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/topLevelVar.kt"); 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 @Test
@TestMetadata("unaryMinusIndepWoExpType.kt") @TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception { public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt"); 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 @Test
@TestMetadata("unsignedOperations.kt") @TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception { 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.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol 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.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -48,6 +49,8 @@ internal fun checkConstantArguments(
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session) return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session)
} }
fun FirExpression.getExpandedType() = resolvedType.fullyExpandedType(session)
when { when {
expression is FirNamedArgumentExpression -> { expression is FirNamedArgumentExpression -> {
checkConstantArguments(expression.expression, session) checkConstantArguments(expression.expression, session)
@@ -93,19 +96,19 @@ internal fun checkConstantArguments(
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
} }
for (exp in (expression as FirCall).arguments) { 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 return ConstantArgumentKind.NOT_CONST
} }
checkConstantArguments(exp, session)?.let { return it } checkConstantArguments(exp, session)?.let { return it }
} }
} }
expression is FirGetClassCall -> { expression is FirGetClassCall -> {
var coneType = (expression as? FirCall)?.argument?.resolvedType var coneType = (expression as? FirCall)?.argument?.getExpandedType()
if (coneType is ConeErrorType) if (coneType is ConeErrorType)
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
while (coneType?.fullyExpandedClassId(session) == StandardClassIds.Array) while (coneType?.classId == StandardClassIds.Array)
coneType = (coneType.lowerBoundIfFlexible().typeArguments.first() as? ConeKotlinTypeProjection)?.type ?: break coneType = (coneType.lowerBoundIfFlexible().typeArguments.first() as? ConeKotlinTypeProjection)?.type ?: break
return when { return when {
@@ -134,7 +137,7 @@ internal fun checkConstantArguments(
} }
expressionSymbol is FirConstructorSymbol -> { expressionSymbol is FirConstructorSymbol -> {
if (expression is FirCallableReferenceAccess) return null if (expression is FirCallableReferenceAccess) return null
if (expression.resolvedType.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)?.let { return it }
} }
@@ -147,7 +150,7 @@ internal fun checkConstantArguments(
if (calleeReference is FirErrorNamedReference) { if (calleeReference is FirErrorNamedReference) {
return null return null
} }
if (expression.resolvedType.fullyExpandedClassId(session) == StandardClassIds.KClass) { if (expression.getExpandedType().classId == StandardClassIds.KClass) {
return ConstantArgumentKind.NOT_KCLASS_LITERAL return ConstantArgumentKind.NOT_KCLASS_LITERAL
} }
@@ -160,7 +163,7 @@ internal fun checkConstantArguments(
for (exp in expression.arguments.plus(expression.dispatchReceiver).plus(expression.extensionReceiver)) { for (exp in expression.arguments.plus(expression.dispatchReceiver).plus(expression.extensionReceiver)) {
if (exp == null) continue 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 // TODO, KT-59823: add annotation for allowed constant types
if (expClassId !in StandardClassIds.constantAllowedTypes) { if (expClassId !in StandardClassIds.constantAllowedTypes) {
return ConstantArgumentKind.NOT_CONST return ConstantArgumentKind.NOT_CONST
@@ -172,7 +175,7 @@ internal fun checkConstantArguments(
return null return null
} }
expression is FirQualifiedAccessExpression -> { expression is FirQualifiedAccessExpression -> {
val expressionType = expression.resolvedType val expressionType = expression.getExpandedType()
if (expressionType.isReflectFunctionType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty( if (expressionType.isReflectFunctionType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(
session session
) )
@@ -190,7 +193,7 @@ internal fun checkConstantArguments(
return checkConstantArguments(receiver, session) return checkConstantArguments(receiver, session)
} }
propertySymbol.isLocal -> return ConstantArgumentKind.NOT_CONST 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) { return when (property.initializer) {
is FirConstExpression<*> -> when { is FirConstExpression<*> -> when {
@@ -213,16 +216,17 @@ private fun FirExpression.isForbiddenComplexConstant(session: FirSession): Boole
val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature( val intrinsicConstEvaluation = session.languageVersionSettings.supportsFeature(
LanguageFeature.IntrinsicConstEvaluation LanguageFeature.IntrinsicConstEvaluation
) )
return !intrinsicConstEvaluation && forbidComplexBooleanExpressions && isComplexBooleanConstant return !intrinsicConstEvaluation && forbidComplexBooleanExpressions && isComplexBooleanConstant(session)
} }
private val FirExpression.isComplexBooleanConstant private fun FirExpression.isComplexBooleanConstant(session: FirSession): Boolean {
get(): Boolean = when { return when {
!resolvedType.isBoolean -> false !resolvedType.fullyExpandedType(session).isBoolean -> false
this is FirConstExpression<*> -> false this is FirConstExpression<*> -> false
usesVariableAsConstant -> false usesVariableAsConstant -> false
else -> true else -> true
} }
}
/** /**
* See: org.jetbranis.kotlin.resolve.constants.CompileTimeConstant.Parameters.usesVariableAsConstant * 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 val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
if (!symbol.fromKotlin()) return false if (!symbol.fromKotlin()) return false
val coneType = this.dispatchReceiver?.resolvedType val receiverClassId = this.dispatchReceiver?.resolvedType?.fullyExpandedClassId(session)
val receiverClassId = coneType?.fullyExpandedClassId(session)
if (receiverClassId in StandardClassIds.unsignedTypes) return false if (receiverClassId in StandardClassIds.unsignedTypes) return false
+2 -2
View File
@@ -73,7 +73,7 @@ fun throwsSpreadArrayOfUnresolved() {}
typealias UEAlias = <!UNRESOLVED_REFERENCE!>UE<!> typealias UEAlias = <!UNRESOLVED_REFERENCE!>UE<!>
@Throws(UEAlias::class) @Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
fun throwsTypealiasToUnresolved() {} fun throwsTypealiasToUnresolved() {}
interface Base0 { 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<!>)<!>) @Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
suspend fun suspendThrowsSpreadArrayOfUnresolved() {} suspend fun suspendThrowsSpreadArrayOfUnresolved() {}
@Throws(UEAlias::class) @Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
suspend fun suspendThrowsTypealiasToUnresolved() {} suspend fun suspendThrowsTypealiasToUnresolved() {}
@Throws(<!ARGUMENT_TYPE_MISMATCH!>Orphan::class<!>) @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"); 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 @Test
@TestMetadata("unaryMinusIndepWoExpType.kt") @TestMetadata("unaryMinusIndepWoExpType.kt")
public void testUnaryMinusIndepWoExpType() throws Exception { public void testUnaryMinusIndepWoExpType() throws Exception {
@@ -6913,6 +6919,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/constantEvaluator/constant/unaryMinusIndependentExpType.kt"); 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 @Test
@TestMetadata("unsignedOperations.kt") @TestMetadata("unsignedOperations.kt")
public void testUnsignedOperations() throws Exception { public void testUnsignedOperations() throws Exception {