[JS IR] Use a backing field initializer for js() code folding
During a translation of the code from js() call to statement list, the compiler folds the code string. For that it uses property bodies. However the bodies can not be loaded in an incremental rebuild. The patch uses the backing field initializers of constant properties. The initializers are always loaded. ^KT-57002 Fixed
This commit is contained in:
committed by
Space Team
parent
c91ef606f7
commit
f82d3e63a2
+6
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferen
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
||||
@@ -131,6 +132,11 @@ internal class ICHasher {
|
||||
}
|
||||
}
|
||||
(symbol.owner as? IrAnnotationContainer)?.let(hashCalculator::updateAnnotationContainer)
|
||||
(symbol.owner as? IrProperty)?.let { irProperty ->
|
||||
if (irProperty.isConst) {
|
||||
irProperty.backingField?.initializer?.let(hashCalculator::update)
|
||||
}
|
||||
}
|
||||
return hashCalculator.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
+13
-3
@@ -63,7 +63,7 @@ private fun translateJsCodeIntoStatementList(
|
||||
return parseExpressionOrStatement(jsCode, ThrowExceptionOnErrorReporter, currentScope, CodePosition(startLine, offset), fileName)
|
||||
}
|
||||
|
||||
fun foldString(expression: IrExpression, context: JsIrBackendContext?): String? {
|
||||
private fun foldString(expression: IrExpression, context: JsIrBackendContext?): String? {
|
||||
val builder = StringBuilder()
|
||||
var foldingFailed = false
|
||||
expression.acceptVoid(object : IrElementVisitorVoid {
|
||||
@@ -92,6 +92,7 @@ fun foldString(expression: IrExpression, context: JsIrBackendContext?): String?
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
val owner = expression.symbol.owner
|
||||
val propertySymbol = owner.correspondingPropertySymbol
|
||||
return when {
|
||||
expression.origin == IrStatementOrigin.PLUS ->
|
||||
expression.acceptChildrenVoid(this)
|
||||
@@ -99,8 +100,17 @@ fun foldString(expression: IrExpression, context: JsIrBackendContext?): String?
|
||||
owner.body?.acceptChildrenVoid(InitFunVisitor(context))
|
||||
expression.acceptChildrenVoid(this)
|
||||
}
|
||||
owner == owner.correspondingPropertySymbol?.owner?.getter -> {
|
||||
owner.body?.acceptChildrenVoid(this)
|
||||
propertySymbol != null && owner == propertySymbol.owner.getter -> {
|
||||
if (propertySymbol.owner.isConst) {
|
||||
val initializer = propertySymbol.owner.backingField?.initializer
|
||||
if (initializer != null) {
|
||||
initializer.acceptChildrenVoid(this)
|
||||
} else {
|
||||
foldingFailed = true
|
||||
}
|
||||
} else {
|
||||
owner.body?.acceptChildrenVoid(this)
|
||||
}
|
||||
expression.acceptChildrenVoid(this)
|
||||
}
|
||||
else -> super.visitCall(expression)
|
||||
|
||||
Generated
+5
@@ -250,6 +250,11 @@ public class JsIrES6InvalidationTestGenerated extends AbstractJsIrES6Invalidatio
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCode/");
|
||||
}
|
||||
|
||||
@TestMetadata("jsCodeWithConstString")
|
||||
public void testJsCodeWithConstString() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstString/");
|
||||
}
|
||||
|
||||
@TestMetadata("jsExport")
|
||||
public void testJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExport/");
|
||||
|
||||
+5
@@ -250,6 +250,11 @@ public class JsIrInvalidationTestGenerated extends AbstractJsIrInvalidationTest
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCode/");
|
||||
}
|
||||
|
||||
@TestMetadata("jsCodeWithConstString")
|
||||
public void testJsCodeWithConstString() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstString/");
|
||||
}
|
||||
|
||||
@TestMetadata("jsExport")
|
||||
public void testJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExport/");
|
||||
|
||||
@@ -3,3 +3,4 @@ STEP 0:
|
||||
added file: l2.kt
|
||||
STEP 1:
|
||||
dependencies: lib1
|
||||
updated imports: l2.kt
|
||||
|
||||
@@ -5,4 +5,4 @@ STEP 0:
|
||||
dirty js: lib1, lib2, main
|
||||
STEP 1:
|
||||
libs: lib1, lib2, main
|
||||
dirty js: lib1
|
||||
dirty js: lib1, lib2
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun test() : dynamic {
|
||||
return js("var testObj = { $constKey: 0 }; testObj.$constKey")
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun test() : dynamic {
|
||||
return js("var testObj = { $constKey: 1 }; testObj.$constKey")
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun test() : dynamic {
|
||||
return js("var testObj = { $constKey: $constVal }; testObj.$constKey")
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun test() : dynamic {
|
||||
return js("var testObj = { ${constKey1}__bar: $constVal + 1 }; testObj.foo__$constKey2")
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
internal const val constKey = "foo"
|
||||
|
||||
internal const val constVal = "2"
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
internal const val constKey1 = "foo"
|
||||
internal const val constKey2 = "bar"
|
||||
|
||||
internal const val constKey = constKey1 + "_" + constKey2
|
||||
|
||||
internal const val constVal = "3"
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
internal const val constKey1 = "foo"
|
||||
internal const val constKey2 = "bar"
|
||||
|
||||
internal const val constKey = constKey1 + "__" + constKey2
|
||||
|
||||
internal const val constVal = "4"
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
internal const val constKey1 = "foo"
|
||||
internal const val constKey2 = "bar"
|
||||
|
||||
internal const val constKey = constKey1 + "__" + constKey2
|
||||
|
||||
internal const val constVal = 5
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
STEP 0:
|
||||
modifications:
|
||||
U : l1.0.kt -> l1.kt
|
||||
U : js.0.kt -> js.kt
|
||||
U : test.0.kt -> test.kt
|
||||
added file: l1.kt, js.kt, test.kt
|
||||
STEP 1:
|
||||
modifications:
|
||||
U : js.1.kt -> js.kt
|
||||
modified ir: js.kt
|
||||
STEP 2:
|
||||
modifications:
|
||||
U : js.2.kt -> js.kt
|
||||
modified ir: js.kt
|
||||
updated exports: l1.kt
|
||||
STEP 3:
|
||||
modifications:
|
||||
U : l1.3.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
updated imports: js.kt
|
||||
STEP 4:
|
||||
modifications:
|
||||
U : test.4.kt -> test.kt
|
||||
modified ir: test.kt
|
||||
STEP 5:
|
||||
modifications:
|
||||
U : l1.5.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
updated imports: js.kt
|
||||
STEP 6:
|
||||
modifications:
|
||||
U : js.6.kt -> js.kt
|
||||
modified ir: js.kt
|
||||
updated exports: l1.kt
|
||||
STEP 7:
|
||||
modifications:
|
||||
U : l1.7.kt -> l1.kt
|
||||
modified ir: l1.kt, js.kt
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun doTest() = test()
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun doTest() = test() + 1
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fun box(stepId: Int): String {
|
||||
val x = doTest()
|
||||
when (stepId) {
|
||||
in 0..7 -> if (x != stepId) return "Fail, got $x"
|
||||
else -> return "Unknown"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
added file: m.kt
|
||||
STEP 1..7:
|
||||
dependencies: lib1
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
MODULES: lib1, main
|
||||
|
||||
STEP 0:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
STEP 1..7:
|
||||
libs: lib1, main
|
||||
dirty js: lib1
|
||||
Reference in New Issue
Block a user