[AA-FIR] Add support for constant evaluation of string templates.

Support FirStringConcatenationCall in FirCompileTimeConstantEvaluator.
This allows string templates ("foo${bar}") to be evaluated as constants,
assuming the interpolated expressions are themselves constant.

In addition, fixes some handling bugs with KtConstantEvaluationMode,
where some expressions that are not valid in a `const val` declaration
were being supported for `CONSTANT_EXPRESSION_EVALUATION`, including
non-static final Java fields in FIR, and composite expressions of
non-const properties in FE1.0.
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt
index f733cda..c58e4ad 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt
@@ -31,18 +31,11 @@
     ): KtConstantValue? {
         val bindingContext = analysisContext.analyze(expression)
 
-        if (mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION) {
-            // TODO: how to _not_ evaluate composite expression with a non-const property?
-            // TODO: how to _not_ evaluate expressions with a compilation error, e.g., uninitialized property access
-            when (expression) {
-                is KtNameReferenceExpression -> {
-                    val reference = bindingContext[BindingContext.REFERENCE_TARGET, expression]
-                    if (reference is PropertyDescriptor && !reference.isConst) return null
-                }
-            }
-        }
-
         val constant = ConstantExpressionEvaluator.getPossiblyErrorConstant(expression, bindingContext)
+        if (mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION) {
+            // TODO: how to _not_ evaluate expressions with a compilation error, e.g., uninitialized property access
+            if (constant?.usesNonConstValAsConstant == true) return null
+        }
         return constant?.toConstantValue(TypeUtils.NO_EXPECTED_TYPE)?.toKtConstantValue()
     }
 }
diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/compileTimeConstantProvider/Fe10IdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/compileTimeConstantProvider/Fe10IdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
index 5a9918d..0c4c021 100644
--- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/compileTimeConstantProvider/Fe10IdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
+++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/compileTimeConstantProvider/Fe10IdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
@@ -233,6 +233,18 @@
     }
 
     @Test
+    @TestMetadata("string_templateConst.kt")
+    public void testString_templateConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt");
+    }
+
+    @Test
+    @TestMetadata("string_templateNonConst.kt")
+    public void testString_templateNonConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt");
+    }
+
+    @Test
     @TestMetadata("string_toString.kt")
     public void testString_toString() throws Exception {
         runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_toString.kt");
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt
index 7cc200c..8b88824 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt
@@ -15,6 +15,7 @@
 import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
 import org.jetbrains.kotlin.fir.declarations.utils.isConst
 import org.jetbrains.kotlin.fir.declarations.utils.isFinal
+import org.jetbrains.kotlin.fir.declarations.utils.isStatic
 import org.jetbrains.kotlin.fir.expressions.*
 import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
 import org.jetbrains.kotlin.fir.psi
@@ -66,6 +67,9 @@
             is FirFunctionCall -> {
                 evaluateFunctionCall(fir, mode)
             }
+            is FirStringConcatenationCall -> {
+                evaluateStringConcatenationCall(fir, mode)
+            }
             is FirNamedReference -> {
                 fir.toResolvedPropertySymbol()?.toConstExpression(mode)
             }
@@ -93,7 +97,7 @@
         mode: KtConstantEvaluationMode,
     ): FirConstExpression<*>? {
         return when {
-            mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION && !isFinal -> null
+            mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION && !(isStatic && isFinal) -> null
             isVal && hasInitializer -> {
                 evaluate(fir.initializer, mode)
             }
@@ -152,6 +156,20 @@
         )
     }
 
+    private fun evaluateStringConcatenationCall(
+        stringConcatenationCall: FirStringConcatenationCall,
+        mode: KtConstantEvaluationMode,
+    ): FirConstExpression<String>? {
+        val concatenated = buildString {
+            for (arg in stringConcatenationCall.arguments) {
+                val evaluated = evaluate(arg, mode) ?: return null
+                append(evaluated.value.toString())
+            }
+        }
+
+        return ConstantValueKind.String.toConstExpression(stringConcatenationCall.source, concatenated)
+    }
+
     private fun evaluateFunctionCall(
         functionCall: FirFunctionCall,
         mode: KtConstantEvaluationMode,
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeDependentAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeDependentAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
index 4d1ab48..bbf9259 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeDependentAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeDependentAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
@@ -233,6 +233,18 @@
     }
 
     @Test
