From 624e507ec2785abd8476eb1be7c925e2e60da7e1 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 16 Oct 2014 20:42:40 +0400 Subject: [PATCH] Make enum classes comparable #KT-3727 Fixed --- .../boxWithStdlib/enum/sortEnumEntries.kt | 16 +++++++++++++ .../tests/enum/overrideFinalEnumMethods.kt | 2 ++ .../tests/enum/overrideFinalEnumMethods.txt | 3 +++ ...lackBoxWithStdlibCodegenTestGenerated.java | 18 +++++++++++++- core/builtins/native/kotlin/Enum.kt | 4 +++- .../plugin/completion/CompletionSorting.kt | 20 +++++++--------- .../k2js/test/semantics/EnumTest.java | 4 ++++ .../testData/enum/cases/enumIsComparable.kt | 24 +++++++++++++++++++ .../testData/enum/cases/standardMethods.kt | 2 ++ js/js.translator/testData/kotlin_lib.js | 9 +++++++ 10 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/enum/sortEnumEntries.kt create mode 100644 js/js.translator/testData/enum/cases/enumIsComparable.kt diff --git a/compiler/testData/codegen/boxWithStdlib/enum/sortEnumEntries.kt b/compiler/testData/codegen/boxWithStdlib/enum/sortEnumEntries.kt new file mode 100644 index 00000000000..2efe29f7cb5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/enum/sortEnumEntries.kt @@ -0,0 +1,16 @@ +import Game.* + +enum class Game { + ROCK + PAPER + SCISSORS + LIZARD + SPOCK +} + +fun box(): String { + val a = array(LIZARD, SCISSORS, SPOCK, ROCK, PAPER) + a.sort() + val str = a.joinToString(" ") + return if (str == "ROCK PAPER SCISSORS LIZARD SPOCK") "OK" else "Fail: $str" +} diff --git a/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.kt b/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.kt index c3673f411e4..a4589543ea3 100644 --- a/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.kt +++ b/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.kt @@ -4,6 +4,8 @@ enum class E { override fun name(): String = "lol" override fun ordinal(): Int = 0 + override fun compareTo(other: E) = -1 + override fun equals(other: Any?) = true override fun hashCode() = -1 } diff --git a/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.txt b/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.txt index 06ea6b239d3..fc92b0ecc91 100644 --- a/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.txt +++ b/compiler/testData/diagnostics/tests/enum/overrideFinalEnumMethods.txt @@ -2,6 +2,7 @@ package internal final enum class E : kotlin.Enum { private constructor E() + public open override /*1*/ fun compareTo(/*0*/ other: E): kotlin.Int public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ fun hashCode(): kotlin.Int public open override /*1*/ fun name(): kotlin.String @@ -10,6 +11,7 @@ internal final enum class E : kotlin.Enum { public enum entry ENTRY : E { private constructor ENTRY() + public open override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): 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 name(): kotlin.String @@ -18,6 +20,7 @@ internal final enum class E : kotlin.Enum { public class object : E.ENTRY { private constructor () + public open override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): 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 name(): kotlin.String diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index f1e40644885..b5b3c61997b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -32,7 +32,7 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxWithStdlib") @TestDataPath("$PROJECT_ROOT") -@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class}) +@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Enum.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class}) @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxWithStdlib() throws Exception { @@ -1129,6 +1129,22 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/enum") + @TestDataPath("$PROJECT_ROOT") + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class Enum extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInEnum() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/enum"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("sortEnumEntries.kt") + public void testSortEnumEntries() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/enum/sortEnumEntries.kt"); + doTestWithStdlib(fileName); + } + + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/evaluate") @TestDataPath("$PROJECT_ROOT") @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) diff --git a/core/builtins/native/kotlin/Enum.kt b/core/builtins/native/kotlin/Enum.kt index 6504391f0f0..8f8ccc786e3 100644 --- a/core/builtins/native/kotlin/Enum.kt +++ b/core/builtins/native/kotlin/Enum.kt @@ -16,10 +16,12 @@ package kotlin -public abstract class Enum>(name: String, ordinal: Int) { +public abstract class Enum>(name: String, ordinal: Int): Comparable { public final fun name(): String public final fun ordinal(): Int + public override final fun compareTo(other: E): Int + public override final fun equals(other: Any?): Boolean public override final fun hashCode(): Int public override fun toString(): String diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSorting.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSorting.kt index 7fa9db5d7b3..f28ceb43854 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSorting.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSorting.kt @@ -61,9 +61,7 @@ private object PriorityWeigher : LookupElementWeigher("kotlin.priority") { } private object KindWeigher : LookupElementWeigher("kotlin.kind") { - enum class Weight : Comparable { - override fun compareTo(other: Weight) = ordinal().compareTo(other.ordinal()) - + enum class Weight { localOrParameter property keyword @@ -71,7 +69,7 @@ private object KindWeigher : LookupElementWeigher("kotlin.kind") { packages } - override fun weigh(element: LookupElement): Weight { + override fun weigh(element: LookupElement): Comparable { val o = element.getObject() return when (o) { is DeclarationDescriptorLookupObject -> when (o.descriptor) { @@ -84,7 +82,7 @@ private object KindWeigher : LookupElementWeigher("kotlin.kind") { is KeywordLookupObject -> Weight.keyword else -> Weight.default - } + } as Comparable // TODO: a temporary hack until kotlin.Enum : kotlin.Comparable } } @@ -103,9 +101,7 @@ private object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMa } private class JetDeclarationRemotenessWeigher(private val file: JetFile) : LookupElementWeigher("kotlin.declarationRemoteness") { - private enum class Weight : Comparable { - override fun compareTo(other: Weight) = ordinal().compareTo(other.ordinal()) - + private enum class Weight { kotlinDefaultImport thisFile imported @@ -113,12 +109,12 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku notImported } - override fun weigh(element: LookupElement): Weight { + override fun weigh(element: LookupElement): Comparable { val o = element.getObject() if (o is DeclarationDescriptorLookupObject) { val elementFile = o.psiElement?.getContainingFile() if (elementFile is JetFile && elementFile.getOriginalFile() == file) { - return Weight.thisFile + return Weight.thisFile as Comparable // TODO: a temporary hack until kotlin.Enum : kotlin.Comparable } val fqName = DescriptorUtils.getFqName(o.descriptor).toString() @@ -129,10 +125,10 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku ImportInsertHelper.getInstance().needImport(importPath, file) -> Weight.notImported ImportInsertHelper.getInstance().isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport else -> Weight.imported - } + } as Comparable // TODO: a temporary hack until kotlin.Enum : kotlin.Comparable } } - return Weight.normal + return Weight.normal as Comparable // TODO: a temporary hack until kotlin.Enum : kotlin.Comparable } } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java index 8be7e2e43ed..33b840861a3 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java @@ -46,4 +46,8 @@ public class EnumTest extends SingleFileTranslationTest { public void testSuperCallInEnumLiteral() throws Exception { checkFooBoxIsOk(); } + + public void testEnumIsComparable() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/testData/enum/cases/enumIsComparable.kt b/js/js.translator/testData/enum/cases/enumIsComparable.kt new file mode 100644 index 00000000000..8d22c961ee4 --- /dev/null +++ b/js/js.translator/testData/enum/cases/enumIsComparable.kt @@ -0,0 +1,24 @@ +package foo + +enum class A { + one + two +} + +fun box(): String { + val x = A.one.compareTo(A.two) + if (x != -1) return "Fail cmp(one, two) = $x" + val y = A.two.compareTo(A.one) + if (y != 1) return "Fail cmp(two, one) = $y" + + if (!(A.one < A.two)) return "Fail !(one < two)" + if (A.one >= A.two) return "Fail one >= two" + + if (!(A.two > A.one)) return "Fail !(two > one)" + if (A.two <= A.one) return "Fail two <= one" + + val z = A.one.compareTo(A.one) + if (z != 0) return "Fail cmp(one, one) = $z" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/enum/cases/standardMethods.kt b/js/js.translator/testData/enum/cases/standardMethods.kt index 20aa427a899..c8517a574ee 100644 --- a/js/js.translator/testData/enum/cases/standardMethods.kt +++ b/js/js.translator/testData/enum/cases/standardMethods.kt @@ -23,6 +23,7 @@ fun box(): String { val ok2 = Simple.valueOf("OK") if (!ok2.equals(ok)) return "ok2 not equal ok" + if (ok2.hashCode() != ok.hashCode()) return "hash(ok2) not equal hash(ok)" if (!ok2.identityEquals(ok)) return "ok2 not identity equal ok" @@ -33,6 +34,7 @@ fun box(): String { if (A.c.toString() != "c") return "A.c.toString() != c, it: ${A.c.toString()}" if (A.valueOf("b") != A.b) return "A.valueOf('b') != A.b" if (A.a == A.b) return "A.a == A.b" + if (A.a.hashCode() == A.b.hashCode()) return "hash(A.a) == hash(A.b)" if (A.a.name() != "a") return "A.a.name() != a, it: ${A.a.name()}" if (A.b.name() != "b") return "A.b.name() != b, it: ${A.b.name()}" diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index 00ce9f75723..b132913f544 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -292,6 +292,15 @@ ordinal: function () { return this.ordinal$; }, + equals_za3rmp$: function (o) { + return this === o; + }, + hashCode: function () { + return getObjectHashCode(this); + }, + compareTo_za3rmp$: function (o) { + return this.ordinal$ < o.ordinal$ ? -1 : this.ordinal$ > o.ordinal$ ? 1 : 0; + }, toString: function () { return this.name(); }