From c9b468581ad04d48c7bb1fca556d37f00cdff64a Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Fri, 7 Apr 2017 16:37:35 +0300 Subject: [PATCH] Fix type checking of local return inside return expression #KT-16426 Fixed --- .../expressions/FunctionsTypingVisitor.kt | 56 +++++++++++-------- .../localReturnInsideProperty.kt | 13 +++++ .../localReturnInsidePropertyAccessor.kt | 20 +++++++ .../localReturnInsidePropertyAccessor.txt | 10 ++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++ .../checkers/DiagnosticsTestGenerated.java | 6 ++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../LightAnalysisModeTestGenerated.java | 6 ++ .../semantics/JsCodegenBoxTestGenerated.java | 6 ++ 9 files changed, 106 insertions(+), 23 deletions(-) create mode 100644 compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt create mode 100644 compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt create mode 100644 compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index f1d0216c2bc..6fb37bf6873 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -268,8 +268,8 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre val result = Lists.newArrayList() val bodyExpression = functionLiteral.bodyExpression bodyExpression?.accept(object : KtTreeVisitor>() { - override fun visitReturnExpression(expression: KtReturnExpression, data: MutableList): Void? { - data.add(expression) + override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: MutableList): Void? { + insideActualFunction.add(expression) return null } }, result) @@ -285,27 +285,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre if ((function !is KtNamedFunction || function.typeReference != null) && (function !is KtPropertyAccessor || function.returnTypeReference == null)) return - val bodyExpression = function.bodyExpression ?: return - val returns = ArrayList() - - // data == false means, that we inside other function, so ours return should be with label - bodyExpression.accept(object : KtTreeVisitor() { - override fun visitReturnExpression(expression: KtReturnExpression, data: Boolean): Void? { - val label = expression.getTargetLabel() - if ((label != null && trace[BindingContext.LABEL_TARGET, label] == function) - || (label == null && data) - ) { - returns.add(expression) - } - return super.visitReturnExpression(expression, data) - } - - override fun visitNamedFunction(function: KtNamedFunction, data: Boolean): Void? { - return super.visitNamedFunction(function, false) - } - }, true) - - for (returnForCheck in returns) { + for (returnForCheck in collectReturns(function, trace)) { val expression = returnForCheck.returnedExpression if (expression == null) { if (!actualReturnType.isUnit()) { @@ -320,4 +300,34 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre } } } + + private fun collectReturns(function: KtDeclarationWithBody, trace: BindingTrace): List { + val bodyExpression = function.bodyExpression ?: return emptyList() + val returns = ArrayList() + + bodyExpression.accept(object : KtTreeVisitor() { + override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: Boolean): Void? { + val labelTarget = expression.getTargetLabel()?.let { trace[BindingContext.LABEL_TARGET, it] } + if (labelTarget == function || (labelTarget == null && insideActualFunction)) { + returns.add(expression) + } + + return super.visitReturnExpression(expression, insideActualFunction) + } + + override fun visitNamedFunction(function: KtNamedFunction, data: Boolean): Void? { + return super.visitNamedFunction(function, false) + } + + override fun visitPropertyAccessor(accessor: KtPropertyAccessor, data: Boolean): Void? { + return super.visitPropertyAccessor(accessor, false) + } + + override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer, data: Boolean): Void? { + return super.visitAnonymousInitializer(initializer, false) + } + }, true) + + return returns + } } diff --git a/compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt b/compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt new file mode 100644 index 00000000000..7808b367f3e --- /dev/null +++ b/compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt @@ -0,0 +1,13 @@ +interface ClassData + +fun f() = object : ClassData { + val someInt: Int + get() { + return 5 + } +} + +fun box(): String{ + f() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt b/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt new file mode 100644 index 00000000000..31f6a82060d --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt @@ -0,0 +1,20 @@ +interface ClassData + +fun f() = object : ClassData { + val someInt: Int + get() { + return 5 + } +} + +fun g() = object : ClassData { + init { + if (true) { + return 0 + } + } + + fun some(): Int { + return 6 + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.txt b/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.txt new file mode 100644 index 00000000000..85a7cedbfda --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.txt @@ -0,0 +1,10 @@ +package + +public fun f(): ClassData +public fun g(): ClassData + +public interface ClassData { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index bc788706ef4..46689736e7a 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -11093,6 +11093,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("localReturnInsideProperty.kt") + public void testLocalReturnInsideProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt"); + doTest(fileName); + } + @TestMetadata("use.kt") public void testUse() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e0241fcbbe4..35ff0b97726 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4534,6 +4534,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("localReturnInsidePropertyAccessor.kt") + public void testLocalReturnInsidePropertyAccessor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt"); + doTest(fileName); + } + @TestMetadata("specialConstructsAndPlatformTypes.kt") public void testSpecialConstructsAndPlatformTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 944bbd21db0..04b8e31223b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11093,6 +11093,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("localReturnInsideProperty.kt") + public void testLocalReturnInsideProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt"); + doTest(fileName); + } + @TestMetadata("use.kt") public void testUse() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 70bb224b775..10592f8c146 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11093,6 +11093,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("localReturnInsideProperty.kt") + public void testLocalReturnInsideProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt"); + doTest(fileName); + } + @TestMetadata("use.kt") public void testUse() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index ed65b8c0df8..90d16c4fc43 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -12505,6 +12505,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("localReturnInsideProperty.kt") + public void testLocalReturnInsideProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt"); + doTest(fileName); + } + @TestMetadata("use.kt") public void testUse() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");