From 2377a10007f65568b72f10ad5552751628628eae Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Tue, 2 Jun 2015 12:16:55 +0300 Subject: [PATCH] Fix labeling processing on inlining: suport labeled literals #KT-7273 Fixed --- .../kotlin/codegen/inline/InlineCodegen.java | 12 ++-- .../types/expressions/LabelResolver.java | 36 +++++++--- .../nonLocalReturnFromOuterLambda.1.kt | 45 +++++++++++++ .../nonLocalReturnFromOuterLambda.2.kt | 9 +++ .../nonLocalReturnFromOuterLambda.1.kt | 67 +++++++++++++++++++ .../nonLocalReturnFromOuterLambda.2.kt | 9 +++ .../BlackBoxInlineCodegenTestGenerated.java | 12 ++++ ...otlinAgainstInlineKotlinTestGenerated.java | 12 ++++ 8 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.2.kt 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 b96e2d8a3e7..21b1bb94a1f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.name.ClassId; +import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; @@ -44,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; +import org.jetbrains.kotlin.types.expressions.LabelResolver; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Opcodes; @@ -551,14 +553,14 @@ public class InlineCodegen extends CallGenerator { @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); + Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun); + if (label != null) { + result.add(label.asString()); } } + if (!isFunctionLiteral(descriptor)) { if (!descriptor.getName().isSpecial()) { result.add(descriptor.getName().asString()); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.java index 70a8561bf6b..60fb511a54f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.java @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.types.expressions; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import java.util.Collection; import java.util.List; +import java.util.Set; import static org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH; import static org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE; @@ -41,8 +44,8 @@ public class LabelResolver { private LabelResolver() {} @NotNull - private List getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) { - List elements = Lists.newArrayList(); + private Set getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) { + Set elements = Sets.newLinkedHashSet(); PsiElement parent = labelExpression.getParent(); while (parent != null) { Name name = getLabelNameIfAny(parent); @@ -55,24 +58,35 @@ public class LabelResolver { } @Nullable - private Name getLabelNameIfAny(@NotNull PsiElement element) { + public Name getLabelNameIfAny(@NotNull PsiElement element) { if (element instanceof JetLabeledExpression) { - Name labelName = ((JetLabeledExpression) element).getLabelNameAsName(); - if (labelName != null) { - return labelName; - } + return ((JetLabeledExpression) element).getLabelNameAsName(); } + + if (element instanceof JetFunctionLiteral) { + return getLabelNameIfAny(element.getParent()); + } + if (element instanceof JetFunctionLiteralExpression) { - return getCallerName((JetFunctionLiteralExpression) element); + return getLabelForFunctionalExpression((JetExpression) element); } + if (element instanceof JetNamedFunction) { Name name = ((JetNamedFunction) element).getNameAsName(); if (name != null) return name; - return getCallerName((JetNamedFunction) element); + return getLabelForFunctionalExpression((JetExpression) element); } + return null; } + private Name getLabelForFunctionalExpression(@NotNull JetExpression element) { + if (element.getParent() instanceof JetLabeledExpression) { + return getLabelNameIfAny(element.getParent()); + } + return getCallerName(element); + } + @NotNull private JetExpression getExpressionUnderLabel(@NotNull JetExpression labeledExpression) { JetExpression expression = JetPsiUtil.safeDeparenthesize(labeledExpression, true); @@ -160,14 +174,14 @@ public class LabelResolver { @NotNull JetSimpleNameExpression labelExpression, @NotNull BindingTrace trace ) { - List list = getElementsByLabelName(labelName, labelExpression); + Set list = getElementsByLabelName(labelName, labelExpression); if (list.isEmpty()) return null; if (list.size() > 1) { trace.report(LABEL_NAME_CLASH.on(labelExpression)); } - JetElement result = list.get(0); + JetElement result = list.iterator().next(); trace.record(LABEL_TARGET, labelExpression, result); return result; } diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt new file mode 100644 index 00000000000..b8cca4d36bd --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt @@ -0,0 +1,45 @@ +//NO_CHECK_LAMBDA_INLINING + +import test.* + +fun test1() : String { + return a { + test { + return@a "OK" + } + } +} + +fun test2() : String { + return test z@ { + return@z "OK" + } +} + +fun test3() : String { + return test { + return@test "OK" + } +} + +fun test4() : String { + return a z@ { + test { + return@z "OK" + } + } +} + + + +fun box() : String { + if (test1() != "OK") return "fail 1: ${test1()}" + + if (test2() != "OK") return "fail 2: ${test2()}" + + if (test3() != "OK") return "fail 3: ${test3()}" + + if (test4() != "OK") return "fail 4: ${test4()}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.2.kt new file mode 100644 index 00000000000..e2a98ac6ed9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.2.kt @@ -0,0 +1,9 @@ +package test + +fun a(b: () -> String) : String { + return b() +} + +inline fun test(l: () -> String): String { + return l() +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt new file mode 100644 index 00000000000..ef2a0934107 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt @@ -0,0 +1,67 @@ +//NO_CHECK_LAMBDA_INLINING + +import test.* + +fun test1(): String { + return a { + try { + test { + return@a "OK" + } + } + finally { + + } + } +} + +fun test2(): String { + + return test z@ { + try { + return@z "OK" + } + finally { + + } + } + +} + +fun test3(): String { + return test { + try { + return@test "OK" + } + finally { + + } + } +} + + +fun test4(): String { + return a z@ { + try { + test { + return@z "OK" + } + } + finally { + + } + } +} + + +fun box(): String { + if (test1() != "OK") return "fail 1: ${test1()}" + + if (test2() != "OK") return "fail 2: ${test2()}" + + if (test3() != "OK") return "fail 3: ${test3()}" + + if (test4() != "OK") return "fail 4: ${test4()}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.2.kt new file mode 100644 index 00000000000..e2a98ac6ed9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.2.kt @@ -0,0 +1,9 @@ +package test + +fun a(b: () -> String) : String { + return b() +} + +inline fun test(l: () -> String): String { + return l() +} \ 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 289388f1d0a..f31c55effcc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -487,6 +487,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("nonLocalReturnFromOuterLambda.1.kt") + public void testNonLocalReturnFromOuterLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("propertyAccessors.1.kt") public void testPropertyAccessors() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/propertyAccessors.1.kt"); @@ -552,6 +558,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("nonLocalReturnFromOuterLambda.1.kt") + public void testNonLocalReturnFromOuterLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index e0c7b10ca43..a745ddc9644 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -487,6 +487,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("nonLocalReturnFromOuterLambda.1.kt") + public void testNonLocalReturnFromOuterLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/nonLocalReturnFromOuterLambda.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("propertyAccessors.1.kt") public void testPropertyAccessors() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/propertyAccessors.1.kt"); @@ -552,6 +558,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("nonLocalReturnFromOuterLambda.1.kt") + public void testNonLocalReturnFromOuterLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)