Error reporting for class lookup & NPEs in TypeInferrer
This commit is contained in:
@@ -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("<", "<");
|
||||
text = text.replaceAll("<", "<");
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user