diff --git a/idea/src/org/jetbrains/jet/lang/cfg/BlockInfo.java b/idea/src/org/jetbrains/jet/lang/cfg/BlockInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..11634459a08e47ebeb23bfbff85949fc222ac56a --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/BlockInfo.java @@ -0,0 +1,6 @@ +package org.jetbrains.jet.lang.cfg; + +/** +* @author abreslav +*/ +public abstract class BlockInfo {} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/BreakableBlockInfo.java b/idea/src/org/jetbrains/jet/lang/cfg/BreakableBlockInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..d9d529d15e0945ab2ba21f531fa1885f1ba59f11 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/BreakableBlockInfo.java @@ -0,0 +1,30 @@ +package org.jetbrains.jet.lang.cfg; + +import org.jetbrains.jet.lang.psi.JetElement; + +/** +* @author abreslav +*/ +public class BreakableBlockInfo extends BlockInfo { + private final JetElement element; + private final Label entryPoint; + private final Label exitPoint; + + public BreakableBlockInfo(JetElement element, Label entryPoint, Label exitPoint) { + this.element = element; + this.entryPoint = entryPoint; + this.exitPoint = exitPoint; + } + + public JetElement getElement() { + return element; + } + + public Label getEntryPoint() { + return entryPoint; + } + + public Label getExitPoint() { + return exitPoint; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 05854faf797c948cb04dae6a1be75b58cabe369a..9549a4ab0f08dc701c1d3fee8aecbcae03d7a84d 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -31,7 +31,7 @@ public interface JetControlFlowBuilder { Label getExitPoint(@NotNull JetElement labelElement); // Loops - Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint); + LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, @Nullable Label conditionEntryPoint); void exitLoop(@NotNull JetExpression expression); @Nullable diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index 1171c0dd98438dd211261e7704d57d9114951213..6137517b40ce6a260f040c3252680edd927c473a 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -73,8 +73,8 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { } @Override - public Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) { - return builder.enterLoop(expression, loopExitPoint); + public LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) { + return builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 11ca1bf714db90bb3fbbb652d6ee318dfe1ee49c..713f2a0abb6686e07b2f0981285bd380b99fb62e 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -350,35 +350,40 @@ public class JetControlFlowProcessor { @Override public void visitWhileExpression(JetWhileExpression expression) { - Label loopExitPoint = builder.createUnboundLabel(); - Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint); + LoopInfo loopInfo = builder.enterLoop(expression, null, null); + + builder.bindLabel(loopInfo.getConditionEntryPoint()); JetExpression condition = expression.getCondition(); if (condition != null) { value(condition, false, true); } - builder.jumpOnFalse(loopExitPoint); + builder.jumpOnFalse(loopInfo.getExitPoint()); + + builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); if (body != null) { value(body, true, false); } - builder.jump(loopEntryPoint); + builder.jump(loopInfo.getEntryPoint()); builder.exitLoop(expression); builder.readUnit(expression); } @Override public void visitDoWhileExpression(JetDoWhileExpression expression) { - Label loopExitPoint = builder.createUnboundLabel(); - Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint); + LoopInfo loopInfo = builder.enterLoop(expression, null, null); + + builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); if (body != null) { value(body, true, false); } + builder.bindLabel(loopInfo.getConditionEntryPoint()); JetExpression condition = expression.getCondition(); if (condition != null) { value(condition, false, true); } - builder.jumpOnTrue(loopEntryPoint); + builder.jumpOnTrue(loopInfo.getEntryPoint()); builder.exitLoop(expression); builder.readUnit(expression); } @@ -391,13 +396,20 @@ public class JetControlFlowProcessor { } // TODO : primitive cases Label loopExitPoint = builder.createUnboundLabel(); + Label conditionEntryPoint = builder.createUnboundLabel(); + + builder.bindLabel(conditionEntryPoint); builder.nondeterministicJump(loopExitPoint); - Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint); + + LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); + + builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); if (body != null) { value(body, true, false); } - builder.nondeterministicJump(loopEntryPoint); + + builder.nondeterministicJump(loopInfo.getEntryPoint()); builder.exitLoop(expression); builder.readUnit(expression); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index c3d790fe2516ba5c7405fd9e0af6ea16e117a0b2..8dff812a8efcf50eba9ac8f6c5b3d26fe095646c 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetLoopExpression; import java.util.Collection; @@ -25,6 +26,12 @@ public interface JetFlowInformationProvider { public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { throw new UnsupportedOperationException(); } + + @Override + public boolean isBreakable(JetLoopExpression loop) { + throw new UnsupportedOperationException(); + } + }; JetFlowInformationProvider NONE = new JetFlowInformationProvider() { @@ -42,6 +49,12 @@ public interface JetFlowInformationProvider { public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { } + + @Override + public boolean isBreakable(JetLoopExpression loop) { + return false; + } + }; void collectReturnedInformation( @@ -56,4 +69,6 @@ public interface JetFlowInformationProvider { void collectDominatedExpressions( @NotNull JetExpression dominator, @NotNull Collection dominated); + + boolean isBreakable(JetLoopExpression loop); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/LoopInfo.java b/idea/src/org/jetbrains/jet/lang/cfg/LoopInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..37f36d21c3f3ee5893ecd6b2fc6c751549b4754d --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/LoopInfo.java @@ -0,0 +1,25 @@ +package org.jetbrains.jet.lang.cfg; + +import org.jetbrains.jet.lang.psi.JetElement; + +/** +* @author abreslav +*/ +public class LoopInfo extends BreakableBlockInfo { + private final Label bodyEntryPoint; + private final Label conditionEntryPoint; + + public LoopInfo(JetElement element, Label entryPoint, Label exitPoint, Label bodyEntryPoint, Label conditionEntryPoint) { + super(element, entryPoint, exitPoint); + this.bodyEntryPoint = bodyEntryPoint; + this.conditionEntryPoint = conditionEntryPoint; + } + + public Label getBodyEntryPoint() { + return bodyEntryPoint; + } + + public Label getConditionEntryPoint() { + return conditionEntryPoint; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index b78be129e7b9150d99c0af3e7b7fd8b26ddb0b1a..ef7ee3e76f2dfb74cfb5906e7a1f1fe1dac87498 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.GenerationTrigger; -import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder; -import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter; -import org.jetbrains.jet.lang.cfg.Label; +import org.jetbrains.jet.lang.cfg.*; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; @@ -101,14 +98,20 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } @Override - public final Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) { + public final LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) { Label label = createUnboundLabel(); bindLabel(label); - BreakableBlockInfo blockInfo = new BreakableBlockInfo(expression, label, loopExitPoint); + LoopInfo blockInfo = new LoopInfo( + expression, + label, + loopExitPoint != null ? loopExitPoint : createUnboundLabel(), + createUnboundLabel(), + conditionEntryPoint != null ? conditionEntryPoint : createUnboundLabel()); loopInfo.push(blockInfo); elementToBlockInfo.put(expression, blockInfo); allBlocks.push(blockInfo); - return label; + trace.recordLoopInfo(expression, blockInfo); + return blockInfo; } @Override @@ -265,9 +268,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } } - private static abstract class BlockInfo {} - - private static class TryFinallyBlockInfo extends BlockInfo { + public static class TryFinallyBlockInfo extends BlockInfo { private final GenerationTrigger finallyBlock; private TryFinallyBlockInfo(GenerationTrigger finallyBlock) { @@ -279,27 +280,4 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } } - private static class BreakableBlockInfo extends BlockInfo { - private final JetElement element; - private final Label entryPoint; - private final Label exitPoint; - - private BreakableBlockInfo(JetElement element, Label entryPoint, Label exitPoint) { - this.element = element; - this.entryPoint = entryPoint; - this.exitPoint = exitPoint; - } - - public JetElement getElement() { - return element; - } - - public Label getEntryPoint() { - return entryPoint; - } - - public Label getExitPoint() { - return exitPoint; - } - } } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java index 39714a59fa03951b67323da57fbd4a42729e412e..0bdebb992a001aa4f26e00b3a9fa46c02108c434 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java @@ -1,7 +1,9 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.cfg.LoopInfo; import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; /** * @author abreslav @@ -21,10 +23,16 @@ public interface JetPseudocodeTrace { @Override public void close() { } + + @Override + public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { + + } }; void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode); void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction); void close(); + void recordLoopInfo(JetExpression expression, LoopInfo blockInfo); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 9b31e4573687e957bce314a04e113e7aedda5383..93aa12643542147dced68eaef18d7af679e0b476 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -46,6 +46,11 @@ public class Pseudocode { return instructions.subList(getTargetInstructionIndex(), instructions.size()); } + public Instruction resolveToInstruction() { + assert targetInstructionIndex != null; + return instructions.get(targetInstructionIndex); + } + } private final List instructions = new ArrayList(); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 214542e60064ae5cee6074477a1ba874ba6af238..6651734596c432b6de946db2c0c67af8c5c36a0b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; @@ -9,6 +10,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.cfg.LoopInfo; import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -721,6 +723,7 @@ public class ClassDescriptorResolver { final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); final Map pseudocodeMap = new HashMap(); final Map representativeInstructions = new HashMap(); + final Map loopInfo = Maps.newHashMap(); JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { @Override public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { @@ -732,6 +735,13 @@ public class ClassDescriptorResolver { public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { Instruction oldValue = representativeInstructions.put(element, instruction); // assert oldValue == null : element.getText(); + pseudocodeTrace.recordRepresentativeInstruction(element, instruction); + } + + @Override + public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { + loopInfo.put(expression, blockInfo); + pseudocodeTrace.recordLoopInfo(expression, blockInfo); } @Override @@ -762,7 +772,7 @@ public class ClassDescriptorResolver { SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); Set visited = new HashSet(); - collectReachable(enterInstruction, visited); + collectReachable(enterInstruction, visited, null); for (Instruction instruction : pseudocode.getInstructions()) { if (!visited.contains(instruction) && @@ -783,11 +793,11 @@ public class ClassDescriptorResolver { SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); Set reachable = new HashSet(); - collectReachable(enterInstruction, reachable); + collectReachable(enterInstruction, reachable, null); Set reachableWithDominatorProhibited = new HashSet(); reachableWithDominatorProhibited.add(dominatorInstruction); - collectReachable(enterInstruction, reachableWithDominatorProhibited); + collectReachable(enterInstruction, reachableWithDominatorProhibited, null); for (Instruction instruction : reachable) { if (instruction instanceof JetElementInstruction @@ -798,15 +808,39 @@ public class ClassDescriptorResolver { } } } + + @Override + public boolean isBreakable(JetLoopExpression loop) { + LoopInfo info = loopInfo.get(loop); + Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint(); + Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint(); + HashSet visited = Sets.newHashSet(); + Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint(); + visited.add(conditionEntryPoint.resolveToInstruction()); + return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction()); + } + + public boolean isReachable(JetExpression from, JetExpression to) { + Instruction fromInstr = representativeInstructions.get(from); + assert fromInstr != null : "No representative instruction for " + from.getText(); + Instruction toInstr = representativeInstructions.get(to); + assert toInstr != null : "No representative instruction for " + to.getText(); + + return collectReachable(fromInstr, Sets.newHashSet(), toInstr); + } }; } - private void collectReachable(Instruction current, Set visited) { - if (!visited.add(current)) return; + private boolean collectReachable(Instruction current, Set visited, @Nullable Instruction lookFor) { + if (!visited.add(current)) return false; + if (current == lookFor) return true; for (Instruction nextInstruction : current.getNextInstructions()) { - collectReachable(nextInstruction, visited); + if (collectReachable(nextInstruction, visited, lookFor)) { + return true; + } } + return false; } private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index c55623529759634a38631ea9e1c238606c4eea8d..e5ebe93470cc9e2418981f0cb9159a13eefb2262 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -1307,12 +1307,16 @@ public class JetTypeInferrer { } } else if (thenBranch == null) { - getType(scope, elseBranch, true, elseInfo); + JetType type = getType(scope, elseBranch, true, elseInfo); + if (type != null && JetStandardClasses.isNothing(type)) { + resultDataFlowInfo = thenInfo; + } result = JetStandardClasses.getUnitType(); } else { JetType thenType = getType(scope, thenBranch, true, thenInfo); JetType elseType = getType(scope, elseBranch, true, elseInfo); + if (thenType == null) { result = elseType; } @@ -1322,10 +1326,22 @@ public class JetTypeInferrer { else { result = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType)); } + + boolean jumpInThen = thenType != null && JetStandardClasses.isNothing(thenType); + boolean jumpInElse = elseType != null && JetStandardClasses.isNothing(elseType); + + if (jumpInThen && !jumpInElse) { + resultDataFlowInfo = elseInfo; + } + else if (jumpInElse && !jumpInThen) { + resultDataFlowInfo = thenInfo; + } + } } - private DataFlowInfo extractDataFlowInfoFromCondition(@NotNull JetExpression condition, final boolean conditionValue) { + private DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue) { + if (condition == null) return dataFlowInfo; final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo}; condition.accept(new JetVisitor() { @Override @@ -1410,7 +1426,9 @@ public class JetTypeInferrer { DataFlowInfo conditionInfo = condition == null ? dataFlowInfo : extractDataFlowInfoFromCondition(condition, true); getType(scope, body, true, conditionInfo); } - resultDataFlowInfo = condition == null ? null : extractDataFlowInfoFromCondition(condition, false); + if (!flowInformationProvider.isBreakable(expression)) { + resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false); + } result = JetStandardClasses.getUnitType(); } @@ -1434,7 +1452,11 @@ public class JetTypeInferrer { conditionScope = writableScope; getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo); } - checkCondition(conditionScope, expression.getCondition()); + JetExpression condition = expression.getCondition(); + checkCondition(conditionScope, condition); + if (!flowInformationProvider.isBreakable(expression)) { + resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false); + } result = JetStandardClasses.getUnitType(); } @@ -1918,6 +1940,7 @@ public class JetTypeInferrer { if (receiverType != null) { FunctionDescriptor functionDescriptor = lookupFunction(scope, expression, "get", receiverType, argumentTypes, true); if (functionDescriptor != null) { +// checkNullSafety(receiverType, expression.getIndexExpressions().get(0).getNode(), functionDescriptor); result = functionDescriptor.getUnsubstitutedReturnType(); } } diff --git a/idea/testData/cfg/Finally.instructions b/idea/testData/cfg/Finally.instructions index ba202616f563bf73b545e5fcef5def4e6c989a62..a5c381bc8642a592b1a46d9cca624b1897e8dd14 100644 --- a/idea/testData/cfg/Finally.instructions +++ b/idea/testData/cfg/Finally.instructions @@ -224,26 +224,28 @@ fun t3() { --------------------- l0: -l3: +l2: +l5: r(true) - jf(l2) - jmp?(l4) + jf(l3) +l4: + jmp?(l6) r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) + jf(l7) r(2) - jmp(l2) - jmp(l6) -l5: + jmp(l3) + jmp(l8) +l7: read (Unit) -l4: l6: +l8: r(2) - jmp(l3) -l2: + jmp(l2) +l3: read (Unit) l1: @@ -268,22 +270,24 @@ fun t3() { l0: jmp?(l2) -l4: +l3: +l6: r(true) - jf(l3) + jf(l4) +l5: r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) - jmp(l3) - jmp(l6) -l5: - read (Unit) -l6: + jf(l7) jmp(l4) -l3: + jmp(l8) +l7: + read (Unit) +l8: + jmp(l3) +l4: read (Unit) r(5) l2: @@ -310,22 +314,24 @@ fun t3() { l0: jmp?(l2) -l4: +l3: +l6: r(true) - jf(l3) + jf(l4) +l5: r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) - jmp(l3) - jmp(l6) -l5: - read (Unit) -l6: + jf(l7) jmp(l4) -l3: + jmp(l8) +l7: + read (Unit) +l8: + jmp(l3) +l4: read (Unit) l2: r(2) @@ -354,24 +360,26 @@ l0: r(a) r(..) r(1..a) - jmp?(l2) l3: - jmp?(l4) + jmp?(l2) +l4: +l5: + jmp?(l6) r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) + jf(l7) r(2) - jmp(l3) - jmp(l6) -l5: + jmp(l4) + jmp(l8) +l7: read (Unit) -l4: l6: +l8: r(2) - jmp?(l3) + jmp?(l4) l2: read (Unit) l1: @@ -401,20 +409,22 @@ l0: r(a) r(..) r(1..a) - jmp?(l3) l4: + jmp?(l3) +l5: +l6: r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) - jmp(l4) - jmp(l6) -l5: + jf(l7) + jmp(l5) + jmp(l8) +l7: read (Unit) -l6: - jmp?(l4) +l8: + jmp?(l5) l3: read (Unit) r(5) @@ -446,20 +456,22 @@ l0: r(a) r(..) r(1..a) - jmp?(l3) l4: + jmp?(l3) +l5: +l6: r(1) r(2) r(3) r(>) r(2 > 3) - jf(l5) - jmp(l4) - jmp(l6) -l5: + jf(l7) + jmp(l5) + jmp(l8) +l7: read (Unit) -l6: - jmp?(l4) +l8: + jmp?(l5) l3: read (Unit) l2: diff --git a/idea/testData/cfg/OnlyWhileInFunctionBody.instructions b/idea/testData/cfg/OnlyWhileInFunctionBody.instructions index 907bcb116d398dbd9cb9a7f487ace9af40057e5d..4da6384a0b2f4cc6fd7ae9aca4c11a839a2f1401 100644 --- a/idea/testData/cfg/OnlyWhileInFunctionBody.instructions +++ b/idea/testData/cfg/OnlyWhileInFunctionBody.instructions @@ -7,15 +7,17 @@ fun main() { --------------------- l0: -l3: +l2: +l5: r(1) r(0) r(>) r(1 > 0) - jf(l2) + jf(l3) +l4: r(2) - jmp(l3) -l2: + jmp(l2) +l3: read (Unit) l1: @@ -30,14 +32,16 @@ fun dowhile() { --------------------- l0: -l3: +l2: +l4: ret l1 +l5: r(1) r(0) r(>) r(1 > 0) - jt(l3) -l2: + jt(l2) +l3: read (Unit) l1: diff --git a/idea/testData/checker/Nullability.jet b/idea/testData/checker/Nullability.jet index d13f733ce93f3c9f65e399621927e74e49646212..562a27f2026a3d984cf02df9b5d5b7c36c4f6721 100644 --- a/idea/testData/checker/Nullability.jet +++ b/idea/testData/checker/Nullability.jet @@ -139,3 +139,78 @@ fun test() { out.println() } + + +fun f(out : String?) { + out?.get(0) + if (out != null) else return; + out.get(0) +} + +fun f1(out : String?) { + out?.get(0) + if (out != null) else { + 1 + 2 + return; + } + out.get(0) +} + +fun f2(out : String?) { + out?.get(0) + if (out == null) { + 1 + 2 + return; + } + out.get(0) +} + +fun f3(out : String?) { + out?.get(0) + if (out == null) { + 1 + 2 + return; + } + else { + 1 + 2 + } + out.get(0) +} + +fun f4(s : String?) { + s?.get(0) + while (1 < 2 && s != null) { + s.get(0) + } + s?.get(0) + while (s == null || 1 < 2) { + s?.get(0) + } + s.get(0) +} + +fun f5(s : String?) { + s?.get(0) + while (1 < 2 && s != null) { + s.get(0) + } + s?.get(0) + while (s == null || 1 < 2) { + if (1 > 2) break + s?.get(0) + } + s?.get(0); +} + +fun f6(s : String?) { + s?.get(0) + do { + s?.get(0) + if (1 < 2) break; + } while (s == null) + s?.get(0) + do { + s?.get(0) + } while (s == null) + s.get(0) +} diff --git a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java index 39e18d69871312577a0906ba982391f5aa6d626e..210f82eafb60872e94ba8ae8c2ffe447a30767c6 100644 --- a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java +++ b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java @@ -8,11 +8,13 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBase; +import org.jetbrains.jet.lang.cfg.LoopInfo; import org.jetbrains.jet.lang.cfg.pseudocode.Instruction; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamedDeclaration; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; @@ -55,6 +57,10 @@ public class JetControlFlowTest extends JetTestCaseBase { } } + @Override + public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { + } + @Override public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { }