JS: support inlining in new pipeline
This commit is contained in:
@@ -17,10 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.callUtil
|
package org.jetbrains.kotlin.resolve.calls.callUtil
|
||||||
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -210,6 +207,15 @@ fun KtExpression.getPropertyResolvedCallWithAssert(context: BindingContext): Res
|
|||||||
return resolvedCall as ResolvedCall<out PropertyDescriptor>
|
return resolvedCall as ResolvedCall<out PropertyDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KtExpression.getVariableResolvedCallWithAssert(context: BindingContext): ResolvedCall<out VariableDescriptor> {
|
||||||
|
val resolvedCall = getResolvedCallWithAssert(context)
|
||||||
|
assert(resolvedCall.resultingDescriptor is VariableDescriptor) {
|
||||||
|
"ResolvedCall for this expression must be ResolvedCall<? extends PropertyDescriptor>: ${this.getTextWithLocation()}"
|
||||||
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return resolvedCall as ResolvedCall<out VariableDescriptor>
|
||||||
|
}
|
||||||
|
|
||||||
fun KtExpression.getType(context: BindingContext): KotlinType? {
|
fun KtExpression.getType(context: BindingContext): KotlinType? {
|
||||||
val type = context.getType(this)
|
val type = context.getType(this)
|
||||||
if (type != null) return type
|
if (type != null) return type
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class JsProgramFragment {
|
|||||||
private final JsGlobalBlock initializerBlock = new JsGlobalBlock();
|
private final JsGlobalBlock initializerBlock = new JsGlobalBlock();
|
||||||
private final List<JsNameBinding> nameBindings = new ArrayList<JsNameBinding>();
|
private final List<JsNameBinding> nameBindings = new ArrayList<JsNameBinding>();
|
||||||
private final Map<JsName, JsClassModel> classes = new LinkedHashMap<JsName, JsClassModel>();
|
private final Map<JsName, JsClassModel> classes = new LinkedHashMap<JsName, JsClassModel>();
|
||||||
|
private final Map<String, JsExpression> inlineModuleMap = new LinkedHashMap<String, JsExpression>();
|
||||||
|
|
||||||
public JsProgramFragment(@NotNull JsScope scope) {
|
public JsProgramFragment(@NotNull JsScope scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
@@ -61,4 +62,9 @@ public class JsProgramFragment {
|
|||||||
public Map<JsName, JsClassModel> getClasses() {
|
public Map<JsName, JsClassModel> getClasses() {
|
||||||
return classes;
|
return classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Map<String, JsExpression> getInlineModuleMap() {
|
||||||
|
return inlineModuleMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ import org.jetbrains.kotlin.js.inline.util.IdentitySet
|
|||||||
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
||||||
import org.jetbrains.kotlin.js.parser.parseFunction
|
import org.jetbrains.kotlin.js.parser.parseFunction
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
|
||||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
|
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||||
@@ -48,7 +46,7 @@ private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*"
|
|||||||
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
|
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
|
||||||
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
|
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
|
||||||
|
|
||||||
class FunctionReader(private val context: TranslationContext) {
|
class FunctionReader(private val config: LibrarySourcesConfig, private val currentModuleName: JsName, fragments: List<JsProgramFragment>) {
|
||||||
/**
|
/**
|
||||||
* fileContent: .js file content, that contains this module definition.
|
* fileContent: .js file content, that contains this module definition.
|
||||||
* One file can contain more than one module definition.
|
* One file can contain more than one module definition.
|
||||||
@@ -63,8 +61,12 @@ class FunctionReader(private val context: TranslationContext) {
|
|||||||
|
|
||||||
private val moduleNameToInfo = HashMultimap.create<String, ModuleInfo>()
|
private val moduleNameToInfo = HashMultimap.create<String, ModuleInfo>()
|
||||||
|
|
||||||
|
private val moduleNameMap: Map<String, JsExpression>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val libs = context.config.libraries.map(::File)
|
val libs = config.libraries.map(::File)
|
||||||
|
|
||||||
|
moduleNameMap = buildModuleNameMap(fragments)
|
||||||
|
|
||||||
JsLibraryUtils.traverseJsLibraries(libs) { fileContent, _ ->
|
JsLibraryUtils.traverseJsLibraries(libs) { fileContent, _ ->
|
||||||
var current = 0
|
var current = 0
|
||||||
@@ -86,6 +88,13 @@ class FunctionReader(private val context: TranslationContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since we compile each source file in its own context (and we may loose these context when performing incremental compilation)
|
||||||
|
// we don't use contexts to generate proper names for modules. Instead, we generate all necessary information during
|
||||||
|
// translation and rely on it here.
|
||||||
|
private fun buildModuleNameMap(fragments: List<JsProgramFragment>): Map<String, JsExpression> {
|
||||||
|
return fragments.flatMap { it.inlineModuleMap.entries }.associate { (k, v) -> k to v }
|
||||||
|
}
|
||||||
|
|
||||||
private fun rewindToIdentifierStart(text: String, index: Int): Int {
|
private fun rewindToIdentifierStart(text: String, index: Int): Int {
|
||||||
var result = index
|
var result = index
|
||||||
while (result > 0 && Character.isJavaIdentifierPart(text[result - 1])) {
|
while (result > 0 && Character.isJavaIdentifierPart(text[result - 1])) {
|
||||||
@@ -112,7 +121,7 @@ class FunctionReader(private val context: TranslationContext) {
|
|||||||
|
|
||||||
operator fun contains(descriptor: CallableDescriptor): Boolean {
|
operator fun contains(descriptor: CallableDescriptor): Boolean {
|
||||||
val moduleName = getModuleName(descriptor)
|
val moduleName = getModuleName(descriptor)
|
||||||
val currentModuleName = context.config.moduleId
|
val currentModuleName = config.moduleId
|
||||||
return currentModuleName != moduleName && moduleName in moduleNameToInfo.keys()
|
return currentModuleName != moduleName && moduleName in moduleNameToInfo.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +153,7 @@ class FunctionReader(private val context: TranslationContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val function = parseFunction(source, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram()))
|
val function = parseFunction(source, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram()))
|
||||||
val moduleReference = context.getModuleExpressionFor(descriptor) ?: getRootPackage()
|
val moduleReference = moduleNameMap[tag] ?: currentModuleName.makeRef()
|
||||||
|
|
||||||
val replacements = hashMapOf(info.moduleVariable to moduleReference,
|
val replacements = hashMapOf(info.moduleVariable to moduleReference,
|
||||||
info.kotlinVariable to Namer.kotlinObject())
|
info.kotlinVariable to Namer.kotlinObject())
|
||||||
@@ -152,11 +161,6 @@ class FunctionReader(private val context: TranslationContext) {
|
|||||||
function.markInlineArguments(descriptor)
|
function.markInlineArguments(descriptor)
|
||||||
return function
|
return function
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRootPackage(): JsExpression {
|
|
||||||
val rootName = context.program().rootScope.declareName(Namer.getRootPackageName())
|
|
||||||
return JsAstUtils.pureFqn(rootName, null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Char.isWhitespaceOrComma: Boolean
|
private val Char.isWhitespaceOrComma: Boolean
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
|||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
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.config.JsConfig;
|
||||||
|
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor;
|
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedFunctionDefinitionsKt;
|
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedFunctionDefinitionsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedLocalFunctionDeclarationsKt;
|
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedLocalFunctionDeclarationsKt;
|
||||||
@@ -37,7 +39,6 @@ import org.jetbrains.kotlin.js.inline.context.NamingContext;
|
|||||||
import org.jetbrains.kotlin.js.inline.util.CollectUtilsKt;
|
import org.jetbrains.kotlin.js.inline.util.CollectUtilsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.util.CollectionUtilsKt;
|
import org.jetbrains.kotlin.js.inline.util.CollectionUtilsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.util.NamingUtilsKt;
|
import org.jetbrains.kotlin.js.inline.util.NamingUtilsKt;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
|
import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -61,15 +62,34 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
private final Function1<JsNode, Boolean> canBeExtractedByInliner =
|
private final Function1<JsNode, Boolean> canBeExtractedByInliner =
|
||||||
node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node);
|
node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node);
|
||||||
|
|
||||||
public static JsProgram process(@NotNull TranslationContext context) {
|
public static void process(
|
||||||
JsProgram program = context.program();
|
@NotNull JsConfig config,
|
||||||
Map<JsName, JsFunction> functions = CollectUtilsKt.collectNamedFunctions(program);
|
@NotNull DiagnosticSink trace,
|
||||||
Map<String, JsFunction> accessors = CollectUtilsKt.collectAccessors(program);
|
@NotNull JsName currentModuleName,
|
||||||
new DummyAccessorInvocationTransformer().accept(program);
|
@NotNull List<JsProgramFragment> fragments,
|
||||||
JsInliner inliner = new JsInliner(functions, accessors, new FunctionReader(context), context.bindingTrace());
|
@NotNull List<JsProgramFragment> fragmentsToProcess
|
||||||
inliner.accept(program);
|
) {
|
||||||
RemoveUnusedFunctionDefinitionsKt.removeUnusedFunctionDefinitions(program, functions);
|
Map<JsName, JsFunction> functions = CollectUtilsKt.collectNamedFunctions(fragments);
|
||||||
return program;
|
Map<String, JsFunction> accessors = CollectUtilsKt.collectAccessors(fragments);
|
||||||
|
DummyAccessorInvocationTransformer accessorInvocationTransformer = new DummyAccessorInvocationTransformer();
|
||||||
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
|
accessorInvocationTransformer.accept(fragment.getDeclarationBlock());
|
||||||
|
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
||||||
|
}
|
||||||
|
FunctionReader functionReader = new FunctionReader((LibrarySourcesConfig) config, currentModuleName, fragments);
|
||||||
|
JsInliner inliner = new JsInliner(functions, accessors, functionReader, trace);
|
||||||
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
|
inliner.inliningContexts.push(inliner.new JsInliningContext(null, fragment.getScope()));
|
||||||
|
inliner.accept(fragment.getDeclarationBlock());
|
||||||
|
|
||||||
|
// There can be inlined function in top-level initializers, we need to optimize them as well
|
||||||
|
JsFunction fakeInitFunction = new JsFunction(JsDynamicScope.INSTANCE, fragment.getInitializerBlock(), "");
|
||||||
|
inliner.accept(fakeInitFunction);
|
||||||
|
|
||||||
|
inliner.inliningContexts.pop();
|
||||||
|
JsBlock block = new JsBlock(fragment.getDeclarationBlock(), fragment.getInitializerBlock(), fragment.getExportBlock());
|
||||||
|
RemoveUnusedFunctionDefinitionsKt.removeUnusedFunctionDefinitions(block, functions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsInliner(
|
private JsInliner(
|
||||||
@@ -86,7 +106,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
||||||
inliningContexts.push(new JsInliningContext(function));
|
inliningContexts.push(new JsInliningContext(function, function.getScope()));
|
||||||
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
|
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
|
||||||
inProcessFunctions.add(function);
|
inProcessFunctions.add(function);
|
||||||
|
|
||||||
@@ -266,8 +286,8 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
private class JsInliningContext implements InliningContext {
|
private class JsInliningContext implements InliningContext {
|
||||||
private final FunctionContext functionContext;
|
private final FunctionContext functionContext;
|
||||||
|
|
||||||
JsInliningContext(@NotNull JsFunction function) {
|
JsInliningContext(@NotNull JsScope scope) {
|
||||||
functionContext = new FunctionContext(function, functionReader) {
|
functionContext = new FunctionContext(scope) {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.js.inline.util.*
|
|||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
|
||||||
abstract class FunctionContext(
|
abstract class FunctionContext(
|
||||||
private val function: JsFunction,
|
private val scope: JsScope,
|
||||||
private val functionReader: FunctionReader
|
private val functionReader: FunctionReader
|
||||||
) {
|
) {
|
||||||
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
||||||
@@ -40,7 +40,7 @@ abstract class FunctionContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getScope(): JsScope {
|
fun getScope(): JsScope {
|
||||||
return function.scope
|
return scope
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -137,6 +137,15 @@ fun collectNamedFunctions(scope: JsNode) = collectNamedFunctionsAndMetadata(scop
|
|||||||
|
|
||||||
fun collectNamedFunctionsOrMetadata(scope: JsNode) = collectNamedFunctionsAndMetadata(scope).mapValues { it.value.second }
|
fun collectNamedFunctionsOrMetadata(scope: JsNode) = collectNamedFunctionsAndMetadata(scope).mapValues { it.value.second }
|
||||||
|
|
||||||
|
fun collectNamedFunctions(fragments: List<JsProgramFragment>): Map<JsName, JsFunction> {
|
||||||
|
val result = mutableMapOf<JsName, JsFunction>()
|
||||||
|
for (fragment in fragments) {
|
||||||
|
result += collectNamedFunctions(fragment.declarationBlock)
|
||||||
|
result += collectNamedFunctions(fragment.initializerBlock)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
fun collectNamedFunctionsAndMetadata(scope: JsNode): Map<JsName, Pair<JsFunction, JsExpression>> {
|
fun collectNamedFunctionsAndMetadata(scope: JsNode): Map<JsName, Pair<JsFunction, JsExpression>> {
|
||||||
val namedFunctions = mutableMapOf<JsName, Pair<JsFunction, JsExpression>>()
|
val namedFunctions = mutableMapOf<JsName, Pair<JsFunction, JsExpression>>()
|
||||||
|
|
||||||
@@ -200,6 +209,14 @@ fun collectAccessors(scope: JsNode): Map<String, JsFunction> {
|
|||||||
return accessors
|
return accessors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun collectAccessors(fragments: List<JsProgramFragment>): Map<String, JsFunction> {
|
||||||
|
val result = mutableMapOf<String, JsFunction>()
|
||||||
|
for (fragment in fragments) {
|
||||||
|
result += collectAccessors(fragment.declarationBlock)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
fun <T : JsNode> collectInstances(klass: Class<T>, scope: JsNode): List<T> {
|
fun <T : JsNode> collectInstances(klass: Class<T>, scope: JsNode): List<T> {
|
||||||
return with(InstanceCollector(klass, visitNestedDeclarations = false)) {
|
return with(InstanceCollector(klass, visitNestedDeclarations = false)) {
|
||||||
accept(scope)
|
accept(scope)
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
|
||||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
|
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
|
||||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult;
|
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram;
|
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule;
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||||
import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer;
|
import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer;
|
||||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
||||||
|
import org.jetbrains.kotlin.js.inline.JsInliner;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
||||||
|
import org.jetbrains.kotlin.js.translate.general.AstGenerationResult;
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
@@ -74,18 +76,20 @@ public final class K2JSTranslator {
|
|||||||
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
||||||
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
||||||
|
|
||||||
JsProgram program = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
AstGenerationResult translationResult = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|
||||||
//JsInliner.process(program);
|
JsInliner.process(config, analysisResult.getBindingTrace(), translationResult.getInnerModuleName(),
|
||||||
ResolveTemporaryNamesKt.resolveTemporaryNames(program);
|
translationResult.getFragments(), translationResult.getFragments());
|
||||||
|
|
||||||
|
ResolveTemporaryNamesKt.resolveTemporaryNames(translationResult.getProgram());
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|
||||||
CoroutineTransformer coroutineTransformer = new CoroutineTransformer(program);
|
CoroutineTransformer coroutineTransformer = new CoroutineTransformer(translationResult.getProgram());
|
||||||
coroutineTransformer.accept(program);
|
coroutineTransformer.accept(translationResult.getProgram());
|
||||||
RemoveUnusedImportsKt.removeUnusedImports(program);
|
RemoveUnusedImportsKt.removeUnusedImports(translationResult.getProgram());
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|
||||||
@@ -93,10 +97,10 @@ public final class K2JSTranslator {
|
|||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
|
|
||||||
List<String> importedModules = new ArrayList<>();
|
List<String> importedModules = new ArrayList<>();
|
||||||
/*for (JsImportedModule module : context.getImportedModules()) {
|
for (JsImportedModule module : translationResult.getImportedModuleList()) {
|
||||||
importedModules.add(module.getExternalName());
|
importedModules.add(module.getExternalName());
|
||||||
}*/
|
}
|
||||||
return new TranslationResult.Success(config, files, program, diagnostics, importedModules, moduleDescriptor,
|
return new TranslationResult.Success(config, files, translationResult.getProgram(), diagnostics, importedModules,
|
||||||
bindingTrace.getBindingContext());
|
moduleDescriptor, bindingTrace.getBindingContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -34,7 +34,8 @@ internal class DeclarationExporter(val context: StaticContext) {
|
|||||||
private val objectLikeKinds = setOf(ClassKind.OBJECT, ClassKind.ENUM_ENTRY)
|
private val objectLikeKinds = setOf(ClassKind.OBJECT, ClassKind.ENUM_ENTRY)
|
||||||
private val exportedDeclarations = mutableSetOf<MemberDescriptor>()
|
private val exportedDeclarations = mutableSetOf<MemberDescriptor>()
|
||||||
private val localPackageNames = mutableMapOf<FqName, JsName>()
|
private val localPackageNames = mutableMapOf<FqName, JsName>()
|
||||||
val statements = mutableListOf<JsStatement>()
|
private val statements: MutableList<JsStatement>
|
||||||
|
get() = context.fragment.exportBlock.statements
|
||||||
|
|
||||||
fun export(descriptor: MemberDescriptor, force: Boolean) {
|
fun export(descriptor: MemberDescriptor, force: Boolean) {
|
||||||
if (exportedDeclarations.contains(descriptor)) return
|
if (exportedDeclarations.contains(descriptor)) return
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ public final class StaticContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
|
private JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
|
||||||
JsName name = getModuleInnerName(descriptor);
|
JsName name = getModuleInnerName(descriptor);
|
||||||
return name != null ? JsAstUtils.pureFqn(name, null) : null;
|
return name != null ? JsAstUtils.pureFqn(name, null) : null;
|
||||||
}
|
}
|
||||||
@@ -748,6 +748,11 @@ public final class StaticContext {
|
|||||||
return currentModule;
|
return currentModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
||||||
|
String tag = Namer.getFunctionTag(descriptor);
|
||||||
|
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
/*public void postProcess() {
|
/*public void postProcess() {
|
||||||
addInterfaceDefaultMethods();
|
addInterfaceDefaultMethods();
|
||||||
rootFunction.getBody().getStatements().addAll(importStatements);
|
rootFunction.getBody().getStatements().addAll(importStatements);
|
||||||
|
|||||||
+2
-3
@@ -625,9 +625,8 @@ public class TranslationContext {
|
|||||||
callSites.add(new DeferredCallSite(constructor, invocationArgs, this));
|
callSites.add(new DeferredCallSite(constructor, invocationArgs, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
||||||
public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
|
staticContext.addInlineCall(descriptor);
|
||||||
return staticContext.getModuleExpressionFor(descriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDeclarationStatement(@NotNull JsStatement statement) {
|
public void addDeclarationStatement(@NotNull JsStatement statement) {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.js.translate.general
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsProgramFragment
|
||||||
|
|
||||||
|
class AstGenerationResult(
|
||||||
|
val program: JsProgram,
|
||||||
|
val innerModuleName: JsName,
|
||||||
|
val fragments: List<JsProgramFragment>,
|
||||||
|
val importedModuleList: List<JsImportedModule>
|
||||||
|
)
|
||||||
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.general
|
package org.jetbrains.kotlin.js.translate.general
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
|
|
||||||
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName) {
|
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName, val module: ModuleDescriptor) {
|
||||||
// Maps unique signature (see generateSignature) to names
|
// Maps unique signature (see generateSignature) to names
|
||||||
private val nameTable = mutableMapOf<String, JsName>()
|
private val nameTable = mutableMapOf<String, JsName>()
|
||||||
private val importedModuleTable = mutableMapOf<JsImportedModuleKey, JsName>()
|
private val importedModuleTable = mutableMapOf<JsImportedModuleKey, JsName>()
|
||||||
@@ -114,6 +115,7 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
|||||||
this += importBlock.statements
|
this += importBlock.statements
|
||||||
addClassPrototypes(this)
|
addClassPrototypes(this)
|
||||||
this += declarationBlock.statements
|
this += declarationBlock.statements
|
||||||
|
this += exportBlock.statements
|
||||||
this += initializerBlock.statements
|
this += initializerBlock.statements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ public final class Translation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsProgram generateAst(
|
public static AstGenerationResult generateAst(
|
||||||
@NotNull BindingTrace bindingTrace,
|
@NotNull BindingTrace bindingTrace,
|
||||||
@NotNull Collection<KtFile> files,
|
@NotNull Collection<KtFile> files,
|
||||||
@NotNull MainCallParameters mainCallParameters,
|
@NotNull MainCallParameters mainCallParameters,
|
||||||
@@ -253,7 +253,7 @@ public final class Translation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static JsProgram doGenerateAst(
|
private static AstGenerationResult doGenerateAst(
|
||||||
@NotNull BindingTrace bindingTrace,
|
@NotNull BindingTrace bindingTrace,
|
||||||
@NotNull Collection<KtFile> files,
|
@NotNull Collection<KtFile> files,
|
||||||
@NotNull MainCallParameters mainCallParameters,
|
@NotNull MainCallParameters mainCallParameters,
|
||||||
@@ -263,7 +263,7 @@ public final class Translation {
|
|||||||
JsProgram program = new JsProgram();
|
JsProgram program = new JsProgram();
|
||||||
JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function");
|
JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function");
|
||||||
JsName internalModuleName = program.getScope().declareName("_");
|
JsName internalModuleName = program.getScope().declareName("_");
|
||||||
Merger merger = new Merger(rootFunction, internalModuleName);
|
Merger merger = new Merger(rootFunction, internalModuleName, moduleDescriptor);
|
||||||
|
|
||||||
List<JsProgramFragment> fragments = new ArrayList<JsProgramFragment>();
|
List<JsProgramFragment> fragments = new ArrayList<JsProgramFragment>();
|
||||||
for (KtFile file : files) {
|
for (KtFile file : files) {
|
||||||
@@ -280,15 +280,13 @@ public final class Translation {
|
|||||||
|
|
||||||
List<JsStatement> statements = rootBlock.getStatements();
|
List<JsStatement> statements = rootBlock.getStatements();
|
||||||
|
|
||||||
//staticContext.postProcess();
|
|
||||||
statements.add(0, program.getStringLiteral("use strict").makeStmt());
|
statements.add(0, program.getStringLiteral("use strict").makeStmt());
|
||||||
if (!isBuiltinModule(fragments)) {
|
if (!isBuiltinModule(fragments)) {
|
||||||
defineModule(program, statements, config.getModuleId());
|
defineModule(program, statements, config.getModuleId());
|
||||||
}
|
}
|
||||||
|
|
||||||
//mayBeGenerateTests(files, rootBlock, context);
|
//mayBeGenerateTests(files, rootBlock, context);
|
||||||
JsName rootPackageName = program.getScope().declareName(Namer.getRootPackageName());
|
rootFunction.getParameters().add(new JsParameter(internalModuleName));
|
||||||
rootFunction.getParameters().add(new JsParameter((rootPackageName)));
|
|
||||||
|
|
||||||
// Invoke function passing modules as arguments
|
// Invoke function passing modules as arguments
|
||||||
// This should help minifier tool to recognize references to these modules as local variables and make them shorter.
|
// This should help minifier tool to recognize references to these modules as local variables and make them shorter.
|
||||||
@@ -307,13 +305,13 @@ public final class Translation {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
statements.add(new JsReturn(rootPackageName.makeRef()));
|
statements.add(new JsReturn(internalModuleName.makeRef()));
|
||||||
|
|
||||||
JsBlock block = program.getGlobalBlock();
|
JsBlock block = program.getGlobalBlock();
|
||||||
block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program,
|
block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program,
|
||||||
config.getModuleKind()));
|
config.getModuleKind()));
|
||||||
|
|
||||||
return program;
|
return new AstGenerationResult(program, internalModuleName, fragments, importedModuleList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBuiltinModule(@NotNull List<JsProgramFragment> fragments) {
|
private static boolean isBuiltinModule(@NotNull List<JsProgramFragment> fragments) {
|
||||||
|
|||||||
+5
-6
@@ -39,13 +39,12 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce
|
|||||||
@NotNull KtReferenceExpression referenceExpression,
|
@NotNull KtReferenceExpression referenceExpression,
|
||||||
@Nullable JsExpression receiver
|
@Nullable JsExpression receiver
|
||||||
) {
|
) {
|
||||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(referenceExpression, context.bindingContext());
|
ResolvedCall<? extends VariableDescriptor> resolvedCall =
|
||||||
|
CallUtilKt.getVariableResolvedCallWithAssert(referenceExpression, context.bindingContext());
|
||||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||||
resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
|
resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
|
||||||
}
|
}
|
||||||
assert resolvedCall.getResultingDescriptor() instanceof VariableDescriptor;
|
return new VariableAccessTranslator(context, referenceExpression, resolvedCall, receiver);
|
||||||
return new VariableAccessTranslator(context, referenceExpression, (ResolvedCall<? extends VariableDescriptor>) resolvedCall,
|
|
||||||
receiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce
|
|||||||
if (InlineUtil.isInline(getter)) {
|
if (InlineUtil.isInline(getter)) {
|
||||||
if (e instanceof JsNameRef) {
|
if (e instanceof JsNameRef) {
|
||||||
// Get was translated as a name reference
|
// Get was translated as a name reference
|
||||||
setInlineCallMetadata((JsNameRef) e, referenceExpression, getter);
|
setInlineCallMetadata((JsNameRef) e, referenceExpression, getter, context());
|
||||||
} else {
|
} else {
|
||||||
setInlineCallMetadata(e, referenceExpression, getter, context());
|
setInlineCallMetadata(e, referenceExpression, getter, context());
|
||||||
}
|
}
|
||||||
@@ -94,7 +93,7 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce
|
|||||||
if (InlineUtil.isInline(setter)) {
|
if (InlineUtil.isInline(setter)) {
|
||||||
if (e instanceof JsBinaryOperation && ((JsBinaryOperation) e).getOperator().isAssignment()) {
|
if (e instanceof JsBinaryOperation && ((JsBinaryOperation) e).getOperator().isAssignment()) {
|
||||||
// Set was translated as an assignment
|
// Set was translated as an assignment
|
||||||
setInlineCallMetadata((JsNameRef) (((JsBinaryOperation) e).getArg1()), referenceExpression, setter);
|
setInlineCallMetadata((JsNameRef) (((JsBinaryOperation) e).getArg1()), referenceExpression, setter, context());
|
||||||
} else {
|
} else {
|
||||||
setInlineCallMetadata(e, referenceExpression, setter, context());
|
setInlineCallMetadata(e, referenceExpression, setter, context());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ fun setInlineCallMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitor.accept(expression)
|
visitor.accept(expression)
|
||||||
|
|
||||||
|
context.addInlineCall(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setInlineCallMetadata(
|
fun setInlineCallMetadata(
|
||||||
@@ -76,11 +78,14 @@ fun setInlineCallMetadata(
|
|||||||
fun setInlineCallMetadata(
|
fun setInlineCallMetadata(
|
||||||
nameRef: JsNameRef,
|
nameRef: JsNameRef,
|
||||||
psiElement: KtExpression,
|
psiElement: KtExpression,
|
||||||
descriptor: CallableDescriptor
|
descriptor: CallableDescriptor,
|
||||||
|
context: TranslationContext
|
||||||
) {
|
) {
|
||||||
nameRef.descriptor = descriptor
|
nameRef.descriptor = descriptor
|
||||||
nameRef.inlineStrategy = InlineStrategy.IN_PLACE
|
nameRef.inlineStrategy = InlineStrategy.IN_PLACE
|
||||||
nameRef.psiElement = psiElement
|
nameRef.psiElement = psiElement
|
||||||
|
|
||||||
|
context.addInlineCall(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TranslationContext.aliasedName(descriptor: CallableDescriptor): JsName {
|
fun TranslationContext.aliasedName(descriptor: CallableDescriptor): JsName {
|
||||||
|
|||||||
Reference in New Issue
Block a user