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.InliningContext;
|
||||||
import org.jetbrains.kotlin.js.inline.context.NamingContext;
|
import org.jetbrains.kotlin.js.inline.context.NamingContext;
|
||||||
import org.jetbrains.kotlin.js.inline.util.*;
|
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.js.translate.expression.InlineMetadata;
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
|
import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
|
||||||
|
|
||||||
@@ -62,7 +61,13 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node);
|
node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node);
|
||||||
private int inlineFunctionDepth;
|
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(
|
public static void process(
|
||||||
@NotNull JsConfig.Reporter reporter,
|
@NotNull JsConfig.Reporter reporter,
|
||||||
@@ -75,6 +80,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
) {
|
) {
|
||||||
Map<JsName, FunctionWithWrapper> functions = CollectUtilsKt.collectNamedFunctionsAndWrappers(fragments);
|
Map<JsName, FunctionWithWrapper> functions = CollectUtilsKt.collectNamedFunctionsAndWrappers(fragments);
|
||||||
Map<String, FunctionWithWrapper> accessors = CollectUtilsKt.collectAccessors(fragments);
|
Map<String, FunctionWithWrapper> accessors = CollectUtilsKt.collectAccessors(fragments);
|
||||||
|
Map<JsName, String> inverseNameBindings = CollectUtilsKt.collectNameBindings(fragments);
|
||||||
|
|
||||||
DummyAccessorInvocationTransformer accessorInvocationTransformer = new DummyAccessorInvocationTransformer();
|
DummyAccessorInvocationTransformer accessorInvocationTransformer = new DummyAccessorInvocationTransformer();
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
@@ -82,7 +88,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
||||||
}
|
}
|
||||||
FunctionReader functionReader = new FunctionReader(reporter, config, currentModuleName, fragments);
|
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) {
|
for (JsStatement statement : importStatements) {
|
||||||
inliner.processImportStatement(statement);
|
inliner.processImportStatement(statement);
|
||||||
@@ -90,6 +96,8 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
|
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
inliner.existingImports.clear();
|
inliner.existingImports.clear();
|
||||||
|
inliner.additionalNameBindings.clear();
|
||||||
|
inliner.existingNameBindings = CollectUtilsKt.collectNameBindings(Collections.singletonList(fragment));
|
||||||
|
|
||||||
inliner.inliningContexts.push(inliner.new JsInliningContext(inliner.new ListContext<JsStatement>()));
|
inliner.inliningContexts.push(inliner.new JsInliningContext(inliner.new ListContext<JsStatement>()));
|
||||||
inliner.acceptStatement(fragment.getDeclarationBlock());
|
inliner.acceptStatement(fragment.getDeclarationBlock());
|
||||||
@@ -103,6 +111,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
|
|
||||||
inliner.inliningContexts.pop();
|
inliner.inliningContexts.pop();
|
||||||
fragment.getInitializerBlock().getStatements().addAll(0, initWrapper.getStatements());
|
fragment.getInitializerBlock().getStatements().addAll(0, initWrapper.getStatements());
|
||||||
|
fragment.getNameBindings().addAll(inliner.additionalNameBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
@@ -117,6 +126,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
@NotNull JsConfig config,
|
@NotNull JsConfig config,
|
||||||
@NotNull Map<JsName, FunctionWithWrapper> functions,
|
@NotNull Map<JsName, FunctionWithWrapper> functions,
|
||||||
@NotNull Map<String, FunctionWithWrapper> accessors,
|
@NotNull Map<String, FunctionWithWrapper> accessors,
|
||||||
|
@NotNull Map<JsName, String> inverseNameBindings,
|
||||||
@NotNull FunctionReader functionReader,
|
@NotNull FunctionReader functionReader,
|
||||||
@NotNull DiagnosticSink trace
|
@NotNull DiagnosticSink trace
|
||||||
) {
|
) {
|
||||||
@@ -127,6 +137,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
namedFunctionsSet.add(functionWithWrapper.getFunction());
|
namedFunctionsSet.add(functionWithWrapper.getFunction());
|
||||||
}
|
}
|
||||||
this.accessors = accessors;
|
this.accessors = accessors;
|
||||||
|
this.inverseNameBindings = inverseNameBindings;
|
||||||
this.functionReader = functionReader;
|
this.functionReader = functionReader;
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
|
|
||||||
@@ -396,10 +407,10 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
@NotNull InliningContext inliningContext
|
@NotNull InliningContext inliningContext
|
||||||
) {
|
) {
|
||||||
// Apparently we should avoid this trick when we implement fair support for crossinline
|
// 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;
|
JsContext ctx = k.context;
|
||||||
|
|
||||||
Map<JsName, JsExpression> newReplacements = new HashMap<>();
|
Map<JsName, JsNameRef> newReplacements = new HashMap<>();
|
||||||
|
|
||||||
List<JsStatement> copiedStatements = new ArrayList<>();
|
List<JsStatement> copiedStatements = new ArrayList<>();
|
||||||
for (JsStatement statement : wrapper.getStatements()) {
|
for (JsStatement statement : wrapper.getStatements()) {
|
||||||
@@ -427,7 +438,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name != existingName) {
|
if (name != existingName) {
|
||||||
JsExpression replacement = pureFqn(existingName, null);
|
JsNameRef replacement = pureFqn(existingName, null);
|
||||||
newReplacements.put(name, replacement);
|
newReplacements.put(name, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,7 +456,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
for (JsName name : definedNames) {
|
for (JsName name : definedNames) {
|
||||||
JsName alias = JsScope.declareTemporaryName(name.getIdent());
|
JsName alias = JsScope.declareTemporaryName(name.getIdent());
|
||||||
alias.copyMetadataFrom(name);
|
alias.copyMetadataFrom(name);
|
||||||
JsExpression replacement = pureFqn(alias, null);
|
JsNameRef replacement = pureFqn(alias, null);
|
||||||
newReplacements.put(name, replacement);
|
newReplacements.put(name, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,9 +475,21 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
JsWrapperKey key = new JsWrapperKey(inliningContext.getStatementContextBeforeCurrentFunction(), originalFunction);
|
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);
|
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) {
|
private static void replaceExpressionsWithLocalAliases(@NotNull JsStatement statement) {
|
||||||
|
|||||||
@@ -230,6 +230,16 @@ fun collectAccessors(fragments: List<JsProgramFragment>): Map<String, FunctionWi
|
|||||||
return result
|
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) {
|
fun extractFunction(expression: JsExpression) = when (expression) {
|
||||||
is JsFunction -> FunctionWithWrapper(expression, null)
|
is JsFunction -> FunctionWithWrapper(expression, null)
|
||||||
else -> InlineMetadata.decompose(expression)?.function ?: InlineMetadata.tryExtractFunction(expression)
|
else -> InlineMetadata.decompose(expression)?.function ?: InlineMetadata.tryExtractFunction(expression)
|
||||||
|
|||||||
Reference in New Issue
Block a user