From 918ce78c5ad199b0ffb4c793881ea2b42811c0ab Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 25 Jul 2017 13:59:20 +0300 Subject: [PATCH] Support inlining internal functions to friend modules in JS BE There's one exception: if an inline internal function calls private function, this will fail at run time. --- .../js/descriptorUtils/descriptorUtils.kt | 18 +++++++++++++++--- .../js/test/semantics/BoxJsTestGenerated.java | 6 ++++++ .../translate/context/DeclarationExporter.kt | 11 ++--------- .../translate/context/TranslationContext.java | 6 +++--- .../translate/expression/FunctionTranslator.kt | 4 ++-- .../reference/ReferenceTranslator.java | 4 +++- .../box/inline/metadataForPublicFunction.kt | 2 +- .../box/inlineMultiModule/internalFriend.kt | 10 ++++++++++ 8 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 js/js.translator/testData/box/inlineMultiModule/internalFriend.kt diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt index 256c578d794..207938a7ccf 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt @@ -18,10 +18,11 @@ package org.jetbrains.kotlin.js.descriptorUtils import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.JsConfig +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.KotlinType @@ -52,3 +53,14 @@ fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConst val DeclarationDescriptor.isCoroutineLambda: Boolean get() = this is AnonymousFunctionDescriptor && isSuspend + + +fun DeclarationDescriptor.shouldBeExported(config: JsConfig): Boolean = + this !is DeclarationDescriptorWithVisibility || effectiveVisibility(visibility, true).shouldBeExported(config) || + AnnotationsUtils.getJsNameAnnotation(this) != null + +private fun EffectiveVisibility.shouldBeExported(config: JsConfig): Boolean { + if (publicApi) return true + if (config.configuration.getBoolean(JSConfigurationKeys.FRIEND_PATHS_DISABLED)) return false + return toVisibility() == Visibilities.INTERNAL +} \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 10abf51f10b..56457473294 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -4754,6 +4754,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("internalFriend.kt") + public void testInternalFriend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/internalFriend.kt"); + doTest(fileName); + } + @TestMetadata("internalNameClash.kt") public void testInternalNameClash() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/internalNameClash.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt index 4c96f475514..7ca4fee87e4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.isEffectivelyInlineOnly import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef -import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.descriptorUtils.shouldBeExported import org.jetbrains.kotlin.js.translate.utils.* import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject @@ -147,13 +147,6 @@ internal class DeclarationExporter(val context: StaticContext) { it.exportedTag = context.getTag(declaration) } - private fun EffectiveVisibility.publicOrInternal(): Boolean { - if (publicApi) return true - if (context.config.configuration.getBoolean(JSConfigurationKeys.FRIEND_PATHS_DISABLED)) return false - return toVisibility() == Visibilities.INTERNAL - } - - private fun MemberDescriptor.shouldBeExported(force: Boolean) = - force || effectiveVisibility(checkPublishedApi = true).publicOrInternal() || AnnotationsUtils.getJsNameAnnotation(this) != null + private fun MemberDescriptor.shouldBeExported(force: Boolean) = force || shouldBeExported(context.config) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index e7c8f2752e6..4a244f0f82f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind; import java.util.*; import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.isCoroutineLambda; +import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.shouldBeExported; import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor; import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement; @@ -285,7 +286,7 @@ public class TranslationContext { @NotNull public JsName getInlineableInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) { JsName name; - if (inlineFunctionContext == null || !isPublicInlineFunction() || + if (inlineFunctionContext == null || !isPublicInlineFunction() || !shouldBeExported(descriptor, getConfig()) || DescriptorUtils.isAncestor(inlineFunctionContext.getDescriptor(), descriptor, false)) { name = getInnerNameForDescriptor(descriptor); } @@ -802,8 +803,7 @@ public class TranslationContext { public boolean isPublicInlineFunction() { if (inlineFunctionContext == null) return false; - CallableDescriptor function = inlineFunctionContext.getDescriptor(); - return function.getVisibility().effectiveVisibility(function, true).getPublicApi(); + return shouldBeExported(inlineFunctionContext.getDescriptor(), getConfig()); } @Nullable diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt index c987c71dc45..2706e62a3f0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue +import org.jetbrains.kotlin.js.descriptorUtils.shouldBeExported import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper import org.jetbrains.kotlin.js.translate.context.Namer @@ -35,7 +36,6 @@ import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue -import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.PsiSourceFile @@ -106,7 +106,7 @@ fun TranslationContext.wrapWithInlineMetadata( function: JsFunction, descriptor: FunctionDescriptor ): JsExpression { val sourceInfo = descriptor.source.getPsi() - return if (descriptor.isInline && descriptor.isEffectivelyPublicApi) { + return if (descriptor.isInline && descriptor.shouldBeExported(config)) { val metadata = InlineMetadata.compose(function, descriptor, this) val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java index 5ff0afee8c4..218abd91f66 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsName; import org.jetbrains.kotlin.js.backend.ast.JsNameRef; import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties; import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind; +import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; @@ -109,7 +110,8 @@ public final class ReferenceTranslator { } private static boolean isLocallyAvailableDeclaration(@NotNull TranslationContext context, @NotNull DeclarationDescriptor descriptor) { - return context.isFromCurrentModule(descriptor) && !context.isPublicInlineFunction(); + return context.isFromCurrentModule(descriptor) && !(context.isPublicInlineFunction() && + DescriptorUtilsKt.shouldBeExported(descriptor, context.getConfig())); } @NotNull diff --git a/js/js.translator/testData/box/inline/metadataForPublicFunction.kt b/js/js.translator/testData/box/inline/metadataForPublicFunction.kt index a67c0705695..497d14152a3 100644 --- a/js/js.translator/testData/box/inline/metadataForPublicFunction.kt +++ b/js/js.translator/testData/box/inline/metadataForPublicFunction.kt @@ -9,7 +9,7 @@ package foo // CHECK_HAS_INLINE_METADATA: apply // CHECK_HAS_INLINE_METADATA: applyL_h43q6c$ // CHECK_HAS_INLINE_METADATA: applyM_h43q6c$ -// CHECK_HAS_NO_INLINE_METADATA: applyN_h43q6c$ +// CHECK_HAS_INLINE_METADATA: applyN_h43q6c$ // CHECK_HAS_NO_INLINE_METADATA: applyO_h43q6c$ inline diff --git a/js/js.translator/testData/box/inlineMultiModule/internalFriend.kt b/js/js.translator/testData/box/inlineMultiModule/internalFriend.kt new file mode 100644 index 00000000000..4371ca5e199 --- /dev/null +++ b/js/js.translator/testData/box/inlineMultiModule/internalFriend.kt @@ -0,0 +1,10 @@ +// EXPECTED_REACHABLE_NODES: 992 +// MODULE: lib +// FILE: lib.kt +internal fun bar() = "OK" + +internal inline fun foo() = bar() + +// MODULE: main(lib)(lib) +// FILE: main.kt +fun box(): String = foo() \ No newline at end of file