JS: create appropriate nameBinding's upon inlining
Otherwise JsName's don't get linked properly upon deserialization. As a result a function/constructor doesn't get renamed at call site during the name conflict resolution phase.
This commit is contained in:
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.js.inline.context.FunctionContext;
|
||||
import org.jetbrains.kotlin.js.inline.context.InliningContext;
|
||||
import org.jetbrains.kotlin.js.inline.context.NamingContext;
|
||||
import org.jetbrains.kotlin.js.inline.util.*;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
|
||||
|
||||
@@ -62,7 +61,13 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node);
|
||||
private int inlineFunctionDepth;
|
||||
|
||||
private final Map<JsWrapperKey, Map<JsName, JsExpression>> replacementsInducedByWrappers = new HashMap<>();
|
||||
private final Map<JsWrapperKey, Map<JsName, JsNameRef>> replacementsInducedByWrappers = new HashMap<>();
|
||||
|
||||
private final Map<JsName, String> inverseNameBindings;
|
||||
|
||||
private Map<JsName, String> existingNameBindings = new HashMap<>();
|
||||
|
||||
private final List<JsNameBinding> additionalNameBindings = new ArrayList<>();
|
||||
|
||||
public static void process(
|
||||
@NotNull JsConfig.Reporter reporter,
|
||||
@@ -75,6 +80,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
) {
|
||||
Map<JsName, FunctionWithWrapper> functions = CollectUtilsKt.collectNamedFunctionsAndWrappers(fragments);
|
||||
Map<String, FunctionWithWrapper> accessors = CollectUtilsKt.collectAccessors(fragments);
|
||||
Map<JsName, String> inverseNameBindings = CollectUtilsKt.collectNameBindings(fragments);
|
||||
|
||||
DummyAccessorInvocationTransformer accessorInvocationTransformer = new DummyAccessorInvocationTransformer();
|
||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||
@@ -82,7 +88,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
||||
}
|
||||
FunctionReader functionReader = new FunctionReader(reporter, config, currentModuleName, fragments);
|
||||
JsInliner inliner = new JsInliner(config, functions, accessors, functionReader, trace);
|
||||
JsInliner inliner = new JsInliner(config, functions, accessors, inverseNameBindings, functionReader, trace);
|
||||
|
||||
for (JsStatement statement : importStatements) {
|
||||
inliner.processImportStatement(statement);
|
||||
@@ -90,6 +96,8 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
|
||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||
inliner.existingImports.clear();
|
||||
inliner.additionalNameBindings.clear();
|
||||
inliner.existingNameBindings = CollectUtilsKt.collectNameBindings(Collections.singletonList(fragment));
|
||||
|
||||
inliner.inliningContexts.push(inliner.new JsInliningContext(inliner.new ListContext<JsStatement>()));
|
||||
inliner.acceptStatement(fragment.getDeclarationBlock());
|
||||
@@ -103,6 +111,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
|
||||
inliner.inliningContexts.pop();
|
||||
fragment.getInitializerBlock().getStatements().addAll(0, initWrapper.getStatements());
|
||||
fragment.getNameBindings().addAll(inliner.additionalNameBindings);
|
||||
}
|
||||
|
||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||
@@ -117,6 +126,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
@NotNull JsConfig config,
|
||||
@NotNull Map<JsName, FunctionWithWrapper> functions,
|
||||
@NotNull Map<String, FunctionWithWrapper> accessors,
|
||||
@NotNull Map<JsName, String> inverseNameBindings,
|
||||
@NotNull FunctionReader functionReader,
|
||||
@NotNull DiagnosticSink trace
|
||||
) {
|
||||
@@ -127,6 +137,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
namedFunctionsSet.add(functionWithWrapper.getFunction());
|
||||
}
|
||||
this.accessors = accessors;
|
||||
this.inverseNameBindings = inverseNameBindings;
|
||||
this.functionReader = functionReader;
|
||||
this.trace = trace;
|
||||
|
||||
@@ -396,10 +407,10 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
@NotNull InliningContext inliningContext
|
||||
) {
|
||||
// Apparently we should avoid this trick when we implement fair support for crossinline
|
||||
Function<JsWrapperKey, Map<JsName, JsExpression>> replacementGen = k -> {
|
||||
Function<JsWrapperKey, Map<JsName, JsNameRef>> replacementGen = k -> {
|
||||
JsContext ctx = k.context;
|
||||
|
||||
Map<JsName, JsExpression> newReplacements = new HashMap<>();
|
||||
Map<JsName, JsNameRef> newReplacements = new HashMap<>();
|
||||
|
||||
List<JsStatement> copiedStatements = new ArrayList<>();
|
||||
for (JsStatement statement : wrapper.getStatements()) {
|
||||
@@ -427,7 +438,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
}
|
||||
|
||||
if (name != existingName) {
|
||||
JsExpression replacement = pureFqn(existingName, null);
|
||||
JsNameRef replacement = pureFqn(existingName, null);
|
||||
newReplacements.put(name, replacement);
|
||||
}
|
||||
|
||||
@@ -445,7 +456,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
for (JsName name : definedNames) {
|
||||
JsName alias = JsScope.declareTemporaryName(name.getIdent());
|
||||
alias.copyMetadataFrom(name);
|
||||
JsExpression replacement = pureFqn(alias, null);
|
||||
JsNameRef replacement = pureFqn(alias, null);
|
||||
newReplacements.put(name, replacement);
|
||||
}
|
||||
|
||||
@@ -464,9 +475,21 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
};
|
||||
|
||||
JsWrapperKey key = new JsWrapperKey(inliningContext.getStatementContextBeforeCurrentFunction(), originalFunction);
|
||||
Map<JsName, JsExpression> replacements = replacementsInducedByWrappers.computeIfAbsent(key, replacementGen);
|
||||
Map<JsName, JsNameRef> replacements = replacementsInducedByWrappers.computeIfAbsent(key, replacementGen);
|
||||
|
||||
RewriteUtilsKt.replaceNames(function, replacements);
|
||||
|
||||
// Copy nameBinding's for inlined localAlias'es
|
||||
for (JsNameRef nameRef : replacements.values()) {
|
||||
JsName name = nameRef.getName();
|
||||
if (name != null && !existingNameBindings.containsKey(name)) {
|
||||
String tag = inverseNameBindings.get(name);
|
||||
if (tag != null) {
|
||||
existingNameBindings.put(name, tag);
|
||||
additionalNameBindings.add(new JsNameBinding(tag, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceExpressionsWithLocalAliases(@NotNull JsStatement statement) {
|
||||
|
||||
@@ -230,6 +230,16 @@ fun collectAccessors(fragments: List<JsProgramFragment>): Map<String, FunctionWi
|
||||
return result
|
||||
}
|
||||
|
||||
fun collectNameBindings(fragments: List<JsProgramFragment>): Map<JsName, String> {
|
||||
val result = mutableMapOf<JsName, String>()
|
||||
for (fragment in fragments) {
|
||||
for (binding in fragment.nameBindings) {
|
||||
result[binding.name] = binding.key
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun extractFunction(expression: JsExpression) = when (expression) {
|
||||
is JsFunction -> FunctionWithWrapper(expression, null)
|
||||
else -> InlineMetadata.decompose(expression)?.function ?: InlineMetadata.tryExtractFunction(expression)
|
||||
|
||||
Reference in New Issue
Block a user