diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.java b/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.java index d14b8465c66..f316e63c999 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.java @@ -83,6 +83,10 @@ public class ConstantExpressionEvaluator extends JetVisitor visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) { + CompileTimeConstant compileTimeConstant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); + if (compileTimeConstant != null) { + return compileTimeConstant; + } JetExpression selectorExpression = expression.getSelectorExpression(); if (selectorExpression != null) { return selectorExpression.accept(this, null); 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 8c0c820ae65..cfd0071fd00 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 @@ -34,7 +34,7 @@ import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; -import org.jetbrains.jet.lang.resolve.constants.ConstantUtils; +import org.jetbrains.jet.lang.resolve.constants.ConstantsPackage; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -417,15 +417,15 @@ public class CallExpressionResolver { context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo()); - if (selectorExpression instanceof JetSimpleNameExpression) { - ConstantUtils.propagateConstantValues(expression, context.trace, (JetSimpleNameExpression) selectorExpression); - } - JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo( new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context); JetType selectorReturnType = selectorReturnTypeInfo.getType(); + if (receiverExpression instanceof JetConstantExpression && selectorExpression instanceof JetCallExpression) { + ConstantsPackage.propagateConstantValues(expression, context.trace, (JetCallExpression) selectorExpression); + } + //TODO move further if (!(receiverType instanceof NamespaceType) && expression.getOperationSign() == JetTokens.SAFE_ACCESS) { if (selectorReturnType != null && !selectorReturnType.isNullable() && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java deleted file mode 100644 index ab3ea5ddb24..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve.constants; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetQualifiedExpression; -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.JetTypeInfo; -import org.jetbrains.jet.lang.types.TypeUtils; -import org.jetbrains.jet.lang.types.expressions.OperatorConventions; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; - -import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*; - -public class ConstantUtils { - - public static void propagateConstantValues(JetQualifiedExpression expression, BindingTrace trace, JetSimpleNameExpression selectorExpression) { - JetExpression receiverExpression = expression.getReceiverExpression(); - CompileTimeConstant receiverValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression); - CompileTimeConstant wholeExpressionValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression); - DeclarationDescriptor declarationDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, selectorExpression); - if (wholeExpressionValue == null && receiverValue != null && !(receiverValue instanceof ErrorValue) && receiverValue.getValue() instanceof Number - && KotlinBuiltIns.getInstance().getNumber() == declarationDescriptor) { - Number value = (Number) receiverValue.getValue(); - Name referencedName = selectorExpression.getReferencedNameAsName(); - if (OperatorConventions.NUMBER_CONVERSIONS.contains(referencedName)) { - if (DOUBLE.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new DoubleValue(value.doubleValue())); - } - else if (FLOAT.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new FloatValue(value.floatValue())); - } - else if (LONG.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new LongValue(value.longValue())); - } - else if (SHORT.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ShortValue(value.shortValue())); - } - else if (BYTE.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ByteValue(value.byteValue())); - } - else if (INT.equals(referencedName)) { - trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new IntValue(value.intValue())); - } - } - } - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.kt new file mode 100644 index 00000000000..606c57bb914 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.constants + +import org.jetbrains.jet.lang.psi.JetQualifiedExpression +import org.jetbrains.jet.lang.psi.JetCallExpression +import org.jetbrains.jet.lang.resolve.BindingTrace +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.types.expressions.OperatorConventions + +public fun propagateConstantValues(expression : JetQualifiedExpression, trace : BindingTrace, selectorExpression : JetCallExpression) { + val wholeExpressionValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression) + if (wholeExpressionValue != null) { + return + } + + val receiverExpression = expression.getReceiverExpression() + val receiverValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression) + if (receiverValue == null || receiverValue is ErrorValue) { + return + } + + val calleeExpression = selectorExpression.getCalleeExpression() + if (calleeExpression !is JetSimpleNameExpression) { + return + } + + val declarationDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, calleeExpression) + if (declarationDescriptor !is FunctionDescriptor) { + return + } + + val returnType = declarationDescriptor.getReturnType() + if (returnType == null || !KotlinBuiltIns.getInstance().isPrimitiveType(returnType)) { + return + } + + val referencedName = calleeExpression.getReferencedNameAsName() + val value = receiverValue.getValue() + val compileTimeValue = when (value) { + is Number -> { + when(referencedName) { + OperatorConventions.DOUBLE -> DoubleValue(value.toDouble()) + OperatorConventions.FLOAT -> FloatValue(value.toFloat()) + OperatorConventions.LONG -> LongValue(value.toLong()) + OperatorConventions.SHORT -> ShortValue(value.toShort()) + OperatorConventions.BYTE -> ByteValue(value.toByte()) + OperatorConventions.INT -> IntValue(value.toInt()) + OperatorConventions.CHAR -> CharValue(value.toInt().toChar()) + } + } + is Char -> { + when(referencedName) { + OperatorConventions.DOUBLE -> DoubleValue(value.toChar().toDouble()) + OperatorConventions.FLOAT -> FloatValue(value.toChar().toFloat()) + OperatorConventions.LONG -> LongValue(value.toChar().toLong()) + OperatorConventions.SHORT -> ShortValue(value.toChar().toShort()) + OperatorConventions.BYTE -> ByteValue(value.toChar().toByte()) + OperatorConventions.INT -> IntValue(value.toChar().toInt()) + OperatorConventions.CHAR -> CharValue(value.toChar()) + } + } + else -> null + } + + if (compileTimeValue != null) { + trace.record(BindingContext.COMPILE_TIME_VALUE, expression,compileTimeValue) + } + +} + diff --git a/compiler/testData/resolveAnnotations/parameters/byte.kt b/compiler/testData/resolveAnnotations/parameters/byte.kt new file mode 100644 index 00000000000..76a150332d8 --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/byte.kt @@ -0,0 +1,12 @@ +package test + +annotation class Ann( + val b1: Byte, + val b2: Byte, + val b3: Byte, + val b4: Byte +) + +Ann(1, 1.toByte(), 128.toByte(), 128) class MyClass + +// EXPECTED: Ann[b1 = 1.toByte(): jet.Byte, b2 = 1.toByte(): jet.Byte, b3 = -128.toByte(): jet.Byte, b4 = 128.toInt(): jet.Int] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/char.kt b/compiler/testData/resolveAnnotations/parameters/char.kt new file mode 100644 index 00000000000..f980e40f7f6 --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/char.kt @@ -0,0 +1,16 @@ +package test + +annotation class Ann( + val b1: Char, + val b2: Char, + val b3: Int, + val b4: Long, + val b5: Byte, + val b6: Short, + val b7: Double, + val b8: Float +) + +Ann('c', 99.toChar(), 'c'.toInt(), 'c'.toLong(), 'c'.toByte(), 'c'.toShort(), 'c'.toDouble(), 'c'.toFloat()) class MyClass + +// EXPECTED: Ann[b1 = #99(c): jet.Char, b2 = #99(c): jet.Char, b3 = 99.toInt(): jet.Int, b4 = 99.toLong(): jet.Long, b5 = 99.toByte(): jet.Byte, b6 = 99.toShort(): jet.Short, b7 = 99.0.toDouble(): jet.Double, b8 = 99.0.toFloat(): jet.Float] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/double.kt b/compiler/testData/resolveAnnotations/parameters/double.kt new file mode 100644 index 00000000000..7f7d88c7c4d --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/double.kt @@ -0,0 +1,12 @@ +package test + +annotation class Ann( + val b1: Double, + val b2: Double, + val b3: Double, + val b4: Double +) + +Ann(1.0, 1.toDouble(), 1.7976931348623157E309.toDouble(), 1.7976931348623157E309) class MyClass + +// EXPECTED: Ann[b1 = 1.0.toDouble(): jet.Double, b2 = 1.0.toDouble(): jet.Double, b3 = Infinity.toDouble(): jet.Double, b4 = Infinity.toDouble(): jet.Double] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/float.kt b/compiler/testData/resolveAnnotations/parameters/float.kt new file mode 100644 index 00000000000..e02e4cc7daf --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/float.kt @@ -0,0 +1,12 @@ +package test + +annotation class Ann( + val b1: Float, + val b2: Float, + val b3: Float, + val b4: Float +) + +Ann(1.0, 1.toFloat(), 1.0.toFloat()) class MyClass + +// EXPECTED: Ann[b1 = 1.0.toFloat(): jet.Float, b2 = 1.0.toFloat(): jet.Float, b3 = 1.0.toFloat(): jet.Float] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/int.kt b/compiler/testData/resolveAnnotations/parameters/int.kt new file mode 100644 index 00000000000..df6ec577022 --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/int.kt @@ -0,0 +1,12 @@ +package test + +annotation class Ann( + val b1: Int, + val b2: Int, + val b3: Int, + val b4: Int +) + +Ann(1, 1.toInt(), 2147483648.toInt(), 2147483648) class MyClass + +// EXPECTED: Ann[b1 = 1.toInt(): jet.Int, b2 = 1.toInt(): jet.Int, b3 = -2147483648.toInt(): jet.Int, b4 = 2147483648.toLong(): jet.Long] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/long.kt b/compiler/testData/resolveAnnotations/parameters/long.kt new file mode 100644 index 00000000000..28c23aa4101 --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/long.kt @@ -0,0 +1,10 @@ +package test + +annotation class Ann( + val b1: Long, + val b2: Long +) + +Ann(1, 1.toLong()) class MyClass + +// EXPECTED: Ann[b1 = 1.toLong(): jet.Long, b2 = 1.toLong(): jet.Long] \ No newline at end of file diff --git a/compiler/testData/resolveAnnotations/parameters/short.kt b/compiler/testData/resolveAnnotations/parameters/short.kt new file mode 100644 index 00000000000..422bf8a4e0e --- /dev/null +++ b/compiler/testData/resolveAnnotations/parameters/short.kt @@ -0,0 +1,12 @@ +package test + +annotation class Ann( + val b1: Short, + val b2: Short, + val b3: Short, + val b4: Short +) + +Ann(1, 1.toShort(), 32768.toShort(), 32768) class MyClass + +// EXPECTED: Ann[b1 = 1.toShort(): jet.Short, b2 = 1.toShort(): jet.Short, b3 = -32768.toShort(): jet.Short, b4 = 32768.toInt(): jet.Int] \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationParameterTest.kt b/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationParameterTest.kt new file mode 100644 index 00000000000..5f8dd5ae905 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/annotation/AbstractAnnotationParameterTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.resolve.annotation + +import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.jet.InTextDirectivesUtils +import java.io.File + +public abstract class AbstractAnnotationParameterTest : AbstractAnnotationDescriptorResolveTest() { + fun doTest(path: String) { + val fileText = FileUtil.loadFile(File(path)) + val namespaceDescriptor = getNamespaceDescriptor(fileText) + val classDescriptor = AbstractAnnotationDescriptorResolveTest.getClassDescriptor(namespaceDescriptor, "MyClass") + + val expected = InTextDirectivesUtils.findListWithPrefixes(fileText, "// EXPECTED: ").makeString(", ") + AbstractAnnotationDescriptorResolveTest.checkDescriptor(expected, classDescriptor) + } +} diff --git a/compiler/tests/org/jetbrains/jet/resolve/annotation/AnnotationParameterTestGenerated.java b/compiler/tests/org/jetbrains/jet/resolve/annotation/AnnotationParameterTestGenerated.java new file mode 100644 index 00000000000..41b618502aa --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/annotation/AnnotationParameterTestGenerated.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.resolve.annotation; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; +import java.util.regex.Pattern; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; + +import org.jetbrains.jet.resolve.annotation.AbstractAnnotationParameterTest; + +/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/resolveAnnotations/parameters") +public class AnnotationParameterTestGenerated extends AbstractAnnotationParameterTest { + public void testAllFilesPresentInParameters() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolveAnnotations/parameters"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("byte.kt") + public void testByte() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/byte.kt"); + } + + @TestMetadata("char.kt") + public void testChar() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/char.kt"); + } + + @TestMetadata("double.kt") + public void testDouble() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/double.kt"); + } + + @TestMetadata("float.kt") + public void testFloat() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/float.kt"); + } + + @TestMetadata("int.kt") + public void testInt() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/int.kt"); + } + + @TestMetadata("long.kt") + public void testLong() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/long.kt"); + } + + @TestMetadata("short.kt") + public void testShort() throws Exception { + doTest("compiler/testData/resolveAnnotations/parameters/short.kt"); + } + +} diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java index c4db518cc0b..4596ea58f13 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java @@ -64,6 +64,7 @@ import org.jetbrains.jet.psi.AbstractJetPsiMatcherTest; import org.jetbrains.jet.resolve.AbstractResolveBaseTest; import org.jetbrains.jet.resolve.AbstractResolveTest; import org.jetbrains.jet.resolve.AbstractResolveWithLibTest; +import org.jetbrains.jet.resolve.annotation.AbstractAnnotationParameterTest; import org.jetbrains.jet.safeDelete.AbstractJetSafeDeleteTest; import java.io.File; @@ -557,6 +558,13 @@ public class GenerateTests { AbstractRenameTest.class, new SingleClassTestModel(new File("idea/testData/refactoring/rename"), Pattern.compile("^(.+)\\.test$"), "doTest") ); + + generateTest( + "compiler/tests", + "AnnotationParameterTestGenerated", + AbstractAnnotationParameterTest.class, + testModel("compiler/testData/resolveAnnotations/parameters") + ); } private static SimpleTestClassModel testModel(@NotNull String rootPath) {