Index: compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
index 326ae8342c21a2c7eb351f642f6e1a1fbbc24d90..e42b75fbd84ee682dd6a43f1bf6905ba2650ddec 100644 |
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
@@ -182,6 +182,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
private final boolean developerModeChecks; |
private final boolean suppressSdkWarnings; |
private final boolean memberWarningForInferredTypes; |
+ private final Map<DartBlock, VariableElementsRestorer> restoreOnBlockExit = Maps.newHashMap(); |
/** |
* Keeps track of the number of nested catches, used to detect re-throws |
@@ -606,49 +607,58 @@ public class TypeAnalyzer implements DartCompilationPhase { |
private void visitConditionalNode(DartExpression condition, DartNode node) { |
final VariableElementsRestorer variableRestorer = new VariableElementsRestorer(); |
try { |
- if (condition != null) { |
- condition.accept(new ASTVisitor<Void>() { |
- boolean negation = false; |
- @Override |
- public Void visitUnaryExpression(DartUnaryExpression node) { |
- boolean negationOld = negation; |
- try { |
- if (node.getOperator() == Token.NOT) { |
- negation = !negation; |
- } |
- return super.visitUnaryExpression(node); |
- } finally { |
- negation = negationOld; |
+ inferVariableTypesFromIsConditions(condition, variableRestorer); |
+ typeOf(node); |
+ } finally { |
+ variableRestorer.restore(); |
+ } |
+ } |
+ |
+ /** |
+ * Helper for setting {@link Type}s of {@link VariableElement}s when given "condition" is |
+ * satisfied. |
+ */ |
+ private void inferVariableTypesFromIsConditions(DartExpression condition, |
+ final VariableElementsRestorer variableRestorer) { |
+ if (condition != null) { |
+ condition.accept(new ASTVisitor<Void>() { |
+ boolean negation = false; |
+ @Override |
+ public Void visitUnaryExpression(DartUnaryExpression node) { |
+ boolean negationOld = negation; |
+ try { |
+ if (node.getOperator() == Token.NOT) { |
+ negation = !negation; |
} |
+ return super.visitUnaryExpression(node); |
+ } finally { |
+ negation = negationOld; |
} |
+ } |
- @Override |
- public Void visitBinaryExpression(DartBinaryExpression node) { |
- // apply "as" always |
- // apply "is" only if not negated |
- if (node.getOperator() == Token.AS || node.getOperator() == Token.IS && !negation) { |
- DartExpression arg1 = node.getArg1(); |
- DartExpression arg2 = node.getArg2(); |
- if (arg1 instanceof DartIdentifier && arg1.getElement() instanceof VariableElement |
- && arg2 instanceof DartTypeExpression) { |
- VariableElement variableElement = (VariableElement) arg1.getElement(); |
- Type rhsType = arg2.getType(); |
- Type varType = Types.makeInferred(rhsType); |
- variableRestorer.setType(variableElement, varType); |
- } |
- } |
- // operator || means that we can not be sure about types |
- if (node.getOperator() == Token.OR) { |
- return null; |
+ @Override |
+ public Void visitBinaryExpression(DartBinaryExpression node) { |
+ // apply "as" always |
+ // apply "is" only if not negated |
+ if (node.getOperator() == Token.AS || node.getOperator() == Token.IS && !negation) { |
+ DartExpression arg1 = node.getArg1(); |
+ DartExpression arg2 = node.getArg2(); |
+ if (arg1 instanceof DartIdentifier && arg1.getElement() instanceof VariableElement |
+ && arg2 instanceof DartTypeExpression) { |
+ VariableElement variableElement = (VariableElement) arg1.getElement(); |
+ Type rhsType = arg2.getType(); |
+ Type varType = Types.makeInferred(rhsType); |
+ variableRestorer.setType(variableElement, varType); |
} |
- // continue |
- return super.visitBinaryExpression(node); |
} |
- }); |
- } |
- typeOf(node); |
- } finally { |
- variableRestorer.restore(); |
+ // operator || means that we can not be sure about types |
+ if (node.getOperator() == Token.OR) { |
+ return null; |
+ } |
+ // continue |
+ return super.visitBinaryExpression(node); |
+ } |
+ }); |
} |
} |
@@ -1204,7 +1214,14 @@ public class TypeAnalyzer implements DartCompilationPhase { |
@Override |
public Type visitBlock(DartBlock node) { |
- return typeAsVoid(node); |
+ try { |
+ return typeAsVoid(node); |
+ } finally { |
+ VariableElementsRestorer variableRestorer = restoreOnBlockExit.remove(node); |
+ if (variableRestorer != null) { |
+ variableRestorer.restore(); |
+ } |
+ } |
} |
@Override |
@@ -2288,6 +2305,14 @@ public class TypeAnalyzer implements DartCompilationPhase { |
if (node.getArguments().size() == 1) { |
DartExpression condition = node.getArguments().get(0); |
checkAssertCondition(condition); |
+ // infer types, which are valid until the end of the enclosing control block |
+ if (node.getParent() instanceof DartExprStmt |
+ && node.getParent().getParent() instanceof DartBlock) { |
+ DartBlock restoreBlock = getBlockForAssertTypesInference(node); |
+ VariableElementsRestorer variableRestorer = new VariableElementsRestorer(); |
+ restoreOnBlockExit.put(restoreBlock, variableRestorer); |
+ inferVariableTypesFromIsConditions(condition, variableRestorer); |
+ } |
} else { |
onError(node, TypeErrorCode.ASSERT_NUMBER_ARGUMENTS); |
} |
@@ -2324,6 +2349,21 @@ public class TypeAnalyzer implements DartCompilationPhase { |
return returnType; |
} |
+ private static DartBlock getBlockForAssertTypesInference(DartNode node) { |
+ while (node != null) { |
+ if (node instanceof DartBlock) { |
+ DartBlock block = (DartBlock) node; |
+ DartNode p = block.getParent(); |
+ if (p instanceof DartIfStatement || p instanceof DartForStatement |
+ || p instanceof DartForInStatement || p instanceof DartDoWhileStatement) { |
+ return block; |
+ } |
+ } |
+ node = node.getParent(); |
+ } |
+ return null; |
+ } |
+ |
/** |
* Report warning if given {@link Element} is deprecated. |
*/ |