From 8e278778170f95ddb18f28530b4d95879bfd0324 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 29 Nov 2013 19:53:18 +0400 Subject: [PATCH] check definite return in local functions --- .../lang/cfg/JetFlowInformationProvider.java | 37 ++++++++++++++++--- .../codegen/box/extensionFunctions/kt4118.kt | 6 +-- .../testData/codegen/box/functions/kt1038.kt | 2 +- .../ReturnFromFunctionInObject.kt | 13 +++++++ .../kt3444_ReturnFromLocalFunctions.kt | 17 +++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 32 +++++++++++++++- 6 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/ReturnFromFunctionInObject.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt3444_ReturnFromLocalFunctions.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index e781b0b2712..0381e3d7140 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -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; diff --git a/compiler/testData/codegen/box/extensionFunctions/kt4118.kt b/compiler/testData/codegen/box/extensionFunctions/kt4118.kt index e7293b8ca3a..2d9d5b27d8d 100644 --- a/compiler/testData/codegen/box/extensionFunctions/kt4118.kt +++ b/compiler/testData/codegen/box/extensionFunctions/kt4118.kt @@ -12,7 +12,7 @@ fun Array.test1Nested(): Array { fun Array.test2() : Array { class Z2() { fun run(): Array { - this@test2 + return this@test2 } } return Z2().run() @@ -34,7 +34,7 @@ fun Array.test2Nested() : Array { fun Array.test3(): Array { fun local(): Array { - this@test3 + return this@test3 } return local() } @@ -42,7 +42,7 @@ fun Array.test3(): Array { fun Array.test3Nested(): Array { fun local(): Array { fun local2(): Array { - this@test3Nested + return this@test3Nested } return local2() } diff --git a/compiler/testData/codegen/box/functions/kt1038.kt b/compiler/testData/codegen/box/functions/kt1038.kt index d8c46c35b15..e3681113efe 100644 --- a/compiler/testData/codegen/box/functions/kt1038.kt +++ b/compiler/testData/codegen/box/functions/kt1038.kt @@ -39,7 +39,7 @@ fun Iterable.where(predicate : (TItem)->Boolean) : Iterable if (predicate(next)) return next } - null + return null } { yielder() } } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/ReturnFromFunctionInObject.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/ReturnFromFunctionInObject.kt new file mode 100644 index 00000000000..04f9bff6ade --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/ReturnFromFunctionInObject.kt @@ -0,0 +1,13 @@ +trait X { + fun f(): Boolean +} + +val m = object : X { + override fun f(): Boolean { + } + + fun foo() { + fun local(): Int { + } + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt3444_ReturnFromLocalFunctions.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt3444_ReturnFromLocalFunctions.kt new file mode 100644 index 00000000000..5282b52f47d --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt3444_ReturnFromLocalFunctions.kt @@ -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 { + } + + return local() +} + +fun main(args: Array) { + box() +} + diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index f3c61b45489..c742a03e152 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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());