Add closure signature to dependencies

Adds these missing dependencies to the deferred loading partition:

1. Signature of a local function / closure.
2. Bounds of type variables.

TBR=johnniwinther@google.com

Change-Id: I201d08cf874381e58e161d2f910b60d83932968c
Reviewed-on: https://dart-review.googlesource.com/71120
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 5f32672..c176d1d 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -20,6 +20,7 @@
         InstantiationConstantValue;
 import 'elements/types.dart';
 import 'elements/entities.dart';
+import 'kernel/kelements.dart' show KLocalFunction;
 import 'library_loader.dart';
 import 'universe/use.dart';
 import 'universe/world_impact.dart'
@@ -278,16 +279,7 @@
     // TODO(het): we would like to separate out types that are only needed for
     // rti from types that are needed for their members.
     if (type is FunctionType) {
-      for (DartType argumentType in type.parameterTypes) {
-        _collectTypeDependencies(argumentType, dependencies);
-      }
-      for (DartType argumentType in type.optionalParameterTypes) {
-        _collectTypeDependencies(argumentType, dependencies);
-      }
-      for (DartType argumentType in type.namedParameterTypes) {
-        _collectTypeDependencies(argumentType, dependencies);
-      }
-      _collectTypeDependencies(type.returnType, dependencies);
+      _collectFunctionTypeDependencies(type, dependencies);
     } else if (type is TypedefType) {
       type.typeArguments
           .forEach((t) => _collectTypeDependencies(t, dependencies));
@@ -299,6 +291,23 @@
     }
   }
 
