[kernel] Account for defaultType in some of the Kernel visitors

Fixes #33324

Bug: http://dartbug.com/33324
Change-Id: I6c6a503a1fe016d7a8743df1597660c979ce27ea
Reviewed-on: https://dart-review.googlesource.com/58720
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/testcases/inference/bug33324.dart b/pkg/front_end/testcases/inference/bug33324.dart
new file mode 100644
index 0000000..cdce5f17
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart
@@ -0,0 +1,15 @@
+// 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 greatest closure uses 'dynamic' and not Object as
+// the top type.
+
+int foo() {
+  Function f = (x) => x;
+  var l = ["bar"].map(f).toList();
+  l.add(42);
+  return l.first.length;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/inference/bug33324.dart.direct.expect b/pkg/front_end/testcases/inference/bug33324.dart.direct.expect
new file mode 100644
index 0000000..2e1ecb9
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart.direct.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+  core::Function f = (dynamic x) → dynamic => x;
+  dynamic l = <dynamic>["bar"].map(f).toList();
+  l.add(42);
+  return l.first.length;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/bug33324.dart.direct.transformed.expect b/pkg/front_end/testcases/inference/bug33324.dart.direct.transformed.expect
new file mode 100644
index 0000000..2e1ecb9
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart.direct.transformed.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+  core::Function f = (dynamic x) → dynamic => x;
+  dynamic l = <dynamic>["bar"].map(f).toList();
+  l.add(42);
+  return l.first.length;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/bug33324.dart.outline.expect b/pkg/front_end/testcases/inference/bug33324.dart.outline.expect
new file mode 100644
index 0000000..06c9cfc
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/inference/bug33324.dart.strong.expect b/pkg/front_end/testcases/inference/bug33324.dart.strong.expect
new file mode 100644
index 0000000..f88135b
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart.strong.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+  core::Function f = (dynamic x) → dynamic => x;
+  core::List<dynamic> l = <core::String>["bar"].{core::Iterable::map}<dynamic>(f as{TypeError} (core::String) → dynamic).{core::Iterable::toList}();
+  l.{core::List::add}(42);
+  return l.{core::Iterable::first}.length as{TypeError} core::int;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/bug33324.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/bug33324.dart.strong.transformed.expect
new file mode 100644
index 0000000..f88135b
--- /dev/null
+++ b/pkg/front_end/testcases/inference/bug33324.dart.strong.transformed.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+  core::Function f = (dynamic x) → dynamic => x;
+  core::List<dynamic> l = <core::String>["bar"].{core::Iterable::map}<dynamic>(f as{TypeError} (core::String) → dynamic).{core::Iterable::toList}();
+  l.{core::List::add}(42);
+  return l.{core::Iterable::first}.length as{TypeError} core::int;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
index e3ccda9..e9adaf2 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
@@ -10,6 +10,6 @@
     return (self::C::T y) → core::Null {};
 }
 static method test(self::C<core::String> c) → void {
-  (core::int) → (core::String) → void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object>(U) → (core::String) → void<core::int>;
+  (core::int) → (core::String) → void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object = dynamic>(U) → (core::String) → void<core::int>;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
index e3ccda9..e9adaf2 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
@@ -10,6 +10,6 @@
     return (self::C::T y) → core::Null {};
 }
 static method test(self::C<core::String> c) → void {
-  (core::int) → (core::String) → void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object>(U) → (core::String) → void<core::int>;
+  (core::int) → (core::String) → void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object = dynamic>(U) → (core::String) → void<core::int>;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.direct.expect b/pkg/front_end/testcases/regress/issue_30838.dart.direct.expect
index 9e4af92..9efb697 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.direct.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object = dynamic> = <T extends core::Object = dynamic>(T) → S;
 class A extends core::Object {
-  field <T extends core::Object>(T) → core::int f = null;
+  field <T extends core::Object = dynamic>(T) → core::int f = null;
   synthetic constructor •() → void
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object = dynamic>(self::foo::T x) → core::int
   return 3;
-static method bar() → <T extends core::Object>(T) → core::int
+static method bar() → <T extends core::Object = dynamic>(T) → core::int
   return self::foo;
 static method test1() → void {
   self::bar().call<core::String>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_30838.dart.direct.transformed.expect
index 9e4af92..9efb697 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.direct.transformed.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object = dynamic> = <T extends core::Object = dynamic>(T) → S;
 class A extends core::Object {
-  field <T extends core::Object>(T) → core::int f = null;
+  field <T extends core::Object = dynamic>(T) → core::int f = null;
   synthetic constructor •() → void
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object = dynamic>(self::foo::T x) → core::int
   return 3;
-static method bar() → <T extends core::Object>(T) → core::int
+static method bar() → <T extends core::Object = dynamic>(T) → core::int
   return self::foo;
 static method test1() → void {
   self::bar().call<core::String>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
index 55709ba..10ab505 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object = dynamic> = <T extends core::Object = dynamic>(T) → S;
 class A extends core::Object {
-  field <T extends core::Object>(T) → core::int f;
+  field <T extends core::Object = dynamic>(T) → core::int f;
   synthetic constructor •() → void
     ;
   method test() → void
@@ -12,7 +12,7 @@
 }
 static method foo<T extends core::Object = dynamic>(self::foo::T x) → core::int
   ;
-static method bar() → <T extends core::Object>(T) → core::int
+static method bar() → <T extends core::Object = dynamic>(T) → core::int
   ;
 static method test1() → void
   ;
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
index f08b8e7..7526f86 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object = dynamic> = <T extends core::Object = dynamic>(T) → S;
 class A extends core::Object {
-  field <T extends core::Object>(T) → core::int f = null;
+  field <T extends core::Object = dynamic>(T) → core::int f = null;
   synthetic constructor •() → void
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object = dynamic>(self::foo::T x) → core::int
   return 3;
-static method bar() → <T extends core::Object>(T) → core::int
+static method bar() → <T extends core::Object = dynamic>(T) → core::int
   return self::foo;
 static method test1() → void {
   self::bar().call<core::String>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
index f08b8e7..7526f86 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object = dynamic> = <T extends core::Object = dynamic>(T) → S;
 class A extends core::Object {
-  field <T extends core::Object>(T) → core::int f = null;
+  field <T extends core::Object = dynamic>(T) → core::int f = null;
   synthetic constructor •() → void
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object = dynamic>(self::foo::T x) → core::int
   return 3;
-static method bar() → <T extends core::Object>(T) → core::int
+static method bar() → <T extends core::Object = dynamic>(T) → core::int
   return self::foo;
 static method test1() → void {
   self::bar().call<core::String>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.direct.expect b/pkg/front_end/testcases/regress/issue_31213.dart.direct.expect
index a54adf0..da2a301 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.direct.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object = dynamic, K extends core::Object = dynamic> = <B extends core::Object = dynamic>(A, K, B) → core::int;
-typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object>(A, K, B) → core::int;
+typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, K, B) → core::int;
 static method producer<K extends core::Object = dynamic>() → dynamic {
   return <A extends core::Object = dynamic>(core::int v1) → dynamic {
     return <B extends core::Object = dynamic>(A v2, self::producer::K v3, B v4) → dynamic => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String>() is <A extends core::Object>(core::int) → <B extends core::Object>(A, core::String, B) → core::int);
+  assert(self::producer<core::String>() is <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, core::String, B) → core::int);
 }
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_31213.dart.direct.transformed.expect
index a54adf0..da2a301 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.direct.transformed.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object = dynamic, K extends core::Object = dynamic> = <B extends core::Object = dynamic>(A, K, B) → core::int;
-typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object>(A, K, B) → core::int;
+typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, K, B) → core::int;
 static method producer<K extends core::Object = dynamic>() → dynamic {
   return <A extends core::Object = dynamic>(core::int v1) → dynamic {
     return <B extends core::Object = dynamic>(A v2, self::producer::K v3, B v4) → dynamic => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String>() is <A extends core::Object>(core::int) → <B extends core::Object>(A, core::String, B) → core::int);
+  assert(self::producer<core::String>() is <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, core::String, B) → core::int);
 }
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
index 2626a19..a1d78e7 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object = dynamic, K extends core::Object = dynamic> = <B extends core::Object = dynamic>(A, K, B) → core::int;
-typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object>(A, K, B) → core::int;
+typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, K, B) → core::int;
 static method producer<K extends core::Object = dynamic>() → dynamic
   ;
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
index 730da9b..2bb9fe5 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object = dynamic, K extends core::Object = dynamic> = <B extends core::Object = dynamic>(A, K, B) → core::int;
-typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object>(A, K, B) → core::int;
+typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, K, B) → core::int;
 static method producer<K extends core::Object = dynamic>() → dynamic {
   return <A extends core::Object = dynamic>(core::int v1) → <B extends core::Object = dynamic>(A, self::producer::K, B) → core::int {
     return <B extends core::Object = dynamic>(A v2, self::producer::K v3, B v4) → core::int => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String>() is <A extends core::Object>(core::int) → <B extends core::Object>(A, core::String, B) → core::int);
+  assert(self::producer<core::String>() is <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, core::String, B) → core::int);
 }
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
index 730da9b..2bb9fe5 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object = dynamic, K extends core::Object = dynamic> = <B extends core::Object = dynamic>(A, K, B) → core::int;
-typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object>(A, K, B) → core::int;
+typedef D<K extends core::Object = dynamic> = <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, K, B) → core::int;
 static method producer<K extends core::Object = dynamic>() → dynamic {
   return <A extends core::Object = dynamic>(core::int v1) → <B extends core::Object = dynamic>(A, self::producer::K, B) → core::int {
     return <B extends core::Object = dynamic>(A v2, self::producer::K v3, B v4) → core::int => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String>() is <A extends core::Object>(core::int) → <B extends core::Object>(A, core::String, B) → core::int);
+  assert(self::producer<core::String>() is <A extends core::Object = dynamic>(core::int) → <B extends core::Object = dynamic>(A, core::String, B) → core::int);
 }
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 821f9d5..8b47a74 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -229,12 +229,9 @@
   }
   for (int i = 0; i < typeParameters.length; ++i) {
     freshParameters[i].bound = substitute(typeParameters[i].bound, map);
-
-    // [defaultType] is populated using instantiate-to-bound algorithm, so it
-    // shouldn't refer to type parameters from the same declaration.  However,
-    // if a transformation changes [defaultType], it may get such references,
-    // and the line below should invoke [substitute], like for [bound] above.
-    freshParameters[i].defaultType = typeParameters[i].defaultType;
+    freshParameters[i].defaultType = typeParameters[i].defaultType != null
+        ? substitute(typeParameters[i].defaultType, map)
+        : null;
   }
   return new FreshTypeParameters(freshParameters, Substitution.fromMap(map));
 }
@@ -479,6 +476,9 @@
     var fresh = new TypeParameter(node.name);
     substitution[node] = new TypeParameterType(fresh);
     fresh.bound = visit(node.bound);
+    if (node.defaultType != null) {
+      fresh.defaultType = visit(node.defaultType);
+    }
     return fresh;
   }
 }
@@ -846,7 +846,9 @@
 
   bool handleTypeParameter(TypeParameter node) {
     assert(!variables.contains(node));
-    return node.bound.accept(this);
+    if (node.bound.accept(this)) return true;
+    if (node.defaultType == null) return false;
+    return node.defaultType.accept(this);
   }
 }
 
@@ -882,6 +884,7 @@
   visitFunctionType(FunctionType node) {
     for (TypeParameter typeParameter in node.typeParameters) {
       typeParameter.bound.accept(this);
+      typeParameter.defaultType?.accept(this);
     }
     for (DartType parameter in node.positionalParameters) {
       parameter.accept(this);