update number value type properly
This commit is contained in:
@@ -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()));
|
||||||
|
|||||||
+4
-1
@@ -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
|
||||||
|
|||||||
+4
-1
@@ -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
|
||||||
|
|||||||
+4
-1
@@ -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)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user