Skip to content

Commit fed1e4b

Browse files
Kevin Millikincommit-bot@chromium.org
Kevin Millikin
authored andcommitted
Fix a bug in compilation of while loops
Unlabeled while loops in Kernel (these are ones that are not the target of a break) did not shadow labeled ones. The compiler would generate a break without a label in JS which would target the wrong loop. Bug: Change-Id: Ib060ab66326a3ea0779eaceccaf1ca06ccfafb75 Reviewed-on: https://dart-review.googlesource.com/23421 Reviewed-by: Dmitry Stefantsov <[email protected]> Commit-Queue: Kevin Millikin <[email protected]>
1 parent 5ce5811 commit fed1e4b

File tree

2 files changed

+68
-57
lines changed

2 files changed

+68
-57
lines changed

pkg/dev_compiler/lib/src/kernel/compiler.dart

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,70 +3065,86 @@ class ProgramCompiler
30653065
return body;
30663066
}
30673067

3068+
JS.Statement translateLoop(Statement node, JS.Statement action()) {
3069+
var savedBreakTargets;
3070+
if (_currentBreakTargets.isNotEmpty &&
3071+
_effectiveTargets[_currentBreakTargets.first] != node) {
3072+
// If breaking without a label targets some other (outer) loop, then
3073+
// this loop prevents breaking to that loop without a label. This loop
3074+
// was not labeled for a break in Kernel, otherwise it would be the
3075+
// effective target of the current break targets, so it is not itself the
3076+
// target of a break.
3077+
savedBreakTargets = _currentBreakTargets;
3078+
_currentBreakTargets = <LabeledStatement>[];
3079+
}
3080+
var savedContinueTargets = _currentContinueTargets;
3081+
var result = action();
3082+
if (savedBreakTargets != null) _currentBreakTargets = savedBreakTargets;
3083+
_currentContinueTargets = savedContinueTargets;
3084+
return result;
3085+
}
3086+
30683087
@override
30693088
JS.While visitWhileStatement(WhileStatement node) {
3070-
var condition = _visitTest(node.condition);
3071-
3072-
var saved = _currentContinueTargets;
3073-
var body = _visitScope(effectiveBodyOf(node, node.body));
3074-
_currentContinueTargets = saved;
3075-
3076-
return new JS.While(condition, body);
3089+
return translateLoop(node, () {
3090+
var condition = _visitTest(node.condition);
3091+
var body = _visitScope(effectiveBodyOf(node, node.body));
3092+
return new JS.While(condition, body);
3093+
});
30773094
}
30783095

30793096
@override
30803097
JS.Do visitDoStatement(DoStatement node) {
3081-
var saved = _currentContinueTargets;
3082-
var body = _visitScope(effectiveBodyOf(node, node.body));
3083-
_currentContinueTargets = saved;
3084-
3085-
return new JS.Do(body, _visitTest(node.condition));
3098+
return translateLoop(node, () {
3099+
var body = _visitScope(effectiveBodyOf(node, node.body));
3100+
var condition = _visitTest(node.condition);
3101+
return new JS.Do(body, condition);
3102+
});
30863103
}
30873104

30883105
@override
30893106
JS.For visitForStatement(ForStatement node) {
3090-
emitForInitializer(VariableDeclaration v) => new JS.VariableInitialization(
3091-
_emitVariableRef(v)..sourceInformation = v,
3092-
_visitInitializer(v.initializer, v.annotations));
3093-
3094-
var init = node.variables.map(emitForInitializer).toList();
3095-
var initList =
3096-
init.isEmpty ? null : new JS.VariableDeclarationList('let', init);
3097-
var updates = node.updates;
3098-
JS.Expression update;
3099-
if (updates.isNotEmpty) {
3100-
update = new JS.Expression.binary(
3101-
updates.map(_visitAndMarkExpression).toList(), ',')
3102-
.toVoidExpression();
3103-
}
3104-
var condition = _visitTest(node.condition);
3105-
3106-
var saved = _currentContinueTargets;
3107-
var body = _visitScope(effectiveBodyOf(node, node.body));
3108-
_currentContinueTargets = saved;
3107+
return translateLoop(node, () {
3108+
emitForInitializer(VariableDeclaration v) =>
3109+
new JS.VariableInitialization(
3110+
_emitVariableRef(v)..sourceInformation = v,
3111+
_visitInitializer(v.initializer, v.annotations));
3112+
3113+
var init = node.variables.map(emitForInitializer).toList();
3114+
var initList =
3115+
init.isEmpty ? null : new JS.VariableDeclarationList('let', init);
3116+
var updates = node.updates;
3117+
JS.Expression update;
3118+
if (updates.isNotEmpty) {
3119+
update = new JS.Expression.binary(
3120+
updates.map(_visitAndMarkExpression).toList(), ',')
3121+
.toVoidExpression();
3122+
}
3123+
var condition = _visitTest(node.condition);
3124+
var body = _visitScope(effectiveBodyOf(node, node.body));
31093125

3110-
return new JS.For(initList, condition, update, body);
3126+
return new JS.For(initList, condition, update, body);
3127+
});
31113128
}
31123129

