JS BE: expose imported modules via $$importsForInline$$ property
... and use it as prefix to FQN in inline functions. This allows to properly inline function declared in module A to module B, when this function calls another function in module C. See KT-18201
This commit is contained in:
@@ -349,25 +349,30 @@ class NameSuggestion {
|
||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||
}
|
||||
|
||||
// See ES 5.1 spec: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
private fun Char.isES5IdentifierStart() =
|
||||
Character.isLetter(this) || // Lu | Ll | Lt | Lm | Lo
|
||||
Character.getType(this).toByte() == Character.LETTER_NUMBER ||
|
||||
// Nl which is missing in Character.isLetter, but present in UnicodeLetter in spec
|
||||
this == '_' ||
|
||||
this == '$'
|
||||
|
||||
private fun Char.isES5IdentifierPart() =
|
||||
isES5IdentifierStart() ||
|
||||
when (Character.getType(this).toByte()) {
|
||||
Character.NON_SPACING_MARK,
|
||||
Character.COMBINING_SPACING_MARK,
|
||||
Character.DECIMAL_DIGIT_NUMBER,
|
||||
Character.CONNECTOR_PUNCTUATION -> true
|
||||
else -> false
|
||||
} ||
|
||||
this == '\u200C' || // Zero-width non-joiner
|
||||
this == '\u200D' // Zero-width joiner
|
||||
}
|
||||
}
|
||||
|
||||
// See ES 5.1 spec: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
fun Char.isES5IdentifierStart() =
|
||||
Character.isLetter(this) || // Lu | Ll | Lt | Lm | Lo
|
||||
Character.getType(this).toByte() == Character.LETTER_NUMBER ||
|
||||
// Nl which is missing in Character.isLetter, but present in UnicodeLetter in spec
|
||||
this == '_' ||
|
||||
this == '$'
|
||||
|
||||
fun Char.isES5IdentifierPart() =
|
||||
isES5IdentifierStart() ||
|
||||
when (Character.getType(this).toByte()) {
|
||||
Character.NON_SPACING_MARK,
|
||||
Character.COMBINING_SPACING_MARK,
|
||||
Character.DECIMAL_DIGIT_NUMBER,
|
||||
Character.CONNECTOR_PUNCTUATION -> true
|
||||
else -> false
|
||||
} ||
|
||||
this == '\u200C' || // Zero-width non-joiner
|
||||
this == '\u200D' // Zero-width joiner
|
||||
|
||||
fun String.isValidES5Identifier() =
|
||||
isNotEmpty() &&
|
||||
first().isES5IdentifierStart() &&
|
||||
drop(1).all { it.isES5IdentifierPart() }
|
||||
@@ -821,6 +821,30 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineJsModule.kt")
|
||||
public void testInlineJsModule() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/inlineJsModule.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineJsModulePackage.kt")
|
||||
public void testInlineJsModulePackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/inlineJsModulePackage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineModule.kt")
|
||||
public void testInlineModule() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/inlineModule.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineModuleNonIndentifier.kt")
|
||||
public void testInlineModuleNonIndentifier() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/inlineModuleNonIndentifier.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/lambda.kt");
|
||||
@@ -3497,6 +3521,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleReimport.kt")
|
||||
public void testMultipleReimport() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/incremental/multipleReimport.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/incremental/simple.kt");
|
||||
|
||||
+4
-12
@@ -19,17 +19,13 @@ package org.jetbrains.kotlin.js.translate.context
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.isEffectivelyInlineOnly
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedPackage
|
||||
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.translate.utils.AnnotationsUtils
|
||||
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
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.assignment
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
@@ -138,13 +134,9 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
var name = localPackageNames[packageName]
|
||||
if (name == null) {
|
||||
name = JsScope.declareTemporaryName("package$" + packageName.shortName().asString())
|
||||
localPackageNames.put(packageName, name)
|
||||
|
||||
val parentRef = getLocalPackageReference(packageName.parent())
|
||||
val selfRef = JsNameRef(packageName.shortName().asString(), parentRef)
|
||||
val rhs = JsAstUtils.or(selfRef, assignment(selfRef.deepCopy(), JsObjectLiteral(false)))
|
||||
|
||||
statements.add(JsAstUtils.newVar(name, rhs).apply { exportedPackage = packageName.asString() })
|
||||
localPackageNames[packageName] = name
|
||||
statements += definePackageAlias(packageName.shortName().asString(), name, packageName.asString(),
|
||||
getLocalPackageReference(packageName.parent()))
|
||||
}
|
||||
return name.makeRef()
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ public final class Namer {
|
||||
public static final String ENUM_NAME_FIELD = "name$";
|
||||
public static final String ENUM_ORDINAL_FIELD = "ordinal$";
|
||||
|
||||
public static final String IMPORTS_FOR_INLINE_PROPERTY = "$$importsForInline$$";
|
||||
|
||||
@NotNull
|
||||
public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor, @NotNull JsConfig config) {
|
||||
String intrinsicTag = ArrayFIF.INSTANCE.getTag(functionDescriptor, config);
|
||||
|
||||
@@ -53,7 +53,10 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.js.config.JsConfig.UNKNOWN_EXTERNAL_MODULE_NAME;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
|
||||
@@ -135,6 +138,9 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private final ClassModelGenerator classModelGenerator;
|
||||
|
||||
@Nullable
|
||||
private JsName nameForImportsForInline;
|
||||
|
||||
public StaticContext(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull JsConfig config,
|
||||
@@ -230,6 +236,11 @@ public final class StaticContext {
|
||||
return fqn.deepCopy();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SuggestedName suggestName(@NotNull DeclarationDescriptor descriptor) {
|
||||
return nameSuggestion.suggest(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
@@ -265,7 +276,7 @@ public final class StaticContext {
|
||||
}
|
||||
}
|
||||
|
||||
SuggestedName suggested = nameSuggestion.suggest(descriptor);
|
||||
SuggestedName suggested = suggestName(descriptor);
|
||||
if (suggested == null) {
|
||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||
JsExpression result = getModuleExpressionFor(module);
|
||||
@@ -686,14 +697,7 @@ public final class StaticContext {
|
||||
if (currentModule == module) {
|
||||
return rootScope.declareName(Namer.getRootPackageName());
|
||||
}
|
||||
String moduleName;
|
||||
if (module == module.getBuiltIns().getBuiltInsModule()) {
|
||||
moduleName = Namer.KOTLIN_LOWER_NAME;
|
||||
}
|
||||
else {
|
||||
moduleName = module.getName().asString();
|
||||
moduleName = moduleName.substring(1, moduleName.length() - 1);
|
||||
}
|
||||
String moduleName = suggestModuleName(module);
|
||||
|
||||
if (UNKNOWN_EXTERNAL_MODULE_NAME.equals(moduleName)) return null;
|
||||
|
||||
@@ -701,7 +705,18 @@ public final class StaticContext {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsImportedModule getImportedModule(@NotNull String baseName, @Nullable DeclarationDescriptor descriptor) {
|
||||
public static String suggestModuleName(@NotNull ModuleDescriptor module) {
|
||||
if (module == module.getBuiltIns().getBuiltInsModule()) {
|
||||
return Namer.KOTLIN_LOWER_NAME;
|
||||
}
|
||||
else {
|
||||
String moduleName = module.getName().asString();
|
||||
return moduleName.substring(1, moduleName.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsImportedModule getImportedModule(@NotNull String baseName, @Nullable DeclarationDescriptor descriptor) {
|
||||
String plainName = descriptor != null && config.getModuleKind() == ModuleKind.UMD ? getPlainId(descriptor) : null;
|
||||
JsImportedModuleKey key = new JsImportedModuleKey(baseName, plainName);
|
||||
|
||||
@@ -785,4 +800,17 @@ public final class StaticContext {
|
||||
String tag = Namer.getFunctionTag(descriptor, config);
|
||||
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForImportsForInline() {
|
||||
if (nameForImportsForInline == null) {
|
||||
JsName name = JsScope.declareTemporaryName(Namer.IMPORTS_FOR_INLINE_PROPERTY);
|
||||
fragment.getNameBindings().add(new JsNameBinding(Namer.IMPORTS_FOR_INLINE_PROPERTY, name));
|
||||
nameForImportsForInline = name;
|
||||
return name;
|
||||
}
|
||||
else {
|
||||
return nameForImportsForInline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
-4
@@ -26,9 +26,14 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestionKt;
|
||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -38,12 +43,15 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||
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.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
|
||||
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.JsAstUtils.pureFqn;
|
||||
|
||||
/**
|
||||
* All the info about the state of the translation process.
|
||||
@@ -66,6 +74,8 @@ public class TranslationContext {
|
||||
@Nullable
|
||||
private final VariableDescriptor continuationParameterDescriptor;
|
||||
|
||||
private final Set<String> modulesImportedForInline = new HashSet<>();
|
||||
|
||||
@NotNull
|
||||
public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
|
||||
DynamicContext rootDynamicContext = DynamicContext.rootContext(
|
||||
@@ -265,15 +275,121 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof MemberDescriptor && isFromCurrentModule(descriptor) && isPublicInlineFunction()) {
|
||||
staticContext.export((MemberDescriptor) descriptor, true);
|
||||
JsNameRef result = staticContext.getQualifiedReference(descriptor);
|
||||
if (isPublicInlineFunction()) {
|
||||
if (isFromCurrentModule(descriptor)) {
|
||||
if (descriptor instanceof MemberDescriptor) {
|
||||
staticContext.export((MemberDescriptor) descriptor, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||
ModuleDescriptor currentModule = staticContext.getCurrentModule();
|
||||
if (module != currentModule && !isInlineFunction(descriptor)) {
|
||||
result = exportModuleForInline(currentModule, module, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isInlineFunction(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof CallableDescriptor)) return false;
|
||||
return CallExpressionTranslator.shouldBeInlined((CallableDescriptor) descriptor, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNameRef exportModuleForInline(
|
||||
@NotNull ModuleDescriptor currentModule, @NotNull ModuleDescriptor module,
|
||||
@NotNull JsNameRef fqn
|
||||
) {
|
||||
if (currentModule.getBuiltIns().getBuiltInsModule() == module) return fqn;
|
||||
|
||||
String moduleName = StaticContext.suggestModuleName(module);
|
||||
if (moduleName.equals(Namer.KOTLIN_LOWER_NAME)) return fqn;
|
||||
|
||||
return exportModuleForInline(currentModule, moduleName, staticContext.getInnerNameForDescriptor(module), fqn);
|
||||
}
|
||||
|
||||
private JsNameRef exportModuleForInline(
|
||||
@NotNull ModuleDescriptor currentModule,
|
||||
@NotNull String moduleId, @NotNull JsName moduleName,
|
||||
@NotNull JsNameRef fqn) {
|
||||
JsExpression currentModuleRef = pureFqn(staticContext.getInnerNameForDescriptor(currentModule), null);
|
||||
JsExpression importsRef = pureFqn(Namer.IMPORTS_FOR_INLINE_PROPERTY, currentModuleRef);
|
||||
JsExpression currentImports = pureFqn(staticContext.getNameForImportsForInline(), null);
|
||||
|
||||
JsExpression moduleRef;
|
||||
JsExpression lhsModuleRef;
|
||||
if (NameSuggestionKt.isValidES5Identifier(moduleId)) {
|
||||
moduleRef = pureFqn(moduleId, importsRef);
|
||||
lhsModuleRef = pureFqn(moduleId, currentImports);
|
||||
}
|
||||
else {
|
||||
moduleRef = new JsArrayAccess(importsRef, new JsStringLiteral(moduleId));
|
||||
MetadataProperties.setSideEffects(moduleRef, SideEffectKind.PURE);
|
||||
lhsModuleRef = new JsArrayAccess(currentImports, new JsStringLiteral(moduleId));
|
||||
}
|
||||
|
||||
fqn = (JsNameRef) replaceModuleReference(fqn, moduleName, moduleRef);
|
||||
|
||||
if (modulesImportedForInline.add(moduleId)) {
|
||||
JsExpressionStatement importStmt = new JsExpressionStatement(JsAstUtils.assignment(lhsModuleRef, moduleName.makeRef()));
|
||||
MetadataProperties.setExportedTag(importStmt, "imports:" + moduleId);
|
||||
staticContext.getFragment().getExportBlock().getStatements().add(importStmt);
|
||||
}
|
||||
|
||||
return fqn;
|
||||
}
|
||||
|
||||
private static JsExpression replaceModuleReference(
|
||||
@NotNull JsExpression expression,
|
||||
@NotNull JsName expectedModuleName,
|
||||
@NotNull JsExpression reexportExpr
|
||||
) {
|
||||
if (expression instanceof JsNameRef) {
|
||||
JsNameRef nameRef = (JsNameRef) expression;
|
||||
if (nameRef.getQualifier() == null) {
|
||||
return expectedModuleName == nameRef.getName() ? reexportExpr : expression;
|
||||
}
|
||||
else {
|
||||
JsExpression newQualifier = replaceModuleReference(nameRef.getQualifier(), expectedModuleName, reexportExpr);
|
||||
if (newQualifier == nameRef.getQualifier()) {
|
||||
return expression;
|
||||
}
|
||||
JsExpression result = nameRef.getName() != null ?
|
||||
new JsNameRef(nameRef.getName(), newQualifier) :
|
||||
new JsNameRef(nameRef.getIdent(), newQualifier);
|
||||
result.copyMetadataFrom(nameRef);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return expression;
|
||||
}
|
||||
return staticContext.getQualifiedReference(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef getInnerReference(@NotNull DeclarationDescriptor descriptor) {
|
||||
return JsAstUtils.pureFqn(getInnerNameForDescriptor(descriptor), null);
|
||||
JsNameRef result = pureFqn(getInnerNameForDescriptor(descriptor), null);
|
||||
|
||||
SuggestedName suggested = staticContext.suggestName(descriptor);
|
||||
if (suggested != null && getConfig().getModuleKind() != ModuleKind.PLAIN && isPublicInlineFunction()) {
|
||||
String moduleId = AnnotationsUtils.getModuleName(suggested.getDescriptor());
|
||||
if (moduleId != null && result.getName() != null && result.getQualifier() == null) {
|
||||
result = exportModuleForInline(getCurrentModule(), moduleId, result.getName(), result);
|
||||
}
|
||||
else if (isNativeObject(suggested.getDescriptor()) && DescriptorUtils.isTopLevelDeclaration(suggested.getDescriptor())) {
|
||||
String fileModuleId = AnnotationsUtils.getFileModuleName(bindingContext(), suggested.getDescriptor());
|
||||
if (fileModuleId != null) {
|
||||
JsName fileModuleName = staticContext.getImportedModule(fileModuleId, null).getInternalName();
|
||||
result = exportModuleForInline(getCurrentModule(), fileModuleId, fileModuleName,
|
||||
staticContext.getQualifiedReference(descriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.exportedPackage
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.definePackageAlias
|
||||
|
||||
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName, val module: ModuleDescriptor) {
|
||||
// Maps unique signature (see generateSignature) to names
|
||||
@@ -134,8 +135,8 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
fragment.inlineModuleMap.forEach { (_, value) -> rename(value) }
|
||||
}
|
||||
|
||||
private fun <T: JsNode> Map<JsName, JsName>.rename(node: T): T {
|
||||
node.accept(object : RecursiveJsVisitor() {
|
||||
private fun <T: JsNode> Map<JsName, JsName>.rename(rootNode: T): T {
|
||||
rootNode.accept(object : RecursiveJsVisitor() {
|
||||
override fun visitElement(node: JsNode) {
|
||||
super.visitElement(node)
|
||||
if (node is HasName) {
|
||||
@@ -152,12 +153,13 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
}
|
||||
}
|
||||
})
|
||||
return node
|
||||
return rootNode
|
||||
}
|
||||
|
||||
// Adds different boilerplate code (like imports, class prototypes, etc) to resulting program.
|
||||
fun merge() {
|
||||
rootFunction.body.statements.apply {
|
||||
addImportForInlineDeclarationIfNecessary()
|
||||
this += importBlock.statements
|
||||
addClassPrototypes(this)
|
||||
this += declarationBlock.statements
|
||||
@@ -167,6 +169,12 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<JsStatement>.addImportForInlineDeclarationIfNecessary() {
|
||||
val importsForInlineName = nameTable[Namer.IMPORTS_FOR_INLINE_PROPERTY] ?: return
|
||||
this += definePackageAlias(Namer.IMPORTS_FOR_INLINE_PROPERTY, importsForInlineName, Namer.IMPORTS_FOR_INLINE_PROPERTY,
|
||||
JsNameRef(Namer.getRootPackageName()))
|
||||
}
|
||||
|
||||
private fun addClassPrototypes(statements: MutableList<JsStatement>) {
|
||||
val visited = mutableSetOf<JsName>()
|
||||
for (cls in classes.keys) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.CoroutineMetadata
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedPackage
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
|
||||
@@ -193,3 +194,10 @@ fun JsFunction.fillCoroutineMetadata(
|
||||
psiElement = descriptor.source.getPsi()
|
||||
)
|
||||
}
|
||||
|
||||
fun definePackageAlias(name: String, varName: JsName, tag: String, parentRef: JsExpression): JsStatement {
|
||||
val selfRef = JsNameRef(name, parentRef)
|
||||
val rhs = JsAstUtils.or(selfRef, JsAstUtils.assignment(selfRef.deepCopy(), JsObjectLiteral(false)))
|
||||
|
||||
return JsAstUtils.newVar(varName, rhs).apply { exportedPackage = tag }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// EXPECTED_REACHABLE_NODES: 547
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.js
|
||||
define("lib1", [], function() {
|
||||
return function() {
|
||||
return "OK";
|
||||
}
|
||||
})
|
||||
|
||||
// MODULE: lib2(lib1)
|
||||
// FILE: lib2.kt
|
||||
// MODULE_KIND: AMD
|
||||
@JsModule("lib1")
|
||||
external fun foo(): String
|
||||
|
||||
// MODULE: lib3(lib2)
|
||||
// FILE: lib3.kt
|
||||
// MODULE_KIND: AMD
|
||||
inline fun bar() = foo()
|
||||
|
||||
// MODULE: main(lib3)
|
||||
// FILE: main.kt
|
||||
// MODULE_KIND: AMD
|
||||
|
||||
fun box() = bar()
|
||||
@@ -0,0 +1,28 @@
|
||||
// EXPECTED_REACHABLE_NODES: 490
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.js
|
||||
define("lib1", [], function() {
|
||||
return {
|
||||
foo: function() {
|
||||
return "OK";
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
// MODULE: lib2(lib1)
|
||||
// FILE: lib2.kt
|
||||
// MODULE_KIND: AMD
|
||||
@file:JsModule("lib1")
|
||||
|
||||
external fun foo(): String
|
||||
|
||||
// MODULE: lib3(lib2)
|
||||
// FILE: lib3.kt
|
||||
// MODULE_KIND: AMD
|
||||
inline fun bar() = foo()
|
||||
|
||||
// MODULE: main(lib3)
|
||||
// FILE: main.kt
|
||||
// MODULE_KIND: AMD
|
||||
|
||||
fun box() = bar()
|
||||
@@ -0,0 +1,15 @@
|
||||
// EXPECTED_REACHABLE_NODES: 489
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.kt
|
||||
|
||||
fun foo() = "OK"
|
||||
|
||||
// MODULE: lib2(lib1)
|
||||
// FILE: lib2.kt
|
||||
|
||||
inline fun bar() = foo()
|
||||
|
||||
// MODULE: main(lib1, lib2)
|
||||
// FILE: main.kt
|
||||
|
||||
fun box() = bar()
|
||||
@@ -0,0 +1,15 @@
|
||||
// EXPECTED_REACHABLE_NODES: 489
|
||||
// MODULE: 1
|
||||
// FILE: lib1.kt
|
||||
|
||||
fun foo() = "OK"
|
||||
|
||||
// MODULE: 2(1)
|
||||
// FILE: lib2.kt
|
||||
|
||||
inline fun bar() = foo()
|
||||
|
||||
// MODULE: main(2)
|
||||
// FILE: main.kt
|
||||
|
||||
fun box() = bar()
|
||||
@@ -0,0 +1,24 @@
|
||||
// EXPECTED_REACHABLE_NODES: 491
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.kt
|
||||
|
||||
fun foo() = "O"
|
||||
|
||||
fun bar() = "K"
|
||||
|
||||
// MODULE: lib2(lib1)
|
||||
// FILE: lib2a.kt
|
||||
// PROPERTY_WRITE_COUNT: name=lib1 count=1
|
||||
// PROPERTY_WRITE_COUNT: name=$$imports$$ count=1
|
||||
|
||||
inline fun o() = foo()
|
||||
|
||||
// FILE: lib2b.kt
|
||||
|
||||
inline fun k() = bar()
|
||||
|
||||
// MODULE: main(lib2)
|
||||
// FILE: main.kt
|
||||
// RECOMPILE
|
||||
|
||||
fun box() = o() + k()
|
||||
Reference in New Issue
Block a user