[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 <sra@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Mayank Patke 2022-02-18 00:58:20 +00:00 committed by Commit Bot
parent 30195a437b
commit d539c43372
5 changed files with 76 additions and 4 deletions

View file

@ -543,10 +543,13 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation>
// 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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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));
}

View file

@ -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));
}