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.google.common.collect.Sets;
import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; 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.ResolutionTask;
import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer; import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; 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.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.DataFlowUtils; import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; 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.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
@@ -373,7 +377,7 @@ public class CandidateResolver {
DataFlowUtils.checkType(result, expression, contextForArgument); DataFlowUtils.checkType(result, expression, contextForArgument);
} }
@NotNull @Nullable
private JetExpression getDeferredComputationKeyExpression(@NotNull JetExpression expression) { private JetExpression getDeferredComputationKeyExpression(@NotNull JetExpression expression) {
JetVisitor<JetExpression, Void> selectorExpressionFinder = new JetVisitor<JetExpression, Void>() { JetVisitor<JetExpression, Void> selectorExpressionFinder = new JetVisitor<JetExpression, Void>() {
@Override @Override
@@ -386,6 +390,30 @@ public class CandidateResolver {
public JetExpression visitExpression(JetExpression expression, Void data) { public JetExpression visitExpression(JetExpression expression, Void data) {
return expression; 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); return expression.accept(selectorExpressionFinder, null);
} }
@@ -412,13 +440,34 @@ public class CandidateResolver {
if (type != null && !type.getConstructor().isDenotable()) { if (type != null && !type.getConstructor().isDenotable()) {
if (type.getConstructor() instanceof NumberValueTypeConstructor) { if (type.getConstructor() instanceof NumberValueTypeConstructor) {
NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor(); NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor();
type = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType); JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
BindingContextUtils.updateRecordedType(type, expression, context.trace, false); updateNumberType(primitiveType, expression, context);
return primitiveType;
} }
} }
return type; 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( private <D extends CallableDescriptor> void checkResultArgumentType(
@Nullable JetType type, @Nullable JetType type,
@NotNull ValueArgument argument, @NotNull ValueArgument argument,
@@ -478,8 +527,8 @@ public class CandidateResolver {
traceToResolveFunctionLiteral, statementExpression, mismatch); traceToResolveFunctionLiteral, statementExpression, mismatch);
CallCandidateResolutionContext<D> newContext = CallCandidateResolutionContext<D> newContext =
context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType); context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType);
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) argumentExpression, newContext, JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
RESOLVE_FUNCTION_ARGUMENTS).getType(); (JetFunctionLiteralExpression) argumentExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
if (!mismatch[0]) { if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint( constraintSystem.addSubtypeConstraint(
type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex())); type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
@@ -34,7 +34,10 @@ public class DoubleValueTypeConstructor extends NumberValueTypeConstructor {
private final List<JetType> supertypes; private final List<JetType> supertypes;
private DoubleValueTypeConstructor() { 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 @NotNull
@@ -31,9 +31,12 @@ public class IntegerValueTypeConstructor extends NumberValueTypeConstructor {
} }
private IntegerValueTypeConstructor(long value) { 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) 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) 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()); supertypes.add(KotlinBuiltIns.getInstance().getLongType());
} }
@@ -580,9 +580,12 @@ public class TypeUtils {
return upperBounds; return upperBounds;
} }
@Nullable @NotNull
public static JetType getDefaultPrimitiveNumberType(@NotNull NumberValueTypeConstructor numberValueTypeConstructor) { 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 @Nullable
@@ -602,7 +605,7 @@ public class TypeUtils {
return null; return null;
} }
@Nullable @NotNull
public static JetType getPrimitiveNumberType( public static JetType getPrimitiveNumberType(
@NotNull NumberValueTypeConstructor numberValueTypeConstructor, @NotNull NumberValueTypeConstructor numberValueTypeConstructor,
@NotNull JetType expectedType @NotNull JetType expectedType
@@ -139,6 +139,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
CompileTimeConstant<?> value = compileTimeConstantResolver.getCompileTimeConstant(expression, context.expectedType); CompileTimeConstant<?> value = compileTimeConstantResolver.getCompileTimeConstant(expression, context.expectedType);
if (value instanceof ErrorValue) { if (value instanceof ErrorValue) {
// 'checkType' for 'UNKNOWN_EXPECTED_TYPE' will take place in 'completeInferenceForArgument'
if (context.expectedType != UNKNOWN_EXPECTED_TYPE) { if (context.expectedType != UNKNOWN_EXPECTED_TYPE) {
context.trace.report(ERROR_COMPILE_TIME_VALUE.on(expression, ((ErrorValue) value).getMessage())); 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); result = visitAssignmentOperation(expression, contextWithExpectedType);
} }
else if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationType)) { 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(); dataFlowInfo = typeInfo.getDataFlowInfo();
JetType compareToReturnType = typeInfo.getType(); JetType compareToReturnType = typeInfo.getType();
if (compareToReturnType != null && !ErrorUtils.isErrorType(compareToReturnType)) { if (compareToReturnType != null && !ErrorUtils.isErrorType(compareToReturnType)) {