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) {
|
if (referenceExpression == null || referencedName == null) {
|
||||||
return;
|
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);
|
ClassDescriptor classDescriptor = resolveClass(scope, type);
|
||||||
if (classDescriptor != null) {
|
if (classDescriptor != null) {
|
||||||
trace.recordReferenceResolution(referenceExpression, classDescriptor);
|
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
|
@Override
|
||||||
@@ -173,7 +171,12 @@ public class TypeResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@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();
|
JetSimpleNameExpression expression = userType.getReferenceExpression();
|
||||||
if (expression == null) {
|
if (expression == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -182,16 +185,29 @@ public class TypeResolver {
|
|||||||
if (referencedName == null) {
|
if (referencedName == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ClassDescriptor classDescriptor = null;
|
||||||
if (userType.isAbsoluteInRootNamespace()) {
|
if (userType.isAbsoluteInRootNamespace()) {
|
||||||
return JetModuleUtil.getRootNamespaceScope(userType).getClass(referencedName);
|
classDescriptor = JetModuleUtil.getRootNamespaceScope(userType).getClass(referencedName);
|
||||||
}
|
}
|
||||||
JetUserType qualifier = userType.getQualifier();
|
else {
|
||||||
if (qualifier != null) {
|
JetUserType qualifier = userType.getQualifier();
|
||||||
scope = resolveClassLookupScope(scope, qualifier);
|
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) {
|
private JetScope resolveClassLookupScope(JetScope scope, JetUserType userType) {
|
||||||
ClassDescriptor classDescriptor = resolveClass(scope, userType);
|
ClassDescriptor classDescriptor = resolveClass(scope, userType);
|
||||||
if (classDescriptor != null) {
|
if (classDescriptor != null) {
|
||||||
@@ -200,7 +216,7 @@ public class TypeResolver {
|
|||||||
|
|
||||||
NamespaceDescriptor namespaceDescriptor = resolveNamespace(scope, userType);
|
NamespaceDescriptor namespaceDescriptor = resolveNamespace(scope, userType);
|
||||||
if (namespaceDescriptor == null) {
|
if (namespaceDescriptor == null) {
|
||||||
return JetScope.EMPTY;
|
return null;
|
||||||
}
|
}
|
||||||
return namespaceDescriptor.getMemberScope();
|
return namespaceDescriptor.getMemberScope();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,12 +92,13 @@ public class JetTypeInferrer {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
private JetExpression deparenthesize(@NotNull JetExpression expression) {
|
private static JetExpression deparenthesize(@NotNull JetExpression expression) {
|
||||||
while (expression instanceof JetParenthesizedExpression) {
|
JetExpression result = expression;
|
||||||
expression = ((JetParenthesizedExpression) expression).getExpression();
|
while (result instanceof JetParenthesizedExpression) {
|
||||||
|
result = ((JetParenthesizedExpression) expression).getExpression();
|
||||||
}
|
}
|
||||||
return expression;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -158,9 +159,10 @@ public class JetTypeInferrer {
|
|||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
|
JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
|
||||||
|
String referencedName = referenceExpression.getReferencedName();
|
||||||
|
|
||||||
if (receiverType != null) {
|
if (receiverType != null && referencedName != null) {
|
||||||
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
|
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
|
||||||
reference[0] = referenceExpression;
|
reference[0] = referenceExpression;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -171,8 +173,11 @@ public class JetTypeInferrer {
|
|||||||
@Override
|
@Override
|
||||||
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
||||||
// a -- create a hierarchical lookup domain for this.a
|
// a -- create a hierarchical lookup domain for this.a
|
||||||
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, expression.getReferencedName());
|
String referencedName = expression.getReferencedName();
|
||||||
reference[0] = expression;
|
if (referencedName != null) {
|
||||||
|
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, referencedName);
|
||||||
|
reference[0] = expression;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -498,22 +503,29 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitThisExpression(JetThisExpression expression) {
|
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();
|
JetType thisType = scope.getThisType();
|
||||||
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
|
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
|
||||||
if (superTypeQualifier != null) {
|
if (superTypeQualifier != null) {
|
||||||
// This cast must be safe (assuming the PSI doesn't contain errors)
|
JetTypeElement superTypeElement = superTypeQualifier.getTypeElement();
|
||||||
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
|
// Errors are reported by the parser
|
||||||
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
|
if (superTypeElement instanceof JetUserType) {
|
||||||
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
|
JetUserType typeElement = (JetUserType) superTypeElement;
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
|
ClassDescriptor superclass = typeResolver.resolveClassByUserType(scope, typeElement);
|
||||||
for (JetType declaredSupertype : supertypes) {
|
if (superclass != null) {
|
||||||
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
|
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
|
||||||
result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
|
||||||
break;
|
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 {
|
} else {
|
||||||
result = thisType;
|
result = thisType;
|
||||||
}
|
}
|
||||||
@@ -541,7 +553,10 @@ public class JetTypeInferrer {
|
|||||||
if (finallyBlock == null) {
|
if (finallyBlock == null) {
|
||||||
for (JetCatchClause catchClause : catchClauses) {
|
for (JetCatchClause catchClause : catchClauses) {
|
||||||
// TODO: change scope here
|
// 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 {
|
} else {
|
||||||
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
|
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
|
||||||
@@ -650,6 +665,7 @@ public class JetTypeInferrer {
|
|||||||
propertyDescriptor = classDescriptorResolver.resolveValueParameterDescriptor(scope.getContainingDeclaration(), scope, loopParameter);
|
propertyDescriptor = classDescriptorResolver.resolveValueParameterDescriptor(scope.getContainingDeclaration(), scope, loopParameter);
|
||||||
JetType actualParameterType = propertyDescriptor.getOutType();
|
JetType actualParameterType = propertyDescriptor.getOutType();
|
||||||
if (expectedParameterType != null &&
|
if (expectedParameterType != null &&
|
||||||
|
actualParameterType != null &&
|
||||||
!semanticServices.getTypeChecker().isSubtypeOf(expectedParameterType, actualParameterType)) {
|
!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);
|
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>();
|
List<JetType> types = new ArrayList<JetType>();
|
||||||
for (JetTypeProjection projection : typeArguments) {
|
for (JetTypeProjection projection : typeArguments) {
|
||||||
// TODO : check that there's no projection
|
// 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>();
|
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
|
||||||
@@ -889,7 +908,6 @@ public class JetTypeInferrer {
|
|||||||
@Override
|
@Override
|
||||||
public void visitIsExpression(JetIsExpression expression) {
|
public void visitIsExpression(JetIsExpression expression) {
|
||||||
// TODO : patterns and everything
|
// TODO : patterns and everything
|
||||||
System.out.println("Pattern matching is not supported yet.");
|
|
||||||
result = semanticServices.getStandardLibrary().getBooleanType();
|
result = semanticServices.getStandardLibrary().getBooleanType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
|
|||||||
|
|
||||||
private String render(DeclarationDescriptor declarationDescriptor) {
|
private String render(DeclarationDescriptor declarationDescriptor) {
|
||||||
String text = DescriptorUtil.renderPresentableText(declarationDescriptor);
|
String text = DescriptorUtil.renderPresentableText(declarationDescriptor);
|
||||||
// text = text.replaceAll("<", "<");
|
text = text.replaceAll("<", "<");
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user