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:
Anton Bannykh
2018-08-16 15:05:36 +03:00
parent 3b4a49eebf
commit 8e5b2fe657
2 changed files with 41 additions and 8 deletions
@@ -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)