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.
This commit is contained in:
@@ -18,10 +18,11 @@ package org.jetbrains.kotlin.js.descriptorUtils
|
|||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
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.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -52,3 +53,14 @@ fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConst
|
|||||||
|
|
||||||
val DeclarationDescriptor.isCoroutineLambda: Boolean
|
val DeclarationDescriptor.isCoroutineLambda: Boolean
|
||||||
get() = this is AnonymousFunctionDescriptor && isSuspend
|
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
|
||||||
|
}
|
||||||
@@ -4754,6 +4754,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("internalNameClash.kt")
|
||||||
public void testInternalNameClash() throws Exception {
|
public void testInternalNameClash() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/internalNameClash.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/internalNameClash.kt");
|
||||||
|
|||||||
+2
-9
@@ -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.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag
|
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
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.*
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||||
@@ -147,13 +147,6 @@ internal class DeclarationExporter(val context: StaticContext) {
|
|||||||
it.exportedTag = context.getTag(declaration)
|
it.exportedTag = context.getTag(declaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun EffectiveVisibility.publicOrInternal(): Boolean {
|
private fun MemberDescriptor.shouldBeExported(force: Boolean) = force || shouldBeExported(context.config)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.isCoroutineLambda;
|
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.context.UsageTrackerKt.getNameForCapturedDescriptor;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
|
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
|
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
|
||||||
@@ -285,7 +286,7 @@ public class TranslationContext {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public JsName getInlineableInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
public JsName getInlineableInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||||
JsName name;
|
JsName name;
|
||||||
if (inlineFunctionContext == null || !isPublicInlineFunction() ||
|
if (inlineFunctionContext == null || !isPublicInlineFunction() || !shouldBeExported(descriptor, getConfig()) ||
|
||||||
DescriptorUtils.isAncestor(inlineFunctionContext.getDescriptor(), descriptor, false)) {
|
DescriptorUtils.isAncestor(inlineFunctionContext.getDescriptor(), descriptor, false)) {
|
||||||
name = getInnerNameForDescriptor(descriptor);
|
name = getInnerNameForDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
@@ -802,8 +803,7 @@ public class TranslationContext {
|
|||||||
public boolean isPublicInlineFunction() {
|
public boolean isPublicInlineFunction() {
|
||||||
if (inlineFunctionContext == null) return false;
|
if (inlineFunctionContext == null) return false;
|
||||||
|
|
||||||
CallableDescriptor function = inlineFunctionContext.getDescriptor();
|
return shouldBeExported(inlineFunctionContext.getDescriptor(), getConfig());
|
||||||
return function.getVisibility().effectiveVisibility(function, true).getPublicApi();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
+2
-2
@@ -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.descriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor
|
import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue
|
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.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper
|
import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
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.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
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.getPsi
|
||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ fun TranslationContext.wrapWithInlineMetadata(
|
|||||||
function: JsFunction, descriptor: FunctionDescriptor
|
function: JsFunction, descriptor: FunctionDescriptor
|
||||||
): JsExpression {
|
): JsExpression {
|
||||||
val sourceInfo = descriptor.source.getPsi()
|
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 metadata = InlineMetadata.compose(function, descriptor, this)
|
||||||
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
|
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -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.JsNameRef;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
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.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
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) {
|
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
|
@NotNull
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ package foo
|
|||||||
// CHECK_HAS_INLINE_METADATA: apply
|
// CHECK_HAS_INLINE_METADATA: apply
|
||||||
// CHECK_HAS_INLINE_METADATA: applyL_h43q6c$
|
// CHECK_HAS_INLINE_METADATA: applyL_h43q6c$
|
||||||
// CHECK_HAS_INLINE_METADATA: applyM_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$
|
// CHECK_HAS_NO_INLINE_METADATA: applyO_h43q6c$
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user