check definite return in local functions

This commit is contained in:
Svetlana Isakova
2013-11-29 19:53:18 +04:00
parent d27c8b7d61
commit 8e27877817
6 changed files with 96 additions and 11 deletions
@@ -49,6 +49,7 @@ import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.FORW
import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
public class JetFlowInformationProvider {
@@ -58,13 +59,21 @@ public class JetFlowInformationProvider {
private final BindingTrace trace;
private PseudocodeVariablesData pseudocodeVariablesData;
public JetFlowInformationProvider(
private JetFlowInformationProvider(
@NotNull JetElement declaration,
@NotNull BindingTrace trace) {
@NotNull BindingTrace trace,
@NotNull Pseudocode pseudocode
) {
subroutine = declaration;
this.trace = trace;
pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration);
this.pseudocode = pseudocode;
}
public JetFlowInformationProvider(
@NotNull JetElement declaration,
@NotNull BindingTrace trace
) {
this(declaration, trace, new JetControlFlowProcessor(trace).generatePseudocode(declaration));
}
public PseudocodeVariablesData getPseudocodeVariablesData() {
@@ -84,9 +93,10 @@ public class JetFlowInformationProvider {
recordInitializedVariables();
}
if (isLocalObject) return;
checkDefiniteReturn(expectedReturnType);
checkDefiniteReturnInLocalFunctions();
if (isLocalObject) return;
if (!isPropertyAccessor) {
// Property accessor is checked through initialization of a class/object or package properties (at 'checkDeclarationContainer')
@@ -158,6 +168,21 @@ public class JetFlowInformationProvider {
}
}
private void checkDefiniteReturnInLocalFunctions() {
for (LocalFunctionDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
JetElement element = localDeclarationInstruction.getElement();
if (element instanceof JetNamedFunction) {
JetNamedFunction localFunction = (JetNamedFunction) element;
SimpleFunctionDescriptor functionDescriptor = trace.getBindingContext().get(BindingContext.FUNCTION, localFunction);
JetType expectedType = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
JetFlowInformationProvider providerForLocalDeclaration =
new JetFlowInformationProvider(localFunction, trace, localDeclarationInstruction.getBody());
providerForLocalDeclaration.checkDefiniteReturn(expectedType != null ? expectedType : NO_EXPECTED_TYPE);
}
}
}
public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) {
assert subroutine instanceof JetDeclarationWithBody;
JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine;
@@ -12,7 +12,7 @@ fun Array<String>.test1Nested(): Array<String> {
fun Array<String>.test2() : Array<String> {
class Z2() {
fun run(): Array<String> {
this@test2
return this@test2
}
}
return Z2().run()
@@ -34,7 +34,7 @@ fun Array<String>.test2Nested() : Array<String> {
fun Array<String>.test3(): Array<String> {
fun local(): Array<String> {
this@test3
return this@test3
}
return local()
}
@@ -42,7 +42,7 @@ fun Array<String>.test3(): Array<String> {
fun Array<String>.test3Nested(): Array<String> {
fun local(): Array<String> {
fun local2(): Array<String> {
this@test3Nested
return this@test3Nested
}
return local2()
}
@@ -39,7 +39,7 @@ fun<TItem> Iterable<TItem>.where(predicate : (TItem)->Boolean) : Iterable<TItem>
if (predicate(next))
return next
}
null
return null
}
{ yielder() }
}
@@ -0,0 +1,13 @@
trait X {
fun f(): Boolean
}
val m = object : X {
override fun f(): Boolean {
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun foo() {
fun local(): Int {
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
}
}
@@ -0,0 +1,17 @@
package f
//KT-3444 Front-end doesn't check if local function or function of anonymous class returns value
fun box(): Int {
fun local(): Int {
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
return local()
}
fun main(args: Array<String>) {
box()
}
@@ -1392,6 +1392,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
}
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
@InnerTestClasses({ControlFlowAnalysis.DefiniteReturn.class})
public static class ControlFlowAnalysis extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInControlFlowAnalysis() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/controlFlowAnalysis"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -1572,6 +1573,35 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt");
}
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn")
public static class DefiniteReturn extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInDefiniteReturn() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("kt3444_ReturnFromLocalFunctions.kt")
public void testKt3444_ReturnFromLocalFunctions() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt3444_ReturnFromLocalFunctions.kt");
}
@TestMetadata("kt4034.kt")
public void testKt4034() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
}
@TestMetadata("ReturnFromFunctionInObject.kt")
public void testReturnFromFunctionInObject() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/ReturnFromFunctionInObject.kt");
}
}
public static Test innerSuite() {
TestSuite suite = new TestSuite("ControlFlowAnalysis");
suite.addTestSuite(ControlFlowAnalysis.class);
suite.addTestSuite(DefiniteReturn.class);
return suite;
}
}
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")
@@ -6619,7 +6649,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
suite.addTest(Cast.innerSuite());
suite.addTestSuite(CheckArguments.class);
suite.addTestSuite(ClassObjects.class);
suite.addTestSuite(ControlFlowAnalysis.class);
suite.addTest(ControlFlowAnalysis.innerSuite());
suite.addTestSuite(ControlStructures.class);
suite.addTestSuite(DataClasses.class);
suite.addTest(DataFlow.innerSuite());