提交 49b60c3a 编写于 作者: A Andrey Breslav

More cases for nullability analysis

上级 9d3abf78
package org.jetbrains.jet.lang.cfg;
/**
* @author abreslav
*/
public abstract class BlockInfo {}
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);
// 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
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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<JetElement> 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<JetElement> 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<JetElement> dominated);
boolean isBreakable(JetLoopExpression loop);
}
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;
}
}
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;
}
}
}
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);
}
......@@ -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<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.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<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
final Map<JetExpression, LoopInfo> 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<Instruction> visited = new HashSet<Instruction>();
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<Instruction> reachable = new HashSet<Instruction>();
collectReachable(enterInstruction, reachable);
collectReachable(enterInstruction, reachable, null);
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
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<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) {
if (!visited.add(current)) return;
private boolean collectReachable(Instruction current, Set<Instruction> 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<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
......
......@@ -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();
}
}
......
......@@ -224,26 +224,28 @@ fun t3() {
---------------------
l0:
<START>
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:
<END>
......@@ -268,22 +270,24 @@ fun t3() {
l0:
<START>
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:
<START>
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:
......
......@@ -7,15 +7,17 @@ fun main() {
---------------------
l0:
<START>
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:
<END>
......@@ -30,14 +32,16 @@ fun dowhile() {
---------------------
l0:
<START>
l3:
l2:
l4:
ret l1
l5:
r(1)
r(0)
r(>)
r(1 > 0)
jt(l3)
l2:
jt(l2)
l3:
read (Unit)
l1:
<END>
......
......@@ -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)
}
......@@ -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) {
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册