update number value type properly

This commit is contained in:
Svetlana Isakova
2013-08-09 18:26:16 +04:00
parent 46b099c858
commit d26806a5ed
5 changed files with 74 additions and 13 deletions
@@ -22,6 +22,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -40,15 +41,18 @@ import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
import org.jetbrains.jet.lang.resolve.constants.*;
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.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import javax.inject.Inject;
import java.util.ArrayList;
@@ -373,7 +377,7 @@ public class CandidateResolver {
DataFlowUtils.checkType(result, expression, contextForArgument);
}
@NotNull
@Nullable
private JetExpression getDeferredComputationKeyExpression(@NotNull JetExpression expression) {
JetVisitor<JetExpression, Void> selectorExpressionFinder = new JetVisitor<JetExpression, Void>() {
@Override
@@ -386,6 +390,30 @@ public class CandidateResolver {
public JetExpression visitExpression(JetExpression expression, Void data) {
return expression;
}
@Override
public JetExpression visitParenthesizedExpression(JetParenthesizedExpression expression, Void data) {
return expression.getExpression();
}
@Override
public JetExpression visitPrefixExpression(JetPrefixExpression expression, Void data) {
JetExpression baseExpression = JetPsiUtil.getBaseExpressionIfLabeledExpression(expression);
return baseExpression != null ? baseExpression : expression;
}
@Override
public JetExpression visitBinaryExpression(JetBinaryExpression expression, Void data) {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
//noinspection SuspiciousMethodCalls
if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationType)) {
//Result type of comparison doesn't depend on expected type:
//it's 'Boolean', but 'compareTo' should return 'Int'.
//So we shouldn't check result type of such a call('Int') at completion phase.
return null;
}
return super.visitBinaryExpression(expression, data);
}
};
return expression.accept(selectorExpressionFinder, null);
}
@@ -412,13 +440,34 @@ public class CandidateResolver {
if (type != null && !type.getConstructor().isDenotable()) {
if (type.getConstructor() instanceof NumberValueTypeConstructor) {
NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor();
type = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
BindingContextUtils.updateRecordedType(type, expression, context.trace, false);
JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
updateNumberType(primitiveType, expression, context);
return primitiveType;
}
}
return type;
}
private <D extends CallableDescriptor> void updateNumberType(
@NotNull JetType numberType,
@Nullable JetExpression expression,
@NotNull CallCandidateResolutionContext<D> context
) {
if (expression == null) return;
BindingContextUtils.updateRecordedType(numberType, expression, context.trace, false);
if (!(expression instanceof JetConstantExpression)) {
updateNumberType(numberType, JetPsiUtil.deparenthesizeWithNoTypeResolution(expression, false), context);
return;
}
CompileTimeConstant<?> constant =
new CompileTimeConstantResolver().getCompileTimeConstant((JetConstantExpression) expression, numberType);
if (!(constant instanceof ErrorValue)) {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, constant);
}
}
private <D extends CallableDescriptor> void checkResultArgumentType(
@Nullable JetType type,
@NotNull ValueArgument argument,
@@ -478,8 +527,8 @@ public class CandidateResolver {
traceToResolveFunctionLiteral, statementExpression, mismatch);
CallCandidateResolutionContext<D> newContext =
context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType);
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) argumentExpression, newContext,
RESOLVE_FUNCTION_ARGUMENTS).getType();
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
(JetFunctionLiteralExpression) argumentExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(
type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
@@ -34,7 +34,10 @@ public class DoubleValueTypeConstructor extends NumberValueTypeConstructor {
private final List<JetType> supertypes;
private DoubleValueTypeConstructor() {
supertypes = Lists.newArrayList(KotlinBuiltIns.getInstance().getFloatType(), KotlinBuiltIns.getInstance().getDoubleType());
// 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());
}
@NotNull
@@ -31,9 +31,12 @@ public class IntegerValueTypeConstructor extends NumberValueTypeConstructor {
}
private IntegerValueTypeConstructor(long value) {
// order of types matters
// 'getPrimitiveNumberType' returns first of supertypes that is a subtype of expected type
// for expected type 'Any' result type 'Int' should be returned
checkBoundsAndAddSuperType(value, (long) Integer.MIN_VALUE, (long) Integer.MAX_VALUE, KotlinBuiltIns.getInstance().getIntType());
checkBoundsAndAddSuperType(value, (long) Byte.MIN_VALUE, (long) Byte.MAX_VALUE, KotlinBuiltIns.getInstance().getByteType());
checkBoundsAndAddSuperType(value, (long) Short.MIN_VALUE, (long) Short.MAX_VALUE, KotlinBuiltIns.getInstance().getShortType());
checkBoundsAndAddSuperType(value, (long) Integer.MIN_VALUE, (long) Integer.MAX_VALUE, KotlinBuiltIns.getInstance().getIntType());
supertypes.add(KotlinBuiltIns.getInstance().getLongType());
}
@@ -580,9 +580,12 @@ public class TypeUtils {
return upperBounds;
}
@Nullable
@NotNull
public static JetType getDefaultPrimitiveNumberType(@NotNull NumberValueTypeConstructor numberValueTypeConstructor) {
return getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
JetType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
"Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
return type;
}
@Nullable
@@ -602,7 +605,7 @@ public class TypeUtils {
return null;
}
@Nullable
@NotNull
public static JetType getPrimitiveNumberType(
@NotNull NumberValueTypeConstructor numberValueTypeConstructor,
@NotNull JetType expectedType
@@ -139,6 +139,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
CompileTimeConstant<?> value = compileTimeConstantResolver.getCompileTimeConstant(expression, context.expectedType);
if (value instanceof ErrorValue) {
// 'checkType' for 'UNKNOWN_EXPECTED_TYPE' will take place in 'completeInferenceForArgument'
if (context.expectedType != UNKNOWN_EXPECTED_TYPE) {
context.trace.report(ERROR_COMPILE_TIME_VALUE.on(expression, ((ErrorValue) value).getMessage()));
}
@@ -911,7 +912,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = visitAssignmentOperation(expression, contextWithExpectedType);
}
else if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationType)) {
JetTypeInfo typeInfo = getTypeInfoForBinaryCall(context.scope, OperatorConventions.COMPARE_TO, context, expression);
//we don't complete 'compareTo' call, because we change its result type from 'Int' to 'Boolean'
JetTypeInfo typeInfo = getTypeInfoForBinaryCall(
context.scope, OperatorConventions.COMPARE_TO, context.replaceResolveMode(ResolveMode.TOP_LEVEL_CALL), expression);
dataFlowInfo = typeInfo.getDataFlowInfo();
JetType compareToReturnType = typeInfo.getType();
if (compareToReturnType != null && !ErrorUtils.isErrorType(compareToReturnType)) {