1 as Byte typechecks fine
This commit is contained in:
@@ -7,6 +7,7 @@ import com.google.common.collect.Sets;
|
|||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
import com.intellij.psi.tree.TokenSet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
@@ -952,6 +953,11 @@ public class JetTypeInferrer {
|
|||||||
if (newTrace == trace) return this;
|
if (newTrace == trace) return this;
|
||||||
return new TypeInferenceContext(newTrace, scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
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<JetType, TypeInferenceContext> {
|
private class TypeInferrerVisitor extends JetVisitor<JetType, TypeInferenceContext> {
|
||||||
@@ -1301,35 +1307,74 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context) {
|
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();
|
JetTypeReference right = expression.getRight();
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
JetType targetType = context.typeResolver.resolveType(context.scope, right);
|
JetType targetType = context.typeResolver.resolveType(context.scope, right);
|
||||||
if (operationType == JetTokens.COLON) {
|
|
||||||
if (actualType != null && !semanticServices.getTypeChecker().isSubtypeOf(actualType, targetType)) {
|
if (isTypeFlexible(expression.getLeft())) {
|
||||||
context.trace.getErrorHandler().typeMismatch(expression.getLeft(), targetType, actualType);
|
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 {
|
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);
|
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) {
|
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();
|
JetTypeChecker typeChecker = semanticServices.getTypeChecker();
|
||||||
if (!typeChecker.isSubtypeOf(targetType, actualType)) {
|
if (!typeChecker.isSubtypeOf(targetType, actualType)) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun test() {
|
||||||
|
1 : Byte
|
||||||
|
1 : Int
|
||||||
|
<error>1</error> : Double
|
||||||
|
1 <warning>as</warning> Byte
|
||||||
|
1 <warning>as</warning> Int
|
||||||
|
1 <warning>as</warning> Double
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user