From 26a2319d7c5e50f860a0463d0f91fa1e7afeb821 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 27 Jan 2016 13:43:42 +0300 Subject: [PATCH] ControlFlowBuilder.getExitPoint() now can return null if nothing was found #KT-10823 Fixed Also #EA-73355 Fixed --- .../kotlin/cfg/ControlFlowBuilder.kt | 2 +- .../kotlin/cfg/ControlFlowBuilderAdapter.kt | 2 +- .../kotlin/cfg/ControlFlowProcessor.kt | 2 +- .../ControlFlowInstructionsGenerator.kt | 12 +++---- .../tests/controlFlowAnalysis/kt10823.kt | 33 +++++++++++++++++++ .../tests/controlFlowAnalysis/kt10823.txt | 6 ++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++ 7 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilder.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilder.kt index b40e1d72ecc..a2a28912e52 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilder.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilder.kt @@ -39,7 +39,7 @@ interface ControlFlowBuilder { fun exitLexicalScope(element: KtElement) - fun getExitPoint(labelElement: KtElement): Label + fun getExitPoint(labelElement: KtElement): Label? fun getConditionEntryPoint(labelElement: KtElement): Label // Declarations diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilderAdapter.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilderAdapter.kt index f73273e1a93..0f2c4ba3722 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilderAdapter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowBuilderAdapter.kt @@ -123,7 +123,7 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder { delegateBuilder.throwException(throwExpression, thrownValue) } - override fun getExitPoint(labelElement: KtElement): Label { + override fun getExitPoint(labelElement: KtElement): Label? { return delegateBuilder.getExitPoint(labelElement) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt index 377e170c11f..674715e4eb7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt @@ -785,7 +785,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) { val loop = getCorrespondingLoop(expression) if (loop != null) { checkJumpDoesNotCrossFunctionBoundary(expression, loop) - builder.jump(builder.getExitPoint(loop), expression) + builder.getExitPoint(loop)?.let { builder.jump(it, expression) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt index d5c5cae8bbb..19589040c3e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt @@ -171,9 +171,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() { return (blockInfo as LoopInfo).conditionEntryPoint } - override fun getExitPoint(labelElement: KtElement): Label { - val blockInfo = elementToBlockInfo[labelElement] ?: error(labelElement.text) - return blockInfo.exitPoint + override fun getExitPoint(labelElement: KtElement): Label? { + // It's quite possible to have null here, e.g. for non-local returns (see KT-10823) + return elementToBlockInfo[labelElement]?.exitPoint } private val currentScope: LexicalScope @@ -217,7 +217,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() { } override fun exitSubroutine(subroutine: KtElement): Pseudocode { - bindLabel(getExitPoint(subroutine)) + getExitPoint(subroutine)?.let { bindLabel(it) } pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false)) bindLabel(error) pseudocode.addErrorInstruction(SubroutineExitInstruction(subroutine, currentScope, true)) @@ -245,13 +245,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() { } override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) { - val exitPoint = getExitPoint(subroutine) + val exitPoint = getExitPoint(subroutine) ?: return handleJumpInsideTryFinally(exitPoint) add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue)) } override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) { - val exitPoint = getExitPoint(subroutine) + val exitPoint = getExitPoint(subroutine) ?: return handleJumpInsideTryFinally(exitPoint) add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint)) } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.kt new file mode 100644 index 00000000000..d4a1585ebe0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.kt @@ -0,0 +1,33 @@ +fun find2(): Any? { + fun visit(element: Any) { + return@find2 element + } + return null +} + +// For find(): AssertionError at ControlFlowInstructionsGeneratorWorker.getExitPoint() + +fun find(): Any? { + object : Any() { + fun visit(element: Any) { + return@find element + } + } + return null +} + +fun find4(): Any? { + inline fun visit(element: Any) { + return@find4 element + } + return null +} + +fun find3(): Any? { + object : Any() { + inline fun visit(element: Any) { + return@find3 element + } + } + return null +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.txt new file mode 100644 index 00000000000..f307c55c8b5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.txt @@ -0,0 +1,6 @@ +package + +public fun find(): kotlin.Any? +public fun find2(): kotlin.Any? +public fun find3(): kotlin.Any? +public fun find4(): kotlin.Any? diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5ba4d0930a7..e43416095b1 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2889,6 +2889,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt10823.kt") + public void testKt10823() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10823.kt"); + doTest(fileName); + } + @TestMetadata("kt1156.kt") public void testKt1156() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1156.kt");