| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index 7dbf6e42c99492dbe9054a776fd77d0869c52b5e..f1fb45e006db2ecb53a565d47a312a0f6fdb6b50 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -3470,6 +3470,11 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| */
|
| bool _enclosingBlockContainsBreak = false;
|
|
|
| + /**
|
| + * Add node when a labelled `break` is encountered.
|
| + */
|
| + Set<AstNode> _enclosingBlockBreaksLabel = new Set<AstNode>();
|
| +
|
| @override
|
| bool visitArgumentList(ArgumentList node) =>
|
| _visitExpressions(node.arguments);
|
| @@ -3545,6 +3550,9 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| @override
|
| bool visitBreakStatement(BreakStatement node) {
|
| _enclosingBlockContainsBreak = true;
|
| + if (node.label != null) {
|
| + _enclosingBlockBreaksLabel.add(node.target);
|
| + }
|
| return false;
|
| }
|
|
|
| @@ -3634,13 +3642,13 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| if (_visitExpressions(node.updaters)) {
|
| return true;
|
| }
|
| + bool blockReturns = _nodeExits(node.body);
|
| // TODO(jwren) Do we want to take all constant expressions into account?
|
| // If for(; true; ) (or for(;;)), and the body doesn't return or the body
|
| // doesn't have a break, then return true.
|
| bool implicitOrExplictTrue = conditionExpression == null ||
|
| (conditionExpression is BooleanLiteral && conditionExpression.value);
|
| if (implicitOrExplictTrue) {
|
| - bool blockReturns = _nodeExits(node.body);
|
| if (blockReturns || !_enclosingBlockContainsBreak) {
|
| return true;
|
| }
|
| @@ -3680,18 +3688,18 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| // TODO(jwren) Do we want to take all constant expressions into account?
|
| if (conditionExpression is BooleanLiteral) {
|
| if (conditionExpression.value) {
|
| - // if(true) ...
|
| + // if (true) ...
|
| return _nodeExits(thenStatement);
|
| } else if (elseStatement != null) {
|
| // if (false) ...
|
| return _nodeExits(elseStatement);
|
| }
|
| }
|
| - if (thenStatement == null || elseStatement == null) {
|
| - return false;
|
| - }
|
| bool thenExits = _nodeExits(thenStatement);
|
| bool elseExits = _nodeExits(elseStatement);
|
| + if (thenStatement == null || elseStatement == null) {
|
| + return false;
|
| + }
|
| return thenExits && elseExits;
|
| }
|
|
|
| @@ -3718,8 +3726,16 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| bool visitLabel(Label node) => false;
|
|
|
| @override
|
| - bool visitLabeledStatement(LabeledStatement node) =>
|
| - node.statement.accept(this);
|
| + bool visitLabeledStatement(LabeledStatement node) {
|
| + try {
|
| + bool statementExits = _nodeExits(node.statement);
|
| + bool neverBrokeFromLabel =
|
| + !_enclosingBlockBreaksLabel.contains(node.statement);
|
| + return statementExits && neverBrokeFromLabel;
|
| + } finally {
|
| + _enclosingBlockBreaksLabel.remove(node.statement);
|
| + }
|
| + }
|
|
|
| @override
|
| bool visitLiteral(Literal node) => false;
|
| @@ -3873,11 +3889,11 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| if (conditionExpression.accept(this)) {
|
| return true;
|
| }
|
| + bool blockReturns = node.body.accept(this);
|
| // TODO(jwren) Do we want to take all constant expressions into account?
|
| if (conditionExpression is BooleanLiteral) {
|
| // If while(true), and the body doesn't return or the body doesn't have
|
| // a break, then return true.
|
| - bool blockReturns = node.body.accept(this);
|
| if (conditionExpression.value &&
|
| (blockReturns || !_enclosingBlockContainsBreak)) {
|
| return true;
|
| @@ -3912,7 +3928,7 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
|
| }
|
|
|
| bool _visitStatements(NodeList<Statement> statements) {
|
| - for (int i = statements.length - 1; i >= 0; i--) {
|
| + for (int i = 0; i < statements.length; i++) {
|
| if (statements[i].accept(this)) {
|
| return true;
|
| }
|
|
|