Error reporting for class lookup & NPEs in TypeInferrer

This commit is contained in:
Andrey Breslav
2011-03-25 19:00:00 +03:00
parent 35f781c713
commit 065e0f3bf9
3 changed files with 84 additions and 50 deletions
@@ -45,6 +45,23 @@ public class TypeResolver {
if (referenceExpression == null || referencedName == null) {
return;
}
if (type.getTypeArguments().isEmpty() && type.getQualifier() == null) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(referencedName);
if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(referenceExpression, typeParameterDescriptor);
result[0] = new JetTypeImpl(
attributes,
typeParameterDescriptor.getTypeConstructor(),
nullable || hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
// TODO : joint domain
JetStandardClasses.STUB
);
return;
}
}
ClassDescriptor classDescriptor = resolveClass(scope, type);
if (classDescriptor != null) {
trace.recordReferenceResolution(referenceExpression, classDescriptor);
@@ -62,25 +79,6 @@ public class TypeResolver {
);
}
}
else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(referencedName);
if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(referenceExpression, typeParameterDescriptor);
result[0] = new JetTypeImpl(
attributes,
typeParameterDescriptor.getTypeConstructor(),
nullable || hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
// TODO : joint domain
JetStandardClasses.STUB
);
} else {
semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
}
}
else {
semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
}
}
@Override
@@ -173,7 +171,12 @@ public class TypeResolver {
}
@Nullable
public ClassDescriptor resolveClass(JetScope scope, JetUserType userType) {
public ClassDescriptor resolveClassByUserType(JetScope scope, JetUserType userType) {
return resolveClass(scope, userType);
}
@Nullable
private ClassDescriptor resolveClass(JetScope scope, JetUserType userType) {
JetSimpleNameExpression expression = userType.getReferenceExpression();
if (expression == null) {
return null;
@@ -182,16 +185,29 @@ public class TypeResolver {
if (referencedName == null) {
return null;
}
ClassDescriptor classDescriptor = null;
if (userType.isAbsoluteInRootNamespace()) {
return JetModuleUtil.getRootNamespaceScope(userType).getClass(referencedName);
classDescriptor = JetModuleUtil.getRootNamespaceScope(userType).getClass(referencedName);
}
JetUserType qualifier = userType.getQualifier();
if (qualifier != null) {
scope = resolveClassLookupScope(scope, qualifier);
else {
JetUserType qualifier = userType.getQualifier();
if (qualifier != null) {
scope = resolveClassLookupScope(scope, qualifier);
}
if (scope == null) {
return null;
}
classDescriptor = scope.getClass(referencedName);
}
return scope.getClass(referencedName);
if (classDescriptor == null) {
semanticServices.getErrorHandler().unresolvedReference(expression);
}
return classDescriptor;
}
@Nullable
private JetScope resolveClassLookupScope(JetScope scope, JetUserType userType) {
ClassDescriptor classDescriptor = resolveClass(scope, userType);
if (classDescriptor != null) {
@@ -200,7 +216,7 @@ public class TypeResolver {
NamespaceDescriptor namespaceDescriptor = resolveNamespace(scope, userType);
if (namespaceDescriptor == null) {
return JetScope.EMPTY;
return null;
}
return namespaceDescriptor.getMemberScope();
}
@@ -92,12 +92,13 @@ public class JetTypeInferrer {
return result;
}
@NotNull
private JetExpression deparenthesize(@NotNull JetExpression expression) {
while (expression instanceof JetParenthesizedExpression) {
expression = ((JetParenthesizedExpression) expression).getExpression();
@Nullable
private static JetExpression deparenthesize(@NotNull JetExpression expression) {
JetExpression result = expression;
while (result instanceof JetParenthesizedExpression) {
result = ((JetParenthesizedExpression) expression).getExpression();
}
return expression;
return result;
}
@Nullable
@@ -158,9 +159,10 @@ public class JetTypeInferrer {
JetExpression selectorExpression = expression.getSelectorExpression();
if (selectorExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
String referencedName = referenceExpression.getReferencedName();
if (receiverType != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
if (receiverType != null && referencedName != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
reference[0] = referenceExpression;
}
} else {
@@ -171,8 +173,11 @@ public class JetTypeInferrer {
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
// a -- create a hierarchical lookup domain for this.a
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, expression.getReferencedName());
reference[0] = expression;
String referencedName = expression.getReferencedName();
if (referencedName != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, referencedName);
reference[0] = expression;
}
}
@Override
@@ -498,22 +503,29 @@ public class JetTypeInferrer {
@Override
public void visitThisExpression(JetThisExpression expression) {
// TODO : qualified this, e.g. Foo.this<Bar>
// TODO : qualified this, e.g. this@Foo<Bar>
JetType thisType = scope.getThisType();
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
// This cast must be safe (assuming the PSI doesn't contain errors)
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break;
JetTypeElement superTypeElement = superTypeQualifier.getTypeElement();
// Errors are reported by the parser
if (superTypeElement instanceof JetUserType) {
JetUserType typeElement = (JetUserType) superTypeElement;
ClassDescriptor superclass = typeResolver.resolveClassByUserType(scope, typeElement);
if (superclass != null) {
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break;
}
}
if (result == null) {
semanticServices.getErrorHandler().genericError(superTypeElement.getNode(), "Not a superclass");
}
}
}
assert result != null;
} else {
result = thisType;
}
@@ -541,7 +553,10 @@ public class JetTypeInferrer {
if (finallyBlock == null) {
for (JetCatchClause catchClause : catchClauses) {
// TODO: change scope here
types.add(getType(scope, catchClause.getCatchBody(), true));
JetExpression catchBody = catchClause.getCatchBody();
if (catchBody != null) {
types.add(getType(scope, catchBody, true));
}
}
} else {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
@@ -650,6 +665,7 @@ public class JetTypeInferrer {
propertyDescriptor = classDescriptorResolver.resolveValueParameterDescriptor(scope.getContainingDeclaration(), scope, loopParameter);
JetType actualParameterType = propertyDescriptor.getOutType();
if (expectedParameterType != null &&
actualParameterType != null &&
!semanticServices.getTypeChecker().isSubtypeOf(expectedParameterType, actualParameterType)) {
semanticServices.getErrorHandler().genericError(typeReference.getNode(), "The loop iterates over values of type " + expectedParameterType + " but the parameter is declared to be " + actualParameterType);
}
@@ -860,7 +876,10 @@ public class JetTypeInferrer {
List<JetType> types = new ArrayList<JetType>();
for (JetTypeProjection projection : typeArguments) {
// TODO : check that there's no projection
types.add(typeResolver.resolveType(scope, projection.getTypeReference()));
JetTypeReference typeReference = projection.getTypeReference();
if (typeReference != null) {
types.add(typeResolver.resolveType(scope, typeReference));
}
}
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
@@ -889,7 +908,6 @@ public class JetTypeInferrer {
@Override
public void visitIsExpression(JetIsExpression expression) {
// TODO : patterns and everything
System.out.println("Pattern matching is not supported yet.");
result = semanticServices.getStandardLibrary().getBooleanType();
}
@@ -47,7 +47,7 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
private String render(DeclarationDescriptor declarationDescriptor) {
String text = DescriptorUtil.renderPresentableText(declarationDescriptor);
// text = text.replaceAll("<", "&lt;");
text = text.replaceAll("<", "&lt;");
return text;
}