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:
@@ -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;
|
||||
}
|
||||
|
||||
+20
-14
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user