Fix module re-importing when inlining functions in JS BE
When inliner reads function's body from other module, it performs substitution _ -> moduleAlias. However, local alias can't be used for this purpose, since call site can be in public inline function itself, so the correct substitution would be -> _.$$imports$$.alias
This commit is contained in:
@@ -194,7 +194,7 @@ class FunctionReader(
|
|||||||
|
|
||||||
val position = info.offsetToSourceMapping[offset]
|
val position = info.offsetToSourceMapping[offset]
|
||||||
val function = parseFunction(source, info.filePath, position, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram()))
|
val function = parseFunction(source, info.filePath, position, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram()))
|
||||||
val moduleReference = moduleNameMap[tag] ?: currentModuleName.makeRef()
|
val moduleReference = moduleNameMap[tag]?.deepCopy() ?: currentModuleName.makeRef()
|
||||||
|
|
||||||
val sourceMap = info.sourceMap
|
val sourceMap = info.sourceMap
|
||||||
if (sourceMap != null) {
|
if (sourceMap != null) {
|
||||||
|
|||||||
@@ -4778,6 +4778,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reexportDuringInline.kt")
|
||||||
|
public void testReexportDuringInline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/reexportDuringInline.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/simple.kt");
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ 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.config.JsConfig;
|
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||||
|
import org.jetbrains.kotlin.js.naming.NameSuggestionKt;
|
||||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||||
import org.jetbrains.kotlin.js.translate.context.generator.Generator;
|
import org.jetbrains.kotlin.js.translate.context.generator.Generator;
|
||||||
import org.jetbrains.kotlin.js.translate.context.generator.Rule;
|
import org.jetbrains.kotlin.js.translate.context.generator.Rule;
|
||||||
@@ -48,16 +49,12 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement;
|
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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.config.JsConfig.UNKNOWN_EXTERNAL_MODULE_NAME;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
|
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
|
||||||
@@ -142,6 +139,8 @@ public final class StaticContext {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private JsName nameForImportsForInline;
|
private JsName nameForImportsForInline;
|
||||||
|
|
||||||
|
private final Map<String, JsExpression> modulesImportedForInline = new HashMap<>();
|
||||||
|
|
||||||
public StaticContext(
|
public StaticContext(
|
||||||
@NotNull BindingTrace bindingTrace,
|
@NotNull BindingTrace bindingTrace,
|
||||||
@NotNull JsConfig config,
|
@NotNull JsConfig config,
|
||||||
@@ -707,7 +706,7 @@ public final class StaticContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String suggestModuleName(@NotNull ModuleDescriptor module) {
|
private static String suggestModuleName(@NotNull ModuleDescriptor module) {
|
||||||
if (module == module.getBuiltIns().getBuiltInsModule()) {
|
if (module == module.getBuiltIns().getBuiltInsModule()) {
|
||||||
return Namer.KOTLIN_LOWER_NAME;
|
return Namer.KOTLIN_LOWER_NAME;
|
||||||
}
|
}
|
||||||
@@ -800,11 +799,15 @@ public final class StaticContext {
|
|||||||
|
|
||||||
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
||||||
String tag = Namer.getFunctionTag(descriptor, config);
|
String tag = Namer.getFunctionTag(descriptor, config);
|
||||||
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
JsExpression moduleExpression = exportModuleForInline(DescriptorUtils.getContainingModule(descriptor));
|
||||||
|
if (moduleExpression == null) {
|
||||||
|
moduleExpression = getModuleExpressionFor(descriptor);
|
||||||
|
}
|
||||||
|
fragment.getInlineModuleMap().put(tag, moduleExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsName getNameForImportsForInline() {
|
private JsName getNameForImportsForInline() {
|
||||||
if (nameForImportsForInline == null) {
|
if (nameForImportsForInline == null) {
|
||||||
JsName name = JsScope.declareTemporaryName(Namer.IMPORTS_FOR_INLINE_PROPERTY);
|
JsName name = JsScope.declareTemporaryName(Namer.IMPORTS_FOR_INLINE_PROPERTY);
|
||||||
fragment.getNameBindings().add(new JsNameBinding(Namer.IMPORTS_FOR_INLINE_PROPERTY, name));
|
fragment.getNameBindings().add(new JsNameBinding(Namer.IMPORTS_FOR_INLINE_PROPERTY, name));
|
||||||
@@ -815,4 +818,41 @@ public final class StaticContext {
|
|||||||
return nameForImportsForInline;
|
return nameForImportsForInline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public JsExpression exportModuleForInline(@NotNull ModuleDescriptor declaration) {
|
||||||
|
if (getCurrentModule().getBuiltIns().getBuiltInsModule() == declaration) return null;
|
||||||
|
|
||||||
|
String moduleName = suggestModuleName(declaration);
|
||||||
|
if (moduleName.equals(Namer.KOTLIN_LOWER_NAME)) return null;
|
||||||
|
|
||||||
|
return exportModuleForInline(moduleName, getInnerNameForDescriptor(declaration));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JsExpression exportModuleForInline(@NotNull String moduleId, @NotNull JsName moduleName) {
|
||||||
|
return modulesImportedForInline.computeIfAbsent(moduleId, k -> {
|
||||||
|
JsExpression currentModuleRef = pureFqn(getInnerNameForDescriptor(getCurrentModule()), null);
|
||||||
|
JsExpression importsRef = pureFqn(Namer.IMPORTS_FOR_INLINE_PROPERTY, currentModuleRef);
|
||||||
|
JsExpression currentImports = pureFqn(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
JsExpressionStatement importStmt = new JsExpressionStatement(JsAstUtils.assignment(lhsModuleRef, moduleName.makeRef()));
|
||||||
|
MetadataProperties.setExportedTag(importStmt, "imports:" + moduleId);
|
||||||
|
getFragment().getExportBlock().getStatements().add(importStmt);
|
||||||
|
|
||||||
|
return moduleRef;
|
||||||
|
}).deepCopy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-54
@@ -26,9 +26,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
|||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||||
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.config.JsConfig;
|
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.naming.SuggestedName;
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator;
|
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator;
|
||||||
@@ -74,8 +72,6 @@ public class TranslationContext {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final VariableDescriptor continuationParameterDescriptor;
|
private final VariableDescriptor continuationParameterDescriptor;
|
||||||
|
|
||||||
private final Set<String> modulesImportedForInline = new HashSet<>();
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
|
public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
|
||||||
DynamicContext rootDynamicContext = DynamicContext.rootContext(
|
DynamicContext rootDynamicContext = DynamicContext.rootContext(
|
||||||
@@ -284,9 +280,11 @@ public class TranslationContext {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||||
ModuleDescriptor currentModule = staticContext.getCurrentModule();
|
if (module != staticContext.getCurrentModule() && !isInlineFunction(descriptor)) {
|
||||||
if (module != currentModule && !isInlineFunction(descriptor)) {
|
JsExpression replacement = staticContext.exportModuleForInline(module);
|
||||||
result = exportModuleForInline(currentModule, module, result);
|
if (replacement != null) {
|
||||||
|
result = replaceModuleReference(result, getInnerNameForDescriptor(module), replacement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,50 +296,6 @@ public class TranslationContext {
|
|||||||
return CallExpressionTranslator.shouldBeInlined((CallableDescriptor) descriptor, this);
|
return CallExpressionTranslator.shouldBeInlined((CallableDescriptor) descriptor, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private JsExpression exportModuleForInline(
|
|
||||||
@NotNull ModuleDescriptor currentModule, @NotNull ModuleDescriptor module,
|
|
||||||
@NotNull JsExpression 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 JsExpression exportModuleForInline(
|
|
||||||
@NotNull ModuleDescriptor currentModule,
|
|
||||||
@NotNull String moduleId, @NotNull JsName moduleName,
|
|
||||||
@NotNull JsExpression 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 = 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(
|
private static JsExpression replaceModuleReference(
|
||||||
@NotNull JsExpression expression,
|
@NotNull JsExpression expression,
|
||||||
@NotNull JsName expectedModuleName,
|
@NotNull JsName expectedModuleName,
|
||||||
@@ -378,14 +332,15 @@ public class TranslationContext {
|
|||||||
if (suggested != null && getConfig().getModuleKind() != ModuleKind.PLAIN && isPublicInlineFunction()) {
|
if (suggested != null && getConfig().getModuleKind() != ModuleKind.PLAIN && isPublicInlineFunction()) {
|
||||||
String moduleId = AnnotationsUtils.getModuleName(suggested.getDescriptor());
|
String moduleId = AnnotationsUtils.getModuleName(suggested.getDescriptor());
|
||||||
if (moduleId != null) {
|
if (moduleId != null) {
|
||||||
result = exportModuleForInline(getCurrentModule(), moduleId, name, result);
|
JsExpression replacement = staticContext.exportModuleForInline(moduleId, name);
|
||||||
|
result = replaceModuleReference(result, name, replacement);
|
||||||
}
|
}
|
||||||
else if (isNativeObject(suggested.getDescriptor()) && DescriptorUtils.isTopLevelDeclaration(suggested.getDescriptor())) {
|
else if (isNativeObject(suggested.getDescriptor()) && DescriptorUtils.isTopLevelDeclaration(suggested.getDescriptor())) {
|
||||||
String fileModuleId = AnnotationsUtils.getFileModuleName(bindingContext(), suggested.getDescriptor());
|
String fileModuleId = AnnotationsUtils.getFileModuleName(bindingContext(), suggested.getDescriptor());
|
||||||
if (fileModuleId != null) {
|
if (fileModuleId != null) {
|
||||||
JsName fileModuleName = staticContext.getImportedModule(fileModuleId, null).getInternalName();
|
JsName fileModuleName = staticContext.getImportedModule(fileModuleId, null).getInternalName();
|
||||||
result = exportModuleForInline(getCurrentModule(), fileModuleId, fileModuleName,
|
JsExpression replacement = staticContext.exportModuleForInline(fileModuleId, fileModuleName);
|
||||||
staticContext.getQualifiedReference(descriptor));
|
result = replaceModuleReference(staticContext.getQualifiedReference(descriptor), fileModuleName, replacement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// EXPECTED_REACHABLE_NODES: 490
|
||||||
|
// MODULE: lib1
|
||||||
|
// FILE: lib1.kt
|
||||||
|
inline fun foo() = bar()
|
||||||
|
|
||||||
|
fun bar() = "OK"
|
||||||
|
|
||||||
|
// MODULE: lib2(lib1)
|
||||||
|
// FILE: lib2.kt
|
||||||
|
|
||||||
|
inline fun baz() = foo()
|
||||||
|
|
||||||
|
// MODULE: main(lib2)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun box() = baz()
|
||||||
Reference in New Issue
Block a user