[dart2js] Skip lowering async functions with await...for loops.
These loops introduce control flow that is more complex and harder to represent with Futures.
Tests are back to their state prior to the start of the async/await lowering changes. (The one failing test was already timing out)
Change-Id: Ia65f1a11bd73f2a30e7a186d69c34774c9e361a1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240381
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
diff --git a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
index 8f60070..1f5e31b 100644
--- a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
@@ -11,6 +11,7 @@
class _FunctionData {
final List<AwaitExpression> awaits = [];
final Set<ReturnStatement> returnStatements = {};
+ bool hasAsyncLoop = false;
_FunctionData();
@@ -34,7 +35,7 @@
AsyncLowering(this._coreTypes);
bool _shouldTryAsyncLowering(FunctionNode node) =>
- node.asyncMarker == AsyncMarker.Async;
+ node.asyncMarker == AsyncMarker.Async && !_functions.last.hasAsyncLoop;
void enterFunction(FunctionNode node) {
_functions.add(_FunctionData());
@@ -134,4 +135,10 @@
void visitReturnStatement(ReturnStatement statement) {
_functions.last.returnStatements.add(statement);
}
+
+ void visitForInStatement(ForInStatement statement) {
+ if (statement.isAsync && _functions.isNotEmpty) {
+ _functions.last.hasAsyncLoop = true;
+ }
+ }
}
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
index ba289ae..b90f526 100644
--- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -107,4 +107,11 @@
statement.transformChildren(this);
return statement;
}
+
+ @override
+ TreeNode visitForInStatement(ForInStatement statement) {
+ _asyncLowering?.visitForInStatement(statement);
+ statement.transformChildren(this);
+ return statement;
+ }
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
index bbef654..e19523f 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
@@ -8,7 +8,14 @@
return (await 6) + 3;
}
+Future<void> foo3() async {
+ await for (final x in Stream.empty()) {
+ break;
+ }
+}
+
void main() {
foo1();
foo2();
+ foo3();
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
index eb616ff..f3422b1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
@@ -9,7 +9,14 @@
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
return (await 6).{core::num::+}(3){(core::num) → core::int};
}
+static method foo3() → asy::Future<void> async /* futureValueType= void */ {
+ #L1:
+ await for (final dynamic x in new asy::_EmptyStream::•<dynamic>()) {
+ break #L1;
+ }
+}
static method main() → void {
self::foo1();
self::foo2();
+ self::foo3();
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
index eb616ff..f3422b1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
@@ -9,7 +9,14 @@
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
return (await 6).{core::num::+}(3){(core::num) → core::int};
}
+static method foo3() → asy::Future<void> async /* futureValueType= void */ {
+ #L1:
+ await for (final dynamic x in new asy::_EmptyStream::•<dynamic>()) {
+ break #L1;
+ }
+}
static method main() → void {
self::foo1();
self::foo2();
+ self::foo3();
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
index 06a5c0d..c9ebdd9 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
@@ -1,3 +1,4 @@
Future<void> foo1() async {}
Future<int> foo2() async {}
+Future<void> foo3() async {}
void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
index 4ab99eed..4ab2b8a 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
@@ -1,3 +1,4 @@
Future<int> foo2() async {}
Future<void> foo1() async {}
+Future<void> foo3() async {}
void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
index eb616ff..f3422b1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
@@ -9,7 +9,14 @@
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
return (await 6).{core::num::+}(3){(core::num) → core::int};
}
+static method foo3() → asy::Future<void> async /* futureValueType= void */ {
+ #L1:
+ await for (final dynamic x in new asy::_EmptyStream::•<dynamic>()) {
+ break #L1;
+ }
+}
static method main() → void {
self::foo1();
self::foo2();
+ self::foo3();
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
index eb616ff..f3422b1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
@@ -9,7 +9,14 @@
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
return (await 6).{core::num::+}(3){(core::num) → core::int};
}
+static method foo3() → asy::Future<void> async /* futureValueType= void */ {
+ #L1:
+ await for (final dynamic x in new asy::_EmptyStream::•<dynamic>()) {
+ break #L1;
+ }
+}
static method main() → void {
self::foo1();
self::foo2();
+ self::foo3();
}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
index 85b14b9..0c508d4 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
@@ -7,5 +7,7 @@
;
static method foo2() → asy::Future<core::int> async
;
+static method foo3() → asy::Future<void> async
+ ;
static method main() → void
;
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
index eb616ff..f3422b1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
@@ -9,7 +9,14 @@
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
return (await 6).{core::num::+}(3){(core::num) → core::int};
}
+static method foo3() → asy::Future<void> async /* futureValueType= void */ {
+ #L1:
+ await for (final dynamic x in new asy::_EmptyStream::•<dynamic>()) {
+ break #L1;
+ }
+}
static method main() → void {
self::foo1();
self::foo2();
+ self::foo3();
}