Bindings are propagated over control flow, only directly, otherwise it is confusing
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user