Report 'break or continue outside a loop'

for break/continue outside a loop body (e.g. in loop condition)

 #KT-5724 Fixed
This commit is contained in:
Svetlana Isakova
2014-09-01 19:01:47 +04:00
parent 0b4f313b6d
commit 61dc110cc7
22 changed files with 355 additions and 275 deletions
@@ -19,19 +19,24 @@ package org.jetbrains.jet.lang.cfg;
import com.google.common.collect.Sets;
import org.jetbrains.jet.lang.psi.JetElement;
import java.util.Collections;
import java.util.Set;
public class BreakableBlockInfo extends BlockInfo {
private final JetElement element;
private final Label entryPoint;
private final Label exitPoint;
protected final Set<Label> referablePoints;
private final Set<Label> referablePoints = Sets.newHashSet();
public BreakableBlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
this.element = element;
this.entryPoint = entryPoint;
this.exitPoint = exitPoint;
referablePoints = Sets.newHashSet(entryPoint, exitPoint);
markReferablePoints(entryPoint, exitPoint);
}
protected void markReferablePoints(Label... labels) {
Collections.addAll(referablePoints, labels);
}
public JetElement getElement() {
@@ -82,11 +82,12 @@ public interface JetControlFlowBuilder {
void throwException(@NotNull JetThrowExpression throwExpression, @NotNull PseudoValue thrownValue);
// Loops
LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, @Nullable Label conditionEntryPoint);
void exitLoop(@NotNull JetExpression expression);
@NotNull
LoopInfo enterLoop(@NotNull JetLoopExpression expression);
void enterLoopBody(@NotNull JetLoopExpression expression);
void exitLoopBody(@NotNull JetLoopExpression expression);
@Nullable
JetElement getCurrentLoop();
JetLoopExpression getCurrentLoop();
// Try-Finally
void enterTryFinally(@NotNull GenerationTrigger trigger);
@@ -189,19 +189,25 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
return getDelegateBuilder().getConditionEntryPoint(labelElement);
}
@NotNull
@Override
public LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, Label conditionEntryPoint) {
return getDelegateBuilder().enterLoop(expression, loopExitPoint, conditionEntryPoint);
public LoopInfo enterLoop(@NotNull JetLoopExpression expression) {
return getDelegateBuilder().enterLoop(expression);
}
@Override
public void exitLoop(@NotNull JetExpression expression) {
getDelegateBuilder().exitLoop(expression);
public void enterLoopBody(@NotNull JetLoopExpression expression) {
getDelegateBuilder().enterLoopBody(expression);
}
@Override
public void exitLoopBody(@NotNull JetLoopExpression expression) {
getDelegateBuilder().exitLoopBody(expression);
}
@Override
@Nullable
public JetElement getCurrentLoop() {
public JetLoopExpression getCurrentLoop() {
return getDelegateBuilder().getCurrentLoop();
}
@@ -39,7 +39,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils;
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.model.*;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -801,7 +800,7 @@ public class JetControlFlowProcessor {
@Override
public void visitWhileExpression(@NotNull JetWhileExpression expression) {
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
LoopInfo loopInfo = builder.enterLoop(expression);
builder.bindLabel(loopInfo.getConditionEntryPoint());
JetExpression condition = expression.getCondition();
@@ -821,13 +820,14 @@ public class JetControlFlowProcessor {
builder.magic(condition, null, values, typePredicates, MagicKind.VALUE_CONSUMER);
}
builder.bindLabel(loopInfo.getBodyEntryPoint());
builder.enterLoopBody(expression);
JetExpression body = expression.getBody();
if (body != null) {
generateInstructions(body);
}
builder.jump(loopInfo.getEntryPoint(), expression);
builder.exitLoop(expression);
builder.exitLoopBody(expression);
builder.bindLabel(loopInfo.getExitPoint());
builder.loadUnit(expression);
}
@@ -835,20 +835,21 @@ public class JetControlFlowProcessor {
public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
builder.enterLexicalScope(expression);
mark(expression);
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
LoopInfo loopInfo = builder.enterLoop(expression);
builder.bindLabel(loopInfo.getBodyEntryPoint());
builder.enterLoopBody(expression);
JetExpression body = expression.getBody();
if (body != null) {
generateInstructions(body);
}
builder.exitLoopBody(expression);
builder.bindLabel(loopInfo.getConditionEntryPoint());
JetExpression condition = expression.getCondition();
if (condition != null) {
generateInstructions(condition);
}
builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition));
builder.exitLoop(expression);
builder.bindLabel(loopInfo.getExitPoint());
builder.loadUnit(expression);
builder.exitLexicalScope(expression);
}
@@ -864,26 +865,24 @@ public class JetControlFlowProcessor {
declareLoopParameter(expression);
// TODO : primitive cases
Label loopExitPoint = builder.createUnboundLabel("'for' loop exit point");
Label conditionEntryPoint = builder.createUnboundLabel("'for' loop condition entry point");
LoopInfo loopInfo = builder.enterLoop(expression);
builder.bindLabel(conditionEntryPoint);
builder.nondeterministicJump(loopExitPoint, expression, null);
builder.bindLabel(loopInfo.getConditionEntryPoint());
builder.nondeterministicJump(loopInfo.getExitPoint(), expression, null);
LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
builder.bindLabel(loopInfo.getBodyEntryPoint());
writeLoopParameterAssignment(expression);
mark(expression);
builder.enterLoopBody(expression);
JetExpression body = expression.getBody();
if (body != null) {
generateInstructions(body);
}
builder.jump(loopInfo.getEntryPoint(), expression);
builder.nondeterministicJump(loopInfo.getEntryPoint(), expression, null);
builder.exitLoop(expression);
builder.exitLoopBody(expression);
builder.bindLabel(loopInfo.getExitPoint());
builder.loadUnit(expression);
builder.exitLexicalScope(expression);
}
@@ -957,9 +956,10 @@ public class JetControlFlowProcessor {
}
}
@Nullable
private JetElement getCorrespondingLoop(JetExpressionWithLabel expression) {
String labelName = expression.getLabelName();
JetElement loop;
JetLoopExpression loop;
if (labelName != null) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
@@ -978,6 +978,12 @@ public class JetControlFlowProcessor {
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
}
}
if (loop != null && loop.getBody() != null
// the faster version of 'isAncestor' check:
&& !loop.getBody().getTextRange().contains(expression.getTextRange())) {
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
return null;
}
return loop;
}
@@ -16,27 +16,41 @@
package org.jetbrains.jet.lang.cfg;
import com.google.common.collect.Sets;
import org.jetbrains.jet.lang.psi.JetElement;
import java.util.Set;
import org.jetbrains.jet.lang.psi.JetLoopExpression;
public class LoopInfo extends BreakableBlockInfo {
private final Label bodyEntryPoint;
private final Label bodyExitPoint;
private final Label conditionEntryPoint;
public LoopInfo(JetElement element, Label entryPoint, Label exitPoint, Label bodyEntryPoint, Label conditionEntryPoint) {
super(element, entryPoint, exitPoint);
public LoopInfo(
JetLoopExpression loopExpression,
Label entryPoint,
Label exitPoint,
Label bodyEntryPoint,
Label bodyExitPoint,
Label conditionEntryPoint
) {
super(loopExpression, entryPoint, exitPoint);
this.bodyEntryPoint = bodyEntryPoint;
this.bodyExitPoint = bodyExitPoint;
this.conditionEntryPoint = conditionEntryPoint;
referablePoints.add(bodyEntryPoint);
referablePoints.add(conditionEntryPoint);
markReferablePoints(bodyEntryPoint, bodyExitPoint, conditionEntryPoint);
}
@Override
public JetLoopExpression getElement() {
return (JetLoopExpression) super.getElement();
}
public Label getBodyEntryPoint() {
return bodyEntryPoint;
}
public Label getBodyExitPoint() {
return bodyExitPoint;
}
public Label getConditionEntryPoint() {
return conditionEntryPoint;
}
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import com.google.common.collect.Sets;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,7 +38,7 @@ import java.util.*;
public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
private JetControlFlowBuilder builder = null;
private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>();
private final Stack<LoopInfo> loopInfo = new Stack<LoopInfo>();
private final Stack<LexicalScope> lexicalScopes = new Stack<LexicalScope>();
private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>();
private int labelCount = 0;
@@ -143,33 +142,40 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
return pseudocode.createLabel("L" + labelCount++ + " [" + name + "]");
}
@NotNull
@Override
public final LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, Label conditionEntryPoint) {
public final LoopInfo enterLoop(@NotNull JetLoopExpression expression) {
Label loopEntryLabel = createUnboundLabel("loop entry point");
bindLabel(loopEntryLabel);
LoopInfo blockInfo = new LoopInfo(
expression,
loopEntryLabel,
loopExitPoint != null ? loopExitPoint : createUnboundLabel("loop exit point"),
createUnboundLabel("loop exit point"),
createUnboundLabel("body entry point"),
conditionEntryPoint != null ? conditionEntryPoint : createUnboundLabel("condition entry point"));
loopInfo.push(blockInfo);
createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point"));
elementToBlockInfo.put(expression, blockInfo);
allBlocks.push(blockInfo);
pseudocode.recordLoopInfo(expression, blockInfo);
return blockInfo;
}
@Override
public final void exitLoop(@NotNull JetExpression expression) {
BreakableBlockInfo info = loopInfo.pop();
elementToBlockInfo.remove(expression);
allBlocks.pop();
bindLabel(info.getExitPoint());
public void enterLoopBody(@NotNull JetLoopExpression expression) {
LoopInfo info = (LoopInfo) elementToBlockInfo.get(expression);
bindLabel(info.getBodyEntryPoint());
loopInfo.push(info);
allBlocks.push(info);
}
@Override
public JetElement getCurrentLoop() {
public final void exitLoopBody(@NotNull JetLoopExpression expression) {
LoopInfo info = loopInfo.pop();
elementToBlockInfo.remove(expression);
allBlocks.pop();
bindLabel(info.getBodyExitPoint());
}
@Override
public JetLoopExpression getCurrentLoop() {
return loopInfo.empty() ? null : loopInfo.peek().getElement();
}
@@ -101,8 +101,7 @@ public class PseudocodeImpl implements Pseudocode {
private Set<LocalFunctionDeclarationInstruction> localDeclarations = null;
//todo getters
private final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
private final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
private final JetElement correspondingElement;
@@ -245,10 +244,6 @@ public class PseudocodeImpl implements Pseudocode {
}
}
/*package*/ void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
loopInfo.put(expression, blockInfo);
}
@Override
@NotNull
public SubroutineExitInstruction getExitInstruction() {