KT-3919 Automatic labeling of lambdas by receiving functions

#KT-3919 Fixed
This commit is contained in:
Andrey Breslav
2013-08-22 14:27:01 +04:00
parent 07a8dff5f4
commit 55eb994502
5 changed files with 98 additions and 0 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.descriptors.impl.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
import org.jetbrains.jet.lang.resolve.name.LabelName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.*;
@@ -99,6 +100,11 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
if (bodyExpression == null) return null;
Name callerName = getCallerName(expression);
if (callerName != null) {
context.labelResolver.enterLabeledElement(new LabelName(callerName.asString()), expression);
}
JetType expectedType = context.expectedType;
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
expectedType);
@@ -115,9 +121,49 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
// all checks were done before
return JetTypeInfo.create(resultType, context.dataFlowInfo);
}
if (callerName != null) {
context.labelResolver.exitLabeledElement(expression);
}
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
}
@Nullable
private static Name getCallerName(@NotNull JetFunctionLiteralExpression expression) {
JetCallExpression callExpression = getContainingCallExpression(expression);
if (callExpression == null) return null;
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
return nameExpression.getReferencedNameAsName();
}
return null;
}
@Nullable
private static JetCallExpression getContainingCallExpression(JetFunctionLiteralExpression expression) {
PsiElement parent = expression.getParent();
if (parent instanceof JetCallExpression) {
// f {}
return (JetCallExpression) parent;
}
if (parent instanceof JetValueArgument) {
// f ({}) or f(p = {})
JetValueArgument argument = (JetValueArgument) parent;
PsiElement argList = argument.getParent();
if (argList == null) return null;
PsiElement call = argList.getParent();
if (call instanceof JetCallExpression) {
return (JetCallExpression) call;
}
}
return null;
}
@NotNull
private static AnonymousFunctionDescriptor createFunctionDescriptor(
@NotNull JetFunctionLiteralExpression expression,
@@ -0,0 +1,19 @@
fun box(): String {
val a = 1
val explicitlyReturned = run1 {(): String ->
if (a > 0)
return@run1 "OK"
else "Fail 1"
}
if (explicitlyReturned != "OK") return explicitlyReturned
val implicitlyReturned = run1 {(): String ->
if (a < 0)
return@run1 "Fail 2"
else "OK"
}
if (implicitlyReturned != "OK") return implicitlyReturned
return "OK"
}
fun run1<T>(f: () -> T): T { return f() }
@@ -0,0 +1,23 @@
fun f() {
foo {(): Int ->
return@foo 1
}
foo({(): Int ->
return@foo 1
}
)
foo(a = {(): Int ->
return@foo 1
})
foo {(): Int ->
foo {
(): Int ->
return@foo 1
}
return@foo 1
}
}
fun foo(<!UNUSED_PARAMETER!>a<!>: Any) {}
@@ -2432,6 +2432,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/functionLiterals/return"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("AutoLabels.kt")
public void testAutoLabels() throws Exception {
doTest("compiler/testData/diagnostics/tests/functionLiterals/return/AutoLabels.kt");
}
@TestMetadata("ForbiddenNonLocalReturnNoType.kt")
public void testForbiddenNonLocalReturnNoType() throws Exception {
doTest("compiler/testData/diagnostics/tests/functionLiterals/return/ForbiddenNonLocalReturnNoType.kt");
@@ -1204,6 +1204,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/closures/localReturn.kt");
}
@TestMetadata("localReturnWithAutolabel.kt")
public void testLocalReturnWithAutolabel() throws Exception {
doTest("compiler/testData/codegen/box/closures/localReturnWithAutolabel.kt");
}
@TestMetadata("recursiveClosure.kt")
public void testRecursiveClosure() throws Exception {
doTest("compiler/testData/codegen/box/closures/recursiveClosure.kt");