diff --git a/idea/src/jet/Library.jet b/idea/src/jet/Library.jet index a1af5251d7e..dd9231edeb7 100644 --- a/idea/src/jet/Library.jet +++ b/idea/src/jet/Library.jet @@ -118,7 +118,7 @@ abstract class Number : Hashable { } class Double : Number, Comparable { - fun compareTo(other : Double) : Int + override fun compareTo(other : Double) : Int fun compareTo(other : Float) : Int fun compareTo(other : Long) : Int fun compareTo(other : Int) : Int @@ -181,7 +181,7 @@ class Double : Number, Comparable { class Float : Number, Comparable { fun compareTo(other : Double) : Int - fun compareTo(other : Float) : Int + override fun compareTo(other : Float) : Int fun compareTo(other : Long) : Int fun compareTo(other : Int) : Int fun compareTo(other : Short) : Int @@ -245,7 +245,7 @@ class Float : Number, Comparable { class Long : Number, Comparable { fun compareTo(other : Double) : Int fun compareTo(other : Float) : Int - fun compareTo(other : Long) : Int + override fun compareTo(other : Long) : Int fun compareTo(other : Int) : Int fun compareTo(other : Short) : Int fun compareTo(other : Byte) : Int @@ -317,7 +317,7 @@ class Int : Number, Comparable { fun compareTo(other : Double) : Int fun compareTo(other : Float) : Int fun compareTo(other : Long) : Int - fun compareTo(other : Int) : Int + override fun compareTo(other : Int) : Int fun compareTo(other : Short) : Int fun compareTo(other : Byte) : Int fun compareTo(other : Char) : Int @@ -390,7 +390,7 @@ class Char : Number, Comparable { fun compareTo(other : Long) : Int fun compareTo(other : Int) : Int fun compareTo(other : Short) : Int - fun compareTo(other : Char) : Int + override fun compareTo(other : Char) : Int fun compareTo(other : Byte) : Int fun plus(other : Double) : Double @@ -452,7 +452,7 @@ class Short : Number, Comparable { fun compareTo(other : Float) : Int fun compareTo(other : Long) : Int fun compareTo(other : Int) : Int - fun compareTo(other : Short) : Int + override fun compareTo(other : Short) : Int fun compareTo(other : Byte) : Int fun compareTo(other : Char) : Int @@ -517,7 +517,7 @@ class Byte : Number, Comparable { fun compareTo(other : Int) : Int fun compareTo(other : Short) : Int fun compareTo(other : Char) : Int - fun compareTo(other : Byte) : Int + override fun compareTo(other : Byte) : Int fun plus(other : Double) : Double fun plus(other : Float) : Float diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/MemberModifiers.java b/idea/src/org/jetbrains/jet/lang/descriptors/MemberModifiers.java index 4558f9652d5..f0c74b90bf7 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/MemberModifiers.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/MemberModifiers.java @@ -23,8 +23,4 @@ public class MemberModifiers extends Modifiers { public boolean isOverride() { return isOverride; } - - public boolean isOverridable() { - return isAbstract() || isVirtual() || isOverride(); - } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index c61b94ede24..cb6d9b99f1a 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -221,13 +221,21 @@ public class ClassDescriptorResolver { returnType = ErrorUtils.createErrorType("No type, no body"); } } + MemberModifiers defaultModifiers; + if (containingDescriptor instanceof ClassDescriptor) { + boolean isDefinitelyAbstract = ((ClassDescriptor) containingDescriptor).getModifiers().isTrait() && function.getBodyExpression() == null; + defaultModifiers = new MemberModifiers(isDefinitelyAbstract, isDefinitelyAbstract, false); + } else { + defaultModifiers = MemberModifiers.DEFAULT_MODIFIERS; + } + MemberModifiers memberModifiers = resolveMemberModifiers(function.getModifierList(), defaultModifiers); functionDescriptor.initialize( receiverType, typeParameterDescriptors, valueParameterDescriptors, returnType, - resolveMemberModifiers(function.getModifierList())); + memberModifiers); trace.record(BindingContext.FUNCTION, function, functionDescriptor); return functionDescriptor; @@ -562,9 +570,10 @@ public class ClassDescriptorResolver { boolean abstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD); boolean traitModifier = modifierList.hasModifier(JetTokens.TRAIT_KEYWORD); boolean enumModifier = modifierList.hasModifier(JetTokens.ENUM_KEYWORD); + boolean openModifier = modifierList.hasModifier(JetTokens.OPEN_KEYWORD); return new ClassModifiers( abstractModifier || traitModifier, - modifierList.hasModifier(JetTokens.OPEN_KEYWORD) || abstractModifier || traitModifier, + openModifier || abstractModifier || traitModifier, traitModifier, enumModifier ); @@ -573,10 +582,13 @@ public class ClassDescriptorResolver { @NotNull private MemberModifiers resolveMemberModifiers(@Nullable JetModifierList modifierList, @NotNull MemberModifiers defaultModifiers) { if (modifierList == null) return defaultModifiers; + boolean abstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD); + boolean virtualModifier = modifierList.hasModifier(JetTokens.VIRTUAL_KEYWORD); + boolean overrideModifier = modifierList.hasModifier(JetTokens.OVERRIDE_KEYWORD); return new MemberModifiers( - modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD), - modifierList.hasModifier(JetTokens.VIRTUAL_KEYWORD), - modifierList.hasModifier(JetTokens.OVERRIDE_KEYWORD) + abstractModifier || defaultModifiers.isAbstract(), + virtualModifier || abstractModifier || overrideModifier || defaultModifiers.isVirtual(), + overrideModifier || defaultModifiers.isOverride() ); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 6e5f0bca14b..e4102b77ff3 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -547,34 +547,37 @@ public class TopDownAnalyzer { } } - private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { + protected void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { -// JetFunction function = (JetFunction) trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); -// boolean isOverride = declaredFunction.getModifiers().isOverride(); + JetFunction function = (JetFunction) trace.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 (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); if (overridden != null) { -// if (isOverride && !overridden.getModifiers().isOverridable()) { -// trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.OVERRIDE_KEYWORD), -// "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and can not be overridden"); -// isOverride = false; -// } + if (hasOverrideModifier && !overridden.getModifiers().isVirtual() && !foundError) { + trace.getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and can not be overridden"); + foundError = true; + } ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); } } -// if (declaredFunction.getModifiers().isOverride() && declaredFunction.getOverriddenDescriptors().size() == 0) { -// trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.OVERRIDE_KEYWORD), -// "Method " + declaredFunction.getName() + " overrides nothing"); + if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { + trace.getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); } -// if (!declaredFunction.getModifiers().isOverride() && declaredFunction.getOverriddenDescriptors().size() > 0) { -// FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); -// trace.getErrorHandler().genericError(function.getNameIdentifier().getNode(), -// "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + -// overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); + PsiElement nameIdentifier = function.getNameIdentifier(); + if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { + FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); + trace.getErrorHandler().genericError(nameIdentifier.getNode(), + "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + + overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); } -// } -// } + } + } @Nullable private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) { @@ -1022,35 +1025,33 @@ public class TopDownAnalyzer { protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) { PsiElement nameIdentifier = function.getNameIdentifier(); - boolean isAbstract = functionDescriptor.getModifiers().isAbstract(); + JetModifierList modifierList = function.getModifierList(); + ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; + boolean hasAbstractModifier = abstractNode != null; if (containingDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; 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), - "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); + if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) { + trace.getErrorHandler().genericError(abstractNode, "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); } - if (isAbstract && inTrait) { - trace.getErrorHandler().genericWarning(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Abstract modifier is not necessary in traits"); + if (hasAbstractModifier && inTrait) { + trace.getErrorHandler().genericWarning(abstractNode, "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 && hasAbstractModifier) { + trace.getErrorHandler().genericError(abstractNode, "Method " + function.getName() + " with body can not be abstract"); } - if (function.getBodyExpression() == null && !isAbstract && !inTrait && nameIdentifier != null) { + if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); } return; } - if (isAbstract) { - trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Global function " + function.getName() + " can not be abstract"); + if (hasAbstractModifier) { + trace.getErrorHandler().genericError(abstractNode, "Function " + function.getName() + " can not be abstract"); } - if (function.getBodyExpression() == null && !isAbstract && nameIdentifier != null) { - trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Global function " + function.getName() + " must have body"); + if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { + trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Function " + function.getName() + " must have body"); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index e5b388ee501..988d94280f8 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -350,7 +350,7 @@ public class JavaDescriptorResolver { resolveTypeParameters(functionDescriptorImpl, method.getTypeParameters()), semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters), semanticServices.getTypeTransformer().transformToType(returnType), - MemberModifiers.DEFAULT_MODIFIERS //TODO + new MemberModifiers(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL), false) ); semanticServices.getTrace().record(BindingContext.FUNCTION, method, functionDescriptorImpl); FunctionDescriptor substitutedFunctionDescriptor = functionDescriptorImpl; diff --git a/idea/testData/checker/regression/OverrideResolution.jet b/idea/testData/checker/regression/OverrideResolution.jet index d29864ae258..d912130a4e0 100644 --- a/idea/testData/checker/regression/OverrideResolution.jet +++ b/idea/testData/checker/regression/OverrideResolution.jet @@ -4,13 +4,13 @@ fun box() { } open class A { - fun foo() {} + virtual fun foo() {} } open class B : A { - fun foo() {} + override fun foo() {} } open class C : B { - fun foo() {} + override fun foo() {} } diff --git a/idea/testData/codegen/bridge.jet b/idea/testData/codegen/bridge.jet index 421e675e7e7..e6f0e1a66a2 100644 --- a/idea/testData/codegen/bridge.jet +++ b/idea/testData/codegen/bridge.jet @@ -1,11 +1,11 @@ import java.lang.Integer open class C { - fun f(): Any = "C f" + virtual fun f(): Any = "C f" } class D() : C { - fun f(): String = "D f" + override fun f(): String = "D f" } fun box(): String{ diff --git a/idea/testData/codegen/classes/classObjectInterface.jet b/idea/testData/codegen/classes/classObjectInterface.jet index 8c0cb8210c4..432bb37bee0 100644 --- a/idea/testData/codegen/classes/classObjectInterface.jet +++ b/idea/testData/codegen/classes/classObjectInterface.jet @@ -2,7 +2,7 @@ class C() { fun getInstance(): Runnable = C class object: Runnable { - fun run(): Unit { } + override fun run(): Unit { } } } diff --git a/idea/testData/codegen/controlStructures/forUserType.jet b/idea/testData/codegen/controlStructures/forUserType.jet index be95e3b437e..b3aa1cff8a0 100644 --- a/idea/testData/codegen/controlStructures/forUserType.jet +++ b/idea/testData/codegen/controlStructures/forUserType.jet @@ -70,24 +70,24 @@ fun box() : String { } class MyCollection1(): java.lang.Iterable { - fun iterator(): java.util.Iterator = MyIterator() + override fun iterator(): java.util.Iterator = MyIterator() class MyIterator(): java.util.Iterator { var k : Int = 5 - fun next() : Int = k-- - fun hasNext() = k > 0 + override fun next() : Int = k-- + override fun hasNext() = k > 0 } } class MyCollection2(): Iterable { - fun iterator(): Iterator = MyIterator() + override fun iterator(): Iterator = MyIterator() class MyIterator(): Iterator { var k : Int = 5 - fun next() : Int = k-- - fun hasNext() = k > 0 + override fun next() : Int = k-- + override fun hasNext() = k > 0 } }