Fix labeling processing on inlining: suport labeled literals

#KT-7273 Fixed
This commit is contained in:
Michael Bogdanov
2015-06-02 12:16:55 +03:00
parent f02f663167
commit 2377a10007
8 changed files with 186 additions and 16 deletions
@@ -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<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);
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());
@@ -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<JetElement> getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) {
List<JetElement> elements = Lists.newArrayList();
private Set<JetElement> getElementsByLabelName(@NotNull Name labelName, @NotNull JetSimpleNameExpression labelExpression) {
Set<JetElement> 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<JetElement> list = getElementsByLabelName(labelName, labelExpression);
Set<JetElement> 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;
}
@@ -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"
}
@@ -0,0 +1,9 @@
package test
fun a(b: () -> String) : String {
return b()
}
inline fun test(l: () -> String): String {
return l()
}
@@ -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"
}
@@ -0,0 +1,9 @@
package test
fun a(b: () -> String) : String {
return b()
}
inline fun test(l: () -> String): String {
return l()
}
@@ -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)
@@ -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)