From 1fc7fbed798b0b9f8d3174b76c0998aa9bc8b575 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Fri, 29 Apr 2022 12:13:09 +0000 Subject: [PATCH] rra/ilgonmic/export-call-site [JS IR] Add test with exported overridden property from interface [JS IR] Accessors should not be exported when overridden from non-exported interface Merge-request: KT-MR-6166 Merged-by: Ilya Goncharov ^KT-52144 fixed --- .../transformers/irToJs/JsClassGenerator.kt | 49 ++++++++++--------- .../js/transformers/irToJs/jsAstUtils.kt | 26 +++++----- .../js/test/ir/IrBoxJsTestGenerated.java | 6 +++ .../export/overriddenPropertyFromInterface.kt | 30 ++++++++++++ 4 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 js/js.translator/testData/box/export/overriddenPropertyFromInterface.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 5f694b34617..d68a16f6f68 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.backend.common.compilationException import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported @@ -176,7 +177,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo // }); val getterForwarder = property.getter - .takeIf { it.shouldExportAccessor() } + .takeIf { it.shouldExportAccessor(context.staticContext.backendContext) } .getOrGenerateIfFinal { propertyAccessorForwarder("getter forwarder") { JsReturn(JsInvocation(it)) @@ -184,7 +185,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo } val setterForwarder = property.setter - .takeIf { it.shouldExportAccessor() } + .takeIf { it.shouldExportAccessor(context.staticContext.backendContext) } .getOrGenerateIfFinal { val setterArgName = JsName("value", false) propertyAccessorForwarder("setter forwarder") { @@ -219,20 +220,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo overriddenSymbols.any { it.owner.isDefinedInsideExportedInterface() } } - private fun IrSimpleFunction?.shouldExportAccessor(): Boolean { - if (this == null) return false - - if (parentAsClass.isExported(context.staticContext.backendContext)) return true - - val property = correspondingPropertySymbol!!.owner - - if (property.isOverriddenExported(context.staticContext.backendContext)) { - return isOverriddenExported(context.staticContext.backendContext) - } - - return overridesExternal() || property.getJsName() != null - } - private fun IrSimpleFunction.accessorRef(): JsNameRef? = when (visibility) { DescriptorVisibilities.PRIVATE -> null @@ -260,12 +247,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo return jsElementAccess(name.asString(), classPrototypeRef) } - private fun IrSimpleFunction.overridesExternal(): Boolean { - if (this.isEffectivelyExternal()) return true - - return this.overriddenSymbols.any { it.owner.overridesExternal() } - } - private fun IrClass.shouldCopyFrom(): Boolean { return isInterface && !isEffectivelyExternal() } @@ -430,6 +411,30 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo } } +fun IrSimpleFunction?.shouldExportAccessor(context: JsIrBackendContext): Boolean { + if (this == null) return false + + if (parentAsClass.isExported(context)) return true + + return overriddenStableProperty(context) +} + +fun IrSimpleFunction.overriddenStableProperty(context: JsIrBackendContext): Boolean { + val property = correspondingPropertySymbol!!.owner + + if (property.isOverriddenExported(context)) { + return isOverriddenExported(context) + } + + return overridesExternal() || property.getJsName() != null +} + +private fun IrSimpleFunction.overridesExternal(): Boolean { + if (this.isEffectivelyExternal()) return true + + return this.overriddenSymbols.any { it.owner.overridesExternal() } +} + private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true private val IrClassifierSymbol.isEffectivelyExternal get() = (owner as? IrDeclaration)?.isEffectivelyExternal() == true diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt index 5eb32ad1a1a..354ef1113ec 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt @@ -126,18 +126,20 @@ fun translateCall( property != null && (property.isEffectivelyExternal() || property.isExportedMember(context.staticContext.backendContext)) ) { - val propertyName = context.getNameForProperty(property) - val nameRef = when (jsDispatchReceiver) { - null -> JsNameRef(propertyName) - else -> jsElementAccess(propertyName.ident, jsDispatchReceiver) - } - return when (function) { - property.getter -> nameRef - property.setter -> jsAssignment(nameRef, arguments.single()) - else -> compilationException( - "Function must be an accessor of corresponding property", - function - ) + if (function.overriddenSymbols.isEmpty() || function.overriddenStableProperty(context.staticContext.backendContext)) { + val propertyName = context.getNameForProperty(property) + val nameRef = when (jsDispatchReceiver) { + null -> JsNameRef(propertyName) + else -> jsElementAccess(propertyName.ident, jsDispatchReceiver) + } + return when (function) { + property.getter -> nameRef + property.setter -> jsAssignment(nameRef, arguments.single()) + else -> compilationException( + "Function must be an accessor of corresponding property", + function + ) + } } } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 6128cf0a3d1..41e3acff9ae 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -2568,6 +2568,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/export/overriddenExternalMethodWithSameStableNameMethod.kt"); } + @Test + @TestMetadata("overriddenPropertyFromInterface.kt") + public void testOverriddenPropertyFromInterface() throws Exception { + runTest("js/js.translator/testData/box/export/overriddenPropertyFromInterface.kt"); + } + @Test @TestMetadata("overridenMethod.kt") public void testOverridenMethod() throws Exception { diff --git a/js/js.translator/testData/box/export/overriddenPropertyFromInterface.kt b/js/js.translator/testData/box/export/overriddenPropertyFromInterface.kt new file mode 100644 index 00000000000..3d52db6a828 --- /dev/null +++ b/js/js.translator/testData/box/export/overriddenPropertyFromInterface.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JS_IR + +interface Foo { + val foo: String + + val foo2: String + + var foo3: String +} + +@JsExport +class Bar : Foo { + override val foo: String + get() = "foo" + + override val foo2: String = "foo2" + + override var foo3: String = "foo3" +} + +fun box(): String { + val bar = Bar() + if (bar.foo != "foo") return "fail 1" + if (bar.foo2 != "foo2") return "fail 2" + if (bar.foo3 != "foo3") return "fail 3" + bar.foo3 = "foo4" + if (bar.foo3 != "foo4") return "fail 4" + + return "OK" +} \ No newline at end of file