Refactoring of CompileTimeConstant, introduce flag to represent a constant being referenced by a variable

This commit is contained in:
Tal Man
2014-04-09 14:38:50 -04:00
parent 32a2e63ae5
commit aeb5bae556
38 changed files with 303 additions and 130 deletions
@@ -38,6 +38,7 @@ public class JavaPropertyInitializerEvaluatorImpl implements JavaPropertyInitial
evaluatedExpression, evaluatedExpression,
DescriptorUtils.isPropertyCompileTimeConstant(descriptor), DescriptorUtils.isPropertyCompileTimeConstant(descriptor),
false, false,
true,
descriptor.getType()); descriptor.getType());
} }
return null; return null;
@@ -54,7 +54,6 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
trace.record(BindingContext.COMPILE_TIME_VALUE, expression, compileTimeConstant) trace.record(BindingContext.COMPILE_TIME_VALUE, expression, compileTimeConstant)
return compileTimeConstant return compileTimeConstant
} }
return null return null
} }
@@ -70,9 +69,9 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return createStringConstant(this@ConstantExpressionEvaluator.evaluate(expression, KotlinBuiltIns.getInstance().getStringType())) return createStringConstant(this@ConstantExpressionEvaluator.evaluate(expression, KotlinBuiltIns.getInstance().getStringType()))
} }
override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, data: Nothing?) = StringValue(entry.getText(), true) override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, data: Nothing?) = StringValue(entry.getText(), true, false)
override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = StringValue(entry.getUnescapedValue(), true) override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, data: Nothing?) = StringValue(entry.getUnescapedValue(), true, false)
} }
override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? { override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -92,8 +91,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
if (result == null) return null if (result == null) return null
fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text) fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text)
return createCompileTimeConstant(result, expectedType, !isLongWithSuffix(), true, false)
return createCompileTimeConstant(result, expectedType, !isLongWithSuffix())
} }
override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? { override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -118,6 +116,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val sb = StringBuilder() val sb = StringBuilder()
var interupted = false var interupted = false
var canBeUsedInAnnotation = true var canBeUsedInAnnotation = true
var usesVariableAsConstant = false
for (entry in expression.getEntries()) { for (entry in expression.getEntries()) {
val constant = stringExpressionEvaluator.evaluate(entry) val constant = stringExpressionEvaluator.evaluate(entry)
if (constant == null) { if (constant == null) {
@@ -126,12 +125,14 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
} }
else { else {
if (!constant.canBeUsedInAnnotations()) canBeUsedInAnnotation = false if (!constant.canBeUsedInAnnotations()) canBeUsedInAnnotation = false
if (constant.usesVariableAsConstant()) usesVariableAsConstant = true
sb.append(constant.getValue()) sb.append(constant.getValue())
} }
} }
return if (!interupted) return if (!interupted)
createCompileTimeConstant(sb.toString(), expectedType, createCompileTimeConstant(sb.toString(), expectedType,
isPure = true, canBeUsedInAnnotation = canBeUsedInAnnotation) isPure = true, canBeUsedInAnnotation = canBeUsedInAnnotation,
usesVariableAsConstant = usesVariableAsConstant)
else null else null
} }
@@ -160,7 +161,8 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
JetTokens.OROR -> leftValue as Boolean || rightValue as Boolean JetTokens.OROR -> leftValue as Boolean || rightValue as Boolean
else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}") else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}")
} }
return createCompileTimeConstant(result, expectedType) val usesVariableAsConstant = leftConstant.usesVariableAsConstant() || rightConstant.usesVariableAsConstant()
return createCompileTimeConstant(result, expectedType, true, true, usesVariableAsConstant)
} }
else { else {
return evaluateCall(expression.getOperationReference(), leftExpression, expectedType) return evaluateCall(expression.getOperationReference(), leftExpression, expectedType)
@@ -182,12 +184,16 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
if (result == null) return null if (result == null) return null
val isArgumentPure = isPureConstant(argumentForReceiver.expression) val isArgumentPure = isPureConstant(argumentForReceiver.expression)
val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression)
val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression)
val isNumberConversionMethod = resultingDescriptorName in OperatorConventions.NUMBER_CONVERSIONS val isNumberConversionMethod = resultingDescriptorName in OperatorConventions.NUMBER_CONVERSIONS
return createCompileTimeConstant(result, expectedType, !isNumberConversionMethod && isArgumentPure, canBeUsedInAnnotation) return createCompileTimeConstant(result,
expectedType,
!isNumberConversionMethod && isArgumentPure,
canBeUsedInAnnotation,
usesVariableAsConstant)
} }
else if (argumentsEntrySet.size() == 1) { else if (argumentsEntrySet.size() == 1) {
val (parameter, argument) = argumentsEntrySet.first() val (parameter, argument) = argumentsEntrySet.first()
val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter) val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter)
if (argumentForParameter == null) return null if (argumentForParameter == null) return null
@@ -200,12 +206,13 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val areArgumentsPure = isPureConstant(argumentForReceiver.expression) && isPureConstant(argumentForParameter.expression) val areArgumentsPure = isPureConstant(argumentForReceiver.expression) && isPureConstant(argumentForParameter.expression)
val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression) val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression)
val c = EvaluatorContext(canBeUsedInAnnotation, areArgumentsPure) val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression)
val c = EvaluatorContext(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant)
return when(resultingDescriptorName) { return when(resultingDescriptorName) {
OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, c) OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, c)
OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, c) OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, c)
else -> { else -> {
createCompileTimeConstant(result, expectedType, areArgumentsPure, canBeUsedInAnnotation) createCompileTimeConstant(result, expectedType, areArgumentsPure, canBeUsedInAnnotation, usesVariableAsConstant)
} }
} }
} }
@@ -213,7 +220,10 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return null return null
} }
private fun usesVariableAsConstant(expression: JetExpression) = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)?.usesVariableAsConstant() ?: false
private fun canBeUsedInAnnotation(expression: JetExpression) = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)?.canBeUsedInAnnotations() ?: false private fun canBeUsedInAnnotation(expression: JetExpression) = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)?.canBeUsedInAnnotations() ?: false
private fun isPureConstant(expression: JetExpression): Boolean { private fun isPureConstant(expression: JetExpression): Boolean {
val compileTimeConstant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression) val compileTimeConstant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)
if (compileTimeConstant is IntegerValueConstant) { if (compileTimeConstant is IntegerValueConstant) {
@@ -287,7 +297,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, expectedType: JetType?): CompileTimeConstant<*>? { override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, expectedType: JetType?): CompileTimeConstant<*>? {
val enumDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, expression); val enumDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, expression);
if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) { if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) {
return EnumValue(enumDescriptor as ClassDescriptor); return EnumValue(enumDescriptor as ClassDescriptor, false);
} }
val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression) val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression)
@@ -303,7 +313,8 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
else else
compileTimeConstant.getValue() compileTimeConstant.getValue()
return createCompileTimeConstant(value, expectedType, isPure = false, return createCompileTimeConstant(value, expectedType, isPure = false,
canBeUsedInAnnotation = DescriptorUtils.isPropertyCompileTimeConstant(callableDescriptor)) canBeUsedInAnnotation = DescriptorUtils.isPropertyCompileTimeConstant(callableDescriptor),
usesVariableAsConstant = true)
} }
} }
return null return null
@@ -341,7 +352,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val varargType = resultingDescriptor.getValueParameters().first?.getVarargElementType()!! val varargType = resultingDescriptor.getValueParameters().first?.getVarargElementType()!!
val arguments = call.getValueArguments().values().flatMap { resolveArguments(it.getArguments(), varargType) } val arguments = call.getValueArguments().values().flatMap { resolveArguments(it.getArguments(), varargType) }
return ArrayValue(arguments, resultingDescriptor.getReturnType()!!, true) return ArrayValue(arguments, resultingDescriptor.getReturnType()!!, true, arguments.any() { it.usesVariableAsConstant() })
} }
// Ann() // Ann()
@@ -402,7 +413,6 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val argumentExpression = arguments.first().getArgumentExpression() val argumentExpression = arguments.first().getArgumentExpression()
if (argumentExpression == null) return null if (argumentExpression == null) return null
return createOperationArgument(argumentExpression, parameter.getType(), argumentCompileTimeType) return createOperationArgument(argumentExpression, parameter.getType(), argumentCompileTimeType)
} }
@@ -421,8 +431,12 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return OperationArgument(evaluationResult, compileTimeType, expression) return OperationArgument(evaluationResult, compileTimeType, expression)
} }
fun createCompileTimeConstant(value: Any?, expectedType: JetType?, isPure: Boolean = true, canBeUsedInAnnotation: Boolean = true): CompileTimeConstant<*>? { fun createCompileTimeConstant(value: Any?,
val c = EvaluatorContext(canBeUsedInAnnotation, isPure) expectedType: JetType?,
isPure: Boolean = true,
canBeUsedInAnnotation: Boolean = true,
usesVariableAsConstant: Boolean = false): CompileTimeConstant<*>? {
val c = EvaluatorContext(canBeUsedInAnnotation, isPure, usesVariableAsConstant)
return createCompileTimeConstant(value, c, if (isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null) return createCompileTimeConstant(value, c, if (isPure) expectedType ?: TypeUtils.NO_EXPECTED_TYPE else null)
} }
} }
@@ -490,11 +504,11 @@ private fun createCompileTimeConstantForEquals(result: Any?, operationReference:
assert(operationReference is JetSimpleNameExpression, "This method should be called only for equals operations") assert(operationReference is JetSimpleNameExpression, "This method should be called only for equals operations")
val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType() val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType()
return when (operationToken) { return when (operationToken) {
JetTokens.EQEQ -> BooleanValue(result, c.canBeUsedInAnnotation) JetTokens.EQEQ -> BooleanValue(result, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.EXCLEQ -> BooleanValue(!result, c.canBeUsedInAnnotation) JetTokens.EXCLEQ -> BooleanValue(!result, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.IDENTIFIER -> { JetTokens.IDENTIFIER -> {
assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.EQUALS, "This method should be called only for equals operations") assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.EQUALS, "This method should be called only for equals operations")
return BooleanValue(result, c.canBeUsedInAnnotation) return BooleanValue(result, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
} }
else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.getText()}") else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.getText()}")
} }
@@ -507,13 +521,13 @@ private fun createCompileTimeConstantForCompareTo(result: Any?, operationReferen
assert(operationReference is JetSimpleNameExpression, "This method should be called only for compareTo operations") assert(operationReference is JetSimpleNameExpression, "This method should be called only for compareTo operations")
val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType() val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType()
return when (operationToken) { return when (operationToken) {
JetTokens.LT -> BooleanValue(result < 0, c.canBeUsedInAnnotation) JetTokens.LT -> BooleanValue(result < 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.LTEQ -> BooleanValue(result <= 0, c.canBeUsedInAnnotation) JetTokens.LTEQ -> BooleanValue(result <= 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.GT -> BooleanValue(result > 0, c.canBeUsedInAnnotation) JetTokens.GT -> BooleanValue(result > 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.GTEQ -> BooleanValue(result >= 0, c.canBeUsedInAnnotation) JetTokens.GTEQ -> BooleanValue(result >= 0, c.canBeUsedInAnnotation, c.usesVariableAsConstant)
JetTokens.IDENTIFIER -> { JetTokens.IDENTIFIER -> {
assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.COMPARE_TO, "This method should be called only for compareTo operations") assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.COMPARE_TO, "This method should be called only for compareTo operations")
return IntValue(result, c.canBeUsedInAnnotation, c.isPure) return IntValue(result, c.canBeUsedInAnnotation, c.isPure, c.usesVariableAsConstant)
} }
else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken") else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken")
} }
@@ -523,19 +537,19 @@ private fun createCompileTimeConstantForCompareTo(result: Any?, operationReferen
private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? { private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? {
return when (value) { return when (value) {
is IntegerValueTypeConstant -> StringValue(value.getValue(TypeUtils.NO_EXPECTED_TYPE).toString(), value.canBeUsedInAnnotations()) is IntegerValueTypeConstant -> StringValue(value.getValue(TypeUtils.NO_EXPECTED_TYPE).toString(), value.canBeUsedInAnnotations(), value.usesVariableAsConstant())
is StringValue -> value is StringValue -> value
is IntValue, is ByteValue, is ShortValue, is LongValue, is IntValue, is ByteValue, is ShortValue, is LongValue,
is CharValue, is CharValue,
is DoubleValue, is FloatValue, is DoubleValue, is FloatValue,
is BooleanValue, is BooleanValue,
is NullValue -> StringValue(value.getValue().toString(), value.canBeUsedInAnnotations()) is NullValue -> StringValue(value.getValue().toString(), value.canBeUsedInAnnotations(), value.usesVariableAsConstant())
else -> null else -> null
} }
} }
private fun createCompileTimeConstant(value: Any?, c: EvaluatorContext, expectedType: JetType? = null): CompileTimeConstant<*>? { private fun createCompileTimeConstant(value: Any?, c: EvaluatorContext, expectedType: JetType? = null): CompileTimeConstant<*>? {
return createCompileTimeConstant(value, c.canBeUsedInAnnotation, c.isPure, expectedType) return createCompileTimeConstant(value, c.canBeUsedInAnnotation, c.isPure, c.usesVariableAsConstant, expectedType)
} }
fun isIntegerType(value: Any?) = value is Byte || value is Short || value is Int || value is Long fun isIntegerType(value: Any?) = value is Byte || value is Short || value is Int || value is Long
@@ -567,7 +581,7 @@ private fun getCompileTimeType(c: JetType): CompileTimeType<out Any>? {
} }
} }
private class EvaluatorContext(val canBeUsedInAnnotation: Boolean, val isPure: Boolean) private class EvaluatorContext(val canBeUsedInAnnotation: Boolean, val isPure: Boolean, val usesVariableAsConstant: Boolean = false)
private class CompileTimeType<T> private class CompileTimeType<T>
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import kotlin.Function1;
import kotlin.KotlinPackage; import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -282,11 +283,20 @@ public class AnnotationResolver {
trace); trace);
if (argumentsAsVararg) { if (argumentsAsVararg) {
boolean usesVariableAsConstant = KotlinPackage.any(constants, new Function1<CompileTimeConstant<?>, Boolean>() {
@Override
public Boolean invoke(CompileTimeConstant<?> constant) {
return constant.usesVariableAsConstant();
}
});
JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType); JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
if (arrayType == null) { if (arrayType == null) {
arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType); arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
} }
return new ArrayValue(constants, arrayType, true);
return new ArrayValue(constants, arrayType, true, usesVariableAsConstant);
} }
else { else {
// we should actually get only one element, but just in case of getting many, we take the last one // we should actually get only one element, but just in case of getting many, we take the last one
@@ -18,13 +18,11 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.Annotated; import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator; import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.JetConstantExpression;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.psi.JetTypeReference;
@@ -129,12 +127,10 @@ public class CompileTimeConstantUtils {
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@Nullable Boolean expectedValue @Nullable Boolean expectedValue
) { ) {
if (!(expression instanceof JetConstantExpression) || expression.getNode().getElementType() != JetNodeTypes.BOOLEAN_CONSTANT) { if (expression == null) return false;
return false;
}
CompileTimeConstant<?> compileTimeConstant = CompileTimeConstant<?> compileTimeConstant =
ConstantExpressionEvaluator.object$.evaluate(expression, trace, KotlinBuiltIns.getInstance().getBooleanType()); ConstantExpressionEvaluator.object$.evaluate(expression, trace, KotlinBuiltIns.getInstance().getBooleanType());
if (!(compileTimeConstant instanceof BooleanValue)) return false; if (!(compileTimeConstant instanceof BooleanValue) || compileTimeConstant.usesVariableAsConstant()) return false;
Boolean value = ((BooleanValue) compileTimeConstant).getValue(); Boolean value = ((BooleanValue) compileTimeConstant).getValue();
return expectedValue == null || expectedValue.equals(value); return expectedValue == null || expectedValue.equals(value);
@@ -1,25 +1,25 @@
== main == == main ==
fun main() { fun main() {
while(1 > 0) { while(0 > 1) {
2 2
} }
} }
--------------------- ---------------------
L0: L0:
1 <START> 1 <START>
2 mark({ while(1 > 0) { 2 } }) 2 mark({ while(0 > 1) { 2 } })
mark(while(1 > 0) { 2 }) mark(while(0 > 1) { 2 })
L2 [loop entry point]: L2 [loop entry point]:
L5 [condition entry point]: L5 [condition entry point]:
mark(1 > 0) PREV:[mark(while(1 > 0) { 2 }), jmp(L2 [loop entry point])] mark(0 > 1) PREV:[mark(while(0 > 1) { 2 }), jmp(L2 [loop entry point])]
r(1)
r(0) r(0)
r(1)
call(>, compareTo) call(>, compareTo)
jf(L3 [loop exit point]) NEXT:[read (Unit), mark({ 2 })] jf(L3 [loop exit point]) NEXT:[read (Unit), mark({ 2 })]
L4 [body entry point]: L4 [body entry point]:
3 mark({ 2 }) 3 mark({ 2 })
r(2) r(2)
2 jmp(L2 [loop entry point]) NEXT:[mark(1 > 0)] 2 jmp(L2 [loop entry point]) NEXT:[mark(0 > 1)]
L3 [loop exit point]: L3 [loop exit point]:
read (Unit) PREV:[jf(L3 [loop exit point])] read (Unit) PREV:[jf(L3 [loop exit point])]
L1: L1:
@@ -32,21 +32,21 @@ sink:
== dowhile == == dowhile ==
fun dowhile() { fun dowhile() {
do {return} do {return}
while(1 > 0) while(0 > 1)
} }
--------------------- ---------------------
L0: L0:
1 <START> 1 <START>
2 mark({ do {return} while(1 > 0) }) 2 mark({ do {return} while(0 > 1) })
3 mark(do {return} while(1 > 0)) 3 mark(do {return} while(0 > 1))
L2 [loop entry point]: L2 [loop entry point]:
L4 [body entry point]: L4 [body entry point]:
mark({return}) mark({return})
ret L1 NEXT:[<END>] ret L1 NEXT:[<END>]
L5 [condition entry point]: L5 [condition entry point]:
- mark(1 > 0) PREV:[] - mark(0 > 1) PREV:[]
- r(1) PREV:[]
- r(0) PREV:[] - r(0) PREV:[]
- r(1) PREV:[]
- call(>, compareTo) PREV:[] - call(>, compareTo) PREV:[]
- jt(L2 [loop entry point]) NEXT:[read (Unit), mark({return})] PREV:[] - jt(L2 [loop entry point]) NEXT:[read (Unit), mark({return})] PREV:[]
L3 [loop exit point]: L3 [loop exit point]:
@@ -1,10 +1,10 @@
fun main() { fun main() {
while(1 > 0) { while(0 > 1) {
2 2
} }
} }
fun dowhile() { fun dowhile() {
do {return} do {return}
while(1 > 0) while(0 > 1)
} }
@@ -1,9 +1,9 @@
fun test() { fun test() {
[ann] [ann]
while (1 < 2) {} while (2 < 1) {}
[ann] [ann]
do {} while (1 < 2) do {} while (2 < 1)
[ann] [ann]
for (i in 1..2) {} for (i in 1..2) {}
@@ -0,0 +1,12 @@
fun test() {
[ann]
while (2 > 1) {}
[ann]
<!UNREACHABLE_CODE!>do {} while (2 > 1)<!>
[ann]
<!UNREACHABLE_CODE!>for (i in 1..2) {}<!>
}
annotation class ann
@@ -0,0 +1,11 @@
package test
val x = 1
val y = "a"
// val prop1: true
val prop1 = x
// val prop2: true
val prop2 = y
@@ -0,0 +1,16 @@
package test
enum class MyEnum { A;B }
fun foo(): Boolean = true
val x = 1
// val prop1: null
val prop1 = MyEnum.A
// val prop2: null
val prop2 = foo()
// val prop3: true
val prop3 = "$x"
@@ -0,0 +1,29 @@
package test
val x = 1
val y = true
// val prop1: false
val prop1 = 1 > 2
// val prop2: false
val prop2 = 2 + 3
// val prop3: true
val prop3 = 2 + x
// val prop4: true
val prop4 = x < 2
// val prop5: true
val prop5 = y && true
// val prop6: false
val prop6 = true && false || 2 > 1
// val prop7: true
val prop7 = x == 1
// val prop8: true
val prop8 = 1 / x
@@ -0,0 +1,23 @@
package test
// val prop1: false
val prop1 = 1
// val prop2: false
val prop2 = "hello"
// val prop3: false
val prop3 = true
// val prop4: false
val prop4 = false
// val prop5: false
val prop5 = -7453
// val prop6: false
val prop6 = 3.56
// val prop7: false
val prop7 = 5464564L
@@ -616,6 +616,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/annotations/onLoops.kt"); doTest("compiler/testData/diagnostics/tests/annotations/onLoops.kt");
} }
@TestMetadata("onLoopsUnreachable.kt")
public void testOnLoopsUnreachable() throws Exception {
doTest("compiler/testData/diagnostics/tests/annotations/onLoopsUnreachable.kt");
}
@TestMetadata("onMultiDeclaration.kt") @TestMetadata("onMultiDeclaration.kt")
public void testOnMultiDeclaration() throws Exception { public void testOnMultiDeclaration() throws Exception {
doTest("compiler/testData/diagnostics/tests/annotations/onMultiDeclaration.kt"); doTest("compiler/testData/diagnostics/tests/annotations/onMultiDeclaration.kt");
@@ -20,20 +20,18 @@ import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.resolve.annotation.AbstractAnnotationDescriptorResolveTest import org.jetbrains.jet.resolve.annotation.AbstractAnnotationDescriptorResolveTest
import java.io.File import java.io.File
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.jet.lang.resolve.BindingContextUtils
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.InTextDirectivesUtils import org.jetbrains.jet.InTextDirectivesUtils
import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import java.util.regex.Pattern import java.util.regex.Pattern
import org.intellij.lang.annotations.RegExp
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.jet.JetTestUtils import org.jetbrains.jet.JetTestUtils
import org.jetbrains.jet.util.slicedmap.WritableSlice
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant
import org.jetbrains.jet.lang.resolve.constants.StringValue import org.jetbrains.jet.lang.resolve.constants.StringValue
import org.jetbrains.jet.lang.descriptors.VariableDescriptor import org.jetbrains.jet.lang.descriptors.VariableDescriptor
import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant
import java.util.HashMap
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
import org.jetbrains.jet.lang.types.TypeUtils
abstract class AbstractEvaluateExpressionTest : AbstractAnnotationDescriptorResolveTest() { abstract class AbstractEvaluateExpressionTest : AbstractAnnotationDescriptorResolveTest() {
@@ -63,6 +61,19 @@ abstract class AbstractEvaluateExpressionTest : AbstractAnnotationDescriptorReso
} }
} }
// Test directives should look like [// val testedPropertyName: expectedValue]
fun doUsesVariableAsConstantTest(path: String) {
doTest(path) {
property, context ->
val compileTimeConstant = property.getCompileTimeInitializer()
if (compileTimeConstant == null) {
"null"
} else {
compileTimeConstant.usesVariableAsConstant().toString()
}
}
}
private fun doTest(path: String, getValueToTest: (VariableDescriptor, BindingContext) -> String) { private fun doTest(path: String, getValueToTest: (VariableDescriptor, BindingContext) -> String) {
val myFile = File(path) val myFile = File(path)
val fileText = FileUtil.loadFile(myFile, true) val fileText = FileUtil.loadFile(myFile, true)
@@ -30,7 +30,7 @@ import org.jetbrains.jet.evaluate.AbstractEvaluateExpressionTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all") @SuppressWarnings("all")
@InnerTestClasses({EvaluateExpressionTestGenerated.Constant.class, EvaluateExpressionTestGenerated.IsPure.class}) @InnerTestClasses({EvaluateExpressionTestGenerated.Constant.class, EvaluateExpressionTestGenerated.IsPure.class, EvaluateExpressionTestGenerated.UsesVariableAsConstant.class})
public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionTest { public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionTest {
@TestMetadata("compiler/testData/evaluate/constant") @TestMetadata("compiler/testData/evaluate/constant")
public static class Constant extends AbstractEvaluateExpressionTest { public static class Constant extends AbstractEvaluateExpressionTest {
@@ -168,10 +168,39 @@ public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionT
} }
@TestMetadata("compiler/testData/evaluate/usesVariableAsConstant")
public static class UsesVariableAsConstant extends AbstractEvaluateExpressionTest {
public void testAllFilesPresentInUsesVariableAsConstant() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/evaluate/usesVariableAsConstant"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("binaryTypes.kt")
public void testBinaryTypes() throws Exception {
doUsesVariableAsConstantTest("compiler/testData/evaluate/usesVariableAsConstant/binaryTypes.kt");
}
@TestMetadata("NamedConstants.kt")
public void testNamedConstants() throws Exception {
doUsesVariableAsConstantTest("compiler/testData/evaluate/usesVariableAsConstant/NamedConstants.kt");
}
@TestMetadata("OtherTypes.kt")
public void testOtherTypes() throws Exception {
doUsesVariableAsConstantTest("compiler/testData/evaluate/usesVariableAsConstant/OtherTypes.kt");
}
@TestMetadata("simpleTypes.kt")
public void testSimpleTypes() throws Exception {
doUsesVariableAsConstantTest("compiler/testData/evaluate/usesVariableAsConstant/simpleTypes.kt");
}
}
public static Test suite() { public static Test suite() {
TestSuite suite = new TestSuite("EvaluateExpressionTestGenerated"); TestSuite suite = new TestSuite("EvaluateExpressionTestGenerated");
suite.addTestSuite(Constant.class); suite.addTestSuite(Constant.class);
suite.addTestSuite(IsPure.class); suite.addTestSuite(IsPure.class);
suite.addTestSuite(UsesVariableAsConstant.class);
return suite; return suite;
} }
} }
@@ -108,7 +108,7 @@ class LazyJavaAnnotationDescriptor(
private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): CompileTimeConstant<*>? { private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): CompileTimeConstant<*>? {
return when (argument) { return when (argument) {
is JavaLiteralAnnotationArgument -> createCompileTimeConstant(argument.getValue(), true, false, null) is JavaLiteralAnnotationArgument -> createCompileTimeConstant(argument.getValue(), true, false, false, null)
is JavaReferenceAnnotationArgument -> resolveFromReference(argument.resolve()) is JavaReferenceAnnotationArgument -> resolveFromReference(argument.resolve())
is JavaArrayAnnotationArgument -> resolveFromArray(argument.getName() ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements()) is JavaArrayAnnotationArgument -> resolveFromArray(argument.getName() ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements())
is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation()) is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation())
@@ -137,7 +137,7 @@ class LazyJavaAnnotationDescriptor(
val values = elements.map { val values = elements.map {
argument -> resolveAnnotationArgument(argument) ?: NullValue.NULL argument -> resolveAnnotationArgument(argument) ?: NullValue.NULL
} }
return ArrayValue(values, valueParameter.getType(), true) return ArrayValue(values, valueParameter.getType(), true, values.any { it.usesVariableAsConstant() })
} }
private fun resolveFromReference(element: JavaElement?): CompileTimeConstant<*>? { private fun resolveFromReference(element: JavaElement?): CompileTimeConstant<*>? {
@@ -154,7 +154,7 @@ class LazyJavaAnnotationDescriptor(
val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(element.getName()) val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(element.getName())
if (classifier !is ClassDescriptor) return null if (classifier !is ClassDescriptor) return null
return EnumValue(classifier) return EnumValue(classifier, false)
} }
private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? { private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? {
@@ -126,7 +126,7 @@ public class AnnotationDescriptorDeserializer extends BaseDescriptorDeserializer
@Override @Override
public void visit(@Nullable Name name, @Nullable Object value) { public void visit(@Nullable Name name, @Nullable Object value) {
if (name != null) { if (name != null) {
CompileTimeConstant<?> argument = ConstantsPackage.createCompileTimeConstant(value, true, false, null); CompileTimeConstant<?> argument = ConstantsPackage.createCompileTimeConstant(value, true, false, false, null);
setArgumentValueByName(name, argument != null ? argument : ErrorValue.create("Unsupported annotation argument: " + name)); setArgumentValueByName(name, argument != null ? argument : ErrorValue.create("Unsupported annotation argument: " + name));
} }
} }
@@ -149,7 +149,7 @@ public class AnnotationDescriptorDeserializer extends BaseDescriptorDeserializer
if (enumClass.getKind() == ClassKind.ENUM_CLASS) { if (enumClass.getKind() == ClassKind.ENUM_CLASS) {
ClassifierDescriptor classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name); ClassifierDescriptor classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name);
if (classifier instanceof ClassDescriptor) { if (classifier instanceof ClassDescriptor) {
return new EnumValue((ClassDescriptor) classifier); return new EnumValue((ClassDescriptor) classifier, false);
} }
} }
return ErrorValue.create("Unresolved enum entry: " + enumClassName.getInternalName() + "." + name); return ErrorValue.create("Unresolved enum entry: " + enumClassName.getInternalName() + "." + name);
@@ -89,7 +89,7 @@ public class DescriptorDeserializersStorage {
MemberSignature signature = MemberSignature.fromFieldNameAndDesc(name, desc); MemberSignature signature = MemberSignature.fromFieldNameAndDesc(name, desc);
if (initializer != null) { if (initializer != null) {
propertyConstants.put(signature, ConstantsPackage.createCompileTimeConstant( propertyConstants.put(signature, ConstantsPackage.createCompileTimeConstant(
initializer, /* canBeUsedInAnnotation */ true, /* isPureIntConstant */ true, /* expectedType */ null)); initializer, /* canBeUsedInAnnotation */ true, /* isPureIntConstant */ true, /* usesVariableAsConstant */ true, /* expectedType */ null));
} }
return new MemberAnnotationVisitor(signature); return new MemberAnnotationVisitor(signature);
} }
@@ -25,7 +25,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class AnnotationValue extends CompileTimeConstant<AnnotationDescriptor> { public class AnnotationValue extends CompileTimeConstant<AnnotationDescriptor> {
public AnnotationValue(@NotNull AnnotationDescriptor value) { public AnnotationValue(@NotNull AnnotationDescriptor value) {
super(value, true); super(value, true, false, false);
} }
@NotNull @NotNull
@@ -27,8 +27,11 @@ public class ArrayValue extends CompileTimeConstant<List<CompileTimeConstant<?>>
private final JetType type; private final JetType type;
public ArrayValue(@NotNull List<CompileTimeConstant<?>> value, @NotNull JetType type, boolean canBeUsedInAnnotations) { public ArrayValue(@NotNull List<CompileTimeConstant<?>> value,
super(value, canBeUsedInAnnotations); @NotNull JetType type,
boolean canBeUsedInAnnotations,
boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, false, usesVariableAsConstant);
this.type = type; this.type = type;
} }
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.JetType;
public class BooleanValue extends CompileTimeConstant<Boolean> { public class BooleanValue extends CompileTimeConstant<Boolean> {
public BooleanValue(boolean value, boolean canBeUseInAnnotation) { public BooleanValue(boolean value, boolean canBeUseInAnnotation, boolean usesVariableAsConstant) {
super(value, canBeUseInAnnotation); super(value, canBeUseInAnnotation, false, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class ByteValue extends IntegerValueConstant<Byte> { public class ByteValue extends IntegerValueConstant<Byte> {
public ByteValue(byte value, boolean canBeUsedInAnnotations, boolean pure) { public ByteValue(byte value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVaraiableAsConstant) {
super(value, canBeUsedInAnnotations, pure); super(value, canBeUsedInAnnotations, pure, usesVaraiableAsConstant);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.JetType;
public class CharValue extends IntegerValueConstant<Character> { public class CharValue extends IntegerValueConstant<Character> {
public CharValue(char value, boolean canBeUsedInAnnotations, boolean pure) { public CharValue(char value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, pure); super(value, canBeUsedInAnnotations, pure, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -24,15 +24,38 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public abstract class CompileTimeConstant<T> { public abstract class CompileTimeConstant<T> {
protected final T value; protected final T value;
private final boolean canBeUsedInAnnotations; private final int flags;
protected CompileTimeConstant(T value, boolean canBeUsedInAnnotations) { /*
* if is pure is false then constant type cannot be changed
* ex1. val a: Long = 1.toInt() (TYPE_MISMATCH error, 1.toInt() isn't pure)
* ex2. val b: Int = a (TYPE_MISMATCH error, a isn't pure)
*
*/
private static final int IS_PURE_MASK = 1;
private static final int CAN_BE_USED_IN_ANNOTATIONS_MASK = 1 << 1;
private static final int USES_VARIABLE_AS_CONSTANT_MASK = 1 << 2;
protected CompileTimeConstant(T value,
boolean canBeUsedInAnnotations,
boolean isPure,
boolean usesVariableAsConstant) {
this.value = value; this.value = value;
this.canBeUsedInAnnotations = canBeUsedInAnnotations; flags = (isPure ? IS_PURE_MASK : 0) |
(canBeUsedInAnnotations ? CAN_BE_USED_IN_ANNOTATIONS_MASK : 0) |
(usesVariableAsConstant ? USES_VARIABLE_AS_CONSTANT_MASK : 0);
} }
public boolean canBeUsedInAnnotations() { public boolean canBeUsedInAnnotations() {
return canBeUsedInAnnotations; return (flags & CAN_BE_USED_IN_ANNOTATIONS_MASK) != 0;
}
public boolean isPure() {
return (flags & IS_PURE_MASK) != 0;
}
public boolean usesVariableAsConstant() {
return (flags & USES_VARIABLE_AS_CONSTANT_MASK) != 0;
} }
@Nullable @Nullable
@@ -24,23 +24,24 @@ public fun createCompileTimeConstant(
value: Any?, value: Any?,
canBeUsedInAnnotation: Boolean, canBeUsedInAnnotation: Boolean,
isPureIntConstant: Boolean, isPureIntConstant: Boolean,
usesVariableAsConstant: Boolean = false,
expectedType: JetType? = null expectedType: JetType? = null
): CompileTimeConstant<*>? { ): CompileTimeConstant<*>? {
if (expectedType == null) { if (expectedType == null) {
when(value) { when(value) {
is Byte -> return ByteValue(value, canBeUsedInAnnotation, isPureIntConstant) is Byte -> return ByteValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
is Short -> return ShortValue(value, canBeUsedInAnnotation, isPureIntConstant) is Short -> return ShortValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
is Int -> return IntValue(value, canBeUsedInAnnotation, isPureIntConstant) is Int -> return IntValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
is Long -> return LongValue(value, canBeUsedInAnnotation, isPureIntConstant) is Long -> return LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
} }
} }
return when(value) { return when(value) {
is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), canBeUsedInAnnotation, isPureIntConstant, expectedType) is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant, expectedType)
is Char -> CharValue(value, canBeUsedInAnnotation, isPureIntConstant) is Char -> CharValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
is Float -> FloatValue(value, canBeUsedInAnnotation) is Float -> FloatValue(value, canBeUsedInAnnotation, usesVariableAsConstant)
is Double -> DoubleValue(value, canBeUsedInAnnotation) is Double -> DoubleValue(value, canBeUsedInAnnotation, usesVariableAsConstant)
is Boolean -> BooleanValue(value, canBeUsedInAnnotation) is Boolean -> BooleanValue(value, canBeUsedInAnnotation, usesVariableAsConstant)
is String -> StringValue(value, canBeUsedInAnnotation) is String -> StringValue(value, canBeUsedInAnnotation, usesVariableAsConstant)
null -> NullValue.NULL null -> NullValue.NULL
else -> null else -> null
} }
@@ -50,30 +51,31 @@ private fun getIntegerValue(
value: Long, value: Long,
canBeUsedInAnnotation: Boolean, canBeUsedInAnnotation: Boolean,
isPureIntConstant: Boolean, isPureIntConstant: Boolean,
usesVariableAsConstant: Boolean,
expectedType: JetType expectedType: JetType
): CompileTimeConstant<*>? { ): CompileTimeConstant<*>? {
fun defaultIntegerValue(value: Long) = when (value) { fun defaultIntegerValue(value: Long) = when (value) {
value.toInt().toLong() -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant) value.toInt().toLong() -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
else -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant) else -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
} }
if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) { if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) {
return IntegerValueTypeConstant(value, canBeUsedInAnnotation) return IntegerValueTypeConstant(value, canBeUsedInAnnotation, usesVariableAsConstant)
} }
val builtIns = KotlinBuiltIns.getInstance() val builtIns = KotlinBuiltIns.getInstance()
return when (TypeUtils.makeNotNullable(expectedType)) { return when (TypeUtils.makeNotNullable(expectedType)) {
builtIns.getLongType() -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant) builtIns.getLongType() -> LongValue(value, canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
builtIns.getShortType() -> when (value) { builtIns.getShortType() -> when (value) {
value.toShort().toLong() -> ShortValue(value.toShort(), canBeUsedInAnnotation, isPureIntConstant) value.toShort().toLong() -> ShortValue(value.toShort(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
else -> defaultIntegerValue(value) else -> defaultIntegerValue(value)
} }
builtIns.getByteType() -> when (value) { builtIns.getByteType() -> when (value) {
value.toByte().toLong() -> ByteValue(value.toByte(), canBeUsedInAnnotation, isPureIntConstant) value.toByte().toLong() -> ByteValue(value.toByte(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
else -> defaultIntegerValue(value) else -> defaultIntegerValue(value)
} }
builtIns.getCharType() -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant) builtIns.getCharType() -> IntValue(value.toInt(), canBeUsedInAnnotation, isPureIntConstant, usesVariableAsConstant)
else -> defaultIntegerValue(value) else -> defaultIntegerValue(value)
} }
} }
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.JetType;
public class DoubleValue extends CompileTimeConstant<Double> { public class DoubleValue extends CompileTimeConstant<Double> {
public DoubleValue(double value, boolean canBeUsedInAnnotations) { public DoubleValue(double value, boolean canBeUsedInAnnotations, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations); super(value, canBeUsedInAnnotations, false, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -24,8 +24,8 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class EnumValue extends CompileTimeConstant<ClassDescriptor> { public class EnumValue extends CompileTimeConstant<ClassDescriptor> {
public EnumValue(@NotNull ClassDescriptor value) { public EnumValue(@NotNull ClassDescriptor value, boolean usesVariableAsConstant) {
super(value, true); super(value, true, false, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -25,7 +25,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public abstract class ErrorValue extends CompileTimeConstant<Void> { public abstract class ErrorValue extends CompileTimeConstant<Void> {
public ErrorValue() { public ErrorValue() {
super(null, true); super(null, true, false, false);
} }
@Override @Override
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.JetType;
public class FloatValue extends CompileTimeConstant<Float> { public class FloatValue extends CompileTimeConstant<Float> {
public FloatValue(float value, boolean canBeUsedInAnnotations) { public FloatValue(float value, boolean canBeUsedInAnnotations, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations); super(value, canBeUsedInAnnotations, false, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class IntValue extends IntegerValueConstant<Integer> { public class IntValue extends IntegerValueConstant<Integer> {
public IntValue(int value, boolean canBeUsedInAnnotations, boolean pure) { public IntValue(int value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, pure); super(value, canBeUsedInAnnotations, pure, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -18,19 +18,7 @@ package org.jetbrains.jet.lang.resolve.constants;
public abstract class IntegerValueConstant<T> extends CompileTimeConstant<T> { public abstract class IntegerValueConstant<T> extends CompileTimeConstant<T> {
/* protected IntegerValueConstant(T value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVaraiableAsConstant) {
* if false then constant type cannot be changed super(value, canBeUsedInAnnotations, pure, usesVaraiableAsConstant);
* ex1. val a: Long = 1.toInt() (TYPE_MISMATCH error, 1.toInt() isn't pure)
* ex2. val b: Int = a (TYPE_MISMATCH error, a isn't pure)
* */
private final boolean isPure;
protected IntegerValueConstant(T value, boolean canBeUsedInAnnotations, boolean pure) {
super(value, canBeUsedInAnnotations);
isPure = pure;
}
public boolean isPure() {
return isPure;
} }
} }
@@ -19,10 +19,9 @@ package org.jetbrains.jet.lang.resolve.constants;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import java.util.Collections; import java.util.Collections;
@@ -30,8 +29,8 @@ public class IntegerValueTypeConstant extends IntegerValueConstant<Number> {
private final IntegerValueTypeConstructor typeConstructor; private final IntegerValueTypeConstructor typeConstructor;
public IntegerValueTypeConstant(@NotNull Number value, boolean canBeUsedInAnnotations) { public IntegerValueTypeConstant(@NotNull Number value, boolean canBeUsedInAnnotations, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, true); super(value, canBeUsedInAnnotations, true, usesVariableAsConstant);
this.typeConstructor = new IntegerValueTypeConstructor(value.longValue()); this.typeConstructor = new IntegerValueTypeConstructor(value.longValue());
} }
@@ -24,7 +24,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class JavaClassValue extends CompileTimeConstant<JetType> { public class JavaClassValue extends CompileTimeConstant<JetType> {
public JavaClassValue(@NotNull JetType value) { public JavaClassValue(@NotNull JetType value) {
super(value, true); super(value, true, false, false);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class LongValue extends IntegerValueConstant<Long> { public class LongValue extends IntegerValueConstant<Long> {
public LongValue(long value, boolean canBeUsedInAnnotations, boolean pure) { public LongValue(long value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, pure); super(value, canBeUsedInAnnotations, pure, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -26,7 +26,7 @@ public class NullValue extends CompileTimeConstant<Void> {
public static final NullValue NULL = new NullValue(); public static final NullValue NULL = new NullValue();
private NullValue() { private NullValue() {
super(null, false); super(null, false, false, false);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class ShortValue extends IntegerValueConstant<Short> { public class ShortValue extends IntegerValueConstant<Short> {
public ShortValue(short value, boolean canBeUsedInAnnotations, boolean pure) { public ShortValue(short value, boolean canBeUsedInAnnotations, boolean pure, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations, pure); super(value, canBeUsedInAnnotations, pure, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.types.JetType;
public class StringValue extends CompileTimeConstant<String> { public class StringValue extends CompileTimeConstant<String> {
public StringValue(String value, boolean canBeUsedInAnnotations) { public StringValue(String value, boolean canBeUsedInAnnotations, boolean usesVariableAsConstant) {
super(value, canBeUsedInAnnotations); super(value, canBeUsedInAnnotations, false, usesVariableAsConstant);
} }
@NotNull @NotNull
@@ -242,6 +242,7 @@ fun main(args: Array<String>) {
testClass(javaClass<AbstractEvaluateExpressionTest>()) { testClass(javaClass<AbstractEvaluateExpressionTest>()) {
model("evaluate/constant", testMethod = "doConstantTest") model("evaluate/constant", testMethod = "doConstantTest")
model("evaluate/isPure", testMethod = "doIsPureTest") model("evaluate/isPure", testMethod = "doIsPureTest")
model("evaluate/usesVariableAsConstant", testMethod = "doUsesVariableAsConstantTest")
} }
} }