Checks for . and ?.
This commit is contained in:
@@ -18,7 +18,7 @@ public class ErrorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void structuralError(ASTNode node, String errorMessage) {
|
public void genericError(ASTNode node, String errorMessage) {
|
||||||
throw new IllegalStateException(errorMessage);
|
throw new IllegalStateException(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,12 +36,15 @@ public class ErrorHandler {
|
|||||||
public void unresolvedReference(JetReferenceExpression referenceExpression) {
|
public void unresolvedReference(JetReferenceExpression referenceExpression) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void structuralError(ASTNode node, String errorMessage) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
|
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redeclaration(DeclarationDescriptor existingDescriptor, DeclarationDescriptor redeclaredDescriptor) {
|
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
|
@Override
|
||||||
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
|
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
|
||||||
holder.createErrorAnnotation(expression, "Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
|
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(existingDescriptor);
|
||||||
redeclarations.add(redeclaredDescriptor);
|
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) {
|
for (DeclarationDescriptor redeclaration : redeclarations) {
|
||||||
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(redeclaration);
|
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(redeclaration);
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class ClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bodyExpression == null) {
|
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");
|
returnType = ErrorType.createErrorType("No type, no body");
|
||||||
} else {
|
} else {
|
||||||
// TODO : Recursion possible
|
// TODO : Recursion possible
|
||||||
@@ -184,7 +184,7 @@ public class ClassDescriptorResolver {
|
|||||||
|
|
||||||
JetType type;
|
JetType type;
|
||||||
if (typeReference == null) {
|
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");
|
type = ErrorType.createErrorType("Type annotation was missing");
|
||||||
} else {
|
} else {
|
||||||
type = typeResolver.resolveType(parameterScope, typeReference);
|
type = typeResolver.resolveType(parameterScope, typeReference);
|
||||||
@@ -265,7 +265,7 @@ public class ClassDescriptorResolver {
|
|||||||
if (propertyTypeRef == null) {
|
if (propertyTypeRef == null) {
|
||||||
JetExpression initializer = property.getInitializer();
|
JetExpression initializer = property.getInitializer();
|
||||||
if (initializer == null) {
|
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");
|
type = ErrorType.createErrorType("No type, no body");
|
||||||
} else {
|
} else {
|
||||||
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
||||||
|
|||||||
@@ -137,11 +137,13 @@ public class JetTypeInferrer {
|
|||||||
@Override
|
@Override
|
||||||
public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
||||||
// . or ?.
|
// . or ?.
|
||||||
|
JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
|
||||||
|
checkNullSafety(receiverType, expression);
|
||||||
|
|
||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
|
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
|
||||||
|
|
||||||
JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
|
|
||||||
if (receiverType != null) {
|
if (receiverType != null) {
|
||||||
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
|
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
|
||||||
reference[0] = referenceExpression;
|
reference[0] = referenceExpression;
|
||||||
@@ -172,6 +174,17 @@ public class JetTypeInferrer {
|
|||||||
return wrapForTracing(result[0], reference[0], true);
|
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) {
|
private OverloadDomain wrapForTracing(final OverloadDomain overloadDomain, @NotNull final JetReferenceExpression referenceExpression, final boolean reportUnresolved) {
|
||||||
if (overloadDomain == null) return OverloadDomain.EMPTY;
|
if (overloadDomain == null) return OverloadDomain.EMPTY;
|
||||||
return new OverloadDomain() {
|
return new OverloadDomain() {
|
||||||
@@ -408,7 +421,7 @@ public class JetTypeInferrer {
|
|||||||
// TODO : Check for cast impossibility
|
// TODO : Check for cast impossibility
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
semanticServices.getErrorHandler().structuralError(expression.getOperationSign().getNode(), "Unsupported binary operation");
|
semanticServices.getErrorHandler().genericError(expression.getOperationSign().getNode(), "Unsupported binary operation");
|
||||||
}
|
}
|
||||||
result = targetType;
|
result = targetType;
|
||||||
}
|
}
|
||||||
@@ -422,7 +435,7 @@ public class JetTypeInferrer {
|
|||||||
JetType conditionType = getType(scope, condition, false);
|
JetType conditionType = getType(scope, condition, false);
|
||||||
|
|
||||||
if (conditionType != null && !isBoolean(conditionType)) {
|
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
|
// TODO : change types according to is and nullability checks
|
||||||
@@ -517,14 +530,29 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// TODO : functions
|
||||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
JetType receiverType = getType(scope, receiverExpression, false);
|
JetType receiverType = getType(scope, receiverExpression, false);
|
||||||
if (receiverType != null && selectorExpression != null) { // TODO : review
|
if (receiverType != null) {
|
||||||
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType);
|
checkNullSafety(receiverType, expression);
|
||||||
result = getType(compositeScope, selectorExpression, false);
|
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();
|
JetSimpleNameExpression operationSign = expression.getOperationSign();
|
||||||
String name = unaryOperationNames.get(operationSign.getReferencedNameElementType());
|
String name = unaryOperationNames.get(operationSign.getReferencedNameElementType());
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "Unknown unary operation");
|
semanticServices.getErrorHandler().genericError(operationSign.getNode(), "Unknown unary operation");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType type = getType(scope, expression.getBaseExpression(), false);
|
JetType type = getType(scope, expression.getBaseExpression(), false);
|
||||||
@@ -645,7 +673,7 @@ public class JetTypeInferrer {
|
|||||||
if (constructor.equals(intTypeConstructor)) {
|
if (constructor.equals(intTypeConstructor)) {
|
||||||
result = standardLibrary.getBooleanType();
|
result = standardLibrary.getBooleanType();
|
||||||
} else {
|
} 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();
|
result = semanticServices.getStandardLibrary().getBooleanType();
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
if (resultType != null) {
|
||||||
// TODO : Relax?
|
// TODO : Relax?
|
||||||
if (!isBoolean(resultType)) {
|
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;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return resultType;
|
return resultType;
|
||||||
|
|||||||
Reference in New Issue
Block a user