diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 2a092bc26b5..bda78bdadd6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -250,6 +250,9 @@ private class ConstantExpressionEvaluatorVisitor( private val stringExpressionEvaluator = object : KtVisitor, Nothing?>() { private fun createStringConstant(compileTimeConstant: CompileTimeConstant<*>): TypedCompileTimeConstant? { val constantValue = compileTimeConstant.toConstantValue(TypeUtils.NO_EXPECTED_TYPE) + if (constantValue.isStandaloneOnlyConstant()) { + return null; + } return when (constantValue) { is ErrorValue, is EnumValue -> return null is NullValue -> factory.createStringValue("null") @@ -341,6 +344,10 @@ private class ConstantExpressionEvaluatorVisitor( else null } + private fun isStandaloneOnlyConstant(expression: KtExpression): Boolean { + return ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.isStandaloneOnlyConstant() ?: return false + } + override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS, expectedType: KotlinType?): CompileTimeConstant<*>? { val compileTimeConstant = evaluate(expression.left, expectedType) if (compileTimeConstant != null) { @@ -404,6 +411,9 @@ private class ConstantExpressionEvaluatorVisitor( val resultingDescriptorName = resolvedCall.resultingDescriptor.name val argumentForReceiver = createOperationArgumentForReceiver(resolvedCall, receiverExpression) ?: return null + if (isStandaloneOnlyConstant(argumentForReceiver.expression)) { + return null + } val argumentsEntrySet = resolvedCall.valueArguments.entries if (argumentsEntrySet.isEmpty()) { @@ -426,6 +436,9 @@ private class ConstantExpressionEvaluatorVisitor( else if (argumentsEntrySet.size == 1) { val (parameter, argument) = argumentsEntrySet.first() val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter) ?: return null + if (isStandaloneOnlyConstant(argumentForParameter.expression)) { + return null + } if (isDivisionByZero(resultingDescriptorName.asString(), argumentForParameter.value)) { val parentExpression: KtExpression = PsiTreeUtil.getParentOfType(receiverExpression, KtExpression::class.java)!! @@ -886,3 +899,14 @@ internal fun unaryOperation( internal data class BinaryOperationKey(val f: CompileTimeType, val s: CompileTimeType, val functionName: String) internal data class UnaryOperationKey(val f: CompileTimeType, val functionName: String) + +fun ConstantValue<*>.isStandaloneOnlyConstant(): Boolean { + return this is KClassValue || this is EnumValue || this is AnnotationValue || this is ArrayValue +} + +fun CompileTimeConstant<*>.isStandaloneOnlyConstant(): Boolean { + return when(this) { + is TypedCompileTimeConstant -> this.constantValue.isStandaloneOnlyConstant() + else -> return false + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt new file mode 100644 index 00000000000..dcec148fbe6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt @@ -0,0 +1,18 @@ +annotation class AnnE(val i: String) + +enum class MyEnum { + A +} + +@AnnE("1" + MyEnum.A) +class Test + +@AnnE("1" + MyEnum::class) +class Test2 + +@AnnE("1" + AnnE("23")) +class Test3 + +@AnnE("1" + arrayOf("23", "34")) +class Test4 + diff --git a/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.txt b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.txt new file mode 100644 index 00000000000..20a89ca3c4a --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.txt @@ -0,0 +1,55 @@ +package + +public final annotation class AnnE : kotlin.Annotation { + public constructor AnnE(/*0*/ i: kotlin.String) + public final val i: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final enum class MyEnum : kotlin.Enum { + enum entry A + + private constructor MyEnum() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: MyEnum): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Use 'values()' function instead", replaceWith = kotlin.ReplaceWith(expression = "this.values()", imports = {})) public final /*synthesized*/ val values: kotlin.Array + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): MyEnum + public final /*synthesized*/ fun values(): kotlin.Array +} + +@AnnE() public final class Test { + public constructor Test() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@AnnE() public final class Test2 { + public constructor Test2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@AnnE() public final class Test3 { + public constructor Test3() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@AnnE() public final class Test4 { + public constructor Test4() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e9ca4ee738a..6dbd387e838 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -1163,6 +1163,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("standaloneInExpression.kt") + public void testStandaloneInExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt"); + doTest(fileName); + } + @TestMetadata("strings.kt") public void testStrings() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/strings.kt");