From 907f53e539c17ccd7e153188bde67d0ee8cf0176 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 29 Dec 2017 13:04:36 +0100 Subject: [PATCH] Refactor ConstantValue implementations Remove KotlinBuiltIns and take a ModuleDescriptor instance in getType instead. This will allow to create constant values in contexts where there's no module or built-ins accessible (such as, deserialization of module annotations during indexing of .kotlin_module files in IDE). Note that some values (KClassValue, EnumValue, AnnotationValue) still take module-dependent objects (KotlinType, ClassDescriptor and AnnotationDescriptor respectively). This is to be refactored later --- .../kotlin/codegen/AnnotationCodegen.java | 5 +- .../JavaPropertyInitializerEvaluatorImpl.kt | 6 +- .../script/scriptAnnotationsPreprocessing.kt | 8 +- .../DiagnosticReporterByTrackingStrategy.kt | 6 +- .../constants/CompileTimeConstantChecker.java | 21 ++-- .../evaluate/ConstantExpressionEvaluator.kt | 95 ++++++-------- .../BasicExpressionTypingVisitor.java | 8 +- .../types/expressions/DataFlowAnalyzer.java | 9 +- .../ExpressionTypingComponents.java | 7 ++ .../psi2ir/generators/StatementGenerator.kt | 4 +- ...bstractCompileTimeConstantEvaluatorTest.kt | 5 +- .../java/components/JavaAnnotationMapper.kt | 5 +- .../LazyJavaAnnotationDescriptor.kt | 16 ++- ...aryClassAnnotationAndConstantLoaderImpl.kt | 13 +- .../kotlin/builtins/functionTypes.kt | 2 +- .../descriptors/annotations/annotationUtil.kt | 8 +- .../resolve/constants/CompileTimeConstant.kt | 33 +++-- .../resolve/constants/ConstantValueFactory.kt | 38 +++--- .../resolve/constants/constantValues.kt | 118 +++++++----------- .../deserialization/AnnotationDeserializer.kt | 32 +++-- .../introduce/ExtractableSubstringInfo.kt | 8 +- .../KotlinLightConstantExpressionEvaluator.kt | 7 +- 22 files changed, 207 insertions(+), 247 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index 257638cf059..96515b3e985 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -370,8 +370,9 @@ public abstract class AnnotationCodegen { @Override public Void visitEnumValue(EnumValue value, Void data) { - String propertyName = value.getValue().getName().asString(); - annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType()).getDescriptor(), propertyName); + String enumClassInternalName = AsmUtil.asmTypeByClassId(value.getEnumClassId()).getDescriptor(); + String enumEntryName = value.getEnumEntryName().asString(); + annotationVisitor.visitEnum(name, enumClassInternalName, enumEntryName); return null; } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt index 365eca4e83a..f92608641b5 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt @@ -20,21 +20,19 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.load.java.structure.JavaField import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns class JavaPropertyInitializerEvaluatorImpl : JavaPropertyInitializerEvaluator { override fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor): ConstantValue<*>? { val evaluated = field.initializerValue ?: return null - val factory = ConstantValueFactory(descriptor.builtIns) return when (evaluated) { //Note: evaluated expression may be of class that does not match field type in some cases // tested for Int, left other checks just in case is Byte, is Short, is Int, is Long -> { - factory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.type) + ConstantValueFactory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.type) } else -> { - factory.createConstantValue(evaluated) + ConstantValueFactory.createConstantValue(evaluated) } } } diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/scriptAnnotationsPreprocessing.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/scriptAnnotationsPreprocessing.kt index fe57e2eef9a..5706e6221c7 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/scriptAnnotationsPreprocessing.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/scriptAnnotationsPreprocessing.kt @@ -18,10 +18,13 @@ package org.jetbrains.kotlin.script import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtUserType import org.jetbrains.kotlin.resolve.BindingTraceContext import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator +import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.types.TypeUtils import kotlin.reflect.KClass import kotlin.reflect.KParameter @@ -33,10 +36,11 @@ internal fun String?.orAnonymous(kind: String = ""): String = this ?: "" internal fun constructAnnotation(psi: KtAnnotationEntry, targetClass: KClass): Annotation { + val module = ModuleDescriptorImpl(Name.special(""), LockBasedStorageManager(), DefaultBuiltIns.Instance) + val evaluator = ConstantExpressionEvaluator(module, LanguageVersionSettingsImpl.DEFAULT) + val trace = BindingTraceContext() val valueArguments = psi.valueArguments.map { arg -> - val evaluator = ConstantExpressionEvaluator(DefaultBuiltIns.Instance, LanguageVersionSettingsImpl.DEFAULT) - val trace = BindingTraceContext() val result = evaluator.evaluateToConstantValue(arg.getArgumentExpression()!!, trace, TypeUtils.NO_EXPECTED_TYPE) // TODO: consider inspecting `trace` to find diagnostics reported during the computation (such as division by zero, integer overflow, invalid annotation parameters etc.) val argName = arg.getArgumentName()?.asName?.toString() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index 70a00e1eae5..1ed2a8deb0c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -242,9 +242,9 @@ class DiagnosticReporterByTrackingStrategy( private fun reportConstantTypeMismatch(constraintError: NewConstraintError, expression: KtExpression): Boolean { if (expression is KtConstantExpression) { - val builtIns = context.scope.ownerDescriptor.builtIns + val module = context.scope.ownerDescriptor.module val constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType) - val hasConstantTypeError = CompileTimeConstantChecker(context, builtIns, true) + val hasConstantTypeError = CompileTimeConstantChecker(context, module, true) .checkConstantExpressionType(constantValue, expression, constraintError.upperType) if (hasConstantTypeError) return true } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantChecker.java index 73b094742fe..022a125a9eb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstantChecker.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.KtNodeTypes; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt; @@ -42,20 +43,22 @@ public class CompileTimeConstantChecker { private static final Set> errorsThatDependOnExpectedType = Sets.newHashSet(CONSTANT_EXPECTED_TYPE_MISMATCH, NULL_FOR_NONNULL_TYPE); - private final KotlinBuiltIns builtIns; - private final BindingTrace trace; - private final boolean checkOnlyErrorsThatDependOnExpectedType; private final ResolutionContext context; + private final ModuleDescriptor module; + private final KotlinBuiltIns builtIns; + private final boolean checkOnlyErrorsThatDependOnExpectedType; + private final BindingTrace trace; public CompileTimeConstantChecker( @NotNull ResolutionContext context, - @NotNull KotlinBuiltIns builtIns, + @NotNull ModuleDescriptor module, boolean checkOnlyErrorsThatDependOnExpectedType ) { - this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType; - this.builtIns = builtIns; - this.trace = context.trace; this.context = context; + this.module = module; + this.builtIns = module.getBuiltIns(); + this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType; + this.trace = context.trace; } // return true if there is an error @@ -98,7 +101,7 @@ public class CompileTimeConstantChecker { } if (!noExpectedTypeOrError(expectedType)) { - KotlinType valueType = value.getType(); + KotlinType valueType = value.getType(module); if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { return reportConstantExpectedTypeMismatch(expression, "integer", expectedType, null); } @@ -115,7 +118,7 @@ public class CompileTimeConstantChecker { return reportError(FLOAT_LITERAL_OUT_OF_RANGE.on(expression)); } if (!noExpectedTypeOrError(expectedType)) { - KotlinType valueType = value.getType(); + KotlinType valueType = value.getType(module); if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { return reportConstantExpectedTypeMismatch(expression, "floating-point", expectedType, 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 78ca9e6ac1f..5a2f4a6646a 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 @@ -51,11 +51,9 @@ import java.math.BigInteger import java.util.* class ConstantExpressionEvaluator( - internal val builtIns: KotlinBuiltIns, + internal val module: ModuleDescriptor, internal val languageVersionSettings: LanguageVersionSettings ) { - internal val constantValueFactory = ConstantValueFactory(builtIns) - fun updateNumberType( numberType: KotlinType, expression: KtExpression?, @@ -106,7 +104,7 @@ class ConstantExpressionEvaluator( if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null - return constantValueFactory.createArrayValue(constants, parameterDescriptor.type) + return ConstantValueFactory.createArrayValue(constants, parameterDescriptor.type) } else { // we should actually get only one element, but just in case of getting many, we take the last one return constants.lastOrNull() @@ -116,7 +114,7 @@ class ConstantExpressionEvaluator( private fun isArrayPassedInNamedForm(constants: List>, resolvedArgument: ResolvedValueArgument): Boolean { val constant = constants.singleOrNull() ?: return false val argument = resolvedArgument.arguments.singleOrNull() ?: return false - return KotlinBuiltIns.isArrayOrPrimitiveArray(constant.type) && argument.isNamed() + return constant is ArrayValue && argument.isNamed() } private fun checkCompileTimeConstant( @@ -205,7 +203,7 @@ class ConstantExpressionEvaluator( } val returnType = resolvedCall.resultingDescriptor.returnType ?: return null - val componentType = builtIns.getArrayElementType(returnType) + val componentType = module.builtIns.getArrayElementType(returnType) val result = arrayListOf() for ((_, resolvedValueArgument) in resolvedCall.valueArguments) { @@ -289,8 +287,7 @@ private class ConstantExpressionEvaluatorVisitor( private val constantExpressionEvaluator: ConstantExpressionEvaluator, private val trace: BindingTrace ) : KtVisitor?, KotlinType>() { - - private val factory = constantExpressionEvaluator.constantValueFactory + private val builtIns = constantExpressionEvaluator.module.builtIns fun evaluate(expression: KtExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { val recordedCompileTimeConstant = ConstantExpressionEvaluator.getPossiblyErrorConstant(expression, trace.bindingContext) @@ -314,8 +311,8 @@ private class ConstantExpressionEvaluatorVisitor( } return when (constantValue) { is ErrorValue, is EnumValue -> return null - is NullValue -> factory.createStringValue("null") - else -> factory.createStringValue(constantValue.value.toString()) + is NullValue -> ConstantValueFactory.createStringValue("null") + else -> ConstantValueFactory.createStringValue(constantValue.value.toString()) }.wrap(compileTimeConstant.parameters) } @@ -329,23 +326,26 @@ private class ConstantExpressionEvaluatorVisitor( ): TypedCompileTimeConstant? { val expression = entry.expression ?: return null - return evaluate(expression, constantExpressionEvaluator.builtIns.stringType)?.let { + return evaluate(expression, builtIns.stringType)?.let { createStringConstant(it) } } - override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?) = - factory.createStringValue(entry.text).wrap() + override fun visitLiteralStringTemplateEntry( + entry: KtLiteralStringTemplateEntry, + data: Nothing? + ): TypedCompileTimeConstant = + ConstantValueFactory.createStringValue(entry.text).wrap() - override fun visitEscapeStringTemplateEntry(entry: KtEscapeStringTemplateEntry, data: Nothing?) = - factory.createStringValue(entry.unescapedValue).wrap() + override fun visitEscapeStringTemplateEntry(entry: KtEscapeStringTemplateEntry, data: Nothing?): TypedCompileTimeConstant = + ConstantValueFactory.createStringValue(entry.unescapedValue).wrap() } override fun visitConstantExpression(expression: KtConstantExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { val text = expression.text ?: return null val nodeElementType = expression.node.elementType - if (nodeElementType == KtNodeTypes.NULL) return factory.createNullValue().wrap() + if (nodeElementType == KtNodeTypes.NULL) return ConstantValueFactory.createNullValue().wrap() val result: Any? = when (nodeElementType) { KtNodeTypes.INTEGER_CONSTANT, KtNodeTypes.FLOAT_CONSTANT -> parseNumericLiteral(text, nodeElementType) @@ -461,7 +461,7 @@ private class ConstantExpressionEvaluatorVisitor( val operationToken = expression.operationToken if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationToken)) { - val booleanType = constantExpressionEvaluator.builtIns.booleanType + val booleanType = builtIns.booleanType val leftConstant = evaluate(leftExpression, booleanType) ?: return null val rightExpression = expression.right ?: return null @@ -545,7 +545,7 @@ private class ConstantExpressionEvaluatorVisitor( if ((isIntegerType(argumentForReceiver.value) && isIntegerType(argumentForParameter.value)) || !constantExpressionEvaluator.languageVersionSettings.supportsFeature(LanguageFeature.DivisionByZeroInConstantExpressions)) { - return factory.createErrorValue("Division by zero").wrap() + return ConstantValueFactory.createErrorValue("Division by zero").wrap() } } @@ -563,10 +563,8 @@ private class ConstantExpressionEvaluatorVisitor( val parameters = CompileTimeConstant.Parameters(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant, usesNonConstValAsConstant) return when (resultingDescriptorName) { - OperatorNameConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, factory)?.wrap( - parameters - ) - OperatorNameConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, factory)?.wrap(parameters) + OperatorNameConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression)?.wrap(parameters) + OperatorNameConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression)?.wrap(parameters) else -> { createConstant(result, expectedType, parameters) } @@ -664,7 +662,7 @@ private class ConstantExpressionEvaluatorVisitor( override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { val enumDescriptor = trace.bindingContext.get(BindingContext.REFERENCE_TARGET, expression) if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) { - return factory.createEnumValue(enumDescriptor as ClassDescriptor).wrap() + return ConstantValueFactory.createEnumValue(enumDescriptor as ClassDescriptor).wrap() } val resolvedCall = expression.getResolvedCall(trace.bindingContext) @@ -764,14 +762,14 @@ private class ConstantExpressionEvaluatorVisitor( call: ResolvedCall<*> ): TypedCompileTimeConstant>>? { val returnType = call.resultingDescriptor.returnType ?: return null - val componentType = constantExpressionEvaluator.builtIns.getArrayElementType(returnType) + val componentType = builtIns.getArrayElementType(returnType) val arguments = call.valueArguments.values.flatMap { resolveArguments(it.arguments, componentType) } // not evaluated arguments are not constants: function-calls, properties with custom getter... val evaluatedArguments = arguments.filterNotNull() - return factory.createArrayValue(evaluatedArguments.map { it.toConstantValue(componentType) }, returnType) + return ConstantValueFactory.createArrayValue(evaluatedArguments.map { it.toConstantValue(componentType) }, returnType) .wrap( usesVariableAsConstant = evaluatedArguments.any { it.usesVariableAsConstant }, usesNonConstValAsConstant = arguments.any { it == null || it.usesNonConstValAsConstant } @@ -781,7 +779,7 @@ private class ConstantExpressionEvaluatorVisitor( override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { val type = trace.getType(expression)!! if (type.isError) return null - return factory.createKClassValue(type).wrap() + return ConstantValueFactory.createKClassValue(type).wrap() } private fun resolveArguments(valueArguments: List, expectedType: KotlinType): List?> { @@ -823,10 +821,8 @@ private class ConstantExpressionEvaluatorVisitor( return createOperationArgument(argumentExpression, parameter.type, argumentCompileTimeType) } - - private fun getCompileTimeType(c: KotlinType): CompileTimeType? { - val builtIns = constantExpressionEvaluator.builtIns - return when (TypeUtils.makeNotNullable(c)) { + private fun getCompileTimeType(c: KotlinType): CompileTimeType? = + when (TypeUtils.makeNotNullable(c)) { builtIns.intType -> INT builtIns.byteType -> BYTE builtIns.shortType -> SHORT @@ -839,7 +835,6 @@ private class ConstantExpressionEvaluatorVisitor( builtIns.anyType -> ANY else -> null } - } private fun createOperationArgument( expression: KtExpression, @@ -860,7 +855,7 @@ private class ConstantExpressionEvaluatorVisitor( return if (parameters.isPure) { return createCompileTimeConstant(value, parameters, expectedType ?: TypeUtils.NO_EXPECTED_TYPE) } else { - factory.createConstantValue(value)?.wrap(parameters) + ConstantValueFactory.createConstantValue(value)?.wrap(parameters) } } @@ -871,7 +866,7 @@ private class ConstantExpressionEvaluatorVisitor( ): CompileTimeConstant<*>? { return when (value) { is Byte, is Short, is Int, is Long -> createIntegerCompileTimeConstant((value as Number).toLong(), parameters, expectedType) - else -> factory.createConstantValue(value)?.wrap(parameters) + else -> ConstantValueFactory.createConstantValue(value)?.wrap(parameters) } } @@ -881,20 +876,20 @@ private class ConstantExpressionEvaluatorVisitor( expectedType: KotlinType ): CompileTimeConstant<*>? { if (TypeUtils.noExpectedType(expectedType) || expectedType.isError) { - return IntegerValueTypeConstant(value, constantExpressionEvaluator.builtIns, parameters) + return IntegerValueTypeConstant(value, builtIns, parameters) } - val integerValue = factory.createIntegerConstantValue(value, expectedType) + val integerValue = ConstantValueFactory.createIntegerConstantValue(value, expectedType) if (integerValue != null) { return integerValue.wrap(parameters) } return when (value) { - value.toInt().toLong() -> factory.createIntValue(value.toInt()) - else -> factory.createLongValue(value) + value.toInt().toLong() -> ConstantValueFactory.createIntValue(value.toInt()) + else -> ConstantValueFactory.createLongValue(value) }.wrap(parameters) } private fun ConstantValue.wrap(parameters: CompileTimeConstant.Parameters): TypedCompileTimeConstant = - TypedCompileTimeConstant(this, parameters) + TypedCompileTimeConstant(this, constantExpressionEvaluator.module, parameters) private fun ConstantValue.wrap( canBeUsedInAnnotation: Boolean = this !is NullValue, @@ -962,11 +957,7 @@ private fun parseBoolean(text: String): Boolean { } -private fun createCompileTimeConstantForEquals( - result: Any?, - operationReference: KtExpression, - factory: ConstantValueFactory -): ConstantValue<*>? { +private fun createCompileTimeConstantForEquals(result: Any?, operationReference: KtExpression): ConstantValue<*>? { if (result is Boolean) { assert(operationReference is KtSimpleNameExpression) { "This method should be called only for equals operations" } val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType() @@ -979,27 +970,23 @@ private fun createCompileTimeConstantForEquals( } else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.text}") } - return factory.createBooleanValue(value) + return ConstantValueFactory.createBooleanValue(value) } return null } -private fun createCompileTimeConstantForCompareTo( - result: Any?, - operationReference: KtExpression, - factory: ConstantValueFactory -): ConstantValue<*>? { +private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: KtExpression): ConstantValue<*>? { if (result is Int) { assert(operationReference is KtSimpleNameExpression) { "This method should be called only for compareTo operations" } val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType() return when (operationToken) { - KtTokens.LT -> factory.createBooleanValue(result < 0) - KtTokens.LTEQ -> factory.createBooleanValue(result <= 0) - KtTokens.GT -> factory.createBooleanValue(result > 0) - KtTokens.GTEQ -> factory.createBooleanValue(result >= 0) + KtTokens.LT -> ConstantValueFactory.createBooleanValue(result < 0) + KtTokens.LTEQ -> ConstantValueFactory.createBooleanValue(result <= 0) + KtTokens.GT -> ConstantValueFactory.createBooleanValue(result > 0) + KtTokens.GTEQ -> ConstantValueFactory.createBooleanValue(result >= 0) KtTokens.IDENTIFIER -> { assert(operationReference.getReferencedNameAsName() == OperatorNameConventions.COMPARE_TO) { "This method should be called only for compareTo operations" } - return factory.createIntValue(result) + return ConstantValueFactory.createIntValue(result) } else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken") } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index da33205599b..f26cd4b943c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -208,13 +208,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ); if (!(compileTimeConstant instanceof IntegerValueTypeConstant)) { - CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context, components.builtIns, false); + CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context, components.moduleDescriptor, false); ConstantValue constantValue = compileTimeConstant != null ? ((TypedCompileTimeConstant) compileTimeConstant).getConstantValue() : null; boolean hasError = constantChecker.checkConstantExpressionType(constantValue, expression, context.expectedType); if (hasError) { - return TypeInfoFactoryKt.createTypeInfo(constantValue != null ? constantValue.getType() : getDefaultType(elementType), - context); + return TypeInfoFactoryKt.createTypeInfo( + constantValue != null ? constantValue.getType(components.moduleDescriptor) : getDefaultType(elementType), + context + ); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index fbc90f23362..ffe01d572e7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -53,11 +53,10 @@ import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEP import static org.jetbrains.kotlin.types.TypeUtils.*; public class DataFlowAnalyzer { - private final Iterable additionalTypeCheckers; private final ConstantExpressionEvaluator constantExpressionEvaluator; + private final ModuleDescriptor module; private final KotlinBuiltIns builtIns; - private final SmartCastManager smartCastManager; private final ExpressionTypingFacade facade; private final LanguageVersionSettings languageVersionSettings; private final EffectSystem effectSystem; @@ -65,16 +64,16 @@ public class DataFlowAnalyzer { public DataFlowAnalyzer( @NotNull Iterable additionalTypeCheckers, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator, + @NotNull ModuleDescriptor module, @NotNull KotlinBuiltIns builtIns, - @NotNull SmartCastManager smartCastManager, @NotNull ExpressionTypingFacade facade, @NotNull LanguageVersionSettings languageVersionSettings, @NotNull EffectSystem effectSystem ) { this.additionalTypeCheckers = additionalTypeCheckers; this.constantExpressionEvaluator = constantExpressionEvaluator; + this.module = module; this.builtIns = builtIns; - this.smartCastManager = smartCastManager; this.facade = facade; this.languageVersionSettings = languageVersionSettings; this.effectSystem = effectSystem; @@ -285,7 +284,7 @@ public class DataFlowAnalyzer { if (expression instanceof KtConstantExpression && reportErrorForTypeMismatch) { ConstantValue constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType); - boolean error = new CompileTimeConstantChecker(c, builtIns, true) + boolean error = new CompileTimeConstantChecker(c, module, true) .checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType); hasError.set(error); return expressionType; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index 403f9737d34..825e4669f03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.context.GlobalContext; import org.jetbrains.kotlin.contracts.EffectSystem; import org.jetbrains.kotlin.contracts.parsing.ContractParsingServices; +import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.incremental.components.LookupTracker; import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap; import org.jetbrains.kotlin.resolve.*; @@ -36,6 +37,7 @@ import javax.inject.Inject; public class ExpressionTypingComponents { /*package*/ GlobalContext globalContext; + /*package*/ ModuleDescriptor moduleDescriptor; /*package*/ ExpressionTypingServices expressionTypingServices; /*package*/ CallResolver callResolver; /*package*/ PlatformToKotlinClassMap platformToKotlinClassMap; @@ -74,6 +76,11 @@ public class ExpressionTypingComponents { this.globalContext = globalContext; } + @Inject + public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) { + this.moduleDescriptor = moduleDescriptor; + } + @Inject public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) { this.expressionTypingServices = expressionTypingServices; diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 8e9b97f4d50..f66abd44ad9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -207,7 +207,7 @@ class StatementGenerator( fun generateConstantExpression(expression: KtExpression, constant: CompileTimeConstant<*>): IrExpression { val constantValue = constant.toConstantValue(getInferredTypeWithImplicitCastsOrFail(expression)) - val constantType = constantValue.type + val constantType = constantValue.getType(context.moduleDescriptor) return when (constantValue) { is StringValue -> @@ -231,7 +231,7 @@ class StatementGenerator( is ShortValue -> IrConstImpl.short(expression.startOffset, expression.endOffset, constantType, constantValue.value) else -> - TODO("handle other literal types: ${constantValue.type}") + TODO("handle other literal types: $constantType") } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constants/evaluate/AbstractCompileTimeConstantEvaluatorTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constants/evaluate/AbstractCompileTimeConstantEvaluatorTest.kt index eb165845013..9c8c8243943 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constants/evaluate/AbstractCompileTimeConstantEvaluatorTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constants/evaluate/AbstractCompileTimeConstantEvaluatorTest.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.annotation.AbstractAnnotationDescriptorResolveTest import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.StringValue -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File @@ -65,12 +65,11 @@ abstract class AbstractCompileTimeConstantEvaluatorTest : AbstractAnnotationDesc private fun evaluateInitializer(context: BindingContext, property: VariableDescriptor): CompileTimeConstant<*>? { val propertyDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(property) as KtProperty - val compileTimeConstant = ConstantExpressionEvaluator(property.builtIns, LanguageVersionSettingsImpl.DEFAULT).evaluateExpression( + return ConstantExpressionEvaluator(property.module, LanguageVersionSettingsImpl.DEFAULT).evaluateExpression( propertyDeclaration.initializer!!, DelegatingBindingTrace(context, "trace for evaluating compile time constant"), property.type ) - return compileTimeConstant } private fun doTest(path: String, getValueToTest: (VariableDescriptor, BindingContext) -> String) { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt index aedc1d30922..f56f9dbb875 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt @@ -114,8 +114,7 @@ class JavaDeprecatedAnnotationDescriptor( c: LazyJavaResolverContext ): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.deprecated) { override val allValueArguments: Map> by c.storageManager.createLazyValue { - mapOf(JavaAnnotationMapper.DEPRECATED_ANNOTATION_MESSAGE to - ConstantValueFactory(c.module.builtIns).createStringValue("Deprecated in Java")) + mapOf(JavaAnnotationMapper.DEPRECATED_ANNOTATION_MESSAGE to ConstantValueFactory.createStringValue("Deprecated in Java")) } } @@ -170,7 +169,7 @@ object JavaAnnotationTargetMapper { JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS, builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.target) ) - return ArrayValue(kotlinTargets, parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]"), builtIns) + return ArrayValue(kotlinTargets) { parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]") } } private val retentionNameList = mapOf( diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index cccbafdae05..4b8b74ca683 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -57,8 +57,6 @@ class LazyJavaAnnotationDescriptor( override val source = c.components.sourceElementFactory.source(javaAnnotation) - private val factory = ConstantValueFactory(c.module.builtIns) - override val allValueArguments by c.storageManager.createLazyValue { javaAnnotation.arguments.mapNotNull { arg -> val name = arg.name ?: DEFAULT_ANNOTATION_MEMBER_NAME @@ -68,7 +66,7 @@ class LazyJavaAnnotationDescriptor( private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): ConstantValue<*>? { return when (argument) { - is JavaLiteralAnnotationArgument -> factory.createConstantValue(argument.value) + is JavaLiteralAnnotationArgument -> ConstantValueFactory.createConstantValue(argument.value) is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve(), argument.entryName) is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements()) is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation()) @@ -78,7 +76,7 @@ class LazyJavaAnnotationDescriptor( } private fun resolveFromAnnotation(javaAnnotation: JavaAnnotation): ConstantValue<*> { - return factory.createAnnotationValue(LazyJavaAnnotationDescriptor(c, javaAnnotation)) + return ConstantValueFactory.createAnnotationValue(LazyJavaAnnotationDescriptor(c, javaAnnotation)) } private fun resolveFromArray(argumentName: Name, elements: List): ConstantValue<*>? { @@ -93,16 +91,16 @@ class LazyJavaAnnotationDescriptor( ) val values = elements.map { - argument -> resolveAnnotationArgument(argument) ?: factory.createNullValue() + argument -> resolveAnnotationArgument(argument) ?: ConstantValueFactory.createNullValue() } - return factory.createArrayValue(values, arrayType) + return ConstantValueFactory.createArrayValue(values, arrayType) } private fun resolveFromEnumValue(element: JavaField?, entryName: Name?): ConstantValue<*>? { if (element == null || !element.isEnumEntry) { if (entryName == null) return null - return factory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName)) + return ConstantValueFactory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName)) } val containingJavaClass = element.containingClass @@ -112,7 +110,7 @@ class LazyJavaAnnotationDescriptor( val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(element.name, NoLookupLocation.FROM_JAVA_LOADER) as? ClassDescriptor ?: return null - return factory.createEnumValue(classifier) + return ConstantValueFactory.createEnumValue(classifier) } private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? { @@ -128,7 +126,7 @@ class LazyJavaAnnotationDescriptor( val javaClassObjectType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, jlClass, arguments) - return factory.createKClassValue(javaClassObjectType) + return ConstantValueFactory.createKClassValue(javaClassObjectType) } override fun toString(): String { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt index 62f59bab61f..c6ddc1f8644 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -45,7 +45,6 @@ class BinaryClassAnnotationAndConstantLoaderImpl( storageManager, kotlinClassFinder ) { private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses) - private val factory = ConstantValueFactory(module.builtIns) override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor = annotationDeserializer.deserializeAnnotation(proto, nameResolver) @@ -65,7 +64,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl( initializer } - return factory.createConstantValue(normalizedValue) + return ConstantValueFactory.createConstantValue(normalizedValue) } override fun loadPropertyAnnotations( @@ -116,7 +115,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl( override fun visitEnd() { val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) if (parameter != null) { - arguments[name] = factory.createArrayValue(elements.compact(), parameter.type) + arguments[name] = ConstantValueFactory.createArrayValue(elements.compact(), parameter.type) } } } @@ -139,10 +138,10 @@ class BinaryClassAnnotationAndConstantLoaderImpl( if (enumClass.kind == ClassKind.ENUM_CLASS) { val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(name, NoLookupLocation.FROM_JAVA_LOADER) if (classifier is ClassDescriptor) { - return factory.createEnumValue(classifier) + return ConstantValueFactory.createEnumValue(classifier) } } - return factory.createErrorValue("Unresolved enum entry: $enumClassId.$name") + return ConstantValueFactory.createErrorValue("Unresolved enum entry: $enumClassId.$name") } override fun visitEnd() { @@ -150,8 +149,8 @@ class BinaryClassAnnotationAndConstantLoaderImpl( } private fun createConstant(name: Name?, value: Any?): ConstantValue<*> { - return factory.createConstantValue(value) ?: - factory.createErrorValue("Unsupported annotation argument: $name") + return ConstantValueFactory.createConstantValue(value) ?: + ConstantValueFactory.createErrorValue("Unsupported annotation argument: $name") } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt index 1944870f45b..611f003acd2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt @@ -169,7 +169,7 @@ fun getFunctionTypeArgumentProjections( val parameterNameAnnotation = BuiltInAnnotationDescriptor( builtIns, KotlinBuiltIns.FQ_NAMES.parameterName, - mapOf(Name.identifier("name") to ConstantValueFactory(builtIns).createStringValue(name.asString())) + mapOf(Name.identifier("name") to ConstantValueFactory.createStringValue(name.asString())) ) type.replaceAnnotations(AnnotationsImpl(type.annotations + parameterNameAnnotation)) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt index 2d3a9ec3a0f..2f1a8ffe9e0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt @@ -39,8 +39,10 @@ fun KotlinBuiltIns.createDeprecatedAnnotation( this, KotlinBuiltIns.FQ_NAMES.replaceWith, mapOf( - REPLACE_WITH_EXPRESSION_NAME to StringValue(replaceWith, this), - REPLACE_WITH_IMPORTS_NAME to ArrayValue(emptyList(), getArrayType(Variance.INVARIANT, stringType), this) + REPLACE_WITH_EXPRESSION_NAME to StringValue(replaceWith), + REPLACE_WITH_IMPORTS_NAME to ArrayValue(emptyList()) { module -> + module.builtIns.getArrayType(Variance.INVARIANT, stringType) + } ) ) @@ -48,7 +50,7 @@ fun KotlinBuiltIns.createDeprecatedAnnotation( this, KotlinBuiltIns.FQ_NAMES.deprecated, mapOf( - DEPRECATED_MESSAGE_NAME to StringValue(message, this), + DEPRECATED_MESSAGE_NAME to StringValue(message), DEPRECATED_REPLACE_WITH_NAME to AnnotationValue(replaceWithAnnotation), DEPRECATED_LEVEL_NAME to EnumValue(getDeprecationLevelEnumEntry(level) ?: error("Deprecation level $level not found")) ) 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 7037850f776..5fa82161ca5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt @@ -17,8 +17,12 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.KotlinTypeFactory +import org.jetbrains.kotlin.types.TypeUtils interface CompileTimeConstant { val isError: Boolean @@ -48,12 +52,13 @@ interface CompileTimeConstant { class TypedCompileTimeConstant( val constantValue: ConstantValue, + module: ModuleDescriptor, override val parameters: CompileTimeConstant.Parameters ) : CompileTimeConstant { override val isError: Boolean get() = constantValue is ErrorValue - val type: KotlinType = constantValue.type + val type: KotlinType = constantValue.getType(module) override fun toConstantValue(expectedType: KotlinType): ConstantValue = constantValue @@ -75,32 +80,24 @@ class TypedCompileTimeConstant( class IntegerValueTypeConstant( private val value: Number, - private val builtIns: KotlinBuiltIns, + builtIns: KotlinBuiltIns, override val parameters: CompileTimeConstant.Parameters ) : CompileTimeConstant { private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), builtIns) override fun toConstantValue(expectedType: KotlinType): ConstantValue { - val factory = ConstantValueFactory(builtIns) val type = getType(expectedType) return when { - KotlinBuiltIns.isInt(type) -> { - factory.createIntValue(value.toInt()) - } - KotlinBuiltIns.isByte(type) -> { - factory.createByteValue(value.toByte()) - } - KotlinBuiltIns.isShort(type) -> { - factory.createShortValue(value.toShort()) - } - else -> { - factory.createLongValue(value.toLong()) - } + KotlinBuiltIns.isInt(type) -> ConstantValueFactory.createIntValue(value.toInt()) + KotlinBuiltIns.isByte(type) -> ConstantValueFactory.createByteValue(value.toByte()) + KotlinBuiltIns.isShort(type) -> ConstantValueFactory.createShortValue(value.toShort()) + else -> ConstantValueFactory.createLongValue(value.toLong()) } } - val unknownIntegerType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(Annotations.EMPTY, typeConstructor, emptyList(), - false, ErrorUtils.createErrorScope("Scope for number value type (" + typeConstructor.toString() + ")", true) + val unknownIntegerType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( + Annotations.EMPTY, typeConstructor, emptyList(), false, + ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true) ) fun getType(expectedType: KotlinType): KotlinType = TypeUtils.getPrimitiveNumberType(typeConstructor, expectedType) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt index 799821df788..c9bc96f1188 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt @@ -19,41 +19,37 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils -class ConstantValueFactory( - private val builtins: KotlinBuiltIns -) { - fun createLongValue(value: Long) = LongValue(value, builtins) +object ConstantValueFactory { + fun createLongValue(value: Long) = LongValue(value) - fun createIntValue(value: Int) = IntValue(value, builtins) + fun createIntValue(value: Int) = IntValue(value) fun createErrorValue(message: String) = ErrorValue.create(message) - fun createShortValue(value: Short) = ShortValue(value, builtins) + fun createShortValue(value: Short) = ShortValue(value) - fun createByteValue(value: Byte) = ByteValue(value, builtins) + fun createByteValue(value: Byte) = ByteValue(value) - fun createDoubleValue(value: Double) = DoubleValue(value, builtins) + fun createDoubleValue(value: Double) = DoubleValue(value) - fun createFloatValue(value: Float) = FloatValue(value, builtins) + fun createFloatValue(value: Float) = FloatValue(value) - fun createBooleanValue(value: Boolean) = BooleanValue(value, builtins) + fun createBooleanValue(value: Boolean) = BooleanValue(value) - fun createCharValue(value: Char) = CharValue(value, builtins) + fun createCharValue(value: Char) = CharValue(value) - fun createStringValue(value: String) = StringValue(value, builtins) + fun createStringValue(value: String) = StringValue(value) - fun createNullValue() = NullValue(builtins) + fun createNullValue() = NullValue() fun createEnumValue(enumEntryClass: ClassDescriptor): EnumValue = EnumValue(enumEntryClass) - fun createArrayValue( - value: List>, - type: KotlinType - ) = ArrayValue(value, type, builtins) + fun createArrayValue(value: List>, type: KotlinType) = createArrayValue(value) { type } fun createAnnotationValue(value: AnnotationDescriptor) = AnnotationValue(value) @@ -83,11 +79,14 @@ class ConstantValueFactory( } } + private fun createArrayValue(value: List>, computeType: (ModuleDescriptor) -> KotlinType): ArrayValue = + ArrayValue(value, computeType) + private fun List<*>.arrayToList(): List> = this.toList().mapNotNull { createConstantValue(it) } - private fun PrimitiveType.arrayType(): KotlinType = - builtins.getPrimitiveArrayKotlinType(this) + private fun PrimitiveType.arrayType(): (ModuleDescriptor) -> KotlinType = + { module -> module.builtIns.getPrimitiveArrayKotlinType(this) } fun createIntegerConstantValue( value: Long, @@ -104,4 +103,3 @@ class ConstantValueFactory( } } } - diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt index ab016e64dc3..1c88a3415be 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt @@ -18,14 +18,19 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType abstract class ConstantValue(open val value: T) { - abstract val type: KotlinType + abstract fun getType(module: ModuleDescriptor): KotlinType abstract fun accept(visitor: AnnotationArgumentVisitor, data: D): R @@ -36,8 +41,7 @@ abstract class IntegerValueConstant protected constructor(value: T) : Con class AnnotationValue(value: AnnotationDescriptor) : ConstantValue(value) { - override val type: KotlinType - get() = value.type + override fun getType(module: ModuleDescriptor): KotlinType = value.type override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitAnnotationValue(this, data) override fun toString() = value.toString() @@ -45,12 +49,10 @@ class AnnotationValue(value: AnnotationDescriptor) : ConstantValue>, - override val type: KotlinType, - private val builtIns: KotlinBuiltIns + private val computeType: (ModuleDescriptor) -> KotlinType ) : ConstantValue>>(value) { - - init { - assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) { "Type should be an array, but was " + type + ": " + value } + override fun getType(module: ModuleDescriptor): KotlinType = computeType(module).also { type -> + assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) { "Type should be an array, but was $type: $value" } } override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitArrayValue(this, data) @@ -60,33 +62,20 @@ class ArrayValue( override fun hashCode() = value.hashCode() } -class BooleanValue( - value: Boolean, - builtIns: KotlinBuiltIns -) : ConstantValue(value) { - - override val type = builtIns.booleanType +class BooleanValue(value: Boolean) : ConstantValue(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.booleanType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitBooleanValue(this, data) - } -class ByteValue( - value: Byte, - builtIns: KotlinBuiltIns -) : IntegerValueConstant(value) { - - override val type = builtIns.byteType +class ByteValue(value: Byte) : IntegerValueConstant(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.byteType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitByteValue(this, data) override fun toString(): String = "$value.toByte()" } -class CharValue( - value: Char, - builtIns: KotlinBuiltIns -) : IntegerValueConstant(value) { - - override val type = builtIns.charType +class CharValue(value: Char) : IntegerValueConstant(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.charType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitCharValue(this, data) @@ -96,7 +85,7 @@ class CharValue( '\b' -> "\\b" '\t' -> "\\t" '\n' -> "\\n" - //TODO: KT-8507 + //TODO: KT-8507 12.toChar() -> "\\f" '\r' -> "\\r" else -> if (isPrintableUnicode(c)) Character.toString(c) else "?" @@ -114,27 +103,26 @@ class CharValue( } } -class DoubleValue( - value: Double, - builtIns: KotlinBuiltIns -) : ConstantValue(value) { - override val type = builtIns.doubleType +class DoubleValue(value: Double) : ConstantValue(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.doubleType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitDoubleValue(this, data) override fun toString() = "$value.toDouble()" } -class EnumValue( - value: ClassDescriptor -) : ConstantValue(value) { +class EnumValue(value: ClassDescriptor) : ConstantValue(value) { + val enumClassId: ClassId get() = (value.containingDeclaration as ClassDescriptor).classId!! - override val type: KotlinType - get() = value.classValueType ?: ErrorUtils.createErrorType("Containing class for error-class based enum entry $value") + val enumEntryName: Name get() = value.name + + override fun getType(module: ModuleDescriptor): KotlinType = + value.classValueType + ?: ErrorUtils.createErrorType("Containing class for error-class based enum entry ${value.fqNameUnsafe}") override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitEnumValue(this, data) - override fun toString() = "$type.${value.name}" + override fun toString() = "${enumClassId.shortClassName}.$enumEntryName" override fun equals(other: Any?): Boolean = this === other || value == (other as? EnumValue)?.value @@ -151,7 +139,7 @@ abstract class ErrorValue : ConstantValue(Unit) { class ErrorValueWithMessage(val message: String) : ErrorValue() { - override val type = ErrorUtils.createErrorType(message) + override fun getType(module: ModuleDescriptor) = ErrorUtils.createErrorType(message) override fun toString() = message } @@ -163,23 +151,16 @@ abstract class ErrorValue : ConstantValue(Unit) { } } -class FloatValue( - value: Float, - builtIns: KotlinBuiltIns -) : ConstantValue(value) { - override val type = builtIns.floatType +class FloatValue(value: Float) : ConstantValue(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.floatType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitFloatValue(this, data) override fun toString() = "$value.toFloat()" } -class IntValue( - value: Int, - builtIns: KotlinBuiltIns -) : IntegerValueConstant(value) { - - override val type = builtIns.intType +class IntValue(value: Int) : IntegerValueConstant(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.intType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitIntValue(this, data) @@ -188,54 +169,41 @@ class IntValue( override fun hashCode() = value } -class KClassValue(override val type: KotlinType) : - ConstantValue(type) { +class KClassValue(private val type: KotlinType) : ConstantValue(type) { + override fun getType(module: ModuleDescriptor): KotlinType = type + override val value: KotlinType get() = type.arguments.single().type override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitKClassValue(this, data) } -class LongValue( - value: Long, - builtIns: KotlinBuiltIns -) : IntegerValueConstant(value) { - - override val type = builtIns.longType +class LongValue(value: Long) : IntegerValueConstant(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.longType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitLongValue(this, data) override fun toString() = "$value.toLong()" } -class NullValue( - builtIns: KotlinBuiltIns -) : ConstantValue(null) { - - override val type = builtIns.nullableNothingType +class NullValue : ConstantValue(null) { + override fun getType(module: ModuleDescriptor) = module.builtIns.nullableNothingType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitNullValue(this, data) override fun toString() = "null" } -class ShortValue( - value: Short, - builtIns: KotlinBuiltIns -) : IntegerValueConstant(value) { - - override val type = builtIns.shortType +class ShortValue(value: Short) : IntegerValueConstant(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.shortType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitShortValue(this, data) override fun toString() = "$value.toShort()" } -class StringValue( - value: String, - builtIns: KotlinBuiltIns -) : ConstantValue(value) { - override val type = builtIns.stringType +class StringValue(value: String) : ConstantValue(value) { + override fun getType(module: ModuleDescriptor) = module.builtIns.stringType override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitStringValue(this, data) 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 465afc082c0..56245cffa73 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt @@ -40,8 +40,6 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n private val builtIns: KotlinBuiltIns get() = module.builtIns - private val factory = ConstantValueFactory(builtIns) - fun deserializeAnnotation(proto: Annotation, nameResolver: NameResolver): AnnotationDescriptor { val annotationClass = resolveClass(nameResolver.getClassId(proto.id)) @@ -72,16 +70,16 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n nameResolver: NameResolver ): ConstantValue<*> { val result: ConstantValue<*> = when (value.type) { - Type.BYTE -> factory.createByteValue(value.intValue.toByte()) - Type.CHAR -> factory.createCharValue(value.intValue.toChar()) - Type.SHORT -> factory.createShortValue(value.intValue.toShort()) - Type.INT -> factory.createIntValue(value.intValue.toInt()) - Type.LONG -> factory.createLongValue(value.intValue) - Type.FLOAT -> factory.createFloatValue(value.floatValue) - Type.DOUBLE -> factory.createDoubleValue(value.doubleValue) - Type.BOOLEAN -> factory.createBooleanValue(value.intValue != 0L) + Type.BYTE -> ConstantValueFactory.createByteValue(value.intValue.toByte()) + Type.CHAR -> ConstantValueFactory.createCharValue(value.intValue.toChar()) + Type.SHORT -> ConstantValueFactory.createShortValue(value.intValue.toShort()) + Type.INT -> ConstantValueFactory.createIntValue(value.intValue.toInt()) + Type.LONG -> ConstantValueFactory.createLongValue(value.intValue) + Type.FLOAT -> ConstantValueFactory.createFloatValue(value.floatValue) + Type.DOUBLE -> ConstantValueFactory.createDoubleValue(value.doubleValue) + Type.BOOLEAN -> ConstantValueFactory.createBooleanValue(value.intValue != 0L) Type.STRING -> { - factory.createStringValue(nameResolver.getString(value.stringValue)) + ConstantValueFactory.createStringValue(nameResolver.getString(value.stringValue)) } Type.CLASS -> { resolveClassLiteralValue(nameResolver.getClassId(value.classId)) @@ -111,7 +109,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n val expectedElementType = builtIns.getArrayElementType(if (expectedIsArray) expectedType else actualArrayType) - factory.createArrayValue( + ConstantValueFactory.createArrayValue( arrayElements.map { resolveValue(expectedElementType, it, nameResolver) }, @@ -121,12 +119,12 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n else -> error("Unsupported annotation argument type: ${value.type} (expected $expectedType)") } - return if (result.type.isSubtypeOf(expectedType)) { + return if (result.getType(module).isSubtypeOf(expectedType)) { result } else { // This means that an annotation class has been changed incompatibly without recompiling clients - factory.createErrorValue("Unexpected argument value") + ConstantValueFactory.createErrorValue("Unexpected argument value") } } @@ -136,7 +134,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n val starProjectedType = resolveClass(classId).defaultType.replaceArgumentsWithStarProjections() val kClass = resolveClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.kClass.toSafe())) val type = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClass, listOf(TypeProjectionImpl(starProjectedType))) - return factory.createKClassValue(type) + return ConstantValueFactory.createKClassValue(type) } // NOTE: see analogous code in BinaryClassAnnotationAndConstantLoaderImpl @@ -145,10 +143,10 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n if (enumClass.kind == ClassKind.ENUM_CLASS) { val enumEntry = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(enumEntryName, NoLookupLocation.FROM_DESERIALIZATION) if (enumEntry is ClassDescriptor) { - return factory.createEnumValue(enumEntry) + return ConstantValueFactory.createEnumValue(enumEntry) } } - return factory.createErrorValue("Unresolved enum entry: $enumClassId.$enumEntryName") + return ConstantValueFactory.createErrorValue("Unresolved enum entry: $enumClassId.$enumEntryName") } private fun resolveArrayElementType(value: Value, nameResolver: NameResolver): SimpleType = diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractableSubstringInfo.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractableSubstringInfo.kt index 8eb8714dc7d..1978c214c9b 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractableSubstringInfo.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractableSubstringInfo.kt @@ -43,8 +43,8 @@ class ExtractableSubstringInfo( ) { private fun guessLiteralType(literal: String): KotlinType { val facade = template.getResolutionFacade() - val builtIns = facade.moduleDescriptor.builtIns - val stringType = builtIns.stringType + val module = facade.moduleDescriptor + val stringType = module.builtIns.stringType if (startEntry != endEntry || startEntry !is KtLiteralStringTemplateEntry) return stringType @@ -56,10 +56,10 @@ class ExtractableSubstringInfo( val tempContext = expr.analyzeInContext(scope, template) val trace = DelegatingBindingTrace(tempContext, "Evaluate '$literal'") val languageVersionSettings = facade.getFrontendService(LanguageVersionSettings::class.java) - val value = ConstantExpressionEvaluator(builtIns, languageVersionSettings).evaluateExpression(expr, trace) + val value = ConstantExpressionEvaluator(module, languageVersionSettings).evaluateExpression(expr, trace) if (value == null || value.isError) return stringType - return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).type + return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).getType(module) } val template: KtStringTemplateExpression = startEntry.parent as KtStringTemplateExpression diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt index 0046c2a816f..e099b529b1c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt @@ -54,8 +54,9 @@ class KotlinLightConstantExpressionEvaluator : ConstantExpressionEvaluator { return when (expressionToCompute) { is KtExpression -> { val resolutionFacade = expressionToCompute.getResolutionFacade() - val evaluator = FrontendConstantExpressionEvaluator(resolutionFacade.moduleDescriptor.builtIns, - expressionToCompute.languageVersionSettings) + val evaluator = FrontendConstantExpressionEvaluator( + resolutionFacade.moduleDescriptor, expressionToCompute.languageVersionSettings + ) val evaluatorTrace = DelegatingBindingTrace(resolutionFacade.analyze(expressionToCompute), "Evaluating annotation argument") val constant = evaluator.evaluateExpression(expressionToCompute, evaluatorTrace) ?: return null @@ -72,4 +73,4 @@ class KotlinLightConstantExpressionEvaluator : ConstantExpressionEvaluator { else -> null } } -} \ No newline at end of file +}