31133130
@override
31143131
JS.Statement visitForInStatement(ForInStatement node) {
3115-
if (node.isAsync) {
3116-
return _emitAwaitFor(node);
3117-
}
3118-
3119-
var iterable = _visitAndMarkExpression(node.iterable);
3132+
return translateLoop(node, () {
3133+
if (node.isAsync) {
3134+
return _emitAwaitFor(node);
3135+
}
31203136

3121-
var saved = _currentContinueTargets;
3122-
var body = _visitScope(effectiveBodyOf(node, node.body));
3123-
_currentContinueTargets = saved;
3137+
var iterable = _visitAndMarkExpression(node.iterable);
3138+
var body = _visitScope(effectiveBodyOf(node, node.body));
31243139

3125-
var v = _emitVariableRef(node.variable);
3126-
var init = js.call('let #', v);
3127-
if (_annotatedNullCheck(node.variable.annotations)) {
3128-
body = new JS.Block([_nullParameterCheck(v), body]);
3129-
}
3140+
var v = _emitVariableRef(node.variable);
3141+
var init = js.call('let #', v);
3142+
if (_annotatedNullCheck(node.variable.annotations)) {
3143+
body = new JS.Block([_nullParameterCheck(v), body]);
3144+
}
31303145

3131-
return new JS.ForOf(init, iterable, body);
3146+
return new JS.ForOf(init, iterable, body);
3147+
});
31323148
}
31333149

