Support functional expression in non-local returns
This commit is contained in:
@@ -94,8 +94,7 @@ import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
|
||||
@@ -1845,13 +1844,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@Nullable
|
||||
private NonLocalReturnInfo getNonLocalReturnInfo(@NotNull CallableMemberDescriptor descriptor, @NotNull JetReturnExpression expression) {
|
||||
//call inside lambda
|
||||
if (DescriptorUtils.isFunctionLiteral(descriptor)) {
|
||||
if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
|
||||
if (expression.getLabelName() == null) {
|
||||
//non labeled return couldn't be local in lambda
|
||||
FunctionDescriptor containingFunction =
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
|
||||
//ROOT_LABEL to prevent clashing with existing labels
|
||||
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.ROOT_LABEL);
|
||||
if (isFunctionLiteral(descriptor)) {
|
||||
//non labeled return couldn't be local in lambda
|
||||
FunctionDescriptor containingFunction =
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, false).getFirst();
|
||||
//FIRST_FUN_LABEL to prevent clashing with existing labels
|
||||
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
|
||||
} else {
|
||||
//local
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
PsiElement element = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
|
||||
|
||||
@@ -35,8 +35,7 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteral;
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.kotlin.psi.JetFunction;
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
@@ -233,9 +232,8 @@ public class JvmCodegenUtil {
|
||||
|
||||
public static boolean isLambdaWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
|
||||
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
|
||||
return declaration instanceof JetFunctionLiteral &&
|
||||
declaration.getParent() instanceof JetFunctionLiteralExpression &&
|
||||
InlineUtil.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false);
|
||||
return InlineUtil.isFunctionalExpression(declaration) &&
|
||||
InlineUtil.isInlineLambda((JetFunction)declaration, bindingContext, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -34,7 +35,6 @@ import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
@@ -55,10 +55,7 @@ import org.jetbrains.org.objectweb.asm.tree.LabelNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
|
||||
@@ -269,33 +266,15 @@ public class InlineCodegen extends CallGenerator {
|
||||
InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
|
||||
|
||||
CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
|
||||
final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
|
||||
LabelOwner labelOwner = new LabelOwner() {
|
||||
|
||||
final CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
|
||||
|
||||
@Override
|
||||
public boolean isMyLabel(@NotNull String name) {
|
||||
if (InlineCodegenUtil.ROOT_LABEL.equals(name)) {
|
||||
return !isFunctionLiteral(descriptor);
|
||||
}
|
||||
|
||||
//check function name if exists
|
||||
if (descriptor.getName().asString().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//check functional expression labels
|
||||
if (isFunctionExpression(descriptor)) {
|
||||
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
|
||||
if (element != null && element.getParent() instanceof JetLabeledExpression) {
|
||||
String labelName = ((JetLabeledExpression) element.getParent()).getLabelName();
|
||||
return name.equals(labelName);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return labels.contains(name);
|
||||
}
|
||||
};
|
||||
|
||||
List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
|
||||
generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.totalSize() + 1).value).index);
|
||||
|
||||
@@ -549,23 +528,35 @@ public class InlineCodegen extends CallGenerator {
|
||||
|
||||
public void rememberClosure(JetExpression expression, Type type) {
|
||||
JetExpression lambda = JetPsiUtil.deparenthesize(expression);
|
||||
assert isInlinableParameterExpression(lambda) :"Couldn't find inline expression in " + expression.getText();
|
||||
assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
|
||||
|
||||
String labelNameIfPresent = null;
|
||||
PsiElement parent = lambda.getParent();
|
||||
if (parent instanceof JetLabeledExpression) {
|
||||
labelNameIfPresent = ((JetLabeledExpression) parent).getLabelName();
|
||||
}
|
||||
if (lambda instanceof JetFunctionLiteralExpression) {
|
||||
lambda = ((JetFunctionLiteralExpression) lambda).getFunctionLiteral();
|
||||
}
|
||||
LambdaInfo info = new LambdaInfo(lambda, typeMapper, labelNameIfPresent);
|
||||
LambdaInfo info = new LambdaInfo(lambda, typeMapper);
|
||||
|
||||
ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
|
||||
closureInfo.setLambda(info);
|
||||
expressionMap.put(closureInfo.getIndex(), info);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
if (lambdaOrFun != null) {
|
||||
PsiElement parent = lambdaOrFun.getParent();
|
||||
if (parent instanceof JetLabeledExpression) {
|
||||
String labelName = ((JetLabeledExpression) parent).getLabelName();
|
||||
assert labelName != null : "Labeled expression should have not nul label " + parent.getText();
|
||||
result.add(labelName);
|
||||
}
|
||||
}
|
||||
if (!isFunctionLiteral(descriptor)) {
|
||||
if (!descriptor.getName().isSpecial()) {
|
||||
result.add(descriptor.getName().asString());
|
||||
}
|
||||
result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void putClosureParametersOnStack() {
|
||||
for (LambdaInfo next : expressionMap.values()) {
|
||||
activeLambda = next;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class InlineCodegenUtil {
|
||||
|
||||
public static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
|
||||
|
||||
public static final String ROOT_LABEL = "$$$$$ROOT$$$$$";
|
||||
public static final String FIRST_FUN_LABEL = "$$$$$ROOT$$$$$";
|
||||
public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
||||
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
||||
public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
@@ -27,7 +26,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.JetExpression;
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||
@@ -35,6 +36,7 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
|
||||
@@ -44,8 +46,8 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
private final JetTypeMapper typeMapper;
|
||||
|
||||
@Nullable
|
||||
public final String labelName;
|
||||
@NotNull
|
||||
public final Set<String> labels;
|
||||
|
||||
private final CalculatedClosure closure;
|
||||
|
||||
@@ -59,10 +61,11 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
private final Type closureClassType;
|
||||
|
||||
LambdaInfo(@NotNull JetExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
|
||||
this.expression = expression;
|
||||
LambdaInfo(@NotNull JetExpression expr, @NotNull JetTypeMapper typeMapper) {
|
||||
this.expression = expr instanceof JetFunctionLiteralExpression ?
|
||||
((JetFunctionLiteralExpression) expr).getFunctionLiteral() : expr;
|
||||
|
||||
this.typeMapper = typeMapper;
|
||||
this.labelName = labelName;
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
|
||||
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
|
||||
@@ -72,6 +75,9 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
assert closure != null : "Closure for lambda should be not null " + expression.getText();
|
||||
|
||||
|
||||
labels = InlineCodegen.getDeclarationLabels(expr, functionDescriptor);
|
||||
}
|
||||
|
||||
public SMAPAndMethodNode getNode() {
|
||||
@@ -171,7 +177,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
@Override
|
||||
public boolean isMyLabel(@NotNull String name) {
|
||||
return name.equals(labelName);
|
||||
return labels.contains(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -873,6 +873,9 @@ public class JetPsiUtil {
|
||||
else if (parent instanceof JetValueArgument || parent instanceof JetValueArgumentList) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
else if (parent instanceof JetFunctionLiteralExpression) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
+5
-3
@@ -17,17 +17,19 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.psi.JetFunction
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteral
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.types.expressions.CaptureKind
|
||||
|
||||
@@ -67,9 +69,9 @@ class CapturingInClosureChecker : CallChecker {
|
||||
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
||||
): Boolean {
|
||||
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
|
||||
if (scopeDeclaration !is JetFunctionLiteral) return false
|
||||
if (!InlineUtil.isFunctionalExpression(scopeDeclaration)) return false
|
||||
|
||||
if (scopeDeclaration.isInlined(context)) {
|
||||
if (InlineUtil.isInlineLambda(scopeDeclaration as JetFunction, context, false)) {
|
||||
val scopeContainerParent = scopeContainer.getContainingDeclaration()
|
||||
assert(scopeContainerParent != null) { "parent is null for " + scopeContainer }
|
||||
return !isCapturedVariable(variableParent, scopeContainerParent) || isCapturedInInline(context, scopeContainerParent, variableParent)
|
||||
|
||||
@@ -179,10 +179,3 @@ public fun JetExpression.getFunctionResolvedCallWithAssert(context: BindingConte
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
return resolvedCall as ResolvedCall<out FunctionDescriptor>
|
||||
}
|
||||
|
||||
public fun JetFunctionLiteral.isInlined(bindingContext: BindingContext): Boolean {
|
||||
val parent = this.getParent()
|
||||
assert(parent is JetFunctionLiteralExpression) { "parent of JetFunctionLiteral is " + parent }
|
||||
|
||||
return InlineUtil.isInlineLambda(parent as JetFunctionLiteralExpression, bindingContext, false)
|
||||
}
|
||||
|
||||
@@ -102,10 +102,8 @@ public class InlineUtil {
|
||||
|
||||
BindingContext bindingContext = trace.getBindingContext();
|
||||
|
||||
while (containingFunction instanceof JetFunctionLiteral && fromFunction != containingFunctionDescriptor) {
|
||||
//JetFunctionLiteralExpression
|
||||
containingFunction = containingFunction.getParent();
|
||||
if (!isInlineLambda((JetFunctionLiteralExpression) containingFunction, bindingContext, true)) {
|
||||
while (isFunctionalExpression(containingFunction) && fromFunction != containingFunctionDescriptor) {
|
||||
if (!isInlineLambda((JetFunction) containingFunction, bindingContext, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,15 +118,17 @@ public class InlineUtil {
|
||||
}
|
||||
|
||||
public static boolean isInlineLambda(
|
||||
@NotNull JetFunctionLiteralExpression lambdaExpression,
|
||||
@NotNull JetFunction functionalExpression,
|
||||
@NotNull BindingContext bindingContext,
|
||||
boolean checkNonLocalReturn
|
||||
) {
|
||||
JetExpression call = JetPsiUtil.getParentCallIfPresent(lambdaExpression);
|
||||
if (!isFunctionalExpression(functionalExpression)) return false;
|
||||
|
||||
JetExpression call = JetPsiUtil.getParentCallIfPresent(functionalExpression);
|
||||
if (call != null) {
|
||||
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext);
|
||||
if (resolvedCall != null && isInline(resolvedCall.getResultingDescriptor())) {
|
||||
ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), lambdaExpression);
|
||||
ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), functionalExpression);
|
||||
if (argument != null) {
|
||||
ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument);
|
||||
if (mapping instanceof ArgumentMatch) {
|
||||
@@ -143,6 +143,10 @@ public class InlineUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isFunctionalExpression(@Nullable PsiElement functionalExpression) {
|
||||
return functionalExpression instanceof JetFunctionLiteral || functionalExpression instanceof JetNamedFunction;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) {
|
||||
DeclarationDescriptor current = strict ? descriptor.getContainingDeclaration() : descriptor;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import test.*
|
||||
|
||||
fun test1(local: Int, nonLocal: String, doNonLocal: Boolean): String {
|
||||
|
||||
val localResult = doCall(
|
||||
fun (): Int {
|
||||
if (doNonLocal) {
|
||||
return@test1 nonLocal
|
||||
}
|
||||
return local
|
||||
})
|
||||
|
||||
if (localResult == 11) {
|
||||
return "OK_LOCAL"
|
||||
}
|
||||
else {
|
||||
return "LOCAL_FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
fun test2(local: Int, nonLocal: String, doNonLocal: Boolean): String {
|
||||
|
||||
val localResult = doCall(
|
||||
fun xxx(): Int {
|
||||
if (doNonLocal) {
|
||||
return@test2 nonLocal
|
||||
}
|
||||
return@xxx local
|
||||
})
|
||||
|
||||
if (localResult == 11) {
|
||||
return "OK_LOCAL"
|
||||
}
|
||||
else {
|
||||
return "LOCAL_FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
fun test3(local: Int, nonLocal: String, doNonLocal: Boolean): String {
|
||||
|
||||
val localResult = doCall(
|
||||
yy@ fun xxx(): Int {
|
||||
if (doNonLocal) {
|
||||
return@test3 nonLocal
|
||||
}
|
||||
return@yy local
|
||||
})
|
||||
|
||||
if (localResult == 11) {
|
||||
return "OK_LOCAL"
|
||||
}
|
||||
else {
|
||||
return "LOCAL_FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var test1 = test1(11, "fail", false)
|
||||
if (test1 != "OK_LOCAL") return "test1: ${test1}"
|
||||
|
||||
test1 = test1(-1, "OK_NONLOCAL", true)
|
||||
if (test1 != "OK_NONLOCAL") return "test2: ${test1}"
|
||||
|
||||
var test2 = test2(11, "fail", false)
|
||||
if (test2 != "OK_LOCAL") return "test1: ${test2}"
|
||||
|
||||
test2 = test2(-1, "OK_NONLOCAL", true)
|
||||
if (test2 != "OK_NONLOCAL") return "test2: ${test2}"
|
||||
|
||||
var test3 = test3(11, "fail", false)
|
||||
if (test3 != "OK_LOCAL") return "test1: ${test3}"
|
||||
|
||||
test3 = test3(-1, "OK_NONLOCAL", true)
|
||||
if (test3 != "OK_NONLOCAL") return "test2: ${test3}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
public inline fun <R> doCall(block: ()-> R) : R {
|
||||
return block()
|
||||
}
|
||||
+6
@@ -472,6 +472,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleFunctional.1.kt")
|
||||
public void testSimpleFunctional() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleVoid.1.kt")
|
||||
public void testSimpleVoid() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/simpleVoid.1.kt");
|
||||
|
||||
+6
@@ -472,6 +472,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleFunctional.1.kt")
|
||||
public void testSimpleFunctional() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleVoid.1.kt")
|
||||
public void testSimpleVoid() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/simpleVoid.1.kt");
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
|
||||
public class KotlinHighlightExitPointsHandlerFactory: HighlightUsagesHandlerFactoryBase() {
|
||||
companion object {
|
||||
@@ -85,8 +85,8 @@ private fun JetExpression.getRelevantFunction(): JetFunction? {
|
||||
}
|
||||
for (parent in parents(false)) {
|
||||
when (parent) {
|
||||
is JetFunctionLiteral -> if (!parent.isInlined((parent.getParent() as JetFunctionLiteralExpression).analyze())) return parent
|
||||
is JetNamedFunction -> return parent
|
||||
is JetFunctionLiteral,
|
||||
is JetNamedFunction -> if (!InlineUtil.isInlineLambda(parent as JetFunction, parent.analyze(), false)) return parent
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
@@ -56,8 +56,8 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
private fun getEnclosingFunction(element: JetElement): JetNamedFunction? {
|
||||
for (parent in element.parents(false)) {
|
||||
when (parent) {
|
||||
is JetFunctionLiteral -> if (!parent.isInlined(parent.analyze())) return null
|
||||
is JetNamedFunction -> return parent
|
||||
is JetFunctionLiteral -> if (!InlineUtil.isInlineLambda(parent, parent.analyze(), false)) return null
|
||||
is JetNamedFunction -> if (!InlineUtil.isInlineLambda(parent, parent.analyze(), false)) return parent
|
||||
is JetClassOrObject -> return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fun test() {
|
||||
|
||||
fun f(a: Int) {
|
||||
if (a > 0) {
|
||||
<lineMarker descr="Recursive call">f</lineMarker>(a-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fun f(a: Int) {
|
||||
run(fun () {
|
||||
<lineMarker>f</lineMarker>(a - 1)
|
||||
})
|
||||
}
|
||||
|
||||
fun ff(a: Int) {
|
||||
run1 {
|
||||
ff(a - 1)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> run1(noinline f: () -> T): T { }
|
||||
|
||||
@@ -202,12 +202,24 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionalExpression.kt")
|
||||
public void testFunctionalExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/functionalExpression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("generic.kt")
|
||||
public void testGeneric() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/generic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inInlinedFunctionExpression.kt")
|
||||
public void testInInlinedFunctionExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/inInlinedFunctionExpression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inInlinedLambda.kt")
|
||||
public void testInInlinedLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/inInlinedLambda.kt");
|
||||
|
||||
Reference in New Issue
Block a user