+    @TestMetadata("string_templateConst.kt")
+    public void testString_templateConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt");
+    }
+
+    @Test
+    @TestMetadata("string_templateNonConst.kt")
+    public void testString_templateNonConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt");
+    }
+
+    @Test
     @TestMetadata("string_toString.kt")
     public void testString_toString() throws Exception {
         runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_toString.kt");
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
index f12f7ad..2b40bc8 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirIdeNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
@@ -233,6 +233,18 @@
     }
 
     @Test
+    @TestMetadata("string_templateConst.kt")
+    public void testString_templateConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt");
+    }
+
+    @Test
+    @TestMetadata("string_templateNonConst.kt")
+    public void testString_templateNonConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt");
+    }
+
+    @Test
     @TestMetadata("string_toString.kt")
     public void testString_toString() throws Exception {
         runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_toString.kt");
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirStandaloneNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirStandaloneNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
index 714d54a..00142ea 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirStandaloneNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/compileTimeConstantProvider/FirStandaloneNormalAnalysisSourceModuleCompileTimeConstantEvaluatorTestGenerated.java
@@ -233,6 +233,18 @@
     }
 
     @Test
+    @TestMetadata("string_templateConst.kt")
+    public void testString_templateConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt");
+    }
+
+    @Test
+    @TestMetadata("string_templateNonConst.kt")
+    public void testString_templateNonConst() throws Exception {
+        runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt");
+    }
+
+    @Test
     @TestMetadata("string_toString.kt")
     public void testString_toString() throws Exception {
         runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_toString.kt");
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/javaFinalField.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/javaFinalField.txt
index 700c8b4..d9b12f5 100644
--- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/javaFinalField.txt
+++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/javaFinalField.txt
@@ -1,8 +1,8 @@
 expression: Build.VERSION_CODES().CUPCAKE
 
 CONSTANT_EXPRESSION_EVALUATION
-constant: 3
-constantValueKind: Int
+constant: NOT_EVALUATED
+constantValueKind: NOT_EVALUATED
 
 CONSTANT_LIKE_EXPRESSION_EVALUATION
 constantLike: 3
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_DivByOtherProperty_val.descriptors.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_DivByOtherProperty_val.descriptors.txt
deleted file mode 100644
index 9cd860b..0000000
--- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_DivByOtherProperty_val.descriptors.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-expression: 42 / d
-
-CONSTANT_EXPRESSION_EVALUATION
-constant: 42
-constantValueKind: Int
-
-CONSTANT_LIKE_EXPRESSION_EVALUATION
-constantLike: 42
-constantLikeValueKind: Int
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt
new file mode 100644
index 0000000..01f3700
--- /dev/null
+++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.kt
@@ -0,0 +1,4 @@
+const val QUESTION = "the ultimate question of life, the universe, and everything"
+const val ANSWER = 42
+
+val MESSAGE = <expr>"The answer to ${QUESTION} is ${ANSWER}."</expr>
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.txt
new file mode 100644
index 0000000..b0a74ff
--- /dev/null
+++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateConst.txt
@@ -0,0 +1,9 @@
+expression: "The answer to ${QUESTION} is ${ANSWER}."
+
+CONSTANT_EXPRESSION_EVALUATION
+constant: "The answer to the ultimate question of life, the universe, and everything is 42."
+constantValueKind: String
+
+CONSTANT_LIKE_EXPRESSION_EVALUATION
+constantLike: "The answer to the ultimate question of life, the universe, and everything is 42."
+constantLikeValueKind: String
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt
new file mode 100644
index 0000000..1692398
--- /dev/null
+++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.kt
@@ -0,0 +1,5 @@
+val QUESTION = "the ultimate question of life, the universe, and everything"
+val ANSWER = 42
+val QUESTION_MEANING = null
+
+val MESSAGE = <expr>"The answer to ${QUESTION} is ${ANSWER}. The question is: ${QUESTION_MEANING}"</expr>
diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.txt
new file mode 100644
index 0000000..a11063a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/string_templateNonConst.txt
@@ -0,0 +1,9 @@
+expression: "The answer to ${QUESTION} is ${ANSWER}. The question is: ${QUESTION_MEANING}"
+
+CONSTANT_EXPRESSION_EVALUATION
+constant: NOT_EVALUATED
+constantValueKind: NOT_EVALUATED
+
+CONSTANT_LIKE_EXPRESSION_EVALUATION
+constantLike: "The answer to the ultimate question of life, the universe, and everything is 42. The question is: null"
+constantLikeValueKind: String