[dartdevc] Adding support for async operations in block expressions

Moving YieldFinder to shared_compiler


Change-Id: Id4d95447443929376f922005e10f66930630dfaf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97040
Reviewed-by: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Mark Zhou <markzipan@google.com>
diff --git a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
index 65cfe52..e911dca 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
@@ -4,7 +4,7 @@
 
 // TODO(jmesserly): import from its own package
 import '../js_ast/js_ast.dart';
-
+import 'shared_compiler.dart' show YieldFinder;
 import 'js_names.dart' show TemporaryId;
 
 /// A synthetic `let*` node, similar to that found in Scheme.
@@ -181,7 +181,7 @@
   }
 
   Expression _toInvokedFunction(Block block) {
-    var finder = _YieldFinder();
+    var finder = YieldFinder();
     block.accept(finder);
     if (!finder.hasYield) {
       return Call(ArrowFun([], block), []);
@@ -353,34 +353,3 @@
     if (!found) super.visitNode(node);
   }
 }
-
-class _YieldFinder extends BaseVisitor {
-  bool hasYield = false;
-  bool hasThis = false;
-  bool _nestedFunction = false;
-
-  @override
-  visitThis(This node) {
-    hasThis = true;
-  }
-
-  @override
-  visitFunctionExpression(FunctionExpression node) {
-    var savedNested = _nestedFunction;
-    _nestedFunction = true;
-    super.visitFunctionExpression(node);
-    _nestedFunction = savedNested;
-  }
-
-  @override
-  visitYield(Yield node) {
-    if (!_nestedFunction) hasYield = true;
-    super.visitYield(node);
-  }
-
-  @override
-  visitNode(Node node) {
-    if (hasYield && hasThis) return; // found both, nothing more to do.
-    super.visitNode(node);
-  }
-}
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index 66e0628..be9b13f 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -192,3 +192,34 @@
     if (!found) super.visitNode(node);
   }
 }
+
+class YieldFinder extends JS.BaseVisitor {
+  bool hasYield = false;
+  bool hasThis = false;
+  bool _nestedFunction = false;
+
+  @override
+  visitThis(JS.This node) {
+    hasThis = true;
+  }
+
+  @override
+  visitFunctionExpression(JS.FunctionExpression node) {
+    var savedNested = _nestedFunction;
+    _nestedFunction = true;
+    super.visitFunctionExpression(node);
+    _nestedFunction = savedNested;
+  }
+
+  @override
+  visitYield(JS.Yield node) {
+    if (!_nestedFunction) hasYield = true;
+    super.visitYield(node);
+  }
+
+  @override
+  visitNode(JS.Node node) {
+    if (hasYield && hasThis) return; // found both, nothing more to do.
+    super.visitNode(node);
+  }
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 160be8b..a2cba73 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5061,7 +5061,20 @@
         .map(_visitStatement)
         .toList()
           ..add(JS.Return(jsExpr));
-    return JS.Call(JS.ArrowFun([], JS.Block(jsStmts)), []);
+    var jsBlock = JS.Block(jsStmts);
+    // BlockExpressions with async operations must be constructed
+    // with a generator instead of a lambda.
+    var finder = YieldFinder();
+    jsBlock.accept(finder);
+    if (finder.hasYield) {
+      var genFn = JS.Fun([], jsBlock, isGenerator: true);
+      var asyncLibrary = emitLibraryName(coreTypes.asyncLibrary);
+      var returnType = _emitType(node.getStaticType(types));
+      var asyncCall =
+          js.call('#.async(#, #)', [asyncLibrary, returnType, genFn]);
+      return JS.Yield(asyncCall);
+    }
+    return JS.Call(JS.ArrowFun([], jsBlock), []);
   }
 
   @override