31343150
JS.Statement _emitAwaitFor(ForInStatement node) {

tests/language_2/language_2_dartdevc.status

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,12 +1033,7 @@ wrong_number_type_arguments_test/01: MissingCompileTimeError
10331033
assertion_test: RuntimeError # Issue 30326; Expect.equals(expected: <1>, actual: <0>) fails.
10341034
async_star_cancel_while_paused_test: RuntimeError # Issue 29920; Uncaught Expect.listEquals(list length, expected: <4>, actual: <3>) fails: Next element <*3>
10351035
async_star_pause_test: RuntimeError # Uncaught Expect.listEquals(at index 2, expected: <0+>, actual: <0!>) fails
1036-
async_star_test/01: RuntimeError
10371036
async_star_test/02: RuntimeError
1038-
async_star_test/03: RuntimeError
1039-
async_star_test/04: RuntimeError
1040-
async_star_test/05: RuntimeError
1041-
async_star_test/none: RuntimeError
10421037
bit_operations_test: RuntimeError # No bigints on web.; Expect.equals(expected: <-25>, actual: <4294967271>) fails.
10431038
branch_canonicalization_test: RuntimeError # Issue 29920; Expect.equals(expected: <0>, actual: <1>) fails.
10441039
call_closurization_test: RuntimeError # Issue 29920; TypeError: Cannot read property '0' of undefined
@@ -1091,7 +1086,6 @@ invocation_mirror_invoke_on_test: RuntimeError # UnimplementedError: JsInstanceM
10911086
invocation_mirror_test: RuntimeError # Type 'NativeJavaScriptObject' is not a subtype of type 'int' in strong mode
10921087
issue21159_test: RuntimeError # Issue 30701; TypeError: method.bind is not a function
10931088
issue23244_test: RuntimeError # Issue 29920; Uncaught Unsupported operation: only top-level functions can be spawned.
1094-
label_test: RuntimeError # Issue 30675; Expect.equals(expected: <111>, actual: <1>) fails.
10951089
lazy_static3_test: RuntimeError # Issue 30852; Expect.equals(expected: <null>, actual: <499>) fails.
10961090
lazy_static8_test: RuntimeError # Issue 30852; Expect.equals(expected: <42>, actual: <2>) fails.
10971091
least_upper_bound_expansive_test/none: RuntimeError # 30908; Uncaught RangeError: Maximum call stack size exceeded
@@ -1132,6 +1126,11 @@ switch_try_catch_test: RuntimeError # Issue 29920; Expect.throws: Unexpected 'Un
11321126
truncdiv_test: RuntimeError # Issue 29920; Expect.throws fails: Did not throw
11331127

11341128
[ $compiler == dartdevc && $runtime != none ]
1129+
async_star_test/01: RuntimeError
1130+
async_star_test/03: RuntimeError
1131+
async_star_test/04: RuntimeError
1132+
async_star_test/05: RuntimeError
1133+
async_star_test/none: RuntimeError
11351134
asyncstar_throw_in_catch_test: Skip # Times out. Issue 29920
11361135
await_future_test: Pass, Timeout # Issue 29920
11371136
bit_operations_test: RuntimeError # No bigints on web.
@@ -1152,6 +1151,7 @@ fuzzy_arrows_test/03: RuntimeError # Issue 29630
11521151
generic_method_types_test/02: RuntimeError
11531152
getter_closure_execution_order_test: RuntimeError # Issue 29920
11541153
implicit_downcast_during_compound_assignment_test: RuntimeError
1154+
label_test: RuntimeError
11551155
lazy_static3_test: RuntimeError # Issue 30852
11561156
lazy_static8_test: RuntimeError # Issue 30852
11571157
left_shift_test: RuntimeError # Ints and doubles are unified.
@@ -1192,16 +1192,12 @@ assertion_initializer_const_error2_test/cc11: RuntimeError # Assertion failed: "
11921192
async_throw_in_catch_test/forceAwait: RuntimeError # Uncaught Expect.equals(expected: <Error2>, actual: <Expect.equals(expected: <e>, actual: <c>) fails.>) fails.
11931193
async_throw_in_catch_test/none: RuntimeError # Uncaught Expect.equals(expected: <Error2>, actual: <Expect.equals(expected: <e>, actual: <c>) fails.>) fails.
11941194
asyncstar_throw_in_catch_test: RuntimeError # Uncaught Expect.equals(expected: <abcX>, actual: <abbcX>) fails.
1195-
await_for_cancel_test: Timeout
1196-
break_test: RuntimeError # Expect.equals(expected: <6>, actual: <10>) fails.
11971195
built_in_identifier_type_annotation_test/05: RuntimeError # TypeError: Cannot read property 'Symbol(dartx.toString)' of null
11981196
built_in_identifier_type_annotation_test/39: RuntimeError # TypeError: Cannot read property 'Symbol(dartx.toString)' of null
11991197
built_in_identifier_type_annotation_test/56: RuntimeError # TypeError: Cannot read property 'Symbol(dartx.toString)' of null
12001198
built_in_identifier_type_annotation_test/73: RuntimeError # TypeError: Cannot read property 'Symbol(dartx.toString)' of null
12011199
callable_test/none: RuntimeError # Expect.throws(TypeError) fails: Did not throw
12021200
checked_setter3_test: RuntimeError # Expect.throws(TypeError) fails: Did not throw
1203-
closure_break1_test: Timeout
1204-
closure_break2_test: Timeout
12051201
closure_in_constructor_test: RuntimeError # ReferenceError: VoidToListOfT is not defined
12061202
closure_type_variables_test: RuntimeError # ReferenceError: VoidToAOfT is not defined
12071203
closures_initializer_test: RuntimeError # ReferenceError: VoidToListOfT is not defined
@@ -1339,7 +1335,6 @@ string_interpolate_test: RuntimeError # Uncaught Type 'PrivateSymbol' is not a s
13391335
super_bound_closure_test/none: RuntimeError # TypeError: Cannot read property '0' of undefined
13401336
switch_test: RuntimeError # RangeError: Maximum call stack size exceeded
13411337
syncstar_yield_test/copyParameters: RuntimeError # Expect.equals(expected: <2>, actual: <3>) fails.
1342-
type_argument_in_super_type_test: RuntimeError # Expect.throws(TypeError) fails: Did not throw
13431338
type_literal_test: RuntimeError # Expect.equals(expected: <Func>, actual: <(bool) => int>) fails.
13441339
type_parameter_test/none: RuntimeError # ReferenceError: VoidToSetOfT is not defined
13451340
type_promotion_functions_test/02: RuntimeError

0 commit comments

Comments
 (0)