KT-3919 Automatic labeling of lambdas by receiving functions
#KT-3919 Fixed
This commit is contained in:
+46
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.descriptors.impl.*;
|
|||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
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.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
@@ -99,6 +100,11 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
|
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
|
||||||
if (bodyExpression == null) return null;
|
if (bodyExpression == null) return null;
|
||||||
|
|
||||||
|
Name callerName = getCallerName(expression);
|
||||||
|
if (callerName != null) {
|
||||||
|
context.labelResolver.enterLabeledElement(new LabelName(callerName.asString()), expression);
|
||||||
|
}
|
||||||
|
|
||||||
JetType expectedType = context.expectedType;
|
JetType expectedType = context.expectedType;
|
||||||
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
|
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
|
||||||
expectedType);
|
expectedType);
|
||||||
@@ -115,9 +121,49 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
// all checks were done before
|
// all checks were done before
|
||||||
return JetTypeInfo.create(resultType, context.dataFlowInfo);
|
return JetTypeInfo.create(resultType, context.dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callerName != null) {
|
||||||
|
context.labelResolver.exitLabeledElement(expression);
|
||||||
|
}
|
||||||
|
|
||||||
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
|
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
|
@NotNull
|
||||||
private static AnonymousFunctionDescriptor createFunctionDescriptor(
|
private static AnonymousFunctionDescriptor createFunctionDescriptor(
|
||||||
@NotNull JetFunctionLiteralExpression expression,
|
@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);
|
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")
|
@TestMetadata("ForbiddenNonLocalReturnNoType.kt")
|
||||||
public void testForbiddenNonLocalReturnNoType() throws Exception {
|
public void testForbiddenNonLocalReturnNoType() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/functionLiterals/return/ForbiddenNonLocalReturnNoType.kt");
|
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");
|
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")
|
@TestMetadata("recursiveClosure.kt")
|
||||||
public void testRecursiveClosure() throws Exception {
|
public void testRecursiveClosure() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/closures/recursiveClosure.kt");
|
doTest("compiler/testData/codegen/box/closures/recursiveClosure.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user