From 5dbe81fd7f3c7de59eaea0cd6d5563cceaa3b46a Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Wed, 15 Nov 2023 17:25:19 +0100 Subject: [PATCH] [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 --- ...CompilerTestFE10TestdataTestGenerated.java | 12 +++++++ ...sticCompilerFE10TestDataTestGenerated.java | 12 +++++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 12 +++++++ ...siOldFrontendDiagnosticsTestGenerated.java | 12 +++++++ .../fir/analysis/checkers/FirConstChecks.kt | 31 ++++++++++--------- .../diagnostics/nativeTests/throws.fir.kt | 4 +-- .../constant/typeAliasToUnsigned.kt | 8 +++++ .../constant/unresolvedReference.kt | 9 ++++++ .../test/runners/DiagnosticTestGenerated.java | 12 +++++++ 9 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt create mode 100644 compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index fd94d20a6e7..7645d17ae05 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -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 { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index f912831885a..0392e393574 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index b6eb1ed5fe1..9df230e2838 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 970601e6df3..58787f8991d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -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 { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt index 1da395eff44..6ff4982e27a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt @@ -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 diff --git a/compiler/testData/diagnostics/nativeTests/throws.fir.kt b/compiler/testData/diagnostics/nativeTests/throws.fir.kt index 224e4e875f3..cf3a03be1fc 100644 --- a/compiler/testData/diagnostics/nativeTests/throws.fir.kt +++ b/compiler/testData/diagnostics/nativeTests/throws.fir.kt @@ -73,7 +73,7 @@ fun throwsSpreadArrayOfUnresolved() {} typealias UEAlias = UE -@Throws(UEAlias::class) +@Throws(UEAlias::class) fun throwsTypealiasToUnresolved() {} interface Base0 { @@ -313,7 +313,7 @@ suspend fun suspendThrowsSpreadLiteralWithUnresolved() {} @Throws(*arrayOf(UE::class)) suspend fun suspendThrowsSpreadArrayOfUnresolved() {} -@Throws(UEAlias::class) +@Throws(UEAlias::class) suspend fun suspendThrowsTypealiasToUnresolved() {} @Throws(Orphan::class) diff --git a/compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt b/compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt new file mode 100644 index 00000000000..3dce5b884ad --- /dev/null +++ b/compiler/testData/diagnostics/tests/constantEvaluator/constant/typeAliasToUnsigned.kt @@ -0,0 +1,8 @@ +// FIR_IDENTICAL +// WITH_STDLIB + +typealias UI = UInt + +const val a: UI = 1u +const val b: UI = a +const val c = a == b diff --git a/compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt b/compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt new file mode 100644 index 00000000000..17118d98147 --- /dev/null +++ b/compiler/testData/diagnostics/tests/constantEvaluator/constant/unresolvedReference.kt @@ -0,0 +1,9 @@ +// FIR_IDENTICAL +import kotlin.reflect.KClass + +public annotation class Throws(vararg val exceptionClasses: KClass) + +typealias UEAlias = UE + +@Throws(UEAlias::class) +fun throwsTypealiasToUnresolved() {} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index c1cb6465684..b74b59eef07 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -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 {