Bindings are propagated over control flow, only directly, otherwise it is confusing

This commit is contained in:
Andrey Breslav
2011-06-14 18:48:27 +04:00
parent 79d3f318b9
commit 400e939c21
2 changed files with 66 additions and 95 deletions
@@ -373,12 +373,12 @@ public class JetTypeInferrer {
if (newDataFlowInfo == null) { if (newDataFlowInfo == null) {
newDataFlowInfo = dataFlowInfo; newDataFlowInfo = dataFlowInfo;
} }
WritableScope newScope = blockLevelVisitor.getResultScope(); // WritableScope newScope = blockLevelVisitor.getResultScope();
if (newScope == null) { // if (newScope == null) {
newScope = scope; // newScope = scope;
} // }
if (newDataFlowInfo != dataFlowInfo || newScope != scope) { if (newDataFlowInfo != dataFlowInfo) {// || newScope != scope) {
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(newScope, true, newDataFlowInfo); blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo);
} }
else { else {
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope? blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
@@ -591,7 +591,7 @@ public class JetTypeInferrer {
protected JetType result; protected JetType result;
protected DataFlowInfo resultDataFlowInfo; protected DataFlowInfo resultDataFlowInfo;
protected WritableScope resultScope; // protected WritableScope resultScope;
private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo) { private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo) {
this.scope = scope; this.scope = scope;
@@ -604,16 +604,16 @@ public class JetTypeInferrer {
return resultDataFlowInfo; return resultDataFlowInfo;
} }
public WritableScope getResultScope() { // public WritableScope getResultScope() {
if (resultScope instanceof WritableScopeImpl) { // if (resultScope instanceof WritableScopeImpl) {
WritableScopeImpl writableScope = (WritableScopeImpl) resultScope; // WritableScopeImpl writableScope = (WritableScopeImpl) resultScope;
if (!writableScope.hasDeclaredItems()) { // if (!writableScope.hasDeclaredItems()) {
return null; // return null;
} // }
} // }
return resultScope; // return resultScope;
} // }
//
@Nullable @Nullable
public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, boolean preferBlock) { public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, boolean preferBlock) {
return getType(scope, expression, preferBlock, dataFlowInfo); return getType(scope, expression, preferBlock, dataFlowInfo);
@@ -673,7 +673,7 @@ public class JetTypeInferrer {
public void resetResult() { public void resetResult() {
result = null; result = null;
resultDataFlowInfo = null; resultDataFlowInfo = null;
resultScope = null; // resultScope = null;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1350,7 +1350,7 @@ public class JetTypeInferrer {
JetType type = getType(thenScope, thenBranch, true, thenInfo); JetType type = getType(thenScope, thenBranch, true, thenInfo);
if (type != null && JetStandardClasses.isNothing(type)) { if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = elseInfo; resultDataFlowInfo = elseInfo;
resultScope = elseScope; // resultScope = elseScope;
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
@@ -1359,7 +1359,7 @@ public class JetTypeInferrer {
JetType type = getType(elseScope, elseBranch, true, elseInfo); JetType type = getType(elseScope, elseBranch, true, elseInfo);
if (type != null && JetStandardClasses.isNothing(type)) { if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = thenInfo; resultDataFlowInfo = thenInfo;
resultScope = thenScope; // resultScope = thenScope;
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
@@ -1382,16 +1382,16 @@ public class JetTypeInferrer {
if (jumpInThen && !jumpInElse) { if (jumpInThen && !jumpInElse) {
resultDataFlowInfo = elseInfo; resultDataFlowInfo = elseInfo;
resultScope = elseScope; // resultScope = elseScope;
} }
else if (jumpInElse && !jumpInThen) { else if (jumpInElse && !jumpInThen) {
resultDataFlowInfo = thenInfo; resultDataFlowInfo = thenInfo;
resultScope = thenScope; // resultScope = thenScope;
} }
} }
} }
private DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @NotNull final WritableScope scopeToExtend) { private DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend) {
if (condition == null) return dataFlowInfo; 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() {
@@ -1399,72 +1399,39 @@ public class JetTypeInferrer {
public void visitIsExpression(JetIsExpression expression) { public void visitIsExpression(JetIsExpression expression) {
if (conditionValue) { if (conditionValue) {
JetPattern pattern = expression.getPattern(); JetPattern pattern = expression.getPattern();
for (VariableDescriptor variableDescriptor : patternsToBoundVariableLists.get(pattern)) {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
result[0] = patternsToDataFlowInfo.get(pattern); result[0] = patternsToDataFlowInfo.get(pattern);
if (scopeToExtend != null) {
for (VariableDescriptor variableDescriptor : patternsToBoundVariableLists.get(pattern)) {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
}
} }
} }
@Override @Override
public void visitBinaryExpression(JetBinaryExpression expression) { public void visitBinaryExpression(JetBinaryExpression expression) {
IElementType operationToken = expression.getOperationToken(); IElementType operationToken = expression.getOperationToken();
if (operationToken == JetTokens.ANDAND) { if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) {
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, scopeToExtend); WritableScope actualScopeToExtend;
if (operationToken == JetTokens.ANDAND) {
actualScopeToExtend = conditionValue ? scopeToExtend : null;
}
else {
actualScopeToExtend = conditionValue ? null : scopeToExtend;
}
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, actualScopeToExtend);
JetExpression expressionRight = expression.getRight(); JetExpression expressionRight = expression.getRight();
if (expressionRight != null) { if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, scopeToExtend); DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, actualScopeToExtend);
DataFlowInfo.CompositionOperator operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR; DataFlowInfo.CompositionOperator operator;
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo); if (operationToken == JetTokens.ANDAND) {
} operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
// TODO : intersect scopes when condition is false
result[0] = dataFlowInfo;
}
else if (operationToken == JetTokens.OROR) {
WritableScopeImpl leftScope = newWritableScopeImpl(scopeToExtend);
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, leftScope);
JetExpression expressionRight = expression.getRight();
WritableScopeImpl rightScope = newWritableScopeImpl(scopeToExtend);
if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, rightScope);
DataFlowInfo.CompositionOperator operator = conditionValue ? DataFlowInfo.OR : DataFlowInfo.AND;
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo);
}
// TODO : this is incorrect, we need to intersect only when condition is true (and on && and condition being false), and intersect together with dataFlowInfo
if (leftScope.hasDeclaredItems() && rightScope.hasDeclaredItems()) {
Map<String, VariableDescriptor> leftVariableMap = Maps.newHashMap();
for (VariableDescriptor leftVariable : leftScope.getDeclaredVariables()) {
leftVariableMap.put(leftVariable.getName(), leftVariable);
} }
for (VariableDescriptor rightVariable : rightScope.getDeclaredVariables()) { else {
VariableDescriptor leftVariable = leftVariableMap.get(rightVariable.getName()); operator = conditionValue ? DataFlowInfo.OR : DataFlowInfo.AND;
if (leftVariable != null) {
// TODO : allow only vals
JetType leftType = leftVariable.getOutType();
if (leftType == null) {
continue;
}
JetType rightType = rightVariable.getOutType();
if (rightType == null) {
continue;
}
List<JetType> leftPossibleTypes = dataFlowInfo.getPossibleTypes(leftVariable);
List<JetType> rightPossibleTypes = dataFlowInfo.getPossibleTypes(rightVariable);
VariableDescriptor variable;
if (semanticServices.getTypeChecker().isSubtypeOf(rightType, leftType)) {
variable = leftVariable;
}
else if (semanticServices.getTypeChecker().isSubtypeOf(leftType, rightType)) {
variable = rightVariable;
}
else {
continue;
}
scopeToExtend.addVariableDescriptor(variable);
}
} }
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo);
} }
result[0] = dataFlowInfo; result[0] = dataFlowInfo;
} }
@@ -1571,8 +1538,8 @@ public class JetTypeInferrer {
getType(scopeToExtend, body, true, conditionInfo); getType(scopeToExtend, body, true, conditionInfo);
} }
if (!flowInformationProvider.isBreakable(expression)) { if (!flowInformationProvider.isBreakable(expression)) {
resultScope = newWritableScopeImpl(); // resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, resultScope); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null);
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
@@ -1600,8 +1567,8 @@ public class JetTypeInferrer {
JetExpression condition = expression.getCondition(); JetExpression condition = expression.getCondition();
checkCondition(conditionScope, condition); checkCondition(conditionScope, condition);
if (!flowInformationProvider.isBreakable(expression)) { if (!flowInformationProvider.isBreakable(expression)) {
resultScope = newWritableScopeImpl(); // resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, resultScope); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null);
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
+17 -13
View File
@@ -117,29 +117,33 @@ fun f13(a : A?) {
<error>c</error>.bar() <error>c</error>.bar()
} }
// a?.foo() if (!(a is val c is B) || !(a is val x is C)) {
// if ((a is val c is B) || (a is val c is A)) { <error>x</error>
// c.foo() <error>c</error>
// c.bar() }
// } else {
// else { <info descr="Automatically cast to C">x</info>.bar()
// a?.foo() <info descr="Automatically cast to B">c</info>.bar()
// c.bar() }
// }
if (!(a is val <error>c</error> is B) || !(a is val <error>c</error> is C)) {
}
if (!(a is val c is B)) return if (!(a is val c is B)) return
<info descr="Automatically cast to B">a</info>.bar() <info descr="Automatically cast to B">a</info>.bar()
c.foo() <error>c</error>.foo()
<info descr="Automatically cast to B">c</info>.bar() <error>c</error>.bar()
} }
fun f14(a : A?) { fun f14(a : A?) {
while (!(a is val c is B)) { while (!(a is val c is B)) {
} }
<info descr="Automatically cast to B">c</info>.bar() <info descr="Automatically cast to B">a</info>.bar()
<error>c</error>.bar()
} }
fun f15(a : A?) { fun f15(a : A?) {
do { do {
} while (!(a is val c is B)) } while (!(a is val c is B))
<info descr="Automatically cast to B">c</info>.bar() <info descr="Automatically cast to B">a</info>.bar()
<error>c</error>.bar()
} }