From 01ca690a67feb289f1bc0b4fc5929f0aed6d30bb Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Wed, 27 Sep 2017 09:38:53 +0000 Subject: [PATCH] Add test for break to labeled statements. Change-Id: Ia1d7e5f93426d2781c7b3b583af10d88af142f28 Reviewed-on: https://dart-review.googlesource.com/8044 Reviewed-by: Sigmund Cherem --- pkg/compiler/lib/src/js_model/locals.dart | 13 +++++----- .../dart2js/equivalence/id_equivalence.dart | 21 +++++++++++++++ .../equivalence/id_equivalence_test.dart | 6 +++++ .../jumps/data/labeled_statements.dart | 26 +++++++++++++++++++ tests/compiler/dart2js/jumps/jump_test.dart | 24 +++++++++++++++++ 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 tests/compiler/dart2js/jumps/data/labeled_statements.dart diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart index e4b65bab419..9e3d04315fd 100644 --- a/pkg/compiler/lib/src/js_model/locals.dart +++ b/pkg/compiler/lib/src/js_model/locals.dart @@ -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; } diff --git a/tests/compiler/dart2js/equivalence/id_equivalence.dart b/tests/compiler/dart2js/equivalence/id_equivalence.dart index a1feaaa2fe2..f517a9d0683 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence.dart @@ -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); diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_test.dart b/tests/compiler/dart2js/equivalence/id_equivalence_test.dart index 879d69bff11..5cb08f03ff1 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence_test.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence_test.dart @@ -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 ''; } diff --git a/tests/compiler/dart2js/jumps/data/labeled_statements.dart b/tests/compiler/dart2js/jumps/data/labeled_statements.dart new file mode 100644 index 00000000000..0d430c7b505 --- /dev/null +++ b/tests/compiler/dart2js/jumps/data/labeled_statements.dart @@ -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'); + } +} diff --git a/tests/compiler/dart2js/jumps/jump_test.dart b/tests/compiler/dart2js/jumps/jump_test.dart index 9a7ad990aa3..b18da0edbc1 100644 --- a/tests/compiler/dart2js/jumps/jump_test.dart +++ b/tests/compiler/dart2js/jumps/jump_test.dart @@ -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));