diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaPropertyInitializerEvaluatorImpl.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaPropertyInitializerEvaluatorImpl.java index 09f05f5d778..582a69a9e9f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaPropertyInitializerEvaluatorImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaPropertyInitializerEvaluatorImpl.java @@ -37,10 +37,13 @@ public class JavaPropertyInitializerEvaluatorImpl implements JavaPropertyInitial if (evaluatedExpression != null) { return ConstantsPackage.createCompileTimeConstant( evaluatedExpression, - ConstantExpressionEvaluator.isPropertyCompileTimeConstant(descriptor), - false, - true, - descriptor.getType()); + new CompileTimeConstant.Parameters.Impl( + ConstantExpressionEvaluator.isPropertyCompileTimeConstant(descriptor), + false, + true + ), + descriptor.getType() + ); } return null; } 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 994956bf95b..015a4fcdff6 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 @@ -96,9 +96,9 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT return createStringConstant(this@ConstantExpressionEvaluator.evaluate(expression, KotlinBuiltIns.getInstance().getStringType())) } - override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, data: Nothing?) = StringValue(entry.getText(), true, false) + override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, data: Nothing?) = StringValue(entry.getText(), CompileTimeConstant.Parameters.Impl(true, false, false)) - override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = StringValue(entry.getUnescapedValue(), true, false) + override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = StringValue(entry.getUnescapedValue(), CompileTimeConstant.Parameters.Impl(true, false, false)) } override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? { @@ -118,7 +118,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT if (result == null) return null fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text) - return createCompileTimeConstant(result, expectedType, !isLongWithSuffix(), true, false) + return createConstant(result, expectedType, CompileTimeConstant.Parameters.Impl(true, !isLongWithSuffix(), false)) } override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? { @@ -155,9 +155,15 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT } } return if (!interupted) - createCompileTimeConstant(sb.toString(), expectedType, - isPure = true, canBeUsedInAnnotation = canBeUsedInAnnotation, - usesVariableAsConstant = usesVariableAsConstant) + createConstant( + sb.toString(), + expectedType, + CompileTimeConstant.Parameters.Impl( + isPure = true, + canBeUsedInAnnotation = canBeUsedInAnnotation, + usesVariableAsConstant = usesVariableAsConstant + ) + ) else null } @@ -190,7 +196,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}") } val usesVariableAsConstant = leftConstant.usesVariableAsConstant() || rightConstant.usesVariableAsConstant() - return createCompileTimeConstant(result, expectedType, true, true, usesVariableAsConstant) + return createConstant(result, expectedType, CompileTimeConstant.Parameters.Impl(true, true, usesVariableAsConstant)) } else { return evaluateCall(expression.getOperationReference(), leftExpression, expectedType) @@ -214,11 +220,14 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression) val isNumberConversionMethod = resultingDescriptorName in OperatorConventions.NUMBER_CONVERSIONS - return createCompileTimeConstant(result, - expectedType, - !isNumberConversionMethod && isArgumentPure, - canBeUsedInAnnotation, - usesVariableAsConstant) + return createConstant( + result, + expectedType, + CompileTimeConstant.Parameters.Impl( + canBeUsedInAnnotation, + !isNumberConversionMethod && isArgumentPure, + usesVariableAsConstant) + ) } else if (argumentsEntrySet.size() == 1) { val (parameter, argument) = argumentsEntrySet.first() @@ -237,12 +246,12 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val areArgumentsPure = isPureConstant(argumentForReceiver.expression) && isPureConstant(argumentForParameter.expression) val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression) val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression) - val c = EvaluatorContext(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant) + val parameters = CompileTimeConstant.Parameters.Impl(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant) return when(resultingDescriptorName) { - OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, c) - OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, c) + OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, parameters) + OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, parameters) else -> { - createCompileTimeConstant(result, expectedType, areArgumentsPure, canBeUsedInAnnotation, usesVariableAsConstant) + createConstant(result, expectedType, CompileTimeConstant.Parameters.Impl(areArgumentsPure, canBeUsedInAnnotation, usesVariableAsConstant)) } } } @@ -327,7 +336,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, expectedType: JetType?): CompileTimeConstant<*>? { val enumDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, expression); if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) { - return EnumValue(enumDescriptor as ClassDescriptor, false); + return EnumValue(enumDescriptor as ClassDescriptor) } val resolvedCall = expression.getResolvedCall(trace.getBindingContext()) @@ -342,9 +351,15 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT compileTimeConstant.getValue(expectedType ?: TypeUtils.NO_EXPECTED_TYPE) else compileTimeConstant.value - return createCompileTimeConstant(value, expectedType, isPure = false, - canBeUsedInAnnotation = isPropertyCompileTimeConstant(callableDescriptor), - usesVariableAsConstant = true) + return createConstant( + value, + expectedType, + CompileTimeConstant.Parameters.Impl( + canBeUsedInAnnotation = isPropertyCompileTimeConstant(callableDescriptor), + isPure = false, + usesVariableAsConstant = true + ) + ) } } return null @@ -468,18 +483,17 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT return OperationArgument(evaluationResult, compileTimeType, expression) } - fun createCompileTimeConstant(value: Any?, - expectedType: JetType?, - isPure: Boolean = true, - canBeUsedInAnnotation: Boolean = true, - usesVariableAsConstant: Boolean = false): CompileTimeConstant<*>? { - val c = EvaluatorContext(canBeUsedInAnnotation, isPure, usesVariableAsConstant) - return createCompileTimeConstant(value, c, if (isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null) + fun createConstant( + value: Any?, + expectedType: JetType?, + parameters: CompileTimeConstant.Parameters + ): CompileTimeConstant<*>? { + return createCompileTimeConstant(value, parameters, if (parameters.isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null) } } public fun IntegerValueTypeConstant.createCompileTimeConstantWithType(expectedType: JetType): CompileTimeConstant<*>? - = createCompileTimeConstant(this.getValue(expectedType), EvaluatorContext(this.canBeUsedInAnnotations(), true)) + = createCompileTimeConstant(this.getValue(expectedType), CompileTimeConstant.Parameters.Impl(this.canBeUsedInAnnotations(), true, false)) private fun hasLongSuffix(text: String) = text.endsWith('l') || text.endsWith('L') @@ -536,16 +550,16 @@ private fun parseBoolean(text: String): Boolean { } -private fun createCompileTimeConstantForEquals(result: Any?, operationReference: JetExpression, c: EvaluatorContext): CompileTimeConstant<*>? { +private fun createCompileTimeConstantForEquals(result: Any?, operationReference: JetExpression, parameters: CompileTimeConstant.Parameters): CompileTimeConstant<*>? { if (result is Boolean) { assert(operationReference is JetSimpleNameExpression, "This method should be called only for equals operations") val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType() return when (operationToken) { - JetTokens.EQEQ -> BooleanValue(result, c.canBeUsedInAnnotation, c.usesVariableAsConstant) - JetTokens.EXCLEQ -> BooleanValue(!result, c.canBeUsedInAnnotation, c.usesVariableAsConstant) + JetTokens.EQEQ -> BooleanValue(result, parameters) + JetTokens.EXCLEQ -> BooleanValue(!result, parameters) JetTokens.IDENTIFIER -> { assert (operationReference.getReferencedNameAsName() == OperatorConventions.EQUALS, "This method should be called only for equals operations") - return BooleanValue(result, c.canBeUsedInAnnotation, c.usesVariableAsConstant) + return BooleanValue(result, parameters) } else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.getText()}") } @@ -553,18 +567,18 @@ private fun createCompileTimeConstantForEquals(result: Any?, operationReference: return null } -private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: JetExpression, c: EvaluatorContext): CompileTimeConstant<*>? { +private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: JetExpression, parameters: CompileTimeConstant.Parameters): CompileTimeConstant<*>? { if (result is Int) { assert(operationReference is JetSimpleNameExpression, "This method should be called only for compareTo operations") val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType() return when (operationToken) { - JetTokens.LT -> BooleanValue(result < 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant) - JetTokens.LTEQ -> BooleanValue(result <= 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant) - JetTokens.GT -> BooleanValue(result > 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant) - JetTokens.GTEQ -> BooleanValue(result >= 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant) + JetTokens.LT -> BooleanValue(result < 0, parameters) + JetTokens.LTEQ -> BooleanValue(result <= 0, parameters) + JetTokens.GT -> BooleanValue(result > 0, parameters) + JetTokens.GTEQ -> BooleanValue(result >= 0, parameters) JetTokens.IDENTIFIER -> { assert (operationReference.getReferencedNameAsName() == OperatorConventions.COMPARE_TO, "This method should be called only for compareTo operations") - return IntValue(result, c.canBeUsedInAnnotation, c.isPure, c.usesVariableAsConstant) + return IntValue(result, parameters) } else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken") } @@ -574,21 +588,17 @@ private fun createCompileTimeConstantForCompareTo(result: Any?, operationReferen private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? { return when (value) { - is IntegerValueTypeConstant -> StringValue(value.getValue(TypeUtils.NO_EXPECTED_TYPE).toString(), value.canBeUsedInAnnotations(), value.usesVariableAsConstant()) + is IntegerValueTypeConstant -> StringValue(value.getValue(TypeUtils.NO_EXPECTED_TYPE).toString(), value.parameters) is StringValue -> value is IntValue, is ByteValue, is ShortValue, is LongValue, is CharValue, is DoubleValue, is FloatValue, is BooleanValue, - is NullValue -> StringValue("${value.value}", value.canBeUsedInAnnotations(), value.usesVariableAsConstant()) + is NullValue -> StringValue("${value.value}", value.parameters) else -> null } } -private fun createCompileTimeConstant(value: Any?, c: EvaluatorContext, expectedType: JetType? = null): CompileTimeConstant<*>? { - return createCompileTimeConstant(value, c.canBeUsedInAnnotation, c.isPure, c.usesVariableAsConstant, expectedType) -} - fun isIntegerType(value: Any?) = value is Byte || value is Short || value is Int || value is Long private fun getReceiverExpressionType(resolvedCall: ResolvedCall<*>): JetType? { @@ -618,8 +628,6 @@ private fun getCompileTimeType(c: JetType): CompileTimeType? { } } -private class EvaluatorContext(val canBeUsedInAnnotation: Boolean, val isPure: Boolean, val usesVariableAsConstant: Boolean = false) - private class CompileTimeType private val BYTE = CompileTimeType() diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt index 6e6d7416e23..b936d81084e 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt @@ -121,11 +121,12 @@ public object AnnotationSerializer { // TODO: IntegerValueTypeConstant should not occur in annotation arguments val number = constant.getValue(type) val specificConstant = with(KotlinBuiltIns.getInstance()) { + val parameters = CompileTimeConstant.Parameters.ThrowException when (type) { - getLongType() -> LongValue(number.toLong(), true, true, true) - getIntType() -> IntValue(number.toInt(), true, true, true) - getShortType() -> ShortValue(number.toShort(), true, true, true) - getByteType() -> ByteValue(number.toByte(), true, true, true) + getLongType() -> LongValue(number.toLong(), parameters) + getIntType() -> IntValue(number.toInt(), parameters) + getShortType() -> ShortValue(number.toShort(), parameters) + getByteType() -> ByteValue(number.toByte(), parameters) else -> throw IllegalStateException("Integer constant $constant has non-integer type $type") } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index bb7c81b8a04..d8ab3ebcbf0 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -100,7 +100,7 @@ class LazyJavaAnnotationDescriptor( private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): CompileTimeConstant<*>? { return when (argument) { - is JavaLiteralAnnotationArgument -> createCompileTimeConstant(argument.value, true, false, false, null) + is JavaLiteralAnnotationArgument -> createCompileTimeConstant(argument.value, CompileTimeConstant.Parameters.Impl(true, false, false)) is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve()) is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements()) is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation()) @@ -125,7 +125,7 @@ class LazyJavaAnnotationDescriptor( val values = elements.map { argument -> resolveAnnotationArgument(argument) ?: NullValue } - return ArrayValue(values, valueParameter.getType(), values.any { it.usesVariableAsConstant() }) + return ArrayValue(values, valueParameter.getType(), CompileTimeConstant.Parameters.Impl(true, false, values.any { it.usesVariableAsConstant() })) } private fun resolveFromEnumValue(element: JavaField?): CompileTimeConstant<*>? { @@ -140,7 +140,7 @@ class LazyJavaAnnotationDescriptor( val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(element.getName()) if (classifier !is ClassDescriptor) return null - return EnumValue(classifier, false) + return EnumValue(classifier) } private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt index 0a8c0c9984e..17beab314dd 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -66,8 +66,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( } val compileTimeConstant = createCompileTimeConstant( - normalizedValue, canBeUsedInAnnotation = true, isPureIntConstant = true, - usesVariableAsConstant = true, expectedType = null + normalizedValue, CompileTimeConstant.Parameters.ThrowException ) return compileTimeConstant } @@ -107,7 +106,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) if (parameter != null) { elements.trimToSize() - arguments[parameter] = ArrayValue(elements, parameter.getType(), false) + arguments[parameter] = ArrayValue(elements, parameter.getType(), CompileTimeConstant.Parameters.ThrowException) } } } @@ -130,7 +129,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( if (enumClass.getKind() == ClassKind.ENUM_CLASS) { val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name) if (classifier is ClassDescriptor) { - return EnumValue(classifier, false) + return EnumValue(classifier) } } return ErrorValue.create("Unresolved enum entry: $enumClassId.$name") @@ -141,9 +140,10 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( } private fun createConstant(name: Name?, value: Any?): CompileTimeConstant<*> { - return createCompileTimeConstant(value, canBeUsedInAnnotation = true, isPureIntConstant = false, - usesVariableAsConstant = false, expectedType = null) - ?: ErrorValue.create("Unsupported annotation argument: $name") + return createCompileTimeConstant( + value, + CompileTimeConstant.Parameters.ThrowException + ) ?: ErrorValue.create("Unsupported annotation argument: $name") } private fun setArgumentValueByName(name: Name, argumentValue: CompileTimeConstant<*>) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/AnnotationValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/AnnotationValue.kt index 0fcc18648ed..8dcd6304934 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/AnnotationValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/AnnotationValue.kt @@ -21,7 +21,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.types.JetType -public class AnnotationValue(value: AnnotationDescriptor) : CompileTimeConstant(value, true, false, false) { +public class AnnotationValue(value: AnnotationDescriptor) : + CompileTimeConstant(value, CompileTimeConstant.Parameters.Impl(true, false, false)) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = value.getType() override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitAnnotationValue(this, data) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ArrayValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ArrayValue.kt index 137f84f1012..46ae183fb7b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ArrayValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ArrayValue.kt @@ -24,8 +24,17 @@ import java.util.* public class ArrayValue( value: List>, private val type: JetType, - usesVariableAsConstant: Boolean -) : CompileTimeConstant>>(value, true, false, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant>>(value, parameters) { + + public constructor( + value: List>, + type: JetType, + usesVariableAsConstant: Boolean + ) : this(value, type, CompileTimeConstant.Parameters.Impl(true, false, usesVariableAsConstant)) + + override fun canBeUsedInAnnotations() = true + override fun isPure() = false init { assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) { "Type should be an array, but was " + type + ": " + value } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/BooleanValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/BooleanValue.kt index aa691a535f5..d703db17024 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/BooleanValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/BooleanValue.kt @@ -22,9 +22,10 @@ import org.jetbrains.kotlin.types.JetType public class BooleanValue( value: Boolean, - canBeUseInAnnotation: Boolean, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, canBeUseInAnnotation, false, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant(value, parameters) { + override fun isPure(): Boolean = false + override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getBooleanType() override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitBooleanValue(this, data) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ByteValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ByteValue.kt index 973ec0af255..a9d73f2b598 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ByteValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ByteValue.kt @@ -22,10 +22,8 @@ import org.jetbrains.kotlin.types.JetType public class ByteValue( value: Byte, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVaraiableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, pure, usesVaraiableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getByteType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CharValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CharValue.kt index fb9a93adda1..f5285f8ea97 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CharValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CharValue.kt @@ -22,10 +22,8 @@ import org.jetbrains.kotlin.types.JetType public class CharValue( value: Char, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVariableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, pure, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getCharType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt index d7c8c477387..a9d752f6c41 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt @@ -20,24 +20,15 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.types.JetType -public abstract class CompileTimeConstant protected constructor(public open val value: T, canBeUsedInAnnotations: Boolean, isPure: Boolean, usesVariableAsConstant: Boolean) { - private val flags: Int +public abstract class CompileTimeConstant protected constructor( + public open val value: T, + public val parameters: CompileTimeConstant.Parameters +) { + public open fun canBeUsedInAnnotations(): Boolean = parameters.canBeUsedInAnnotation - init { - flags = (if (isPure) IS_PURE_MASK else 0) or (if (canBeUsedInAnnotations) CAN_BE_USED_IN_ANNOTATIONS_MASK else 0) or (if (usesVariableAsConstant) USES_VARIABLE_AS_CONSTANT_MASK else 0) - } + public open fun isPure(): Boolean = parameters.isPure - public fun canBeUsedInAnnotations(): Boolean { - return (flags and CAN_BE_USED_IN_ANNOTATIONS_MASK) != 0 - } - - public fun isPure(): Boolean { - return (flags and IS_PURE_MASK) != 0 - } - - public fun usesVariableAsConstant(): Boolean { - return (flags and USES_VARIABLE_AS_CONSTANT_MASK) != 0 - } + public open fun usesVariableAsConstant(): Boolean = parameters.usesVariableAsConstant public abstract fun getType(kotlinBuiltIns: KotlinBuiltIns): JetType @@ -45,16 +36,24 @@ public abstract class CompileTimeConstant protected constructor(public open v override fun toString() = value.toString() - companion object { + public interface Parameters { + public open val canBeUsedInAnnotation: Boolean + public open val isPure: Boolean + public open val usesVariableAsConstant: Boolean - /* - * if is pure is false then constant type cannot be changed - * ex1. val a: Long = 1.toInt() (TYPE_MISMATCH error, 1.toInt() isn't pure) - * ex2. val b: Int = a (TYPE_MISMATCH error, a isn't pure) - * - */ - private val IS_PURE_MASK = 1 - private val CAN_BE_USED_IN_ANNOTATIONS_MASK = 1 shl 1 - private val USES_VARIABLE_AS_CONSTANT_MASK = 1 shl 2 + public class Impl( + override val canBeUsedInAnnotation: Boolean, + override val isPure: Boolean, + override val usesVariableAsConstant: Boolean + ) : Parameters + + public object ThrowException : Parameters { + override val canBeUsedInAnnotation: Boolean + get() = error("Should not be called") + override val isPure: Boolean + get() = error("Should not be called") + override val usesVariableAsConstant: Boolean + get() = error("Should not be called") + } } -} +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantUtils.kt index a82205ecf24..7273006d1fc 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantUtils.kt @@ -22,27 +22,25 @@ import org.jetbrains.kotlin.types.TypeUtils public fun createCompileTimeConstant( value: Any?, - canBeUsedInAnnotation: Boolean, - isPureIntConstant: Boolean, - usesVariableAsConstant: Boolean = false, + parameters: CompileTimeConstant.Parameters, expectedType: JetType? = null ): CompileTimeConstant<*>? { // TODO: primitive arrays if (expectedType == null) { when(value) { - is Byte -> return ByteValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - is Short -> return ShortValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - is Int -> return IntValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - is Long -> return LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) + is Byte -> return ByteValue(value, parameters) + is Short -> return ShortValue(value, parameters) + is Int -> return IntValue(value, parameters) + is Long -> return LongValue(value, parameters) } } return when(value) { - is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant, expectedType) - is Char -> CharValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - is Float -> FloatValue(value, canBeUsedInAnnotation, usesVariableAsConstant) - is Double -> DoubleValue(value, canBeUsedInAnnotation, usesVariableAsConstant) - is Boolean -> BooleanValue(value, canBeUsedInAnnotation, usesVariableAsConstant) - is String -> StringValue(value, canBeUsedInAnnotation, usesVariableAsConstant) + is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), parameters, expectedType) + is Char -> CharValue(value, parameters) + is Float -> FloatValue(value, parameters) + is Double -> DoubleValue(value, parameters) + is Boolean -> BooleanValue(value, parameters) + is String -> StringValue(value, parameters) null -> NullValue else -> null } @@ -50,32 +48,37 @@ public fun createCompileTimeConstant( private fun getIntegerValue( value: Long, - canBeUsedInAnnotation: Boolean, - isPureIntConstant: Boolean, - usesVariableAsConstant: Boolean, + parameters: CompileTimeConstant.Parameters, expectedType: JetType ): CompileTimeConstant<*>? { fun defaultIntegerValue(value: Long) = when (value) { - value.toInt().toLong() -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - else -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) + value.toInt().toLong() -> IntValue(value.toInt(), parameters) + else -> LongValue(value, parameters) } if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) { - return IntegerValueTypeConstant(value, canBeUsedInAnnotation, usesVariableAsConstant) + return IntegerValueTypeConstant(value, parameters) } val notNullExpected = TypeUtils.makeNotNullable(expectedType) return when { - KotlinBuiltIns.isLong(notNullExpected) -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - KotlinBuiltIns.isShort(notNullExpected) -> when (value) { - value.toShort().toLong() -> ShortValue(value.toShort(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - else -> defaultIntegerValue(value) - } - KotlinBuiltIns.isByte(notNullExpected) -> when (value) { - value.toByte().toLong() -> ByteValue(value.toByte(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) - else -> defaultIntegerValue(value) - } - KotlinBuiltIns.isChar(notNullExpected) -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant) + KotlinBuiltIns.isLong(notNullExpected) -> LongValue(value, parameters) + + KotlinBuiltIns.isShort(notNullExpected) -> + if (value == value.toShort().toLong()) + ShortValue(value.toShort(), parameters) + else + defaultIntegerValue(value) + + KotlinBuiltIns.isByte(notNullExpected) -> + if (value == value.toByte().toLong()) + ByteValue(value.toByte(), parameters) + else + defaultIntegerValue(value) + + KotlinBuiltIns.isChar(notNullExpected) -> + IntValue(value.toInt(), parameters) + else -> defaultIntegerValue(value) } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/DoubleValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/DoubleValue.kt index 351861c4c86..111ea9acad3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/DoubleValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/DoubleValue.kt @@ -22,9 +22,10 @@ import org.jetbrains.kotlin.types.JetType public class DoubleValue( value: Double, - canBeUsedInAnnotations: Boolean, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, canBeUsedInAnnotations, false, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant(value, parameters) { + + override fun isPure() = false override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getDoubleType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/EnumValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/EnumValue.kt index 2afd293da3c..fe734397589 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/EnumValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/EnumValue.kt @@ -24,9 +24,8 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.utils.sure public class EnumValue( - value: ClassDescriptor, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, true, false, usesVariableAsConstant) { + value: ClassDescriptor +) : CompileTimeConstant(value, CompileTimeConstant.Parameters.Impl(true, false, false)) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = getType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ErrorValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ErrorValue.kt index 74164f3019d..e73a0802c42 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ErrorValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ErrorValue.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.JetType -public abstract class ErrorValue : CompileTimeConstant(Unit, true, false, false) { +public abstract class ErrorValue : CompileTimeConstant(Unit, CompileTimeConstant.Parameters.Impl(true, false, false)) { deprecated("Should not be called, for this is not a real value, but a indication of an error") override val value: Unit diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/FloatValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/FloatValue.kt index ba1e4f037c6..c78672653ea 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/FloatValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/FloatValue.kt @@ -22,9 +22,9 @@ import org.jetbrains.kotlin.types.JetType public class FloatValue( value: Float, - canBeUsedInAnnotations: Boolean, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, canBeUsedInAnnotations, false, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant(value, parameters) { + override fun isPure() = false override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getFloatType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntValue.kt index bb3333e70de..ec2bbce627b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntValue.kt @@ -22,10 +22,8 @@ import org.jetbrains.kotlin.types.JetType public class IntValue( value: Int, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVariableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, pure, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getIntType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueConstant.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueConstant.kt index 3c71270741f..e6501aee9e2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueConstant.kt @@ -18,7 +18,5 @@ package org.jetbrains.kotlin.resolve.constants public abstract class IntegerValueConstant protected constructor( value: T, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, canBeUsedInAnnotations, pure, usesVariableAsConstant) + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant(value, parameters) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstant.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstant.kt index 65744390727..f487be511b3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstant.kt @@ -25,9 +25,10 @@ import java.util.Collections public class IntegerValueTypeConstant( value: Number, - canBeUsedInAnnotations: Boolean, - usesVariableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, true, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { + + override fun isPure() = true private val typeConstructor = IntegerValueTypeConstructor(value.toLong()) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/KClassValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/KClassValue.kt index ec518f99fbd..9a6a867198e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/KClassValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/KClassValue.kt @@ -20,8 +20,8 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.types.JetType - -public class KClassValue(private val type: JetType) : CompileTimeConstant(type, true, false, false) { +public class KClassValue(private val type: JetType) : + CompileTimeConstant(type, CompileTimeConstant.Parameters.Impl(true, false, false)) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = type override val value: JetType get() = type.getArguments().single().getType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/LongValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/LongValue.kt index c442492f435..fe443987362 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/LongValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/LongValue.kt @@ -22,10 +22,8 @@ import org.jetbrains.kotlin.types.JetType public class LongValue( value: Long, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVariableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, pure, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getLongType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/NullValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/NullValue.kt index 8c28e6ca910..5554fc8167a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/NullValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/NullValue.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.types.JetType -public object NullValue : CompileTimeConstant(null, false, false, false) { +public object NullValue : CompileTimeConstant(null, CompileTimeConstant.Parameters.Impl(false, false, false)) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getNullableNothingType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ShortValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ShortValue.kt index f1d71050be2..917fcb77f1f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ShortValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ShortValue.kt @@ -22,10 +22,8 @@ import org.jetbrains.kotlin.types.JetType public class ShortValue( value: Short, - canBeUsedInAnnotations: Boolean, - pure: Boolean, - usesVariableAsConstant: Boolean -) : IntegerValueConstant(value, canBeUsedInAnnotations, pure, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : IntegerValueConstant(value, parameters) { override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getShortType() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/StringValue.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/StringValue.kt index f8467927cd8..26c9b2c5286 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/StringValue.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/StringValue.kt @@ -22,9 +22,9 @@ import org.jetbrains.kotlin.types.JetType public class StringValue( value: String, - canBeUsedInAnnotations: Boolean, - usesVariableAsConstant: Boolean -) : CompileTimeConstant(value, canBeUsedInAnnotations, false, usesVariableAsConstant) { + parameters: CompileTimeConstant.Parameters +) : CompileTimeConstant(value, parameters) { + override fun isPure() = false override fun getType(kotlinBuiltIns: KotlinBuiltIns) = kotlinBuiltIns.getStringType() diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt index 25faaeb8d90..b42e01b7e1b 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt @@ -68,17 +68,18 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { value: Value, nameResolver: NameResolver ): CompileTimeConstant<*> { + val parameters = CompileTimeConstant.Parameters.ThrowException val result = when (value.getType()) { - Type.BYTE -> ByteValue(value.getIntValue().toByte(), true, true, true) - Type.CHAR -> CharValue(value.getIntValue().toChar(), true, true, true) - Type.SHORT -> ShortValue(value.getIntValue().toShort(), true, true, true) - Type.INT -> IntValue(value.getIntValue().toInt(), true, true, true) - Type.LONG -> LongValue(value.getIntValue(), true, true, true) - Type.FLOAT -> FloatValue(value.getFloatValue(), true, true) - Type.DOUBLE -> DoubleValue(value.getDoubleValue(), true, true) - Type.BOOLEAN -> BooleanValue(value.getIntValue() != 0L, true, true) + Type.BYTE -> ByteValue(value.getIntValue().toByte(), parameters) + Type.CHAR -> CharValue(value.getIntValue().toChar(), parameters) + Type.SHORT -> ShortValue(value.getIntValue().toShort(), parameters) + Type.INT -> IntValue(value.getIntValue().toInt(), parameters) + Type.LONG -> LongValue(value.getIntValue(), parameters) + Type.FLOAT -> FloatValue(value.getFloatValue(), parameters) + Type.DOUBLE -> DoubleValue(value.getDoubleValue(), parameters) + Type.BOOLEAN -> BooleanValue(value.getIntValue() != 0L, parameters) Type.STRING -> { - StringValue(nameResolver.getString(value.getStringValue()), true, true) + StringValue(nameResolver.getString(value.getStringValue()), parameters) } Type.CLASS -> { // TODO: support class literals @@ -114,7 +115,7 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { resolveValue(expectedElementType, it, nameResolver) }, actualArrayType, - true + parameters ) } else -> error("Unsupported annotation argument type: ${value.getType()} (expected $expectedType)") @@ -135,7 +136,7 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { if (enumClass.getKind() == ClassKind.ENUM_CLASS) { val enumEntry = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(enumEntryName) if (enumEntry is ClassDescriptor) { - return EnumValue(enumEntry, true) + return EnumValue(enumEntry) } } return ErrorValue.create("Unresolved enum entry: $enumClassId.$enumEntryName")