diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index 002ce6dcd5d..4f8d45290b1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -35,6 +35,7 @@ import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE_PARAMETER; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.classCanHaveAbstractMembers; public class DeclarationsChecker { @NotNull @@ -385,7 +386,7 @@ public class DeclarationsChecker { ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; if (abstractNode != null) { //has abstract modifier - if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) { + if (!classCanHaveAbstractMembers(classDescriptor)) { String name = property.getName(); trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor)); return; @@ -489,9 +490,7 @@ public class DeclarationsChecker { if (containingDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; - boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS; - boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT; - if (hasAbstractModifier && !inAbstractClass && !inEnum) { + if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) { trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor)); } if (hasAbstractModifier && inTrait) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 6d0ef7b3869..0cf8e855062 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -49,6 +49,7 @@ import java.util.*; import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.classCanHaveAbstractMembers; import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; public class OverrideResolver { @@ -372,7 +373,7 @@ public class OverrideResolver { trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, manyImpl.iterator().next())); } - if (classDescriptor.getModality() != Modality.ABSTRACT && !abstractNoImpl.isEmpty()) { + if (!classCanHaveAbstractMembers(classDescriptor) && !abstractNoImpl.isEmpty()) { trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next())); } } diff --git a/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.kt b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.kt new file mode 100644 index 00000000000..e0d0e769052 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.kt @@ -0,0 +1,21 @@ +trait T1 { + fun foo() +} + +enum class EnumImplementingTraitWithFun: T1 { + E1 { + override fun foo() {} + } + E2 +} + +trait T2 { + val bar: Int +} + +enum class EnumImplementingTraitWithVal: T2 { + E1 { + override val bar = 1 + } + E2 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.txt b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.txt new file mode 100644 index 00000000000..ce8b23a7f02 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.txt @@ -0,0 +1,123 @@ +package + +internal final enum class EnumImplementingTraitWithFun : kotlin.Enum, T1 { + private constructor EnumImplementingTraitWithFun() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + public enum entry E1 : EnumImplementingTraitWithFun { + private constructor E1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumImplementingTraitWithFun.E1 { + private constructor () + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public enum entry E2 : EnumImplementingTraitWithFun { + private constructor E2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumImplementingTraitWithFun.E2 { + private constructor () + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): EnumImplementingTraitWithFun + public final /*synthesized*/ fun values(): kotlin.Array +} + +internal final enum class EnumImplementingTraitWithVal : kotlin.Enum, T2 { + private constructor EnumImplementingTraitWithVal() + internal abstract override /*1*/ /*fake_override*/ val bar: kotlin.Int + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + public enum entry E1 : EnumImplementingTraitWithVal { + private constructor E1() + internal open override /*1*/ val bar: kotlin.Int = 1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumImplementingTraitWithVal.E1 { + private constructor () + internal open override /*1*/ /*fake_override*/ val bar: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public enum entry E2 : EnumImplementingTraitWithVal { + private constructor E2() + internal abstract override /*1*/ /*fake_override*/ val bar: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumImplementingTraitWithVal.E2 { + private constructor () + internal abstract override /*1*/ /*fake_override*/ val bar: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): EnumImplementingTraitWithVal + public final /*synthesized*/ fun values(): kotlin.Array +} + +internal trait T1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal trait T2 { + internal abstract val bar: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 66bda19e23e..c0d5da5ecb5 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3781,6 +3781,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("enumImplementingTrait.kt") + public void testEnumImplementingTrait() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/enumImplementingTrait.kt"); + doTest(fileName); + } + @TestMetadata("enumInheritance.kt") public void testEnumInheritance() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/enumInheritance.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 9ac8fb7c476..7a313d5d16e 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -401,4 +401,8 @@ public class DescriptorUtils { builtIns.getNumber().getDefaultType().equals(type) || builtIns.getAnyType().equals(type); } + + public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) { + return classDescriptor.getModality() == Modality.ABSTRACT || classDescriptor.getKind() == ClassKind.ENUM_CLASS; + } }