Merge ConstantExpressionEvaluator and CompileTimeConstantResolver

This commit is contained in:
Natalia Ukhorskaya
2013-11-22 16:13:26 +04:00
parent e6923ba29e
commit d63f6843c8
55 changed files with 296 additions and 355 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator
import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -581,8 +582,7 @@ public class JetControlFlowProcessor {
}
boolean conditionIsTrueConstant = false;
if (condition instanceof JetConstantExpression && condition.getNode().getElementType() == JetNodeTypes.BOOLEAN_CONSTANT) {
if (BooleanValue.TRUE == new CompileTimeConstantResolver().getBooleanValue(
(JetConstantExpression) condition, KotlinBuiltIns.getInstance().getBooleanType())) {
if (BooleanValue.TRUE == ConstantExpressionEvaluator.object$.evaluate(condition, trace, KotlinBuiltIns.getInstance().getBooleanType())) {
conditionIsTrueConstant = true;
}
}
@@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.types.TypeUtils
import java.lang.Short as JShort
import java.lang.Byte as JByte
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.jet.JetNodeTypes
[suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")]
public class ConstantExpressionEvaluator private (val trace: BindingTrace) : JetVisitor<CompileTimeConstant<*>, JetType>() {
@@ -71,7 +72,19 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? {
return trace.get(BindingContext.COMPILE_TIME_VALUE, expression)
val text = expression.getText()
if (text == null) return null
val result: Any? = when (expression.getNode().getElementType()) {
JetNodeTypes.INTEGER_CONSTANT -> CompileTimeConstantResolver.parseLongValue(text)
JetNodeTypes.FLOAT_CONSTANT -> CompileTimeConstantResolver.parseDoubleValue(text)
JetNodeTypes.BOOLEAN_CONSTANT -> CompileTimeConstantResolver.parseBooleanValue(text)
JetNodeTypes.CHARACTER_CONSTANT -> CompileTimeConstantResolver.parseCharValue(text)
JetNodeTypes.NULL -> null
else -> throw IllegalArgumentException("Unsupported constant: " + expression)
}
if (result == null && expression.getNode().getElementType() == JetNodeTypes.NULL) return NullValue.NULL
return createCompileTimeConstant(result, expectedType)
}
override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? {
@@ -164,7 +177,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
else if (argumentsEntrySet.size() == 1) {
val (parameter, argument) = argumentsEntrySet.first()
val argumentForParameter = createOperationArgumentForFristParameter(argument, parameter)
val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter)
if (argumentForParameter == null) return null
val function = binaryOperations[BinaryOperationKey(argumentForReceiver.ctcType, argumentForParameter.ctcType, resultingDescriptorName)]
@@ -258,7 +271,6 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
}
private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: JetType): List<CompileTimeConstant<*>> {
//todo flatMap
val constants = arrayListOf<CompileTimeConstant<*>>()
for (argument in valueArguments) {
val argumentExpression = argument.getArgumentExpression()
@@ -298,7 +310,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet
return OperationArgument(receiverValue, receiverCompileTimeType)
}
private fun createOperationArgumentForFristParameter(argument: ResolvedValueArgument, parameter: ValueParameterDescriptor): OperationArgument? {
private fun createOperationArgumentForFirstParameter(argument: ResolvedValueArgument, parameter: ValueParameterDescriptor): OperationArgument? {
val argumentCompileTimeType = getCompileTimeType(parameter.getType())
if (argumentCompileTimeType == null) return null
@@ -348,44 +360,39 @@ private fun createStringConstant(value: CompileTimeConstant<*>?): StringValue? {
}
}
private fun createCompileTimeConstant(value: Any?, expectedType: JetType?): CompileTimeConstant<*>? {
public fun createCompileTimeConstant(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 Char -> CharValue(value)
is Float -> if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType) ||
expectedType == KotlinBuiltIns.getInstance().getDoubleType()) DoubleValue(value.toDouble())
else FloatValue(value)
is Float -> FloatValue(value)
is Double -> DoubleValue(value)
is Boolean -> if (value) BooleanValue.TRUE else BooleanValue.FALSE
is Boolean -> BooleanValue.valueOf(value)
is String -> StringValue(value)
else -> null
}
}
private fun getIntegerValue(value: Long, expectedType: JetType): CompileTimeConstant<*>? {
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
return IntValue(value.toInt())
}
return LongValue(value)
}
fun defaultIntegerValue(value: Long) = when (value) {
in Integer.MIN_VALUE..Integer.MAX_VALUE.toLong() -> IntValue(value.toInt())
value.toInt().toLong() -> IntValue(value.toInt())
else -> LongValue(value)
}
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
return defaultIntegerValue(value)
}
val builtIns = KotlinBuiltIns.getInstance()
return when (TypeUtils.makeNotNullable(expectedType)) {
builtIns.getIntType() -> IntValue(value.toInt())
builtIns.getLongType() -> LongValue(value)
builtIns.getShortType() -> when (value) {
in JShort.MIN_VALUE..JShort.MAX_VALUE.toLong() -> ShortValue(value.toShort())
value.toShort().toLong() -> ShortValue(value.toShort())
else -> defaultIntegerValue(value)
}
builtIns.getByteType() -> when (value) {
in JByte.MIN_VALUE..JByte.MAX_VALUE.toLong() -> ByteValue(value.toByte())
value.toByte().toLong() -> ByteValue(value.toByte())
else -> defaultIntegerValue(value)
}
builtIns.getCharType() -> IntValue(value.toInt())
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
@@ -22,15 +22,17 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
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.*;
import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstructor;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
@@ -299,11 +301,7 @@ public class ArgumentTypeResolver {
}
return;
}
CompileTimeConstant<?> constant =
new CompileTimeConstantResolver().getCompileTimeConstant((JetConstantExpression) expression, numberType);
if (!(constant instanceof ErrorValue)) {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, constant);
}
ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, numberType);
}
}
@@ -16,19 +16,18 @@
package org.jetbrains.jet.lang.resolve.constants;
import com.google.common.base.Function;
import com.google.common.collect.Sets;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.JetConstantExpression;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeConstructor;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
@@ -38,125 +37,74 @@ import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
public class CompileTimeConstantResolver {
private static final Set<DiagnosticFactory> errorsThatDependOnExpectedType =
Sets.<DiagnosticFactory>newHashSet(CONSTANT_EXPECTED_TYPE_MISMATCH, NULL_FOR_NONNULL_TYPE);
private final KotlinBuiltIns builtIns;
private final BindingTrace trace;
private final boolean checkOnlyErrorsThatDependOnExpectedType;
public CompileTimeConstantResolver() {
public CompileTimeConstantResolver(@NotNull BindingTrace trace, boolean checkOnlyErrorsThatDependOnExpectedType) {
this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType;
this.builtIns = KotlinBuiltIns.getInstance();
this.trace = trace;
}
@Nullable
public Diagnostic checkConstantExpressionType(
@NotNull JetConstantExpression expression,
@NotNull JetType expectedType
) {
CompileTimeConstant<?> compileTimeConstant = getCompileTimeConstant(expression, expectedType);
Set<DiagnosticFactory> errorsThatDependOnExpectedType =
Sets.<DiagnosticFactory>newHashSet(CONSTANT_EXPECTED_TYPE_MISMATCH, NULL_FOR_NONNULL_TYPE);
if (compileTimeConstant instanceof ErrorValueWithDiagnostic) {
Diagnostic diagnostic = ((ErrorValueWithDiagnostic) compileTimeConstant).getDiagnostic();
if (errorsThatDependOnExpectedType.contains(diagnostic.getFactory())) {
return diagnostic;
}
}
return null;
}
@NotNull
public CompileTimeConstant<?> getCompileTimeConstant(
@NotNull JetConstantExpression expression,
@NotNull JetType expectedType
) {
// return true if there is an error
public boolean checkConstantExpressionType(@NotNull JetConstantExpression expression, @NotNull JetType expectedType) {
CompileTimeConstant<?> compileTimeConstant = ConstantExpressionEvaluator.object$.evaluate(expression, trace, expectedType);
IElementType elementType = expression.getNode().getElementType();
CompileTimeConstant<?> value;
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
value = getIntegerValue(expression, expectedType);
return checkIntegerValue(compileTimeConstant, expectedType, expression);
}
else if (elementType == JetNodeTypes.FLOAT_CONSTANT) {
value = getFloatValue(expression, expectedType);
return checkFloatValue(compileTimeConstant, expectedType, expression);
}
else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) {
value = getBooleanValue(expression, expectedType);
return checkBooleanValue(compileTimeConstant, expectedType, expression);
}
else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) {
value = getCharValue(expression, expectedType);
return checkCharValue(compileTimeConstant, expectedType, expression);
}
else if (elementType == JetNodeTypes.NULL) {
value = getNullValue(expression, expectedType);
return checkNullValue(expectedType, expression);
}
else {
throw new IllegalArgumentException("Unsupported constant: " + expression);
}
return value;
return false;
}
@NotNull
public CompileTimeConstant<?> getIntegerValue(
@NotNull JetConstantExpression expression, @NotNull JetType expectedType
) {
String text = expression.getText();
return getIntegerValue(parseLongValue(text), expectedType, expression);
}
@NotNull
public CompileTimeConstant<?> getIntegerValue(
@Nullable Long value,
private boolean checkIntegerValue(
@Nullable CompileTimeConstant value,
@NotNull JetType expectedType,
@NotNull JetConstantExpression expression
) {
if (value == null) {
return createErrorValue(INT_LITERAL_OUT_OF_RANGE.on(expression));
return reportError(INT_LITERAL_OUT_OF_RANGE.on(expression));
}
if (noExpectedTypeOrError(expectedType)) {
if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
return new IntValue(value.intValue());
}
return new LongValue(value);
}
Function<Long, ? extends CompileTimeConstant<?>> create;
long lowerBound;
long upperBound;
TypeConstructor constructor = expectedType.getConstructor();
if (constructor == builtIns.getInt().getTypeConstructor()) {
create = IntValue.CREATE;
lowerBound = Integer.MIN_VALUE;
upperBound = Integer.MAX_VALUE;
}
else if (constructor == builtIns.getLong().getTypeConstructor()) {
create = LongValue.CREATE;
lowerBound = Long.MIN_VALUE;
upperBound = Long.MAX_VALUE;
}
else if (constructor == builtIns.getShort().getTypeConstructor()) {
create = ShortValue.CREATE;
lowerBound = Short.MIN_VALUE;
upperBound = Short.MAX_VALUE;
}
else if (constructor == builtIns.getByte().getTypeConstructor()) {
create = ByteValue.CREATE;
lowerBound = Byte.MIN_VALUE;
upperBound = Byte.MAX_VALUE;
}
else {
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
JetType intType = builtIns.getIntType();
JetType longType = builtIns.getLongType();
if (typeChecker.isSubtypeOf(intType, expectedType)) {
return getIntegerValue(value, intType, expression);
}
else if (typeChecker.isSubtypeOf(longType, expectedType)) {
return getIntegerValue(value, longType, expression);
}
else {
return createErrorValue(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType));
if (!noExpectedTypeOrError(expectedType)) {
JetType valueType = value.getType(KotlinBuiltIns.getInstance());
if (!JetTypeChecker.INSTANCE.isSubtypeOf(valueType, expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType));
}
}
return false;
}
if (value != null && lowerBound <= value && value <= upperBound) {
return create.apply(value);
public boolean checkFloatValue(
@Nullable CompileTimeConstant value,
@NotNull JetType expectedType,
@NotNull JetConstantExpression expression
) {
if (value == null) {
return reportError(FLOAT_LITERAL_OUT_OF_RANGE.on(expression));
}
return createErrorValue(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType));
if (!noExpectedTypeOrError(expectedType)) {
JetType valueType = value.getType(KotlinBuiltIns.getInstance());
if (!JetTypeChecker.INSTANCE.isSubtypeOf(valueType, expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "floating-point", expectedType));
}
}
return false;
}
@Nullable
@@ -192,128 +140,107 @@ public class CompileTimeConstantResolver {
}
@NotNull
public CompileTimeConstant<?> getFloatValue(
@NotNull JetConstantExpression expression, @NotNull JetType expectedType
) {
String text = expression.getText();
try {
if (noExpectedTypeOrError(expectedType)
|| JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getDoubleType(), expectedType)) {
return new DoubleValue(Double.parseDouble(text));
}
else if (JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getFloatType(), expectedType)) {
return new FloatValue(Float.parseFloat(text));
}
else {
return createErrorValue(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "floating-point", expectedType));
}
}
catch (NumberFormatException e) {
return createErrorValue(FLOAT_LITERAL_OUT_OF_RANGE.on(expression));
}
}
@Nullable
private static CompileTimeConstant<?> checkNativeType(
JetType expectedType,
String title,
JetType nativeType,
JetConstantExpression expression
) {
if (!noExpectedTypeOrError(expectedType)
&& !JetTypeChecker.INSTANCE.isSubtypeOf(nativeType, expectedType)) {
return createErrorValue(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, title, expectedType));
}
return null;
}
@NotNull
public CompileTimeConstant<?> getBooleanValue(
@NotNull JetConstantExpression expression, @NotNull JetType expectedType
) {
String text = expression.getText();
CompileTimeConstant<?> error = checkNativeType(expectedType, "boolean", builtIns.getBooleanType(), expression);
if (error != null) {
return error;
}
public static Object parseBooleanValue(@NotNull String text) {
if ("true".equals(text)) {
return BooleanValue.TRUE;
return true;
}
else if ("false".equals(text)) {
return BooleanValue.FALSE;
return false;
}
throw new IllegalStateException("Must not happen. A boolean literal has text: " + text);
}
@NotNull
public CompileTimeConstant<?> getCharValue(
@NotNull JetConstantExpression expression, @NotNull JetType expectedType
private boolean checkBooleanValue(
@Nullable CompileTimeConstant value,
@NotNull JetType expectedType,
@NotNull JetConstantExpression expression
) {
String text = expression.getText();
CompileTimeConstant<?> error = checkNativeType(expectedType, "character", builtIns.getCharType(), expression);
if (error != null) {
return error;
if (!noExpectedTypeOrError(expectedType)
&& !JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getBooleanType(), expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "boolean", expectedType));
}
return false;
}
@Nullable
public static Character parseCharValue(@NotNull String text) {
// Strip the quotes
if (text.length() < 2 || text.charAt(0) != '\'' || text.charAt(text.length() - 1) != '\'') {
return createErrorValue(INCORRECT_CHARACTER_LITERAL.on(expression));
return null;
}
text = text.substring(1, text.length() - 1); // now there're no quotes
if (text.length() == 0) {
return createErrorValue(EMPTY_CHARACTER_LITERAL.on(expression));
return null;
}
if (text.charAt(0) != '\\') {
// No escape
if (text.length() == 1) {
return new CharValue(text.charAt(0));
return text.charAt(0);
}
return createErrorValue(TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL.on(expression, expression));
}
return escapedStringToCharValue(text, expression);
return escapedStringToCharValue(text);
}
@NotNull
public static CompileTimeConstant<?> escapedStringToCharValue(
@NotNull String text,
@NotNull JetElement expression
) {
assert text.length() > 0 && text.charAt(0) == '\\' : "Only escaped sequences must be passed to this routine: " + text;
@Nullable
public static Character escapedStringToCharValue(@NotNull String text) {
if (!(text.length() > 0 && text.charAt(0) == '\\')) return null;
// Escape
String escape = text.substring(1); // strip the slash
switch (escape.length()) {
case 0:
// bare slash
return illegalEscape(expression);
case 0: return null;
case 1:
// one-char escape
Character escaped = translateEscape(escape.charAt(0));
if (escaped == null) {
return illegalEscape(expression);
return null;
}
return new CharValue(escaped);
return escaped;
case 5:
// unicode escape
if (escape.charAt(0) == 'u') {
try {
Integer intValue = Integer.valueOf(escape.substring(1), 16);
return new CharValue((char) intValue.intValue());
return (char) intValue.intValue();
} catch (NumberFormatException e) {
// Will be reported below
}
}
break;
}
return illegalEscape(expression);
return null;
}
@NotNull
private static CompileTimeConstant<?> illegalEscape(@NotNull JetElement expression) {
return createErrorValue(ILLEGAL_ESCAPE.on(expression, expression));
private boolean checkCharValue(CompileTimeConstant<?> constant, JetType expectedType, JetConstantExpression expression) {
String text = expression.getText();
if (!noExpectedTypeOrError(expectedType)
&& !JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getCharType(), expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "character", expectedType));
}
// Strip the quotes
if (text.length() < 2 || text.charAt(0) != '\'' || text.charAt(text.length() - 1) != '\'') {
return reportError(INCORRECT_CHARACTER_LITERAL.on(expression));
}
text = text.substring(1, text.length() - 1); // now there're no quotes
if (text.length() == 0) {
return reportError(EMPTY_CHARACTER_LITERAL.on(expression));
}
if (text.charAt(0) != '\\') {
// No escape
if (text.length() == 1) {
return false;
}
return reportError(TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL.on(expression, expression));
}
if (constant == null) {
return reportError(ILLEGAL_ESCAPE.on(expression, expression));
}
return false;
}
@Nullable
@@ -339,44 +266,22 @@ public class CompileTimeConstantResolver {
return null;
}
@NotNull
public static CompileTimeConstant<?> getNullValue(@NotNull JetConstantExpression expression, @NotNull JetType expectedType) {
if (noExpectedTypeOrError(expectedType) || expectedType.isNullable()) {
return NullValue.NULL;
public boolean checkNullValue(@NotNull JetType expectedType, @NotNull JetConstantExpression expression) {
if (!noExpectedTypeOrError(expectedType) && !expectedType.isNullable()) {
return reportError(NULL_FOR_NONNULL_TYPE.on(expression, expectedType));
}
return createErrorValue(NULL_FOR_NONNULL_TYPE.on(expression, expectedType));
return false;
}
public static boolean noExpectedTypeOrError(JetType expectedType) {
return TypeUtils.noExpectedType(expectedType) || expectedType.isError();
}
@NotNull
private static ErrorValue createErrorValue(@NotNull Diagnostic diagnostic) {
return new ErrorValueWithDiagnostic(diagnostic);
}
public static class ErrorValueWithDiagnostic extends ErrorValue {
private final Diagnostic diagnostic;
public ErrorValueWithDiagnostic(@NotNull Diagnostic diagnostic) {
this.diagnostic = diagnostic;
}
@NotNull
public Diagnostic getDiagnostic() {
return diagnostic;
}
@NotNull
@Override
public JetType getType(@NotNull KotlinBuiltIns kotlinBuiltIns) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return DefaultErrorMessages.RENDERER.render(diagnostic);
private boolean reportError(@NotNull Diagnostic diagnostic) {
if (!checkOnlyErrorsThatDependOnExpectedType || errorsThatDependOnExpectedType.contains(diagnostic.getFactory())) {
trace.report(diagnostic);
return true;
}
return false;
}
}
@@ -34,7 +34,7 @@ public class DoubleValueTypeConstructor extends NumberValueTypeConstructor {
// order of types matters
// 'getPrimitiveNumberType' returns first of supertypes that is a subtype of expected type
// for expected type 'Any' result type 'Double' should be returned
supertypes = Lists.newArrayList(KotlinBuiltIns.getInstance().getDoubleType(), KotlinBuiltIns.getInstance().getFloatType());
supertypes = Lists.newArrayList(KotlinBuiltIns.getInstance().getDoubleType());
}
@NotNull
@@ -28,6 +28,7 @@ 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.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
@@ -71,7 +72,6 @@ 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.ErrorValueWithDiagnostic;
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;
@@ -134,7 +134,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
IElementType elementType = expression.getNode().getElementType();
String text = expression.getNode().getText();
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
CompileTimeConstantResolver compileTimeConstantResolver = context.getCompileTimeConstantResolver();
if (noExpectedType(context.expectedType) && context.contextDependency == DEPENDENT) {
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
@@ -150,15 +149,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
}
}
CompileTimeConstant<?> value = compileTimeConstantResolver.getCompileTimeConstant(expression, context.expectedType);
if (value instanceof ErrorValue) {
assert value instanceof ErrorValueWithDiagnostic;
//noinspection CastConflictsWithInstanceof
context.trace.report(((ErrorValueWithDiagnostic)value).getDiagnostic());
CompileTimeConstantResolver compileTimeConstantResolver = context.getCompileTimeConstantResolver();
boolean hasError = compileTimeConstantResolver.checkConstantExpressionType(expression, context.expectedType);
if (hasError) {
return JetTypeInfo.create(getDefaultType(elementType), context.dataFlowInfo);
}
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, value);
CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, context.expectedType);
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);
}
@@ -1173,10 +1170,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, ExpressionTypingContext contextWithExpectedType) {
final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
final StringBuilder builder = new StringBuilder();
final boolean[] isCompileTimeValue = new boolean[] { true };
final DataFlowInfo[] dataFlowInfo = new DataFlowInfo[] { context.dataFlowInfo };
for (JetStringTemplateEntry entry : expression.getEntries()) {
entry.accept(new JetVisitorVoid() {
@@ -1187,32 +1181,18 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetTypeInfo typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(dataFlowInfo[0]));
dataFlowInfo[0] = typeInfo.getDataFlowInfo();
}
isCompileTimeValue[0] = false;
}
@Override
public void visitLiteralStringTemplateEntry(@NotNull JetLiteralStringTemplateEntry entry) {
builder.append(entry.getText());
}
@Override
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
CompileTimeConstant<?> character = CompileTimeConstantResolver.escapedStringToCharValue(entry.getText(), entry);
if (character instanceof ErrorValue) {
assert character instanceof ErrorValueWithDiagnostic;
//noinspection CastConflictsWithInstanceof
context.trace.report(((ErrorValueWithDiagnostic) character).getDiagnostic());
isCompileTimeValue[0] = false;
}
else {
builder.append(((CharValue) character).getValue());
Character character = CompileTimeConstantResolver.escapedStringToCharValue(entry.getText());
if (character == null) {
context.trace.report(Errors.ILLEGAL_ESCAPE.on(entry, entry));
}
}
});
}
if (isCompileTimeValue[0]) {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new StringValue(builder.toString()));
}
ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, contextWithExpectedType.expectedType);
return DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getStringType(), expression, contextWithExpectedType, dataFlowInfo[0]);
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -166,11 +165,7 @@ public class DataFlowUtils {
}
if (expression instanceof JetConstantExpression) {
Diagnostic diagnostic =
new CompileTimeConstantResolver().checkConstantExpressionType((JetConstantExpression) expression, expectedType);
if (diagnostic != null) {
trace.report(diagnostic);
}
new CompileTimeConstantResolver(trace, true).checkConstantExpressionType((JetConstantExpression) expression, expectedType);
return expressionType;
}
@@ -120,7 +120,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
public CompileTimeConstantResolver getCompileTimeConstantResolver() {
if (compileTimeConstantResolver == null) {
compileTimeConstantResolver = new CompileTimeConstantResolver();
compileTimeConstantResolver = new CompileTimeConstantResolver(trace, false);
}
return compileTimeConstantResolver;
}
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
@@ -395,11 +396,7 @@ public class ExpressionTypingServices {
if (defaultValue != null) {
getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), dataFlowInfo, trace);
if (DescriptorUtils.isAnnotationClass(DescriptorUtils.getContainingClass(declaringScope))) {
CompileTimeConstant<?> constant =
AnnotationResolver.resolveExpressionToCompileTimeValue(defaultValue, valueParameterDescriptor.getType(), trace);
if (constant != null) {
trace.record(BindingContext.COMPILE_TIME_VALUE, defaultValue, constant);
}
ConstantExpressionEvaluator.object$.evaluate(defaultValue, trace, valueParameterDescriptor.getType());
}
}
}