Use default type for type variable bounds.

Change-Id: I5d21a16a76eb6cd898e8e11104d0be0f7e669426
Reviewed-on: https://dart-review.googlesource.com/59420
Reviewed-by: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index c4419b5..738bd388 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -1455,6 +1455,12 @@
   /// `Object`.
   DartType getTypeVariableBound(TypeVariableEntity typeVariable);
 
+  /// The default type of the [typeVariable].
+  ///
+  /// This is the type used as the default type argument when no explicit type
+  /// argument is passed.
+  DartType getTypeVariableDefaultType(TypeVariableEntity typeVariable);
+
   /// Returns the type of [function].
   FunctionType getFunctionType(FunctionEntity function);
 
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 492adf3..d3267ab 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -170,7 +170,7 @@
           targetArguments[count++] = _rtiEncoder.getTypeRepresentation(
               _emitter,
               _closedWorld.elementEnvironment
-                  .getTypeVariableBound(typeVariable.element),
+                  .getTypeVariableDefaultType(typeVariable.element),
               (_) => _emitter.constantReference(new NullConstantValue()));
         } else {
           String jsName = '\$${typeVariable.element.name}';
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index e566ff0..ee5006d 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -682,6 +682,12 @@
     return data.getBound(this);
   }
 
+  DartType _getTypeVariableDefaultType(IndexedTypeVariable typeVariable) {
+    assert(checkFamily(typeVariable));
+    TypeVariableData data = _typeVariables.getData(typeVariable);
+    return data.getDefaultType(this);
+  }
+
   ClassEntity _getAppliedMixin(IndexedClass cls) {
     assert(checkFamily(cls));
     ClassData data = _classes.getData(cls);
@@ -1280,6 +1286,11 @@
     return super._getTypeVariableBound(typeVariable);
   }
 
+  DartType _getTypeVariableDefaultType(TypeVariableEntity typeVariable) {
+    if (typeVariable is KLocalTypeVariable) return typeVariable.defaultType;
+    return super._getTypeVariableDefaultType(typeVariable);
+  }
+
   @override
   void _forEachNestedClosure(
       MemberEntity member, void f(FunctionEntity closure)) {
@@ -1373,6 +1384,8 @@
       index = 0;
       for (ir.TypeParameter typeParameter in function.typeParameters) {
         typeVariables[index].bound = getDartType(typeParameter.bound);
+        typeVariables[index].defaultType =
+            getDartType(typeParameter.defaultType);
         index++;
       }
       localFunction.functionType = getFunctionType(function);
@@ -1488,6 +1501,11 @@
   }
 
   @override
+  DartType getTypeVariableDefaultType(TypeVariableEntity typeVariable) {
+    return elementMap._getTypeVariableDefaultType(typeVariable);
+  }
+
+  @override
   InterfaceType createInterfaceType(
       ClassEntity cls, List<DartType> typeArguments) {
     return new InterfaceType(cls, typeArguments);
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index dde76e85..dcef78f 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -1014,6 +1014,7 @@
 class TypeVariableData {
   final ir.TypeParameter node;
   DartType _bound;
+  DartType _defaultType;
 
   TypeVariableData(this.node);
 
@@ -1021,6 +1022,10 @@
     return _bound ??= elementMap.getDartType(node.bound);
   }
 
+  DartType getDefaultType(KernelToElementMap elementMap) {
+    return _defaultType ??= elementMap.getDartType(node.defaultType);
+  }
+
   TypeVariableData copy() {
     return new TypeVariableData(node);
   }
diff --git a/pkg/compiler/lib/src/kernel/kelements.dart b/pkg/compiler/lib/src/kernel/kelements.dart
index 3b18fbc..38d7dd6 100644
--- a/pkg/compiler/lib/src/kernel/kelements.dart
+++ b/pkg/compiler/lib/src/kernel/kelements.dart
@@ -293,6 +293,7 @@
   final String name;
   final int index;
   DartType bound;
+  DartType defaultType;
 
   KLocalTypeVariable(this.typeDeclaration, this.name, this.index);
 
diff --git a/tests/compiler/dart2js/generic_methods/generic_method_test.dart b/tests/compiler/dart2js/generic_methods/generic_method_test.dart
index e907015..ae1e4fd 100644
--- a/tests/compiler/dart2js/generic_methods/generic_method_test.dart
+++ b/tests/compiler/dart2js/generic_methods/generic_method_test.dart
@@ -113,8 +113,6 @@
   new Class2().method5<int>(0);
   new Class3().method6<int>(0);
   dynamic c3 = args != null ? new Class3() : new Class2();
-  // TODO(johnniwinther): Expected bounds should be `dynamic` when CFE supports
-  // instantiate-to-bound.
   c3.method6(0); // Missing type arguments.
   try {
     dynamic c2 = args == null ? new Class3() : new Class2();
@@ -162,8 +160,8 @@
 "foo" is int = false
 
 Class3.method6:
-0 is Object = true
-"foo" is Object = true
+0 is dynamic = true
+"foo" is dynamic = true
 
 Class2.method6:
 0 is int = true
diff --git a/tests/language_2/function_call_generic_test.dart b/tests/language_2/function_call_generic_test.dart
index b98584e..db40488 100644
--- a/tests/language_2/function_call_generic_test.dart
+++ b/tests/language_2/function_call_generic_test.dart
@@ -1,6 +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.
+// dart2jsOptions=-Ddart.isdart2js=true
 
 import "package:expect/expect.dart";
 
@@ -21,7 +22,8 @@
   print('a:  $expected');
   print('b:  $actual');
   if (((actual[0] == Object && expected[0] == dynamic) ||
-      (actual[0] == dynamic && expected[0] == Object))) {
+          (actual[0] == dynamic && expected[0] == Object)) &&
+      !const bool.fromEnvironment('dart.isdart2js')) {
     // TODO(32483): dartdevk sometimes defaults type to 'Object' when 'dynamic'
     // is required. Remove this hack when fixed.
     // TODO(31581): dart2js needs instantiate-to-bound to generic 'dynamic'