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 e843278189f..12c6f423d10 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/evaluate/ConstantExpressionEvaluator.kt @@ -294,7 +294,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet if (resolvedCall != null) { val callableDescriptor = resolvedCall.getResultingDescriptor() if (callableDescriptor is VariableDescriptor) { - val compileTimeConstant = trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, callableDescriptor) + val compileTimeConstant = callableDescriptor.getCompileTimeInitializer() ?: trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, callableDescriptor) if (compileTimeConstant == null) return null val value: Any? = @@ -435,10 +435,15 @@ public fun recordCompileTimeValueForInitializerIfNeeded( trace: BindingTrace ) { if (!variableDescriptor.isVar()) { - if (trace.get(BindingContext.COMPILE_TIME_INITIALIZER, variableDescriptor) == null) { + if (variableDescriptor.getCompileTimeInitializer() == null && 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) + if (constant is IntegerValueTypeConstant) { + trace.record(BindingContext.COMPILE_TIME_INITIALIZER, variableDescriptor, constant.createCompileTimeConstantWithType(variableType)) + } + else { + trace.record(BindingContext.COMPILE_TIME_INITIALIZER, variableDescriptor, constant) + } } } } @@ -552,55 +557,11 @@ private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? { } private fun createCompileTimeConstant(value: Any?, c: EvaluatorContext, expectedType: JetType? = null): CompileTimeConstant<*>? { - if (expectedType == null) { - when(value) { - is Byte -> return ByteValue(value, c.canBeUsedInAnnotation, c.isPure) - is Short -> return ShortValue(value, c.canBeUsedInAnnotation, c.isPure) - is Int -> return IntValue(value, c.canBeUsedInAnnotation, c.isPure) - is Long -> return LongValue(value, c.canBeUsedInAnnotation, c.isPure) - } - } - return when(value) { - is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), c, expectedType) - is Char -> CharValue(value, c.canBeUsedInAnnotation, c.isPure) - is Float -> FloatValue(value, c.canBeUsedInAnnotation) - is Double -> DoubleValue(value, c.canBeUsedInAnnotation) - is Boolean -> BooleanValue(value, c.canBeUsedInAnnotation) - is String -> StringValue(value, c.canBeUsedInAnnotation) - else -> null - } + return ConstantUtils.createCompileTimeConstant(value, c.canBeUsedInAnnotation, c.isPure, expectedType) } - fun isIntegerType(value: Any?) = value is Byte || value is Short || value is Int || value is Long -private fun getIntegerValue(value: Long, c: EvaluatorContext, expectedType: JetType): CompileTimeConstant<*>? { - fun defaultIntegerValue(value: Long) = when (value) { - value.toInt().toLong() -> IntValue(value.toInt(), c.canBeUsedInAnnotation, c.isPure) - else -> LongValue(value, c.canBeUsedInAnnotation, c.isPure) - } - - if (CompileTimeConstantChecker.noExpectedTypeOrError(expectedType)) { - return IntegerValueTypeConstant(value, c.canBeUsedInAnnotation) - } - - val builtIns = KotlinBuiltIns.getInstance() - - return when (TypeUtils.makeNotNullable(expectedType)) { - builtIns.getLongType() -> LongValue(value, c.canBeUsedInAnnotation, c.isPure) - builtIns.getShortType() -> when (value) { - value.toShort().toLong() -> ShortValue(value.toShort(), c.canBeUsedInAnnotation, c.isPure) - else -> defaultIntegerValue(value) - } - builtIns.getByteType() -> when (value) { - value.toByte().toLong() -> ByteValue(value.toByte(), c.canBeUsedInAnnotation, c.isPure) - else -> defaultIntegerValue(value) - } - builtIns.getCharType() -> IntValue(value.toInt(), c.canBeUsedInAnnotation, c.isPure) - else -> defaultIntegerValue(value) - } -} - private fun getReceiverExpressionType(resolvedCall: ResolvedCall<*>): JetType? { return when (resolvedCall.getExplicitReceiverKind()) { ExplicitReceiverKind.THIS_OBJECT -> resolvedCall.getThisObject().getType() 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 a99fedb55ee..c95ea182507 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -29,9 +29,12 @@ 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.ConstantExpressionEvaluator; 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.constants.CompileTimeConstant; +import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; @@ -913,7 +916,7 @@ public class DescriptorResolver { @NotNull private JetType getVariableType( - @NotNull final VariableDescriptor variableDescriptor, + @NotNull final VariableDescriptorImpl variableDescriptor, @NotNull final JetScope scope, @NotNull final JetVariableDeclaration variable, @NotNull final DataFlowInfo dataFlowInfo, @@ -955,17 +958,17 @@ public class DescriptorResolver { new Function0() { @Override public JetType invoke() { - JetType type = resolveInitializerType(scope, initializer, dataFlowInfo, trace); - - EvaluatePackage.recordCompileTimeValueForInitializerIfNeeded( - variableDescriptor, initializer, type, trace); - return transformAnonymousTypeIfNeeded(variableDescriptor, variable, type, trace); + JetType initializerType = resolveInitializerType(scope, initializer, dataFlowInfo, trace); + setConstantForVariable(variableDescriptor, initializer, initializerType, trace); + return transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace); } } ); } else { - return resolveInitializerType(scope, initializer, dataFlowInfo, trace); + JetType initializerType = resolveInitializerType(scope, initializer, dataFlowInfo, trace); + setConstantForVariable(variableDescriptor, initializer, initializerType, trace); + return initializerType; } } } @@ -974,6 +977,19 @@ public class DescriptorResolver { } } + private static void setConstantForVariable( + @NotNull VariableDescriptorImpl variableDescriptor, + @NotNull JetExpression initializer, + @NotNull JetType initializerType, + @NotNull BindingTrace trace + ) { + CompileTimeConstant constant = ConstantExpressionEvaluator.object$.evaluate(initializer, trace, initializerType); + if (constant instanceof IntegerValueTypeConstant){ + constant = EvaluatePackage.createCompileTimeConstantWithType((IntegerValueTypeConstant) constant, initializerType); + } + variableDescriptor.setCompileTimeInitializer(constant); + } + @NotNull private JetType resolveDelegatedPropertyType( @NotNull JetProperty property, diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java index b9d164f1dfd..c3d2dd0f316 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java @@ -17,6 +17,8 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; @@ -32,4 +34,7 @@ public interface VariableDescriptor extends CallableDescriptor { VariableDescriptor substitute(@NotNull TypeSubstitutor substitutor); boolean isVar(); + + @Nullable + CompileTimeConstant getCompileTimeInitializer(); } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/VariableDescriptorImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/VariableDescriptorImpl.java index 9109a7a04a9..6267ee2b02b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/VariableDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/VariableDescriptorImpl.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotations; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; @@ -29,6 +30,7 @@ import java.util.Set; public abstract class VariableDescriptorImpl extends DeclarationDescriptorNonRootImpl implements VariableDescriptor { private JetType outType; + private CompileTimeConstant compileTimeInitializer; public VariableDescriptorImpl( @NotNull DeclarationDescriptor containingDeclaration, @@ -60,6 +62,18 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorNonRoo this.outType = outType; } + @Nullable + @Override + public CompileTimeConstant getCompileTimeInitializer() { + return compileTimeInitializer; + } + + public void setCompileTimeInitializer(@Nullable CompileTimeConstant compileTimeInitializer) { + if (!isVar()) { + this.compileTimeInitializer = compileTimeInitializer; + } + } + @Override @NotNull public VariableDescriptor getOriginal() { diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java new file mode 100644 index 00000000000..c675fd9215f --- /dev/null +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010-2014 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.annotations.Nullable; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; + +public class ConstantUtils { + + @Nullable + private static CompileTimeConstant getIntegerValue( + long value, + boolean canBeUsedInAnnotations, + boolean isPureIntConstant, + @NotNull JetType expectedType + ) { + if (TypeUtils.noExpectedType(expectedType) || expectedType.isError()) { + return new IntegerValueTypeConstant(value, canBeUsedInAnnotations); + } + + KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); + + JetType notNullExpectedType = TypeUtils.makeNotNullable(expectedType); + if (notNullExpectedType.equals(builtIns.getLongType())) { + return new LongValue(value, canBeUsedInAnnotations, isPureIntConstant); + } + else if (notNullExpectedType.equals(builtIns.getShortType())) { + if (value == (long) ((short) value)) { + return new ShortValue((short) value, canBeUsedInAnnotations, isPureIntConstant); + } + return getDefaultIntegerValue(value, canBeUsedInAnnotations, isPureIntConstant); + } + if (notNullExpectedType.equals(builtIns.getByteType())) { + if (value == (long) ((byte) value)) { + return new ByteValue((byte) value, canBeUsedInAnnotations, isPureIntConstant); + } + return getDefaultIntegerValue(value, canBeUsedInAnnotations, isPureIntConstant); + } + else { + return getDefaultIntegerValue(value, canBeUsedInAnnotations, isPureIntConstant); + } + } + + @NotNull + private static CompileTimeConstant getDefaultIntegerValue( + long value, boolean canBeUsedInAnnotations, + boolean isPureIntConstant + ) { + if (value == (long) ((int) value)) { + return new IntValue((int) value, canBeUsedInAnnotations, isPureIntConstant); + } + else { + return new LongValue(value, canBeUsedInAnnotations, isPureIntConstant); + } + } + + @Nullable + public static CompileTimeConstant createCompileTimeConstant( + @Nullable Object value, + boolean canBeUsedInAnnotations, + boolean isPureIntConstant, + @Nullable JetType expectedType + ) { + if (expectedType == null) { + if (value instanceof Integer) { + return new IntValue((Integer) value, canBeUsedInAnnotations, isPureIntConstant); + } + else if (value instanceof Long) { + return new LongValue((Long) value, canBeUsedInAnnotations, isPureIntConstant); + } + else if (value instanceof Byte) { + return new ByteValue((Byte) value, canBeUsedInAnnotations, isPureIntConstant); + } + else if (value instanceof Short) { + return new ShortValue((Short) value, canBeUsedInAnnotations, isPureIntConstant); + } + } + if (value instanceof Integer) { + return getIntegerValue((Integer) value, canBeUsedInAnnotations, isPureIntConstant, expectedType); + } + else if (value instanceof Long) { + return getIntegerValue((Long) value, canBeUsedInAnnotations, isPureIntConstant, expectedType); + } + else if (value instanceof Byte) { + return getIntegerValue((Byte) value, canBeUsedInAnnotations, isPureIntConstant, expectedType); + } + else if (value instanceof Short) { + return getIntegerValue((Short) value, canBeUsedInAnnotations, isPureIntConstant, expectedType); + } + else if (value instanceof Character) { + return new CharValue((Character) value, canBeUsedInAnnotations, isPureIntConstant); + } + else if (value instanceof Float) { + return new FloatValue((Float) value, canBeUsedInAnnotations); + } + else if (value instanceof Double) { + return new DoubleValue((Double) value, canBeUsedInAnnotations); + } + else if (value instanceof Boolean) { + return new BooleanValue((Boolean) value, canBeUsedInAnnotations); + } + else if (value instanceof String) { + return new StringValue((String) value, canBeUsedInAnnotations); + } + return null; + } + + private ConstantUtils() { + } +}