Default 'abstract' in traits

This commit is contained in:
svtk
2011-09-08 18:31:56 +04:00
parent cd2db7f1ee
commit 2c3076d1c2
12 changed files with 79 additions and 53 deletions
@@ -45,5 +45,5 @@ public interface ClassDescriptor extends ClassifierDescriptor {
boolean isObject(); boolean isObject();
@NotNull @NotNull
ClassModifiers getClassModifiers(); ClassModifiers getModifiers();
} }
@@ -118,7 +118,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
@Override @Override
@NotNull @NotNull
public ClassModifiers getClassModifiers() { public ClassModifiers getModifiers() {
return ClassModifiers.DEFAULT_MODIFIERS; return ClassModifiers.DEFAULT_MODIFIERS;
} }
} }
@@ -4,15 +4,17 @@ package org.jetbrains.jet.lang.descriptors;
* @author svtk * @author svtk
*/ */
public class ClassModifiers extends Modifiers { public class ClassModifiers extends Modifiers {
public static final ClassModifiers DEFAULT_MODIFIERS = new ClassModifiers(false, false, false); public static final ClassModifiers DEFAULT_MODIFIERS = new ClassModifiers(false, false, false, false);
private boolean open; private boolean open;
private boolean trait; private boolean trait;
private boolean isEnum;
public ClassModifiers(boolean anAbstract, boolean open, boolean trait) { public ClassModifiers(boolean anAbstract, boolean open, boolean trait, boolean isEnum) {
super(anAbstract); super(anAbstract);
this.open = open; this.open = open;
this.trait = trait; this.trait = trait;
this.isEnum = isEnum;
} }
public boolean isOpen() { public boolean isOpen() {
@@ -22,6 +24,8 @@ public class ClassModifiers extends Modifiers {
public boolean isTrait() { public boolean isTrait() {
return trait; return trait;
} }
public boolean isEnum() {
return isEnum;
}
} }
@@ -141,8 +141,8 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
@Override @Override
@NotNull @NotNull
public ClassModifiers getClassModifiers() { public ClassModifiers getModifiers() {
return original.getClassModifiers(); return original.getModifiers();
} }
@Override @Override
@@ -254,7 +254,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@Override @Override
@NotNull @NotNull
public ClassModifiers getClassModifiers() { public ClassModifiers getModifiers() {
return classModifiers; return classModifiers;
} }
@@ -561,10 +561,12 @@ public class ClassDescriptorResolver {
if (modifierList == null) return ClassModifiers.DEFAULT_MODIFIERS; if (modifierList == null) return ClassModifiers.DEFAULT_MODIFIERS;
boolean abstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD); boolean abstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD);
boolean traitModifier = modifierList.hasModifier(JetTokens.TRAIT_KEYWORD); boolean traitModifier = modifierList.hasModifier(JetTokens.TRAIT_KEYWORD);
boolean enumModifier = modifierList.hasModifier(JetTokens.ENUM_KEYWORD);
return new ClassModifiers( return new ClassModifiers(
abstractModifier || traitModifier, abstractModifier || traitModifier,
modifierList.hasModifier(JetTokens.OPEN_KEYWORD) || abstractModifier || traitModifier, modifierList.hasModifier(JetTokens.OPEN_KEYWORD) || abstractModifier || traitModifier,
traitModifier traitModifier,
enumModifier
); );
} }
@@ -487,7 +487,7 @@ public class TopDownAnalyzer {
private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) { private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) {
if (!klass.hasPrimaryConstructor()) return; if (!klass.hasPrimaryConstructor()) return;
if (classDescriptor.getClassModifiers().isTrait()) { if (classDescriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor"); trace.getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor");
} }
@@ -509,7 +509,7 @@ public class TopDownAnalyzer {
} }
private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) {
if (classDescriptor.getClassModifiers().isTrait()) { if (classDescriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(constructor.getNameNode(), "A trait may not have a constructor"); trace.getErrorHandler().genericError(constructor.getNameNode(), "A trait may not have a constructor");
} }
ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor( ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor(
@@ -632,7 +632,7 @@ public class TopDownAnalyzer {
@Override @Override
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
if (descriptor.getClassModifiers().isTrait()) { if (descriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); trace.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation");
} }
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
@@ -653,7 +653,7 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetValueArgumentList valueArgumentList = call.getValueArgumentList(); JetValueArgumentList valueArgumentList = call.getValueArgumentList();
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
if (descriptor.getClassModifiers().isTrait()) { if (descriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes"); trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes");
} }
JetTypeReference typeReference = call.getTypeReference(); JetTypeReference typeReference = call.getTypeReference();
@@ -664,7 +664,7 @@ public class TopDownAnalyzer {
recordSupertype(typeReference, supertype); recordSupertype(typeReference, supertype);
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) { if (classDescriptor != null) {
if (classDescriptor.getClassModifiers().isTrait()) { if (classDescriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(node, "A trait may not have a constructor"); trace.getErrorHandler().genericError(node, "A trait may not have a constructor");
} }
} }
@@ -673,7 +673,7 @@ public class TopDownAnalyzer {
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
} }
} }
else if (!descriptor.getClassModifiers().isTrait()) { else if (!descriptor.getModifiers().isTrait()) {
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype); recordSupertype(typeReference, supertype);
@@ -692,8 +692,8 @@ public class TopDownAnalyzer {
if (supertype != null) { if (supertype != null) {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) { if (classDescriptor != null) {
if (!descriptor.getClassModifiers().isTrait()) { if (!descriptor.getModifiers().isTrait()) {
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getClassModifiers().isTrait()) { if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here"); trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here");
} }
} }
@@ -735,7 +735,7 @@ public class TopDownAnalyzer {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) { if (classDescriptor != null) {
if (!classDescriptor.getClassModifiers().isTrait()) { if (!classDescriptor.getModifiers().isTrait()) {
if (classAppeared) { if (classAppeared) {
trace.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list"); trace.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list");
} }
@@ -987,7 +987,7 @@ public class TopDownAnalyzer {
"Global property can not be abstract"); "Global property can not be abstract");
return; return;
} }
if (!classDescriptor.getClassModifiers().isAbstract()) { if (!classDescriptor.getModifiers().isAbstract()) {
trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD),
"Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName());
return; return;
@@ -1008,7 +1008,7 @@ public class TopDownAnalyzer {
if (initializer == null && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { if (initializer == null && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) { if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) {
trace.getErrorHandler().genericError(nameNode, "Property must be initialized"); trace.getErrorHandler().genericError(nameNode, "Property must be initialized");
} else if (!classDescriptor.getClassModifiers().isTrait()) { } else if (!classDescriptor.getModifiers().isTrait()) {
trace.getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract"); trace.getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract");
} }
} }
@@ -1022,22 +1022,34 @@ public class TopDownAnalyzer {
protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) { protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) {
PsiElement nameIdentifier = function.getNameIdentifier(); PsiElement nameIdentifier = function.getNameIdentifier();
boolean isAbstract = functionDescriptor.getModifiers().isAbstract();
if (containingDescriptor instanceof ClassDescriptor) { if (containingDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
if (functionDescriptor.getModifiers().isAbstract() && !classDescriptor.getClassModifiers().isAbstract()) { boolean inTrait = classDescriptor.getModifiers().isTrait();
boolean inEnum = classDescriptor.getModifiers().isEnum();
boolean inAbstractClass = classDescriptor.getModifiers().isAbstract();
if (isAbstract && !inAbstractClass && !inTrait && !inEnum) {
trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD),
"Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName());
} }
if (function.getBodyExpression() == null && !functionDescriptor.getModifiers().isAbstract() && nameIdentifier != null) { if (isAbstract && inTrait) {
trace.getErrorHandler().genericWarning(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD),
"Abstract modifier is not necessary in traits");
}
if (function.getBodyExpression() != null && isAbstract) {
trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD),
"Method " + function.getName() + " with body can not be abstract");
}
if (function.getBodyExpression() == null && !isAbstract && !inTrait && nameIdentifier != null) {
trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract");
} }
return; return;
} }
if (functionDescriptor.getModifiers().isAbstract()) { if (isAbstract) {
trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD),
"Global function " + function.getName() + " can not be abstract"); "Global function " + function.getName() + " can not be abstract");
} }
if (function.getBodyExpression() == null && !functionDescriptor.getModifiers().isAbstract() && nameIdentifier != null) { if (function.getBodyExpression() == null && !isAbstract && nameIdentifier != null) {
trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Global function " + function.getName() + " must have body"); trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Global function " + function.getName() + " must have body");
} }
} }
@@ -101,7 +101,7 @@ public class CallResolver {
@Override @Override
public <D extends CallableDescriptor> boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { public <D extends CallableDescriptor> boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) {
if (descriptor instanceof ConstructorDescriptor) { if (descriptor instanceof ConstructorDescriptor) {
ClassModifiers modifiers = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getClassModifiers(); ClassModifiers modifiers = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModifiers();
if (modifiers.isAbstract()) { if (modifiers.isAbstract()) {
tracing.reportOverallResolutionError(trace, "Can not create an instance of an abstract class"); tracing.reportOverallResolutionError(trace, "Can not create an instance of an abstract class");
return false; return false;
@@ -21,9 +21,6 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements
private JetType classObjectType; private JetType classObjectType;
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>"); private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
private ClassModifiers modifiers; private ClassModifiers modifiers;
// private boolean isAbstract;
// private boolean isOpen;
// private boolean isTrait;
public JavaClassDescriptor(DeclarationDescriptor containingDeclaration) { public JavaClassDescriptor(DeclarationDescriptor containingDeclaration) {
super(containingDeclaration); super(containingDeclaration);
@@ -33,11 +30,8 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements
this.typeConstructor = typeConstructor; this.typeConstructor = typeConstructor;
} }
public void setModifiers(boolean isAbstract, boolean isOpen, boolean isTrait) { public void setModifiers(boolean isAbstract, boolean isOpen, boolean isTrait, boolean isEnum) {
this.modifiers = new ClassModifiers(isAbstract, isOpen, isTrait); this.modifiers = new ClassModifiers(isAbstract, isOpen, isTrait, isEnum);
// this.isAbstract = isAbstract;
// this.isOpen = isOpen;
// this.isTrait = isTrait;
} }
public void setUnsubstitutedMemberScope(JavaClassMembersScope memberScope) { public void setUnsubstitutedMemberScope(JavaClassMembersScope memberScope) {
@@ -131,24 +125,9 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements
return false; return false;
} }
// @Override
// public boolean isAbstract() {
// return isAbstract;
// }
//
// @Override
// public boolean isOpen() {
// return isOpen;
// }
//
// @Override
// public boolean isTrait() {
// return isTrait;
// }
@Override @Override
@NotNull @NotNull
public ClassModifiers getClassModifiers() { public ClassModifiers getModifiers() {
return modifiers; return modifiers;
} }
@@ -109,7 +109,8 @@ public class JavaDescriptorResolver {
classDescriptor.setModifiers( classDescriptor.setModifiers(
psiClass.hasModifierProperty(PsiModifier.ABSTRACT), psiClass.hasModifierProperty(PsiModifier.ABSTRACT),
!psiClass.hasModifierProperty(PsiModifier.FINAL), !psiClass.hasModifierProperty(PsiModifier.FINAL),
psiClass.isInterface() psiClass.isInterface(),
psiClass.isEnum()
); );
classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor);
classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false));
@@ -251,7 +251,7 @@ public class DescriptorRenderer {
@Override @Override
public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) { public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) {
String keyword = descriptor.getClassModifiers().isTrait() ? "trait class" : "class"; String keyword = descriptor.getModifiers().isTrait() ? "trait class" : "class";
renderClassDescriptor(descriptor, builder, keyword); renderClassDescriptor(descriptor, builder, keyword);
return super.visitClassDescriptor(descriptor, builder); return super.visitClassDescriptor(descriptor, builder);
} }
+29 -1
View File
@@ -1,5 +1,33 @@
namespace abstract namespace abstract
class MyClass() {
fun <error>f</error>()
fun g() {}
<error>abstract</error> fun h()
<error>abstract</error> fun j() {}
}
abstract class MyAbstractClass() {
fun <error>f</error>()
fun g() {}
abstract fun h()
<error>abstract</error> fun j() {}
}
trait class MyTrait {
fun f()
fun g() {}
<warning>abstract</warning> fun h()
<error>abstract</error> fun j() {}
}
enum class MyEnum {
fun <error>f</error>()
fun g() {}
abstract fun h()
<error>abstract</error> fun j() {}
}
class A1() { class A1() {
fun <error>foo</error>(): Int fun <error>foo</error>(): Int
<error>abstract</error> fun f(): Int <error>abstract</error> fun f(): Int
@@ -65,4 +93,4 @@ abstract class B3(i: Int) {
fun foo(a: B3) { fun foo(a: B3) {
val a = <error>B3()</error> val a = <error>B3()</error>
val b = <error>B1(2, "s")</error> val b = <error>B1(2, "s")</error>
} }