提交 76346732 编写于 作者: A Alexey Andreev

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
上级 cc4e55b8
......@@ -194,7 +194,7 @@ class FunctionReader(
val position = info.offsetToSourceMapping[offset]
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
if (sourceMap != null) {
......
......@@ -4778,6 +4778,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
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")
public void testSimple() throws Exception {
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.config.JsConfig;
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.translate.context.generator.Generator;
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.calls.tasks.DynamicCallsKt;
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.serialization.js.ModuleKind;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static org.jetbrains.kotlin.js.config.JsConfig.UNKNOWN_EXTERNAL_MODULE_NAME;
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
......@@ -142,6 +139,8 @@ public final class StaticContext {
@Nullable
private JsName nameForImportsForInline;
private final Map<String, JsExpression> modulesImportedForInline = new HashMap<>();
public StaticContext(
@NotNull BindingTrace bindingTrace,
@NotNull JsConfig config,
......@@ -707,7 +706,7 @@ public final class StaticContext {
}
@NotNull
public static String suggestModuleName(@NotNull ModuleDescriptor module) {
private static String suggestModuleName(@NotNull ModuleDescriptor module) {
if (module == module.getBuiltIns().getBuiltInsModule()) {
return Namer.KOTLIN_LOWER_NAME;
}
......@@ -800,11 +799,15 @@ public final class StaticContext {
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
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
public JsName getNameForImportsForInline() {
private 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));
......@@ -815,4 +818,41 @@ public final class StaticContext {
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();
}
}
......@@ -26,9 +26,7 @@ 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;
......@@ -74,8 +72,6 @@ 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(
......@@ -284,9 +280,11 @@ public class TranslationContext {
}
else {
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
ModuleDescriptor currentModule = staticContext.getCurrentModule();
if (module != currentModule && !isInlineFunction(descriptor)) {
result = exportModuleForInline(currentModule, module, result);
if (module != staticContext.getCurrentModule() && !isInlineFunction(descriptor)) {
JsExpression replacement = staticContext.exportModuleForInline(module);
if (replacement != null) {
result = replaceModuleReference(result, getInnerNameForDescriptor(module), replacement);
}
}
}
}
......@@ -298,50 +296,6 @@ public class TranslationContext {
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(
@NotNull JsExpression expression,
@NotNull JsName expectedModuleName,
......@@ -378,14 +332,15 @@ public class TranslationContext {
if (suggested != null && getConfig().getModuleKind() != ModuleKind.PLAIN && isPublicInlineFunction()) {
String moduleId = AnnotationsUtils.getModuleName(suggested.getDescriptor());
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())) {
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));
JsExpression replacement = staticContext.exportModuleForInline(fileModuleId, fileModuleName);
result = replaceModuleReference(staticContext.getQualifiedReference(descriptor), fileModuleName, replacement);
}
}
}
......
// 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()
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册