提交 71610fb7 编写于 作者: A Andrey Breslav

Checks for . and ?.

上级 69d2c27e
......@@ -18,7 +18,7 @@ public class ErrorHandler {
}
@Override
public void structuralError(ASTNode node, String errorMessage) {
public void genericError(ASTNode node, String errorMessage) {
throw new IllegalStateException(errorMessage);
}
......@@ -36,12 +36,15 @@ public class ErrorHandler {
public void unresolvedReference(JetReferenceExpression referenceExpression) {
}
public void structuralError(ASTNode node, String errorMessage) {
}
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
}
public void redeclaration(DeclarationDescriptor existingDescriptor, DeclarationDescriptor redeclaredDescriptor) {
}
public void genericError(ASTNode node, String errorMessage) {
}
public void genericWarning(ASTNode node, String message) {
}
}
......@@ -50,11 +50,6 @@ public class JetPsiChecker implements Annotator {
}
}
@Override
public void structuralError(ASTNode node, String errorMessage) {
holder.createErrorAnnotation(node, errorMessage);
}
@Override
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
holder.createErrorAnnotation(expression, "Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
......@@ -65,6 +60,16 @@ public class JetPsiChecker implements Annotator {
redeclarations.add(existingDescriptor);
redeclarations.add(redeclaredDescriptor);
}
@Override
public void genericError(ASTNode node, String errorMessage) {
holder.createErrorAnnotation(node, errorMessage);
}
@Override
public void genericWarning(ASTNode node, String message) {
holder.createWarningAnnotation(node, message);
}
});
for (DeclarationDescriptor redeclaration : redeclarations) {
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(redeclaration);
......
......@@ -159,7 +159,7 @@ public class ClassDescriptorResolver {
}
} else {
if (bodyExpression == null) {
semanticServices.getErrorHandler().structuralError(function.getNode(), "This function must either declare a return type or have a body expression");
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body expression");
returnType = ErrorType.createErrorType("No type, no body");
} else {
// TODO : Recursion possible
......@@ -184,7 +184,7 @@ public class ClassDescriptorResolver {
JetType type;
if (typeReference == null) {
semanticServices.getErrorHandler().structuralError(valueParameter.getNode(), "A type annotation is required on a value parameter " + valueParameter.getName());
semanticServices.getErrorHandler().genericError(valueParameter.getNode(), "A type annotation is required on a value parameter " + valueParameter.getName());
type = ErrorType.createErrorType("Type annotation was missing");
} else {
type = typeResolver.resolveType(parameterScope, typeReference);
......@@ -265,7 +265,7 @@ public class ClassDescriptorResolver {
if (propertyTypeRef == null) {
JetExpression initializer = property.getInitializer();
if (initializer == null) {
semanticServices.getErrorHandler().structuralError(property.getNode(), "This property must either have a type annotation or be initialized");
semanticServices.getErrorHandler().genericError(property.getNode(), "This property must either have a type annotation or be initialized");
type = ErrorType.createErrorType("No type, no body");
} else {
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
......
......@@ -137,11 +137,13 @@ public class JetTypeInferrer {
@Override
public void visitQualifiedExpression(JetQualifiedExpression expression) {
// . or ?.
JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
checkNullSafety(receiverType, expression);
JetExpression selectorExpression = expression.getSelectorExpression();
if (selectorExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
if (receiverType != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression;
......@@ -172,6 +174,17 @@ public class JetTypeInferrer {
return wrapForTracing(result[0], reference[0], true);
}
private void checkNullSafety(JetType receiverType, JetQualifiedExpression expression) {
if (receiverType != null) {
if (receiverType.isNullable() && expression.getOperationSign() == JetTokens.DOT) {
semanticServices.getErrorHandler().genericError(expression.getOperationTokenNode(), "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
}
else if (!receiverType.isNullable() && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
semanticServices.getErrorHandler().genericWarning(expression.getOperationTokenNode(), "Unnecessary safe call on a non-null receiver of type " + receiverType);
}
}
}
private OverloadDomain wrapForTracing(final OverloadDomain overloadDomain, @NotNull final JetReferenceExpression referenceExpression, final boolean reportUnresolved) {
if (overloadDomain == null) return OverloadDomain.EMPTY;
return new OverloadDomain() {
......@@ -408,7 +421,7 @@ public class JetTypeInferrer {
// TODO : Check for cast impossibility
}
else {
semanticServices.getErrorHandler().structuralError(expression.getOperationSign().getNode(), "Unsupported binary operation");
semanticServices.getErrorHandler().genericError(expression.getOperationSign().getNode(), "Unsupported binary operation");
}
result = targetType;
}
......@@ -422,7 +435,7 @@ public class JetTypeInferrer {
JetType conditionType = getType(scope, condition, false);
if (conditionType != null && !isBoolean(conditionType)) {
semanticServices.getErrorHandler().structuralError(condition.getNode(), "Condition must be of type Boolean, but was of type " + conditionType);
semanticServices.getErrorHandler().genericError(condition.getNode(), "Condition must be of type Boolean, but was of type " + conditionType);
}
}
// TODO : change types according to is and nullability checks
......@@ -517,14 +530,29 @@ public class JetTypeInferrer {
}
@Override
public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) {
public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitPredicateExpression(JetPredicateExpression expression) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitQualifiedExpression(JetQualifiedExpression expression) {
// TODO : functions
JetExpression receiverExpression = expression.getReceiverExpression();
JetExpression selectorExpression = expression.getSelectorExpression();
JetType receiverType = getType(scope, receiverExpression, false);
if (receiverType != null && selectorExpression != null) { // TODO : review
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType);
result = getType(compositeScope, selectorExpression, false);
if (receiverType != null) {
checkNullSafety(receiverType, expression);
if (selectorExpression != null) {
// TODO : review
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType);
result = getType(compositeScope, selectorExpression, false);
}
}
}
......@@ -597,7 +625,7 @@ public class JetTypeInferrer {
JetSimpleNameExpression operationSign = expression.getOperationSign();
String name = unaryOperationNames.get(operationSign.getReferencedNameElementType());
if (name == null) {
semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "Unknown unary operation");
semanticServices.getErrorHandler().genericError(operationSign.getNode(), "Unknown unary operation");
}
else {
JetType type = getType(scope, expression.getBaseExpression(), false);
......@@ -645,7 +673,7 @@ public class JetTypeInferrer {
if (constructor.equals(intTypeConstructor)) {
result = standardLibrary.getBooleanType();
} else {
semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "compareTo must return Int, but returns " + compareToReturnType);
semanticServices.getErrorHandler().genericError(operationSign.getNode(), "compareTo must return Int, but returns " + compareToReturnType);
}
}
}
......@@ -692,7 +720,7 @@ public class JetTypeInferrer {
result = semanticServices.getStandardLibrary().getBooleanType();
}
else {
semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "Unknown operation");
semanticServices.getErrorHandler().genericError(operationSign.getNode(), "Unknown operation");
}
}
......@@ -700,7 +728,7 @@ public class JetTypeInferrer {
if (resultType != null) {
// TODO : Relax?
if (!isBoolean(resultType)) {
semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "'" + name + "' must return Boolean but returns " + resultType);
semanticServices.getErrorHandler().genericError(operationSign.getNode(), "'" + name + "' must return Boolean but returns " + resultType);
return null;
} else {
return resultType;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册