Use type from compile time value for prefix expression

This commit is contained in:
Natalia Ukhorskaya
2013-12-02 15:01:32 +04:00
parent 9c176ddaa8
commit 2a023c16a9
49 changed files with 805 additions and 140 deletions
@@ -93,7 +93,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
if (result == null && expression.getNode().getElementType() == JetNodeTypes.NULL) return NullValue.NULL
return createCompileTimeConstant(result, expectedType)
return createCompileTimeConstant(result, expression, expectedType)
}
override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -127,7 +127,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
sb.append(constant.getValue())
}
}
return if (!interupted) createCompileTimeConstant(sb.toString(), expectedType) else null
return if (!interupted) createCompileTimeConstant(sb.toString(), expression, expectedType) else null
}
override fun visitBinaryExpression(expression: JetBinaryExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -155,23 +155,18 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
JetTokens.OROR -> leftValue as Boolean || rightValue as Boolean
else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}")
}
return createCompileTimeConstant(result, expectedType)
return createCompileTimeConstant(result, expression, expectedType)
}
else {
val result = evaluateCall(expression.getOperationReference(), leftExpression)
return when(operationToken) {
in OperatorConventions.COMPARISON_OPERATIONS -> createCompileTimeConstantForCompareTo(result, operationToken!!)
in OperatorConventions.EQUALS_OPERATIONS -> createCompileTimeConstantForEquals(result, operationToken!!)
else -> createCompileTimeConstant(result, expectedType)
}
return evaluateCall(expression, expression.getOperationReference(), leftExpression, expectedType)
}
}
private fun evaluateCall(callExpression: JetExpression, receiverExpression: JetExpression): Any? {
private fun evaluateCall(fullExpression: JetExpression, callExpression: JetExpression, receiverExpression: JetExpression, expectedType: JetType?): CompileTimeConstant<*>? {
val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, callExpression)
if (resolvedCall == null) return null
val resultingDescriptorName = resolvedCall.getResultingDescriptor()?.getName()?.asString()
val resultingDescriptorName = resolvedCall.getResultingDescriptor()?.getName()
if (resultingDescriptorName == null) return null
val argumentForReceiver = createOperationArgumentForReceiver(resolvedCall, receiverExpression)
@@ -179,7 +174,10 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val argumentsEntrySet = resolvedCall.getValueArguments().entrySet()
if (argumentsEntrySet.isEmpty()) {
return evaluateUnaryAndCheck(argumentForReceiver, resultingDescriptorName, callExpression)
val result = evaluateUnaryAndCheck(argumentForReceiver, resultingDescriptorName.asString(), callExpression)
val isArgumentPure = trace.get(BindingContext.IS_PURE_CONSTANT_EXPRESSION, argumentForReceiver.expression)
val isNumberConventionMethod = resultingDescriptorName in OperatorConventions.NUMBER_CONVERSIONS
return createCompileTimeConstant(result, fullExpression, expectedType, !isNumberConventionMethod && isArgumentPure ?: false)
}
else if (argumentsEntrySet.size() == 1) {
val (parameter, argument) = argumentsEntrySet.first()
@@ -187,7 +185,16 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter)
if (argumentForParameter == null) return null
return evaluateBinaryAndCheck(argumentForReceiver, argumentForParameter, resultingDescriptorName, callExpression)
val result = evaluateBinaryAndCheck(argumentForReceiver, argumentForParameter, resultingDescriptorName.asString(), callExpression)
return when(resultingDescriptorName) {
OperatorConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression)
OperatorConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression)
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)
}
}
}
return null
@@ -251,8 +258,8 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
override fun visitUnaryExpression(expression: JetUnaryExpression, expectedType: JetType?): CompileTimeConstant<*>? {
val leftExpression = expression.getBaseExpression()
if (leftExpression == null) return null
val result = evaluateCall(expression.getOperationReference(), leftExpression)
return createCompileTimeConstant(result, expectedType)
return evaluateCall(expression, expression.getOperationReference(), leftExpression, expectedType)
}
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -283,13 +290,16 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
val receiverExpression = expression.getReceiverExpression()
val result = evaluateCall(calleeExpression, receiverExpression)
return createCompileTimeConstant(result, expectedType)
return evaluateCall(expression, calleeExpression, receiverExpression, expectedType)
}
// Mynum.A
if (selectorExpression != null) {
return evaluate(selectorExpression, expectedType)
val compileTimeConstant = evaluate(selectorExpression, expectedType)
if (compileTimeConstant != null) {
trace.record(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression, true);
}
return compileTimeConstant
}
return null
@@ -348,7 +358,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
private class OperationArgument(val value: Any?, val ctcType: CompileTimeType<*>)
private class OperationArgument(val value: Any, val ctcType: CompileTimeType<*>, val expression: JetExpression)
private fun createOperationArgumentForReceiver(resolvedCall: ResolvedCall<*>, expression: JetExpression): OperationArgument? {
val receiverExpressionType = getReceiverExpressionType(resolvedCall)
@@ -360,21 +370,65 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
val receiverValue = evaluate(expression, receiverExpressionType)?.getValue()
if (receiverValue == null) return null
return OperationArgument(receiverValue, receiverCompileTimeType)
if (receiverValue is NumberValueTypeConstructor<*>) {
val newValue = receiverValue.getValueForNumberType(receiverExpressionType)
if (newValue != null) {
return OperationArgument(newValue, receiverCompileTimeType, expression)
}
}
return OperationArgument(receiverValue, receiverCompileTimeType, expression)
}
private fun createOperationArgumentForFirstParameter(argument: ResolvedValueArgument, parameter: ValueParameterDescriptor): OperationArgument? {
val argumentCompileTimeType = getCompileTimeType(parameter.getType())
if (argumentCompileTimeType == null) return null
val argumentCompileTimeValue = resolveArguments(argument.getArguments(), parameter.getType())
if (argumentCompileTimeValue.size != 1) return null
val arguments = argument.getArguments()
if (arguments.size != 1) return null
val argumentValue = argumentCompileTimeValue.first().getValue()
val argumentExpression = arguments.first().getArgumentExpression()
if (argumentExpression == null) return null
val constant = evaluate(argumentExpression, parameter.getType())
if (constant == null) return null
val argumentValue = constant.getValue()
if (argumentValue == null) return null
return OperationArgument(argumentValue, argumentCompileTimeType)
if (argumentValue is NumberValueTypeConstructor<*>) {
val newValue = argumentValue.getValueForNumberType(parameter.getType())
if (newValue != null) {
return OperationArgument(newValue, argumentCompileTimeType, argumentExpression)
}
}
return OperationArgument(argumentValue, argumentCompileTimeType, argumentExpression)
}
fun createCompileTimeConstant(value: Any?, expression: JetExpression, expectedType: JetType?, isPure: Boolean = true): CompileTimeConstant<*>? {
if (isPure) {
val compileTimeConstant = createConvertibleCompileTimeConstant(value, expectedType)
trace.record(BindingContext.IS_PURE_CONSTANT_EXPRESSION, expression, true)
return compileTimeConstant
}
val compileTimeConstant = createUnconvertibleCompileTimeConstant(value)
return compileTimeConstant
}
}
public fun NumberValueTypeConstructor<out Number?>.getValueForNumberType(expectedType: JetType): Any? {
val valueWithNewType = this.getCompileTimeConstantForNumberType(expectedType)
if (valueWithNewType != null) {
return valueWithNewType.getValue()
}
return null
}
public fun NumberValueTypeConstructor<out Number?>.getCompileTimeConstantForNumberType(expectedType: JetType): CompileTimeConstant<*>? {
val defaultType = TypeUtils.getPrimitiveNumberType(this, expectedType)
return createConvertibleCompileTimeConstant(this.getValue(), defaultType)
}
public fun parseLong(text: String): Long? {
@@ -411,33 +465,61 @@ private fun parseBoolean(text: String): Boolean {
}
private fun createCompileTimeConstantForEquals(result: Any?, operationToken: IElementType): CompileTimeConstant<*>? {
private fun createCompileTimeConstantForEquals(result: Any?, operationReference: JetExpression): CompileTimeConstant<*>? {
if (result is Boolean) {
assert(operationReference is JetSimpleNameExpression, "This method should be called only for equals operations")
val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType()
return when (operationToken) {
JetTokens.EQEQ -> BooleanValue.valueOf(result)
JetTokens.EXCLEQ -> BooleanValue.valueOf(!result)
else -> throw IllegalStateException("Unknown equals operation token: $operationToken")
JetTokens.IDENTIFIER -> {
assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.EQUALS, "This method should be called only for equals operations")
return BooleanValue.valueOf(result)
}
else -> throw IllegalStateException("Unknown equals operation token: $operationToken ${operationReference.getText()}")
}
}
return null
}
private fun createCompileTimeConstantForCompareTo(result: Any?, operationToken: IElementType): CompileTimeConstant<*>? {
private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: JetExpression): CompileTimeConstant<*>? {
if (result is Int) {
assert(operationReference is JetSimpleNameExpression, "This method should be called only for compareTo operations")
val operationToken = (operationReference as JetSimpleNameExpression).getReferencedNameElementType()
return when (operationToken) {
JetTokens.LT -> BooleanValue.valueOf(result < 0)
JetTokens.LTEQ -> BooleanValue.valueOf(result <= 0)
JetTokens.GT -> BooleanValue.valueOf(result > 0)
JetTokens.GTEQ -> BooleanValue.valueOf(result >= 0)
JetTokens.IDENTIFIER -> {
assert ((operationReference as JetSimpleNameExpression).getReferencedNameAsName() == OperatorConventions.COMPARE_TO, "This method should be called only for compareTo operations")
return IntValue(result)
}
else -> throw IllegalStateException("Unknown compareTo operation token: $operationToken")
}
}
return null
}
private fun createUnconvertibleCompileTimeConstant(value: Any?): CompileTimeConstant<*>? {
return when(value) {
null -> null
is Byte -> ByteValue(value)
is Short -> ShortValue(value)
is Int -> IntValue(value)
is Long -> LongValue(value)
is Char -> CharValue(value)
is Float -> FloatValue(value)
is Double -> DoubleValue(value)
is Boolean -> BooleanValue.valueOf(value)
else -> null
}
}
private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? {
return when (value) {
null -> null
is IntegerValueTypeConstant -> createStringConstant(value.getValue().getCompileTimeConstantForNumberType(TypeUtils.NO_EXPECTED_TYPE))
is StringValue -> value
is IntValue, is ByteValue, is ShortValue, is LongValue,
is CharValue,
@@ -447,10 +529,10 @@ private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? {
}
}
public fun createCompileTimeConstant(value: Any?, expectedType: JetType?): CompileTimeConstant<*>? {
private fun createConvertibleCompileTimeConstant(value: Any?, expectedType: JetType?): CompileTimeConstant<*>? {
return when(value) {
null -> null
is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
is Byte, is Short, is Int, is Long-> getIntegerValue((value as Number).toLong(), expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
is Char -> CharValue(value)
is Float -> FloatValue(value)
is Double -> DoubleValue(value)
@@ -469,7 +551,7 @@ private fun getIntegerValue(value: Long, expectedType: JetType): CompileTimeCons
}
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
return defaultIntegerValue(value)
return IntegerValueTypeConstant(value)
}
val builtIns = KotlinBuiltIns.getInstance()
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
@@ -34,6 +35,8 @@ 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.ArrayValue;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstant;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstructor;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.ErrorUtils;
@@ -49,6 +52,7 @@ import java.util.Map;
import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.getPrimitiveNumberType;
public class AnnotationResolver {
@@ -243,6 +247,11 @@ public class AnnotationResolver {
JetExpression argumentExpression = argument.getArgumentExpression();
if (argumentExpression != null) {
CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
if (constant instanceof NumberValueTypeConstant) {
NumberValueTypeConstructor typeConstructor = ((NumberValueTypeConstant) constant).getValue();
JetType defaultType = getPrimitiveNumberType(typeConstructor, expectedType);
ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
}
if (constant != null) {
constants.add(constant);
}
@@ -73,6 +73,7 @@ public interface BindingContext {
WritableSlice<JetAnnotationEntry, AnnotationDescriptorImpl> ANNOTATION =
Slices.<JetAnnotationEntry, AnnotationDescriptorImpl>sliceBuilder().setOpposite(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT).build();
WritableSlice<JetExpression, Boolean> IS_PURE_CONSTANT_EXPRESSION = Slices.createSimpleSlice();
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
WritableSlice<PropertyDescriptor, CompileTimeConstant<?>> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice();
@@ -264,7 +264,7 @@ public class ArgumentTypeResolver {
}
@Nullable
public <D extends CallableDescriptor> JetType updateResultArgumentTypeIfNotDenotable(
public static <D extends CallableDescriptor> JetType updateResultArgumentTypeIfNotDenotable(
@NotNull ResolutionContext context,
@NotNull JetExpression expression
) {
@@ -273,35 +273,35 @@ public class ArgumentTypeResolver {
if (type.getConstructor() instanceof NumberValueTypeConstructor) {
NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor();
JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
updateNumberType(primitiveType, expression, context);
updateNumberType(primitiveType, expression, context.trace);
return primitiveType;
}
}
return type;
}
private <D extends CallableDescriptor> void updateNumberType(
public static <D extends CallableDescriptor> void updateNumberType(
@NotNull JetType numberType,
@Nullable JetExpression expression,
@NotNull ResolutionContext context
@NotNull BindingTrace trace
) {
if (expression == null) return;
BindingContextUtils.updateRecordedType(numberType, expression, context.trace, false);
BindingContextUtils.updateRecordedType(numberType, expression, trace, false);
if (!(expression instanceof JetConstantExpression)) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression, false);
if (deparenthesized != expression) {
updateNumberType(numberType, deparenthesized, context);
updateNumberType(numberType, deparenthesized, trace);
}
if (deparenthesized instanceof JetBlockExpression) {
JetElement lastStatement = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesized);
if (lastStatement instanceof JetExpression) {
updateNumberType(numberType, (JetExpression) lastStatement, context);
updateNumberType(numberType, (JetExpression) lastStatement, trace);
}
}
return;
}
ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, numberType);
ConstantExpressionEvaluator.object$.evaluate(expression, trace, numberType);
}
}
@@ -0,0 +1,39 @@
/*
* 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;
public class IntegerValueTypeConstant extends NumberValueTypeConstant<Long> {
private final IntegerValueTypeConstructor value;
public IntegerValueTypeConstant(long value) {
this.value = new IntegerValueTypeConstructor(value);
}
@NotNull
@Override
public IntegerValueTypeConstructor getValue() {
return value;
}
@Override
public String toString() {
return value.toString();
}
}
@@ -23,7 +23,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collection;
public class IntegerValueTypeConstructor extends NumberValueTypeConstructor {
public class IntegerValueTypeConstructor extends NumberValueTypeConstructor<Long> {
private final long value;
private final Collection<JetType> supertypes = Lists.newArrayList();
@@ -44,6 +44,11 @@ public class IntegerValueTypeConstructor extends NumberValueTypeConstructor {
}
}
@Override
public Long getValue() {
return value;
}
@NotNull
@Override
public Collection<JetType> getSupertypes() {
@@ -22,16 +22,15 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
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.*;
import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
@@ -50,7 +49,7 @@ import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstant;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstructor;
import org.jetbrains.jet.lang.resolve.name.LabelName;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -73,12 +72,10 @@ import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT;
import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver.ErrorCharValueWithDiagnostic;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
import static org.jetbrains.jet.lang.types.TypeUtils.*;
import static org.jetbrains.jet.lang.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction;
import static org.jetbrains.jet.lang.types.expressions.ControlStructureTypingUtils.resolveSpecialConstructionAsCall;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*;
@@ -122,39 +119,21 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return facade.getTypeInfo(innerExpression, context.replaceScope(context.scope), isStatement);
}
private static JetTypeInfo createNumberValueTypeInfo(
@NotNull NumberValueTypeConstructor numberValueTypeConstructor,
@NotNull Number value,
@NotNull DataFlowInfo dataFlowInfo
) {
return JetTypeInfo.create(new JetTypeImpl(
Collections.<AnnotationDescriptor>emptyList(), numberValueTypeConstructor,
false, Collections.<TypeProjection>emptyList(),
ErrorUtils.createErrorScope("Scope for number value type (" + value + ")", true)), dataFlowInfo);
}
@Override
public JetTypeInfo visitConstantExpression(@NotNull JetConstantExpression expression, ExpressionTypingContext context) {
IElementType elementType = expression.getNode().getElementType();
String text = expression.getNode().getText();
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, context.expectedType);
if (noExpectedType(context.expectedType) && context.contextDependency == DEPENDENT) {
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
Long longValue = EvaluatePackage.parseLong(text);
if (longValue != null) {
return createNumberValueTypeInfo(new IntegerValueTypeConstructor(longValue), longValue, context.dataFlowInfo);
}
if (!(value instanceof NumberValueTypeConstant)) {
CompileTimeConstantResolver compileTimeConstantResolver = context.getCompileTimeConstantResolver();
boolean hasError = compileTimeConstantResolver.checkConstantExpressionType(value, expression, context.expectedType);
if (hasError) {
IElementType elementType = expression.getNode().getElementType();
return JetTypeInfo.create(getDefaultType(elementType), context.dataFlowInfo);
}
}
CompileTimeConstantResolver compileTimeConstantResolver = context.getCompileTimeConstantResolver();
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, context.expectedType);
boolean hasError = compileTimeConstantResolver.checkConstantExpressionType(value, expression, context.expectedType);
if (hasError) {
return JetTypeInfo.create(getDefaultType(elementType), context.dataFlowInfo);
}
assert value != null : "CompileTimeConstant should be evaluated for constant expression or an error should be recorded " + expression.getText();
return DataFlowUtils.checkType(value.getType(builtIns), expression, context, context.dataFlowInfo);
return createCompileTimeConstantTypeInfo(value, expression, context);
}
@Override
@@ -715,9 +694,31 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else {
result = returnType;
}
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, contextWithExpectedType.trace,
contextWithExpectedType.expectedType);
if (value != null) {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return DataFlowUtils.checkType(result, expression, contextWithExpectedType, dataFlowInfo);
}
@NotNull
private static JetTypeInfo createCompileTimeConstantTypeInfo(
@NotNull CompileTimeConstant<?> value,
@NotNull JetExpression expression,
@NotNull ExpressionTypingContext context
) {
JetType expressionType = value.getType(KotlinBuiltIns.getInstance());
if (value instanceof NumberValueTypeConstant && context.contextDependency == INDEPENDENT) {
expressionType = getPrimitiveNumberType(((NumberValueTypeConstant) value).getValue(), context.expectedType);
ArgumentTypeResolver.updateNumberType(expressionType, expression, context.trace);
}
return DataFlowUtils.checkType(expressionType, expression, context, context.dataFlowInfo);
}
private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null;
@@ -21,6 +21,7 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -30,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstant;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInfo;
import org.jetbrains.jet.lang.types.TypeUtils;
@@ -161,13 +163,16 @@ public class DataFlowUtils {
JetExpression expression = JetPsiUtil.safeDeparenthesize(expressionToCheck, false);
recordExpectedType(trace, expression, expectedType);
if (expressionType == null || noExpectedType(expectedType) ||
if (expressionType == null || noExpectedType(expectedType) || !expectedType.getConstructor().isDenotable() ||
JetTypeChecker.INSTANCE.isSubtypeOf(expressionType, expectedType)) {
return expressionType;
}
if (expression instanceof JetConstantExpression) {
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, trace, expectedType);
if (value instanceof NumberValueTypeConstant) {
value = EvaluatePackage.getCompileTimeConstantForNumberType(((NumberValueTypeConstant) value).getValue(), expectedType);
}
new CompileTimeConstantResolver(trace, true).checkConstantExpressionType(value, (JetConstantExpression) expression, expectedType);
return expressionType;
}