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