Support plus, minus, div, mod, multiply in ConstantExpressionEvaluator
This commit is contained in:
+128
-26
@@ -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();
|
||||
|
||||
+255
-1
@@ -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)) {
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user