From d26806a5edf7106b7f71e2b5c2c10edca8422199 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 9 Aug 2013 18:26:16 +0400 Subject: [PATCH] update number value type properly --- .../lang/resolve/calls/CandidateResolver.java | 63 ++++++++++++++++--- .../constants/DoubleValueTypeConstructor.java | 5 +- .../IntegerValueTypeConstructor.java | 5 +- .../jetbrains/jet/lang/types/TypeUtils.java | 9 ++- .../BasicExpressionTypingVisitor.java | 5 +- 5 files changed, 74 insertions(+), 13 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 64190a2f118..ca5d3d1e58a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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 selectorExpressionFinder = new JetVisitor() { @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 void updateNumberType( + @NotNull JetType numberType, + @Nullable JetExpression expression, + @NotNull CallCandidateResolutionContext 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 void checkResultArgumentType( @Nullable JetType type, @NotNull ValueArgument argument, @@ -478,8 +527,8 @@ public class CandidateResolver { traceToResolveFunctionLiteral, statementExpression, mismatch); CallCandidateResolutionContext 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())); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/DoubleValueTypeConstructor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/DoubleValueTypeConstructor.java index 307ecf87cb5..fc4edf55340 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/DoubleValueTypeConstructor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/DoubleValueTypeConstructor.java @@ -34,7 +34,10 @@ public class DoubleValueTypeConstructor extends NumberValueTypeConstructor { private final List 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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/IntegerValueTypeConstructor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/IntegerValueTypeConstructor.java index f0af894da22..b37aea35bc9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/IntegerValueTypeConstructor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/IntegerValueTypeConstructor.java @@ -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()); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 9b2575dcfb7..1e6dc3de23b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index a2777f4dc46..2142865e66c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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)) {