diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index d48511d667e..60d6ffcaa24 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -49,9 +49,7 @@ import java.util.List; import java.util.Map; import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*; -import static org.jetbrains.kotlin.diagnostics.Severity.ERROR; -import static org.jetbrains.kotlin.diagnostics.Severity.INFO; -import static org.jetbrains.kotlin.diagnostics.Severity.WARNING; +import static org.jetbrains.kotlin.diagnostics.Severity.*; /** * For error messages, see DefaultErrorMessages and IdeErrorMessages. @@ -272,6 +270,8 @@ public interface Errors { DiagnosticFactory0 NULLABLE_SUPERTYPE = DiagnosticFactory0.create(ERROR, NULLABLE_TYPE); DiagnosticFactory0 DYNAMIC_SUPERTYPE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 CLASS_CANNOT_BE_EXTENDED_DIRECTLY = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 MISSING_CONSTRUCTOR_KEYWORD = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 NON_PRIVATE_CONSTRUCTOR_IN_ENUM = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 1704a98e5f8..baf8cf61690 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -541,6 +541,7 @@ public class DefaultErrorMessages { MAP.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects"); MAP.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class"); MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton"); + MAP.put(CLASS_CANNOT_BE_EXTENDED_DIRECTLY, "Class {0} cannot be extended directly", NAME); MAP.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain"); MAP.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java index 05efaf483cc..3f369321219 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java @@ -584,6 +584,9 @@ public class BodyResolver { else if (ModalityKt.isFinalOrEnum(classDescriptor)) { trace.report(FINAL_SUPERTYPE.on(typeReference)); } + else if (KotlinBuiltIns.isEnum(classDescriptor)) { + trace.report(CLASS_CANNOT_BE_EXTENDED_DIRECTLY.on(typeReference, classDescriptor)); + } } } } diff --git a/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.kt b/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.kt new file mode 100644 index 00000000000..3f71edb0bd8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.kt @@ -0,0 +1,9 @@ +class Test1 : Enum("", 0) + +class Outer { + class Test2 : Enum("", 0) +} + +fun outer() { + class Test3 : Enum("", 0) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.txt b/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.txt new file mode 100644 index 00000000000..bb5ed30b994 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.txt @@ -0,0 +1,36 @@ +package + +public fun outer(): kotlin.Unit + +public final class Outer { + public constructor Outer() + 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 + + public final class Test2 : kotlin.Enum { + public constructor Test2() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Outer.Test2): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class Test1 : kotlin.Enum { + public constructor Test1() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Test1): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 25e9d9949f6..c2e1ba64bdc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7363,6 +7363,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("extendingEnumDirectly.kt") + public void testExtendingEnumDirectly() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.kt"); + doTest(fileName); + } + @TestMetadata("extensionNamedAsEnumEntry.kt") public void testExtensionNamedAsEnumEntry() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/extensionNamedAsEnumEntry.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index f00a7013cc7..2b12b751138 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -1040,6 +1040,10 @@ public abstract class KotlinBuiltIns { return descriptor.getContainingDeclaration() == getAny(); } + public static boolean isEnum(@NotNull ClassDescriptor descriptor) { + return classFqNameEquals(descriptor, FQ_NAMES._enum); + } + public static boolean isCharSequence(@Nullable KotlinType type) { return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.charSequence); }