Version 2.14.0-249.0.dev

Merge commit '2a3e884c80dff9ade28dda397d726ee66c8e5332' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f32243e..94b1829 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,9 @@
 
 ### `dart:html`
 
-* [#44319][]: `convertNativeToDart_Dictionary()` now converts objects
-  recursively, this fixes APIs like MediaStreamTrack.getCapabilities
-  that convert between Maps and browser Dictionaries.
+*   [#44319][]: `convertNativeToDart_Dictionary()` now converts objects
+    recursively, this fixes APIs like MediaStreamTrack.getCapabilities
+    that convert between Maps and browser Dictionaries.
 
 [44319]: (https://github.com/dart-lang/sdk/issues/44319)
 
@@ -23,6 +23,8 @@
 
 #### `dart:core`
 
+*   Introduce `Enum` interface implemented by all `enum` declarations.
+
 *   The native `DateTime` class now better handles local time around
     daylight saving changes that are not precisely one hour.
     (No change on the Web which uses the JavaScript `Date` object.)
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 73824a7..1229ded 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -5176,6 +5176,64 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(int count, int count2)>
+    templateInstantiationTooFewArguments =
+    const Template<Message Function(int count, int count2)>(
+        messageTemplate:
+            r"""Too few type arguments: #count required, #count2 given.""",
+        tipTemplate: r"""Try adding the missing type arguments.""",
+        withArguments: _withArgumentsInstantiationTooFewArguments);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(int count, int count2)>
+    codeInstantiationTooFewArguments =
+    const Code<Message Function(int count, int count2)>(
+  "InstantiationTooFewArguments",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInstantiationTooFewArguments(int count, int count2) {
+  // ignore: unnecessary_null_comparison
+  if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
+  if (count2 == null) throw 'No count provided';
+  return new Message(codeInstantiationTooFewArguments,
+      message:
+          """Too few type arguments: ${count} required, ${count2} given.""",
+      tip: """Try adding the missing type arguments.""",
+      arguments: {'count': count, 'count2': count2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(int count, int count2)>
+    templateInstantiationTooManyArguments =
+    const Template<Message Function(int count, int count2)>(
+        messageTemplate:
+            r"""Too many type arguments: #count allowed, but #count2 found.""",
+        tipTemplate: r"""Try removing the extra type arguments.""",
+        withArguments: _withArgumentsInstantiationTooManyArguments);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(int count, int count2)>
+    codeInstantiationTooManyArguments =
+    const Code<Message Function(int count, int count2)>(
+  "InstantiationTooManyArguments",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInstantiationTooManyArguments(int count, int count2) {
+  // ignore: unnecessary_null_comparison
+  if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
+  if (count2 == null) throw 'No count provided';
+  return new Message(codeInstantiationTooManyArguments,
+      message:
+          """Too many type arguments: ${count} allowed, but ${count2} found.""",
+      tip: """Try removing the extra type arguments.""",
+      arguments: {'count': count, 'count2': count2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         String
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_in/core.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_in/core.dart
index da9e41a..79f1f75 100644
--- a/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_in/core.dart
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_in/core.dart
@@ -24,6 +24,9 @@
   String toString() => '';
 }
 
+/*class: Enum:Enum,Object*/
+abstract class Enum {}
+
 /*class: Null:Null,Object*/
 class Null {
   factory Null._uninstantiable() {
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_out/core.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_out/core.dart
index 0df65e1..2682390 100644
--- a/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_out/core.dart
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/object_opt_out/core.dart
@@ -26,6 +26,9 @@
   String toString() => '';
 }
 
+/*class: Enum:Enum,Object*/
+abstract class Enum {}
+
 /*class: Null:Null,Object*/
 class Null {
   factory Null._uninstantiable() {
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_non_standard_sdk_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_non_standard_sdk_test.dart
index e8ba7bf..4a0e09d 100644
--- a/pkg/analysis_server/test/integration/analysis/get_errors_non_standard_sdk_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_errors_non_standard_sdk_test.dart
@@ -38,6 +38,7 @@
 class int {}
 class num {}
 class Object {}
+class Enum {}
 class Iterable<E> {}
 class Map<K, V> {}
 class Null {}
diff --git a/pkg/analyzer/lib/dart/element/type_provider.dart b/pkg/analyzer/lib/dart/element/type_provider.dart
index f1fb800..fd72800 100644
--- a/pkg/analyzer/lib/dart/element/type_provider.dart
+++ b/pkg/analyzer/lib/dart/element/type_provider.dart
@@ -31,6 +31,12 @@
   /// Return the type representing the built-in type `dynamic`.
   DartType get dynamicType;
 
+  /// Return the element representing the built-in type `Enum`.
+  ClassElement get enumElement;
+
+  /// Return the type representing the built-in type `Enum`.
+  InterfaceType get enumType;
+
   /// Return the type representing the built-in type `Function`.
   InterfaceType get functionType;
 
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index bbdc21f..abd2d98 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2668,7 +2668,8 @@
   }
 
   @override
-  List<InterfaceType> get allSupertypes => <InterfaceType>[supertype];
+  List<InterfaceType> get allSupertypes =>
+      <InterfaceType>[...interfaces, supertype];
 
   List<FieldElement> get constants {
     return fields.where((field) => !field.isSynthetic).toList();
@@ -2700,7 +2701,8 @@
   bool get hasStaticMember => true;
 
   @override
-  List<InterfaceType> get interfaces => const <InterfaceType>[];
+  List<InterfaceType> get interfaces =>
+      <InterfaceType>[library.typeProvider.enumType];
 
   @override
   bool get isAbstract => false;
diff --git a/pkg/analyzer/lib/src/dart/element/type_provider.dart b/pkg/analyzer/lib/src/dart/element/type_provider.dart
index dbc4a34..6f29133 100644
--- a/pkg/analyzer/lib/src/dart/element/type_provider.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_provider.dart
@@ -27,6 +27,7 @@
 const Set<String> _nonSubtypableDartCoreClassNames = {
   'bool',
   'double',
+  'Enum',
   'int',
   'Null',
   'num',
@@ -104,6 +105,7 @@
 
   ClassElement? _boolElement;
   ClassElement? _doubleElement;
+  ClassElement? _enumElement;
   ClassElement? _futureElement;
   ClassElement? _futureOrElement;
   ClassElement? _intElement;
@@ -122,6 +124,7 @@
   InterfaceType? _deprecatedType;
   InterfaceType? _doubleType;
   InterfaceType? _doubleTypeQuestion;
+  InterfaceType? _enumType;
   InterfaceType? _functionType;
   InterfaceType? _futureDynamicType;
   InterfaceType? _futureNullType;
@@ -151,7 +154,7 @@
     required LibraryElement coreLibrary,
     required LibraryElement asyncLibrary,
     required bool isNonNullableByDefault,
-  })   : _coreLibrary = coreLibrary,
+  })  : _coreLibrary = coreLibrary,
         _asyncLibrary = asyncLibrary,
         isNonNullableByDefault = isNonNullableByDefault;
 
@@ -220,6 +223,16 @@
   DartType get dynamicType => DynamicTypeImpl.instance;
 
   @override
+  ClassElement get enumElement {
+    return _enumElement ??= _getClassElement(_coreLibrary, "Enum");
+  }
+
+  @override
+  InterfaceType get enumType {
+    return _enumType ??= _getType(_coreLibrary, "Enum");
+  }
+
+  @override
   InterfaceType get functionType {
     return _functionType ??= _getType(_coreLibrary, "Function");
   }
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index a19caf2..3aa1807 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -523,6 +523,10 @@
   external dynamic noSuchMethod(Invocation invocation);
 }
 
+abstract class Enum {
+  int get index;
+}
+
 abstract class Pattern {
   Iterable<Match> allMatches(String string, [int start = 0]);
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/enum_test.dart b/pkg/analyzer/test/src/dart/resolution/enum_test.dart
index c4dc7ed..7a52582 100644
--- a/pkg/analyzer/test/src/dart/resolution/enum_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/enum_test.dart
@@ -24,7 +24,7 @@
 ''');
 
     var v = findElement.topVar('v');
-    assertType(v.type, 'List<Object>');
+    assertType(v.type, 'List<Enum>');
   }
 
   test_isConstantEvaluated() async {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index dc4d4cf..3859042 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -4624,6 +4624,8 @@
       enum E @5
         codeOffset: 0
         codeLength: 26
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -9667,6 +9669,8 @@
           synthetic @-1
     enums
       enum E @30
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -11764,6 +11768,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -11816,6 +11822,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14445,6 +14453,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14467,6 +14477,8 @@
           synthetic toString @-1
             returnType: String
       enum E @19
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14723,6 +14735,8 @@
     enums
       enum E @65
         documentationComment: /**\n * Docs\n */
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14758,6 +14772,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14804,6 +14820,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14863,6 +14881,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14894,6 +14914,8 @@
   definingUnit
     enums
       enum E1 @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14912,6 +14934,8 @@
           synthetic toString @-1
             returnType: String
       enum E2 @20
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -14997,6 +15021,8 @@
                 superKeyword: super @0
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -22565,6 +22591,8 @@
   definingUnit
     enums
       enum E @19
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -22634,6 +22662,8 @@
             returnType: dynamic
     enums
       enum E @64
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -22707,6 +22737,8 @@
               staticElement: self::@getter::a
               staticType: null
               token: a @15
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -24202,6 +24234,8 @@
               staticElement: self::@getter::foo
               staticType: null
               token: foo @17
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -25392,6 +25426,8 @@
           synthetic @-1
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -26873,6 +26909,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -29182,6 +29220,8 @@
           synthetic @-1
     enums
       enum E @16
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -29288,6 +29328,8 @@
             synthetic @-1
       enums
         enum E @27
+          interfaces
+            Enum
           fields
             synthetic final index @-1
               type: int
@@ -29328,6 +29370,8 @@
           synthetic @-1
     enums
       enum E @42
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
@@ -29405,6 +29449,8 @@
             synthetic @-1
       enums
         enum E @27
+          interfaces
+            Enum
           fields
             synthetic final index @-1
               type: int
@@ -29480,6 +29526,8 @@
             synthetic @-1
       enums
         enum E @27
+          interfaces
+            Enum
           fields
             synthetic final index @-1
               type: int
@@ -29623,6 +29671,8 @@
   definingUnit
     enums
       enum E @5
+        interfaces
+          Enum
         fields
           synthetic final index @-1
             type: int
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index f05be5b..f381e96 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -79,6 +79,8 @@
 
   final NamedTypeBuilder objectType;
 
+  final NamedTypeBuilder enumType;
+
   final NamedTypeBuilder listType;
 
   EnumBuilder.internal(
@@ -91,6 +93,7 @@
       this.intType,
       this.listType,
       this.objectType,
+      this.enumType,
       this.stringType,
       LibraryBuilder parent,
       int startCharOffset,
@@ -151,6 +154,12 @@
         /* arguments = */ null,
         /* fileUri = */ null,
         /* charOffset = */ null);
+    NamedTypeBuilder enumType = new NamedTypeBuilder(
+        "Enum",
+        const NullabilityBuilder.omitted(),
+        /* arguments = */ null,
+        /* fileUri = */ null,
+        /* charOffset = */ null);
     Class cls = new Class(
         name: name, reference: referencesFrom?.reference, fileUri: fileUri);
     Map<String, MemberBuilder> members = <String, MemberBuilder>{};
@@ -393,6 +402,7 @@
         intType,
         listType,
         objectType,
+        enumType,
         stringType,
         parent,
         startCharOffsetComputed,
@@ -429,8 +439,12 @@
         coreLibrary.scope, charOffset, fileUri, libraryBuilder);
     objectType.resolveIn(
         coreLibrary.scope, charOffset, fileUri, libraryBuilder);
+    enumType.resolveIn(coreLibrary.scope, charOffset, fileUri, libraryBuilder);
     listType.resolveIn(coreLibrary.scope, charOffset, fileUri, libraryBuilder);
 
+    cls.implementedTypes
+        .add(enumType.buildSupertype(libraryBuilder, charOffset, fileUri));
+
     SourceFieldBuilder indexFieldBuilder = firstMemberNamed("index");
     indexFieldBuilder.build(libraryBuilder);
     Field indexField = indexFieldBuilder.field;
diff --git a/pkg/front_end/lib/src/fasta/denylisted_classes.dart b/pkg/front_end/lib/src/fasta/denylisted_classes.dart
index 345ec12..5df3707 100644
--- a/pkg/front_end/lib/src/fasta/denylisted_classes.dart
+++ b/pkg/front_end/lib/src/fasta/denylisted_classes.dart
@@ -8,6 +8,7 @@
   "int",
   "num",
   "double",
+  "Enum",
   "String",
   "Null"
 ];
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index 4efd282..5674281 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -1786,6 +1786,111 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
         Message Function(DartType _type, DartType _type2, String name,
+            DartType _type3, bool isNonNullableByDefault)>
+    templateIncorrectTypeArgumentInstantiation = const Template<
+            Message Function(DartType _type, DartType _type2, String name,
+                DartType _type3, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Type argument '#type' doesn't conform to the bound '#type2' of the type variable '#name' on '#type3'.""",
+        tipTemplate:
+            r"""Try changing type arguments so that they conform to the bounds.""",
+        withArguments: _withArgumentsIncorrectTypeArgumentInstantiation);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(DartType _type, DartType _type2, String name,
+            DartType _type3, bool isNonNullableByDefault)>
+    codeIncorrectTypeArgumentInstantiation = const Code<
+            Message Function(DartType _type, DartType _type2, String name,
+                DartType _type3, bool isNonNullableByDefault)>(
+        "IncorrectTypeArgumentInstantiation",
+        analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsIncorrectTypeArgumentInstantiation(
+    DartType _type,
+    DartType _type2,
+    String name,
+    DartType _type3,
+    bool isNonNullableByDefault) {
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  List<Object> type2Parts = labeler.labelType(_type2);
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  List<Object> type3Parts = labeler.labelType(_type3);
+  String type = typeParts.join();
+  String type2 = type2Parts.join();
+  String type3 = type3Parts.join();
+  return new Message(codeIncorrectTypeArgumentInstantiation,
+      message:
+          """Type argument '${type}' doesn't conform to the bound '${type2}' of the type variable '${name}' on '${type3}'.""" +
+              labeler.originMessages,
+      tip: """Try changing type arguments so that they conform to the bounds.""",
+      arguments: {
+        'type': _type,
+        'type2': _type2,
+        'name': name,
+        'type3': _type3
+      });
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(DartType _type, DartType _type2, String name,
+            DartType _type3, bool isNonNullableByDefault)>
+    templateIncorrectTypeArgumentInstantiationInferred = const Template<
+            Message Function(DartType _type, DartType _type2, String name,
+                DartType _type3, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Inferred type argument '#type' doesn't conform to the bound '#type2' of the type variable '#name' on '#type3'.""",
+        tipTemplate:
+            r"""Try specifying type arguments explicitly so that they conform to the bounds.""",
+        withArguments:
+            _withArgumentsIncorrectTypeArgumentInstantiationInferred);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(DartType _type, DartType _type2, String name,
+            DartType _type3, bool isNonNullableByDefault)>
+    codeIncorrectTypeArgumentInstantiationInferred = const Code<
+            Message Function(DartType _type, DartType _type2, String name,
+                DartType _type3, bool isNonNullableByDefault)>(
+        "IncorrectTypeArgumentInstantiationInferred",
+        analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsIncorrectTypeArgumentInstantiationInferred(
+    DartType _type,
+    DartType _type2,
+    String name,
+    DartType _type3,
+    bool isNonNullableByDefault) {
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  List<Object> type2Parts = labeler.labelType(_type2);
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  List<Object> type3Parts = labeler.labelType(_type3);
+  String type = typeParts.join();
+  String type2 = type2Parts.join();
+  String type3 = type3Parts.join();
+  return new Message(codeIncorrectTypeArgumentInstantiationInferred,
+      message:
+          """Inferred type argument '${type}' doesn't conform to the bound '${type2}' of the type variable '${name}' on '${type3}'.""" +
+              labeler.originMessages,
+      tip: """Try specifying type arguments explicitly so that they conform to the bounds.""",
+      arguments: {
+        'type': _type,
+        'type2': _type2,
+        'name': name,
+        'type3': _type3
+      });
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(DartType _type, DartType _type2, String name,
             DartType _type3, String name2, bool isNonNullableByDefault)>
     templateIncorrectTypeArgumentQualified = const Template<
             Message Function(DartType _type, DartType _type2, String name,
@@ -1940,6 +2045,37 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
+    templateInstantiationNonGenericFunctionType = const Template<
+            Message Function(DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""The static type of the explicit instantiation operand must be a generic function type but is '#type'.""",
+        tipTemplate:
+            r"""Try changing the operand or remove the type arguments.""",
+        withArguments: _withArgumentsInstantiationNonGenericFunctionType);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type, bool isNonNullableByDefault)>
+    codeInstantiationNonGenericFunctionType =
+    const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
+  "InstantiationNonGenericFunctionType",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInstantiationNonGenericFunctionType(
+    DartType _type, bool isNonNullableByDefault) {
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeInstantiationNonGenericFunctionType,
+      message:
+          """The static type of the explicit instantiation operand must be a generic function type but is '${type}'.""" +
+              labeler.originMessages,
+      tip: """Try changing the operand or remove the type arguments.""",
+      arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
         Message Function(
             String string, DartType _type, bool isNonNullableByDefault)>
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index fa29641..2336024 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -6302,13 +6302,21 @@
 
   @override
   void handleTypeArgumentApplication(Token openAngleBracket) {
-    /// TODO(johnniwinther, paulberry): add support for this construct when the
-    /// "constructor-tearoffs" feature is enabled.
+    assert(checkState(openAngleBracket, [
+      ValueKinds.TypeArguments,
+      unionOfKinds([ValueKinds.Generator, ValueKinds.Expression])
+    ]));
     List<UnresolvedType> typeArguments = pop(); // typeArguments
     if (libraryBuilder.enableConstructorTearOffsInLibrary) {
-      Generator generator = pop();
-      push(generator.applyTypeArguments(
-          openAngleBracket.charOffset, typeArguments));
+      Object operand = pop();
+      if (operand is Generator) {
+        push(operand.applyTypeArguments(
+            openAngleBracket.charOffset, typeArguments));
+      } else {
+        push(new Instantiation(
+            toValue(operand), buildDartTypeArguments(typeArguments))
+          ..fileOffset = openAngleBracket.charOffset);
+      }
     } else {
       addProblem(
           templateExperimentNotEnabled.withArguments(
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 1c7f034..737f649 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -86,6 +86,7 @@
     required bool desugarSets,
     required bool enableTripleShift,
     required bool enableConstFunctions,
+    required bool enableConstructorTearOff,
     required bool errorOnUnevaluatedConstant,
     CoreTypes? coreTypes,
     ClassHierarchy? hierarchy}) {
@@ -99,6 +100,8 @@
   assert(enableConstFunctions != null);
   // ignore: unnecessary_null_comparison
   assert(errorOnUnevaluatedConstant != null);
+  // ignore: unnecessary_null_comparison
+  assert(enableConstructorTearOff != null);
   coreTypes ??= new CoreTypes(component);
   hierarchy ??= new ClassHierarchy(component, coreTypes);
 
@@ -110,7 +113,8 @@
       enableTripleShift: enableTripleShift,
       enableConstFunctions: enableConstFunctions,
       errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
-      evaluateAnnotations: evaluateAnnotations);
+      evaluateAnnotations: evaluateAnnotations,
+      enableConstructorTearOff: enableConstructorTearOff);
   return component;
 }
 
@@ -124,7 +128,8 @@
     {required bool evaluateAnnotations,
     required bool enableTripleShift,
     required bool enableConstFunctions,
-    required bool errorOnUnevaluatedConstant}) {
+    required bool errorOnUnevaluatedConstant,
+    required bool enableConstructorTearOff}) {
   // ignore: unnecessary_null_comparison
   assert(evaluateAnnotations != null);
   // ignore: unnecessary_null_comparison
@@ -133,12 +138,15 @@
   assert(enableConstFunctions != null);
   // ignore: unnecessary_null_comparison
   assert(errorOnUnevaluatedConstant != null);
+  // ignore: unnecessary_null_comparison
+  assert(enableConstructorTearOff != null);
   final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
       backend,
       environmentDefines,
       evaluateAnnotations,
       enableTripleShift,
       enableConstFunctions,
+      enableConstructorTearOff,
       errorOnUnevaluatedConstant,
       typeEnvironment,
       errorReporter,
@@ -156,10 +164,11 @@
     TypeEnvironment typeEnvironment,
     ErrorReporter errorReporter,
     EvaluationMode evaluationMode,
-    {bool evaluateAnnotations: true,
-    bool enableTripleShift: false,
-    bool enableConstFunctions: false,
-    bool errorOnUnevaluatedConstant: false}) {
+    {required bool evaluateAnnotations,
+    required bool enableTripleShift,
+    required bool enableConstFunctions,
+    required bool enableConstructorTearOff,
+    required bool errorOnUnevaluatedConstant}) {
   // ignore: unnecessary_null_comparison
   assert(evaluateAnnotations != null);
   // ignore: unnecessary_null_comparison
@@ -168,12 +177,15 @@
   assert(enableConstFunctions != null);
   // ignore: unnecessary_null_comparison
   assert(errorOnUnevaluatedConstant != null);
+  // ignore: unnecessary_null_comparison
+  assert(enableConstructorTearOff != null);
   final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
       backend,
       environmentDefines,
       evaluateAnnotations,
       enableTripleShift,
       enableConstFunctions,
+      enableConstructorTearOff,
       errorOnUnevaluatedConstant,
       typeEnvironment,
       errorReporter,
@@ -360,6 +372,7 @@
   final bool evaluateAnnotations;
   final bool enableTripleShift;
   final bool enableConstFunctions;
+  final bool enableConstructorTearOff;
   final bool errorOnUnevaluatedConstant;
 
   ConstantsTransformer(
@@ -368,6 +381,7 @@
       this.evaluateAnnotations,
       this.enableTripleShift,
       this.enableConstFunctions,
+      this.enableConstructorTearOff,
       this.errorOnUnevaluatedConstant,
       this.typeEnvironment,
       ErrorReporter errorReporter,
@@ -696,6 +710,18 @@
   }
 
   @override
+  TreeNode visitInstantiation(Instantiation node, TreeNode? removalSentinel) {
+    Instantiation result =
+        super.visitInstantiation(node, removalSentinel) as Instantiation;
+    if (enableConstructorTearOff &&
+        result.expression is ConstantExpression &&
+        result.typeArguments.every(isInstantiated)) {
+      return evaluateAndTransformWithContext(node, result);
+    }
+    return node;
+  }
+
+  @override
   TreeNode visitSwitchCase(SwitchCase node, TreeNode? removalSentinel) {
     transformExpressions(node.expressions, node);
     return super.visitSwitchCase(node, removalSentinel);
@@ -872,9 +898,6 @@
   final bool enableTripleShift;
   final bool enableConstFunctions;
 
-  final bool Function(DartType) isInstantiated =
-      new IsInstantiatedVisitor().isInstantiated;
-
   final Map<Constant, Constant> canonicalizationCache;
   final Map<Node, Constant?> nodeCache;
   final CloneVisitorNotMembers cloner = new CloneVisitorNotMembers();
@@ -4479,6 +4502,10 @@
   }
 }
 
+bool isInstantiated(DartType type) {
+  return type.accept(new IsInstantiatedVisitor());
+}
+
 class IsInstantiatedVisitor extends DartTypeVisitor<bool> {
   final _availableVariables = new Set<TypeParameter>();
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index ff56187..f9c2d18 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -153,9 +153,6 @@
           bodyBuilder.parseFieldInitializer(initializerToken);
       initializerToken = null;
 
-      // The type is needed in the inference below, so the helper should be set.
-      typeInferrer.helper = bodyBuilder;
-
       ExpressionInferenceResult result = typeInferrer.inferExpression(
           initializer, const UnknownType(), true,
           isVoidAllowed: true);
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index a78e798..3ff0062 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -63,10 +63,35 @@
 
   InferenceVisitor(this.inferrer);
 
+  /// Computes uri and offset for [node] for internal errors in a way that is
+  /// safe for both top-level and full inference.
+  _UriOffset _computeUriOffset(TreeNode node) {
+    Uri uri;
+    int fileOffset;
+    if (!inferrer.isTopLevel) {
+      // In local inference we have access to the current file uri.
+      uri = inferrer.helper.uri;
+      fileOffset = node.fileOffset;
+    } else {
+      Location location = node.location;
+      if (location != null) {
+        // Use the location file uri, if available.
+        uri = location.file;
+        fileOffset = node.fileOffset;
+      } else {
+        // Otherwise use the library file uri with no offset.
+        uri = inferrer.library.fileUri;
+        fileOffset = TreeNode.noOffset;
+      }
+    }
+    return new _UriOffset(uri, fileOffset);
+  }
+
   ExpressionInferenceResult _unhandledExpression(
       Expression node, DartType typeContext) {
-    unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
-        inferrer.helper.uri);
+    _UriOffset uriOffset = _computeUriOffset(node);
+    unhandled("${node.runtimeType}", "InferenceVisitor", uriOffset.fileOffset,
+        uriOffset.uri);
   }
 
   @override
@@ -190,12 +215,6 @@
   }
 
   @override
-  ExpressionInferenceResult visitInstantiation(
-      Instantiation node, DartType typeContext) {
-    return _unhandledExpression(node, typeContext);
-  }
-
-  @override
   ExpressionInferenceResult visitConstructorTearOff(
       ConstructorTearOff node, DartType typeContext) {
     return _unhandledExpression(node, typeContext);
@@ -220,8 +239,9 @@
   }
 
   StatementInferenceResult _unhandledStatement(Statement node) {
-    return unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
-        inferrer.helper.uri);
+    _UriOffset uriOffset = _computeUriOffset(node);
+    return unhandled("${node.runtimeType}", "InferenceVisitor",
+        uriOffset.fileOffset, uriOffset.uri);
   }
 
   @override
@@ -273,6 +293,63 @@
   }
 
   @override
+  ExpressionInferenceResult visitInstantiation(
+      Instantiation node, DartType typeContext) {
+    ExpressionInferenceResult operandResult = inferrer.inferExpression(
+        node.expression, const UnknownType(), true,
+        isVoidAllowed: true);
+    node.expression = operandResult.expression..parent = node;
+    DartType operandType = operandResult.inferredType;
+    Expression result = node;
+    DartType resultType = const InvalidType();
+    if (operandType is FunctionType) {
+      if (operandType.typeParameters.length == node.typeArguments.length) {
+        inferrer.checkBoundsInInstantiation(
+            operandType, node.typeArguments, node.fileOffset,
+            inferred: false);
+        resultType = Substitution.fromPairs(
+                operandType.typeParameters, node.typeArguments)
+            .substituteType(operandType.withoutTypeParameters);
+      } else {
+        if (!inferrer.isTopLevel) {
+          if (operandType.typeParameters.isEmpty) {
+            result = inferrer.helper.buildProblem(
+                templateInstantiationNonGenericFunctionType.withArguments(
+                    operandType, inferrer.isNonNullableByDefault),
+                node.fileOffset,
+                noLength);
+          } else if (operandType.typeParameters.length >
+              node.typeArguments.length) {
+            result = inferrer.helper.buildProblem(
+                templateInstantiationTooFewArguments.withArguments(
+                    operandType.typeParameters.length,
+                    node.typeArguments.length),
+                node.fileOffset,
+                noLength);
+          } else if (operandType.typeParameters.length <
+              node.typeArguments.length) {
+            result = inferrer.helper.buildProblem(
+                templateInstantiationTooManyArguments.withArguments(
+                    operandType.typeParameters.length,
+                    node.typeArguments.length),
+                node.fileOffset,
+                noLength);
+          }
+        }
+      }
+    } else {
+      if (!inferrer.isTopLevel) {
+        result = inferrer.helper.buildProblem(
+            templateInstantiationNonGenericFunctionType.withArguments(
+                operandType, inferrer.isNonNullableByDefault),
+            node.fileOffset,
+            noLength);
+      }
+    }
+    return new ExpressionInferenceResult(resultType, result);
+  }
+
+  @override
   ExpressionInferenceResult visitIntLiteral(
       IntLiteral node, DartType typeContext) {
     return new ExpressionInferenceResult(
@@ -991,11 +1068,12 @@
     } else if (syntheticAssignment is InvalidExpression || hasProblem) {
       return new InvalidForInVariable(syntheticAssignment);
     } else {
+      _UriOffset uriOffset = _computeUriOffset(syntheticAssignment);
       return unhandled(
           "${syntheticAssignment.runtimeType}",
           "handleForInStatementWithoutVariable",
-          syntheticAssignment.fileOffset,
-          inferrer.helper.uri);
+          uriOffset.fileOffset,
+          uriOffset.uri);
     }
   }
 
@@ -7262,3 +7340,10 @@
   Expression inferAssignment(TypeInferrerImpl inferrer, DartType rhsType) =>
       expression;
 }
+
+class _UriOffset {
+  final Uri uri;
+  final int fileOffset;
+
+  _UriOffset(this.uri, this.fileOffset);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index eb47f3f..3fe1f73 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1214,6 +1214,8 @@
             isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
         enableConstFunctions:
             isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+        enableConstructorTearOff:
+            isExperimentEnabledGlobally(ExperimentalFlag.constructorTearoffs),
         errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
     ticker.logMs("Evaluated constants");
 
@@ -1255,18 +1257,21 @@
     constants.EvaluationMode evaluationMode = _getConstantEvaluationMode();
 
     constants.transformProcedure(
-        procedure,
-        backendTarget.constantsBackend(loader.coreTypes),
-        environmentDefines,
-        environment,
-        new KernelConstantErrorReporter(loader),
-        evaluationMode,
-        evaluateAnnotations: true,
-        enableTripleShift:
-            isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
-        enableConstFunctions:
-            isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
-        errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
+      procedure,
+      backendTarget.constantsBackend(loader.coreTypes),
+      environmentDefines,
+      environment,
+      new KernelConstantErrorReporter(loader),
+      evaluationMode,
+      evaluateAnnotations: true,
+      enableTripleShift:
+          isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
+      enableConstFunctions:
+          isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+      enableConstructorTearOff:
+          isExperimentEnabledGlobally(ExperimentalFlag.constructorTearoffs),
+      errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
+    );
     ticker.logMs("Evaluated constants");
 
     backendTarget.performTransformationsOnProcedure(
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index bffa568..00e4320 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -3533,23 +3533,43 @@
         typeParameter = null;
       } else {
         if (issue.enclosingType == null && targetReceiver != null) {
-          if (issueInferred) {
-            message =
-                templateIncorrectTypeArgumentQualifiedInferred.withArguments(
-                    argument,
-                    typeParameter.bound,
-                    typeParameter.name,
-                    targetReceiver,
-                    targetName,
-                    isNonNullableByDefault);
+          if (targetName != null) {
+            if (issueInferred) {
+              message =
+                  templateIncorrectTypeArgumentQualifiedInferred.withArguments(
+                      argument,
+                      typeParameter.bound,
+                      typeParameter.name,
+                      targetReceiver,
+                      targetName,
+                      isNonNullableByDefault);
+            } else {
+              message = templateIncorrectTypeArgumentQualified.withArguments(
+                  argument,
+                  typeParameter.bound,
+                  typeParameter.name,
+                  targetReceiver,
+                  targetName,
+                  isNonNullableByDefault);
+            }
           } else {
-            message = templateIncorrectTypeArgumentQualified.withArguments(
-                argument,
-                typeParameter.bound,
-                typeParameter.name,
-                targetReceiver,
-                targetName,
-                isNonNullableByDefault);
+            if (issueInferred) {
+              message = templateIncorrectTypeArgumentInstantiationInferred
+                  .withArguments(
+                      argument,
+                      typeParameter.bound,
+                      typeParameter.name,
+                      targetReceiver,
+                      isNonNullableByDefault);
+            } else {
+              message =
+                  templateIncorrectTypeArgumentInstantiation.withArguments(
+                      argument,
+                      typeParameter.bound,
+                      typeParameter.name,
+                      targetReceiver,
+                      isNonNullableByDefault);
+            }
           }
         } else {
           String enclosingName = issue.enclosingType == null
@@ -4046,6 +4066,41 @@
         targetName: localName ?? 'call');
   }
 
+  void checkBoundsInInstantiation(
+      TypeEnvironment typeEnvironment,
+      ClassHierarchy hierarchy,
+      TypeInferrerImpl typeInferrer,
+      FunctionType functionType,
+      List<DartType> typeArguments,
+      Uri fileUri,
+      int offset,
+      {bool inferred}) {
+    assert(inferred != null);
+    if (typeArguments.isEmpty) return;
+
+    List<TypeParameter> functionTypeParameters = functionType.typeParameters;
+    // The error is to be reported elsewhere.
+    if (functionTypeParameters.length != typeArguments.length) return;
+    final DartType bottomType = isNonNullableByDefault
+        ? const NeverType.nonNullable()
+        : const NullType();
+    List<TypeArgumentIssue> issues = findTypeArgumentIssuesForInvocation(
+        functionTypeParameters,
+        typeArguments,
+        typeEnvironment,
+        isNonNullableByDefault
+            ? SubtypeCheckMode.withNullabilities
+            : SubtypeCheckMode.ignoringNullabilities,
+        bottomType,
+        isNonNullableByDefault: library.isNonNullableByDefault,
+        areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
+    reportTypeArgumentIssues(issues, fileUri, offset,
+        targetReceiver: functionType,
+        typeArgumentsInfo: inferred
+            ? const AllInferredTypeArgumentsInfo()
+            : const NoneInferredTypeArgumentsInfo());
+  }
+
   void checkTypesInOutline(TypeEnvironment typeEnvironment) {
     Iterator<Builder> iterator = this.iterator;
     while (iterator.moveNext()) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 03c4d7d..ddf578b 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -1578,6 +1578,9 @@
   bool operator==(dynamic) {}
 }
 
+abstract class Enum {
+}
+
 class String {}
 
 class Symbol {}
diff --git a/pkg/front_end/lib/src/fasta/source/value_kinds.dart b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
index 1f59675..03261c1 100644
--- a/pkg/front_end/lib/src/fasta/source/value_kinds.dart
+++ b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
@@ -85,6 +85,8 @@
   static const ValueKind Token = const SingleValueKind<type.Token>();
   static const ValueKind TokenOrNull =
       const SingleValueKind<type.Token>(NullValue.Token);
+  static const ValueKind TypeArguments =
+      const SingleValueKind<List<type.UnresolvedType>>();
   static const ValueKind TypeArgumentsOrNull =
       const SingleValueKind<List<type.UnresolvedType>>(NullValue.TypeArguments);
   static const ValueKind TypeBuilder =
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index a02f453..5424d61 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -3752,6 +3752,19 @@
     }
   }
 
+  void checkBoundsInInstantiation(
+      FunctionType functionType, List<DartType> arguments, int fileOffset,
+      {bool inferred}) {
+    assert(inferred != null);
+    // If [arguments] were inferred, check them.
+    if (!isTopLevel) {
+      // We only perform checks in full inference.
+      library.checkBoundsInInstantiation(typeSchemaEnvironment, classHierarchy,
+          this, functionType, arguments, helper.uri, fileOffset,
+          inferred: inferred);
+    }
+  }
+
   void _checkBoundsInFunctionInvocation(FunctionType functionType,
       String localName, Arguments arguments, int fileOffset) {
     // If [arguments] were inferred, check them.
@@ -3910,6 +3923,9 @@
         typeSchemaEnvironment.inferGenericFunctionOrType(instantiatedType,
             typeParameters, [], [], context, inferredTypes, library.library);
         if (!isTopLevel) {
+          checkBoundsInInstantiation(
+              functionType, inferredTypes, expression.fileOffset,
+              inferred: true);
           expression = new Instantiation(expression, inferredTypes)
             ..fileOffset = expression.fileOffset;
         }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 709f244..18c7bae 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -434,6 +434,9 @@
 InitializerOutsideConstructor/example: Fail
 InputFileNotFound/analyzerCode: Fail
 InputFileNotFound/example: Fail
+InstantiationNonGenericFunctionType/analyzerCode: Fail
+InstantiationTooFewArguments/analyzerCode: Fail
+InstantiationTooManyArguments/analyzerCode: Fail
 IntegerLiteralIsOutOfRange/example: Fail
 InterfaceCheck/analyzerCode: Fail
 InterfaceCheck/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index c411adb..8045d59 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4291,6 +4291,27 @@
     class A<T extends A<T>> {}
     class B extends A {}
 
+IncorrectTypeArgumentInstantiation:
+  template: "Type argument '#type' doesn't conform to the bound '#type2' of the type variable '#name' on '#type3'."
+  tip: "Try changing type arguments so that they conform to the bounds."
+  analyzerCode: TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  experiments: constructor-tearoffs
+  script: |
+    X bounded<X extends num>(X x) => x;
+    main() {
+      bounded<String>;
+    }
+
+IncorrectTypeArgumentInstantiationInferred:
+  template: "Inferred type argument '#type' doesn't conform to the bound '#type2' of the type variable '#name' on '#type3'."
+  tip: "Try specifying type arguments explicitly so that they conform to the bounds."
+  analyzerCode: TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  script: |
+    X bounded<X extends num>(X x) => x;
+    main() {
+      String Function(String) c = bounded;
+    }
+
 IncorrectTypeArgumentVariable:
   template: "This is the type variable whose bound isn't conformed to."
   severity: CONTEXT
@@ -5187,3 +5208,27 @@
   severity: INFO
   script: |
     import 'dart-ext:foo.dart';
+
+InstantiationNonGenericFunctionType:
+  template: "The static type of the explicit instantiation operand must be a generic function type but is '#type'."
+  tip: "Try changing the operand or remove the type arguments."
+  experiments: constructor-tearoffs
+  script: |
+    f() {}
+    main() => f<int>;
+
+InstantiationTooFewArguments:
+  template: "Too few type arguments: #count required, #count2 given."
+  tip: "Try adding the missing type arguments."
+  experiments: constructor-tearoffs
+  script: |
+    f<X, Y>() {}
+    main() => f<int>;
+
+InstantiationTooManyArguments:
+  template: "Too many type arguments: #count allowed, but #count2 found."
+  tip: "Try removing the extra type arguments."
+  experiments: constructor-tearoffs
+  script: |
+    f<X>() {}
+    main() => f<int, String>;
diff --git a/pkg/front_end/test/constant_evaluator_benchmark.dart b/pkg/front_end/test/constant_evaluator_benchmark.dart
index c1eb8fb..4595cf8 100644
--- a/pkg/front_end/test/constant_evaluator_benchmark.dart
+++ b/pkg/front_end/test/constant_evaluator_benchmark.dart
@@ -103,6 +103,8 @@
                 .isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
             enableConstFunctions: target
                 .isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+            enableConstructorTearOff: target.isExperimentEnabledGlobally(
+                ExperimentalFlag.constructorTearoffs),
             errorOnUnevaluatedConstant:
                 incrementalCompiler.context.options.errorOnUnevaluatedConstant);
         print("Transformed constants with $environmentDefinesDescription"
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 2ff813f..c957a82 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -267,9 +267,11 @@
 ec
 echo
 edits
+einst
 elapse
 elegantly
 ell
+emethod
 entrypoint
 entrypoints
 eoo
@@ -278,6 +280,7 @@
 erased
 err
 esc
+estat
 et
 everytime
 evicting
@@ -294,6 +297,10 @@
 expansive
 explainer
 extern
+f1
+f2
+f3
+f4
 fac
 faking
 falling
@@ -530,6 +537,7 @@
 minimize
 minimizer
 minimizing
+minst
 mintty
 minutes
 mismatched
@@ -539,11 +547,13 @@
 misspelled
 mistake
 mistakes
+mmethod
 mod
 modelled
 month
 moo
 mouse
+mstat
 mul
 mx
 mxn
diff --git a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.expect b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.expect
index 3f856cd..a52e3ca 100644
--- a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.expect
+++ b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.expect
@@ -16,7 +16,7 @@
 import self as mai;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<mai::Enum> values = #C4;
diff --git a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.transformed.expect b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.transformed.expect
index 4306d18..f92bdce 100644
--- a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.strong.transformed.expect
@@ -17,7 +17,7 @@
 import self as mai;
 import "dart:core" as core;
 
-abstract class Enum extends core::Object {
+abstract class Enum extends core::Object implements core::Enum {
 }
 class Class extends core::Object {
   synthetic constructor •() → mai::Class
diff --git a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.expect b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.expect
index de7f194..c05364c 100644
--- a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.expect
+++ b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.expect
@@ -16,7 +16,7 @@
 import self as mai;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<mai::Enum> values = #C4;
diff --git a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.outline.expect b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.outline.expect
index 21ae4a4..1dd0498 100644
--- a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.outline.expect
@@ -10,7 +10,7 @@
 import self as self2;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self2::Enum> values = #C4;
diff --git a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.transformed.expect b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.transformed.expect
index e779a8d..33ef7bc 100644
--- a/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/aot/enum_from_lib_used_as_type/main.dart.weak.transformed.expect
@@ -17,7 +17,7 @@
 import self as mai;
 import "dart:core" as core;
 
-abstract class Enum extends core::Object {
+abstract class Enum extends core::Object implements core::Enum {
   abstract get /*isLegacy*/ index() → core::int;
 }
 class Class extends core::Object {
diff --git a/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.expect b/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.expect
index be139bc..961f514 100644
--- a/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.expect
+++ b/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.expect
@@ -5,7 +5,7 @@
 
 import "org-dartlang-testcase:///main_lib.dart";
 
-class UnusedEnum extends core::Object /*isEnum*/  {
+class UnusedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UnusedEnum> values = #C7;
@@ -17,7 +17,7 @@
   method toString() → core::String
     return this.{self::UnusedEnum::_name}{core::String};
 }
-class UsedEnum extends core::Object /*isEnum*/  {
+class UsedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UsedEnum> values = #C12;
@@ -67,7 +67,7 @@
 import self as mai;
 import "dart:core" as core;
 
-class ConstEnum extends core::Object /*isEnum*/  {
+class ConstEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<mai::ConstEnum> values = #C15;
diff --git a/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.transformed.expect b/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.transformed.expect
index bc950b3..077bd72 100644
--- a/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/aot/tree_shake/main.dart.strong.transformed.expect
@@ -6,9 +6,9 @@
 
 import "org-dartlang-testcase:///main_lib.dart";
 
-abstract class UnusedEnum extends core::Object {
+abstract class UnusedEnum extends core::Object implements core::Enum {
 }
-class UsedEnum extends core::Object /*isEnum*/  {
+class UsedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   method toString() → core::String
@@ -43,7 +43,7 @@
 import self as mai;
 import "dart:core" as core;
 
-abstract class ConstEnum extends core::Object {
+abstract class ConstEnum extends core::Object implements core::Enum {
 }
 class ConstClass extends core::Object {
   synthetic constructor •() → mai::ConstClass
diff --git a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.expect b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.expect
index 9b15013..cd3c2b4 100644
--- a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.expect
+++ b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.expect
@@ -5,7 +5,7 @@
 
 import "org-dartlang-testcase:///main_lib.dart";
 
-class UnusedEnum extends core::Object /*isEnum*/  {
+class UnusedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UnusedEnum> values = #C7;
@@ -17,7 +17,7 @@
   method toString() → core::String
     return this.{self::UnusedEnum::_name}{core::String};
 }
-class UsedEnum extends core::Object /*isEnum*/  {
+class UsedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UsedEnum> values = #C12;
@@ -67,7 +67,7 @@
 import self as mai;
 import "dart:core" as core;
 
-class ConstEnum extends core::Object /*isEnum*/  {
+class ConstEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<mai::ConstEnum> values = #C15;
diff --git a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.outline.expect b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.outline.expect
index 4e85b30..a041682 100644
--- a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.outline.expect
@@ -4,7 +4,7 @@
 
 import "org-dartlang-testcase:///main_lib.dart";
 
-class UnusedEnum extends core::Object /*isEnum*/  {
+class UnusedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UnusedEnum> values = const <self::UnusedEnum>[self::UnusedEnum::a, self::UnusedEnum::b];
@@ -16,7 +16,7 @@
   method toString() → core::String
     return this.{self::UnusedEnum::_name}{core::String};
 }
-class UsedEnum extends core::Object /*isEnum*/  {
+class UsedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::UsedEnum> values = const <self::UsedEnum>[self::UsedEnum::unusedValue, self::UsedEnum::usedValue];
@@ -55,7 +55,7 @@
 import self as self2;
 import "dart:core" as core;
 
-class ConstEnum extends core::Object /*isEnum*/  {
+class ConstEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self2::ConstEnum> values = #C4;
diff --git a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.transformed.expect b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.transformed.expect
index 0ab2aae..9382897 100644
--- a/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/aot/tree_shake/main.dart.weak.transformed.expect
@@ -6,9 +6,9 @@
 
 import "org-dartlang-testcase:///main_lib.dart";
 
-abstract class UnusedEnum extends core::Object {
+abstract class UnusedEnum extends core::Object implements core::Enum {
 }
-class UsedEnum extends core::Object /*isEnum*/  {
+class UsedEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   method toString() → core::String
@@ -43,7 +43,7 @@
 import self as mai;
 import "dart:core" as core;
 
-abstract class ConstEnum extends core::Object {
+abstract class ConstEnum extends core::Object implements core::Enum {
   abstract get /*isLegacy*/ index() → core::int;
 }
 class ConstClass extends core::Object {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart
new file mode 100644
index 0000000..6d8b22b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2021, 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.
+
+T func<T>(T value) => value;
+var funcValue = func;
+int Function(int) f = funcValue.call; // Disallowed!
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.expect
new file mode 100644
index 0000000..2d0b3bf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+// int Function(int) f = funcValue.call; // Disallowed!
+//                                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::Object? = dynamic>(T%) → T% funcValue = #C1;
+static field (core::int) → core::int f = let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+int Function(int) f = funcValue.call; // Disallowed!
+                                ^" in self::funcValue.call as{TypeError,ForNonNullableByDefault} (core::int) → core::int;
+static method func<T extends core::Object? = dynamic>(self::func::T% value) → self::func::T%
+  return value;
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::func
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.transformed.expect
new file mode 100644
index 0000000..2d0b3bf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.strong.transformed.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+// int Function(int) f = funcValue.call; // Disallowed!
+//                                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::Object? = dynamic>(T%) → T% funcValue = #C1;
+static field (core::int) → core::int f = let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+int Function(int) f = funcValue.call; // Disallowed!
+                                ^" in self::funcValue.call as{TypeError,ForNonNullableByDefault} (core::int) → core::int;
+static method func<T extends core::Object? = dynamic>(self::func::T% value) → self::func::T%
+  return value;
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::func
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline.expect
new file mode 100644
index 0000000..26c075f
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+T func<T>(T value) => value;
+var funcValue = func;
+int Function(int) f = funcValue.call;
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..fa69e2d
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+T func<T>(T value) => value;
+int Function(int) f = funcValue.call;
+main() {}
+var funcValue = func;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.expect
new file mode 100644
index 0000000..2d0b3bf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+// int Function(int) f = funcValue.call; // Disallowed!
+//                                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::Object? = dynamic>(T%) → T% funcValue = #C1;
+static field (core::int) → core::int f = let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+int Function(int) f = funcValue.call; // Disallowed!
+                                ^" in self::funcValue.call as{TypeError,ForNonNullableByDefault} (core::int) → core::int;
+static method func<T extends core::Object? = dynamic>(self::func::T% value) → self::func::T%
+  return value;
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::func
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.outline.expect
new file mode 100644
index 0000000..cce6eb8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.outline.expect
@@ -0,0 +1,10 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::Object? = dynamic>(T%) → T% funcValue;
+static field (core::int) → core::int f;
+static method func<T extends core::Object? = dynamic>(self::func::T% value) → self::func::T%
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.transformed.expect
new file mode 100644
index 0000000..2d0b3bf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart.weak.transformed.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+// int Function(int) f = funcValue.call; // Disallowed!
+//                                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::Object? = dynamic>(T%) → T% funcValue = #C1;
+static field (core::int) → core::int f = let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/call_instantiation.dart:7:33: Error: A value of type 'T Function<T>(T)' can't be assigned to a variable of type 'int Function(int)'.
+int Function(int) f = funcValue.call; // Disallowed!
+                                ^" in self::funcValue.call as{TypeError,ForNonNullableByDefault} (core::int) → core::int;
+static method func<T extends core::Object? = dynamic>(self::func::T% value) → self::func::T%
+  return value;
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::func
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart
new file mode 100644
index 0000000..10102d5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, 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.
+
+typedef ListList<T> = List<List<T>>;
+
+T top<T>(T value) => value;
+
+class C {
+  static T stat<T>(T value) => value;
+  T inst<T>(T value) => value;
+  void method() {
+    var f1 = stat<int>;
+    var f1TypeName = stat<int>.runtimeType.toString();
+    var f2 = inst<int>;
+    var f2TypeName = inst<int>.runtimeType.toString();
+    var f3 = this.inst<int>;
+    var f3TypeName = this.inst<int>.runtimeType.toString();
+  }
+}
+
+mixin M on C {
+  static T mstat<T>(T value) => value;
+  T minst<T>(T value) => value;
+  void mmethod() {
+    var f1 = mstat<int>;
+    var f1TypeName = mstat<int>.runtimeType.toString();
+    var f2 = minst<int>;
+    var f2TypeName = minst<int>.runtimeType.toString();
+    var f3 = this.minst<int>;
+    var f3TypeName = this.minst<int>.runtimeType.toString();
+  }
+}
+
+extension Ext on C {
+  static T estat<T>(T value) => value;
+  T einst<T>(T value) => value;
+  void emethod() {
+    var f1 = estat<int>; // works like (int $) => Ext.estat<int>($)
+    var f1TypeName = estat<int>.runtimeType.toString();
+    var f2 = einst<int>; // works like (int $) => Ext(this).einst<int>($)
+    var f2TypeName = einst<int>.runtimeType.toString();
+    var f3 = this.einst<int>; // works like (int $) => Ext(this).einst<int>($)
+    var f3TypeName = this.einst<int>.runtimeType.toString();
+  }
+}
+class D extends C with M {
+  void method() {
+    var f4 = super.inst<int>; // works like (int $) => super.inst<int>($)
+    var f4TypeName = super.inst<int>.runtimeType.toString();
+  }
+}
+void main() {
+  // Type literals.
+  var t1 = List<int>; // Type object for `List<int>`.
+  var t2 = ListList<int>; // Type object for `List<List<int>>`.
+
+  // Instantiated function tear-offs.
+  T local<T>(T value) => value;
+
+  const f1 = top<int>; // int Function(int), works like (int $) => top<int>($);
+  const f2 = C.stat<int>; // int Function(int), works like (int $) => C.stat<int>($);
+  var f3 = local<int>; // int Function(int), works like (int $) => local<int>($);
+  var d = D();
+  var f4 = d.inst<int>; // int Function(int), works like (int $) => c.inst<int>($);
+  var f5 = d.minst<int>; // int Function(int), works like (int $) => c.minst<int>($);
+  var f6 = d.einst<int>; // int Function(int), works like (int $) => Ext(c).einst<int>($);
+
+  var typeName = (List<int>).toString();
+  var functionTypeName = local<int>.runtimeType.toString();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect
new file mode 100644
index 0000000..efd5a53
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef ListList<T extends core::Object? = dynamic> = core::List<core::List<T%>>;
+class C extends core::Object {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  static method stat<T extends core::Object? = dynamic>(self::C::stat::T% value) → self::C::stat::T%
+    return value;
+  method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
+    return value;
+  method method() → void {
+    (core::int) → core::int f1 = #C2;
+    core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class M extends self::C /*isMixinDeclaration*/  {
+  static method mstat<T extends core::Object? = dynamic>(self::M::mstat::T% value) → self::M::mstat::T%
+    return value;
+  method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class _D&C&M = self::C with self::M /*isAnonymousMixin*/  {
+  synthetic constructor •() → self::_D&C&M
+    : super self::C::•()
+    ;
+  mixin-super-stub method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
+    return super.{self::M::minst}<self::_D&C&M::minst::T%>(value);
+  mixin-super-stub method mmethod() → void
+    return super.{self::M::mmethod}();
+}
+class D extends self::_D&C&M {
+  synthetic constructor •() → self::D
+    : super self::_D&C&M::•()
+    ;
+  method method() → void {
+    (core::int) → core::int f4 = super.{self::C::inst}<core::int>;
+    core::String f4TypeName = (super.{self::C::inst}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+extension Ext on self::C {
+  static method estat = self::Ext|estat;
+  method einst = self::Ext|einst;
+  tearoff einst = self::Ext|get#einst;
+  method emethod = self::Ext|emethod;
+  tearoff emethod = self::Ext|get#emethod;
+}
+static method top<T extends core::Object? = dynamic>(self::top::T% value) → self::top::T%
+  return value;
+static method Ext|estat<T extends core::Object? = dynamic>(self::Ext|estat::T% value) → self::Ext|estat::T%
+  return value;
+static method Ext|einst<T extends core::Object? = dynamic>(lowered final self::C #this, self::Ext|einst::T% value) → self::Ext|einst::T%
+  return value;
+static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
+  return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
+static method Ext|emethod(lowered final self::C #this) → void {
+  (core::int) → core::int f1 = #C6;
+  core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
+  core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
+  core::String f3TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+static method Ext|get#emethod(lowered final self::C #this) → () → void
+  return () → void => self::Ext|emethod(#this);
+static method main() → void {
+  core::Type t1 = #C7;
+  core::Type t2 = #C8;
+  function local<T extends core::Object? = dynamic>(T% value) → T%
+    return value;
+  (core::int) → core::int f3 = local<core::int>;
+  self::D d = new self::D::•();
+  (core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
+  core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
+  core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+
+constants  {
+  #C1 = tearoff self::C::stat
+  #C2 = partial-instantiation self::C::stat <core::int>
+  #C3 = tearoff self::M::mstat
+  #C4 = partial-instantiation self::M::mstat <core::int>
+  #C5 = tearoff self::Ext|estat
+  #C6 = partial-instantiation self::Ext|estat <core::int>
+  #C7 = TypeLiteralConstant(core::List<core::int>)
+  #C8 = TypeLiteralConstant(core::List<core::List<core::int>>)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect
new file mode 100644
index 0000000..ba6e6f0
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect
@@ -0,0 +1,111 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef ListList<T extends core::Object? = dynamic> = core::List<core::List<T%>>;
+class C extends core::Object {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  static method stat<T extends core::Object? = dynamic>(self::C::stat::T% value) → self::C::stat::T%
+    return value;
+  method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
+    return value;
+  method method() → void {
+    (core::int) → core::int f1 = #C2;
+    core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class M extends self::C /*isMixinDeclaration*/  {
+  static method mstat<T extends core::Object? = dynamic>(self::M::mstat::T% value) → self::M::mstat::T%
+    return value;
+  method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class _D&C&M extends self::C implements self::M /*isAnonymousMixin,isEliminatedMixin*/  {
+  synthetic constructor •() → self::_D&C&M
+    : super self::C::•()
+    ;
+  method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+  static method mstat<T extends core::Object? = dynamic>(self::_D&C&M::mstat::T% value) → self::_D&C&M::mstat::T%
+    return value;
+}
+class D extends self::_D&C&M {
+  synthetic constructor •() → self::D
+    : super self::_D&C&M::•()
+    ;
+  method method() → void {
+    (core::int) → core::int f4 = super.{self::C::inst}<core::int>;
+    core::String f4TypeName = (super.{self::C::inst}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+extension Ext on self::C {
+  static method estat = self::Ext|estat;
+  method einst = self::Ext|einst;
+  tearoff einst = self::Ext|get#einst;
+  method emethod = self::Ext|emethod;
+  tearoff emethod = self::Ext|get#emethod;
+}
+static method top<T extends core::Object? = dynamic>(self::top::T% value) → self::top::T%
+  return value;
+static method Ext|estat<T extends core::Object? = dynamic>(self::Ext|estat::T% value) → self::Ext|estat::T%
+  return value;
+static method Ext|einst<T extends core::Object? = dynamic>(lowered final self::C #this, self::Ext|einst::T% value) → self::Ext|einst::T%
+  return value;
+static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
+  return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
+static method Ext|emethod(lowered final self::C #this) → void {
+  (core::int) → core::int f1 = #C6;
+  core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
+  core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
+  core::String f3TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+static method Ext|get#emethod(lowered final self::C #this) → () → void
+  return () → void => self::Ext|emethod(#this);
+static method main() → void {
+  core::Type t1 = #C7;
+  core::Type t2 = #C8;
+  function local<T extends core::Object? = dynamic>(T% value) → T%
+    return value;
+  (core::int) → core::int f3 = local<core::int>;
+  self::D d = new self::D::•();
+  (core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
+  core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
+  core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+
+constants  {
+  #C1 = tearoff self::C::stat
+  #C2 = partial-instantiation self::C::stat <core::int>
+  #C3 = tearoff self::M::mstat
+  #C4 = partial-instantiation self::M::mstat <core::int>
+  #C5 = tearoff self::Ext|estat
+  #C6 = partial-instantiation self::Ext|estat <core::int>
+  #C7 = TypeLiteralConstant(core::List<core::int>)
+  #C8 = TypeLiteralConstant(core::List<core::List<core::int>>)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline.expect
new file mode 100644
index 0000000..809236b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline.expect
@@ -0,0 +1,26 @@
+typedef ListList<T> = List<List<T>>;
+T top<T>(T value) => value;
+
+class C {
+  static T stat<T>(T value) => value;
+  T inst<T>(T value) => value;
+  void method() {}
+}
+
+mixin M on C {
+  static T mstat<T>(T value) => value;
+  T minst<T>(T value) => value;
+  void mmethod() {}
+}
+
+extension Ext on C {
+  static T estat<T>(T value) => value;
+  T einst<T>(T value) => value;
+  void emethod() {}
+}
+
+class D extends C with M {
+  void method() {}
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..0322870
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.textual_outline_modelled.expect
@@ -0,0 +1,25 @@
+T top<T>(T value) => value;
+
+class C {
+  T inst<T>(T value) => value;
+  static T stat<T>(T value) => value;
+  void method() {}
+}
+
+class D extends C with M {
+  void method() {}
+}
+
+extension Ext on C {
+  T einst<T>(T value) => value;
+  static T estat<T>(T value) => value;
+  void emethod() {}
+}
+
+mixin M on C {
+  T minst<T>(T value) => value;
+  static T mstat<T>(T value) => value;
+  void mmethod() {}
+}
+typedef ListList<T> = List<List<T>>;
+void main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect
new file mode 100644
index 0000000..70f8b63
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef ListList<T extends core::Object? = dynamic> = core::List<core::List<T%>>;
+class C extends core::Object {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  static method stat<T extends core::Object? = dynamic>(self::C::stat::T% value) → self::C::stat::T%
+    return value;
+  method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
+    return value;
+  method method() → void {
+    (core::int) → core::int f1 = #C2;
+    core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class M extends self::C /*isMixinDeclaration*/  {
+  static method mstat<T extends core::Object? = dynamic>(self::M::mstat::T% value) → self::M::mstat::T%
+    return value;
+  method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class _D&C&M = self::C with self::M /*isAnonymousMixin*/  {
+  synthetic constructor •() → self::_D&C&M
+    : super self::C::•()
+    ;
+  mixin-super-stub method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
+    return super.{self::M::minst}<self::_D&C&M::minst::T%>(value);
+  mixin-super-stub method mmethod() → void
+    return super.{self::M::mmethod}();
+}
+class D extends self::_D&C&M {
+  synthetic constructor •() → self::D
+    : super self::_D&C&M::•()
+    ;
+  method method() → void {
+    (core::int) → core::int f4 = super.{self::C::inst}<core::int>;
+    core::String f4TypeName = (super.{self::C::inst}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+extension Ext on self::C {
+  static method estat = self::Ext|estat;
+  method einst = self::Ext|einst;
+  tearoff einst = self::Ext|get#einst;
+  method emethod = self::Ext|emethod;
+  tearoff emethod = self::Ext|get#emethod;
+}
+static method top<T extends core::Object? = dynamic>(self::top::T% value) → self::top::T%
+  return value;
+static method Ext|estat<T extends core::Object? = dynamic>(self::Ext|estat::T% value) → self::Ext|estat::T%
+  return value;
+static method Ext|einst<T extends core::Object? = dynamic>(lowered final self::C #this, self::Ext|einst::T% value) → self::Ext|einst::T%
+  return value;
+static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
+  return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
+static method Ext|emethod(lowered final self::C #this) → void {
+  (core::int) → core::int f1 = #C6;
+  core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
+  core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
+  core::String f3TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+static method Ext|get#emethod(lowered final self::C #this) → () → void
+  return () → void => self::Ext|emethod(#this);
+static method main() → void {
+  core::Type t1 = #C7;
+  core::Type t2 = #C8;
+  function local<T extends core::Object? = dynamic>(T% value) → T%
+    return value;
+  (core::int) → core::int f3 = local<core::int>;
+  self::D d = new self::D::•();
+  (core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
+  core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
+  core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+
+constants  {
+  #C1 = tearoff self::C::stat
+  #C2 = partial-instantiation self::C::stat <core::int*>
+  #C3 = tearoff self::M::mstat
+  #C4 = partial-instantiation self::M::mstat <core::int*>
+  #C5 = tearoff self::Ext|estat
+  #C6 = partial-instantiation self::Ext|estat <core::int*>
+  #C7 = TypeLiteralConstant(core::List<core::int*>*)
+  #C8 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.outline.expect
new file mode 100644
index 0000000..6476dce
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.outline.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef ListList<T extends core::Object? = dynamic> = core::List<core::List<T%>>;
+class C extends core::Object {
+  synthetic constructor •() → self::C
+    ;
+  static method stat<T extends core::Object? = dynamic>(self::C::stat::T% value) → self::C::stat::T%
+    ;
+  method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
+    ;
+  method method() → void
+    ;
+}
+abstract class M extends self::C /*isMixinDeclaration*/  {
+  static method mstat<T extends core::Object? = dynamic>(self::M::mstat::T% value) → self::M::mstat::T%
+    ;
+  method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
+    ;
+  method mmethod() → void
+    ;
+}
+abstract class _D&C&M = self::C with self::M /*isAnonymousMixin*/  {
+  synthetic constructor •() → self::_D&C&M
+    : super self::C::•()
+    ;
+  mixin-super-stub method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
+    return super.{self::M::minst}<self::_D&C&M::minst::T%>(value);
+  mixin-super-stub method mmethod() → void
+    return super.{self::M::mmethod}();
+}
+class D extends self::_D&C&M {
+  synthetic constructor •() → self::D
+    ;
+  method method() → void
+    ;
+}
+extension Ext on self::C {
+  static method estat = self::Ext|estat;
+  method einst = self::Ext|einst;
+  tearoff einst = self::Ext|get#einst;
+  method emethod = self::Ext|emethod;
+  tearoff emethod = self::Ext|get#emethod;
+}
+static method top<T extends core::Object? = dynamic>(self::top::T% value) → self::top::T%
+  ;
+static method Ext|estat<T extends core::Object? = dynamic>(self::Ext|estat::T% value) → self::Ext|estat::T%
+  ;
+static method Ext|einst<T extends core::Object? = dynamic>(lowered final self::C #this, self::Ext|einst::T% value) → self::Ext|einst::T%
+  ;
+static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
+  return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
+static method Ext|emethod(lowered final self::C #this) → void
+  ;
+static method Ext|get#emethod(lowered final self::C #this) → () → void
+  return () → void => self::Ext|emethod(#this);
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect
new file mode 100644
index 0000000..217f0b6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect
@@ -0,0 +1,111 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef ListList<T extends core::Object? = dynamic> = core::List<core::List<T%>>;
+class C extends core::Object {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  static method stat<T extends core::Object? = dynamic>(self::C::stat::T% value) → self::C::stat::T%
+    return value;
+  method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
+    return value;
+  method method() → void {
+    (core::int) → core::int f1 = #C2;
+    core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class M extends self::C /*isMixinDeclaration*/  {
+  static method mstat<T extends core::Object? = dynamic>(self::M::mstat::T% value) → self::M::mstat::T%
+    return value;
+  method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+abstract class _D&C&M extends self::C implements self::M /*isAnonymousMixin,isEliminatedMixin*/  {
+  synthetic constructor •() → self::_D&C&M
+    : super self::C::•()
+    ;
+  method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
+    return value;
+  method mmethod() → void {
+    (core::int) → core::int f1 = #C4;
+    core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+    (core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+    core::String f3TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+  static method mstat<T extends core::Object? = dynamic>(self::_D&C&M::mstat::T% value) → self::_D&C&M::mstat::T%
+    return value;
+}
+class D extends self::_D&C&M {
+  synthetic constructor •() → self::D
+    : super self::_D&C&M::•()
+    ;
+  method method() → void {
+    (core::int) → core::int f4 = super.{self::C::inst}<core::int>;
+    core::String f4TypeName = (super.{self::C::inst}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  }
+}
+extension Ext on self::C {
+  static method estat = self::Ext|estat;
+  method einst = self::Ext|einst;
+  tearoff einst = self::Ext|get#einst;
+  method emethod = self::Ext|emethod;
+  tearoff emethod = self::Ext|get#emethod;
+}
+static method top<T extends core::Object? = dynamic>(self::top::T% value) → self::top::T%
+  return value;
+static method Ext|estat<T extends core::Object? = dynamic>(self::Ext|estat::T% value) → self::Ext|estat::T%
+  return value;
+static method Ext|einst<T extends core::Object? = dynamic>(lowered final self::C #this, self::Ext|einst::T% value) → self::Ext|einst::T%
+  return value;
+static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
+  return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
+static method Ext|emethod(lowered final self::C #this) → void {
+  (core::int) → core::int f1 = #C6;
+  core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
+  core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+  (core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
+  core::String f3TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+static method Ext|get#emethod(lowered final self::C #this) → () → void
+  return () → void => self::Ext|emethod(#this);
+static method main() → void {
+  core::Type t1 = #C7;
+  core::Type t2 = #C8;
+  function local<T extends core::Object? = dynamic>(T% value) → T%
+    return value;
+  (core::int) → core::int f3 = local<core::int>;
+  self::D d = new self::D::•();
+  (core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
+  (core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
+  core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
+  core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+}
+
+constants  {
+  #C1 = tearoff self::C::stat
+  #C2 = partial-instantiation self::C::stat <core::int*>
+  #C3 = tearoff self::M::mstat
+  #C4 = partial-instantiation self::M::mstat <core::int*>
+  #C5 = tearoff self::Ext|estat
+  #C6 = partial-instantiation self::Ext|estat <core::int*>
+  #C7 = TypeLiteralConstant(core::List<core::int*>*)
+  #C8 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart
new file mode 100644
index 0000000..7a1e566
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, 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.
+
+X id<X>(X x) => x;
+
+void method<X, Y>() {}
+
+X boundedMethod<X extends num>(X x) => x;
+
+test() {
+  var a = id; // ok
+  var b = a<int>; // ok
+  var c = id<int>; // ok
+  var d = id<int, String>; // error - too many args
+  var e = method<int>; // error - too few args
+  var f = 0<int>; // error - non-function type operand
+  var g = main<int>; // error - non-generic function type operand
+  var h = boundedMethod<String>; // error - invalid bound
+}
+
+var a = id; // ok
+var b = a<int>; // ok
+var c = id<int>; // ok
+var d = id<int, String>; // error - too many args
+var e = method<int>; // error - too few args
+var f = 0<int>; // error - non-function type operand
+var g = main<int>; // error - non-generic function type operand
+var h = boundedMethod<String>; // error - invalid bound
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect
new file mode 100644
index 0000000..7d47228
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+//   var d = id<int, String>; // error - too many args
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+//   var e = method<int>; // error - too few args
+//                 ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+//   var f = 0<int>; // error - non-function type operand
+//            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+//   var g = main<int>; // error - non-generic function type operand
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+//   var h = boundedMethod<String>; // error - invalid bound
+//                        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+//           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+//          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+//                      ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+          ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+              ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+         ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+            ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+  return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+  return x;
+static method test() → dynamic {
+  <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+  (core::int) → core::int b = a<core::int>;
+  (core::int) → core::int c = #C2;
+  invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+  var d = id<int, String>; // error - too many args
+            ^";
+  invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+  var e = method<int>; // error - too few args
+                ^";
+  invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+  var f = 0<int>; // error - non-function type operand
+           ^";
+  invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+  var g = main<int>; // error - non-generic function type operand
+              ^";
+  (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int>
+  #C3 = tearoff self::boundedMethod
+  #C4 = partial-instantiation self::boundedMethod <core::String>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect
new file mode 100644
index 0000000..7d47228
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+//   var d = id<int, String>; // error - too many args
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+//   var e = method<int>; // error - too few args
+//                 ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+//   var f = 0<int>; // error - non-function type operand
+//            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+//   var g = main<int>; // error - non-generic function type operand
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+//   var h = boundedMethod<String>; // error - invalid bound
+//                        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+//           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+//          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+//                      ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+          ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+              ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+         ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+            ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+  return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+  return x;
+static method test() → dynamic {
+  <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+  (core::int) → core::int b = a<core::int>;
+  (core::int) → core::int c = #C2;
+  invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+  var d = id<int, String>; // error - too many args
+            ^";
+  invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+  var e = method<int>; // error - too few args
+                ^";
+  invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+  var f = 0<int>; // error - non-function type operand
+           ^";
+  invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+  var g = main<int>; // error - non-generic function type operand
+              ^";
+  (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int>
+  #C3 = tearoff self::boundedMethod
+  #C4 = partial-instantiation self::boundedMethod <core::String>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.textual_outline.expect
new file mode 100644
index 0000000..ee11ff6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.textual_outline.expect
@@ -0,0 +1,13 @@
+X id<X>(X x) => x;
+void method<X, Y>() {}
+X boundedMethod<X extends num>(X x) => x;
+test() {}
+var a = id;
+var b = a<int>;
+var c = id<int>;
+var d = id<int, String>;
+var e = method<int>;
+var f = 0<int>;
+var g = main<int>;
+var h = boundedMethod<String>;
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect
new file mode 100644
index 0000000..c32e295
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+//   var d = id<int, String>; // error - too many args
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+//   var e = method<int>; // error - too few args
+//                 ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+//   var f = 0<int>; // error - non-function type operand
+//            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+//   var g = main<int>; // error - non-generic function type operand
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+//   var h = boundedMethod<String>; // error - invalid bound
+//                        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+//           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+//          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+//                      ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+          ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+              ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+         ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+            ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+  return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+  return x;
+static method test() → dynamic {
+  <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+  (core::int) → core::int b = a<core::int>;
+  (core::int) → core::int c = #C2;
+  invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+  var d = id<int, String>; // error - too many args
+            ^";
+  invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+  var e = method<int>; // error - too few args
+                ^";
+  invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+  var f = 0<int>; // error - non-function type operand
+           ^";
+  invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+  var g = main<int>; // error - non-generic function type operand
+              ^";
+  (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+  #C3 = tearoff self::boundedMethod
+  #C4 = partial-instantiation self::boundedMethod <core::String*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.outline.expect
new file mode 100644
index 0000000..f85acff
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a;
+static field (core::int) → core::int b;
+static field (core::int) → core::int c;
+static field invalid-type d;
+static field invalid-type e;
+static field invalid-type f;
+static field invalid-type g;
+static field (core::String) → core::String h;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+  ;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void
+  ;
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+  ;
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect
new file mode 100644
index 0000000..c32e295
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+//   var d = id<int, String>; // error - too many args
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+//   var e = method<int>; // error - too few args
+//                 ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+//   var f = 0<int>; // error - non-function type operand
+//            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+//   var g = main<int>; // error - non-generic function type operand
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+//   var h = boundedMethod<String>; // error - invalid bound
+//                        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+//           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+//               ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+//          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+//             ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+//                      ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+          ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+              ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+         ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+            ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+  return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+  return x;
+static method test() → dynamic {
+  <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+  (core::int) → core::int b = a<core::int>;
+  (core::int) → core::int c = #C2;
+  invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+  var d = id<int, String>; // error - too many args
+            ^";
+  invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+  var e = method<int>; // error - too few args
+                ^";
+  invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+  var f = 0<int>; // error - non-function type operand
+           ^";
+  invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+  var g = main<int>; // error - non-generic function type operand
+              ^";
+  (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+  #C3 = tearoff self::boundedMethod
+  #C4 = partial-instantiation self::boundedMethod <core::String*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart
new file mode 100644
index 0000000..6cb7494
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, 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.
+
+T id<T>(T t) => t;
+
+int Function(int) implicitInstantiation = id;
+var explicitInstantiation = id<int>;
+const int Function(int) implicitConstInstantiation = id;
+const explicitConstInstantiation = id<int>;
+
+T Function(T) create<T>() => id<T>;
+
+main() {
+  expect(true, identical(implicitInstantiation, implicitInstantiation));
+  expect(true, identical(implicitInstantiation, explicitInstantiation));
+  expect(true, identical(implicitInstantiation, implicitConstInstantiation));
+  expect(true, identical(implicitInstantiation, explicitConstInstantiation));
+  expect(true, identical(implicitInstantiation, id<int>));
+  expect(false, identical(implicitInstantiation, id<String>));
+  expect(false, identical(implicitInstantiation, create<int>()));
+
+  expect(true, identical(explicitInstantiation, implicitInstantiation));
+  expect(true, identical(explicitInstantiation, explicitInstantiation));
+  expect(true, identical(explicitInstantiation, implicitConstInstantiation));
+  expect(true, identical(explicitInstantiation, explicitConstInstantiation));
+  expect(true, identical(explicitInstantiation, id<int>));
+  expect(false, identical(explicitInstantiation, id<String>));
+  expect(false, identical(explicitInstantiation, create<int>()));
+
+  expect(true, identical(implicitConstInstantiation, implicitInstantiation));
+  expect(true, identical(implicitConstInstantiation, explicitInstantiation));
+  expect(true, identical(implicitConstInstantiation,
+      implicitConstInstantiation));
+  expect(true, identical(implicitConstInstantiation,
+      explicitConstInstantiation));
+  expect(true, identical(implicitConstInstantiation, id<int>));
+  expect(false, identical(implicitConstInstantiation, id<String>));
+  expect(false, identical(implicitConstInstantiation, create<int>()));
+
+  expect(true, identical(explicitConstInstantiation, implicitInstantiation));
+  expect(true, identical(explicitConstInstantiation, explicitInstantiation));
+  expect(true, identical(explicitConstInstantiation,
+      implicitConstInstantiation));
+  expect(true, identical(explicitConstInstantiation,
+      explicitConstInstantiation));
+  expect(true, identical(explicitConstInstantiation, id<int>));
+  expect(false, identical(explicitConstInstantiation, id<String>));
+  expect(false, identical(explicitConstInstantiation, create<int>()));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect
new file mode 100644
index 0000000..8df289d3
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect
@@ -0,0 +1,52 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, #C3));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(false, core::identical(self::explicitInstantiation, #C3));
+  self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int>
+  #C3 = partial-instantiation self::id <core::String>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect
new file mode 100644
index 0000000..3afa4cf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect
@@ -0,0 +1,63 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, #C3));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(false, core::identical(self::explicitInstantiation, #C3));
+  self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int>
+  #C3 = partial-instantiation self::id <core::String>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:33:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:35:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:37:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:38:17 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:43:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:45:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:47:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:48:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 92, effectively constant: 8
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect
new file mode 100644
index 0000000..558b2b1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+int Function(int) implicitInstantiation = id;
+var explicitInstantiation = id<int>;
+const int Function(int) implicitConstInstantiation = id;
+const explicitConstInstantiation = id<int>;
+T Function(T) create<T>() => id<T>;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect
new file mode 100644
index 0000000..c33a355
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect
@@ -0,0 +1,52 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, #C3));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(false, core::identical(self::explicitInstantiation, #C3));
+  self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+  #C3 = partial-instantiation self::id <core::String*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect
new file mode 100644
index 0000000..d3f2e88
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation;
+static field (core::int) → core::int explicitInstantiation;
+static const field (core::int) → core::int implicitConstInstantiation = self::id<core::int>;
+static const field (core::int) → core::int explicitConstInstantiation = self::id<core::int>;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  ;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:9:54 -> PartialInstantiationConstant(id<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:10:38 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 2, effectively constant: 2
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
new file mode 100644
index 0000000..9cdfa3c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
@@ -0,0 +1,63 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, #C3));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(true, core::identical(self::explicitInstantiation, #C2));
+  self::expect(false, core::identical(self::explicitInstantiation, #C3));
+  self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::explicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, #C3));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+  #C3 = partial-instantiation self::id <core::String*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:33:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:35:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:37:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:38:17 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:43:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:45:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:47:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:48:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 92, effectively constant: 8
diff --git a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.expect b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.expect
index 8a535a9..bd3e8df 100644
--- a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.expect
+++ b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.expect
@@ -18,7 +18,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = #C10;
diff --git a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.outline.expect b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.outline.expect
index 9467f32..3b90344 100644
--- a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.outline.expect
@@ -18,7 +18,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = const <self::Foo*>[self::Foo::bar, self::Foo::baz, self::Foo::cafebabe];
diff --git a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.transformed.expect b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.transformed.expect
index 8a535a9..bd3e8df 100644
--- a/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/annotation_on_enum_values.dart.weak.transformed.expect
@@ -18,7 +18,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = #C10;
diff --git a/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart
new file mode 100644
index 0000000..d0c6c8e
--- /dev/null
+++ b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, 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.
+
+test() {
+  X bounded<X extends num>(X x) => x;
+  String a = bounded('');
+  String b = bounded<String>('');
+  String Function(String) c = bounded;
+  String d = c('');
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline.expect b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline.expect
new file mode 100644
index 0000000..ec6b9e0
--- /dev/null
+++ b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f67dbb0
--- /dev/null
+++ b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+main() {}
+test() {}
diff --git a/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.expect b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.expect
new file mode 100644
index 0000000..cf6e3f3
--- /dev/null
+++ b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/bounded_implicit_instantiation.dart:7:22: Error: The argument type 'String' can't be assigned to the parameter type 'Never'.
+//   String a = bounded('');
+//                      ^
+//
+// pkg/front_end/testcases/general/bounded_implicit_instantiation.dart:8:21: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'bounded'.
+// Try changing type arguments so that they conform to the bounds.
+//   String b = bounded<String>('');
+//                     ^
+//
+// pkg/front_end/testcases/general/bounded_implicit_instantiation.dart:9:31: Error: Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   String Function(String) c = bounded;
+//                               ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+  function bounded<X extends core::num>(X x) → X
+    return x;
+  core::String a = let final Never #t1 = bounded<Never>(let final Never #t2 = invalid-expression "pkg/front_end/testcases/general/bounded_implicit_instantiation.dart:7:22: Error: The argument type 'String' can't be assigned to the parameter type 'Never'.
+  String a = bounded('');
+                     ^" in "" as{TypeError,ForNonNullableByDefault} Never){(Never) → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::String b = bounded<core::String>(""){(core::String) → core::String};
+  (core::String) → core::String c = bounded<core::String>;
+  core::String d = c(""){(core::String) → core::String};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.outline.expect b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.outline.expect
new file mode 100644
index 0000000..64923de
--- /dev/null
+++ b/pkg/front_end/testcases/general/bounded_implicit_instantiation.dart.weak.outline.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.expect b/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.expect
index 280c716..ce50dfd 100644
--- a/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.expect
+++ b/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.expect
@@ -481,7 +481,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#4 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#4 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#4*>* values = #C4;
@@ -501,7 +501,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#3 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#3 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#3*>* values = #C12;
@@ -523,7 +523,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#2 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#2 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#2*>* values = #C17;
@@ -545,7 +545,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#1 extends core::Object /*isEnum*/  {
+class Enum#1 extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#1*>* values = #C21;
@@ -567,7 +567,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum*>* values = #C25;
@@ -589,7 +589,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class AnotherEnum extends core::Object /*isEnum*/  {
+class AnotherEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::AnotherEnum*>* values = #C32;
diff --git a/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.outline.expect b/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.outline.expect
index 325b6441..1113a3a 100644
--- a/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/duplicated_declarations.dart.weak.outline.expect
@@ -419,7 +419,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#4 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#4 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#4*>* values = const <self::Enum#4*>[self::Enum#4::a];
@@ -439,7 +439,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#3 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#3 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#3*>* values = const <self::Enum#3*>[self::Enum#3::a, self::Enum#3::b, self::Enum#3::c];
@@ -461,7 +461,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#2 extends core::Object /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
+class Enum#2 extends core::Object implements core::Enum /*isEnum*/  { // from org-dartlang-testcase:///duplicated_declarations_part.dart
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#2*>* values = const <self::Enum#2*>[self::Enum#2::Enum, self::Enum#2::a, self::Enum#2::b];
@@ -483,7 +483,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum#1 extends core::Object /*isEnum*/  {
+class Enum#1 extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum#1*>* values = const <self::Enum#1*>[self::Enum#1::a, self::Enum#1::b, self::Enum#1::c];
@@ -505,7 +505,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Enum*>* values = const <self::Enum*>[self::Enum::Enum, self::Enum::a, self::Enum::b];
@@ -527,7 +527,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class AnotherEnum extends core::Object /*isEnum*/  {
+class AnotherEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::AnotherEnum*>* values = const <self::AnotherEnum*>[self::AnotherEnum::a, self::AnotherEnum::b, self::AnotherEnum::c];
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
new file mode 100644
index 0000000..955feff
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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.
+
+// @dart=2.13
+
+// This test is similar to
+//
+//   constructor_tearoffs/identical_instantiated_function_tearoffs.dart
+//
+// but verifies that before the constructor-tearoffs experiment was enabled,
+// instantiations in non-constant context were not canonicalized.
+
+T id<T>(T t) => t;
+
+int Function(int) implicitInstantiation = id;
+const int Function(int) implicitConstInstantiation = id;
+
+T Function(T) create<T>() => id;
+
+main() {
+  expect(true, identical(implicitInstantiation, implicitInstantiation));
+  expect(false, identical(implicitInstantiation, implicitConstInstantiation));
+  expect(false, identical(implicitInstantiation, create<int>()));
+
+  expect(false, identical(implicitConstInstantiation, implicitInstantiation));
+  expect(
+      true, identical(implicitConstInstantiation, implicitConstInstantiation));
+  expect(false, identical(implicitConstInstantiation, create<int>()));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
new file mode 100644
index 0000000..90e26eb
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+// @dart = 2.13
+T id<T>(T t) => t;
+int Function(int) implicitInstantiation = id;
+const int Function(int) implicitConstInstantiation = id;
+T Function(T) create<T>() => id;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a0e9251
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+// @dart = 2.13
+T Function(T) create<T>() => id;
+T id<T>(T t) => t;
+const int Function(int) implicitConstInstantiation = id;
+expect(expected, actual) {}
+int Function(int) implicitInstantiation = id;
+main() {}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
new file mode 100644
index 0000000..daf6f36
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(false, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(false, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
new file mode 100644
index 0000000..02a352f
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
@@ -0,0 +1,19 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation;
+static const field (core::int) → core::int implicitConstInstantiation = self::id<core::int>;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  ;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:17:54 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
new file mode 100644
index 0000000..ad67316
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+  return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+  return #C1<self::create::T%>;
+static method main() → dynamic {
+  self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+  self::expect(false, core::identical(self::implicitInstantiation, #C2));
+  self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+  self::expect(false, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, #C2));
+  self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = partial-instantiation self::id <core::int*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:28:13 -> BoolConstant(true)
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:16:43 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 30, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/metadata_enum.dart.weak.expect b/pkg/front_end/testcases/general/metadata_enum.dart.weak.expect
index 226967f..16f3460 100644
--- a/pkg/front_end/testcases/general/metadata_enum.dart.weak.expect
+++ b/pkg/front_end/testcases/general/metadata_enum.dart.weak.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 @#C1
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C11;
diff --git a/pkg/front_end/testcases/general/metadata_enum.dart.weak.outline.expect b/pkg/front_end/testcases/general/metadata_enum.dart.weak.outline.expect
index eccf60e..44f4d21 100644
--- a/pkg/front_end/testcases/general/metadata_enum.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/metadata_enum.dart.weak.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 @self::a
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = const <self::E*>[self::E::E1, self::E::E2, self::E::E3];
diff --git a/pkg/front_end/testcases/general/metadata_enum.dart.weak.transformed.expect b/pkg/front_end/testcases/general/metadata_enum.dart.weak.transformed.expect
index 226967f..16f3460 100644
--- a/pkg/front_end/testcases/general/metadata_enum.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/metadata_enum.dart.weak.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 @#C1
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C11;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.1.expect
index 5c66b3c..f919f21 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.1.expect
@@ -30,7 +30,7 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
   }
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.2.expect
index 654e34c..0b4afaf 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_2.yaml.world.2.expect
@@ -30,7 +30,7 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
   }
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.1.expect
index fa8fec9..46a055a 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.1.expect
@@ -37,7 +37,7 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
   }
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.2.expect
index 2311e2e..f17b4d8 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.2.expect
@@ -37,7 +37,7 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
   }
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.3.expect b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.3.expect
index 395e141..de577dd 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_6.yaml.world.3.expect
@@ -30,7 +30,7 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
   }
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.1.expect
index 28c10a2..73cad31 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.1.expect
@@ -42,7 +42,7 @@
     }
   }
   @#C1
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C15;
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.2.expect
index 28c10a2..73cad31 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_7.yaml.world.2.expect
@@ -42,7 +42,7 @@
     }
   }
   @#C1
-  class CompilationStrategy extends dart.core::Object /*isEnum*/  {
+  class CompilationStrategy extends dart.core::Object implements dart.core::Enum /*isEnum*/  {
     final field dart.core::int* index;
     final field dart.core::String* _name;
     static const field dart.core::List<main::CompilationStrategy*>* values = #C15;
diff --git a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
index 22921fb..2c7b116 100644
--- a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
@@ -2,6 +2,12 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:26:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOI(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:28:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
 //                                                                         ^
@@ -10,6 +16,24 @@
 //       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
 //                                                                         ^
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:31:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOON(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:32:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOO(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:45:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOI(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:46:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //   takeIDI(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
 //                                                                        ^
@@ -18,6 +42,36 @@
 //   takeDID(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
 //                                                                        ^
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:48:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOON(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:49:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOO(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:73:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:75:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:82:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:86:29: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //           . /*@target=C.m*/ m);
 //                             ^
diff --git a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
index 5857dad..d465ca9 100644
--- a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
@@ -2,6 +2,12 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:26:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOI(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:28:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
 //                                                                         ^
@@ -10,6 +16,24 @@
 //       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
 //                                                                         ^
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:31:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOON(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:32:70: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOO(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ math.max);
+//                                                                      ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:45:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOI(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:46:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //   takeIDI(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
 //                                                                        ^
@@ -18,6 +42,36 @@
 //   takeDID(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
 //                                                                        ^
 //
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:48:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOON(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:49:65: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   takeOOO(/*error:COULD_NOT_INFER,error:INVALID_CAST_FUNCTION*/ min);
+//                                                                 ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:73:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:75:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
+// pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:82:25: Error: Inferred type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'T Function<T extends num>(T, T)'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//       . /*@target=C.m*/ m);
+//                         ^
+//
 // pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:86:29: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
 //           . /*@target=C.m*/ m);
 //                             ^
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.expect
index b8edb82..84bd9ed 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C4;
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.outline.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.outline.expect
index e92663e..0f72ee9 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = const <self::E*>[self::E::v1];
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.transformed.expect
index b8edb82..84bd9ed 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C4;
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.expect
index 5bb945f..827859e 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C4;
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.outline.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.outline.expect
index 4584120..f462cb1 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = const <self::E*>[self::E::v1];
diff --git a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.transformed.expect
index 5bb945f..827859e 100644
--- a/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/inferred_type_is_enum_values.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::E*>* values = #C4;
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.strong.expect b/pkg/front_end/testcases/nnbd/return_null.dart.strong.expect
index 95f3397..2c50f0d 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.strong.expect
@@ -58,7 +58,7 @@
 
 import "dart:async";
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect
index 81d9731..0aaa16b 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect
@@ -58,7 +58,7 @@
 
 import "dart:async";
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.weak.expect b/pkg/front_end/testcases/nnbd/return_null.dart.weak.expect
index 65b134d..d2df46e 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.weak.expect
@@ -59,7 +59,7 @@
 
 import "dart:async";
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/return_null.dart.weak.outline.expect
index 04d2e5b..29d9ba1 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.weak.outline.expect
@@ -5,7 +5,7 @@
 
 import "dart:async";
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = const <self::Enum>[self::Enum::a, self::Enum::b];
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect
index 51a7d44..b0fa47a 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect
@@ -59,7 +59,7 @@
 
 import "dart:async";
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.expect b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.expect
index 7ad41a1..3435d06 100644
--- a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.expect
@@ -9,7 +9,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.transformed.expect
index 7ad41a1..3435d06 100644
--- a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.strong.transformed.expect
@@ -9,7 +9,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.expect b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.expect
index 61fa678..6d0b4f2 100644
--- a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.expect
@@ -10,7 +10,7 @@
 import "dart:core" as core;
 import "dart:_internal" as _in;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.outline.expect
index d3643d7..ed400bb 100644
--- a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = const <self::Enum>[self::Enum::e1, self::Enum::e2];
diff --git a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.transformed.expect
index 61fa678..6d0b4f2 100644
--- a/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/switch_nullable_enum.dart.weak.transformed.expect
@@ -10,7 +10,7 @@
 import "dart:core" as core;
 import "dart:_internal" as _in;
 
-class Enum extends core::Object /*isEnum*/  {
+class Enum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::Enum> values = #C7;
diff --git a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.expect
index b130d3b..ead85b1 100644
--- a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.expect
@@ -428,7 +428,7 @@
     : uns::OptInClass6b::field = field, super core::Object::•()
     ;
 }
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<uns::E> values = #C8;
diff --git a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.outline.expect
index d853a42..2a7d4ca 100644
--- a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.outline.expect
@@ -201,7 +201,7 @@
   constructor •(core::int field) → self2::OptInClass6b
     ;
 }
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self2::E> values = const <self2::E>[self2::E::e1, self2::E::e2];
diff --git a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.transformed.expect
index f635ea8..ede6557 100644
--- a/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/unsound_checks.dart.weak.transformed.expect
@@ -428,7 +428,7 @@
     : uns::OptInClass6b::field = field, super core::Object::•()
     ;
 }
-class E extends core::Object /*isEnum*/  {
+class E extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<uns::E> values = #C8;
diff --git a/pkg/front_end/testcases/rasta/enum.dart.weak.expect b/pkg/front_end/testcases/rasta/enum.dart.weak.expect
index 71f1044..99090fe 100644
--- a/pkg/front_end/testcases/rasta/enum.dart.weak.expect
+++ b/pkg/front_end/testcases/rasta/enum.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = #C7;
diff --git a/pkg/front_end/testcases/rasta/enum.dart.weak.outline.expect b/pkg/front_end/testcases/rasta/enum.dart.weak.outline.expect
index 5df7acc..3d39d28 100644
--- a/pkg/front_end/testcases/rasta/enum.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/rasta/enum.dart.weak.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = const <self::Foo*>[self::Foo::ec1, self::Foo::ec2];
diff --git a/pkg/front_end/testcases/rasta/enum.dart.weak.transformed.expect b/pkg/front_end/testcases/rasta/enum.dart.weak.transformed.expect
index 71f1044..99090fe 100644
--- a/pkg/front_end/testcases/rasta/enum.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/rasta/enum.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo extends core::Object /*isEnum*/  {
+class Foo extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int* index;
   final field core::String* _name;
   static const field core::List<self::Foo*>* values = #C7;
diff --git a/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.expect b/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.expect
index 6115731..6d82f2d 100644
--- a/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.expect
+++ b/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object /*isEnum*/  {
+class A extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::A> values = #C7;
diff --git a/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.transformed.expect b/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.transformed.expect
index 6115731..6d82f2d 100644
--- a/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/static_field_lowering/enum.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object /*isEnum*/  {
+class A extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::A> values = #C7;
diff --git a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.expect b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.expect
index bece663..7609699 100644
--- a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.expect
+++ b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object /*isEnum*/  {
+class A extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::A> values = #C7;
diff --git a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.outline.expect b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.outline.expect
index a6cad98..23e0446 100644
--- a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object /*isEnum*/  {
+class A extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::A> values = const <self::A>[self::A::a, self::A::b];
diff --git a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.transformed.expect b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.transformed.expect
index bece663..7609699 100644
--- a/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/static_field_lowering/enum.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object /*isEnum*/  {
+class A extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::A> values = #C7;
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 24201ec..c7df9c9 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -22,6 +22,7 @@
 general/accessors: RuntimeError
 general/ambiguous_exports: RuntimeError
 general/await_in_non_async: RuntimeError
+general/bounded_implicit_instantiation: TypeCheckError
 general/bug30695: TypeCheckError
 general/bug31124: RuntimeError
 general/call: TypeCheckError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index fd8e874..29acb62 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -23,8 +23,10 @@
 const_functions/const_functions_const_ctor: FormatterCrash
 const_functions/const_functions_const_ctor_error: FormatterCrash
 const_functions/const_functions_const_factory: FormatterCrash
+constructor_tearoffs/explicit_instantiation_errors: FormatterCrash
 constructor_tearoffs/generic_tearoff_with_context: FormatterCrash
 constructor_tearoffs/generic_tearoff_without_context: FormatterCrash
+constructor_tearoffs/identical_instantiated_function_tearoffs: FormatterCrash
 constructor_tearoffs/instantiation: FormatterCrash
 constructor_tearoffs/nongeneric_tearoff_with_context: FormatterCrash
 constructor_tearoffs/nongeneric_tearoff_without_context: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 3c2c427..82c2ba6 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -27,6 +27,7 @@
 general/accessors: RuntimeError
 general/ambiguous_exports: RuntimeError # Expected, this file exports two main methods.
 general/await_in_non_async: RuntimeError # Expected.
+general/bounded_implicit_instantiation: TypeCheckError
 general/bug30695: TypeCheckError
 general/bug31124: RuntimeError # Test has no main method (and we shouldn't add one).
 general/call: TypeCheckError
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect b/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect
index 38a3e92..37d5226 100644
--- a/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect
+++ b/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect
@@ -19,7 +19,7 @@
   method toString() → core::String
     return "I am a Foo";
 }
-class FooEnum extends core::Object /*isEnum*/  {
+class FooEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::FooEnum> values = #C11;
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect b/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect
index a858cd6..d5bbdbf 100644
--- a/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect
+++ b/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect
@@ -19,7 +19,7 @@
   method toString() → core::String
     return super.toString();
 }
-class FooEnum extends core::Object /*isEnum*/  {
+class FooEnum extends core::Object implements core::Enum /*isEnum*/  {
   final field core::int index;
   final field core::String _name;
   static const field core::List<self::FooEnum> values = #C11;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
index 4487ac5..1a8dce9 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
@@ -11,7 +11,7 @@
 [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:2,getterSelectorId:3]  method getBar() → core::String*
     return "bar";
 }
-class B extends core::Object /*isEnum*/  {
+class B extends core::Object implements core::Enum /*isEnum*/  {
 [@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:4] [@vm.unboxing-info.metadata=()->i]  final field core::int* index;
 [@vm.inferred-type.metadata=dart.core::_OneByteString (value: "B.b2")] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:5]  final field core::String* _name;
 [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method toString() → core::String*
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/enum_used_as_type.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/enum_used_as_type.dart.expect
index 92f5135..ac4bbc2 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/enum_used_as_type.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/enum_used_as_type.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 import "dart:_internal" as _in;
 
-abstract class Enum extends core::Object {
+abstract class Enum extends core::Object implements core::Enum {
 [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1]  abstract get index() → core::int*;
 }
 class Class extends core::Object {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_46461.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_46461.dart.expect
index 82c5c73..6ca7b29 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_46461.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_46461.dart.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-abstract class A extends core::Object {
+abstract class A extends core::Object implements core::Enum {
 }
 abstract class B extends core::Object {
 [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → void;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
index 07ed13e..64a9777 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -95,7 +95,13 @@
   @patch
   static apply(Function function, List<dynamic>? positionalArguments,
       [Map<Symbol, dynamic>? namedArguments]) {
-    positionalArguments ??= [];
+    if (positionalArguments == null) {
+      positionalArguments = [];
+    } else if (JS<bool>('!', '!Array.isArray(#)', positionalArguments)) {
+      // dcall expects the positionalArguments as a JS array.
+      positionalArguments = List.of(positionalArguments);
+    }
+
     // dcall expects the namedArguments as a JS map in the last slot.
     if (namedArguments != null && namedArguments.isNotEmpty) {
       var map = JS('', '{}');
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 174b2ff..0c30b2c 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -320,7 +320,7 @@
   let errorMessage = $_argumentErrors($ftype, $args, $named);
   if (errorMessage == null) {
     if ($typeArgs != null) $args = $typeArgs.concat($args);
-    if ($named != null) $args.push($named);
+    if ($named != null) $args = $args.concat($named);
     return $f.apply($obj, $args);
   }
   return callNSM(errorMessage);
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 7e96d5c..3799c08 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -178,6 +178,7 @@
 part "date_time.dart";
 part "double.dart";
 part "duration.dart";
+part "enum.dart";
 part "errors.dart";
 part "exceptions.dart";
 part "expando.dart";
diff --git a/sdk/lib/core/core_sources.gni b/sdk/lib/core/core_sources.gni
index ce2785e..66362e9 100644
--- a/sdk/lib/core/core_sources.gni
+++ b/sdk/lib/core/core_sources.gni
@@ -13,6 +13,7 @@
   "date_time.dart",
   "double.dart",
   "duration.dart",
+  "enum.dart",
   "errors.dart",
   "exceptions.dart",
   "expando.dart",
diff --git a/sdk/lib/core/enum.dart b/sdk/lib/core/enum.dart
new file mode 100644
index 0000000..c220b42
--- /dev/null
+++ b/sdk/lib/core/enum.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, 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 dart.core;
+
+/// An enumerated value.
+///
+/// This class is implemented by all types and values
+/// introduced using an `enum` declaration.
+/// Non-platform classes cannot implement, extend or
+/// mix in this class.
+@Since("2.14")
+abstract class Enum {
+  /// A numeric identifier for the enumerated value.
+  ///
+  /// The values of a single enumeration are numbered
+  /// consecutively from zero to one less than the
+  /// number of values.
+  /// This is also the index of the value in the
+  /// enumerated type's static `values` list.
+  int get index;
+}
diff --git a/tests/language/closure/partial_instantiation_static_bounds_check_test.dart b/tests/language/closure/partial_instantiation_static_bounds_check_test.dart
index 38192ba..435918e 100644
--- a/tests/language/closure/partial_instantiation_static_bounds_check_test.dart
+++ b/tests/language/closure/partial_instantiation_static_bounds_check_test.dart
@@ -17,6 +17,7 @@
     void Function(int) k = instanceFn;
     //                     ^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+    // [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'dynamic Function<S extends T>(S)'.
   }
 }
 
@@ -28,7 +29,9 @@
   void Function(String) k0 = localFn;
   //                         ^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  // [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'Null Function<T extends num>(T)'.
   void Function(String) k1 = topFn;
   //                         ^^^^^
   // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  // [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'dynamic Function<T extends num>(T)'.
 }
diff --git a/tests/language/enum/enum_test.dart b/tests/language/enum/enum_test.dart
index 87d6d65..8b21613 100644
--- a/tests/language/enum/enum_test.dart
+++ b/tests/language/enum/enum_test.dart
@@ -88,6 +88,11 @@
     expectIs(value, (e) => e is JSFunctionPrototype);
   }
   Expect.equals(JSFunctionPrototype.length, JSFunctionPrototype.values[0]);
+
+  // Enums implement Enum.
+  Expect.type<Enum>(Enum1._);
+  Enum enumValue = Enum1._;
+  Expect.equals(0, enumValue.index);
 }
 
 test1(Enum1 e) {
diff --git a/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart b/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart
index 8de7729..968ae22 100644
--- a/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart
+++ b/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart
@@ -17,7 +17,7 @@
   R instanceMethod<R, T>(T value, [T? other]) => value as R;
 
   void tearOffsOnThis() {
-    const staticTearoff = staticMethod<int, String>;
+    const staticTearOff = staticMethod<int, String>;
     staticMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
     instanceMethod<int, String>
@@ -37,7 +37,7 @@
   R mixinInstanceMethod<R, T>(T value, [T? other]) => value as R;
 
   void mixinTearOffsOnThis() {
-    const staticTearoff = staticMethod<int, String>;
+    const staticTearOff = staticMethod<int, String>;
     staticMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
     mixinInstanceMethod<int, String>
@@ -57,8 +57,8 @@
   static R staticMethod<R, T>(T value, [T? other]) => value as R;
   R extInstanceMethod<R, T>(T value, [T? other]) => value as R;
 
-  void extenstionTearOffsOnThis() {
-    const staticTearoff = staticMethod<int, String>;
+  void extensionTearOffsOnThis() {
+    const staticTearOff = staticMethod<int, String>;
     staticMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
     extInstanceMethod<int, String>
@@ -87,10 +87,10 @@
   R local<R, T>(T value, [T? other]) => value as R;
 
   // Check that some tear-offs are constant.
-  const topTearoff = toplevel<int, String>;
-  const staticTearoff = C.staticMethod<int, String>;
-  const mixinStaticTearoff = M.staticMethod<int, String>;
-  const extensionStaticTearoff = E.staticMethod<int, String>;
+  const topTearOff = toplevel<int, String>;
+  const staticTearOff = C.staticMethod<int, String>;
+  const mixinStaticTearOff = M.staticMethod<int, String>;
+  const extensionStaticTearOff = E.staticMethod<int, String>;
 
   // Check that the tear-offs have the correct static type.
 
@@ -105,23 +105,23 @@
   E
       .staticMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
-  c
+  o
       .instanceMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
-  c
+  o
       .mixinInstanceMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
-  c
+  o
       .extInstanceMethod<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
   local<int, String>
       .expectStaticType<Exactly<int Function(String, [String?])>>();
 
   // Check that the tear-offs are canonicalized where possible.
-  Expect.identical(toplevel<int, String>, topTearoff);
-  Expect.identical(C.staticMethod<int, String>, staticTearoff);
-  Expect.identical(M.staticMethod<int, String>, mixinStaticTearoff);
-  Expect.identical(E.staticMethod<int, String>, extensionStaticTearoff);
+  Expect.identical(toplevel<int, String>, topTearOff);
+  Expect.identical(C.staticMethod<int, String>, staticTearOff);
+  Expect.identical(M.staticMethod<int, String>, mixinStaticTearOff);
+  Expect.identical(E.staticMethod<int, String>, extensionStaticTearOff);
 
   // Instantiated local methods may or may not be equal.
   // (Specification makes no promise about equality.).
@@ -161,7 +161,7 @@
   }<int>());
 
   o.tearOffsOnThis();
-  o.tearOffOnSuper();
-  o.mixinTearOffOnThis();
-  o.extensionTearOffOnThis();
+  o.tearOffsOnSuper();
+  o.mixinTearOffsOnThis();
+  o.extensionTearOffsOnThis();
 }
diff --git a/tests/language/unsorted/inference_enum_list_test.dart b/tests/language/unsorted/inference_enum_list_test.dart
index dc7b7bd3..0502272 100644
--- a/tests/language/unsorted/inference_enum_list_test.dart
+++ b/tests/language/unsorted/inference_enum_list_test.dart
@@ -4,11 +4,12 @@
 
 enum E1 { a, b }
 enum E2 { a, b }
+enum E3 { a, b }
 
 var v = [E1.a, E2.b];
 
 main() {
-  // Test that v is `List<Object>`, so any of these assignemnts are OK.
-  v[0] = 0;
-  v[1] = '1';
+  // Test that v is `List<Enum>`, so these assignments are OK.
+  v[0] = E3.a;
+  List<Enum> w = v;
 }
diff --git a/tests/language_2/closure/partial_instantiation_static_bounds_check_test.dart b/tests/language_2/closure/partial_instantiation_static_bounds_check_test.dart
index 2810e7a..34e6b18 100644
--- a/tests/language_2/closure/partial_instantiation_static_bounds_check_test.dart
+++ b/tests/language_2/closure/partial_instantiation_static_bounds_check_test.dart
@@ -19,6 +19,7 @@
     void Function(int) k = instanceFn;
     //                     ^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+    // [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'dynamic Function<S extends T>(S)'.
   }
 }
 
@@ -30,7 +31,9 @@
   void Function(String) k0 = localFn;
   //                         ^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  // [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'Null Function<T extends num>(T)'.
   void Function(String) k1 = topFn;
   //                         ^^^^^
   // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  // [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'dynamic Function<T extends num>(T)'.
 }
diff --git a/tests/language_2/enum/enum_test.dart b/tests/language_2/enum/enum_test.dart
index eb0d039..8eb762f 100644
--- a/tests/language_2/enum/enum_test.dart
+++ b/tests/language_2/enum/enum_test.dart
@@ -90,6 +90,11 @@
     expectIs(value, (e) => e is JSFunctionPrototype);
   }
   Expect.equals(JSFunctionPrototype.length, JSFunctionPrototype.values[0]);
+
+  // Enums implement Enum.
+  Expect.type<Enum>(Enum1._);
+  Enum enumValue = Enum1._;
+  Expect.equals(0, enumValue.index);
 }
 
 test1(Enum1 e) {
diff --git a/tests/language_2/unsorted/inference_enum_list_test.dart b/tests/language_2/unsorted/inference_enum_list_test.dart
index 66e7a00..45ec575 100644
--- a/tests/language_2/unsorted/inference_enum_list_test.dart
+++ b/tests/language_2/unsorted/inference_enum_list_test.dart
@@ -6,11 +6,12 @@
 
 enum E1 { a, b }
 enum E2 { a, b }
+enum E3 { a, b }
 
 var v = [E1.a, E2.b];
 
 main() {
-  // Test that v is `List<Object>`, so any of these assignemnts are OK.
-  v[0] = 0;
-  v[1] = '1';
+  // Test that v is `List<Enum>`, so these assignments are OK.
+  v[0] = E3.a;
+  List<Enum> w = v;
 }
diff --git a/tests/web/internal/mock_libraries.dart b/tests/web/internal/mock_libraries.dart
index f747443..9f0be35 100644
--- a/tests/web/internal/mock_libraries.dart
+++ b/tests/web/internal/mock_libraries.dart
@@ -50,6 +50,10 @@
         static var nan = 0;
         static parse(s) {}
       }''',
+  'Enum': r'''
+      abstract class Enum {
+        int get index;
+      }''',
   'Function': r'''
       class Function {
         static apply(Function fn, List positional, [Map named]) => null;
diff --git a/tools/VERSION b/tools/VERSION
index 2264ce2..54a920f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 248
+PRERELEASE 249
 PRERELEASE_PATCH 0
\ No newline at end of file