From 121c9200998a001b4f2c13c150ef3d1faba63d01 Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Mon, 13 Feb 2023 14:45:21 +0100 Subject: [PATCH] [JS IR IC] Load only top level signatures for function type interfaces The dependency signature may refer to function type interface properties (e.g. name) or methods. It is impossible to detect (without hacks) which binary symbol for loading is required. However, when loading a property or a method the entire function type interface is loaded. And vice versa, a loading of function type interface loads properties and methods as well. Therefore, load the top level signature only, it must be the signature of function type interface. ^KT-56582 Fixed --- .../ir/backend/js/ic/JsIrLinkerLoader.kt | 8 +++++++- .../JsIrES6InvalidationTestGenerated.java | 5 +++++ .../JsIrInvalidationTestGenerated.java | 5 +++++ .../functionTypeInterfaceReflect/lib1/A.0.kt | 3 +++ .../functionTypeInterfaceReflect/lib1/B.0.kt | 3 +++ .../functionTypeInterfaceReflect/lib1/C.0.kt | 3 +++ .../lib1/module.info | 12 +++++++++++ .../functionTypeInterfaceReflect/main/m.kt | 11 ++++++++++ .../main/module.info | 20 +++++++++++++++++++ .../main/test.0.kt | 10 ++++++++++ .../main/test.1.kt | 10 ++++++++++ .../main/test.2.kt | 11 ++++++++++ .../main/test.3.kt | 12 +++++++++++ .../functionTypeInterfaceReflect/project.info | 5 +++++ 14 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/A.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/B.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/C.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/m.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.1.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.2.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.3.kt create mode 100644 js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/project.info diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt index 6282214b26c..852cbbe59e9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt @@ -189,7 +189,13 @@ internal class JsIrLinkerLoader( for (loadingSrcFileSignatures in loadingSrcFiles.values) { for (loadingSignature in loadingSrcFileSignatures.getExportedSignatures()) { if (checkIsFunctionInterface(loadingSignature)) { - moduleDeserializer.tryDeserializeIrSymbol(loadingSignature, BinarySymbolData.SymbolKind.CLASS_SYMBOL) + // The signature may refer to function type interface properties (e.g. name) or methods. + // It is impossible to detect (without hacks) here which binary symbol is required. + // However, when loading a property or a method the entire function type interface is loaded. + // And vice versa, a loading of function type interface loads properties and methods as well. + // Therefore, load the top level signature only - it must be the signature of function type interface. + val topLevelSignature = loadingSignature.topLevelSignature() + moduleDeserializer.tryDeserializeIrSymbol(topLevelSignature, BinarySymbolData.SymbolKind.CLASS_SYMBOL) } else if (loadingSignature in moduleDeserializer) { moduleDeserializer.addModuleReachableTopLevel(loadingSignature) } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java index ac4de7eb438..4e27816da92 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.java @@ -175,6 +175,11 @@ public class JsIrES6InvalidationTestGenerated extends AbstractJsIrES6Invalidatio runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterface/"); } + @TestMetadata("functionTypeInterfaceReflect") + public void testFunctionTypeInterfaceReflect() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/"); + } + @TestMetadata("genericFunctions") public void testGenericFunctions() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/genericFunctions/"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java index 7bca10aad0c..8807ff5d38f 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationTestGenerated.java @@ -175,6 +175,11 @@ public class JsIrInvalidationTestGenerated extends AbstractJsIrInvalidationTest runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterface/"); } + @TestMetadata("functionTypeInterfaceReflect") + public void testFunctionTypeInterfaceReflect() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/"); + } + @TestMetadata("genericFunctions") public void testGenericFunctions() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/genericFunctions/"); diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/A.0.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/A.0.kt new file mode 100644 index 00000000000..cc41d9671c4 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/A.0.kt @@ -0,0 +1,3 @@ +object A { + public fun testFunction() { } +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/B.0.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/B.0.kt new file mode 100644 index 00000000000..a0ac75471c6 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/B.0.kt @@ -0,0 +1,3 @@ +object B { + public fun testFunction(x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any) { } +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/C.0.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/C.0.kt new file mode 100644 index 00000000000..b10926a20f8 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/C.0.kt @@ -0,0 +1,3 @@ +object C { + public fun testFunction(x1: Any, x2: Any, x3: Any, x4: Any, x5: Any, x6: Any, x7: Any, x8: Any) { } +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/module.info b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/module.info new file mode 100644 index 00000000000..3ab6a1079ad --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/lib1/module.info @@ -0,0 +1,12 @@ +STEP 0: + modifications: + U : A.0.kt -> A.kt + U : B.0.kt -> B.kt + U : C.0.kt -> C.kt + added file: A.kt, B.kt, C.kt +STEP 1: + updated exports: A.kt, B.kt +STEP 2: + updated exports: A.kt +STEP 3: + updated exports: C.kt diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/m.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/m.kt new file mode 100644 index 00000000000..b5665751c6b --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/m.kt @@ -0,0 +1,11 @@ +fun box(stepId: Int): String { + val s = test() + when (stepId) { + 0 -> if (s != "class A - testFunction") return "Fail, got '$s'" + 1 -> if (s != "class B - testFunction") return "Fail, got '$s'" + 2 -> if (s != "class A - testFunction, class B - testFunction") return "Fail, got '$s'" + 3 -> if (s != "class A - testFunction, class B - testFunction, class C - testFunction") return "Fail, got '$s'" + else -> return "Unknown" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/module.info b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/module.info new file mode 100644 index 00000000000..a960b60bdb2 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/module.info @@ -0,0 +1,20 @@ +STEP 0: + dependencies: lib1 + modifications: + U : test.0.kt -> test.kt + added file: m.kt, test.kt +STEP 1: + dependencies: lib1 + modifications: + U : test.1.kt -> test.kt + modified ir: test.kt +STEP 2: + dependencies: lib1 + modifications: + U : test.2.kt -> test.kt + modified ir: test.kt +STEP 3: + dependencies: lib1 + modifications: + U : test.3.kt -> test.kt + modified ir: test.kt diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.0.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.0.kt new file mode 100644 index 00000000000..3603c5c6259 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.0.kt @@ -0,0 +1,10 @@ +import kotlin.reflect.KClass + +private fun nameToString( + kClass: KClass<*>, + methodName: String +) = "$kClass - $methodName" + +internal fun test(): String { + return nameToString(A::class, A::testFunction.name) +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.1.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.1.kt new file mode 100644 index 00000000000..6485b15f536 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.1.kt @@ -0,0 +1,10 @@ +import kotlin.reflect.KClass + +private fun nameToString( + kClass: KClass<*>, + methodName: String +) = "$kClass - $methodName" + +internal fun test(): String { + return nameToString(B::class, B::testFunction.name) +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.2.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.2.kt new file mode 100644 index 00000000000..78278c59e1d --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.2.kt @@ -0,0 +1,11 @@ +import kotlin.reflect.KClass + +private fun nameToString( + kClass: KClass<*>, + methodName: String +) = "$kClass - $methodName" + +internal fun test(): String { + return "${nameToString(A::class, A::testFunction.name)}, " + + "${nameToString(B::class, B::testFunction.name)}" +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.3.kt b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.3.kt new file mode 100644 index 00000000000..231d32242d6 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/main/test.3.kt @@ -0,0 +1,12 @@ +import kotlin.reflect.KClass + +private fun nameToString( + kClass: KClass<*>, + methodName: String +) = "$kClass - $methodName" + +internal fun test(): String { + return "${nameToString(A::class, A::testFunction.name)}, " + + "${nameToString(B::class, B::testFunction.name)}, " + + "${nameToString(C::class, C::testFunction.name)}" +} diff --git a/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/project.info b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/project.info new file mode 100644 index 00000000000..c8d9369c64b --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/project.info @@ -0,0 +1,5 @@ +MODULES: lib1, main + +STEP 0..3: + libs: lib1, main + dirty js: lib1, main