Add test for break to labeled statements.
Change-Id: Ia1d7e5f93426d2781c7b3b583af10d88af142f28 Reviewed-on: https://dart-review.googlesource.com/8044 Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
@@ -217,7 +217,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
@override
|
||||
defaultNode(ir.Node node) => node.visitChildren(this);
|
||||
|
||||
bool _canBeBreakTarget(ir.TreeNode node) {
|
||||
static bool canBeBreakTarget(ir.TreeNode node) {
|
||||
return node is ir.ForStatement ||
|
||||
node is ir.ForInStatement ||
|
||||
node is ir.WhileStatement ||
|
||||
@@ -225,8 +225,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
node is ir.SwitchStatement;
|
||||
}
|
||||
|
||||
bool _canBeContinueTarget(ir.TreeNode node) {
|
||||
// TODO(johnniwinther): Add more.
|
||||
static bool canBeContinueTarget(ir.TreeNode node) {
|
||||
return node is ir.ForStatement ||
|
||||
node is ir.ForInStatement ||
|
||||
node is ir.WhileStatement ||
|
||||
@@ -238,7 +237,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
JJumpTarget target;
|
||||
ir.TreeNode body = node.target.body;
|
||||
ir.TreeNode parent = node.target.parent;
|
||||
if (_canBeBreakTarget(body)) {
|
||||
if (canBeBreakTarget(body)) {
|
||||
// We have code like
|
||||
//
|
||||
// l1: for (int i = 0; i < 10; i++) {
|
||||
@@ -251,7 +250,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
ir.TreeNode search = node;
|
||||
bool needsLabel = false;
|
||||
while (search != node.target) {
|
||||
if (_canBeBreakTarget(search)) {
|
||||
if (canBeBreakTarget(search)) {
|
||||
needsLabel = search != body;
|
||||
break;
|
||||
}
|
||||
@@ -261,7 +260,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
JLabelDefinition label = _getOrCreateLabel(target, node.target);
|
||||
label.isBreakTarget = true;
|
||||
}
|
||||
} else if (_canBeContinueTarget(parent)) {
|
||||
} else if (canBeContinueTarget(parent)) {
|
||||
// We have code like
|
||||
//
|
||||
// for (int i = 0; i < 10; i++) l1: {
|
||||
@@ -275,7 +274,7 @@ class JumpVisitor extends ir.Visitor {
|
||||
ir.TreeNode search = node;
|
||||
bool needsLabel = false;
|
||||
while (search != node.target) {
|
||||
if (_canBeContinueTarget(search)) {
|
||||
if (canBeContinueTarget(search)) {
|
||||
needsLabel = search != body;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import 'package:compiler/src/common.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
import 'package:compiler/src/kernel/element_map.dart';
|
||||
import 'package:compiler/src/js_model/locals.dart';
|
||||
import 'package:compiler/src/resolution/access_semantics.dart';
|
||||
import 'package:compiler/src/resolution/send_structure.dart';
|
||||
import 'package:compiler/src/resolution/tree_elements.dart';
|
||||
@@ -293,6 +294,9 @@ abstract class AstDataExtractor extends ast.Visitor with DataRegistry {
|
||||
return new NodeId(node.getBeginToken().charOffset, IdKind.moveNext);
|
||||
}
|
||||
|
||||
NodeId createLabeledStatementId(ast.LabeledStatement node) =>
|
||||
computeDefaultNodeId(node.statement);
|
||||
|
||||
NodeId createLoopId(ast.Node node) => computeDefaultNodeId(node);
|
||||
|
||||
NodeId createGotoId(ast.Node node) => computeDefaultNodeId(node);
|
||||
@@ -413,6 +417,13 @@ abstract class AstDataExtractor extends ast.Visitor with DataRegistry {
|
||||
visitNode(node);
|
||||
}
|
||||
|
||||
visitLabeledStatement(ast.LabeledStatement node) {
|
||||
if (node.statement is! ast.Loop && node.statement is! ast.SwitchStatement) {
|
||||
computeForNode(node, createLabeledStatementId(node));
|
||||
}
|
||||
visitNode(node);
|
||||
}
|
||||
|
||||
visitSwitchStatement(ast.SwitchStatement node) {
|
||||
computeForNode(node, createSwitchId(node));
|
||||
visitNode(node);
|
||||
@@ -513,6 +524,8 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry {
|
||||
return new NodeId(node.fileOffset, IdKind.moveNext);
|
||||
}
|
||||
|
||||
NodeId createLabeledStatementId(ir.LabeledStatement node) =>
|
||||
computeDefaultNodeId(node.body);
|
||||
NodeId createLoopId(ir.TreeNode node) => computeDefaultNodeId(node);
|
||||
NodeId createGotoId(ir.TreeNode node) => computeDefaultNodeId(node);
|
||||
NodeId createSwitchId(ir.SwitchStatement node) => computeDefaultNodeId(node);
|
||||
@@ -604,6 +617,14 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry {
|
||||
super.visitWhileStatement(node);
|
||||
}
|
||||
|
||||
visitLabeledStatement(ir.LabeledStatement node) {
|
||||
if (!JumpVisitor.canBeBreakTarget(node.body) &&
|
||||
!JumpVisitor.canBeContinueTarget(node.parent)) {
|
||||
computeForNode(node, createLabeledStatementId(node));
|
||||
}
|
||||
super.visitLabeledStatement(node);
|
||||
}
|
||||
|
||||
visitBreakStatement(ir.BreakStatement node) {
|
||||
computeForNode(node, createGotoId(node));
|
||||
super.visitBreakStatement(node);
|
||||
|
||||
@@ -117,6 +117,8 @@ class ComputerMixin {
|
||||
String get switchName => 'switch';
|
||||
|
||||
String get switchCaseName => 'case';
|
||||
|
||||
String get labelName => 'label';
|
||||
}
|
||||
|
||||
/// AST visitor for computing a descriptive mapping of the [Id]s in a member.
|
||||
@@ -138,6 +140,8 @@ class ResolvedAstComputer extends AstDataExtractor with ComputerMixin {
|
||||
return switchName;
|
||||
} else if (node is ast.SwitchCase) {
|
||||
return switchCaseName;
|
||||
} else if (node is ast.LabeledStatement) {
|
||||
return labelName;
|
||||
}
|
||||
|
||||
dynamic sendStructure;
|
||||
@@ -268,6 +272,8 @@ class IrComputer extends IrDataExtractor with ComputerMixin {
|
||||
return switchName;
|
||||
} else if (node is ir.SwitchCase) {
|
||||
return switchCaseName;
|
||||
} else if (node is ir.LabeledStatement) {
|
||||
return labelName;
|
||||
}
|
||||
return '<unknown:$node (${node.runtimeType})>';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
main() {
|
||||
breakFromIf(true);
|
||||
breakFromBlock(true);
|
||||
}
|
||||
|
||||
breakFromIf(c) {
|
||||
label:
|
||||
/*0@break*/ if (c) {
|
||||
/*target=0*/ break label;
|
||||
}
|
||||
}
|
||||
|
||||
breakFromBlock(c) {
|
||||
label:
|
||||
/*0@break*/
|
||||
{
|
||||
if (c) {
|
||||
/*target=0*/ break label;
|
||||
}
|
||||
print('1');
|
||||
}
|
||||
}
|
||||
@@ -159,6 +159,19 @@ class JumpsAstComputer extends AstDataExtractor with JumpsMixin {
|
||||
super.visitGotoStatement(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitLabeledStatement(ast.LabeledStatement node) {
|
||||
if (node.statement is! ast.Loop && node.statement is! ast.SwitchStatement) {
|
||||
JumpTarget target = elements.getTargetDefinition(node.statement);
|
||||
if (target != null) {
|
||||
NodeId id = createLabeledStatementId(node);
|
||||
SourceSpan sourceSpan = computeSourceSpan(node);
|
||||
targets[target] = new TargetData(index++, id, sourceSpan, target);
|
||||
}
|
||||
}
|
||||
super.visitLabeledStatement(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitSwitchStatement(ast.SwitchStatement node) {
|
||||
JumpTarget target = elements.getTargetDefinition(node);
|
||||
@@ -246,6 +259,17 @@ class JumpsIrChecker extends IrDataExtractor with JumpsMixin {
|
||||
super.visitBreakStatement(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitLabeledStatement(ir.LabeledStatement node) {
|
||||
JumpTarget target = _localsMap.getJumpTargetForLabel(node);
|
||||
if (target != null) {
|
||||
NodeId id = createLabeledStatementId(node);
|
||||
SourceSpan sourceSpan = computeSourceSpan(node);
|
||||
targets[target] = new TargetData(index++, id, sourceSpan, target);
|
||||
}
|
||||
super.visitLabeledStatement(node);
|
||||
}
|
||||
|
||||
visitSwitchStatement(ir.SwitchStatement node) {
|
||||
addTargetData(
|
||||
node, createSwitchId(node), _localsMap.getJumpTargetForSwitch(node));
|
||||
|
||||
Reference in New Issue
Block a user