From 7d46ff951e2262d3ccf4f16df741dee9ff2d517c Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 5 Mar 2014 19:38:50 +0400 Subject: [PATCH] Jump after 'for' cycle to loop parameter change. Not to the cycle body. --- .../jet/lang/cfg/JetControlFlowProcessor.java | 53 +++++++++++++------ .../varInitializationInIfInCycle.instructions | 26 ++++----- .../lexicalScopes/forScope.instructions | 8 +-- .../controlStructures/Finally.instructions | 30 +++++------ .../cfg/controlStructures/For.instructions | 8 +-- .../varInitializationInIfInCycle.kt | 15 ++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ 7 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt 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 eba98ed267c..c8e5854075b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; -import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; import org.jetbrains.jet.lang.descriptors.*; @@ -608,14 +607,7 @@ public class JetControlFlowProcessor { if (loopRange != null) { generateInstructions(loopRange, NOT_IN_CONDITION); } - JetParameter loopParameter = expression.getLoopParameter(); - if (loopParameter != null) { - generateInstructions(loopParameter, context); - } - else { - JetMultiDeclaration multiParameter = expression.getMultiParameter(); - generateInstructions(multiParameter, context); - } + declareLoopParameter(expression); // TODO : primitive cases Label loopExitPoint = builder.createUnboundLabel(); @@ -627,6 +619,8 @@ public class JetControlFlowProcessor { LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); builder.bindLabel(loopInfo.getBodyEntryPoint()); + writeLoopParameterAssignment(expression); + JetExpression body = expression.getBody(); if (body != null) { generateInstructions(body, NOT_IN_CONDITION); @@ -638,6 +632,30 @@ public class JetControlFlowProcessor { builder.exitLexicalScope(expression); } + private void declareLoopParameter(JetForExpression expression) { + JetParameter loopParameter = expression.getLoopParameter(); + JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); + if (loopParameter != null) { + builder.declareParameter(loopParameter); + } + else if (multiDeclaration != null) { + visitMultiDeclaration(multiDeclaration, false); + } + } + + private void writeLoopParameterAssignment(JetForExpression expression) { + JetParameter loopParameter = expression.getLoopParameter(); + JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); + if (loopParameter != null) { + builder.write(loopParameter, loopParameter); + } + else if (multiDeclaration != null) { + for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) { + builder.write(entry, entry); + } + } + } + @Override public void visitBreakExpressionVoid(@NotNull JetBreakExpression expression, CFPContext context) { JetElement loop = getCorrespondingLoop(expression); @@ -832,18 +850,21 @@ public class JetControlFlowProcessor { @Override public void visitMultiDeclarationVoid(@NotNull JetMultiDeclaration declaration, CFPContext context) { - JetExpression initializer = declaration.getInitializer(); - if (initializer != null) { - generateInstructions(initializer, NOT_IN_CONDITION); - } - List entries = declaration.getEntries(); - for (JetMultiDeclarationEntry entry : entries) { + visitMultiDeclaration(declaration, true); + } + + private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { + generateInstructions(declaration.getInitializer(), NOT_IN_CONDITION); + + for (JetMultiDeclarationEntry entry : declaration.getEntries()) { builder.declareVariable(entry); ResolvedCall resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); if (resolvedCall != null) { builder.call(entry, resolvedCall); } - builder.write(entry, entry); + if (generateWriteForEntries) { + builder.write(entry, entry); + } } } diff --git a/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions b/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions index 8e155925d3a..44cb3f1bd24 100644 --- a/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions +++ b/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions @@ -21,14 +21,14 @@ L0: 3 mark(for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) USE: in: {numbers=READ} out: {numbers=READ} r(numbers) USE: in: {} out: {numbers=READ} v(i) INIT: in: {numbers=ID} out: {i=D, numbers=ID} - w(i) INIT: in: {i=D, numbers=ID} out: {i=ID, numbers=ID} L3: - jmp?(L2) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} USE: in: {} out: {} + jmp?(L2) INIT: in: {i=D, numbers=ID} out: {i=D, numbers=ID} L4 [loop entry point]: L5 [body entry point]: - 4 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) INIT: in: {b=ID, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} - v(val b: Boolean) - mark(if (1 < 2) { b = false } else { b = true }) + w(i) INIT: in: {i=D, numbers=ID} out: {i=ID, numbers=ID} USE: in: {} out: {} + 4 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} + v(val b: Boolean) INIT: in: {i=ID, numbers=ID} out: {b=D, i=ID, numbers=ID} + mark(if (1 < 2) { b = false } else { b = true }) INIT: in: {b=D, i=ID, numbers=ID} out: {b=D, i=ID, numbers=ID} mark(1 < 2) r(1) r(2) @@ -36,20 +36,20 @@ L5 [body entry point]: jf(L6) 5 mark({ b = false }) r(false) USE: in: {b=WRITTEN_AFTER_READ} out: {b=WRITTEN_AFTER_READ} - w(b) USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} - 4 jmp(L7) USE: in: {b=READ} out: {b=READ} + w(b) INIT: in: {b=D, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} + 4 jmp(L7) INIT: in: {b=ID, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=READ} L6: - 5 mark({ b = true }) + 5 mark({ b = true }) INIT: in: {b=D, i=ID, numbers=ID} out: {b=D, i=ID, numbers=ID} r(true) USE: in: {b=WRITTEN_AFTER_READ} out: {b=WRITTEN_AFTER_READ} - w(b) USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} + w(b) INIT: in: {b=D, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} L7: - 4 mark(use(b)) USE: in: {b=READ} out: {b=READ} - r(b) USE: in: {b=WRITTEN_AFTER_READ} out: {b=READ} + 4 mark(use(b)) INIT: in: {b=ID, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=READ} + r(b) USE: in: {} out: {b=READ} call(use, use) - jmp(L4 [loop entry point]) USE: in: {b=WRITTEN_AFTER_READ} out: {b=WRITTEN_AFTER_READ} + jmp(L4 [loop entry point]) USE: in: {} out: {} - 3 jmp?(L4 [loop entry point]) L2: - read (Unit) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} + read (Unit) INIT: in: {i=D, numbers=ID} out: {i=D, numbers=ID} L1: 1 INIT: in: {numbers=ID} out: {numbers=ID} error: diff --git a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions index d78a1b3932a..792aeb3efad 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions @@ -18,18 +18,18 @@ L0: r(10) call(.., rangeTo) v(i) INIT: in: {} out: {i=D} - w(i) INIT: in: {i=D} out: {i=ID} L3: - jmp?(L2) INIT: in: {i=ID} out: {i=ID} + jmp?(L2) INIT: in: {i=D} out: {i=D} L4 [loop entry point]: L5 [body entry point]: - 4 mark({ val a = i }) + w(i) INIT: in: {i=D} out: {i=ID} + 4 mark({ val a = i }) INIT: in: {i=ID} out: {i=ID} v(val a = i) INIT: in: {i=ID} out: {a=D, i=ID} r(i) INIT: in: {a=D, i=ID} out: {a=D, i=ID} w(a) INIT: in: {a=D, i=ID} out: {a=ID, i=ID} 3 jmp?(L4 [loop entry point]) INIT: in: {i=ID} out: {i=ID} USE: in: {i=READ} out: {i=READ} L2: - read (Unit) + read (Unit) INIT: in: {i=D} out: {i=D} 2 mark("after") INIT: in: {} out: {} r("after") L1: diff --git a/compiler/testData/cfg/controlStructures/Finally.instructions b/compiler/testData/cfg/controlStructures/Finally.instructions index 2c084c57410..8521596ca16 100644 --- a/compiler/testData/cfg/controlStructures/Finally.instructions +++ b/compiler/testData/cfg/controlStructures/Finally.instructions @@ -444,12 +444,12 @@ L0: r(a) call(.., rangeTo) v(i) - w(i) L3: - jmp?(L2) NEXT:[read (Unit), mark({ try { 1 if (2 > 3) { continue @ } } finally { 2 } })] + jmp?(L2) NEXT:[read (Unit), w(i)] L4 [loop entry point]: L5 [body entry point]: - 4 mark({ try { 1 if (2 > 3) { continue @ } } finally { 2 } }) PREV:[jmp?(L2), jmp(L4 [loop entry point]), jmp?(L4 [loop entry point])] + w(i) PREV:[jmp?(L2), jmp(L4 [loop entry point]), jmp?(L4 [loop entry point])] + 4 mark({ try { 1 if (2 > 3) { continue @ } } finally { 2 } }) mark(try { 1 if (2 > 3) { continue @ } } finally { 2 }) jmp?(L6 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ 1 if (2 > 3) { continue @ } })] 5 mark({ 1 if (2 > 3) { continue @ } }) @@ -465,7 +465,7 @@ L8 [start finally]: 7 mark({ 2 }) r(2) L9 [finish finally]: - 6 jmp(L4 [loop entry point]) NEXT:[mark({ try { 1 if (2 > 3) { continue @ } } finally { 2 } })] + 6 jmp(L4 [loop entry point]) NEXT:[w(i)] - 5 jmp(L10) NEXT:[jmp(L11 [skipFinallyToErrorBlock])] PREV:[] L7: read (Unit) PREV:[jf(L7)] @@ -478,7 +478,7 @@ L6 [onExceptionToFinallyBlock]: L11 [skipFinallyToErrorBlock]: 7 mark({ 2 }) PREV:[jmp(L11 [skipFinallyToErrorBlock])] r(2) - 3 jmp?(L4 [loop entry point]) NEXT:[mark({ try { 1 if (2 > 3) { continue @ } } finally { 2 } }), read (Unit)] + 3 jmp?(L4 [loop entry point]) NEXT:[w(i), read (Unit)] L2: read (Unit) PREV:[jmp?(L2), jmp?(L4 [loop entry point])] L1: @@ -518,12 +518,12 @@ L0: r(a) call(.., rangeTo) v(i) - w(i) L4: - jmp?(L3) NEXT:[read (Unit), mark({ 1 if (2 > 3) { continue @ } })] + jmp?(L3) NEXT:[read (Unit), w(i)] L5 [loop entry point]: L6 [body entry point]: - 5 mark({ 1 if (2 > 3) { continue @ } }) PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] + w(i) PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] + 5 mark({ 1 if (2 > 3) { continue @ } }) r(1) mark(if (2 > 3) { continue @ }) mark(2 > 3) @@ -532,12 +532,12 @@ L6 [body entry point]: call(>, compareTo) jf(L7) NEXT:[read (Unit), mark({ continue @ })] 6 mark({ continue @ }) - jmp(L5 [loop entry point]) NEXT:[mark({ 1 if (2 > 3) { continue @ } })] + jmp(L5 [loop entry point]) NEXT:[w(i)] - 5 jmp(L8) NEXT:[jmp?(L5 [loop entry point])] PREV:[] L7: read (Unit) PREV:[jf(L7)] L8: - 4 jmp?(L5 [loop entry point]) NEXT:[mark({ 1 if (2 > 3) { continue @ } }), read (Unit)] + 4 jmp?(L5 [loop entry point]) NEXT:[w(i), read (Unit)] L3: read (Unit) PREV:[jmp?(L3), jmp?(L5 [loop entry point])] 3 r(5) @@ -587,12 +587,12 @@ L0: r(a) call(.., rangeTo) v(i) - w(i) L4: - jmp?(L3) NEXT:[read (Unit), mark({ 1 if (2 > 3) { continue @ } })] + jmp?(L3) NEXT:[read (Unit), w(i)] L5 [loop entry point]: L6 [body entry point]: - 5 mark({ 1 if (2 > 3) { continue @ } }) PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] + w(i) PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] + 5 mark({ 1 if (2 > 3) { continue @ } }) r(1) mark(if (2 > 3) { continue @ }) mark(2 > 3) @@ -601,12 +601,12 @@ L6 [body entry point]: call(>, compareTo) jf(L7) NEXT:[read (Unit), mark({ continue @ })] 6 mark({ continue @ }) - jmp(L5 [loop entry point]) NEXT:[mark({ 1 if (2 > 3) { continue @ } })] + jmp(L5 [loop entry point]) NEXT:[w(i)] - 5 jmp(L8) NEXT:[jmp?(L5 [loop entry point])] PREV:[] L7: read (Unit) PREV:[jf(L7)] L8: - 4 jmp?(L5 [loop entry point]) NEXT:[mark({ 1 if (2 > 3) { continue @ } }), read (Unit)] + 4 jmp?(L5 [loop entry point]) NEXT:[w(i), read (Unit)] L3: read (Unit) PREV:[jmp?(L3), jmp?(L5 [loop entry point])] 2 jmp(L9 [skipFinallyToErrorBlock]) NEXT:[mark({ 2 })] diff --git a/compiler/testData/cfg/controlStructures/For.instructions b/compiler/testData/cfg/controlStructures/For.instructions index bc0d47a75d4..fe2791f8809 100644 --- a/compiler/testData/cfg/controlStructures/For.instructions +++ b/compiler/testData/cfg/controlStructures/For.instructions @@ -14,16 +14,16 @@ L0: r(2) call(.., rangeTo) v(i) - w(i) L3: - jmp?(L2) NEXT:[read (Unit), mark({ doSmth(i) })] + jmp?(L2) NEXT:[read (Unit), w(i)] L4 [loop entry point]: L5 [body entry point]: - 4 mark({ doSmth(i) }) PREV:[jmp?(L2), jmp?(L4 [loop entry point])] + w(i) PREV:[jmp?(L2), jmp?(L4 [loop entry point])] + 4 mark({ doSmth(i) }) mark(doSmth(i)) r(i) call(doSmth, doSmth) - 3 jmp?(L4 [loop entry point]) NEXT:[mark({ doSmth(i) }), read (Unit)] + 3 jmp?(L4 [loop entry point]) NEXT:[w(i), read (Unit)] L2: read (Unit) PREV:[jmp?(L2), jmp?(L4 [loop entry point])] L1: diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt new file mode 100644 index 00000000000..5757b44bd08 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt @@ -0,0 +1,15 @@ +fun foo(numbers: Collection) { + for (i in numbers) { + val b: Boolean + if (1 < 2) { + b = false + } + else { + b = true + } + use(b) + continue + } +} + +fun use(vararg a: Any?) = a diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index c7fb0e5d6ae..0e9071a7931 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1688,6 +1688,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt"); } + @TestMetadata("varInitializationInIfInCycle.kt") + public void testVarInitializationInIfInCycle() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt"); + } + @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn") public static class DefiniteReturn extends AbstractJetDiagnosticsTest { public void testAllFilesPresentInDefiniteReturn() throws Exception {