Bindings are propagated over control flow, scope intersections are not supported yet

This commit is contained in:
Andrey Breslav
2011-06-13 16:12:32 +04:00
parent 3cacb512a3
commit 79d3f318b9
2 changed files with 124 additions and 34 deletions
@@ -1350,6 +1350,7 @@ public class JetTypeInferrer {
JetType type = getType(thenScope, thenBranch, true, thenInfo);
if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = elseInfo;
resultScope = elseScope;
}
result = JetStandardClasses.getUnitType();
}
@@ -1358,6 +1359,7 @@ public class JetTypeInferrer {
JetType type = getType(elseScope, elseBranch, true, elseInfo);
if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = thenInfo;
resultScope = thenScope;
}
result = JetStandardClasses.getUnitType();
}
@@ -1380,11 +1382,12 @@ public class JetTypeInferrer {
if (jumpInThen && !jumpInElse) {
resultDataFlowInfo = elseInfo;
resultScope = elseScope;
}
else if (jumpInElse && !jumpInThen) {
resultDataFlowInfo = thenInfo;
resultScope = thenScope;
}
}
}
@@ -1400,43 +1403,69 @@ public class JetTypeInferrer {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
result[0] = patternsToDataFlowInfo.get(pattern);
// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression.getLeftHandSide());
// if (variableDescriptor != null && pattern != null) {
// JetType outType = variableDescriptor.getOutType();
// if (outType == null) {
// outType = ErrorUtils.createErrorType("<Unknown>");
// }
// trace.getErrorHandler().openRegion();
// result[0] = checkPatternType(pattern, outType, scopeToExtend, variableDescriptor);
// trace.getErrorHandler().closeAndReturnCurrentRegion();
//
// }
//// if (pattern instanceof JetTypePattern) {
//// JetTypePattern jetTypePattern = (JetTypePattern) pattern;
//// result[0] = dataFlowInfo.isInstanceOf(variableDescriptor, trace.getBindingContext().resolveTypeReference(jetTypePattern.getTypeReference()));
//// }
//// }
}
}
@Override
public void visitBinaryExpression(JetBinaryExpression expression) {
IElementType operationToken = expression.getOperationToken();
if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) {
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, scopeToExtend); // TODO
if (operationToken == JetTokens.ANDAND) {
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, scopeToExtend);
JetExpression expressionRight = expression.getRight();
if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, scopeToExtend); // TODO
DataFlowInfo.CompositionOperator operator;
if (operationToken == JetTokens.ANDAND) {
operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
}
else {
operator = conditionValue ? DataFlowInfo.OR : DataFlowInfo.AND;
}
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, scopeToExtend);
DataFlowInfo.CompositionOperator operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo);
}
// 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()) {
VariableDescriptor leftVariable = leftVariableMap.get(rightVariable.getName());
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);
}
}
}
result[0] = dataFlowInfo;
}
else if (operationToken == JetTokens.EQEQ
@@ -1505,7 +1534,7 @@ public class JetTypeInferrer {
if (operationTokenType == JetTokens.EXCL) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
result[0] = extractDataFlowInfoFromCondition(baseExpression, !conditionValue, scopeToExtend); // TODO
result[0] = extractDataFlowInfoFromCondition(baseExpression, !conditionValue, scopeToExtend);
}
}
}
@@ -1578,7 +1607,11 @@ public class JetTypeInferrer {
}
protected WritableScopeImpl newWritableScopeImpl() {
return new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler());
return newWritableScopeImpl(scope);
}
private WritableScopeImpl newWritableScopeImpl(JetScope scopeToExtend) {
return new WritableScopeImpl(scopeToExtend, scopeToExtend.getContainingDeclaration(), trace.getErrorHandler());
}
@Override
@@ -1865,7 +1898,6 @@ public class JetTypeInferrer {
@Override
public void visitIsExpression(JetIsExpression expression) {
// TODO : patterns and everything
JetType knownType = getType(scope, expression.getLeftHandSide(), false);
JetPattern pattern = expression.getPattern();
if (pattern != null && knownType != null) {
@@ -1990,9 +2022,10 @@ public class JetTypeInferrer {
}
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
JetType leftType = getType(scope, left, false);
// TODO!!!
DataFlowInfo flowInfoLeft = extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, newWritableScopeImpl()); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
JetType rightType = right == null ? null : getType(scope, right, false, flowInfoLeft);
WritableScopeImpl leftScope = newWritableScopeImpl();
DataFlowInfo flowInfoLeft = extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, leftScope); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
WritableScopeImpl rightScope = operationType == JetTokens.ANDAND ? leftScope : newWritableScopeImpl();
JetType rightType = right == null ? null : getType(rightScope, right, false, flowInfoLeft);
if (leftType != null && !isBoolean(leftType)) {
trace.getErrorHandler().typeMismatch(left, semanticServices.getStandardLibrary().getBooleanType(), leftType);
}
+57
View File
@@ -86,3 +86,60 @@ fun f12(a : A?) {
<info descr="Automatically cast to B">b</info>.bar()
}
}
fun f13(a : A?) {
if (a is val c is B) {
c.foo()
<info descr="Automatically cast to B">c</info>.bar()
}
else {
a?.foo()
<error>c</error>.bar()
}
a?.foo()
if (!(a is val c is B)) {
a?.foo()
<error>c</error>.bar()
}
else {
a.foo()
<info descr="Automatically cast to B">c</info>.bar()
}
a?.foo()
if (a is val c is B && a.foo() == () && <info descr="Automatically cast to B">c</info>.bar() == ()) {
c.foo()
<info descr="Automatically cast to B">c</info>.bar()
}
else {
a?.foo()
<error>c</error>.bar()
}
// a?.foo()
// if ((a is val c is B) || (a is val c is A)) {
// c.foo()
// c.bar()
// }
// else {
// a?.foo()
// c.bar()
// }
if (!(a is val c is B)) return
<info descr="Automatically cast to B">a</info>.bar()
c.foo()
<info descr="Automatically cast to B">c</info>.bar()
}
fun f14(a : A?) {
while (!(a is val c is B)) {
}
<info descr="Automatically cast to B">c</info>.bar()
}
fun f15(a : A?) {
do {
} while (!(a is val c is B))
<info descr="Automatically cast to B">c</info>.bar()
}