Support functional expression in non-local returns

This commit is contained in:
Michael Bogdanov
2015-04-27 13:59:15 +03:00
parent 3a6e5ac78c
commit e0aa64b8d2
18 changed files with 210 additions and 81 deletions
@@ -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;
}
@@ -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()
}
@@ -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");
@@ -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");
@@ -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
@@ -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");