[Compiler CLI] Sort flags and features before appending them to string

 JS IR BE incremental compilation infrastructure uses
 LanguageVersionSettings::toString method to detect if any
 compiler features or flags were enabled or disabled.
 It is important that the features and flags order are stable
 in the result string.

^KT-56580 Fixed
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt
index c8e6bfd..42361b6 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.backend.common.serialization.Hash128Bits
 import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.KotlinCompilerVersion
 import org.jetbrains.kotlin.config.languageVersionSettings
 import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferences
 import org.jetbrains.kotlin.ir.IrElement
@@ -87,6 +88,8 @@
     private val hashCalculator = HashCalculatorForIC()
 
     fun calculateConfigHash(config: CompilerConfiguration): ICHash {
+        hashCalculator.update(KotlinCompilerVersion.VERSION)
+
         val importantSettings = listOf(
             JSConfigurationKeys.GENERATE_DTS,
             JSConfigurationKeys.MODULE_KIND,
diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
index 0c59ccb..b73e4cb 100644
--- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
@@ -538,7 +538,7 @@
 
     override fun toString() = buildString {
         append("Language = $languageVersion, API = $apiVersion")
-        specificFeatures.forEach { (feature, state) ->
+        specificFeatures.entries.sortedBy { (feature, _) -> feature.ordinal }.forEach { (feature, state) ->
             val char = when (state) {
                 LanguageFeature.State.ENABLED -> '+'
                 LanguageFeature.State.ENABLED_WITH_WARNING -> '~'
@@ -546,7 +546,7 @@
             }
             append(" $char$feature")
         }
-        analysisFlags.forEach { (flag, value) ->
+        analysisFlags.entries.sortedBy { (flag, _) -> flag.toString() }.forEach { (flag, value) ->
             append(" $flag:$value")
         }
     }
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java
index 4e27816..415c18f 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java
@@ -255,6 +255,11 @@
         runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotation/");
     }
 
+    @TestMetadata("languageVersionSettings")
+    public void testLanguageVersionSettings() throws Exception {
+        runTest("js/js.translator/testData/incremental/invalidation/languageVersionSettings/");
+    }
+
     @TestMetadata("localInlineFunction")
     public void testLocalInlineFunction() throws Exception {
         runTest("js/js.translator/testData/incremental/invalidation/localInlineFunction/");
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java
index 8807ff5..420db07 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java
@@ -255,6 +255,11 @@
         runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotation/");
     }
 
+    @TestMetadata("languageVersionSettings")
+    public void testLanguageVersionSettings() throws Exception {
+        runTest("js/js.translator/testData/incremental/invalidation/languageVersionSettings/");
+    }
+
     @TestMetadata("localInlineFunction")
     public void testLocalInlineFunction() throws Exception {
         runTest("js/js.translator/testData/incremental/invalidation/localInlineFunction/");
diff --git a/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/l1.kt b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/l1.kt
new file mode 100644
index 0000000..9ef0f8b
--- /dev/null
+++ b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/l1.kt
@@ -0,0 +1 @@
+fun demo() = 42
diff --git a/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/module.info b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/module.info
new file mode 100644
index 0000000..65006af
--- /dev/null
+++ b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/lib1/module.info
@@ -0,0 +1,6 @@
+STEP 0..3:
+    added file: l1.kt
+STEP 4..5:
+STEP 6:
+    added file: l1.kt
+STEP 7:
diff --git a/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/m.kt b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/m.kt
new file mode 100644
index 0000000..4c45e2b
--- /dev/null
+++ b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/m.kt
@@ -0,0 +1,7 @@
+fun box(stepId: Int): String {
+    when (stepId) {
+        in 0..7 -> if (demo() != 42) return "Fail"
+        else -> return "Unknown"
+    }
+    return "OK"
+}
diff --git a/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/module.info b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/module.info
new file mode 100644
index 0000000..2da8a32
--- /dev/null
+++ b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/main/module.info
@@ -0,0 +1,10 @@
+STEP 0..3:
+    dependencies: lib1
+    added file: m.kt
+STEP 4..5:
+    dependencies: lib1
+STEP 6:
+    dependencies: lib1
+    added file: m.kt
+STEP 7:
+    dependencies: lib1
diff --git a/js/js.translator/testData/incremental/invalidation/languageVersionSettings/project.info b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/project.info
new file mode 100644
index 0000000..43a1037
--- /dev/null
+++ b/js/js.translator/testData/incremental/invalidation/languageVersionSettings/project.info
@@ -0,0 +1,30 @@
+MODULES: lib1, main
+
+STEP 0:
+    libs: lib1, main
+    dirty js: lib1, main
+STEP 1:
+    language: +TypeAliases
+    libs: lib1, main
+    dirty js: lib1, main
+STEP 2:
+    language: +TypeAliases, +BoundCallableReferences, +LocalDelegatedProperties, +TopLevelSealedInheritance
+    libs: lib1, main
+    dirty js: lib1, main
+STEP 3:
+    language: +TypeAliases, +BoundCallableReferences, +TopLevelSealedInheritance
+    libs: lib1, main
+    dirty js: lib1, main
+STEP 4:
+    language: +BoundCallableReferences, +TopLevelSealedInheritance, +TypeAliases
+    libs: lib1, main
+STEP 5:
+    language: +BoundCallableReferences, +TypeAliases, +TopLevelSealedInheritance
+    libs: lib1, main
+STEP 6:
+    language: +BoundCallableReferences, -TypeAliases, +TopLevelSealedInheritance
+    libs: lib1, main
+    dirty js: lib1, main
+STEP 7:
+    language: +TopLevelSealedInheritance, +BoundCallableReferences, +TypeAliases
+    libs: lib1, main