diff --git a/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt b/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt new file mode 100644 index 00000000000..92b69222523 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt @@ -0,0 +1,12 @@ +public fun publicToInternalFunction() = 42 +public fun publicToPrivateFunction() = 42 + +open class Container { + public fun publicToProtectedFunction() = 42 + public fun publicToInternalFunction() = 42 + public fun publicToPrivateFunction() = 42 + + protected fun protectedToPublicFunction() = 42 + protected fun protectedToInternalFunction() = 42 + protected fun protectedToPrivateFunction() = 42 +} diff --git a/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt.1 b/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt.1 new file mode 100644 index 00000000000..168fe22ba66 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/lib1/l1.kt.1 @@ -0,0 +1,12 @@ +internal fun publicToInternalFunction() = 42 +private fun publicToPrivateFunction() = 42 + +open class Container { + protected fun publicToProtectedFunction() = 42 + internal fun publicToInternalFunction() = 42 + private fun publicToPrivateFunction() = 42 + + public fun protectedToPublicFunction() = 42 + internal fun protectedToInternalFunction() = 42 + private fun protectedToPrivateFunction() = 42 +} diff --git a/compiler/testData/klibABI/changeFunctionVisibility/lib1/module.info b/compiler/testData/klibABI/changeFunctionVisibility/lib1/module.info new file mode 100644 index 00000000000..99edefccd79 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/lib1/module.info @@ -0,0 +1,6 @@ +STEP 0: + dependencies: stdlib +STEP 1: + dependencies: stdlib + modifications: + U : l1.kt.1 -> l1.kt diff --git a/compiler/testData/klibABI/changeFunctionVisibility/lib2/l2.kt b/compiler/testData/klibABI/changeFunctionVisibility/lib2/l2.kt new file mode 100644 index 00000000000..4b24ade7d72 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/lib2/l2.kt @@ -0,0 +1,11 @@ +class ContainerImpl : Container() { + // Just to check that accessing from within the class hierarchy has the same effect as accessing from the outside: + fun publicToProtectedFunctionAccess() = publicToProtectedFunction() + fun publicToInternalFunctionAccess() = publicToInternalFunction() + fun publicToPrivateFunctionAccess() = publicToPrivateFunction() + + // As far as protected members can't be accessed outside of the class hierarchy, we need special accessors. + fun protectedToPublicFunctionAccess() = protectedToPublicFunction() + fun protectedToInternalFunctionAccess() = protectedToInternalFunction() + fun protectedToPrivateFunctionAccess() = protectedToPrivateFunction() +} diff --git a/compiler/testData/klibABI/changeFunctionVisibility/lib2/module.info b/compiler/testData/klibABI/changeFunctionVisibility/lib2/module.info new file mode 100644 index 00000000000..391aab979a6 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/lib2/module.info @@ -0,0 +1,2 @@ +STEP 0: + dependencies: stdlib, lib1 \ No newline at end of file diff --git a/compiler/testData/klibABI/changeFunctionVisibility/main/m.kt b/compiler/testData/klibABI/changeFunctionVisibility/main/m.kt new file mode 100644 index 00000000000..9d5a55deffd --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/main/m.kt @@ -0,0 +1,127 @@ +fun test1(): String { + return try { + publicToInternalFunction() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL1" } + } +} + +fun test2(): String { + return try { + publicToPrivateFunction() + "FAIL2" + } catch(e: Throwable) { + e.checkLinkageError("function publicToPrivateFunction can not be called") + } +} + +fun test3(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedFunction() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL3" } + } +} + +fun test4(): String { + val c = ContainerImpl() + return try { + c.publicToInternalFunction() + "FAIL4" + } catch(e: Throwable) { + e.checkLinkageError("function publicToInternalFunction can not be called") + } +} + +fun test5(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateFunction() + "FAIL5" + } catch(e: Throwable) { + e.checkLinkageError("function publicToPrivateFunction can not be called") + } +} + +fun test6(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedFunctionAccess() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL6" } + } +} + +fun test7(): String { + val c = ContainerImpl() + return try { + c.publicToInternalFunctionAccess() + "FAIL7" + } catch(e: Throwable) { + e.checkLinkageError("function publicToInternalFunction can not be called") + } +} + +fun test8(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateFunctionAccess() + "FAIL8" + } catch(e: Throwable) { + e.checkLinkageError("function publicToPrivateFunction can not be called") + } +} + +fun test9(): String { + val c = ContainerImpl() + return try { + c.protectedToPublicFunctionAccess() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL9" } + } +} + +fun test10(): String { + val c = ContainerImpl() + return try { + c.protectedToInternalFunctionAccess() + "FAIL10" + } catch(e: Throwable) { + e.checkLinkageError("function protectedToInternalFunction can not be called") + } +} + +fun test11(): String { + val c = ContainerImpl() + return try { + c.protectedToPrivateFunctionAccess() + "FAIL11" + } catch(e: Throwable) { + e.checkLinkageError("function protectedToPrivateFunction can not be called") + } +} + +fun box() = checkResults(test1(), test2(), test3(), test4(), test5(), test6(), test7(), test8(), test9(), test10(), test11()) + +private fun Throwable.checkLinkageError(prefix: String): String { + if (this::class.simpleName != "IrLinkageError") return "Unexpected throwable: ${this::class}" + + val expectedMessagePrefix = "$prefix because it uses unlinked symbols" + val actualMessage = message.orEmpty() + + return if (actualMessage.startsWith(expectedMessagePrefix)) + "OK" + else + "EXPECTED: $expectedMessagePrefix, ACTUAL: $actualMessage" +} + +private fun checkResults(vararg results: String): String = when { + results.isEmpty() -> "no results to check" + results.all { it == "OK" } -> "OK" + else -> results.joinToString("\n") +} diff --git a/compiler/testData/klibABI/changeFunctionVisibility/main/module.info b/compiler/testData/klibABI/changeFunctionVisibility/main/module.info new file mode 100644 index 00000000000..62f7f4fab07 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/main/module.info @@ -0,0 +1,2 @@ +STEP 0: + dependencies: stdlib, lib1, lib2 \ No newline at end of file diff --git a/compiler/testData/klibABI/changeFunctionVisibility/project.info b/compiler/testData/klibABI/changeFunctionVisibility/project.info new file mode 100644 index 00000000000..2147306d715 --- /dev/null +++ b/compiler/testData/klibABI/changeFunctionVisibility/project.info @@ -0,0 +1,7 @@ +MODULES: lib1, lib2, main + +STEP 0: + libs: lib1, lib2, main + +STEP 1: + libs: lib1 \ No newline at end of file diff --git a/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt b/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt new file mode 100644 index 00000000000..99bbb9e4e5d --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt @@ -0,0 +1,20 @@ +public val publicToInternalProperty1 = 42 +public val publicToInternalProperty2 get() = 42 +public val publicToPrivateProperty1 = 42 +public val publicToPrivateProperty2 get() = 42 + +open class Container { + public val publicToProtectedProperty1 = 42 + public val publicToProtectedProperty2 get() = 42 + public val publicToInternalProperty1 = 42 + public val publicToInternalProperty2 get() = 42 + public val publicToPrivateProperty1 = 42 + public val publicToPrivateProperty2 get() = 42 + + protected val protectedToPublicProperty1 = 42 + protected val protectedToPublicProperty2 get() = 42 + protected val protectedToInternalProperty1 = 42 + protected val protectedToInternalProperty2 get() = 42 + protected val protectedToPrivateProperty1 = 42 + protected val protectedToPrivateProperty2 get() = 42 +} diff --git a/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt.1 b/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt.1 new file mode 100644 index 00000000000..bb5e646d009 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/lib1/l1.kt.1 @@ -0,0 +1,20 @@ +internal val publicToInternalProperty1 = 42 +internal val publicToInternalProperty2 get() = 42 +private val publicToPrivateProperty1 = 42 +private val publicToPrivateProperty2 get() = 42 + +open class Container { + protected val publicToProtectedProperty1 = 42 + protected val publicToProtectedProperty2 get() = 42 + internal val publicToInternalProperty1 = 42 + internal val publicToInternalProperty2 get() = 42 + private val publicToPrivateProperty1 = 42 + private val publicToPrivateProperty2 get() = 42 + + public val protectedToPublicProperty1 = 42 + public val protectedToPublicProperty2 get() = 42 + internal val protectedToInternalProperty1 = 42 + internal val protectedToInternalProperty2 get() = 42 + private val protectedToPrivateProperty1 = 42 + private val protectedToPrivateProperty2 get() = 42 +} diff --git a/compiler/testData/klibABI/changePropertyVisibility/lib1/module.info b/compiler/testData/klibABI/changePropertyVisibility/lib1/module.info new file mode 100644 index 00000000000..99edefccd79 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/lib1/module.info @@ -0,0 +1,6 @@ +STEP 0: + dependencies: stdlib +STEP 1: + dependencies: stdlib + modifications: + U : l1.kt.1 -> l1.kt diff --git a/compiler/testData/klibABI/changePropertyVisibility/lib2/l2.kt b/compiler/testData/klibABI/changePropertyVisibility/lib2/l2.kt new file mode 100644 index 00000000000..1eac7b1eb86 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/lib2/l2.kt @@ -0,0 +1,17 @@ +class ContainerImpl : Container() { + // Just to check that accessing from within the class hierarchy has the same effect as accessing from the outside: + fun publicToProtectedProperty1Access() = publicToProtectedProperty1 + fun publicToProtectedProperty2Access() = publicToProtectedProperty2 + fun publicToInternalProperty1Access() = publicToInternalProperty1 + fun publicToInternalProperty2Access() = publicToInternalProperty2 + fun publicToPrivateProperty1Access() = publicToPrivateProperty1 + fun publicToPrivateProperty2Access() = publicToPrivateProperty2 + + // As far as protected members can't be accessed outside of the class hierarchy, we need special accessors. + fun protectedToPublicProperty1Access() = protectedToPublicProperty1 + fun protectedToPublicProperty2Access() = protectedToPublicProperty2 + fun protectedToInternalProperty1Access() = protectedToInternalProperty1 + fun protectedToInternalProperty2Access() = protectedToInternalProperty2 + fun protectedToPrivateProperty1Access() = protectedToPrivateProperty1 + fun protectedToPrivateProperty2Access() = protectedToPrivateProperty2 +} diff --git a/compiler/testData/klibABI/changePropertyVisibility/lib2/module.info b/compiler/testData/klibABI/changePropertyVisibility/lib2/module.info new file mode 100644 index 00000000000..391aab979a6 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/lib2/module.info @@ -0,0 +1,2 @@ +STEP 0: + dependencies: stdlib, lib1 \ No newline at end of file diff --git a/compiler/testData/klibABI/changePropertyVisibility/main/m.kt b/compiler/testData/klibABI/changePropertyVisibility/main/m.kt new file mode 100644 index 00000000000..52adee4cb6e --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/main/m.kt @@ -0,0 +1,238 @@ +fun test1(): String { + return try { + publicToInternalProperty1 + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL1" } + } +} + +fun test2(): String { + return try { + publicToInternalProperty2 + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL2" } + } +} + +fun test3(): String { + return try { + publicToPrivateProperty1 + "FAIL3" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty1. can not be called") + } +} + +fun test4(): String { + return try { + publicToPrivateProperty2 + "FAIL4" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty2. can not be called") + } +} + +fun test5(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedProperty1 + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL5" } + } +} + +fun test6(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedProperty2 + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL6" } + } +} + +fun test7(): String { + val c = ContainerImpl() + return try { + c.publicToInternalProperty1 + "FAIL7" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToInternalProperty1. can not be called") + } +} + +fun test8(): String { + val c = ContainerImpl() + return try { + c.publicToInternalProperty2 + "FAIL8" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToInternalProperty2. can not be called") + } +} + +fun test9(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateProperty1 + "FAIL9" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty1. can not be called") + } +} + +fun test10(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateProperty2 + "FAIL10" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty2. can not be called") + } +} + +fun test11(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedProperty1Access() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL11" } + } +} + +fun test12(): String { + val c = ContainerImpl() + return try { + c.publicToProtectedProperty2Access() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL12" } + } +} + +fun test13(): String { + val c = ContainerImpl() + return try { + c.publicToInternalProperty1Access() + "FAIL13" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToInternalProperty1. can not be called") + } +} + +fun test14(): String { + val c = ContainerImpl() + return try { + c.publicToInternalProperty2Access() + "FAIL14" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToInternalProperty2. can not be called") + } +} + +fun test15(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateProperty1Access() + "FAIL15" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty1. can not be called") + } +} + +fun test16(): String { + val c = ContainerImpl() + return try { + c.publicToPrivateProperty2Access() + "FAIL16" + } catch(e: Throwable) { + e.checkLinkageError("property accessor publicToPrivateProperty2. can not be called") + } +} + +fun test17(): String { + val c = ContainerImpl() + return try { + c.protectedToPublicProperty1Access() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL17" } + } +} + +fun test18(): String { + val c = ContainerImpl() + return try { + c.protectedToPublicProperty2Access() + "OK" + } catch(e: Throwable) { + e.message.orEmpty().ifBlank { "FAIL18" } + } +} + +fun test19(): String { + val c = ContainerImpl() + return try { + c.protectedToInternalProperty1Access() + "FAIL19" + } catch(e: Throwable) { + e.checkLinkageError("property accessor protectedToInternalProperty1. can not be called") + } +} + +fun test20(): String { + val c = ContainerImpl() + return try { + c.protectedToInternalProperty2Access() + "FAIL20" + } catch(e: Throwable) { + e.checkLinkageError("property accessor protectedToInternalProperty2. can not be called") + } +} + +fun test21(): String { + val c = ContainerImpl() + return try { + c.protectedToPrivateProperty1Access() + "FAIL21" + } catch(e: Throwable) { + e.checkLinkageError("property accessor protectedToPrivateProperty1. can not be called") + } +} + +fun test22(): String { + val c = ContainerImpl() + return try { + c.protectedToPrivateProperty2Access() + "FAIL22" + } catch(e: Throwable) { + e.checkLinkageError("property accessor protectedToPrivateProperty2. can not be called") + } +} + +fun box() = checkResults( + test1(), test2(), test3(), test4(), test5(), test6(), test7(), test8(), test9(), test10(), + test11(), test12(), test13(), test14(), test15(), test16(), test17(), test18(), test19(), test20(), + test21(), test22()) + +private fun Throwable.checkLinkageError(prefix: String): String { + if (this::class.simpleName != "IrLinkageError") return "Unexpected throwable: ${this::class}" + + val expectedMessagePrefix = "$prefix because it uses unlinked symbols" + val actualMessage = message.orEmpty() + + return if (actualMessage.startsWith(expectedMessagePrefix)) + "OK" + else + "EXPECTED: $expectedMessagePrefix, ACTUAL: $actualMessage" +} + +private fun checkResults(vararg results: String): String = when { + results.isEmpty() -> "no results to check" + results.all { it == "OK" } -> "OK" + else -> results.joinToString("\n") +} diff --git a/compiler/testData/klibABI/changePropertyVisibility/main/module.info b/compiler/testData/klibABI/changePropertyVisibility/main/module.info new file mode 100644 index 00000000000..62f7f4fab07 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/main/module.info @@ -0,0 +1,2 @@ +STEP 0: + dependencies: stdlib, lib1, lib2 \ No newline at end of file diff --git a/compiler/testData/klibABI/changePropertyVisibility/project.info b/compiler/testData/klibABI/changePropertyVisibility/project.info new file mode 100644 index 00000000000..2147306d715 --- /dev/null +++ b/compiler/testData/klibABI/changePropertyVisibility/project.info @@ -0,0 +1,7 @@ +MODULES: lib1, lib2, main + +STEP 0: + libs: lib1, lib2, main + +STEP 1: + libs: lib1 \ No newline at end of file diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABINoICTestCaseGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABINoICTestCaseGenerated.java index 9876a496b0f..1b7787dcd7c 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABINoICTestCaseGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABINoICTestCaseGenerated.java @@ -30,6 +30,16 @@ public class JsKLibABINoICTestCaseGenerated extends AbstractJsKLibABINoICTestCas KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/klibABI"), Pattern.compile("^([^_](.+))$"), null, TargetBackend.JS_IR, false); } + @TestMetadata("changeFunctionVisibility") + public void testChangeFunctionVisibility() throws Exception { + runTest("compiler/testData/klibABI/changeFunctionVisibility/"); + } + + @TestMetadata("changePropertyVisibility") + public void testChangePropertyVisibility() throws Exception { + runTest("compiler/testData/klibABI/changePropertyVisibility/"); + } + @TestMetadata("nonAbstractFunctionInAbstractClassBecomesAbstract") public void testNonAbstractFunctionInAbstractClassBecomesAbstract() throws Exception { runTest("compiler/testData/klibABI/nonAbstractFunctionInAbstractClassBecomesAbstract/"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABIWithICTestCaseGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABIWithICTestCaseGenerated.java index 3e1208ee54e..5b0146f1231 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABIWithICTestCaseGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsKLibABIWithICTestCaseGenerated.java @@ -30,6 +30,16 @@ public class JsKLibABIWithICTestCaseGenerated extends AbstractJsKLibABIWithICTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/klibABI"), Pattern.compile("^([^_](.+))$"), null, TargetBackend.JS_IR, false); } + @TestMetadata("changeFunctionVisibility") + public void testChangeFunctionVisibility() throws Exception { + runTest("compiler/testData/klibABI/changeFunctionVisibility/"); + } + + @TestMetadata("changePropertyVisibility") + public void testChangePropertyVisibility() throws Exception { + runTest("compiler/testData/klibABI/changePropertyVisibility/"); + } + @TestMetadata("nonAbstractFunctionInAbstractClassBecomesAbstract") public void testNonAbstractFunctionInAbstractClassBecomesAbstract() throws Exception { runTest("compiler/testData/klibABI/nonAbstractFunctionInAbstractClassBecomesAbstract/"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/KlibABITestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/KlibABITestGenerated.java index ca537f27c0e..a62c4683ff5 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/KlibABITestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/KlibABITestGenerated.java @@ -24,6 +24,18 @@ public class KlibABITestGenerated extends AbstractNativeKlibABITest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/klibABI"), Pattern.compile("^([^_](.+))$"), null, false); } + @Test + @TestMetadata("changeFunctionVisibility") + public void testChangeFunctionVisibility() throws Exception { + runTest("compiler/testData/klibABI/changeFunctionVisibility/"); + } + + @Test + @TestMetadata("changePropertyVisibility") + public void testChangePropertyVisibility() throws Exception { + runTest("compiler/testData/klibABI/changePropertyVisibility/"); + } + @Test @TestMetadata("nonAbstractFunctionInAbstractClassBecomesAbstract") public void testNonAbstractFunctionInAbstractClassBecomesAbstract() throws Exception {