diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 4ced0a47419..58f4938e3e1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -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 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()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 328ef286f21..9824ea18c2e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -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 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 2dd9da1bdeb..061f38d1d03 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -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 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 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 getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) { + Set result = new HashSet(); + 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; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index 6d2167ee378..a2aadac8497 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -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"; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java index 825bd79f3eb..bb72d658571 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java @@ -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 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); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java index 624c74440c2..9f7926029b0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java @@ -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; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt index bf633e98bcd..3641eefce4c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index 739e8126337..3f2d9a4ad17 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -179,10 +179,3 @@ public fun JetExpression.getFunctionResolvedCallWithAssert(context: BindingConte [suppress("UNCHECKED_CAST")] return resolvedCall as ResolvedCall } - -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) -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java index 0db3556e99c..93030a98ac7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java @@ -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; diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.1.kt new file mode 100644 index 00000000000..e14077c7ab8 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.2.kt new file mode 100644 index 00000000000..12d90f9709d --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/simpleFunctional.2.kt @@ -0,0 +1,5 @@ +package test + +public inline fun doCall(block: ()-> R) : R { + return block() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 73b5a6d19e8..57f60fc61d8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 3316a5eaea9..987762e8758 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -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"); diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt index 6311a8fbc22..c508f68da83 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.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 diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt index df58f2bae73..b082f616aa3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt @@ -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 } } diff --git a/idea/testData/codeInsight/lineMarker/recursiveCall/functionalExpression.kt b/idea/testData/codeInsight/lineMarker/recursiveCall/functionalExpression.kt new file mode 100644 index 00000000000..a4a3972d4e8 --- /dev/null +++ b/idea/testData/codeInsight/lineMarker/recursiveCall/functionalExpression.kt @@ -0,0 +1,8 @@ +fun test() { + + fun f(a: Int) { + if (a > 0) { + f(a-1) + } + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/lineMarker/recursiveCall/inInlinedFunctionExpression.kt b/idea/testData/codeInsight/lineMarker/recursiveCall/inInlinedFunctionExpression.kt new file mode 100644 index 00000000000..91660fded15 --- /dev/null +++ b/idea/testData/codeInsight/lineMarker/recursiveCall/inInlinedFunctionExpression.kt @@ -0,0 +1,14 @@ +fun f(a: Int) { + run(fun () { + f(a - 1) + }) +} + +fun ff(a: Int) { + run1 { + ff(a - 1) + } +} + +inline fun run1(noinline f: () -> T): T { } + diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java index f3680f9a501..fa3aec3cda1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java @@ -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");