From d539c4337237c7b5eef47e86d4a314a00d749d16 Mon Sep 17 00:00:00 2001 From: Mayank Patke Date: Fri, 18 Feb 2022 00:58:20 +0000 Subject: [PATCH] [dart2js] Create child LocalState for inference of labeled statements. This is analogous to what we do for other control flow constructs. Without this, a `break` to the label causes the outer scope to also appear aborted. Fixes: #48317 Bug: https://github.com/flutter/flutter/issues/96394 Change-Id: I575a5bf96b25b49df6f15d429881e310b3b34d15 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/233446 Reviewed-by: Stephen Adams Commit-Queue: Mayank Patke --- .../lib/src/inferrer/builder_kernel.dart | 5 ++- .../test/inference/data/break_continue.dart | 35 ++++++++++++++++++- pkg/compiler/test/inference/data/general.dart | 4 +-- tests/web/regress/48317_test.dart | 18 ++++++++++ tests/web_2/regress/48317_test.dart | 18 ++++++++++ 5 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tests/web/regress/48317_test.dart create mode 100644 tests/web_2/regress/48317_test.dart diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart index 12f0069c5eb..937f1c01d5b 100644 --- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart +++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart @@ -543,10 +543,13 @@ class KernelTypeGraphBuilder extends ir.Visitor // Loops and switches handle their own labels. visit(body); } else { + LocalState stateBefore = _state; JumpTarget jumpTarget = _localsMap.getJumpTargetForLabel(node); _setupBreaksAndContinues(jumpTarget); + _state = LocalState.childPath(stateBefore); visit(body); - _state.mergeAfterBreaks(_inferrer, _getBreaks(jumpTarget)); + _state = stateBefore.mergeAfterBreaks(_inferrer, _getBreaks(jumpTarget), + keepOwnLocals: false); _clearBreaksAndContinues(jumpTarget); } return null; diff --git a/pkg/compiler/test/inference/data/break_continue.dart b/pkg/compiler/test/inference/data/break_continue.dart index 9fbb86ead7b..d815f1d0b36 100644 --- a/pkg/compiler/test/inference/data/break_continue.dart +++ b/pkg/compiler/test/inference/data/break_continue.dart @@ -12,6 +12,8 @@ main() { noContinueInWhile(); breakInIf(); noBreakInIf(); + breakInBlock(); + noBreakInBlock(); } //////////////////////////////////////////////////////////////////////////////// @@ -107,7 +109,7 @@ noContinueInWhile() { } //////////////////////////////////////////////////////////////////////////////// -// A break statement in a labeled statement. +// A conditional break statement in a labeled statement. //////////////////////////////////////////////////////////////////////////////// /*member: _breakInIf:Union([exact=JSString], [exact=JSUInt31])*/ @@ -150,3 +152,34 @@ noBreakInIf() { _noBreakInIf(true); _noBreakInIf(false); } + +//////////////////////////////////////////////////////////////////////////////// +// An unconditional break statement in a labeled statement. +//////////////////////////////////////////////////////////////////////////////// + +/*member: breakInBlock:Value([exact=JSString], value: "")*/ +breakInBlock() { + dynamic local = 42; + label: + { + local = ''; + break label; + local = false; + } + return local; +} + +//////////////////////////////////////////////////////////////////////////////// +// The "labeled statement" above _without_ the break statement. +//////////////////////////////////////////////////////////////////////////////// + +/*member: noBreakInBlock:Value([exact=JSBool], value: false)*/ +noBreakInBlock() { + dynamic local = 42; + label: + { + local = ''; + local = false; + } + return local; +} diff --git a/pkg/compiler/test/inference/data/general.dart b/pkg/compiler/test/inference/data/general.dart index da299fc6c4f..db114da4503 100644 --- a/pkg/compiler/test/inference/data/general.dart +++ b/pkg/compiler/test/inference/data/general.dart @@ -560,13 +560,13 @@ testDoWhile2() { return a; } -/*member: testDoWhile3:[exact=JSUInt31]*/ +/*member: testDoWhile3:Value([exact=JSBool], value: false)*/ testDoWhile3() { dynamic a = 42; do { a = 'foo'; if (true) continue; - return 42; + return false; } while (true); // ignore: dead_code return a; diff --git a/tests/web/regress/48317_test.dart b/tests/web/regress/48317_test.dart new file mode 100644 index 00000000000..ff16cfc8185 --- /dev/null +++ b/tests/web/regress/48317_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2022, 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. + +import 'package:expect/expect.dart'; + +helper(num c) => c * -1; + +void main() { + num a = 3; + + label: + { + break label; + } + + Expect.equals(-3, helper(a)); +} diff --git a/tests/web_2/regress/48317_test.dart b/tests/web_2/regress/48317_test.dart new file mode 100644 index 00000000000..ff16cfc8185 --- /dev/null +++ b/tests/web_2/regress/48317_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2022, 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. + +import 'package:expect/expect.dart'; + +helper(num c) => c * -1; + +void main() { + num a = 3; + + label: + { + break label; + } + + Expect.equals(-3, helper(a)); +}