Record COMPILE_TIME_INITIALIZER for all final variables

This commit is contained in:
Natalia Ukhorskaya
2014-01-17 13:10:55 +04:00
parent 2ddda59465
commit 97da2def08
23 changed files with 611 additions and 52 deletions
@@ -182,8 +182,9 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
if (argumentsEntrySet.isEmpty()) {
val result = evaluateUnaryAndCheck(argumentForReceiver, resultingDescriptorName.asString(), callExpression)
val isArgumentPure = trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, argumentForReceiver.expression) ?: false
val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression)
val isNumberConversionMethod = resultingDescriptorName in OperatorConventions.NUMBER_CONVERSIONS
return createCompileTimeConstant(result, fullExpression, expectedType, !isNumberConversionMethod && isArgumentPure)
return createCompileTimeConstant(result, fullExpression, expectedType, !isNumberConversionMethod && isArgumentPure, canBeUsedInAnnotation)
}
else if (argumentsEntrySet.size() == 1) {
val (parameter, argument) = argumentsEntrySet.first()
@@ -203,7 +204,8 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
else -> {
val areArgumentsPure = trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, argumentForReceiver.expression) ?: false &&
trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, argumentForParameter.expression) ?: false
createCompileTimeConstant(result, fullExpression, expectedType, areArgumentsPure)
val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression)
createCompileTimeConstant(result, fullExpression, expectedType, areArgumentsPure, canBeUsedInAnnotation)
}
}
}
@@ -211,6 +213,8 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return null
}
private fun canBeUsedInAnnotation(expression: JetExpression) = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)?.canBeUsedInAnnotations() ?: false
private fun evaluateUnaryAndCheck(receiver: OperationArgument, name: String, callExpression: JetExpression): Any? {
val functions = unaryOperations[UnaryOperationKey(receiver.ctcType, name)]
if (functions == null) return null
@@ -254,7 +258,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return actualResult
}
private fun isDivisionByZero(name: String, parameter: Any?): Boolean {
private fun isDivisionByZero(name: String, parameter: Any?): Boolean {
if (name == OperatorConventions.BINARY_OPERATION_NAMES[JetTokens.DIV]!!.asString()) {
if (isIntegerType(parameter)) {
return (parameter as Number).toLong() == 0.toLong()
@@ -282,10 +286,17 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression)
if (resolvedCall != null) {
val callableDescriptor = resolvedCall.getResultingDescriptor()
if (callableDescriptor is PropertyDescriptor) {
if (AnnotationUtils.isPropertyCompileTimeConstant(callableDescriptor)) {
return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, callableDescriptor)
}
if (callableDescriptor is VariableDescriptor) {
val compileTimeConstant = trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, callableDescriptor)
if (compileTimeConstant == null) return null
val value: Any? =
if (compileTimeConstant is IntegerValueTypeConstant)
compileTimeConstant.getValue(expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
else
compileTimeConstant.getValue()
return createCompileTimeConstant(value, expression, expectedType, false,
AnnotationUtils.isPropertyCompileTimeConstant(callableDescriptor))
}
}
return null
@@ -306,7 +317,11 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
// MyEnum.A, Integer.MAX_VALUE
if (selectorExpression != null) {
return evaluate(selectorExpression, expectedType)
val compileTimeConstant = evaluate(selectorExpression, expectedType)
if (trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, selectorExpression) == true) {
trace.record(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression, true)
}
return compileTimeConstant
}
return null
@@ -404,18 +419,36 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return OperationArgument(evaluationResult, compileTimeType, expression)
}
fun createCompileTimeConstant(value: Any?, expression: JetExpression, expectedType: JetType?, isPure: Boolean = true): CompileTimeConstant<*>? {
if (isPure) {
val compileTimeConstant = createCompileTimeConstant(value, expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
trace.record(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression, true)
return compileTimeConstant
}
fun createCompileTimeConstant(value: Any?, expression: JetExpression, expectedType: JetType?, isPure: Boolean = true, canBeUsedInAnnotation: Boolean = true): CompileTimeConstant<*>? {
val compileTimeConstant =
if (isPure) {
trace.record(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression, true)
createCompileTimeConstant(value, expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
}
else createCompileTimeConstant(value)
compileTimeConstant?.setCanBeUsedInAnnotations(canBeUsedInAnnotation)
val compileTimeConstant = createCompileTimeConstant(value)
return compileTimeConstant
}
}
public fun recordCompileTimeValueForInitializerIfNeeded(
variableDescriptor: VariableDescriptor,
initializer: JetExpression,
variableType: JetType,
trace: BindingTrace
) {
if (!variableDescriptor.isVar()) {
if (trace.get(BindingContext.COMPILE_TIME_INITIALIZER, variableDescriptor) == null) {
val constant = ConstantExpressionEvaluator.evaluate(initializer, trace, variableType)
if (constant != null) {
trace.record(BindingContext.COMPILE_TIME_INITIALIZER, variableDescriptor, constant)
}
}
}
}
public fun IntegerValueTypeConstant.createCompileTimeConstantWithType(expectedType: JetType): CompileTimeConstant<*>?
= createCompileTimeConstant(getValue(expectedType))
@@ -524,21 +557,16 @@ private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? {
}
private fun createCompileTimeConstant(value: Any?, expectedType: JetType? = null): CompileTimeConstant<*>? {
return when(value) {
is Byte, is Short, is Int, is Long -> {
return if (expectedType == null) {
when(value) {
is Byte -> ByteValue(value)
is Short -> ShortValue(value)
is Int -> IntValue(value)
is Long -> LongValue(value)
else -> throw IllegalArgumentException("All cases should be catched: $value")
}
}
else {
getIntegerValue((value as Number).toLong(), expectedType)
}
if (expectedType == null) {
when(value) {
is Byte -> return ByteValue(value)
is Short -> return ShortValue(value)
is Int -> return IntValue(value)
is Long -> return LongValue(value)
}
}
return when(value) {
is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), expectedType)
is Char -> CharValue(value)
is Float -> FloatValue(value)
is Double -> DoubleValue(value)
@@ -252,7 +252,7 @@ public class AnnotationResolver {
JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
}
if (constant != null) {
if (constant != null && constant.canBeUsedInAnnotations()) {
constants.add(constant);
}
else {
@@ -20,7 +20,6 @@ import jet.runtime.Intrinsic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
@@ -116,7 +115,7 @@ public class AnnotationUtils {
return "kotlin.javaClass.function".equals(getIntrinsicAnnotationArgument(resolvedCall.getResultingDescriptor().getOriginal()));
}
public static boolean isPropertyCompileTimeConstant(@NotNull PropertyDescriptor descriptor) {
public static boolean isPropertyCompileTimeConstant(@NotNull VariableDescriptor descriptor) {
if (descriptor.isVar()) {
return false;
}
@@ -77,7 +77,7 @@ public interface BindingContext {
WritableSlice<JetExpression, Boolean> IS_PURE_CONSTANT_EXPRESSION = Slices.createSimpleSlice();
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
WritableSlice<PropertyDescriptor, CompileTimeConstant<?>> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice();
WritableSlice<VariableDescriptor, CompileTimeConstant<?>> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice();
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
@@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
@@ -33,7 +33,6 @@ import org.jetbrains.jet.lang.resolve.calls.context.ResolutionResultsCacheImpl;
import org.jetbrains.jet.lang.resolve.calls.context.SimpleResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.*;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.*;
@@ -573,12 +572,8 @@ public class BodyResolver {
scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace);
JetType expectedTypeForInitializer = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, context.getOuterDataFlowInfo(), trace);
if (AnnotationUtils.isPropertyCompileTimeConstant(propertyDescriptor)) {
CompileTimeConstant<?> constant = ConstantExpressionEvaluator.object$.evaluate(initializer, trace, expectedTypeForInitializer);
if (constant != null) {
trace.record(BindingContext.COMPILE_TIME_INITIALIZER, propertyDescriptor, constant);
}
}
EvaluatePackage.recordCompileTimeValueForInitializerIfNeeded(propertyDescriptor, initializer, expectedTypeForInitializer, trace);
}
@NotNull
@@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.descriptors.impl.*;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory1;
import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -952,6 +953,10 @@ public class DescriptorResolver {
JetType type =
resolveInitializerType(scope, initializer, dataFlowInfo, trace);
EvaluatePackage.recordCompileTimeValueForInitializerIfNeeded(
variableDescriptor,
initializer, type,
trace);
return transformAnonymousTypeIfNeeded(variableDescriptor, variable, type,
trace);
}
@@ -466,8 +466,10 @@ public class CallExpressionResolver {
}
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, context.expectedType);
if (value != null) {
return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
if (Boolean.TRUE.equals(context.trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression))) {
if (value != null) {
return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
}
}
JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
@@ -125,6 +126,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetType outType = propertyDescriptor.getType();
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
dataFlowInfo = typeInfo.getDataFlowInfo();
EvaluatePackage.recordCompileTimeValueForInitializerIfNeeded(propertyDescriptor, initializer, outType, context.trace);
}
{