Add deferred test for local functions

Change-Id: I9f4b67de9435e74378af72d2a0c0fc711c0b0252
Reviewed-on: https://dart-review.googlesource.com/55891
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/tests/compiler/dart2js/deferred_loading/data/basic_deferred.dart b/tests/compiler/dart2js/deferred_loading/data/basic_deferred.dart
index b7d44ab..2c0951c 100644
--- a/tests/compiler/dart2js/deferred_loading/data/basic_deferred.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/basic_deferred.dart
@@ -4,6 +4,6 @@
 import '../libs/basic_deferred_lib.dart' deferred as lib;
 
 /*element: main:OutputUnit(main, {})*/
-main() => lib.loadLibrary().then((_) {
+main() => lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
       (lib.funky)();
     });
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_class.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_class.dart
index 0ded6cf..b688215 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_class.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_class.dart
@@ -6,7 +6,7 @@
 
 /*element: main:OutputUnit(main, {})*/
 main() {
-  lib.loadLibrary().then((_) {
+  lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     return new lib.MyClass().foo(87);
   });
 }
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_constant1.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_constant1.dart
index b3d820a..99f8444 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_constant1.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_constant1.dart
@@ -9,7 +9,7 @@
 main() async {
   C1.value;
   print(const C(4));
-  () => print(const C(5));
+  /*OutputUnit(main, {})*/ () => print(const C(5));
   await lib2.loadLibrary();
   lib2.C2.value;
   lib2.C3.value;
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_constant2.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_constant2.dart
index 9f82270..f8821ae 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_constant2.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_constant2.dart
@@ -8,7 +8,7 @@
 
 /*element: main:OutputUnit(main, {})*/
 main() {
-  lib.loadLibrary().then((_) {
+  lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     Expect.equals(499, lib.C1.value);
   });
 }
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_fail_and_retry.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_fail_and_retry.dart
index 819032b..80b59bf 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_fail_and_retry.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_fail_and_retry.dart
@@ -34,14 +34,14 @@
   ]);
 
   asyncStart();
