JS: report error from backend, when inline function is called recursively
This commit is contained in:
+4
-1
@@ -18,15 +18,18 @@ package com.google.dart.compiler.backend.js.ast.metadata
|
|||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import org.jetbrains.kotlin.builtins.InlineStrategy
|
import org.jetbrains.kotlin.builtins.InlineStrategy
|
||||||
import kotlin.properties.Delegates
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
public var JsName.staticRef: JsNode? by MetadataProperty(default = null)
|
public var JsName.staticRef: JsNode? by MetadataProperty(default = null)
|
||||||
|
|
||||||
public var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
|
public var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
|
||||||
|
|
||||||
public var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null)
|
public var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null)
|
||||||
|
|
||||||
|
public var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null)
|
||||||
|
|
||||||
public var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
|
public var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
|
||||||
|
|
||||||
public var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
|
public var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by Delegates.lazy {
|
|||||||
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
||||||
put(ErrorsJs.NON_TOPLEVEL_CLASS_DECLARATION, "Non-toplevel {0} declarations not supported yet", Renderers.STRING)
|
put(ErrorsJs.NON_TOPLEVEL_CLASS_DECLARATION, "Non-toplevel {0} declarations not supported yet", Renderers.STRING)
|
||||||
put(ErrorsJs.SECONDARY_CONSTRUCTOR, "Secondary constructors not supported yet")
|
put(ErrorsJs.SECONDARY_CONSTRUCTOR, "Secondary constructors not supported yet")
|
||||||
|
put(ErrorsJs.INLINE_CALL_CYCLE, "The call is a part of inline cycle")
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
||||||
@@ -44,6 +45,7 @@ public interface ErrorsJs {
|
|||||||
DiagnosticFactory1<JetElement, JetElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
DiagnosticFactory1<JetElement, JetElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||||
DiagnosticFactory1<JetNamedDeclaration, String> NON_TOPLEVEL_CLASS_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_NAME);
|
DiagnosticFactory1<JetNamedDeclaration, String> NON_TOPLEVEL_CLASS_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_NAME);
|
||||||
DiagnosticFactory0<JetNamedDeclaration> SECONDARY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
DiagnosticFactory0<JetNamedDeclaration> SECONDARY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
|
DiagnosticFactory0<PsiElement> INLINE_CALL_CYCLE = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
Object _initializer = new Object() {
|
Object _initializer = new Object() {
|
||||||
|
|||||||
@@ -13,5 +13,6 @@
|
|||||||
<orderEntry type="module" module-name="js.translator" />
|
<orderEntry type="module" module-name="js.translator" />
|
||||||
<orderEntry type="module" module-name="util" />
|
<orderEntry type="module" module-name="util" />
|
||||||
<orderEntry type="module" module-name="js.parser" />
|
<orderEntry type="module" module-name="js.parser" />
|
||||||
|
<orderEntry type="module" module-name="frontend" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -18,16 +18,16 @@ package org.jetbrains.kotlin.js.inline;
|
|||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
|
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.InlineStrategy;
|
import org.jetbrains.kotlin.builtins.InlineStrategy;
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
||||||
import org.jetbrains.kotlin.js.inline.context.*;
|
import org.jetbrains.kotlin.js.inline.context.*;
|
||||||
import org.jetbrains.kotlin.js.inline.exception.InlineRecursionException;
|
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
|
|
||||||
import java.util.IdentityHashMap;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.inline.FunctionInlineMutator.getInlineableCallReplacement;
|
import static org.jetbrains.kotlin.js.inline.FunctionInlineMutator.getInlineableCallReplacement;
|
||||||
import static org.jetbrains.kotlin.js.inline.clean.CleanPackage.removeUnusedFunctionDefinitions;
|
import static org.jetbrains.kotlin.js.inline.clean.CleanPackage.removeUnusedFunctionDefinitions;
|
||||||
@@ -42,6 +42,11 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
private final Set<JsFunction> processedFunctions = IdentitySet();
|
private final Set<JsFunction> processedFunctions = IdentitySet();
|
||||||
private final Set<JsFunction> inProcessFunctions = IdentitySet();
|
private final Set<JsFunction> inProcessFunctions = IdentitySet();
|
||||||
private final FunctionReader functionReader;
|
private final FunctionReader functionReader;
|
||||||
|
private final DiagnosticSink trace;
|
||||||
|
|
||||||
|
// these are needed for error reporting, when inliner detects cycle
|
||||||
|
private final Stack<JsFunction> namedFunctionsStack = new Stack<JsFunction>();
|
||||||
|
private final LinkedList<JsCallInfo> inlineCallInfos = new LinkedList<JsCallInfo>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A statement can contain more, than one inlineable sub-expressions.
|
* A statement can contain more, than one inlineable sub-expressions.
|
||||||
@@ -76,7 +81,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
public static JsProgram process(@NotNull TranslationContext context) {
|
public static JsProgram process(@NotNull TranslationContext context) {
|
||||||
JsProgram program = context.program();
|
JsProgram program = context.program();
|
||||||
IdentityHashMap<JsName, JsFunction> functions = collectNamedFunctions(program);
|
IdentityHashMap<JsName, JsFunction> functions = collectNamedFunctions(program);
|
||||||
JsInliner inliner = new JsInliner(functions, new FunctionReader(context));
|
JsInliner inliner = new JsInliner(functions, new FunctionReader(context), context.bindingTrace());
|
||||||
inliner.accept(program);
|
inliner.accept(program);
|
||||||
removeUnusedFunctionDefinitions(program, functions);
|
removeUnusedFunctionDefinitions(program, functions);
|
||||||
return program;
|
return program;
|
||||||
@@ -84,19 +89,24 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
|
|
||||||
private JsInliner(
|
private JsInliner(
|
||||||
@NotNull IdentityHashMap<JsName, JsFunction> functions,
|
@NotNull IdentityHashMap<JsName, JsFunction> functions,
|
||||||
@NotNull FunctionReader functionReader
|
@NotNull FunctionReader functionReader,
|
||||||
|
@NotNull DiagnosticSink trace
|
||||||
) {
|
) {
|
||||||
this.functions = functions;
|
this.functions = functions;
|
||||||
this.functionReader = functionReader;
|
this.functionReader = functionReader;
|
||||||
|
this.trace = trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(JsFunction function, JsContext context) {
|
public boolean visit(JsFunction function, JsContext context) {
|
||||||
inliningContexts.push(new JsInliningContext(function));
|
inliningContexts.push(new JsInliningContext(function));
|
||||||
|
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
|
||||||
if (inProcessFunctions.contains(function)) throw new InlineRecursionException();
|
|
||||||
inProcessFunctions.add(function);
|
inProcessFunctions.add(function);
|
||||||
|
|
||||||
|
if (functions.containsValue(function)) {
|
||||||
|
namedFunctionsStack.push(function);
|
||||||
|
}
|
||||||
|
|
||||||
return super.visit(function, context);
|
return super.visit(function, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,16 +122,27 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
inProcessFunctions.remove(function);
|
inProcessFunctions.remove(function);
|
||||||
|
|
||||||
inliningContexts.pop();
|
inliningContexts.pop();
|
||||||
|
|
||||||
|
if (!namedFunctionsStack.empty() && namedFunctionsStack.peek() == function) {
|
||||||
|
namedFunctionsStack.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(JsInvocation call, JsContext context) {
|
public boolean visit(JsInvocation call, JsContext context) {
|
||||||
if (call == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldInline(call) && canInline(call)) {
|
if (shouldInline(call) && canInline(call)) {
|
||||||
|
JsFunction containingFunction = getCurrentNamedFunction();
|
||||||
|
if (containingFunction != null) {
|
||||||
|
inlineCallInfos.add(new JsCallInfo(call, containingFunction));
|
||||||
|
}
|
||||||
|
|
||||||
JsFunction definition = getFunctionContext().getFunctionDefinition(call);
|
JsFunction definition = getFunctionContext().getFunctionDefinition(call);
|
||||||
|
|
||||||
|
if (inProcessFunctions.contains(definition)) {
|
||||||
|
reportInlineCycle(call, definition);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!processedFunctions.contains(definition)) {
|
if (!processedFunctions.contains(definition)) {
|
||||||
accept(definition);
|
accept(definition);
|
||||||
}
|
}
|
||||||
@@ -132,6 +153,19 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
return !lastStatementWasShifted;
|
return !lastStatementWasShifted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endVisit(JsInvocation x, JsContext ctx) {
|
||||||
|
JsCallInfo lastCallInfo = null;
|
||||||
|
|
||||||
|
if (!inlineCallInfos.isEmpty()) {
|
||||||
|
lastCallInfo = inlineCallInfos.getLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCallInfo != null && lastCallInfo.call == x) {
|
||||||
|
inlineCallInfos.removeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void inline(@NotNull JsInvocation call, @NotNull JsContext context) {
|
private void inline(@NotNull JsInvocation call, @NotNull JsContext context) {
|
||||||
JsInliningContext inliningContext = getInliningContext();
|
JsInliningContext inliningContext = getInliningContext();
|
||||||
FunctionContext functionContext = getFunctionContext();
|
FunctionContext functionContext = getFunctionContext();
|
||||||
@@ -141,6 +175,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
JsStatement inlineableBody = inlineableResult.getInlineableBody();
|
JsStatement inlineableBody = inlineableResult.getInlineableBody();
|
||||||
JsExpression resultExpression = inlineableResult.getResultExpression();
|
JsExpression resultExpression = inlineableResult.getResultExpression();
|
||||||
StatementContext statementContext = inliningContext.getStatementContext();
|
StatementContext statementContext = inliningContext.getStatementContext();
|
||||||
|
accept(inlineableBody);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assumes, that resultExpression == null, when result is not needed.
|
* Assumes, that resultExpression == null, when result is not needed.
|
||||||
@@ -183,6 +218,30 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
return getInliningContext().getFunctionContext();
|
return getInliningContext().getFunctionContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JsFunction getCurrentNamedFunction() {
|
||||||
|
if (namedFunctionsStack.empty()) return null;
|
||||||
|
return namedFunctionsStack.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportInlineCycle(@NotNull JsInvocation call, @NotNull JsFunction calledFunction) {
|
||||||
|
MetadataPackage.setInlineStrategy(call, InlineStrategy.NOT_INLINE);
|
||||||
|
Iterator<JsCallInfo> it = inlineCallInfos.descendingIterator();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
JsCallInfo callInfo = it.next();
|
||||||
|
PsiElement psiElement = MetadataPackage.getPsiElement(callInfo.call);
|
||||||
|
|
||||||
|
if (psiElement != null) {
|
||||||
|
trace.report(ErrorsJs.INLINE_CALL_CYCLE.on(psiElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callInfo.containingFunction == calledFunction) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean canInline(@NotNull JsInvocation call) {
|
private boolean canInline(@NotNull JsInvocation call) {
|
||||||
FunctionContext functionContext = getFunctionContext();
|
FunctionContext functionContext = getFunctionContext();
|
||||||
return functionContext.hasFunctionDefinition(call);
|
return functionContext.hasFunctionDefinition(call);
|
||||||
@@ -193,7 +252,6 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
return strategy != null && strategy.isInline();
|
return strategy != null && strategy.isInline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class JsInliningContext implements InliningContext {
|
private class JsInliningContext implements InliningContext {
|
||||||
private final FunctionContext functionContext;
|
private final FunctionContext functionContext;
|
||||||
|
|
||||||
@@ -245,4 +303,17 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
return functionContext;
|
return functionContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class JsCallInfo {
|
||||||
|
@NotNull
|
||||||
|
public final JsInvocation call;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public final JsFunction containingFunction;
|
||||||
|
|
||||||
|
private JsCallInfo(@NotNull JsInvocation call, @NotNull JsFunction function) {
|
||||||
|
this.call = call;
|
||||||
|
containingFunction = function;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.inline.exception;
|
|
||||||
|
|
||||||
public class InlineRecursionException extends RuntimeException {
|
|
||||||
public InlineRecursionException() {
|
|
||||||
super("Encountered mutual inline recursion, inline will lead to stack overflow");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -71,12 +71,14 @@ public final class K2JSTranslator {
|
|||||||
BindingTrace bindingTrace = analysisResult.getBindingTrace();
|
BindingTrace bindingTrace = analysisResult.getBindingTrace();
|
||||||
TopDownAnalyzerFacadeForJS.checkForErrors(Config.withJsLibAdded(files, config), bindingTrace.getBindingContext());
|
TopDownAnalyzerFacadeForJS.checkForErrors(Config.withJsLibAdded(files, config), bindingTrace.getBindingContext());
|
||||||
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
||||||
TranslationContext context = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
|
||||||
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
||||||
|
|
||||||
|
TranslationContext context = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|
||||||
JsProgram program = JsInliner.process(context);
|
JsProgram program = JsInliner.process(context);
|
||||||
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|
||||||
return new TranslationResult.Success(config, files, program, diagnostics);
|
return new TranslationResult.Success(config, files, program, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-19
@@ -33,9 +33,7 @@ import org.jetbrains.kotlin.psi.JetStringTemplateExpression;
|
|||||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
@@ -45,6 +43,7 @@ import java.io.StringReader;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getFunctionDescriptor;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.UtilsPackage.setInlineCallMetadata;
|
import static org.jetbrains.kotlin.js.translate.utils.UtilsPackage.setInlineCallMetadata;
|
||||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
|
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
|
||||||
import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall;
|
import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall;
|
||||||
@@ -64,10 +63,9 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate();
|
JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate();
|
||||||
CallableDescriptor descriptor = getFunctionDescriptor(expression, context);
|
|
||||||
|
|
||||||
if (!resolvedCall.isSafeCall() && shouldBeInlined(expression, context)) {
|
if (!resolvedCall.isSafeCall() && shouldBeInlined(expression, context)) {
|
||||||
setInlineCallMetadata(callExpression, descriptor, context);
|
setInlineCallMetadata(callExpression, expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callExpression;
|
return callExpression;
|
||||||
@@ -94,21 +92,6 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static CallableDescriptor getFunctionDescriptor(
|
|
||||||
@NotNull JetCallExpression expression,
|
|
||||||
@NotNull TranslationContext context
|
|
||||||
) {
|
|
||||||
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext());
|
|
||||||
assert resolvedCall != null;
|
|
||||||
|
|
||||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
|
||||||
return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvedCall.getCandidateDescriptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private CallExpressionTranslator(
|
private CallExpressionTranslator(
|
||||||
@NotNull JetCallExpression expression,
|
@NotNull JetCallExpression expression,
|
||||||
@Nullable JsExpression receiver,
|
@Nullable JsExpression receiver,
|
||||||
|
|||||||
@@ -19,9 +19,14 @@ package org.jetbrains.kotlin.js.translate.utils;
|
|||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.lexer.JetToken;
|
import org.jetbrains.kotlin.lexer.JetToken;
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens;
|
import org.jetbrains.kotlin.lexer.JetTokens;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -132,4 +137,19 @@ public final class PsiUtils {
|
|||||||
assert rangeExpression != null;
|
assert rangeExpression != null;
|
||||||
return rangeExpression;
|
return rangeExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static CallableDescriptor getFunctionDescriptor(
|
||||||
|
@NotNull JetCallExpression expression,
|
||||||
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
|
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext());
|
||||||
|
assert resolvedCall != null;
|
||||||
|
|
||||||
|
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||||
|
return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedCall.getCandidateDescriptor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
|||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
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.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.JetCallExpression
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively walks expression and sets metadata for all invocations of descriptor.
|
* Recursively walks expression and sets metadata for all invocations of descriptor.
|
||||||
@@ -38,9 +39,10 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|||||||
*/
|
*/
|
||||||
fun setInlineCallMetadata(
|
fun setInlineCallMetadata(
|
||||||
expression: JsExpression,
|
expression: JsExpression,
|
||||||
descriptor: CallableDescriptor,
|
jetCall: JetCallExpression,
|
||||||
context: TranslationContext
|
context: TranslationContext
|
||||||
) {
|
) {
|
||||||
|
val descriptor = PsiUtils.getFunctionDescriptor(jetCall, context)
|
||||||
assert(CallExpressionTranslator.shouldBeInlined(descriptor)) {
|
assert(CallExpressionTranslator.shouldBeInlined(descriptor)) {
|
||||||
"Expected descriptor of callable, that should be inlined, but got: $descriptor"
|
"Expected descriptor of callable, that should be inlined, but got: $descriptor"
|
||||||
}
|
}
|
||||||
@@ -56,6 +58,7 @@ fun setInlineCallMetadata(
|
|||||||
if (name == invocation.name) {
|
if (name == invocation.name) {
|
||||||
invocation.descriptor = descriptor
|
invocation.descriptor = descriptor
|
||||||
invocation.inlineStrategy = InlineStrategy.IN_PLACE
|
invocation.inlineStrategy = InlineStrategy.IN_PLACE
|
||||||
|
invocation.psiElement = jetCall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user