[JS IR] Fix the instability of LoweredDeclarationSignature

A suspend stub for the abstract function
 may be created in the context of the child function.
 If on an incremental rebuild the stub is created from
 the parent context (e.g. a file with the child is not modified),
 the resulting LoweredDeclarationSignature will be different.
 It will lead to a broken cross-module reference and broken JS code.
 Therefore it is required to wrap the creation routine
 into StageController::restrictTo() explicitly.

^KT-54934 Fixed
This commit is contained in:
Alexander Korepanov
2022-11-14 11:57:42 +01:00
committed by Space Team
parent fb38ab3cbb
commit f7063555ca
11 changed files with 76 additions and 1 deletions
@@ -121,7 +121,9 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: CommonBackendCon
function.copyReceiverParametersFrom(this, substitutionMap)
function.overriddenSymbols += overriddenSymbols.map {
it.owner.getOrCreateFunctionWithContinuationStub(context).symbol
factory.stageController.restrictTo(it.owner) {
it.owner.getOrCreateFunctionWithContinuationStub(context).symbol
}
}
function.valueParameters = valueParameters.map { it.copyTo(function) }
@@ -280,6 +280,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
}
@TestMetadata("suspendInterfaceWithDefaultParams")
public void testSuspendInterfaceWithDefaultParams() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/");
}
@TestMetadata("toplevelProperties")
public void testToplevelProperties() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/toplevelProperties/");
@@ -0,0 +1,6 @@
class ClassA1 : InterfaceA {
override suspend fun functionA(x: Int, s: String, b: Boolean?): Int {
return 0
}
}
@@ -0,0 +1,5 @@
interface InterfaceA {
suspend fun functionA(x: Int, s: String, b: Boolean? = null): Int
}
fun function1(): Int = 0
@@ -0,0 +1,5 @@
interface InterfaceA {
suspend fun functionA(x: Int, s: String, b: Boolean? = null): Int
}
fun function1(): Int = 1
@@ -0,0 +1,9 @@
STEP 0:
modifications:
U : l1I.0.kt -> l1I.kt
U : l1A.0.kt -> l1A.kt
added file: l1I.kt, l1A.kt
STEP 1:
modifications:
U : l1I.1.kt -> l1I.kt
modified ir: l1I.kt
@@ -0,0 +1,6 @@
class ClassA2 : InterfaceA {
override suspend fun functionA(x: Int, s: String, b: Boolean?): Int {
return function1()
}
}
@@ -0,0 +1,7 @@
STEP 0:
dependencies: lib1
modifications:
U : l2A.0.kt -> l2A.kt
added file: l2A.kt
STEP 1:
dependencies: lib1
@@ -0,0 +1,16 @@
internal suspend fun testDefaltParam(stepId: Int): Int {
return callFun(ClassA2())
}
private suspend fun ignoreIt() = ClassA1()
private suspend fun callFun(a: InterfaceA): Int {
return a.functionA(0, "", false)
}
suspend fun box(stepId: Int): String {
if (testDefaltParam(stepId) != stepId) {
return "Fail"
}
return "OK"
}
@@ -0,0 +1,5 @@
STEP 0:
dependencies: lib1, lib2
added file: m.kt
STEP 1:
dependencies: lib1, lib2
@@ -0,0 +1,9 @@
MODULES: lib1, lib2, main
STEP 0:
libs: lib1, lib2, main
dirty js: lib1, lib2, main
STEP 1:
libs: lib1, lib2, main
dirty js: lib1