Support plus, minus, div, mod, multiply in ConstantExpressionEvaluator

This commit is contained in:
Natalia Ukhorskaya
2013-11-08 12:09:54 +04:00
parent 50d29e0526
commit 41387c3544
21 changed files with 725 additions and 92 deletions
@@ -20,6 +20,8 @@ import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
@@ -28,8 +30,11 @@ import org.jetbrains.jet.lang.resolve.constants.*;
import org.jetbrains.jet.lang.resolve.constants.StringValue;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
@@ -132,35 +137,105 @@ public class ConstantExpressionEvaluator extends JetVisitor<CompileTimeConstant<
if (leftExpression == null) {
return null;
}
JetExpression rightExpression = expression.getRight();
if (rightExpression == null) {
return null;
}
return getCallConstant(expression.getOperationReference(), leftExpression);
}
CompileTimeConstant<?> leftConstant = leftExpression.accept(this, data);
if (leftConstant == null) {
return null;
}
CompileTimeConstant<?> rightConstant = rightExpression.accept(this, data);
if (rightConstant == null) {
return null;
}
ResolvedCall<? extends CallableDescriptor> resolvedCall = trace.getBindingContext().get(RESOLVED_CALL, expression.getOperationReference());
@Nullable
private CompileTimeConstant<?> getCallConstant(@NotNull JetExpression resolvedCallExpression, @NotNull JetExpression receiverExpression) {
ResolvedCall<?> resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, resolvedCallExpression);
if (resolvedCall != null) {
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
Object value = EvaluatePackage.evaluateBinaryExpression(leftConstant, rightConstant, resultingDescriptor.getName());
if (value != null) {
return createCompileTimeConstant(value);
JetType receiverExpressionType = getReceiverExpressionType(resolvedCall);
if (receiverExpressionType == null) {
return null;
}
ConstantExpressionEvaluator evaluator = new ConstantExpressionEvaluator(trace, receiverExpressionType);
CompileTimeConstant<?> receiverValue = receiverExpression.accept(evaluator, null);
if (receiverValue == null) {
return null;
}
List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry : resolvedCall.getValueArguments() .entrySet()) {
arguments.addAll(resolveArguments(argumentEntry.getValue().getArguments(), argumentEntry.getKey().getType(), trace));
}
return ConstantsPackage.resolveCallToCompileTimeValue(resultingDescriptor.getName(), receiverValue, arguments, expectedType);
}
return null;
}
public static CompileTimeConstant<?> createCompileTimeConstant(@NotNull Object value, @NotNull JetType expectedType) {
if (value instanceof Integer) {
return getIntegerValue(((Integer) value).longValue(), expectedType);
}
else if (value instanceof Byte) {
return getIntegerValue(((Byte) value).longValue(), expectedType);
}
else if (value instanceof Short) {
return getIntegerValue(((Short) value).longValue(), expectedType);
}
else if (value instanceof Long) {
return new LongValue((Long) value);
}
else if (value instanceof Float) {
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType) ||
expectedType.equals(KotlinBuiltIns.getInstance().getDoubleType())) {
return new DoubleValue(((Float) value).doubleValue());
}
else {
return new FloatValue((Float) value);
}
}
else if (value instanceof Double) {
return new DoubleValue((Double) value);
}
else if (value instanceof Boolean) {
return ((Boolean) value) ? BooleanValue.TRUE : BooleanValue.FALSE;
}
else if (value instanceof Character) {
return new CharValue((Character) value);
}
else if (value instanceof String) {
return new StringValue((String) value);
}
return null;
}
private static CompileTimeConstant<?> createCompileTimeConstant(@NotNull Object value) {
if (value instanceof String) {
return new StringValue((String) value);
@Nullable
private static CompileTimeConstant<?> getIntegerValue(@NotNull Long value, @NotNull JetType expectedType) {
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
return new IntValue(value.intValue());
}
return new LongValue(value);
}
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
if (expectedType.equals(builtIns.getIntType())) {
return new IntValue(value.intValue());
}
else if (expectedType.equals(builtIns.getLongType())) {
return new LongValue(value);
}
else if (expectedType.equals(builtIns.getShortType())) {
if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE) {
return new ShortValue(value.shortValue());
}
else if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
return new IntValue(value.intValue());
}
return new LongValue(value);
}
else if (expectedType.equals(builtIns.getByteType())) {
if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE) {
return new ByteValue(value.byteValue());
}
else if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
return new IntValue(value.intValue());
}
return new LongValue(value);
}
else if (expectedType.equals(builtIns.getCharType())) {
return new IntValue(value.intValue());
}
return null;
}
@@ -187,14 +262,26 @@ public class ConstantExpressionEvaluator extends JetVisitor<CompileTimeConstant<
return null;
}
/* 1.toInt(); 1.plus(1); MyEnum.A */
@Override
public CompileTimeConstant<?> visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
CompileTimeConstant wholeExpressionValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
if (wholeExpressionValue != null) {
return wholeExpressionValue;
}
JetExpression receiverExpression = expression.getReceiverExpression();
JetExpression selectorExpression = expression.getSelectorExpression();
if (receiverExpression instanceof JetConstantExpression && selectorExpression instanceof JetCallExpression) {
CompileTimeConstant<?> constant = ConstantsPackage.propagateConstantValues(expression, trace, (JetCallExpression) selectorExpression);
if (constant != null) {
return constant;
if (selectorExpression instanceof JetCallExpression) {
JetExpression calleeExpression = ((JetCallExpression) selectorExpression).getCalleeExpression();
if (!(calleeExpression instanceof JetSimpleNameExpression)) {
return null;
}
if (((JetCallExpression) selectorExpression).getValueArguments().size() < 2) {
return getCallConstant(calleeExpression, receiverExpression);
}
}
@@ -204,6 +291,17 @@ public class ConstantExpressionEvaluator extends JetVisitor<CompileTimeConstant<
return super.visitQualifiedExpression(expression, data);
}
@Nullable
private static JetType getReceiverExpressionType(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
switch(resolvedCall.getExplicitReceiverKind()) {
case THIS_OBJECT: return resolvedCall.getThisObject().getType();
case RECEIVER_ARGUMENT: return resolvedCall.getReceiverArgument().getType();
case NO_EXPLICIT_RECEIVER: return null;
case BOTH_RECEIVERS: return null;
}
return null;
}
@Override
public CompileTimeConstant<?> visitCallExpression(@NotNull JetCallExpression expression, Void data) {
ResolvedCall<? extends CallableDescriptor> call =
@@ -238,7 +336,11 @@ public class ConstantExpressionEvaluator extends JetVisitor<CompileTimeConstant<
}
@NotNull
private static List<CompileTimeConstant<?>> resolveArguments(@NotNull List<ValueArgument> valueArguments, @NotNull JetType expectedType, @NotNull BindingTrace trace) {
private static List<CompileTimeConstant<?>> resolveArguments(
@NotNull List<ValueArgument> valueArguments,
@NotNull JetType expectedType,
@NotNull BindingTrace trace
) {
List<CompileTimeConstant<?>> constants = Lists.newArrayList();
for (ValueArgument argument : valueArguments) {
JetExpression argumentExpression = argument.getArgumentExpression();
@@ -59,6 +59,260 @@ private val binaryOperations = hashMapOf<BinaryOperation<*, *>, (Any?, Any?) ->
bOp(STRING, LONG, "plus", { a, b -> a + b }),
bOp(STRING, DOUBLE, "plus", { a, b -> a + b }),
bOp(STRING, FLOAT, "plus", { a, b -> a + b }),
bOp(STRING, CHAR, "plus", { a, b -> a + b })
bOp(STRING, CHAR, "plus", { a, b -> a + b }),
// Byte
bOp(BYTE, DOUBLE, "plus", { a, b -> a + b }),
bOp(BYTE, FLOAT, "plus", { a, b -> a + b }),
bOp(BYTE, LONG, "plus", { a, b -> a + b }),
bOp(BYTE, INT, "plus", { a, b -> a + b }),
bOp(BYTE, SHORT, "plus", { a, b -> a + b }),
bOp(BYTE, BYTE, "plus", { a, b -> a + b }),
bOp(BYTE, CHAR, "plus", { a, b -> a + b }),
bOp(BYTE, DOUBLE, "minus", { a, b -> a - b }),
bOp(BYTE, FLOAT, "minus", { a, b -> a - b }),
bOp(BYTE, LONG, "minus", { a, b -> a - b }),
bOp(BYTE, INT, "minus", { a, b -> a - b }),
bOp(BYTE, SHORT, "minus", { a, b -> a - b }),
bOp(BYTE, BYTE, "minus", { a, b -> a - b }),
bOp(BYTE, CHAR, "minus", { a, b -> a - b }),
bOp(BYTE, DOUBLE, "times", { a, b -> a * b }),
bOp(BYTE, FLOAT, "times", { a, b -> a * b }),
bOp(BYTE, LONG, "times", { a, b -> a * b }),
bOp(BYTE, INT, "times", { a, b -> a * b }),
bOp(BYTE, SHORT, "times", { a, b -> a * b }),
bOp(BYTE, BYTE, "times", { a, b -> a * b }),
bOp(BYTE, CHAR, "times", { a, b -> a * b }),
bOp(BYTE, DOUBLE, "div", { a, b -> a / b }),
bOp(BYTE, FLOAT, "div", { a, b -> a / b }),
bOp(BYTE, LONG, "div", { a, b -> a / b }),
bOp(BYTE, INT, "div", { a, b -> a / b }),
bOp(BYTE, SHORT, "div", { a, b -> a / b }),
bOp(BYTE, BYTE, "div", { a, b -> a / b }),
bOp(BYTE, CHAR, "div", { a, b -> a / b }),
bOp(BYTE, DOUBLE, "mod", { a, b -> a % b }),
bOp(BYTE, FLOAT, "mod", { a, b -> a % b }),
bOp(BYTE, LONG, "mod", { a, b -> a % b }),
bOp(BYTE, INT, "mod", { a, b -> a % b }),
bOp(BYTE, SHORT, "mod", { a, b -> a % b }),
bOp(BYTE, BYTE, "mod", { a, b -> a % b }),
bOp(BYTE, CHAR, "mod", { a, b -> a % b }),
// Short
bOp(SHORT, DOUBLE, "plus", { a, b -> a + b }),
bOp(SHORT, FLOAT, "plus", { a, b -> a + b }),
bOp(SHORT, LONG, "plus", { a, b -> a + b }),
bOp(SHORT, INT, "plus", { a, b -> a + b }),
bOp(SHORT, SHORT, "plus", { a, b -> a + b }),
bOp(SHORT, BYTE, "plus", { a, b -> a + b }),
bOp(SHORT, CHAR, "plus", { a, b -> a + b }),
bOp(SHORT, DOUBLE, "minus", { a, b -> a - b }),
bOp(SHORT, FLOAT, "minus", { a, b -> a - b }),
bOp(SHORT, LONG, "minus", { a, b -> a - b }),
bOp(SHORT, INT, "minus", { a, b -> a - b }),
bOp(SHORT, SHORT, "minus", { a, b -> a - b }),
bOp(SHORT, BYTE, "minus", { a, b -> a - b }),
bOp(SHORT, CHAR, "minus", { a, b -> a - b }),
bOp(SHORT, DOUBLE, "times", { a, b -> a * b }),
bOp(SHORT, FLOAT, "times", { a, b -> a * b }),
bOp(SHORT, LONG, "times", { a, b -> a * b }),
bOp(SHORT, INT, "times", { a, b -> a * b }),
bOp(SHORT, SHORT, "times", { a, b -> a * b }),
bOp(SHORT, BYTE, "times", { a, b -> a * b }),
bOp(SHORT, CHAR, "times", { a, b -> a * b }),
bOp(SHORT, DOUBLE, "div", { a, b -> a / b }),
bOp(SHORT, FLOAT, "div", { a, b -> a / b }),
bOp(SHORT, LONG, "div", { a, b -> a / b }),
bOp(SHORT, INT, "div", { a, b -> a / b }),
bOp(SHORT, SHORT, "div", { a, b -> a / b }),
bOp(SHORT, BYTE, "div", { a, b -> a / b }),
bOp(SHORT, CHAR, "div", { a, b -> a / b }),
bOp(SHORT, DOUBLE, "mod", { a, b -> a % b }),
bOp(SHORT, FLOAT, "mod", { a, b -> a % b }),
bOp(SHORT, LONG, "mod", { a, b -> a % b }),
bOp(SHORT, INT, "mod", { a, b -> a % b }),
bOp(SHORT, SHORT, "mod", { a, b -> a % b }),
bOp(SHORT, BYTE, "mod", { a, b -> a % b }),
bOp(SHORT, CHAR, "mod", { a, b -> a % b }),
// Int
bOp(INT, DOUBLE, "plus", { a, b -> a + b }),
bOp(INT, FLOAT, "plus", { a, b -> a + b }),
bOp(INT, LONG, "plus", { a, b -> a + b }),
bOp(INT, INT, "plus", { a, b -> a + b }),
bOp(INT, SHORT, "plus", { a, b -> a + b }),
bOp(INT, BYTE, "plus", { a, b -> a + b }),
bOp(INT, CHAR, "plus", { a, b -> a + b }),
bOp(INT, DOUBLE, "minus", { a, b -> a - b }),
bOp(INT, FLOAT, "minus", { a, b -> a - b }),
bOp(INT, LONG, "minus", { a, b -> a - b }),
bOp(INT, INT, "minus", { a, b -> a - b }),
bOp(INT, SHORT, "minus", { a, b -> a - b }),
bOp(INT, BYTE, "minus", { a, b -> a - b }),
bOp(INT, CHAR, "minus", { a, b -> a - b }),
bOp(INT, DOUBLE, "times", { a, b -> a * b }),
bOp(INT, FLOAT, "times", { a, b -> a * b }),
bOp(INT, LONG, "times", { a, b -> a * b }),
bOp(INT, INT, "times", { a, b -> a * b }),
bOp(INT, SHORT, "times", { a, b -> a * b }),
bOp(INT, BYTE, "times", { a, b -> a * b }),
bOp(INT, CHAR, "times", { a, b -> a * b }),
bOp(INT, DOUBLE, "div", { a, b -> a / b }),
bOp(INT, FLOAT, "div", { a, b -> a / b }),
bOp(INT, LONG, "div", { a, b -> a / b }),
bOp(INT, INT, "div", { a, b -> a / b }),
bOp(INT, SHORT, "div", { a, b -> a / b }),
bOp(INT, BYTE, "div", { a, b -> a / b }),
bOp(INT, CHAR, "div", { a, b -> a / b }),
bOp(INT, DOUBLE, "mod", { a, b -> a % b }),
bOp(INT, FLOAT, "mod", { a, b -> a % b }),
bOp(INT, LONG, "mod", { a, b -> a % b }),
bOp(INT, INT, "mod", { a, b -> a % b }),
bOp(INT, SHORT, "mod", { a, b -> a % b }),
bOp(INT, BYTE, "mod", { a, b -> a % b }),
bOp(INT, CHAR, "mod", { a, b -> a % b }),
// Long
bOp(LONG, DOUBLE, "plus", { a, b -> a + b }),
bOp(LONG, FLOAT, "plus", { a, b -> a + b }),
bOp(LONG, LONG, "plus", { a, b -> a + b }),
bOp(LONG, INT, "plus", { a, b -> a + b }),
bOp(LONG, SHORT, "plus", { a, b -> a + b }),
bOp(LONG, BYTE, "plus", { a, b -> a + b }),
bOp(LONG, CHAR, "plus", { a, b -> a + b }),
bOp(LONG, DOUBLE, "minus", { a, b -> a - b }),
bOp(LONG, FLOAT, "minus", { a, b -> a - b }),
bOp(LONG, LONG, "minus", { a, b -> a - b }),
bOp(LONG, INT, "minus", { a, b -> a - b }),
bOp(LONG, SHORT, "minus", { a, b -> a - b }),
bOp(LONG, BYTE, "minus", { a, b -> a - b }),
bOp(LONG, CHAR, "minus", { a, b -> a - b }),
bOp(LONG, DOUBLE, "times", { a, b -> a * b }),
bOp(LONG, FLOAT, "times", { a, b -> a * b }),
bOp(LONG, LONG, "times", { a, b -> a * b }),
bOp(LONG, INT, "times", { a, b -> a * b }),
bOp(LONG, SHORT, "times", { a, b -> a * b }),
bOp(LONG, BYTE, "times", { a, b -> a * b }),
bOp(LONG, CHAR, "times", { a, b -> a * b }),
bOp(LONG, DOUBLE, "div", { a, b -> a / b }),
bOp(LONG, FLOAT, "div", { a, b -> a / b }),
bOp(LONG, LONG, "div", { a, b -> a / b }),
bOp(LONG, INT, "div", { a, b -> a / b }),
bOp(LONG, SHORT, "div", { a, b -> a / b }),
bOp(LONG, BYTE, "div", { a, b -> a / b }),
bOp(LONG, CHAR, "div", { a, b -> a / b }),
bOp(LONG, DOUBLE, "mod", { a, b -> a % b }),
bOp(LONG, FLOAT, "mod", { a, b -> a % b }),
bOp(LONG, LONG, "mod", { a, b -> a % b }),
bOp(LONG, INT, "mod", { a, b -> a % b }),
bOp(LONG, SHORT, "mod", { a, b -> a % b }),
bOp(LONG, BYTE, "mod", { a, b -> a % b }),
bOp(LONG, CHAR, "mod", { a, b -> a % b }),
// Double
bOp(DOUBLE, DOUBLE, "plus", { a, b -> a + b }),
bOp(DOUBLE, FLOAT, "plus", { a, b -> a + b }),
bOp(DOUBLE, LONG, "plus", { a, b -> a + b }),
bOp(DOUBLE, INT, "plus", { a, b -> a + b }),
bOp(DOUBLE, SHORT, "plus", { a, b -> a + b }),
bOp(DOUBLE, BYTE, "plus", { a, b -> a + b }),
bOp(DOUBLE, CHAR, "plus", { a, b -> a + b }),
bOp(DOUBLE, DOUBLE, "minus", { a, b -> a - b }),
bOp(DOUBLE, FLOAT, "minus", { a, b -> a - b }),
bOp(DOUBLE, LONG, "minus", { a, b -> a - b }),
bOp(DOUBLE, INT, "minus", { a, b -> a - b }),
bOp(DOUBLE, SHORT, "minus", { a, b -> a - b }),
bOp(DOUBLE, BYTE, "minus", { a, b -> a - b }),
bOp(DOUBLE, CHAR, "minus", { a, b -> a - b }),
bOp(DOUBLE, DOUBLE, "times", { a, b -> a * b }),
bOp(DOUBLE, FLOAT, "times", { a, b -> a * b }),
bOp(DOUBLE, LONG, "times", { a, b -> a * b }),
bOp(DOUBLE, INT, "times", { a, b -> a * b }),
bOp(DOUBLE, SHORT, "times", { a, b -> a * b }),
bOp(DOUBLE, BYTE, "times", { a, b -> a * b }),
bOp(DOUBLE, CHAR, "times", { a, b -> a * b }),
bOp(DOUBLE, DOUBLE, "div", { a, b -> a / b }),
bOp(DOUBLE, FLOAT, "div", { a, b -> a / b }),
bOp(DOUBLE, LONG, "div", { a, b -> a / b }),
bOp(DOUBLE, INT, "div", { a, b -> a / b }),
bOp(DOUBLE, SHORT, "div", { a, b -> a / b }),
bOp(DOUBLE, BYTE, "div", { a, b -> a / b }),
bOp(DOUBLE, CHAR, "div", { a, b -> a / b }),
bOp(DOUBLE, DOUBLE, "mod", { a, b -> a % b }),
bOp(DOUBLE, FLOAT, "mod", { a, b -> a % b }),
bOp(DOUBLE, LONG, "mod", { a, b -> a % b }),
bOp(DOUBLE, INT, "mod", { a, b -> a % b }),
bOp(DOUBLE, SHORT, "mod", { a, b -> a % b }),
bOp(DOUBLE, BYTE, "mod", { a, b -> a % b }),
// Float
bOp(FLOAT, DOUBLE, "plus", { a, b -> a + b }),
bOp(FLOAT, FLOAT, "plus", { a, b -> a + b }),
bOp(FLOAT, LONG, "plus", { a, b -> a + b }),
bOp(FLOAT, INT, "plus", { a, b -> a + b }),
bOp(FLOAT, SHORT, "plus", { a, b -> a + b }),
bOp(FLOAT, BYTE, "plus", { a, b -> a + b }),
bOp(FLOAT, CHAR, "plus", { a, b -> a + b }),
bOp(FLOAT, DOUBLE, "minus", { a, b -> a - b }),
bOp(FLOAT, FLOAT, "minus", { a, b -> a - b }),
bOp(FLOAT, LONG, "minus", { a, b -> a - b }),
bOp(FLOAT, INT, "minus", { a, b -> a - b }),
bOp(FLOAT, SHORT, "minus", { a, b -> a - b }),
bOp(FLOAT, BYTE, "minus", { a, b -> a - b }),
bOp(FLOAT, CHAR, "minus", { a, b -> a - b }),
bOp(FLOAT, DOUBLE, "times", { a, b -> a * b }),
bOp(FLOAT, FLOAT, "times", { a, b -> a * b }),
bOp(FLOAT, LONG, "times", { a, b -> a * b }),
bOp(FLOAT, INT, "times", { a, b -> a * b }),
bOp(FLOAT, SHORT, "times", { a, b -> a * b }),
bOp(FLOAT, BYTE, "times", { a, b -> a * b }),
bOp(FLOAT, CHAR, "times", { a, b -> a * b }),
bOp(FLOAT, DOUBLE, "div", { a, b -> a / b }),
bOp(FLOAT, FLOAT, "div", { a, b -> a / b }),
bOp(FLOAT, LONG, "div", { a, b -> a / b }),
bOp(FLOAT, INT, "div", { a, b -> a / b }),
bOp(FLOAT, SHORT, "div", { a, b -> a / b }),
bOp(FLOAT, BYTE, "div", { a, b -> a / b }),
bOp(FLOAT, CHAR, "div", { a, b -> a / b }),
bOp(FLOAT, DOUBLE, "mod", { a, b -> a % b }),
bOp(FLOAT, FLOAT, "mod", { a, b -> a % b }),
bOp(FLOAT, LONG, "mod", { a, b -> a % b }),
bOp(FLOAT, INT, "mod", { a, b -> a % b }),
bOp(FLOAT, SHORT, "mod", { a, b -> a % b }),
bOp(FLOAT, BYTE, "mod", { a, b -> a % b }),
bOp(FLOAT, CHAR, "mod", { a, b -> a % b }),
// Char
bOp(CHAR, DOUBLE, "plus", { a, b -> a + b }),
bOp(CHAR, FLOAT, "plus", { a, b -> a + b }),
bOp(CHAR, LONG, "plus", { a, b -> a + b }),
bOp(CHAR, INT, "plus", { a, b -> a + b }),
bOp(CHAR, SHORT, "plus", { a, b -> a + b }),
bOp(CHAR, BYTE, "plus", { a, b -> a + b }),
bOp(CHAR, DOUBLE, "minus", { a, b -> a - b }),
bOp(CHAR, FLOAT, "minus", { a, b -> a - b }),
bOp(CHAR, LONG, "minus", { a, b -> a - b }),
bOp(CHAR, INT, "minus", { a, b -> a - b }),
bOp(CHAR, SHORT, "minus", { a, b -> a - b }),
bOp(CHAR, BYTE, "minus", { a, b -> a - b }),
bOp(CHAR, CHAR, "minus", { a, b -> a - b }),
bOp(CHAR, DOUBLE, "times", { a, b -> a * b }),
bOp(CHAR, FLOAT, "times", { a, b -> a * b }),
bOp(CHAR, LONG, "times", { a, b -> a * b }),
bOp(CHAR, INT, "times", { a, b -> a * b }),
bOp(CHAR, SHORT, "times", { a, b -> a * b }),
bOp(CHAR, BYTE, "times", { a, b -> a * b }),
bOp(CHAR, DOUBLE, "div", { a, b -> a / b }),
bOp(CHAR, FLOAT, "div", { a, b -> a / b }),
bOp(CHAR, LONG, "div", { a, b -> a / b }),
bOp(CHAR, INT, "div", { a, b -> a / b }),
bOp(CHAR, SHORT, "div", { a, b -> a / b }),
bOp(CHAR, BYTE, "div", { a, b -> a / b }),
bOp(CHAR, DOUBLE, "mod", { a, b -> a % b }),
bOp(CHAR, FLOAT, "mod", { a, b -> a % b }),
bOp(CHAR, LONG, "mod", { a, b -> a % b }),
bOp(CHAR, INT, "mod", { a, b -> a % b }),
bOp(CHAR, SHORT, "mod", { a, b -> a % b }),
bOp(CHAR, BYTE, "mod", { a, b -> a % b })
)
@@ -34,7 +34,6 @@ 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.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;
@@ -422,10 +421,6 @@ public class CallExpressionResolver {
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)) {
@@ -347,7 +347,7 @@ public class CompileTimeConstantResolver {
return createErrorValue(NULL_FOR_NONNULL_TYPE.on(expression, expectedType));
}
private static boolean noExpectedTypeOrError(JetType expectedType) {
public static boolean noExpectedTypeOrError(JetType expectedType) {
return TypeUtils.noExpectedType(expectedType) || expectedType.isError();
}
@@ -16,71 +16,56 @@
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
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.evaluate.evaluateBinaryExpression
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator
import org.jetbrains.jet.lang.types.JetType
public fun propagateConstantValues(expression : JetQualifiedExpression, trace : BindingTrace, selectorExpression : JetCallExpression): CompileTimeConstant<out Any>? {
val wholeExpressionValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression)
if (wholeExpressionValue != null) {
return null
}
val receiverExpression = expression.getReceiverExpression()
val receiverValue = trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression)
if (receiverValue == null || receiverValue is ErrorValue) {
return null
}
val calleeExpression = selectorExpression.getCalleeExpression()
if (calleeExpression !is JetSimpleNameExpression) {
return null
}
val declarationDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, calleeExpression)
if (declarationDescriptor !is FunctionDescriptor) {
return null
}
val returnType = declarationDescriptor.getReturnType()
if (returnType == null || !KotlinBuiltIns.getInstance().isPrimitiveType(returnType)) {
return null
}
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())
public fun resolveCallToCompileTimeValue(
callName: Name,
receiverValue: CompileTimeConstant<*>,
arguments: Collection<CompileTimeConstant<*>>,
expectedType: JetType
): CompileTimeConstant<*>? {
if (arguments.isEmpty()) {
val value = receiverValue.getValue()
return when (value) {
is Number -> {
when(callName) {
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())
else -> null
}
}
}
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())
is Char -> {
when(callName) {
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
}
}
else -> null
}
else -> null
}
else if (arguments.size() == 1) {
val result = evaluateBinaryExpression(receiverValue, arguments.iterator().next(), callName)
if (result == null) {
return null
}
return ConstantExpressionEvaluator.createCompileTimeConstant(result, expectedType)
}
return compileTimeValue
return null
}
@@ -0,0 +1,7 @@
package test
annotation class Ann(val c1: Char)
Ann('a' - 'a') class MyClass
// EXPECTED: Ann[c1 = 0.toInt(): jet.Int]
@@ -0,0 +1,11 @@
package test
annotation class Ann(
val p1: Int,
val p2: Int,
val p3: Int
)
Ann(1.toInt().plus(1), 1.minus(1.toInt()), 1.toInt().times(1.toInt())) class MyClass
// EXPECTED: Ann[p1 = 2.toInt(): jet.Int, p2 = 0.toInt(): jet.Int, p3 = 1.toInt(): jet.Int]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
Ann(1 / 1, 1 / 1, 1 / 1, 1 / 1) class MyClass
// EXPECTED: Ann[b = 1.toByte(): jet.Byte, i = 1.toInt(): jet.Int, l = 1.toLong(): jet.Long, s = 1.toShort(): jet.Short]
@@ -0,0 +1,11 @@
package test
annotation class Ann(
val d1: Double,
val d2: Double,
val d3: Double
)
Ann(1.0 + 1.0, 1.0 + 1, 1 + 1.0) class MyClass
// EXPECTED: Ann[d1 = 2.0.toDouble(): jet.Double, d2 = 2.0.toDouble(): jet.Double, d3 = 2.0.toDouble(): jet.Double]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val d1: Float,
val d2: Float,
val d3: Double
)
Ann(1.toFloat() + 1.toFloat(), 1.toFloat() + 1, 1.toFloat() + 1.0) class MyClass
// EXPECTED: Ann[d1 = 2.0.toFloat(): jet.Float, d2 = 2.0.toFloat(): jet.Float, d3 = 2.0.toDouble(): jet.Double]
@@ -0,0 +1,13 @@
package test
annotation class Ann(
val p1: Int,
val p2: Int,
val p3: Int,
val p4: Int,
val p5: Int
)
Ann(1 plus 1, 1 minus 1, 1 times 1, 1 div 1, 1 mod 1) class MyClass
// EXPECTED: Ann[p1 = 2.toInt(): jet.Int, p2 = 0.toInt(): jet.Int, p3 = 1.toInt(): jet.Int, p4 = 1.toInt(): jet.Int, p5 = 0.toInt(): jet.Int]
@@ -0,0 +1,11 @@
package test
annotation class Ann(
val l1: Long,
val l2: Long,
val l3: Long
)
Ann(1 + 1, java.lang.Long.MAX_VALUE + 1 - 1, java.lang.Long.MAX_VALUE - 1) class MyClass
// EXPECTED: Ann[l1 = 2.toLong(): jet.Long, l2 = 9223372036854775807.toLong(): jet.Long, l3 = 9223372036854775806.toLong(): jet.Long]
@@ -0,0 +1,21 @@
package test
annotation class Ann(
val p1: Byte,
val p2: Short,
val p3: Int,
val p4: Int,
val p5: Long,
val p6: Long
)
Ann(
p1 = java.lang.Byte.MAX_VALUE + 1,
p2 = java.lang.Short.MAX_VALUE + 1,
p3 = java.lang.Integer.MAX_VALUE + 1,
p4 = java.lang.Integer.MAX_VALUE + 1,
p5 = java.lang.Integer.MAX_VALUE + 1.toLong(),
p6 = java.lang.Long.MAX_VALUE + 1
) class MyClass
// EXPECTED: Ann[p1 = 128.toInt(): jet.Int, p2 = 32768.toInt(): jet.Int, p3 = -2147483648.toInt(): jet.Int, p4 = -2147483648.toInt(): jet.Int, p5 = 2147483648.toLong(): jet.Long, p6 = -9223372036854775808.toLong(): jet.Long]
@@ -0,0 +1,19 @@
package test
annotation class Ann(
val p1: Byte,
val p2: Byte,
val p3: Int,
val p4: Int,
val p5: Byte
)
Ann(
p1 = java.lang.Byte.MAX_VALUE + 1,
p2 = 1 + 1,
p3 = java.lang.Byte.MAX_VALUE + 1,
p4 = 1.toByte() + 1.toByte(),
p5 = 1.toByte() + 1.toByte()
) class MyClass
// EXPECTED: Ann[p1 = 128.toInt(): jet.Int, p2 = 2.toByte(): jet.Byte, p3 = 128.toInt(): jet.Int, p4 = 2.toInt(): jet.Int, p5 = 2.toByte(): jet.Byte]
@@ -0,0 +1,19 @@
package test
annotation class Ann(
val p1: Int,
val p2: Int,
val p3: Long,
val p4: Long,
val p5: Int
)
Ann(
p1 = java.lang.Integer.MAX_VALUE + 1,
p2 = 1 + 1,
p3 = java.lang.Integer.MAX_VALUE + 1,
p4 = 1.toInt() + 1.toInt(),
p5 = 1.toInt() + 1.toInt()
) class MyClass
// EXPECTED: Ann[p1 = -2147483648.toInt(): jet.Int, p2 = 2.toInt(): jet.Int, p3 = -2147483648.toLong(): jet.Long, p4 = 2.toLong(): jet.Long, p5 = 2.toInt(): jet.Int]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
Ann(1 * 1, 1 * 1, 1 * 1, 1 * 1) class MyClass
// EXPECTED: Ann[b = 1.toByte(): jet.Byte, i = 1.toInt(): jet.Int, l = 1.toLong(): jet.Long, s = 1.toShort(): jet.Short]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
Ann(1 - 1, 1 - 1, 1 - 1, 1 - 1) class MyClass
// EXPECTED: Ann[b = 0.toByte(): jet.Byte, i = 0.toInt(): jet.Int, l = 0.toLong(): jet.Long, s = 0.toShort(): jet.Short]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
Ann(1 % 1, 1 % 1, 1 % 1, 1 % 1) class MyClass
// EXPECTED: Ann[b = 0.toByte(): jet.Byte, i = 0.toInt(): jet.Int, l = 0.toLong(): jet.Long, s = 0.toShort(): jet.Short]
@@ -0,0 +1,12 @@
package test
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
Ann(1 + 1, 1 + 1, 1 + 1, 1 + 1) class MyClass
// EXPECTED: Ann[b = 2.toByte(): jet.Byte, i = 2.toInt(): jet.Int, l = 2.toLong(): jet.Long, s = 2.toShort(): jet.Short]
@@ -0,0 +1,13 @@
package test
annotation class Ann(
val p1: Int,
val p2: Int,
val p3: Int,
val p4: Int,
val p5: Int
)
Ann(1.plus(1), 1.minus(1), 1.times(1), 1.div(1), 1.mod(1)) class MyClass
// EXPECTED: Ann[p1 = 2.toInt(): jet.Int, p2 = 0.toInt(): jet.Int, p3 = 1.toInt(): jet.Int, p4 = 1.toInt(): jet.Int, p5 = 0.toInt(): jet.Int]
@@ -78,16 +78,116 @@ public class AnnotationParameterTestGenerated extends AbstractAnnotationParamete
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolveAnnotations/parameters/expressions"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("char.kt")
public void testChar() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/char.kt");
}
@TestMetadata("compositeCallBinary.kt")
public void testCompositeCallBinary() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/compositeCallBinary.kt");
}
@TestMetadata("divide.kt")
public void testDivide() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/divide.kt");
}
@TestMetadata("double.kt")
public void testDouble() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/double.kt");
}
@TestMetadata("eqeq.kt")
public void testEqeq() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/eqeq.kt");
}
@TestMetadata("escapedString.kt")
public void testEscapedString() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/escapedString.kt");
}
@TestMetadata("float.kt")
public void testFloat() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/float.kt");
}
@TestMetadata("gt.kt")
public void testGt() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/gt.kt");
}
@TestMetadata("gteq.kt")
public void testGteq() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/gteq.kt");
}
@TestMetadata("infixCallBinary.kt")
public void testInfixCallBinary() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/infixCallBinary.kt");
}
@TestMetadata("long.kt")
public void testLong() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/long.kt");
}
@TestMetadata("lt.kt")
public void testLt() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/lt.kt");
}
@TestMetadata("lteq.kt")
public void testLteq() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/lteq.kt");
}
@TestMetadata("maxValue.kt")
public void testMaxValue() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/maxValue.kt");
}
@TestMetadata("maxValueByte.kt")
public void testMaxValueByte() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/maxValueByte.kt");
}
@TestMetadata("maxValueInt.kt")
public void testMaxValueInt() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/maxValueInt.kt");
}
@TestMetadata("miltiply.kt")
public void testMiltiply() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/miltiply.kt");
}
@TestMetadata("minus.kt")
public void testMinus() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/minus.kt");
}
@TestMetadata("mod.kt")
public void testMod() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/mod.kt");
}
@TestMetadata("multilineString.kt")
public void testMultilineString() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/multilineString.kt");
}
@TestMetadata("plus.kt")
public void testPlus() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/plus.kt");
}
@TestMetadata("simpleCallBinary.kt")
public void testSimpleCallBinary() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/simpleCallBinary.kt");
}
@TestMetadata("stringPlusInt.kt")
public void testStringPlusInt() throws Exception {
doTest("compiler/testData/resolveAnnotations/parameters/expressions/stringPlusInt.kt");