[vm] Instantiate type parameter bounds on closures.

Fixes #34308.

Change-Id: I7d998daa752ada13368631fc327a5c3595ec406c
Reviewed-on: https://dart-review.googlesource.com/72160
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 9439ecc..593ea86 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7131,11 +7131,50 @@
 
   Function& sig = Function::Handle(Function::NewSignatureFunction(
       owner, parent, TokenPosition::kNoSource, space));
+  AbstractType& type = AbstractType::Handle(zone);
+
+  // Copy the type parameters and instantiate their bounds (if necessary).
   if (!delete_type_parameters) {
-    sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters()));
+    const TypeArguments& type_params =
+        TypeArguments::Handle(zone, type_parameters());
+    if (!type_params.IsNull()) {
+      TypeArguments& instantiated_type_params = TypeArguments::Handle(zone);
+      TypeParameter& type_param = TypeParameter::Handle(zone);
+      Class& cls = Class::Handle(zone);
+      String& param_name = String::Handle(zone);
+      for (intptr_t i = 0; i < type_params.Length(); ++i) {
+        type_param ^= type_params.TypeAt(i);
+        type = type_param.bound();
+        if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
+          type = type.InstantiateFrom(
+              instantiator_type_arguments, function_type_arguments,
+              num_free_fun_type_params, NULL, NULL, NULL, space);
+          cls = type_param.parameterized_class();
+          param_name = type_param.name();
+          ASSERT(type_param.IsFinalized());
+          type_param ^=
+              TypeParameter::New(cls, sig, type_param.index(), param_name, type,
+                                 type_param.token_pos());
+          type_param.SetIsFinalized();
+          if (instantiated_type_params.IsNull()) {
+            instantiated_type_params = TypeArguments::New(type_params.Length());
+            for (intptr_t j = 0; j < i; ++j) {
+              type = type_params.TypeAt(j);
+              instantiated_type_params.SetTypeAt(j, type);
+            }
+          }
+          instantiated_type_params.SetTypeAt(i, type_param);
+        } else if (!instantiated_type_params.IsNull()) {
+          instantiated_type_params.SetTypeAt(i, type_param);
+        }
+      }
+      sig.set_type_parameters(instantiated_type_params.IsNull()
+                                  ? type_params
+                                  : instantiated_type_params);
+    }
   }
 
-  AbstractType& type = AbstractType::Handle(zone, result_type());
+  type = result_type();
   if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
     type = type.InstantiateFrom(
         instantiator_type_arguments, function_type_arguments,
@@ -7888,6 +7927,15 @@
       return false;
     }
   }
+  TypeArguments& type_params = TypeArguments::Handle(type_parameters());
+  TypeParameter& type_param = TypeParameter::Handle();
+  for (intptr_t i = 0; i < type_params.Length(); ++i) {
+    type_param ^= type_params.TypeAt(i);
+    type = type_param.bound();
+    if (!type.IsInstantiated(genericity, num_free_fun_type_params, trail)) {
+      return false;
+    }
+  }
   return true;
 }
 
diff --git a/tests/language_2/tearoff_bounds_instantiation_test.dart b/tests/language_2/tearoff_bounds_instantiation_test.dart
new file mode 100644
index 0000000..b823c64
--- /dev/null
+++ b/tests/language_2/tearoff_bounds_instantiation_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.
+//
+// This test checks that the type parameter bounds on tearoffs from generic
+// classes are properly instantiated in the signature of the tearoff.
+
+import "package:expect/expect.dart";
+
+class C<T> {
+  void foo<S extends T>(S x) {}
+}
+
+void foo<S extends int>(S x) {}
+
+void main() {
+  dynamic c = C<int>();
+  dynamic fn = c.foo;
+  Expect.equals("${fn.runtimeType}", "${foo.runtimeType}");
+}