diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt index 0ff8066bc61..e9041f4a9e0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index fff8e64b7e6..4b386653dcf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -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 { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java index 8eeb65131de..58707355f80 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java @@ -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; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 41f12bda04c..1200e3ec16f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -77,7 +77,7 @@ public interface BindingContext { WritableSlice IS_PURE_CONSTANT_EXPRESSION = Slices.createSimpleSlice(); WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice(); - WritableSlice> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice(); + WritableSlice> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice(); WritableSlice TYPE = Slices.createSimpleSlice(); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 24e1a8b90db..06fa6e3fe73 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index f09a9fb7ad3..3443ba9b407 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index 27dd9129146..f18cf0ec1ef 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -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()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 532be83ce43..a8a50ca6664 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -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); } { diff --git a/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt b/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt index 91ab993a6a8..34762a01159 100644 --- a/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt +++ b/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt @@ -1,3 +1,5 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + val intMaxValue: Int = 0x7fffffff val intMinValue: Int = 1 shl 31 @@ -18,4 +20,48 @@ val i15: Int = intMinValue / -1 val l20: Int = 30 * 24 * 60 * 60 * 1000 val l21: Int = intMinValue - intMinValue val l22: Int = intMinValue + -intMinValue -val l23: Int = intMaxValue + -intMinValue \ No newline at end of file +val l23: Int = intMaxValue + -intMinValue + +fun foo() { + val a3: Int = intMaxValue + 1 - 10 + val a4: Int = intMaxValue + 1 + 10 + val i2: Int = intMaxValue - 1 + 2 + val i3: Int = intMaxValue - intMinValue + val i4: Int = -intMinValue + val i5: Int = intMinValue - 1 + val i6: Int = intMinValue - intMaxValue + val i7: Int = intMinValue + intMaxValue + val i8: Int = -intMaxValue + val i10: Int = intMinValue * -1 + val i11: Int = intMinValue * 2 + val i12: Int = intMaxValue * -2 + val i13: Int = intMaxValue * -1 + val i15: Int = intMinValue / -1 + val l20: Int = 30 * 24 * 60 * 60 * 1000 + val l21: Int = intMinValue - intMinValue + val l22: Int = intMinValue + -intMinValue + val l23: Int = intMaxValue + -intMinValue +} + +class A { + fun foo() { + val a3: Int = intMaxValue + 1 - 10 + val a4: Int = intMaxValue + 1 + 10 + val i2: Int = intMaxValue - 1 + 2 + val i3: Int = intMaxValue - intMinValue + val i4: Int = -intMinValue + val i5: Int = intMinValue - 1 + val i6: Int = intMinValue - intMaxValue + val i7: Int = intMinValue + intMaxValue + val i8: Int = -intMaxValue + val i10: Int = intMinValue * -1 + val i11: Int = intMinValue * 2 + val i12: Int = intMaxValue * -2 + val i13: Int = intMaxValue * -1 + val i15: Int = intMinValue / -1 + val l20: Int = 30 * 24 * 60 * 60 * 1000 + val l21: Int = intMinValue - intMinValue + val l22: Int = intMinValue + -intMinValue + val l23: Int = intMaxValue + -intMinValue + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/evaluate/longOverflow.kt b/compiler/testData/diagnostics/tests/evaluate/longOverflow.kt index 298c37b1b4e..e5b77a78c7e 100644 --- a/compiler/testData/diagnostics/tests/evaluate/longOverflow.kt +++ b/compiler/testData/diagnostics/tests/evaluate/longOverflow.kt @@ -1,3 +1,5 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + val longMaxValue: Long = 0x7fffffffffffffff val longMinValue: Long = -longMaxValue - 1 val intMaxValue: Int = 0x7fffffff @@ -20,4 +22,44 @@ val l13: Long = longMinValue * -1 val l14: Long = longMinValue * 2 val l15: Long = longMaxValue * -2 val l16: Long = intMinValue.toLong() * -1 -val l19: Long = longMinValue / -1 \ No newline at end of file +val l19: Long = longMinValue / -1 + +fun foo() { + val l1: Long = longMaxValue + 1 + val l2: Long = longMaxValue - 1 + 2 + val l3: Long = longMaxValue - longMinValue + val l4: Long = -longMinValue + val l5: Long = longMinValue - 1 + val l6: Long = longMinValue - longMaxValue + val l7: Long = longMinValue + longMaxValue + val l8: Long = -longMaxValue + val l10: Long = -intMinValue.toLong() + val l11: Long = -1 + intMinValue.toLong() + val l12: Long = longMinValue * intMinValue + val l13: Long = longMinValue * -1 + val l14: Long = longMinValue * 2 + val l15: Long = longMaxValue * -2 + val l16: Long = intMinValue.toLong() * -1 + val l19: Long = longMinValue / -1 +} + +class A { + fun foo() { + val l1: Long = longMaxValue + 1 + val l2: Long = longMaxValue - 1 + 2 + val l3: Long = longMaxValue - longMinValue + val l4: Long = -longMinValue + val l5: Long = longMinValue - 1 + val l6: Long = longMinValue - longMaxValue + val l7: Long = longMinValue + longMaxValue + val l8: Long = -longMaxValue + val l10: Long = -intMinValue.toLong() + val l11: Long = -1 + intMinValue.toLong() + val l12: Long = longMinValue * intMinValue + val l13: Long = longMinValue * -1 + val l14: Long = longMinValue * 2 + val l15: Long = longMaxValue * -2 + val l16: Long = intMinValue.toLong() * -1 + val l19: Long = longMinValue / -1 + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/evaluate/qualifiedExpressions.kt b/compiler/testData/diagnostics/tests/evaluate/qualifiedExpressions.kt new file mode 100644 index 00000000000..621c9564040 --- /dev/null +++ b/compiler/testData/diagnostics/tests/evaluate/qualifiedExpressions.kt @@ -0,0 +1,8 @@ +// FILE: a.kt +package example.ns +val y: Any? = 2 + +// FILE: b.kt +package example + +val x: Int = if (ns.y is Int) ns.y else 2 \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/classObjectProperty.kt b/compiler/testData/evaluate/constant/classObjectProperty.kt new file mode 100644 index 00000000000..2e97619bf8d --- /dev/null +++ b/compiler/testData/evaluate/constant/classObjectProperty.kt @@ -0,0 +1,49 @@ +package test + +// val prop1: 1.toInt() +val prop1 = A.a + +// val prop2: 2.toInt() +val prop2 = A.a + 1 + +class A { + // val prop3: 1.toInt() + val prop3 = A.a + + // val prop4: 2.toInt() + val prop4 = A.a + 1 + + class object { + val a = 1 + } +} + +fun foo() { + // val prop5: 1.toInt() + val prop5 = A.a + + // val prop6: 2.toInt() + val prop6 = A.a + 1 + + val b = { + // val prop11: 1.toInt() + val prop11 = A.a + + // val prop12: 2.toInt() + val prop12 = A.a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: 1.toInt() + val prop9 = A.a + + // val prop10: 2.toInt() + val prop10 = A.a + 1 + } + } +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/finalProperty.kt b/compiler/testData/evaluate/constant/finalProperty.kt new file mode 100644 index 00000000000..89bcbf05f59 --- /dev/null +++ b/compiler/testData/evaluate/constant/finalProperty.kt @@ -0,0 +1,55 @@ +package test + +// val prop1: 1.toInt() +val prop1 = A().a + +// val prop2: 2.toInt() +val prop2 = A().a + 1 + +class A() { + val a = 1 + + // val prop3: 1.toInt() + val prop3 = a + + // val prop4: 2.toInt() + val prop4 = a + 1 + + fun foo() { + // val prop5: 1.toInt() + val prop5 = A().a + + // val prop6: 2.toInt() + val prop6 = A().a + 1 + + val b = { + // val prop11: 1.toInt() + val prop11 = A().a + + // val prop12: 2.toInt() + val prop12 = A().a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: 1.toInt() + val prop9 = A().a + + // val prop10: 2.toInt() + val prop10 = A().a + 1 + } + } + } +} + +fun foo() { + // val prop7: 1.toInt() + val prop7 = A().a + + // val prop8: 2.toInt() + val prop8 = A().a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/localVal.kt b/compiler/testData/evaluate/constant/localVal.kt new file mode 100644 index 00000000000..20c59bf6e18 --- /dev/null +++ b/compiler/testData/evaluate/constant/localVal.kt @@ -0,0 +1,53 @@ +package test + +class A() { + fun foo() { + val a = 1 + + // val prop5: 1.toInt() + val prop5 = a + + // val prop6: 2.toInt() + val prop6 = a + 1 + + fun local() { + // val prop1: 1.toInt() + val prop1 = a + + // val prop2: 2.toInt() + val prop2 = a + 1 + } + + val b = { + // val prop3: 1.toInt() + val prop3 = a + + // val prop4: 2.toInt() + val prop4 = a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: 1.toInt() + val prop9 = a + + // val prop10: 2.toInt() + val prop10 = a + 1 + } + } + } +} + +fun foo() { + val a = 1 + + // val prop7: 1.toInt() + val prop7 = a + + // val prop8: 2.toInt() + val prop8 = a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/localVar.kt b/compiler/testData/evaluate/constant/localVar.kt new file mode 100644 index 00000000000..a607b8a6172 --- /dev/null +++ b/compiler/testData/evaluate/constant/localVar.kt @@ -0,0 +1,53 @@ +package test + +class A() { + fun foo() { + var a = 1 + + // val prop5: null + val prop5 = a + + // val prop6: null + val prop6 = a + 1 + + fun local() { + // val prop1: null + val prop1 = a + + // val prop2: null + val prop2 = a + 1 + } + + val b = { + // val prop3: null + val prop3 = a + + // val prop4: null + val prop4 = a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: null + val prop9 = a + + // val prop10: null + val prop10 = a + 1 + } + } + } +} + +fun foo() { + var a = 1 + + // val prop7: null + val prop7 = a + + // val prop8: null + val prop8 = a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/nonFinalProperty.kt b/compiler/testData/evaluate/constant/nonFinalProperty.kt new file mode 100644 index 00000000000..41f11e20855 --- /dev/null +++ b/compiler/testData/evaluate/constant/nonFinalProperty.kt @@ -0,0 +1,56 @@ +package test + +// val prop1: null +val prop1 = A().a + +// val prop2: null +val prop2 = A().a + 1 + +class A() { + var a = 1 + + // val prop3: null + val prop3 = a + + // val prop4: null + val prop4 = a + 1 + + fun foo() { + // val prop5: null + val prop5 = A().a + + // val prop6: null + val prop6 = A().a + 1 + + val b = { + // val prop11: null + val prop11 = A().a + + // val prop12: null + val prop12 = A().a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: null + val prop9 = A().a + + // val prop10: null + val prop10 = A().a + 1 + } + } + } + +} + +fun foo() { + // val prop7: null + val prop7 = A().a + + // val prop8: null + val prop8 = A().a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/topLevelVal.kt b/compiler/testData/evaluate/constant/topLevelVal.kt new file mode 100644 index 00000000000..e2f60326ea5 --- /dev/null +++ b/compiler/testData/evaluate/constant/topLevelVal.kt @@ -0,0 +1,47 @@ +package test + +val a = 1 + +// val prop1: 1.toInt() +val prop1 = a + +// val prop2: 2.toInt() +val prop2 = a + 1 + +class A { + // val prop3: 1.toInt() + val prop3 = a + + // val prop4: 2.toInt() + val prop4 = a + 1 + + val b = { + // val prop11: 1.toInt() + val prop11 = a + + // val prop12: 2.toInt() + val prop12 = a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: 1.toInt() + val prop9 = a + + // val prop10: 2.toInt() + val prop10 = a + 1 + } + } +} + +fun foo() { + // val prop5: 1.toInt() + val prop5 = a + + // val prop6: 2.toInt() + val prop6 = a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/testData/evaluate/constant/topLevelVar.kt b/compiler/testData/evaluate/constant/topLevelVar.kt new file mode 100644 index 00000000000..28390177672 --- /dev/null +++ b/compiler/testData/evaluate/constant/topLevelVar.kt @@ -0,0 +1,47 @@ +package test + +var a = 1 + +// val prop1: null +val prop1 = a + +// val prop2: null +val prop2 = a + 1 + +class A { + // val prop3: null + val prop3 = a + + // val prop4: null + val prop4 = a + 1 + + val b = { + // val prop11: null + val prop11 = a + + // val prop12: null + val prop12 = a + 1 + } + + val c = object: Foo { + override fun f() { + // val prop9: null + val prop9 = a + + // val prop10: null + val prop10 = a + 1 + } + } +} + +fun foo() { + // val prop5: null + val prop5 = a + + // val prop6: null + val prop6 = a + 1 +} + +trait Foo { + fun f() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 80581f8e33a..b118457bf60 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2889,6 +2889,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/evaluate/parentesized.kt"); } + @TestMetadata("qualifiedExpressions.kt") + public void testQualifiedExpressions() throws Exception { + doTest("compiler/testData/diagnostics/tests/evaluate/qualifiedExpressions.kt"); + } + @TestMetadata("unaryMinusDepOnExpType.kt") public void testUnaryMinusDepOnExpType() throws Exception { doTest("compiler/testData/diagnostics/tests/evaluate/unaryMinusDepOnExpType.kt"); diff --git a/compiler/tests/org/jetbrains/jet/evaluate/AbstractEvaluateExpressionTest.kt b/compiler/tests/org/jetbrains/jet/evaluate/AbstractEvaluateExpressionTest.kt index 8456535da32..574a2dbb72f 100644 --- a/compiler/tests/org/jetbrains/jet/evaluate/AbstractEvaluateExpressionTest.kt +++ b/compiler/tests/org/jetbrains/jet/evaluate/AbstractEvaluateExpressionTest.kt @@ -32,6 +32,7 @@ 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.descriptors.VariableDescriptor abstract class AbstractEvaluateExpressionTest: AbstractAnnotationDescriptorResolveTest() { @@ -72,7 +73,9 @@ abstract class AbstractEvaluateExpressionTest: AbstractAnnotationDescriptorResol val expected = InTextDirectivesUtils.findStringWithPrefixes(fileText, expectedPropertyPrefix) assertNotNull(expected, "Failed to find expected directive: $expectedPropertyPrefix") - val property = AbstractAnnotationDescriptorResolveTest.getPropertyDescriptor(packageView, propertyName) + val property = AbstractAnnotationDescriptorResolveTest.getPropertyDescriptor(packageView, propertyName, false) + ?: AbstractAnnotationDescriptorResolveTest.getLocalVarDescriptor(context!!, propertyName) + val jetProperty = BindingContextUtils.descriptorToDeclaration(context!!, property) as JetProperty val testedObject = getValueToTest(jetProperty, context!!) diff --git a/compiler/tests/org/jetbrains/jet/evaluate/EvaluateExpressionTestGenerated.java b/compiler/tests/org/jetbrains/jet/evaluate/EvaluateExpressionTestGenerated.java index 6c3fb292e68..3863b3747f8 100644 --- a/compiler/tests/org/jetbrains/jet/evaluate/EvaluateExpressionTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/evaluate/EvaluateExpressionTestGenerated.java @@ -38,6 +38,11 @@ public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionT JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/evaluate/constant"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("classObjectProperty.kt") + public void testClassObjectProperty() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/classObjectProperty.kt"); + } + @TestMetadata("compareTo.kt") public void testCompareTo() throws Exception { doConstantTest("compiler/testData/evaluate/constant/compareTo.kt"); @@ -58,6 +63,11 @@ public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionT doConstantTest("compiler/testData/evaluate/constant/exceptionWhenEvaluate.kt"); } + @TestMetadata("finalProperty.kt") + public void testFinalProperty() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/finalProperty.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { doConstantTest("compiler/testData/evaluate/constant/float.kt"); @@ -78,11 +88,36 @@ public class EvaluateExpressionTestGenerated extends AbstractEvaluateExpressionT doConstantTest("compiler/testData/evaluate/constant/integers.kt"); } + @TestMetadata("localVal.kt") + public void testLocalVal() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/localVal.kt"); + } + + @TestMetadata("localVar.kt") + public void testLocalVar() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/localVar.kt"); + } + + @TestMetadata("nonFinalProperty.kt") + public void testNonFinalProperty() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/nonFinalProperty.kt"); + } + @TestMetadata("strings.kt") public void testStrings() throws Exception { doConstantTest("compiler/testData/evaluate/constant/strings.kt"); } + @TestMetadata("topLevelVal.kt") + public void testTopLevelVal() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/topLevelVal.kt"); + } + + @TestMetadata("topLevelVar.kt") + public void testTopLevelVar() throws Exception { + doConstantTest("compiler/testData/evaluate/constant/topLevelVar.kt"); + } + @TestMetadata("unaryMinusIndepWoExpType.kt") public void testUnaryMinusIndepWoExpType() throws Exception { doConstantTest("compiler/testData/evaluate/constant/unaryMinusIndepWoExpType.kt"); diff --git a/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationDescriptorResolveTest.java b/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationDescriptorResolveTest.java index e72c7825615..b6924f043b5 100644 --- a/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationDescriptorResolveTest.java +++ b/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationDescriptorResolveTest.java @@ -20,6 +20,7 @@ package org.jetbrains.jet.resolve.annotation; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.analyzer.AnalyzeExhaust; @@ -87,7 +88,7 @@ public abstract class AbstractAnnotationDescriptorResolveTest extends JetLiteFix FunctionDescriptor topFoo = getFunctionDescriptor(test, "topFoo"); checkAnnotationsOnFunction(expectedAnnotation, topFoo); - PropertyDescriptor topProp = getPropertyDescriptor(test, "topProp"); + PropertyDescriptor topProp = getPropertyDescriptor(test, "topProp", true); checkAnnotationsOnProperty(expectedAnnotation, topProp); checkDescriptor(expectedAnnotation, getClassDescriptor(test, "MyObject")); @@ -100,7 +101,7 @@ public abstract class AbstractAnnotationDescriptorResolveTest extends JetLiteFix checkDescriptor(expectedAnnotation, getLocalClassDescriptor("LocalClass")); checkDescriptor(expectedAnnotation, getLocalObjectDescriptor("LocalObject")); checkDescriptor(expectedAnnotation, getLocalFunDescriptor("localFun")); - checkDescriptor(expectedAnnotation, getLocalVarDescriptor("localVar")); + checkDescriptor(expectedAnnotation, getLocalVarDescriptor(context, "localVar")); } private static void checkAnnotationsOnProperty(String expectedAnnotation, PropertyDescriptor prop) { @@ -134,12 +135,30 @@ public abstract class AbstractAnnotationDescriptorResolveTest extends JetLiteFix return functions.iterator().next(); } - @NotNull - protected static PropertyDescriptor getPropertyDescriptor(@NotNull PackageViewDescriptor packageView, @NotNull String name) { + @Nullable + protected static PropertyDescriptor getPropertyDescriptor(@NotNull PackageViewDescriptor packageView, @NotNull String name, boolean failOnMissing) { Name propertyName = Name.identifier(name); JetScope memberScope = packageView.getMemberScope(); Collection properties = memberScope.getProperties(propertyName); - assert properties.size() == 1 : "Failed to find property " + propertyName + " in class " + packageView.getName(); + if (properties.isEmpty()) { + for (DeclarationDescriptor descriptor : memberScope.getAllDescriptors()) { + if (descriptor instanceof ClassDescriptor) { + Collection classProperties = + ((ClassDescriptor) descriptor).getMemberScope(Collections.emptyList()) + .getProperties(propertyName); + if (!classProperties.isEmpty()) { + properties = classProperties; + break; + } + } + } + } + if (failOnMissing) { + assert properties.size() == 1 : "Failed to find property " + propertyName + " in class " + packageView.getName(); + } + else if (properties.size() != 1) { + return null; + } return (PropertyDescriptor) properties.iterator().next(); } @@ -216,7 +235,7 @@ public abstract class AbstractAnnotationDescriptorResolveTest extends JetLiteFix } @NotNull - private VariableDescriptor getLocalVarDescriptor(@NotNull String name) { + protected static VariableDescriptor getLocalVarDescriptor(@NotNull BindingContext context, @NotNull String name) { for (VariableDescriptor descriptor : context.getSliceContents(BindingContext.VARIABLE).values()) { if (descriptor.getName().asString().equals(name)) { return descriptor; diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstant.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstant.java index caf1672456d..6b47c653291 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstant.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstant.java @@ -24,11 +24,20 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; public abstract class CompileTimeConstant { protected final T value; + private boolean canBeUsedInAnnotations = true; protected CompileTimeConstant(T value) { this.value = value; } + public boolean canBeUsedInAnnotations() { + return canBeUsedInAnnotations; + } + + public void setCanBeUsedInAnnotations(boolean canBeUsedInAnnotations) { + this.canBeUsedInAnnotations = canBeUsedInAnnotations; + } + @Nullable public T getValue() { return value;