[JS IR] Fix kotlin.js.js with complex constant expressions
Use IR interpreter to evaluate complex constexprs
This commit is contained in:
+1
-1
@@ -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<IrValueDeclaration>()
|
||||
|
||||
+5
-2
@@ -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<JsEx
|
||||
|
||||
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
|
||||
if (context.checkIfJsCode(expression.symbol)) {
|
||||
val statements = translateJsCodeIntoStatementList(expression.getValueArgument(0) ?: error("JsCode is expected"))
|
||||
val statements = translateJsCodeIntoStatementList(expression.getValueArgument(0) ?: error("JsCode is expected"))!!
|
||||
if (statements.isEmpty()) return JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(3)) // TODO: report warning or even error
|
||||
|
||||
val lastStatement = statements.last()
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.constructedClassType
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
@@ -106,7 +106,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
|
||||
override fun visitCall(expression: IrCall, data: JsGenerationContext): JsStatement {
|
||||
if (data.checkIfJsCode(expression.symbol)) {
|
||||
val statements = translateJsCodeIntoStatementList(expression.getValueArgument(0) ?: error("JsCode is expected"))
|
||||
val statements = translateJsCodeIntoStatementList(expression.getValueArgument(0) ?: error("JsCode is expected"))!!
|
||||
return when (statements.size) {
|
||||
0 -> JsEmpty
|
||||
1 -> statements.single()
|
||||
|
||||
+10
-7
@@ -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<JsStatement> {
|
||||
// TODO: check non simple compile time constants (expressions)
|
||||
// Returns null if constant expression could not be parsed
|
||||
fun translateJsCodeIntoStatementList(code: IrExpression): List<JsStatement>? {
|
||||
// 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 <T> visitConst(expression: IrConst<T>) {
|
||||
builder.append(expression.kind.valueOf(expression))
|
||||
@@ -38,10 +39,12 @@ fun translateJsCodeIntoStatementList(code: IrExpression): List<JsStatement> {
|
||||
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<JsStatement>? {
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user