From 2b7f892c4a37b500155f999155c20d9a22b072ea Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 22 Sep 2011 17:51:49 +0400 Subject: [PATCH] OverrideResolver factored out. Modality fixed for vals --- .../jet/lang/resolve/BodyResolver.java | 154 +-------------- .../lang/resolve/ClassDescriptorResolver.java | 41 ++-- .../jet/lang/resolve/OverrideResolver.java | 185 ++++++++++++++++++ .../jet/lang/resolve/TopDownAnalyzer.java | 11 +- .../jet/resolve/DescriptorRenderer.java | 16 ++ 5 files changed, 239 insertions(+), 168 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index b265cc1f68f..2beff92cbe7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -68,7 +68,7 @@ public class BodyResolver { public void resolveBehaviorDeclarationBodies() { - bindOverrides(); +// bindOverrides(); resolveDelegationSpecifierLists(); resolveClassAnnotations(); @@ -81,159 +81,9 @@ public class BodyResolver { checkIfPrimaryConstructorIsNecessary(); - checkOverrides(); +// checkOverrides(); } - private void bindOverrides() { - for (Map.Entry entry : context.getClasses().entrySet()) { - bindOverridesInAClass(entry.getValue()); - } - for (Map.Entry entry : context.getObjects().entrySet()) { - bindOverridesInAClass(entry.getValue()); - } - } - - private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { - for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { - for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { - FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); - if (overridden != null) { - ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); - } - } - } - - for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { - for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { - PropertyDescriptor overridden = findPropertyOverridableBy(propertyDescriptor, supertype); - if (overridden != null) { - propertyDescriptor.addOverriddenDescriptor(overridden); - } - } - } - } - - @Nullable - private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) { - FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName()); - for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) { - if (FunctionDescriptorUtil.isOverridableBy(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) { - return functionDescriptor; - } - } - return null; - } - - @Nullable - private PropertyDescriptor findPropertyOverridableBy(@NotNull PropertyDescriptor declaredProperty, @NotNull JetType supertype) { - PropertyDescriptor property = (PropertyDescriptor) supertype.getMemberScope().getVariable(declaredProperty.getName()); - if (property == null) { - return null; - } - if (isOverridableBy(property, declaredProperty)) { - return property; - } - return null; - } - - private boolean isOverridableBy(@NotNull PropertyDescriptor property, @NotNull PropertyDescriptor overrideCandidate) { - boolean var = property.isVar(); - if (var && !overrideCandidate.isVar()) return false; - JetType propertyType = property.getReturnType(); - JetType overrideType = overrideCandidate.getReturnType(); - JetTypeChecker typeChecker = context.getSemanticServices().getTypeChecker(); - if (var) { - return typeChecker.equalTypes(propertyType, overrideType); - } - else { - return typeChecker.isSubtypeOf(overrideType, propertyType); - } - } - - private void checkOverrides() { - for (Map.Entry entry : context.getClasses().entrySet()) { - checkOverridesInAClass(entry.getValue(), entry.getKey()); - } - for (Map.Entry entry : context.getObjects().entrySet()) { - checkOverridesInAClass(entry.getValue(), entry.getKey()); - } - } - - protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { - for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { - checkOverrideForFunction(declaredFunction); - } - if (classDescriptor.getModality() == Modality.ABSTRACT) { - return; - } - Set allOverriddenFunctions = Sets.newHashSet(); - Collection allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(); - for (DeclarationDescriptor descriptor : allDescriptors) { - if (descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - if (functionDescriptor.getModality() != Modality.ABSTRACT) { - for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) { - allOverriddenFunctions.add(overriddenDescriptor.getOriginal()); - } - } - } - } - boolean foundError = false; - PsiElement nameIdentifier = null; - if (klass instanceof JetClass) { - nameIdentifier = ((JetClass) klass).getNameIdentifier(); - } - else if (klass instanceof JetObjectDeclaration) { - nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier(); - } - for (DeclarationDescriptor descriptor : allDescriptors) { - if (descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) { - DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration(); - if (declarationDescriptor != classDescriptor) { -// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" + -// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName()); - context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor)); - foundError = true; - } - } - } - } - } - - private void checkOverrideForFunction(FunctionDescriptor declaredFunction) { - JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); - assert function != null; - JetModifierList modifierList = function.getModifierList(); - ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; - boolean hasOverrideModifier = overrideNode != null; - boolean foundError = false; - - for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) { - if (overridden != null) { - if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { -// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden"); - context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration())); - foundError = true; - } - } - } - if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { -// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); - context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction)); - } - PsiElement nameIdentifier = function.getNameIdentifier(); - if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { - FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next(); -// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), -// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " + -// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier"); - context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration())); - } - } - - private void checkIfPrimaryConstructorIsNecessary() { for (Map.Entry entry : context.getClasses().entrySet()) { MutableClassDescriptor classDescriptor = entry.getValue(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index cd37ef89117..4244a03f40e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -188,16 +188,8 @@ public class ClassDescriptorResolver { returnType = ErrorUtils.createErrorType("No type, no body"); } } - Modality defaultModality; - if (containingDescriptor instanceof ClassDescriptor) { - boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT; - boolean isDefinitelyAbstract = isTrait && function.getBodyExpression() == null; - Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL; - defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality; - } - else { - defaultModality = Modality.FINAL; - } + boolean hasBody = function.getBodyExpression() != null; + Modality defaultModality = getDefaultModality(containingDescriptor, hasBody); Modality modality = resolveModalityFromModifiers(function.getModifierList(), defaultModality); functionDescriptor.initialize( @@ -211,6 +203,20 @@ public class ClassDescriptorResolver { return functionDescriptor; } + private Modality getDefaultModality(DeclarationDescriptor containingDescriptor, boolean isBodyPresent) { + Modality defaultModality; + if (containingDescriptor instanceof ClassDescriptor) { + boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT; + boolean isDefinitelyAbstract = isTrait && !isBodyPresent; + Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL; + defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality; + } + else { + defaultModality = Modality.FINAL; + } + return defaultModality; + } + @NotNull private List resolveValueParameters(FunctionDescriptor functionDescriptor, WritableScope parameterScope, List valueParameters) { List result = new ArrayList(); @@ -448,7 +454,6 @@ public class ClassDescriptorResolver { @NotNull public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) { - JetScope scopeWithTypeParameters; List typeParameterDescriptors; List typeParameters = property.getTypeParameters(); @@ -474,10 +479,22 @@ public class ClassDescriptorResolver { JetType type = getVariableType(scopeWithTypeParameters, property, true); + boolean hasBody = property.getInitializer() != null; + if (!hasBody) { + JetPropertyAccessor getter = property.getGetter(); + if (getter != null && getter.getBodyExpression() != null) { + hasBody = true; + } + JetPropertyAccessor setter = property.getSetter(); + if (!hasBody && setter != null && setter.getBodyExpression() != null) { + hasBody = true; + } + } + Modality defaultModality = getDefaultModality(containingDeclaration, hasBody); PropertyDescriptor propertyDescriptor = new PropertyDescriptor( containingDeclaration, annotationResolver.resolveAnnotations(scope, modifierList), - resolveModalityFromModifiers(modifierList), // TODO : default modifiers differ in different contexts + resolveModalityFromModifiers(modifierList, defaultModality), isVar, receiverType, JetPsiUtil.safeName(property.getName()), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java new file mode 100644 index 00000000000..03639f1f1a3 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -0,0 +1,185 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.Sets; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeChecker; +import org.jetbrains.jet.lexer.JetTokens; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.diagnostics.Errors.*; + +/** + * @author abreslav + */ +public class OverrideResolver { + + private final TopDownAnalysisContext context; + + public OverrideResolver(@NotNull TopDownAnalysisContext context) { + this.context = context; + } + + public void process() { + bindOverrides(); + checkOverrides(); + } + + private void bindOverrides() { + for (Map.Entry entry : context.getClasses().entrySet()) { + bindOverridesInAClass(entry.getValue()); + } + for (Map.Entry entry : context.getObjects().entrySet()) { + bindOverridesInAClass(entry.getValue()); + } + } + + private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { + for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { + for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { + FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); + if (overridden != null) { + ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); + } + } + } + + for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { + for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { + PropertyDescriptor overridden = findPropertyOverridableBy(propertyDescriptor, supertype); + if (overridden != null) { + propertyDescriptor.addOverriddenDescriptor(overridden); + } + } + } + } + + @Nullable + private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) { + FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName()); + for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) { + if (FunctionDescriptorUtil.isOverridableBy(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) { + return functionDescriptor; + } + } + return null; + } + + @Nullable + private PropertyDescriptor findPropertyOverridableBy(@NotNull PropertyDescriptor declaredProperty, @NotNull JetType supertype) { + PropertyDescriptor property = (PropertyDescriptor) supertype.getMemberScope().getVariable(declaredProperty.getName()); + if (property == null) { + return null; + } + if (isOverridableBy(property, declaredProperty)) { + return property; + } + return null; + } + + private boolean isOverridableBy(@NotNull PropertyDescriptor property, @NotNull PropertyDescriptor overrideCandidate) { + boolean var = property.isVar(); + if (var && !overrideCandidate.isVar()) return false; + JetType propertyType = property.getReturnType(); + JetType overrideType = overrideCandidate.getReturnType(); + JetTypeChecker typeChecker = context.getSemanticServices().getTypeChecker(); + if (var) { + return typeChecker.equalTypes(propertyType, overrideType); + } + else { + return typeChecker.isSubtypeOf(overrideType, propertyType); + } + } + + private void checkOverrides() { + for (Map.Entry entry : context.getClasses().entrySet()) { + checkOverridesInAClass(entry.getValue(), entry.getKey()); + } + for (Map.Entry entry : context.getObjects().entrySet()) { + checkOverridesInAClass(entry.getValue(), entry.getKey()); + } + } + + protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { + checkOverrideForFunction(declaredFunction); + } + if (classDescriptor.getModality() == Modality.ABSTRACT) { + return; + } + Set allOverriddenFunctions = Sets.newHashSet(); + Collection allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(); + for (DeclarationDescriptor descriptor : allDescriptors) { + if (descriptor instanceof FunctionDescriptor) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (functionDescriptor.getModality() != Modality.ABSTRACT) { + for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) { + allOverriddenFunctions.add(overriddenDescriptor.getOriginal()); + } + } + } + } + boolean foundError = false; + PsiElement nameIdentifier = null; + if (klass instanceof JetClass) { + nameIdentifier = ((JetClass) klass).getNameIdentifier(); + } + else if (klass instanceof JetObjectDeclaration) { + nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier(); + } + for (DeclarationDescriptor descriptor : allDescriptors) { + if (descriptor instanceof FunctionDescriptor) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) { + DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration(); + if (declarationDescriptor != classDescriptor) { +// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" + +// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName()); + context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor)); + foundError = true; + } + } + } + } + } + + + private void checkOverrideForFunction(FunctionDescriptor declaredFunction) { + JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); + assert function != null; + JetModifierList modifierList = function.getModifierList(); + ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; + boolean hasOverrideModifier = overrideNode != null; + boolean foundError = false; + + for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) { + if (overridden != null) { + if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { +// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden"); + context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration())); + foundError = true; + } + } + } + if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { +// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); + context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction)); + } + PsiElement nameIdentifier = function.getNameIdentifier(); + if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { + FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next(); +// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), +// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " + +// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier"); + context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration())); + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index ac6a81e01ce..457807e60f0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -65,6 +65,7 @@ public class TopDownAnalyzer { TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); + new OverrideResolver(context).process(); new BodyResolver(context).resolveBehaviorDeclarationBodies(); } @@ -77,6 +78,12 @@ public class TopDownAnalyzer { context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace); new TypeHierarchyResolver(context).process(outerScope, standardLibraryNamespace, namespace.getDeclarations()); new DeclarationResolver(context).process(); + OverrideResolver overrideResolver = new OverrideResolver(context) { + @Override + protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + } + }; + overrideResolver.process(); BodyResolver bodyResolver = new BodyResolver(context) { @Override protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) { @@ -85,10 +92,6 @@ public class TopDownAnalyzer { @Override protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { } - - @Override - protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { - } }; bodyResolver.resolveBehaviorDeclarationBodies(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 32dcfce68ab..847ba7b715e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -172,6 +172,7 @@ public class DescriptorRenderer { @Override public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) { + renderModality(descriptor.getModality(), builder); String typeString = renderPropertyPrefixAndComputeTypeString( builder, descriptor.getTypeParameters(), descriptor.getReceiver(), @@ -182,6 +183,21 @@ public class DescriptorRenderer { return null; } + private void renderModality(Modality modality, StringBuilder builder) { + switch (modality) { + case FINAL: + builder.append("final"); + break; + case OPEN: + builder.append("open"); + break; + case ABSTRACT: + builder.append("abstract"); + break; + } + builder.append(" "); + } + @Override public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) { builder.append(renderKeyword("fun")).append(" ");