-  lib.loadLibrary().then((_) {
+  lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     Expect.fail("Library should not have loaded");
-  }, onError: (error) {
-    lib.loadLibrary().then((_) {
+  }, onError: /*OutputUnit(main, {})*/ (error) {
+    lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
       Expect.equals("loaded", lib.foo());
-    }, onError: (error) {
+    }, onError: /*OutputUnit(main, {})*/ (error) {
       Expect.fail("Library should have loaded this time");
-    }).whenComplete(() {
+    }).whenComplete(/*OutputUnit(main, {})*/ () {
       asyncEnd();
     });
   });
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_function.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_function.dart
index d8895f7..6f809df 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_function.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_function.dart
@@ -14,7 +14,7 @@
 
 /*element: main:OutputUnit(main, {})*/
 main() {
-  lib.loadLibrary().then((_) {
+  lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     lib.foo('b');
     readFoo();
   });
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_overlapping.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_overlapping.dart
index ea2354b..754ee48 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_overlapping.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_overlapping.dart
@@ -8,9 +8,9 @@
 // lib1.C1 and lib2.C2 has a shared base class. It will go in its own hunk.
 /*element: main:OutputUnit(main, {})*/
 void main() {
-  lib1.loadLibrary().then((_) {
+  lib1.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     new lib1.C1();
-    lib2.loadLibrary().then((_) {
+    lib2.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
       new lib2.C2();
     });
   });
diff --git a/tests/compiler/dart2js/deferred_loading/data/dont_inline_deferred_global.dart b/tests/compiler/dart2js/deferred_loading/data/dont_inline_deferred_global.dart
index 58669a5..3e42dd2 100644
--- a/tests/compiler/dart2js/deferred_loading/data/dont_inline_deferred_global.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/dont_inline_deferred_global.dart
@@ -6,7 +6,7 @@
 
 /*element: main:OutputUnit(main, {})*/
 void main() {
-  lib.loadLibrary().then((_) {
+  lib.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
     print(lib.finalVar);
     print(lib.globalVar);
     lib.globalVar = "foobar";
diff --git a/tests/compiler/dart2js/deferred_loading/data/static_separate.dart b/tests/compiler/dart2js/deferred_loading/data/static_separate.dart
new file mode 100644
index 0000000..ac5b27d
--- /dev/null
+++ b/tests/compiler/dart2js/deferred_loading/data/static_separate.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2018, 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.
+
+// The class lib1.C is referenced via lib1
+// The static function lib1.C.foo is referenced via lib2
+// Dart2js will put them in separate hunks.
+// Similarly for C2, ..., C5.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+import "../libs/static_separate_lib1.dart" deferred as lib1;
+import "../libs/static_separate_lib2.dart" deferred as lib2;
+
+/*element: main:OutputUnit(main, {})*/
+void main() {
+  asyncStart();
+  Expect.throws(/*OutputUnit(main, {})*/ () => new lib1.C());
+  lib1.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
+    lib2.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
+      print("HERE");
+      Expect.equals(1, new lib1.C().bar());
+      var x = new lib1.C2();
+      Expect.mapEquals({1: 2}, x.bar);
+      x.bar = {2: 3};
+      Expect.mapEquals({2: 3}, x.bar);
+
+      Expect.equals(lib1.x, new lib1.C3().bar);
+      Expect.mapEquals({lib1.x: lib1.x}, new lib1.C4().bar);
+      Expect.equals(1, new lib1.C5().bar());
+
+      lib2.foo();
+      asyncEnd();
+    });
+  });
+}
diff --git a/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart b/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
index 8abed7c..cef5d1b 100644
--- a/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
+++ b/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
@@ -4,6 +4,7 @@
 
 import 'dart:io' hide Link;
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/closure.dart';
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/deferred_load.dart';
@@ -87,44 +88,73 @@
 void computeKernelOutputUnitData(
     Compiler compiler, MemberEntity member, Map<Id, ActualData> actualMap,
     {bool verbose: false}) {
-  OutputUnitData data = compiler.backend.outputUnitData;
-  String value = outputUnitString(data.outputUnitForEntity(member));
-
   KernelBackendStrategy backendStrategy = compiler.backendStrategy;
   KernelToElementMapForBuilding elementMap = backendStrategy.elementMap;
   MemberDefinition definition = elementMap.getMemberDefinition(member);
+  new TypeMaskIrComputer(
+          compiler.reporter,
+          actualMap,
+          elementMap,
+          member,
+          compiler.backend.outputUnitData,
+          backendStrategy.closureDataLookup as ClosureDataLookup<ir.Node>)
+      .run(definition.node);
+}
 
-  _registerValue(
-      computeEntityId(definition.node),
-      value,
-      member,
-      computeSourceSpanFromTreeNode(definition.node),
-      actualMap,
-      compiler.reporter);
+/// IR visitor for computing inference data for a member.
+class TypeMaskIrComputer extends IrDataExtractor {
+  final KernelToElementMapForBuilding _elementMap;
+  final OutputUnitData _data;
+  final ClosureDataLookup<ir.Node> _closureDataLookup;
 
-  ir.Member memberNode = definition.node;
-  if (memberNode is ir.Field && memberNode.isConst) {
-    ir.Expression node = memberNode.initializer;
-    ConstantValue constant = elementMap.getConstantValue(node);
-    if (constant.isPrimitive) return;
-    SourceSpan span = computeSourceSpanFromTreeNode(node);
-    if (node is ir.ConstructorInvocation ||
-        node is ir.ListLiteral ||
-        (node is ir.MapLiteral && node.keyType == null)) {
-      // Adjust the source-span to match the AST-based location. The kernel FE
-      // skips the "const" keyword for the expression offset and any prefix in
-      // front of the constructor. The "-6" is an approximation assuming that
-      // there is just a single space after "const" and no prefix.
-      // TODO(sigmund): offsets should be fixed in the FE instead.
-      span = new SourceSpan(span.uri, span.begin - 6, span.end - 6);
+  TypeMaskIrComputer(
+      DiagnosticReporter reporter,
+      Map<Id, ActualData> actualMap,
+      this._elementMap,
+      MemberEntity member,
+      this._data,
+      this._closureDataLookup)
+      : super(reporter, actualMap);
+
+  String getMemberValue(MemberEntity member) {
+    return outputUnitString(_data.outputUnitForEntity(member));
+  }
+
+  @override
+  String computeMemberValue(Id id, ir.Member node) {
+    if (node is ir.Field && node.isConst) {
+      ir.Expression initializer = node.initializer;
+      ConstantValue constant = _elementMap.getConstantValue(initializer);
+      if (!constant.isPrimitive) {
+        SourceSpan span = computeSourceSpanFromTreeNode(initializer);
+        if (initializer is ir.ConstructorInvocation) {
+          // Adjust the source-span to match the AST-based location. The kernel FE
+          // skips the "const" keyword for the expression offset and any prefix in
+          // front of the constructor. The "-6" is an approximation assuming that
+          // there is just a single space after "const" and no prefix.
+          // TODO(sigmund): offsets should be fixed in the FE instead.
+          span = new SourceSpan(span.uri, span.begin - 6, span.end - 6);
+        }
+        _registerValue(
+            new NodeId(span.begin, IdKind.node),
+            outputUnitString(_data.outputUnitForConstant(constant)),
+            node,
+            span,
+            actualMap,
+            reporter);
+      }
     }
-    _registerValue(
-        new NodeId(span.begin, IdKind.node),
-        outputUnitString(data.outputUnitForConstant(constant)),
-        member,
-        span,
-        actualMap,
-        compiler.reporter);
+
+    return getMemberValue(_elementMap.getMember(node));
+  }
+
+  @override
+  String computeNodeValue(Id id, ir.TreeNode node) {
+    if (node is ir.FunctionExpression || node is ir.FunctionDeclaration) {
+      ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node);
+      return getMemberValue(info.callMethod);
+    }
+    return null;
   }
 }
 
diff --git a/tests/compiler/dart2js/deferred_loading/libs/dont_inline_deferred_constants_main.dart b/tests/compiler/dart2js/deferred_loading/libs/dont_inline_deferred_constants_main.dart
index 494a35d..a8f56bd 100644
--- a/tests/compiler/dart2js/deferred_loading/libs/dont_inline_deferred_constants_main.dart
+++ b/tests/compiler/dart2js/deferred_loading/libs/dont_inline_deferred_constants_main.dart
@@ -22,8 +22,8 @@
 
 /*element: main:OutputUnit(main, {})*/
 void main() {
-  lib1.loadLibrary().then((_) {
-    lib2.loadLibrary().then((_) {
+  lib1.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
+    lib2.loadLibrary().then(/*OutputUnit(main, {})*/ (_) {
       lib1.foo();
       lib2.foo();
       print(lib1.C1);
diff --git a/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib1.dart b/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib1.dart
new file mode 100644
index 0000000..d95536e
--- /dev/null
+++ b/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib1.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2018, 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.
+
+library lib1;
+
+/*class: ConstClass:OutputUnit(2, {lib1, lib2})*/
+class ConstClass {
+  /*element: ConstClass.x:OutputUnit(2, {lib1, lib2})*/
+  final x;
+
+  /*element: ConstClass.:OutputUnit(2, {lib1, lib2})*/
+  const ConstClass(this.x);
+}
+
+/*element: x:OutputUnit(2, {lib1, lib2})*/
+var x = const ConstClass(const ConstClass(1));
+
+/*class: C:OutputUnit(1, {lib1})*/
+class C {
+  /*element: C.foo:OutputUnit(3, {lib2})*/
+  static foo() {
+    /*OutputUnit(3, {lib2})*/ () {}(); // Hack to avoid inlining.
+    return 1;
+  }
+
+  /*element: C.:OutputUnit(1, {lib1})*/
+  C();
+
+  /*element: C.bar:OutputUnit(1, {lib1})*/
+  bar() {
+    /*OutputUnit(1, {lib1})*/ () {}(); // Hack to avoid inlining.
+    return 1;
+  }
+}
+
+/*class: C1:OutputUnit(main, {})*/
+class C1 {
+  /*element: C1.foo:OutputUnit(3, {lib2})*/
+  static var foo = const {};
+  var bar = const {};
+}
+
+/*class: C2:OutputUnit(1, {lib1})*/
+class C2 {
+  /*element: C2.foo:OutputUnit(3, {lib2})*/
+  static var foo = new Map<int, int>.from({1: 2});
+
+  /*element: C2.bar:OutputUnit(1, {lib1})*/
+  var bar = new Map<int, int>.from({1: 2});
+
+  /*element: C2.:OutputUnit(1, {lib1})*/
+  C2();
+}
+
+/*class: C3:OutputUnit(1, {lib1})*/
+class C3 {
+  /*element: C3.foo:OutputUnit(3, {lib2})*/
+  static final foo = const ConstClass(const ConstClass(1));
+
+  /*element: C3.bar:OutputUnit(1, {lib1})*/
+  final bar = const ConstClass(const ConstClass(1));
+
+  /*element: C3.:OutputUnit(1, {lib1})*/
+  C3();
+}
+
+/*class: C4:OutputUnit(1, {lib1})*/
+class C4 {
+  /*element: C4.foo:OutputUnit(3, {lib2})*/
+  static final foo = new Map<ConstClass, ConstClass>.from({x: x});
+
+  /*element: C4.bar:OutputUnit(1, {lib1})*/
+  final bar = new Map<ConstClass, ConstClass>.from({x: x});
+
+  /*element: C4.:OutputUnit(1, {lib1})*/
+  C4();
+}
+
+/*class: C5:OutputUnit(1, {lib1})*/
+class C5 {
+  /*element: C5.foo:OutputUnit(3, {lib2})*/
+  static const foo = /*OutputUnit(3, {lib2})*/ const [
+    const {1: 3}
+  ];
+
+  /*element: C5.:OutputUnit(1, {lib1})*/
+  C5();
+
+  /*element: C5.bar:OutputUnit(1, {lib1})*/
+  bar() {
+    /*OutputUnit(1, {lib1})*/ () {}(); // Hack to avoid inlining.
+    return 1;
+  }
+}
diff --git a/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib2.dart b/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib2.dart
new file mode 100644
index 0000000..4358474
--- /dev/null
+++ b/tests/compiler/dart2js/deferred_loading/libs/static_separate_lib2.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, 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.
+
+library lib2;
+
+import "package:expect/expect.dart";
+import "static_separate_lib1.dart";
+
+/*element: foo:OutputUnit(3, {lib2})*/
+foo() {
+  Expect.equals(1, C.foo());
+  Expect.mapEquals({}, C1.foo);
+
+  Expect.mapEquals({1: 2}, C2.foo);
+  C2.foo = {1: 2};
+  Expect.mapEquals({1: 2}, C2.foo);
+
+  Expect.equals(x, C3.foo);
+  Expect.mapEquals({x: x}, C4.foo);
+  Expect.listEquals([
+    const {1: 3}
+  ], C5.foo);
+}
diff --git a/tests/compiler/dart2js/deferred_loading/libs/type_argument_dependency_lib1.dart b/tests/compiler/dart2js/deferred_loading/libs/type_argument_dependency_lib1.dart
index 37095d3..d785ac6 100644
--- a/tests/compiler/dart2js/deferred_loading/libs/type_argument_dependency_lib1.dart
+++ b/tests/compiler/dart2js/deferred_loading/libs/type_argument_dependency_lib1.dart
@@ -5,4 +5,4 @@
 import 'type_argument_dependency_lib2.dart';
 
 /*element: doCast:OutputUnit(main, {})*/
-doCast(List<dynamic> l) => l.cast<B>().map((x) => 1);
+doCast(List<dynamic> l) => l.cast<B>().map(/*OutputUnit(main, {})*/ (x) => 1);
diff --git a/tests/compiler/dart2js/inference/inference_test_helper.dart b/tests/compiler/dart2js/inference/inference_test_helper.dart
index a116e44..4094778 100644
--- a/tests/compiler/dart2js/inference/inference_test_helper.dart
+++ b/tests/compiler/dart2js/inference/inference_test_helper.dart
@@ -106,7 +106,7 @@
       .run(definition.node);
 }
 
-/// AST visitor for computing inference data for a member.
+/// IR visitor for computing inference data for a member.
 class TypeMaskIrComputer extends IrDataExtractor
     with ComputeValueMixin<ir.Node> {
   final GlobalTypeInferenceResults<ir.Node> results;