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 582a69a9e9f..e5f1117ea46 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 @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor; import org.jetbrains.kotlin.load.java.structure.JavaField; import org.jetbrains.kotlin.load.java.structure.JavaPropertyInitializerEvaluator; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; -import org.jetbrains.kotlin.resolve.constants.ConstantsPackage; +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantFactory; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; public class JavaPropertyInitializerEvaluatorImpl implements JavaPropertyInitializerEvaluator { @@ -35,15 +35,13 @@ public class JavaPropertyInitializerEvaluatorImpl implements JavaPropertyInitial PsiExpression initializer = ((JavaFieldImpl) field).getInitializer(); Object evaluatedExpression = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false); if (evaluatedExpression != null) { - return ConstantsPackage.createCompileTimeConstant( - evaluatedExpression, + CompileTimeConstantFactory factory = new CompileTimeConstantFactory( new CompileTimeConstant.Parameters.Impl( ConstantExpressionEvaluator.isPropertyCompileTimeConstant(descriptor), false, true - ), - descriptor.getType() - ); + )); + return factory.createCompileTimeConstant(evaluatedExpression, 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 015a4fcdff6..c3c318dc2ab 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 @@ -17,26 +17,27 @@ package org.jetbrains.kotlin.resolve.constants.evaluate import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.JetNodeTypes +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.expressions.OperatorConventions -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument -import org.jetbrains.kotlin.JetNodeTypes -import org.jetbrains.kotlin.diagnostics.DiagnosticUtils +import org.jetbrains.kotlin.types.expressions.OperatorConventions import java.math.BigInteger -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import kotlin.platform.platformStatic public class ConstantExpressionEvaluator private constructor(val trace: BindingTrace) : JetVisitor, JetType>() { @@ -85,6 +86,8 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT } private val stringExpressionEvaluator = object : JetVisitor() { + private val factory = CompileTimeConstantFactory(CompileTimeConstant.Parameters.Impl(true, false, false)) + fun evaluate(entry: JetStringTemplateEntry): StringValue? { return entry.accept(this, null) } @@ -96,14 +99,13 @@ 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(), CompileTimeConstant.Parameters.Impl(true, false, false)) + override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, data: Nothing?) = factory.createStringValue(entry.getText()) - override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = StringValue(entry.getUnescapedValue(), CompileTimeConstant.Parameters.Impl(true, false, false)) + override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = factory.createStringValue(entry.getUnescapedValue()) } override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? { - val text = expression.getText() - if (text == null) return null + val text = expression.getText() ?: return null val nodeElementType = expression.getNode().getElementType() if (nodeElementType == JetNodeTypes.NULL) return NullValue @@ -114,8 +116,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT JetNodeTypes.BOOLEAN_CONSTANT -> parseBoolean(text) JetNodeTypes.CHARACTER_CONSTANT -> CompileTimeConstantChecker.parseChar(expression) else -> throw IllegalArgumentException("Unsupported constant: " + expression) - } - if (result == null) return null + } ?: return null fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text) return createConstant(result, expectedType, CompileTimeConstant.Parameters.Impl(true, !isLongWithSuffix(), false)) @@ -164,11 +165,11 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT usesVariableAsConstant = usesVariableAsConstant ) ) - else null + else null } override fun visitBinaryWithTypeRHSExpression(expression: JetBinaryExpressionWithTypeRHS, expectedType: JetType?): CompileTimeConstant<*>? = - evaluate(expression.getLeft(), expectedType) + evaluate(expression.getLeft(), expectedType) override fun visitBinaryExpression(expression: JetBinaryExpression, expectedType: JetType?): CompileTimeConstant<*>? { val leftExpression = expression.getLeft() @@ -190,7 +191,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val rightValue = rightConstant.value if (leftValue !is Boolean || rightValue !is Boolean) return null - val result = when(operationToken) { + val result = when (operationToken) { JetTokens.ANDAND -> leftValue && rightValue JetTokens.OROR -> leftValue || rightValue else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}") @@ -237,6 +238,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT if (isDivisionByZero(resultingDescriptorName.asString(), argumentForParameter.value)) { val parentExpression: JetExpression = PsiTreeUtil.getParentOfType(receiverExpression, javaClass())!! trace.report(Errors.DIVISION_BY_ZERO.on(parentExpression)) + //TODO_R: return ErrorValue.create("Division by zero") } @@ -247,11 +249,12 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression) val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression) val parameters = CompileTimeConstant.Parameters.Impl(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant) - return when(resultingDescriptorName) { - OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, parameters) - OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, parameters) + val factory = CompileTimeConstantFactory(parameters) + return when (resultingDescriptorName) { + OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, factory) + OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, factory) else -> { - createConstant(result, expectedType, CompileTimeConstant.Parameters.Impl(areArgumentsPure, canBeUsedInAnnotation, usesVariableAsConstant)) + createConstant(result, expectedType, parameters) } } } @@ -296,7 +299,8 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val (function, checker) = functions val actualResult = try { function(receiver.value, parameter.value) - } catch (e: Exception) { + } + catch (e: Exception) { null } if (checker == emptyBinaryFun) { @@ -402,6 +406,7 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT val varargType = resultingDescriptor.getValueParameters().first().getVarargElementType()!! val arguments = call.getValueArguments().values().flatMap { resolveArguments(it.getArguments(), varargType) } + return ArrayValue(arguments, resultingDescriptor.getReturnType()!!, arguments.any() { it.usesVariableAsConstant() }) } @@ -488,12 +493,12 @@ public class ConstantExpressionEvaluator private constructor(val trace: BindingT expectedType: JetType?, parameters: CompileTimeConstant.Parameters ): CompileTimeConstant<*>? { - return createCompileTimeConstant(value, parameters, if (parameters.isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null) + return CompileTimeConstantFactory(parameters).createCompileTimeConstant(value, if (parameters.isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null) } } public fun IntegerValueTypeConstant.createCompileTimeConstantWithType(expectedType: JetType): CompileTimeConstant<*>? - = createCompileTimeConstant(this.getValue(expectedType), CompileTimeConstant.Parameters.Impl(this.canBeUsedInAnnotations(), true, false)) + = CompileTimeConstantFactory(CompileTimeConstant.Parameters.Impl(this.canBeUsedInAnnotations(), true, false)).createCompileTimeConstant(this.getValue(expectedType)) private fun hasLongSuffix(text: String) = text.endsWith('l') || text.endsWith('L') @@ -550,35 +555,36 @@ private fun parseBoolean(text: String): Boolean { } -private fun createCompileTimeConstantForEquals(result: Any?, operationReference: JetExpression, parameters: CompileTimeConstant.Parameters): CompileTimeConstant<*>? { +private fun createCompileTimeConstantForEquals(result: Any?, operationReference: JetExpression, factory: CompileTimeConstantFactory): 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, parameters) - JetTokens.EXCLEQ -> BooleanValue(!result, parameters) + val value: Boolean = when (operationToken) { + JetTokens.EQEQ -> result + JetTokens.EXCLEQ -> !result JetTokens.IDENTIFIER -> { assert (operationReference.getReferencedNameAsName() == OperatorConventions.EQUALS, "This method should be called only for equals operations") - return BooleanValue(result, parameters) + result } else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.getText()}") } + return factory.createBooleanValue(value) } return null } -private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: JetExpression, parameters: CompileTimeConstant.Parameters): CompileTimeConstant<*>? { +private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: JetExpression, factory: CompileTimeConstantFactory): 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, parameters) - JetTokens.LTEQ -> BooleanValue(result <= 0, parameters) - JetTokens.GT -> BooleanValue(result > 0, parameters) - JetTokens.GTEQ -> BooleanValue(result >= 0, parameters) + JetTokens.LT -> factory.createBooleanValue(result < 0) + JetTokens.LTEQ -> factory.createBooleanValue(result <= 0) + JetTokens.GT -> factory.createBooleanValue(result > 0) + JetTokens.GTEQ -> factory.createBooleanValue(result >= 0) JetTokens.IDENTIFIER -> { assert (operationReference.getReferencedNameAsName() == OperatorConventions.COMPARE_TO, "This method should be called only for compareTo operations") - return IntValue(result, parameters) + return factory.createIntValue(result) } else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken") } @@ -588,13 +594,13 @@ 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.parameters) + is IntegerValueTypeConstant -> CompileTimeConstantFactory(value.parameters).createStringValue(value.getValue(TypeUtils.NO_EXPECTED_TYPE).toString()) 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.parameters) + is NullValue -> CompileTimeConstantFactory(value.parameters).createStringValue("${value.value}") else -> null } } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt index b936d81084e..72e006e402d 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt @@ -27,6 +27,9 @@ import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.JetType public object AnnotationSerializer { + + private val factory = CompileTimeConstantFactory(CompileTimeConstant.Parameters.ThrowException) + public fun serializeAnnotation(annotation: AnnotationDescriptor, stringTable: StringTable): ProtoBuf.Annotation { return with(ProtoBuf.Annotation.newBuilder()) { val annotationClass = annotation.getType().getConstructor().getDeclarationDescriptor() as? ClassDescriptor @@ -121,12 +124,11 @@ 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(), parameters) - getIntType() -> IntValue(number.toInt(), parameters) - getShortType() -> ShortValue(number.toShort(), parameters) - getByteType() -> ByteValue(number.toByte(), parameters) + getLongType() -> factory.createLongValue(number.toLong()) + getIntType() -> factory.createIntValue(number.toInt()) + getShortType() -> factory.createShortValue(number.toShort()) + getByteType() -> factory.createByteValue(number.toByte()) 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 d8ab3ebcbf0..9aea20d079d 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 @@ -64,6 +64,8 @@ class LazyJavaAnnotationDescriptor( annotationClass?.getDefaultType() ?: ErrorUtils.createErrorType(fqName.asString()) } + private val factory = CompileTimeConstantFactory(CompileTimeConstant.Parameters.Impl(true, false, false)) + override fun getType(): JetType = type() private val allValueArguments = c.storageManager.createLazyValue { @@ -100,7 +102,7 @@ class LazyJavaAnnotationDescriptor( private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): CompileTimeConstant<*>? { return when (argument) { - is JavaLiteralAnnotationArgument -> createCompileTimeConstant(argument.value, CompileTimeConstant.Parameters.Impl(true, false, false)) + is JavaLiteralAnnotationArgument -> factory.createCompileTimeConstant(argument.value) is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve()) is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements()) is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation()) @@ -110,22 +112,20 @@ class LazyJavaAnnotationDescriptor( } private fun resolveFromAnnotation(javaAnnotation: JavaAnnotation): CompileTimeConstant<*>? { - val descriptor = c.resolveAnnotation(javaAnnotation) - if (descriptor == null) return null + val descriptor = c.resolveAnnotation(javaAnnotation) ?: return null - return AnnotationValue(descriptor) + return factory.createAnnotationValue(descriptor) } private fun resolveFromArray(argumentName: Name, elements: List): CompileTimeConstant<*>? { if (getType().isError()) return null - val valueParameter = DescriptorResolverUtils.getAnnotationParameterByName(argumentName, getAnnotationClass()) - if (valueParameter == null) return null + val valueParameter = DescriptorResolverUtils.getAnnotationParameterByName(argumentName, getAnnotationClass()) ?: return null val values = elements.map { - argument -> resolveAnnotationArgument(argument) ?: NullValue + argument -> resolveAnnotationArgument(argument) ?: factory.createNullValue() } - return ArrayValue(values, valueParameter.getType(), CompileTimeConstant.Parameters.Impl(true, false, values.any { it.usesVariableAsConstant() })) + return factory.createArrayValue(values, valueParameter.getType()) } private fun resolveFromEnumValue(element: JavaField?): CompileTimeConstant<*>? { @@ -134,13 +134,12 @@ class LazyJavaAnnotationDescriptor( val containingJavaClass = element.getContainingClass() //TODO: (module refactoring) moduleClassResolver should be used here - val enumClass = c.javaClassResolver.resolveClass(containingJavaClass) - if (enumClass == null) return null + val enumClass = c.javaClassResolver.resolveClass(containingJavaClass) ?: return null val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(element.getName()) if (classifier !is ClassDescriptor) return null - return EnumValue(classifier) + return factory.createEnumValue(classifier) } private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? { @@ -160,7 +159,7 @@ class LazyJavaAnnotationDescriptor( override fun computeMemberScope() = jlClass.getMemberScope(arguments) } - return KClassValue(javaClassObjectType) + return factory.createKClassValue(javaClassObjectType) } override fun toString(): String { 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 17beab314dd..efa26f4f311 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 @@ -46,6 +46,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( storageManager, kotlinClassFinder, errorReporter ) { private val annotationDeserializer = AnnotationDeserializer(module) + private val factory = CompileTimeConstantFactory(CompileTimeConstant.Parameters.ThrowException) override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor = annotationDeserializer.deserializeAnnotation(proto, nameResolver) @@ -65,10 +66,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( initializer } - val compileTimeConstant = createCompileTimeConstant( - normalizedValue, CompileTimeConstant.Parameters.ThrowException - ) - return compileTimeConstant + return factory.createCompileTimeConstant(normalizedValue) } override fun loadAnnotation( @@ -106,7 +104,7 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) if (parameter != null) { elements.trimToSize() - arguments[parameter] = ArrayValue(elements, parameter.getType(), CompileTimeConstant.Parameters.ThrowException) + arguments[parameter] = factory.createArrayValue(elements, parameter.getType()) } } } @@ -129,10 +127,10 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( if (enumClass.getKind() == ClassKind.ENUM_CLASS) { val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name) if (classifier is ClassDescriptor) { - return EnumValue(classifier) + return factory.createEnumValue(classifier) } } - return ErrorValue.create("Unresolved enum entry: $enumClassId.$name") + return factory.createErrorValue("Unresolved enum entry: $enumClassId.$name") } override fun visitEnd() { @@ -140,10 +138,8 @@ public class BinaryClassAnnotationAndConstantLoaderImpl( } private fun createConstant(name: Name?, value: Any?): CompileTimeConstant<*> { - return createCompileTimeConstant( - value, - CompileTimeConstant.Parameters.ThrowException - ) ?: ErrorValue.create("Unsupported annotation argument: $name") + return factory.createCompileTimeConstant(value) ?: + factory.createErrorValue("Unsupported annotation argument: $name") } private fun setArgumentValueByName(name: Name, argumentValue: CompileTimeConstant<*>) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantFactory.kt new file mode 100644 index 00000000000..5709bc40784 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantFactory.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.constants + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeUtils + +public class CompileTimeConstantFactory(private val parameters: CompileTimeConstant.Parameters) { + fun createLongValue(value: Long) = LongValue(value, parameters) + + fun createIntValue(value: Int) = IntValue(value, parameters) + + fun createErrorValue(message: String) = ErrorValue.create(message) + + fun createShortValue(value: Short) = ShortValue(value, parameters) + + fun createByteValue(value: Byte) = ByteValue(value, parameters) + + fun createDoubleValue(value: Double) = DoubleValue(value, parameters) + + fun createFloatValue(value: Float) = FloatValue(value, parameters) + + fun createBooleanValue(value: Boolean) = BooleanValue(value, parameters) + + fun createCharValue(value: Char) = CharValue(value, parameters) + + fun createStringValue(value: String) = StringValue(value, parameters) + + fun createNullValue() = NullValue + + fun createEnumValue(enumEntryClass: ClassDescriptor): EnumValue = EnumValue(enumEntryClass) + + fun createArrayValue( + value: List>, + type: JetType + ) = ArrayValue(value, type, parameters) + + fun createAnnotationValue(value: AnnotationDescriptor) = AnnotationValue(value) + + fun createKClassValue(type: JetType) = KClassValue(type) + + fun createNumberTypeValue(value: Number) = IntegerValueTypeConstant(value, parameters) + + + fun createCompileTimeConstant( + value: Any?, + expectedType: JetType? = null + ): CompileTimeConstant<*>? { + // TODO: primitive arrays + if (expectedType == null) { + when (value) { + is Byte -> return createByteValue(value) + is Short -> return createShortValue(value) + is Int -> return createIntValue(value) + is Long -> return createLongValue(value) + } + } + return when (value) { + is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), expectedType) + is Char -> createCharValue(value) + is Float -> createFloatValue(value) + is Double -> createDoubleValue(value) + is Boolean -> createBooleanValue(value) + is String -> createStringValue(value) + null -> createNullValue() + else -> null + } + } + + private fun getIntegerValue( + value: Long, + expectedType: JetType + ): CompileTimeConstant<*>? { + fun defaultIntegerValue(value: Long) = when (value) { + value.toInt().toLong() -> createIntValue(value.toInt()) + else -> createLongValue(value) + } + + if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) { + return createNumberTypeValue(value) + } + + val notNullExpected = TypeUtils.makeNotNullable(expectedType) + return when { + KotlinBuiltIns.isLong(notNullExpected) -> createLongValue(value) + + KotlinBuiltIns.isShort(notNullExpected) -> + if (value == value.toShort().toLong()) + createShortValue(value.toShort()) + else + defaultIntegerValue(value) + + KotlinBuiltIns.isByte(notNullExpected) -> + if (value == value.toByte().toLong()) + createByteValue(value.toByte()) + else + defaultIntegerValue(value) + + KotlinBuiltIns.isChar(notNullExpected) -> + createIntValue(value.toInt()) + + else -> defaultIntegerValue(value) + } + } +} \ 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 deleted file mode 100644 index 7273006d1fc..00000000000 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantUtils.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.resolve.constants - -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.types.TypeUtils - -public fun createCompileTimeConstant( - value: Any?, - parameters: CompileTimeConstant.Parameters, - expectedType: JetType? = null -): CompileTimeConstant<*>? { - // TODO: primitive arrays - if (expectedType == null) { - when(value) { - 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(), 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 - } -} - -private fun getIntegerValue( - value: Long, - parameters: CompileTimeConstant.Parameters, - expectedType: JetType -): CompileTimeConstant<*>? { - fun defaultIntegerValue(value: Long) = when (value) { - value.toInt().toLong() -> IntValue(value.toInt(), parameters) - else -> LongValue(value, parameters) - } - - if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) { - return IntegerValueTypeConstant(value, parameters) - } - - val notNullExpected = TypeUtils.makeNotNullable(expectedType) - return when { - 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/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt index b42e01b7e1b..69f858a0ffe 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt @@ -39,6 +39,8 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { private val builtIns: KotlinBuiltIns get() = module.builtIns + private val factory = CompileTimeConstantFactory(CompileTimeConstant.Parameters.ThrowException) + public fun deserializeAnnotation(proto: Annotation, nameResolver: NameResolver): AnnotationDescriptor { val annotationClass = resolveClass(nameResolver.getClassId(proto.getId())) @@ -68,18 +70,17 @@ 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(), 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.BYTE -> factory.createByteValue(value.getIntValue().toByte()) + Type.CHAR -> factory.createCharValue(value.getIntValue().toChar()) + Type.SHORT -> factory.createShortValue(value.getIntValue().toShort()) + Type.INT -> factory.createIntValue(value.getIntValue().toInt()) + Type.LONG -> factory.createLongValue(value.getIntValue()) + Type.FLOAT -> factory.createFloatValue(value.getFloatValue()) + Type.DOUBLE -> factory.createDoubleValue(value.getDoubleValue()) + Type.BOOLEAN -> factory.createBooleanValue(value.getIntValue() != 0L) Type.STRING -> { - StringValue(nameResolver.getString(value.getStringValue()), parameters) + factory.createStringValue(nameResolver.getString(value.getStringValue())) } Type.CLASS -> { // TODO: support class literals @@ -110,12 +111,11 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { val expectedElementType = builtIns.getArrayElementType(if (expectedIsArray) expectedType else actualArrayType) - ArrayValue( + factory.createArrayValue( arrayElements.map { resolveValue(expectedElementType, it, nameResolver) }, - actualArrayType, - parameters + actualArrayType ) } else -> error("Unsupported annotation argument type: ${value.getType()} (expected $expectedType)") @@ -126,7 +126,7 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { } else { // This means that an annotation class has been changed incompatibly without recompiling clients - return ErrorValue.create("Unexpected argument value") + return factory.createErrorValue("Unexpected argument value") } } @@ -136,10 +136,10 @@ 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) + return factory.createEnumValue(enumEntry) } } - return ErrorValue.create("Unresolved enum entry: $enumClassId.$enumEntryName") + return factory.createErrorValue("Unresolved enum entry: $enumClassId.$enumEntryName") } private fun resolveArrayElementType(value: Value, nameResolver: NameResolver): JetType =