+  void _collectFunctionTypeDependencies(
+      FunctionType type, Dependencies dependencies) {
+    for (FunctionTypeVariable typeVariable in type.typeVariables) {
+      _collectTypeDependencies(typeVariable.bound, dependencies);
+    }
+    for (DartType argumentType in type.parameterTypes) {
+      _collectTypeDependencies(argumentType, dependencies);
+    }
+    for (DartType argumentType in type.optionalParameterTypes) {
+      _collectTypeDependencies(argumentType, dependencies);
+    }
+    for (DartType argumentType in type.namedParameterTypes) {
+      _collectTypeDependencies(argumentType, dependencies);
+    }
+    _collectTypeDependencies(type.returnType, dependencies);
+  }
+
   /// Extract any dependencies that are known from the impact of [element].
   void _collectDependenciesFromImpact(
       MemberEntity element, Dependencies dependencies) {
@@ -307,14 +316,17 @@
         element,
         worldImpact,
         new WorldImpactVisitorImpl(visitStaticUse: (StaticUse staticUse) {
-          if (staticUse.element is MemberEntity) {
-            dependencies.members.add(staticUse.element);
+          Entity usedEntity = staticUse.element;
+          if (usedEntity is MemberEntity) {
+            dependencies.members.add(usedEntity);
           } else {
-            assert(
-                staticUse.element is Local,
-                failedAt(
-                    staticUse.element, "Unexpected static use $staticUse."));
-            dependencies.localFunctions.add(staticUse.element);
+            assert(usedEntity is KLocalFunction,
+                failedAt(usedEntity, "Unexpected static use $staticUse."));
+            KLocalFunction localFunction = usedEntity;
+            // TODO(sra): Consult KClosedWorld to see if signature is needed.
+            _collectFunctionTypeDependencies(
+                localFunction.functionType, dependencies);
+            dependencies.localFunctions.add(localFunction);
           }
           switch (staticUse.kind) {
             case StaticUseKind.CONSTRUCTOR_INVOKE:
diff --git a/tests/compiler/dart2js_extra/deferred/34219_bounds_lib1.dart b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib1.dart
new file mode 100644
index 0000000..81bf0ae
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib1.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// Part of 34219_bounds_test.dart
+
+import '34219_bounds_lib2.dart';
+
+class SystemMessage extends GeneratedMessage {}
+
+var g;
+
+test1() {
+  new GeneratedMessage();
+  g = (<T extends SystemMessage>(T a, T b) => a == b);
+}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_bounds_lib2.dart b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib2.dart
new file mode 100644
index 0000000..7726460
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib2.dart
@@ -0,0 +1,7 @@
+// 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.
+
+// Part of 34219_bounds_test.dart
+
+class GeneratedMessage {}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_bounds_lib3.dart b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib3.dart
new file mode 100644
index 0000000..a567162
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_bounds_lib3.dart
@@ -0,0 +1,14 @@
+// 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.
+
+// Part of 34219_bounds_test.dart
+//
+// This library places GeneratedMessage into a different partition to
+// SystemMessage.
+
+import '34219_bounds_lib2.dart';
+
+test3() {
+  new GeneratedMessage();
+}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_bounds_test.dart b/tests/compiler/dart2js_extra/deferred/34219_bounds_test.dart
new file mode 100644
index 0000000..67b77d9
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_bounds_test.dart
@@ -0,0 +1,20 @@
+// 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.
+// dart2jsOptions=--omit-implicit-checks
+
+// Tests that generic function type bounds are walked as dependencies of a
+// closure. If the generic function bounds are not visited, SystemMessage is
+// placed in the main unit while it's superclass GeneratedMessage is placed in a
+// deferred part.
+
+import '34219_bounds_lib1.dart' deferred as lib1;
+import '34219_bounds_lib3.dart' deferred as lib3;
+
+main() async {
+  await lib1.loadLibrary();
+  lib1.test1();
+  await lib3.loadLibrary();
+  lib3.test3();
+  if (lib1.g is bool Function(Object, Object)) print('!');
+}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_signature_lib1.dart b/tests/compiler/dart2js_extra/deferred/34219_signature_lib1.dart
new file mode 100644
index 0000000..b3493bd
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_signature_lib1.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// Part of 34219_signature_test.dart
+
+import '34219_signature_lib2.dart';
+
+class SystemMessage extends GeneratedMessage {}
+
+var g;
+
+test1() {
+  new GeneratedMessage();
+  g = (SystemMessage a, SystemMessage b) => a == b;
+}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_signature_lib2.dart b/tests/compiler/dart2js_extra/deferred/34219_signature_lib2.dart
new file mode 100644
index 0000000..e702fe6
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_signature_lib2.dart
@@ -0,0 +1,7 @@
+// 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.
+
+// Part of 34219_signature_test.dart
+
+class GeneratedMessage {}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_signature_lib3.dart b/tests/compiler/dart2js_extra/deferred/34219_signature_lib3.dart
new file mode 100644
index 0000000..35915d5
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_signature_lib3.dart
@@ -0,0 +1,14 @@
+// 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.
+
+// Part of 34219_signature_test.dart
+//
+// This library places GeneratedMessage into a different partition to
+// SystemMessage.
+
+import '34219_signature_lib2.dart';
+
+test3() {
+  new GeneratedMessage();
+}
diff --git a/tests/compiler/dart2js_extra/deferred/34219_signature_test.dart b/tests/compiler/dart2js_extra/deferred/34219_signature_test.dart
new file mode 100644
index 0000000..d6c2c05
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/34219_signature_test.dart
@@ -0,0 +1,19 @@
+// 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.
+// dart2jsOptions=--omit-implicit-checks
+
+// Tests that closure signatures are walked as dependencies of a closure. If the
+// signature of the closure is not visited, SystemMessage is placed in the main
+// unit while it's superclass GeneratedMessage is placed in a deferred part.
+
+import '34219_signature_lib1.dart' deferred as lib1;
+import '34219_signature_lib3.dart' deferred as lib3;
+
+main() async {
+  await lib1.loadLibrary();
+  lib1.test1();
+  await lib3.loadLibrary();
+  lib3.test3();
+  if (lib1.g is bool Function(Object, Object)) print('!');
+}