diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index c8e5854075b..623d330aab2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -72,9 +72,6 @@ public class JetControlFlowProcessor { public Pseudocode generatePseudocode(@NotNull JetElement subroutine) { Pseudocode pseudocode = generate(subroutine); ((PseudocodeImpl) pseudocode).postProcess(); - for (LocalFunctionDeclarationInstruction localFunctionDeclarationInstruction : pseudocode.getLocalDeclarations()) { - ((PseudocodeImpl) localFunctionDeclarationInstruction.getBody()).postProcess(); - } return pseudocode; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java index d75761cb4b0..248b5c06c5b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java @@ -114,7 +114,7 @@ public class PseudocodeImpl implements Pseudocode { @NotNull private static Set getLocalDeclarations(@NotNull Pseudocode pseudocode) { Set localDeclarations = Sets.newLinkedHashSet(); - for (Instruction instruction : pseudocode.getInstructions()) { + for (Instruction instruction : ((PseudocodeImpl)pseudocode).mutableInstructionList) { if (instruction instanceof LocalFunctionDeclarationInstruction) { localDeclarations.add((LocalFunctionDeclarationInstruction) instruction); localDeclarations.addAll(getLocalDeclarations(((LocalFunctionDeclarationInstruction)instruction).getBody())); @@ -263,9 +263,23 @@ public class PseudocodeImpl implements Pseudocode { postPrecessed = true; errorInstruction.setSink(getSinkInstruction()); exitInstruction.setSink(getSinkInstruction()); - for (int i = 0, instructionsSize = mutableInstructionList.size(); i < instructionsSize; i++) { - processInstruction(mutableInstructionList.get(i), i); + int index = 0; + for (Instruction instruction : mutableInstructionList) { + //recursively invokes 'postProcess' for local declarations + processInstruction(instruction, index); + index++; } + if (getParent() != null) return; + + // Collecting reachable instructions should be done after processing all instructions + // (including instructions in local declarations) to avoid being in incomplete state. + collectAndCacheReachableInstructions(); + for (LocalFunctionDeclarationInstruction localFunctionDeclarationInstruction : getLocalDeclarations()) { + ((PseudocodeImpl) localFunctionDeclarationInstruction.getBody()).collectAndCacheReachableInstructions(); + } + } + + private void collectAndCacheReachableInstructions() { Set reachableInstructions = collectReachableInstructions(); for (Instruction instruction : mutableInstructionList) { if (reachableInstructions.contains(instruction)) { diff --git a/compiler/testData/cfg/bugs/jumpToOuterScope.instructions b/compiler/testData/cfg/bugs/jumpToOuterScope.instructions new file mode 100644 index 00000000000..6d39db0a067 --- /dev/null +++ b/compiler/testData/cfg/bugs/jumpToOuterScope.instructions @@ -0,0 +1,54 @@ +== foo == +fun foo(c: Collection) { + for (e in c) { + { + break + } + } +} +--------------------- +L0: + 1 + v(c: Collection) + w(c) + 2 mark({ for (e in c) { { break } } }) + 3 mark(for (e in c) { { break } }) + r(c) + v(e) +L3: + jmp?(L2) NEXT:[read (Unit), w(e)] +L4 [loop entry point]: +L5 [body entry point]: + w(e) PREV:[jmp?(L2), jmp?(L4 [loop entry point])] + 4 mark({ { break } }) + mark({ break }) + jmp?(L6) NEXT:[r({ break }), d({ break })] + d({ break }) NEXT:[] +L6: + r({ break }) PREV:[jmp?(L6)] + 3 jmp?(L4 [loop entry point]) NEXT:[w(e), read (Unit)] +L2: + read (Unit) PREV:[jmp?(L2), jmp(L2), jmp?(L4 [loop entry point])] +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, , d({ break })] +===================== +== anonymous_0 == +{ + break + } +--------------------- +L7: + 5 + 6 mark(break) + jmp(L2) NEXT:[read (Unit)] +L8: + 5 NEXT:[] PREV:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/bugs/jumpToOuterScope.kt b/compiler/testData/cfg/bugs/jumpToOuterScope.kt new file mode 100644 index 00000000000..781490c016e --- /dev/null +++ b/compiler/testData/cfg/bugs/jumpToOuterScope.kt @@ -0,0 +1,7 @@ +fun foo(c: Collection) { + for (e in c) { + { + break + } + } +} diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index 511da135d36..d509cddf1d4 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.cfg.AbstractControlFlowTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/cfg") -@InnerTestClasses({ControlFlowTestGenerated.Arrays.class, ControlFlowTestGenerated.Basic.class, ControlFlowTestGenerated.ControlStructures.class, ControlFlowTestGenerated.Conventions.class, ControlFlowTestGenerated.DeadCode.class, ControlFlowTestGenerated.Declarations.class, ControlFlowTestGenerated.Expressions.class, ControlFlowTestGenerated.TailCalls.class}) +@InnerTestClasses({ControlFlowTestGenerated.Arrays.class, ControlFlowTestGenerated.Basic.class, ControlFlowTestGenerated.Bugs.class, ControlFlowTestGenerated.ControlStructures.class, ControlFlowTestGenerated.Conventions.class, ControlFlowTestGenerated.DeadCode.class, ControlFlowTestGenerated.Declarations.class, ControlFlowTestGenerated.Expressions.class, ControlFlowTestGenerated.TailCalls.class}) public class ControlFlowTestGenerated extends AbstractControlFlowTest { public void testAllFilesPresentInCfg() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg"), Pattern.compile("^(.+)\\.kt$"), true); @@ -93,6 +93,19 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { } + @TestMetadata("compiler/testData/cfg/bugs") + public static class Bugs extends AbstractControlFlowTest { + public void testAllFilesPresentInBugs() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg/bugs"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("jumpToOuterScope.kt") + public void testJumpToOuterScope() throws Exception { + doTest("compiler/testData/cfg/bugs/jumpToOuterScope.kt"); + } + + } + @TestMetadata("compiler/testData/cfg/controlStructures") public static class ControlStructures extends AbstractControlFlowTest { public void testAllFilesPresentInControlStructures() throws Exception { @@ -416,6 +429,7 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { suite.addTestSuite(ControlFlowTestGenerated.class); suite.addTestSuite(Arrays.class); suite.addTestSuite(Basic.class); + suite.addTestSuite(Bugs.class); suite.addTestSuite(ControlStructures.class); suite.addTestSuite(Conventions.class); suite.addTestSuite(DeadCode.class);