From ec31f991c004c843411504a6dc2b369dc7104fed Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 31 Aug 2011 22:02:05 +0400 Subject: [PATCH] 1 as Byte typechecks fine --- .../jet/lang/types/JetTypeInferrer.java | 79 +++++++++++++++---- idea/testData/checker/Constants.jet | 8 ++ 2 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 idea/testData/checker/Constants.jet diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 8038f27210c..f4a58ef411e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -7,6 +7,7 @@ import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -952,6 +953,11 @@ public class JetTypeInferrer { if (newTrace == trace) return this; return new TypeInferenceContext(newTrace, scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType); } + + public TypeInferenceContext replaceExpectedTypeAndTrace(@NotNull JetType newExpectedType, @NotNull BindingTrace newTrace) { + if (newExpectedType == expectedType && newTrace == trace) return this; + return new TypeInferenceContext(newTrace, scope, preferBlock, dataFlowInfo, newExpectedType, expectedReturnType); + } } private class TypeInferrerVisitor extends JetVisitor { @@ -1301,35 +1307,74 @@ public class JetTypeInferrer { @Override public JetType visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context) { - IElementType operationType = expression.getOperationSign().getReferencedNameElementType(); - JetType actualType = getType(context.scope, expression.getLeft(), false, context.replaceExpectedType(NO_EXPECTED_TYPE)); JetTypeReference right = expression.getRight(); - JetType result = null; + JetType result = null; if (right != null) { JetType targetType = context.typeResolver.resolveType(context.scope, right); - if (operationType == JetTokens.COLON) { - if (actualType != null && !semanticServices.getTypeChecker().isSubtypeOf(actualType, targetType)) { - context.trace.getErrorHandler().typeMismatch(expression.getLeft(), targetType, actualType); + + if (isTypeFlexible(expression.getLeft())) { + TemporaryBindingTrace temporaryTraceWithExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + boolean success = checkBinaryWithTypeRHS(expression, context, targetType, targetType, temporaryTraceWithExpectedType); + if (success) { + temporaryTraceWithExpectedType.addAllMyDataTo(context.trace); + } + else { + TemporaryBindingTrace temporaryTraceWithoutExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + checkBinaryWithTypeRHS(expression, context, targetType, NO_EXPECTED_TYPE, temporaryTraceWithoutExpectedType); + temporaryTraceWithoutExpectedType.addAllMyDataTo(context.trace); } - result = targetType; - } - else if (operationType == JetTokens.AS_KEYWORD) { - checkForCastImpossibility(expression, actualType, targetType, context); - result = targetType; - } - else if (operationType == JetTokens.AS_SAFE) { - checkForCastImpossibility(expression, actualType, targetType, context); - result = TypeUtils.makeNullable(targetType); } else { - context.trace.getErrorHandler().genericError(expression.getOperationSign().getNode(), "Unsupported binary operation"); + TemporaryBindingTrace temporaryTraceWithoutExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + checkBinaryWithTypeRHS(expression, context, targetType, NO_EXPECTED_TYPE, temporaryTraceWithoutExpectedType); + temporaryTraceWithoutExpectedType.addAllMyDataTo(context.trace); } + + IElementType operationType = expression.getOperationSign().getReferencedNameElementType(); + result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; + } + else { + getType(context.scope, expression.getLeft(), false, context.replaceExpectedType(NO_EXPECTED_TYPE)); } return context.services.checkType(result, expression, context); } + private boolean isTypeFlexible(@Nullable JetExpression expression) { + if (expression == null) return false; + + return TokenSet.create( + JetNodeTypes.INTEGER_CONSTANT, + JetNodeTypes.FLOAT_CONSTANT + ).contains(expression.getNode().getElementType()); + } + + private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context, @NotNull JetType targetType, @NotNull JetType expectedType, TemporaryBindingTrace temporaryTrace) { + TypeInferenceContext newContext = context.replaceExpectedTypeAndTrace(expectedType, temporaryTrace); + + JetType actualType = getType(context.scope, expression.getLeft(), false, newContext); + if (actualType == null) return false; + + JetSimpleNameExpression operationSign = expression.getOperationSign(); + IElementType operationType = operationSign.getReferencedNameElementType(); + if (operationType == JetTokens.COLON) { + if (targetType != NO_EXPECTED_TYPE && !semanticServices.getTypeChecker().isSubtypeOf(actualType, targetType)) { + context.trace.getErrorHandler().typeMismatch(expression.getLeft(), targetType, actualType); + return false; + } + return true; + } + else if (operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { + checkForCastImpossibility(expression, actualType, targetType, context); + return true; + } + else { + context.trace.getErrorHandler().genericError(operationSign.getNode(), "Unsupported binary operation"); + return false; + } + } + private void checkForCastImpossibility(JetBinaryExpressionWithTypeRHS expression, JetType actualType, JetType targetType, TypeInferenceContext context) { - if (actualType == null) return; + if (actualType == null || targetType == NO_EXPECTED_TYPE) return; JetTypeChecker typeChecker = semanticServices.getTypeChecker(); if (!typeChecker.isSubtypeOf(targetType, actualType)) { diff --git a/idea/testData/checker/Constants.jet b/idea/testData/checker/Constants.jet new file mode 100644 index 00000000000..d1b647b8fa3 --- /dev/null +++ b/idea/testData/checker/Constants.jet @@ -0,0 +1,8 @@ +fun test() { + 1 : Byte + 1 : Int + 1 : Double + 1 as Byte + 1 as Int + 1 as Double +} \ No newline at end of file