More cases for nullability analysis
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jetbrains.jet.lang.cfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public abstract class BlockInfo {}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ public interface JetControlFlowBuilder {
|
|||||||
Label getExitPoint(@NotNull JetElement labelElement);
|
Label getExitPoint(@NotNull JetElement labelElement);
|
||||||
|
|
||||||
// Loops
|
// Loops
|
||||||
Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint);
|
LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, @Nullable Label conditionEntryPoint);
|
||||||
|
|
||||||
void exitLoop(@NotNull JetExpression expression);
|
void exitLoop(@NotNull JetExpression expression);
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) {
|
public LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) {
|
||||||
return builder.enterLoop(expression, loopExitPoint);
|
return builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -350,35 +350,40 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitWhileExpression(JetWhileExpression expression) {
|
public void visitWhileExpression(JetWhileExpression expression) {
|
||||||
Label loopExitPoint = builder.createUnboundLabel();
|
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||||
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
|
|
||||||
|
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||||
JetExpression condition = expression.getCondition();
|
JetExpression condition = expression.getCondition();
|
||||||
if (condition != null) {
|
if (condition != null) {
|
||||||
value(condition, false, true);
|
value(condition, false, true);
|
||||||
}
|
}
|
||||||
builder.jumpOnFalse(loopExitPoint);
|
builder.jumpOnFalse(loopInfo.getExitPoint());
|
||||||
|
|
||||||
|
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||||
JetExpression body = expression.getBody();
|
JetExpression body = expression.getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
value(body, true, false);
|
value(body, true, false);
|
||||||
}
|
}
|
||||||
builder.jump(loopEntryPoint);
|
builder.jump(loopInfo.getEntryPoint());
|
||||||
builder.exitLoop(expression);
|
builder.exitLoop(expression);
|
||||||
builder.readUnit(expression);
|
builder.readUnit(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDoWhileExpression(JetDoWhileExpression expression) {
|
public void visitDoWhileExpression(JetDoWhileExpression expression) {
|
||||||
Label loopExitPoint = builder.createUnboundLabel();
|
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||||
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
|
|
||||||
|
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||||
JetExpression body = expression.getBody();
|
JetExpression body = expression.getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
value(body, true, false);
|
value(body, true, false);
|
||||||
}
|
}
|
||||||
|
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||||
JetExpression condition = expression.getCondition();
|
JetExpression condition = expression.getCondition();
|
||||||
if (condition != null) {
|
if (condition != null) {
|
||||||
value(condition, false, true);
|
value(condition, false, true);
|
||||||
}
|
}
|
||||||
builder.jumpOnTrue(loopEntryPoint);
|
builder.jumpOnTrue(loopInfo.getEntryPoint());
|
||||||
builder.exitLoop(expression);
|
builder.exitLoop(expression);
|
||||||
builder.readUnit(expression);
|
builder.readUnit(expression);
|
||||||
}
|
}
|
||||||
@@ -391,13 +396,20 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
// TODO : primitive cases
|
// TODO : primitive cases
|
||||||
Label loopExitPoint = builder.createUnboundLabel();
|
Label loopExitPoint = builder.createUnboundLabel();
|
||||||
|
Label conditionEntryPoint = builder.createUnboundLabel();
|
||||||
|
|
||||||
|
builder.bindLabel(conditionEntryPoint);
|
||||||
builder.nondeterministicJump(loopExitPoint);
|
builder.nondeterministicJump(loopExitPoint);
|
||||||
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
|
|
||||||
|
LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
|
||||||
|
|
||||||
|
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||||
JetExpression body = expression.getBody();
|
JetExpression body = expression.getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
value(body, true, false);
|
value(body, true, false);
|
||||||
}
|
}
|
||||||
builder.nondeterministicJump(loopEntryPoint);
|
|
||||||
|
builder.nondeterministicJump(loopInfo.getEntryPoint());
|
||||||
builder.exitLoop(expression);
|
builder.exitLoop(expression);
|
||||||
builder.readUnit(expression);
|
builder.readUnit(expression);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.cfg;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetLoopExpression;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -25,6 +26,12 @@ public interface JetFlowInformationProvider {
|
|||||||
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBreakable(JetLoopExpression loop) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
||||||
@@ -42,6 +49,12 @@ public interface JetFlowInformationProvider {
|
|||||||
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBreakable(JetLoopExpression loop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void collectReturnedInformation(
|
void collectReturnedInformation(
|
||||||
@@ -56,4 +69,6 @@ public interface JetFlowInformationProvider {
|
|||||||
void collectDominatedExpressions(
|
void collectDominatedExpressions(
|
||||||
@NotNull JetExpression dominator,
|
@NotNull JetExpression dominator,
|
||||||
@NotNull Collection<JetElement> dominated);
|
@NotNull Collection<JetElement> dominated);
|
||||||
|
|
||||||
|
boolean isBreakable(JetLoopExpression loop);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-33
@@ -1,10 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.cfg.GenerationTrigger;
|
import org.jetbrains.jet.lang.cfg.*;
|
||||||
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.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
@@ -101,14 +98,20 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) {
|
public final LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) {
|
||||||
Label label = createUnboundLabel();
|
Label label = createUnboundLabel();
|
||||||
bindLabel(label);
|
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);
|
loopInfo.push(blockInfo);
|
||||||
elementToBlockInfo.put(expression, blockInfo);
|
elementToBlockInfo.put(expression, blockInfo);
|
||||||
allBlocks.push(blockInfo);
|
allBlocks.push(blockInfo);
|
||||||
return label;
|
trace.recordLoopInfo(expression, blockInfo);
|
||||||
|
return blockInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -265,9 +268,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class BlockInfo {}
|
public static class TryFinallyBlockInfo extends BlockInfo {
|
||||||
|
|
||||||
private static class TryFinallyBlockInfo extends BlockInfo {
|
|
||||||
private final GenerationTrigger finallyBlock;
|
private final GenerationTrigger finallyBlock;
|
||||||
|
|
||||||
private TryFinallyBlockInfo(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.JetElement;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -21,10 +23,16 @@ public interface JetPseudocodeTrace {
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
||||||
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
|
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
void recordLoopInfo(JetExpression expression, LoopInfo blockInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ public class Pseudocode {
|
|||||||
return instructions.subList(getTargetInstructionIndex(), instructions.size());
|
return instructions.subList(getTargetInstructionIndex(), instructions.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Instruction resolveToInstruction() {
|
||||||
|
assert targetInstructionIndex != null;
|
||||||
|
return instructions.get(targetInstructionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
||||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
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.cfg.pseudocode.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
@@ -721,6 +723,7 @@ public class ClassDescriptorResolver {
|
|||||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||||
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||||
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||||
|
final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
|
||||||
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||||
@Override
|
@Override
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
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) {
|
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||||
Instruction oldValue = representativeInstructions.put(element, instruction);
|
Instruction oldValue = representativeInstructions.put(element, instruction);
|
||||||
// assert oldValue == null : element.getText();
|
// 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
|
@Override
|
||||||
@@ -762,7 +772,7 @@ public class ClassDescriptorResolver {
|
|||||||
|
|
||||||
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
||||||
Set<Instruction> visited = new HashSet<Instruction>();
|
Set<Instruction> visited = new HashSet<Instruction>();
|
||||||
collectReachable(enterInstruction, visited);
|
collectReachable(enterInstruction, visited, null);
|
||||||
|
|
||||||
for (Instruction instruction : pseudocode.getInstructions()) {
|
for (Instruction instruction : pseudocode.getInstructions()) {
|
||||||
if (!visited.contains(instruction) &&
|
if (!visited.contains(instruction) &&
|
||||||
@@ -783,11 +793,11 @@ public class ClassDescriptorResolver {
|
|||||||
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
|
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
|
||||||
|
|
||||||
Set<Instruction> reachable = new HashSet<Instruction>();
|
Set<Instruction> reachable = new HashSet<Instruction>();
|
||||||
collectReachable(enterInstruction, reachable);
|
collectReachable(enterInstruction, reachable, null);
|
||||||
|
|
||||||
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
|
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
|
||||||
reachableWithDominatorProhibited.add(dominatorInstruction);
|
reachableWithDominatorProhibited.add(dominatorInstruction);
|
||||||
collectReachable(enterInstruction, reachableWithDominatorProhibited);
|
collectReachable(enterInstruction, reachableWithDominatorProhibited, null);
|
||||||
|
|
||||||
for (Instruction instruction : reachable) {
|
for (Instruction instruction : reachable) {
|
||||||
if (instruction instanceof JetElementInstruction
|
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<Instruction> 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.<Instruction>newHashSet(), toInstr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectReachable(Instruction current, Set<Instruction> visited) {
|
private boolean collectReachable(Instruction current, Set<Instruction> visited, @Nullable Instruction lookFor) {
|
||||||
if (!visited.add(current)) return;
|
if (!visited.add(current)) return false;
|
||||||
|
if (current == lookFor) return true;
|
||||||
|
|
||||||
for (Instruction nextInstruction : current.getNextInstructions()) {
|
for (Instruction nextInstruction : current.getNextInstructions()) {
|
||||||
collectReachable(nextInstruction, visited);
|
if (collectReachable(nextInstruction, visited, lookFor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
|
private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
|
||||||
|
|||||||
@@ -1307,12 +1307,16 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (thenBranch == null) {
|
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();
|
result = JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType thenType = getType(scope, thenBranch, true, thenInfo);
|
JetType thenType = getType(scope, thenBranch, true, thenInfo);
|
||||||
JetType elseType = getType(scope, elseBranch, true, elseInfo);
|
JetType elseType = getType(scope, elseBranch, true, elseInfo);
|
||||||
|
|
||||||
if (thenType == null) {
|
if (thenType == null) {
|
||||||
result = elseType;
|
result = elseType;
|
||||||
}
|
}
|
||||||
@@ -1322,10 +1326,22 @@ public class JetTypeInferrer {
|
|||||||
else {
|
else {
|
||||||
result = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType));
|
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};
|
final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo};
|
||||||
condition.accept(new JetVisitor() {
|
condition.accept(new JetVisitor() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1410,7 +1426,9 @@ public class JetTypeInferrer {
|
|||||||
DataFlowInfo conditionInfo = condition == null ? dataFlowInfo : extractDataFlowInfoFromCondition(condition, true);
|
DataFlowInfo conditionInfo = condition == null ? dataFlowInfo : extractDataFlowInfoFromCondition(condition, true);
|
||||||
getType(scope, body, true, conditionInfo);
|
getType(scope, body, true, conditionInfo);
|
||||||
}
|
}
|
||||||
resultDataFlowInfo = condition == null ? null : extractDataFlowInfoFromCondition(condition, false);
|
if (!flowInformationProvider.isBreakable(expression)) {
|
||||||
|
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false);
|
||||||
|
}
|
||||||
result = JetStandardClasses.getUnitType();
|
result = JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1434,7 +1452,11 @@ public class JetTypeInferrer {
|
|||||||
conditionScope = writableScope;
|
conditionScope = writableScope;
|
||||||
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo);
|
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();
|
result = JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1918,6 +1940,7 @@ public class JetTypeInferrer {
|
|||||||
if (receiverType != null) {
|
if (receiverType != null) {
|
||||||
FunctionDescriptor functionDescriptor = lookupFunction(scope, expression, "get", receiverType, argumentTypes, true);
|
FunctionDescriptor functionDescriptor = lookupFunction(scope, expression, "get", receiverType, argumentTypes, true);
|
||||||
if (functionDescriptor != null) {
|
if (functionDescriptor != null) {
|
||||||
|
// checkNullSafety(receiverType, expression.getIndexExpressions().get(0).getNode(), functionDescriptor);
|
||||||
result = functionDescriptor.getUnsubstitutedReturnType();
|
result = functionDescriptor.getUnsubstitutedReturnType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,26 +224,28 @@ fun t3() {
|
|||||||
---------------------
|
---------------------
|
||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
l3:
|
l2:
|
||||||
|
l5:
|
||||||
r(true)
|
r(true)
|
||||||
jf(l2)
|
jf(l3)
|
||||||
jmp?(l4)
|
l4:
|
||||||
|
jmp?(l6)
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
r(2)
|
|
||||||
jmp(l2)
|
|
||||||
jmp(l6)
|
|
||||||
l5:
|
|
||||||
read (Unit)
|
|
||||||
l4:
|
|
||||||
l6:
|
|
||||||
r(2)
|
r(2)
|
||||||
jmp(l3)
|
jmp(l3)
|
||||||
l2:
|
jmp(l8)
|
||||||
|
l7:
|
||||||
|
read (Unit)
|
||||||
|
l6:
|
||||||
|
l8:
|
||||||
|
r(2)
|
||||||
|
jmp(l2)
|
||||||
|
l3:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l1:
|
l1:
|
||||||
<END>
|
<END>
|
||||||
@@ -268,22 +270,24 @@ fun t3() {
|
|||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
jmp?(l2)
|
jmp?(l2)
|
||||||
l4:
|
l3:
|
||||||
|
l6:
|
||||||
r(true)
|
r(true)
|
||||||
jf(l3)
|
jf(l4)
|
||||||
|
l5:
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
jmp(l3)
|
|
||||||
jmp(l6)
|
|
||||||
l5:
|
|
||||||
read (Unit)
|
|
||||||
l6:
|
|
||||||
jmp(l4)
|
jmp(l4)
|
||||||
l3:
|
jmp(l8)
|
||||||
|
l7:
|
||||||
|
read (Unit)
|
||||||
|
l8:
|
||||||
|
jmp(l3)
|
||||||
|
l4:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
r(5)
|
r(5)
|
||||||
l2:
|
l2:
|
||||||
@@ -310,22 +314,24 @@ fun t3() {
|
|||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
jmp?(l2)
|
jmp?(l2)
|
||||||
l4:
|
l3:
|
||||||
|
l6:
|
||||||
r(true)
|
r(true)
|
||||||
jf(l3)
|
jf(l4)
|
||||||
|
l5:
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
jmp(l3)
|
|
||||||
jmp(l6)
|
|
||||||
l5:
|
|
||||||
read (Unit)
|
|
||||||
l6:
|
|
||||||
jmp(l4)
|
jmp(l4)
|
||||||
l3:
|
jmp(l8)
|
||||||
|
l7:
|
||||||
|
read (Unit)
|
||||||
|
l8:
|
||||||
|
jmp(l3)
|
||||||
|
l4:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l2:
|
l2:
|
||||||
r(2)
|
r(2)
|
||||||
@@ -354,24 +360,26 @@ l0:
|
|||||||
r(a)
|
r(a)
|
||||||
r(..)
|
r(..)
|
||||||
r(1..a)
|
r(1..a)
|
||||||
jmp?(l2)
|
|
||||||
l3:
|
l3:
|
||||||
jmp?(l4)
|
jmp?(l2)
|
||||||
|
l4:
|
||||||
|
l5:
|
||||||
|
jmp?(l6)
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
r(2)
|
r(2)
|
||||||
jmp(l3)
|
jmp(l4)
|
||||||
jmp(l6)
|
jmp(l8)
|
||||||
l5:
|
l7:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l4:
|
|
||||||
l6:
|
l6:
|
||||||
|
l8:
|
||||||
r(2)
|
r(2)
|
||||||
jmp?(l3)
|
jmp?(l4)
|
||||||
l2:
|
l2:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l1:
|
l1:
|
||||||
@@ -401,20 +409,22 @@ l0:
|
|||||||
r(a)
|
r(a)
|
||||||
r(..)
|
r(..)
|
||||||
r(1..a)
|
r(1..a)
|
||||||
jmp?(l3)
|
|
||||||
l4:
|
l4:
|
||||||
|
jmp?(l3)
|
||||||
|
l5:
|
||||||
|
l6:
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
jmp(l4)
|
jmp(l5)
|
||||||
jmp(l6)
|
jmp(l8)
|
||||||
l5:
|
l7:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l6:
|
l8:
|
||||||
jmp?(l4)
|
jmp?(l5)
|
||||||
l3:
|
l3:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
r(5)
|
r(5)
|
||||||
@@ -446,20 +456,22 @@ l0:
|
|||||||
r(a)
|
r(a)
|
||||||
r(..)
|
r(..)
|
||||||
r(1..a)
|
r(1..a)
|
||||||
jmp?(l3)
|
|
||||||
l4:
|
l4:
|
||||||
|
jmp?(l3)
|
||||||
|
l5:
|
||||||
|
l6:
|
||||||
r(1)
|
r(1)
|
||||||
r(2)
|
r(2)
|
||||||
r(3)
|
r(3)
|
||||||
r(>)
|
r(>)
|
||||||
r(2 > 3)
|
r(2 > 3)
|
||||||
jf(l5)
|
jf(l7)
|
||||||
jmp(l4)
|
jmp(l5)
|
||||||
jmp(l6)
|
jmp(l8)
|
||||||
l5:
|
l7:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l6:
|
l8:
|
||||||
jmp?(l4)
|
jmp?(l5)
|
||||||
l3:
|
l3:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l2:
|
l2:
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ fun main() {
|
|||||||
---------------------
|
---------------------
|
||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
l3:
|
l2:
|
||||||
|
l5:
|
||||||
r(1)
|
r(1)
|
||||||
r(0)
|
r(0)
|
||||||
r(>)
|
r(>)
|
||||||
r(1 > 0)
|
r(1 > 0)
|
||||||
jf(l2)
|
jf(l3)
|
||||||
|
l4:
|
||||||
r(2)
|
r(2)
|
||||||
jmp(l3)
|
jmp(l2)
|
||||||
l2:
|
l3:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l1:
|
l1:
|
||||||
<END>
|
<END>
|
||||||
@@ -30,14 +32,16 @@ fun dowhile() {
|
|||||||
---------------------
|
---------------------
|
||||||
l0:
|
l0:
|
||||||
<START>
|
<START>
|
||||||
l3:
|
l2:
|
||||||
|
l4:
|
||||||
ret l1
|
ret l1
|
||||||
|
l5:
|
||||||
r(1)
|
r(1)
|
||||||
r(0)
|
r(0)
|
||||||
r(>)
|
r(>)
|
||||||
r(1 > 0)
|
r(1 > 0)
|
||||||
jt(l3)
|
jt(l2)
|
||||||
l2:
|
l3:
|
||||||
read (Unit)
|
read (Unit)
|
||||||
l1:
|
l1:
|
||||||
<END>
|
<END>
|
||||||
|
|||||||
@@ -139,3 +139,78 @@ fun test() {
|
|||||||
out.println()
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ import junit.framework.Test;
|
|||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.JetTestCaseBase;
|
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.Instruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
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.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
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
|
@Override
|
||||||
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user