diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCodeOutliningLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCodeOutliningLowering.kt index ee2f29bd01e..ee92c54b356 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCodeOutliningLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCodeOutliningLowering.kt @@ -134,7 +134,7 @@ private class JsCodeOutlineTransformer( return null val jsCodeArg = expression.getValueArgument(0) ?: error("Expected js code string") - val jsStatements = translateJsCodeIntoStatementList(jsCodeArg) + val jsStatements = translateJsCodeIntoStatementList(jsCodeArg) ?: return null // Collect used Kotlin local variables and parameters. val kotlinLocalsUsedInJs = mutableListOf() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt index 9cdb0b6933a..9020c2c2138 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt @@ -17,7 +17,10 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.isUnit -import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.isEffectivelyExternal +import org.jetbrains.kotlin.ir.util.isEnumClass +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.js.backend.ast.* @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") @@ -190,7 +193,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer JsEmpty 1 -> statements.single() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt index 66e2976b23a..9ab7643dff1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation -import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid @@ -21,15 +20,17 @@ import org.jetbrains.kotlin.js.backend.ast.JsRootScope import org.jetbrains.kotlin.js.backend.ast.JsStatement import org.jetbrains.kotlin.js.parser.parseExpressionOrStatement -fun translateJsCodeIntoStatementList(code: IrExpression): List { - // TODO: check non simple compile time constants (expressions) +// Returns null if constant expression could not be parsed +fun translateJsCodeIntoStatementList(code: IrExpression): List? { // TODO: support proper symbol linkage and label clash resolution - fun foldString(expression: IrExpression): String { + fun foldString(expression: IrExpression): String? { val builder = StringBuilder() + var foldingFailed = false expression.acceptVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) = - error("Parameter of js function must be compile time String constant, not ${element.render()}") + override fun visitElement(element: IrElement) { + foldingFailed = true + } override fun visitConst(expression: IrConst) { builder.append(expression.kind.valueOf(expression)) @@ -38,10 +39,12 @@ fun translateJsCodeIntoStatementList(code: IrExpression): List { override fun visitStringConcatenation(expression: IrStringConcatenation) = expression.acceptChildrenVoid(this) }) + if (foldingFailed) return null + return builder.toString() } - return parseJsCode(foldString(code)) ?: emptyList() + return parseJsCode(foldString(code) ?: return null) } fun parseJsCode(jsCode: String): List? { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrBoxJsES6TestGenerated.java index 29b02cda1d4..5e4781bf9ac 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrBoxJsES6TestGenerated.java @@ -5065,6 +5065,11 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { runTest("js/js.translator/testData/box/jsCode/codeFromVariable.kt"); } + @TestMetadata("constantExpression.kt") + public void testConstantExpression() throws Exception { + runTest("js/js.translator/testData/box/jsCode/constantExpression.kt"); + } + @TestMetadata("continue.kt") public void testContinue() throws Exception { runTest("js/js.translator/testData/box/jsCode/continue.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java index 2677f7f960e..e7168d4ce8e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java @@ -5065,6 +5065,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/jsCode/codeFromVariable.kt"); } + @TestMetadata("constantExpression.kt") + public void testConstantExpression() throws Exception { + runTest("js/js.translator/testData/box/jsCode/constantExpression.kt"); + } + @TestMetadata("continue.kt") public void testContinue() throws Exception { runTest("js/js.translator/testData/box/jsCode/continue.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index e0e63cb3aa9..6366fc5de1b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -5080,6 +5080,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/jsCode/codeFromVariable.kt"); } + @TestMetadata("constantExpression.kt") + public void testConstantExpression() throws Exception { + runTest("js/js.translator/testData/box/jsCode/constantExpression.kt"); + } + @TestMetadata("continue.kt") public void testContinue() throws Exception { runTest("js/js.translator/testData/box/jsCode/continue.kt"); diff --git a/js/js.translator/testData/box/jsCode/constantExpression.kt b/js/js.translator/testData/box/jsCode/constantExpression.kt new file mode 100644 index 00000000000..1eac9834603 --- /dev/null +++ b/js/js.translator/testData/box/jsCode/constantExpression.kt @@ -0,0 +1,13 @@ +// EXPECTED_REACHABLE_NODES: 1282 +package foo + +const val x = '2' +const val y = '+' +const val z = '3' + +fun box(): String { + if (js(x.toString() + z) !== 23) return "Fail 1" + if (js(x.toString() + y + z) !== 5) return "Fail 2" + + return "OK" +} \ No newline at end of file