Version 2.15.0-80.0.dev

Merge commit '21cbe332fddc90b337045c7cbec66d64dbb84f55' into 'dev'
diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart
index a7b3682..b67b63c 100644
--- a/pkg/analysis_server/benchmark/perf/memory_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart
@@ -254,14 +254,11 @@
 
     var total = 0;
 
-    List isolateRefs = vm['isolates'];
-    for (Map isolateRef in isolateRefs) {
-      var isolate =
-          await service.call('getIsolate', {'isolateId': isolateRef['id']});
-
-      Map _heaps = isolate['_heaps'];
-      total += _heaps['new']['used'] + _heaps['new']['external'] as int;
-      total += _heaps['old']['used'] + _heaps['old']['external'] as int;
+    List isolateGroupsRefs = vm['isolateGroups'];
+    for (Map isolateGroupRef in isolateGroupsRefs) {
+      final heapUsage = await service.call('getIsolateGroupMemoryUsage',
+          {'isolateGroupId': isolateGroupRef['id']});
+      total += heapUsage['heapUsage'] + heapUsage['externalUsage'] as int;
     }
 
     service.dispose();
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index cccab31..be4cdbe 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -75,9 +75,10 @@
 
   /// Validates that there is an identifier region at [regionSearch] with target
   /// at [targetSearch].
-  void assertHasRegionTarget(String regionSearch, String targetSearch) {
+  void assertHasRegionTarget(String regionSearch, String targetSearch,
+      {int targetLength = -1}) {
     assertHasRegion(regionSearch);
-    assertHasTarget(targetSearch);
+    assertHasTarget(targetSearch, targetLength);
   }
 
   /// Validates that there is a target in [testTargets]  with [testFile], at the
@@ -391,6 +392,62 @@
     assertHasRegionTarget('BBB p', 'BBB {}');
   }
 
+  Future<void> test_constructorReference_named() async {
+    addTestFile('''
+class A {}
+class B<T> {
+  B.named();
+}
+void f() {
+  B<A>.named;
+}
+''');
+    await prepareNavigation();
+    assertHasRegionTarget('B<A>.named;', 'named();');
+    assertHasRegionTarget('named;', 'named();');
+    assertHasRegionTarget('A>', 'A {}');
+  }
+
+  Future<void> test_constructorReference_unnamed_declared() async {
+    addTestFile('''
+class A {
+  A();
+}
+void f() {
+  A.new;
+}
+''');
+    await prepareNavigation();
+    assertHasRegionTarget('A.new;', 'A();', targetLength: 0);
+    assertHasRegionTarget('new;', 'A();', targetLength: 0);
+  }
+
+  Future<void> test_constructorReference_unnamed_declared_new() async {
+    addTestFile('''
+class A {
+  A.new();
+}
+void f() {
+  A.new;
+}
+''');
+    await prepareNavigation();
+    assertHasRegionTarget('A.new;', 'new();');
+    assertHasRegionTarget('new;', 'new();');
+  }
+
+  Future<void> test_constructorReference_unnamed_default() async {
+    addTestFile('''
+class A {}
+void f() {
+  A.new;
+}
+''');
+    await prepareNavigation();
+    assertHasRegionTarget('A.new;', 'A {}');
+    assertHasRegionTarget('new;', 'A {}');
+  }
+
   Future<void> test_enum_constant() async {
     addTestFile('''
 enum E { a, b }
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
index 7927eca..38d0316 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
@@ -334,8 +334,12 @@
     }
 
     // Stop infinite recursion via links.
-    var canonicalFolderPath = folder.resolveSymbolicLinksSync().path;
-    if (!visited.add(canonicalFolderPath)) {
+    try {
+      var canonicalFolderPath = folder.resolveSymbolicLinksSync().path;
+      if (!visited.add(canonicalFolderPath)) {
+        return;
+      }
+    } on FileSystemException {
       return;
     }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_root.dart b/pkg/analyzer/lib/src/dart/analysis/context_root.dart
index 068948f..58a4b93 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_root.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_root.dart
@@ -96,13 +96,25 @@
     Folder folder,
     String includedPath,
   ) sync* {
-    for (Resource resource in folder.getChildren()) {
+    List<Resource> children;
+    try {
+      children = folder.getChildren();
+    } on FileSystemException {
+      return;
+    }
+
+    for (Resource resource in children) {
       String path = resource.path;
       if (!_isExcluded(path, includedPath)) {
         if (resource is File) {
           yield path;
         } else if (resource is Folder) {
-          var canonicalPath = resource.resolveSymbolicLinksSync().path;
+          String canonicalPath;
+          try {
+            canonicalPath = resource.resolveSymbolicLinksSync().path;
+          } on FileSystemException {
+            return;
+          }
           if (visited.add(canonicalPath)) {
             yield* _includedFilesInFolder(visited, resource, includedPath);
             visited.remove(canonicalPath);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 87fd68d..edcf6c3 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1526,6 +1526,16 @@
   ElementKind get kind => ElementKind.CONSTRUCTOR;
 
   @override
+  int get nameLength {
+    final nameEnd = this.nameEnd;
+    if (nameEnd == null || periodOffset == null) {
+      return 0;
+    } else {
+      return nameEnd - nameOffset;
+    }
+  }
+
+  @override
   Element get nonSynthetic {
     return isSynthetic ? enclosingElement : this;
   }
diff --git a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
index 63b08a5..31462c1 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
@@ -95,6 +95,36 @@
     ]);
   }
 
+  void test_locateRoots_link_folder_notExistingTarget() {
+    var rootFolder = newFolder('/test');
+    newFile('/test/lib/a.dart');
+    newFolder('/test/lib/foo');
+    resourceProvider.newLink(
+      convertPath('/test/lib/foo'),
+      convertPath('/test/lib/bar'),
+    );
+
+    var roots = contextLocator.locateRoots(
+      includedPaths: [rootFolder.path],
+    );
+    expect(roots, hasLength(1));
+
+    var root = findRoot(roots, rootFolder);
+    expect(root.includedPaths, unorderedEquals([rootFolder.path]));
+    expect(root.excludedPaths, isEmpty);
+    expect(root.optionsFile, isNull);
+    expect(root.packagesFile, isNull);
+
+    _assertAnalyzedFiles(root, [
+      '/test/lib/a.dart',
+    ]);
+
+    _assertAnalyzed(root, [
+      '/test/lib/a.dart',
+      '/test/lib/foo/b.dart',
+    ]);
+  }
+
   void test_locateRoots_link_folder_toParentInRoot() {
     Folder rootFolder = newFolder('/test');
     newFile('/test/lib/a.dart');
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 557e7c1..ec74ce8 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -310,13 +310,27 @@
 
   @override
   void visitConstructorName(ConstructorName node) {
-    var parent = node.parent;
-    if (parent is InstanceCreationExpression &&
-        parent.constructorName == node) {
-      _addConstructorName(parent, node);
-    } else if (parent is ConstructorDeclaration &&
-        parent.redirectedConstructor == node) {
-      _addConstructorName(node, node);
+    Element? element = node.staticElement;
+    if (element == null) {
+      return;
+    }
+    // add regions
+    var typeName = node.type;
+    // [prefix].ClassName
+    {
+      var name = typeName.name;
+      var className = name;
+      if (name is PrefixedIdentifier) {
+        name.prefix.accept(this);
+        className = name.identifier;
+      }
+      computer._addRegionForNode(className, element);
+    }
+    // <TypeA, TypeB>
+    typeName.typeArguments?.accept(this);
+    // optional "name"
+    if (node.name != null) {
+      computer._addRegionForNode(node.name, element);
     }
   }
 
@@ -459,34 +473,6 @@
     super.visitVariableDeclarationList(node);
   }
 
-  void _addConstructorName(AstNode parent, ConstructorName node) {
-    Element? element = node.staticElement;
-    if (element == null) {
-      return;
-    }
-    // add regions
-    var typeName = node.type;
-    // [prefix].ClassName
-    {
-      var name = typeName.name;
-      var className = name;
-      if (name is PrefixedIdentifier) {
-        name.prefix.accept(this);
-        className = name.identifier;
-      }
-      computer._addRegionForNode(className, element);
-    }
-    // <TypeA, TypeB>
-    var typeArguments = typeName.typeArguments;
-    if (typeArguments != null) {
-      typeArguments.accept(this);
-    }
-    // optional "name"
-    if (node.name != null) {
-      computer._addRegionForNode(node.name, element);
-    }
-  }
-
   /// If the source of the given [element] (referenced by the [node]) exists,
   /// then add the navigation region from the [node] to the [element].
   void _addUriDirectiveRegion(UriBasedDirective node, Element? element) {
diff --git a/pkg/compiler/lib/src/deferred_load/algorithm_state.dart b/pkg/compiler/lib/src/deferred_load/algorithm_state.dart
index fca24eb..ad11986 100644
--- a/pkg/compiler/lib/src/deferred_load/algorithm_state.dart
+++ b/pkg/compiler/lib/src/deferred_load/algorithm_state.dart
@@ -145,4 +145,14 @@
       queue.processNextItem(this);
     }
   }
+
+  /// Processes each [ImportSet], applying [SetTransition]s if their
+  /// prerequisites are met.
+  void applySetTransitions() {
+    var imports = entityToSet.values.toSet();
+    var finalTransitions = importSets.computeFinalTransitions(imports);
+    for (var key in entityToSet.keys) {
+      entityToSet[key] = finalTransitions[entityToSet[key]];
+    }
+  }
 }
diff --git a/pkg/compiler/lib/src/deferred_load/deferred_load.dart b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
index 38da9db..d741a38 100644
--- a/pkg/compiler/lib/src/deferred_load/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
@@ -366,11 +366,16 @@
 
   /// Computes a unique string for the name field for each outputUnit.
   void _createOutputUnits() {
+    // Before finalizing [OutputUnit]s, we apply [ImportSetTransition]s.
+    measureSubtask('apply set transitions', () {
+      algorithmState?.applySetTransitions();
+    });
+
+    // Add an [OutputUnit] for each [ImportSet].
     int counter = 1;
     void addUnit(ImportSet importSet) {
       if (importSet.unit != null) return;
-      var unit = OutputUnit(false, '$counter',
-          importSet.collectImports().map((i) => i.declaration).toSet());
+      var unit = OutputUnit(false, '$counter', importSet.toSet());
       counter++;
       importSet.unit = unit;
       _allOutputUnits.add(unit);
@@ -535,8 +540,9 @@
       // them now.
       if (compiler.programSplitConstraintsData != null) {
         var builder = psc.Builder(compiler.programSplitConstraintsData);
-        var transitions = builder.buildTransitionsMap(_allDeferredImports);
-        importSets.buildInitialSets(transitions);
+        var transitions = builder.build(_allDeferredImports);
+        importSets.buildInitialSets(transitions.singletonTransitions);
+        importSets.buildSetTransitions(transitions.setTransitions);
       }
 
       // Build the [ImportSet] representing the [_mainOutputUnit].
diff --git a/pkg/compiler/lib/src/deferred_load/import_set.dart b/pkg/compiler/lib/src/deferred_load/import_set.dart
index 984f7cb..9bf3816 100644
--- a/pkg/compiler/lib/src/deferred_load/import_set.dart
+++ b/pkg/compiler/lib/src/deferred_load/import_set.dart
@@ -4,9 +4,25 @@
 
 import 'output_unit.dart';
 
+import 'program_split_constraints/builder.dart' as psc show SetTransition;
+
 import '../elements/entities.dart';
 import '../util/maplet.dart';
 
+/// An [ImportSetTransition] is similar to a [SetTransition]
+/// except its source and transitions are represented as a single [ImportSet].
+class ImportSetTransition {
+  /// The [ImportSet] which, if contained in another [ImportSet] means
+  /// [transitions] should be applied.
+  final ImportSet source;
+
+  /// The [ImportSet] which should be applied if [source] is present in an
+  /// [ImportSet].
+  final ImportSet transitions;
+
+  ImportSetTransition(this.source, this.transitions);
+}
+
 /// Indirectly represents a deferred import in an [ImportSet].
 ///
 /// We could directly store the [declaration] in [ImportSet], but adding this
@@ -34,6 +50,10 @@
   /// A map of [ImportEntity] to its initial [ImportSet].
   final Map<ImportEntity, ImportSet> initialSets = {};
 
+  /// A list of [ImportSetTransition]s which should be applied to
+  /// [ImportSet]s either during [union] or just before finalization.
+  final List<ImportSetTransition> importSetTransitions = [];
+
   /// Index of deferred imports that defines the canonical order used by the
   /// operations below.
   Map<ImportEntity, _DeferredImport> _importIndex = {};
@@ -90,6 +110,16 @@
     });
   }
 
+  /// Builds a list of [ImportSetTransition]s which should be applied
+  /// before finalizing [ImportSet]s.
+  void buildSetTransitions(List<psc.SetTransition> setTransitions) {
+    setTransitions.forEach((setTransition) {
+      importSetTransitions.add(ImportSetTransition(
+          setOfImportsToImportSet(setTransition.source),
+          setOfImportsToImportSet(setTransition.transitions)));
+    });
+  }
+
   /// Get the import set that includes the union of [a] and [b].
   ImportSet union(ImportSet a, ImportSet b) {
     if (a == null || a.isEmpty) return b;
@@ -135,6 +165,52 @@
     return result;
   }
 
+  /// Computes a map of transitions, such that the key of every entry in the map
+  /// should be replaced with the value.
+  Map<ImportSet, ImportSet> computeFinalTransitions(Set<ImportSet> imports) {
+    var finalTransitions = <ImportSet, ImportSet>{};
+    var allCandidateTransitions = <ImportSet, Set<ImportSetTransition>>{};
+    bool process(ImportSet originalImportSet) {
+      // If we've already got [finalTransitions] for this [originalImportSet],
+      // i.e. if we've processed it before, we use the processed [ImportSet] for
+      // the next iteration.
+      var importSet = finalTransitions[originalImportSet] ?? originalImportSet;
+      var appliedTransitions = <ImportSetTransition>[];
+
+      // Try and apply any [ImportSetTransition]s that have not yet been
+      // applied to this [ImportSet].
+      var candidateTransitions = allCandidateTransitions[originalImportSet];
+      for (var transition in candidateTransitions) {
+        if (originalImportSet.containsAll(transition.source)) {
+          importSet = union(importSet, transition.transitions);
+          appliedTransitions.add(transition);
+        }
+      }
+
+      // Update [finalTransitions] and remove any applied transitions from
+      // [transitionsToApply] so that they will not be applied again.
+      finalTransitions[originalImportSet] = importSet;
+      candidateTransitions.removeAll(appliedTransitions);
+      return appliedTransitions.isNotEmpty;
+    }
+
+    for (var import in imports) {
+      allCandidateTransitions[import] = importSetTransitions.toSet();
+    }
+
+    // Determine any final transitions.
+    // Note: We have to keep running this algorithm until we reach a fixed
+    // point.
+    var hasChanges = true;
+    do {
+      hasChanges = false;
+      for (var import in imports) {
+        hasChanges |= process(import);
+      }
+    } while (hasChanges);
+    return finalTransitions;
+  }
+
   /// Get the index for an [import] according to the canonical order.
   _DeferredImport _wrap(ImportEntity import) {
     return _importIndex[import] ??=
@@ -182,6 +258,25 @@
   /// The output unit corresponding to this set of imports, if any.
   OutputUnit unit;
 
+  /// Returns true if this [ImportSet] contains all of [other].
+  bool containsAll(ImportSet other) {
+    var current = this;
+    while (true) {
+      if (other.isEmpty) return true;
+      if (current.isEmpty) return false;
+
+      if (current._import.index > other._import.index) {
+        current = current._previous;
+      } else if (other._import.index > current._import.index) {
+        return false;
+      } else {
+        assert(current._import.index == other._import.index);
+        current = current._previous;
+        other = other._previous;
+      }
+    }
+  }
+
   /// Create an import set that adds [import] to all the imports on this set.
   /// This assumes that import's canonical order comes after all imports in
   /// this current set. This should only be called from [ImportSetLattice],
@@ -201,4 +296,9 @@
     sb.write(')');
     return '$sb';
   }
+
+  /// Converts an [ImportSet] to a [Set<ImportEntity].
+  /// Note: Not for performance sensitive code.
+  Set<ImportEntity> toSet() =>
+      collectImports().map((i) => i.declaration).toSet();
 }
diff --git a/pkg/compiler/lib/src/deferred_load/program_split_constraints/builder.dart b/pkg/compiler/lib/src/deferred_load/program_split_constraints/builder.dart
index c270a19..2520547 100644
--- a/pkg/compiler/lib/src/deferred_load/program_split_constraints/builder.dart
+++ b/pkg/compiler/lib/src/deferred_load/program_split_constraints/builder.dart
@@ -28,6 +28,14 @@
   /// Imports which load before [import].
   final Set<Constraint> predecessors = {};
 
+  /// Whether or not this [ConstraintNode] should always apply transitions as
+  /// opposed to conditionally applying transitions.
+  bool get alwaysApplyTransitions {
+    return combinerType == null ||
+        combinerType == CombinerType.and ||
+        combinerType == CombinerType.fuse;
+  }
+
   Constraint(this.name, this.imports, this.combinerType) {
     assert((this.imports.length == 1 && combinerType == null) ||
         (this.imports.length > 1 && combinerType != null));
@@ -65,10 +73,9 @@
 
   Builder(this.nodes);
 
-  /// Builds a map of transitions which can be applied by an [ImportSetLattice]
-  /// when generating [ImportSet]s.
-  Map<ImportEntity, Set<ImportEntity>> buildTransitionsMap(
-      Iterable<ImportEntity> imports) {
+  /// Builds [ProgramSplitConstraints]  which can be applied by an
+  /// [ImportSetLattice] when generating [ImportSet]s.
+  ProgramSplitConstraints build(Iterable<ImportEntity> imports) {
     // 1) Create a map of uri#prefix to [ImportEntity].
     Map<Uri, Map<String, ImportEntity>> importsByUriAndPrefix = {};
     for (var import in imports) {
@@ -126,7 +133,8 @@
     // transitiveTransitions, where each key is a parent [ImportEntity] and each
     // value represents the transitive set of child [ImportEntity]s which are
     // always loaded after the parent.
-    Map<ImportEntity, Set<ImportEntity>> transitiveTransitions = {};
+    Map<ImportEntity, Set<ImportEntity>> singletonTransitions = {};
+    Map<Constraint, SetTransition> setTransitions = {};
     Queue<_WorkItem> queue = Queue.from(nodeToConstraintMap.values
         .where((node) => node.successors.isEmpty)
         .map((node) => _WorkItem(node)));
@@ -138,18 +146,29 @@
       // Update [transitiveTransitions] with reachable transitions for this
       // [_WorkItem]
       var transitiveChildren = item.transitiveChildren;
-      for (var import in imports) {
-        // We insert an implicit 'self' transition for every import.
-        var transitions = transitiveTransitions[import] ??= {import};
 
-        // In the case of [CombinerType.fuse], the nodes in the
-        // [Constraint] form a strongly connected component,
-        // i.e. [ImportEntity]s that are always part of a
-        // single [ImportSet].
-        if (constraint.combinerType == CombinerType.fuse) {
-          transitions.addAll(imports);
+      // We only add singletonTransitions for a given [ImportEntity] when it is
+      // guaranteed to dominate another [ImportEntity]. Some nodes such as 'or'
+      // nodes do not have this property.
+      if (constraint.alwaysApplyTransitions) {
+        for (var import in imports) {
+          // We insert an implicit 'self' transition for every import.
+          var transitions = singletonTransitions[import] ??= {import};
+
+          // In the case of [CombinerType.fuse], the nodes in the
+          // [Constraint] form a strongly connected component,
+          // i.e. [ImportEntity]s that are always part of a
+          // single [ImportSet].
+          if (constraint.combinerType == CombinerType.fuse) {
+            transitions.addAll(imports);
+          }
+          transitions.addAll(transitiveChildren);
         }
-        transitions.addAll(transitiveChildren);
+      } else {
+        assert(constraint.combinerType == CombinerType.or);
+        var setTransition =
+            setTransitions[constraint] ??= SetTransition(constraint.imports);
+        setTransition.transitions.addAll(transitiveChildren);
       }
 
       // Propagate constraints transitively to the parent.
@@ -162,6 +181,34 @@
             transitiveChildren: predecessorTransitiveChildren));
       }
     }
-    return transitiveTransitions;
+    return ProgramSplitConstraints(
+        singletonTransitions, setTransitions.values.toList());
   }
 }
+
+/// A [SetTransition] is a set of [ImportEntity] transitions which can only be
+/// applied when all of the [ImportEntity]s in a given [source] are present in a
+/// given [ImportSet].
+class SetTransition {
+  /// The [Set<ImportEntity>] which, if present in a given [ImportSet] means
+  /// [transitions] should be applied.
+  final Set<ImportEntity> source;
+
+  /// The [Set<ImportEntity>] which is applied if [source] is present in a
+  /// given [ImportSet].
+  final Set<ImportEntity> transitions = {};
+
+  SetTransition(this.source);
+}
+
+/// [ProgramSplitConstraints] is a holder for transitions which should be
+/// applied while splitting a program.
+class ProgramSplitConstraints {
+  /// Transitions which apply when a singleton [ImportEntity] is present.
+  final Map<ImportEntity, Set<ImportEntity>> singletonTransitions;
+
+  /// Transitions which apply only when a set of [ImportEntity]s is present.
+  final List<SetTransition> setTransitions;
+
+  ProgramSplitConstraints(this.singletonTransitions, this.setTransitions);
+}
diff --git a/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart b/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
index ea8a9d6..33f7b58 100644
--- a/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
+++ b/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
@@ -28,7 +28,7 @@
 
 /// A [CombinerType] defines how to combine multiple [ReferenceNode]s in a
 /// single step.
-enum CombinerType { fuse, and }
+enum CombinerType { fuse, and, or }
 
 /// A [CombinerNode] is a [NamedNode] with a list of [ReferenceNode] children
 /// and a [CombinerType] for combining them.
diff --git a/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart b/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
index 3333d8a..a758569 100644
--- a/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
+++ b/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
@@ -43,6 +43,8 @@
         return CombinerType.fuse;
       case 'and':
         return CombinerType.and;
+      case 'or':
+        return CombinerType.or;
       default:
         throw 'Unrecognized Combiner $nodeJson';
     }
@@ -92,6 +94,7 @@
           break;
         case 'and':
         case 'fuse':
+        case 'or':
           combinerConstraints.add(constraint);
           break;
         case 'order':
diff --git a/pkg/compiler/test/custom_split/custom_split_test.dart b/pkg/compiler/test/custom_split/custom_split_test.dart
index 3411e25..5203eb3 100644
--- a/pkg/compiler/test/custom_split/custom_split_test.dart
+++ b/pkg/compiler/test/custom_split/custom_split_test.dart
@@ -17,6 +17,7 @@
   'diamond',
   'diamond_and',
   'diamond_fuse',
+  'diamond_or',
   'two_step',
   'two_branch',
 ];
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/constraints.json b/pkg/compiler/test/custom_split/data/diamond_or/constraints.json
new file mode 100644
index 0000000..310309a
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/constraints.json
@@ -0,0 +1,40 @@
+[
+  {
+    "type": "reference",
+    "name": "s1",
+    "import": "memory:sdk/tests/web/native/main.dart#step1"
+  },
+  {
+    "type": "reference",
+    "name": "s2a",
+    "import": "memory:sdk/tests/web/native/main.dart#step2a"
+  },
+  {
+    "type": "reference",
+    "name": "s2b",
+    "import": "memory:sdk/tests/web/native/main.dart#step2b"
+  },
+  {
+    "type": "reference",
+    "name": "s3",
+    "import": "memory:sdk/tests/web/native/main.dart#step3"
+  },
+  {
+    "type": "or",
+    "name": "s2",
+    "nodes": [
+      "s2a",
+      "s2b"
+    ]
+  },
+  {
+    "type": "order",
+    "predecessor": "s1",
+    "successor": "s2"
+  },
+  {
+    "type": "order",
+    "predecessor": "s2",
+    "successor": "s3"
+  }
+]
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/main.dart b/pkg/compiler/test/custom_split/data/diamond_or/main.dart
new file mode 100644
index 0000000..eeac09b
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/main.dart
@@ -0,0 +1,47 @@
+// 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.
+
+/*library: 
+ a_pre_fragments=[
+  p1: {units: [2{step2a}], usedBy: [], needs: []},
+  p2: {units: [5{step2b}], usedBy: [], needs: []},
+  p3: {units: [7{step3}], usedBy: [], needs: []},
+  p4: {units: [3{step2a, step3}], usedBy: [], needs: []},
+  p5: {units: [6{step2b, step3}], usedBy: [], needs: []},
+  p6: {units: [4{step2a, step2b, step3}], usedBy: [], needs: []},
+  p7: {units: [1{step1, step2a, step2b, step3}], usedBy: [], needs: []}],
+ b_finalized_fragments=[
+  f1: [2{step2a}],
+  f2: [5{step2b}],
+  f3: [7{step3}],
+  f4: [3{step2a, step3}],
+  f5: [6{step2b, step3}],
+  f6: [4{step2a, step2b, step3}],
+  f7: [1{step1, step2a, step2b, step3}]],
+ c_steps=[
+  step1=(f7),
+  step2a=(f7, f6, f4, f1),
+  step2b=(f7, f6, f5, f2),
+  step3=(f7, f6, f5, f4, f3)]
+*/
+import 'step1.dart' deferred as step1;
+import 'step2a.dart' deferred as step2a;
+import 'step2b.dart' deferred as step2b;
+import 'step3.dart' deferred as step3;
+
+/*member: main:member_unit=main{}*/
+main() {
+  step1.loadLibrary().then(/*closure_unit=main{}*/ (_) {
+    print(step1.step());
+    step2a.loadLibrary().then(/*closure_unit=main{}*/ (_) {
+      print(step2a.step());
+    });
+    step2b.loadLibrary().then(/*closure_unit=main{}*/ (_) {
+      print(step2b.step());
+      step3.loadLibrary().then(/*closure_unit=main{}*/ (_) {
+        print(step3.step());
+      });
+    });
+  });
+}
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/shared.dart b/pkg/compiler/test/custom_split/data/diamond_or/shared.dart
new file mode 100644
index 0000000..60cec94
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/shared.dart
@@ -0,0 +1,47 @@
+// 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.
+
+@pragma('dart2js:noInline')
+/*member: step12a:member_unit=1{step1, step2a, step2b, step3}*/
+step12a() => '12a';
+
+@pragma('dart2js:noInline')
+/*member: step12a3:member_unit=1{step1, step2a, step2b, step3}*/
+step12a3() => '12a3';
+
+@pragma('dart2js:noInline')
+/*member: step2a3:member_unit=3{step2a, step3}*/
+step2a3() => '2a3';
+
+@pragma('dart2js:noInline')
+/*member: step12b:member_unit=1{step1, step2a, step2b, step3}*/
+step12b() => '12b';
+
+@pragma('dart2js:noInline')
+/*member: step12b3:member_unit=1{step1, step2a, step2b, step3}*/
+step12b3() => '12b3';
+
+@pragma('dart2js:noInline')
+/*member: step2b3:member_unit=6{step2b, step3}*/
+step2b3() => '2b3';
+
+@pragma('dart2js:noInline')
+/*member: step2ab:member_unit=4{step2a, step2b, step3}*/
+step2ab() => '2ab';
+
+@pragma('dart2js:noInline')
+/*member: step2ab3:member_unit=4{step2a, step2b, step3}*/
+step2ab3() => '2ab3';
+
+@pragma('dart2js:noInline')
+/*member: step13:member_unit=1{step1, step2a, step2b, step3}*/
+step13() => '13';
+
+@pragma('dart2js:noInline')
+/*member: step12ab:member_unit=1{step1, step2a, step2b, step3}*/
+step12ab() => '12ab';
+
+@pragma('dart2js:noInline')
+/*member: step12ab3:member_unit=1{step1, step2a, step2b, step3}*/
+step12ab3() => '12ab3';
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/step1.dart b/pkg/compiler/test/custom_split/data/diamond_or/step1.dart
new file mode 100644
index 0000000..d87a15b
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/step1.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import 'shared.dart';
+
+/*member: step:member_unit=1{step1, step2a, step2b, step3}*/
+step() => [
+      step12a(),
+      step12b(),
+      step13(),
+      step12ab(),
+      step12a3(),
+      step12b3(),
+      step12ab3(),
+    ];
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/step2a.dart b/pkg/compiler/test/custom_split/data/diamond_or/step2a.dart
new file mode 100644
index 0000000..6c52220
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/step2a.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import 'shared.dart';
+
+/*member: step:member_unit=2{step2a}*/
+step() => [
+      step12a(),
+      step12a3(),
+      step12ab(),
+      step12ab3(),
+      step2a3(),
+      step2ab(),
+      step2ab3(),
+    ];
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/step2b.dart b/pkg/compiler/test/custom_split/data/diamond_or/step2b.dart
new file mode 100644
index 0000000..46e7aca
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/step2b.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import 'shared.dart';
+
+/*member: step:member_unit=5{step2b}*/
+step() => [
+      step12b(),
+      step12b3(),
+      step12ab(),
+      step12ab3(),
+      step2b3(),
+      step2ab(),
+      step2ab3(),
+    ];
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/step3.dart b/pkg/compiler/test/custom_split/data/diamond_or/step3.dart
new file mode 100644
index 0000000..c4d45a9
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/step3.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import 'shared.dart';
+
+/*member: step:member_unit=7{step3}*/
+step() => [
+      step2a3(),
+      step2b3(),
+      step13(),
+      step2ab3(),
+      step12a3(),
+      step12b3(),
+      step12ab3(),
+    ];
diff --git a/pkg/dartdev/lib/src/analysis_server.dart b/pkg/dartdev/lib/src/analysis_server.dart
index 0d0ce90..0954378 100644
--- a/pkg/dartdev/lib/src/analysis_server.dart
+++ b/pkg/dartdev/lib/src/analysis_server.dart
@@ -27,10 +27,12 @@
     this.packagesFile,
     this.sdkPath,
     this.analysisRoots, {
+    this.cacheDirectoryPath,
     @required this.commandName,
     @required this.argResults,
   });
 
+  final String cacheDirectoryPath;
   final File packagesFile;
   final Directory sdkPath;
   final List<FileSystemEntity> analysisRoots;
@@ -87,6 +89,7 @@
       '--disable-server-feature-search',
       '--sdk',
       sdkPath.path,
+      if (cacheDirectoryPath != null) '--cache=$cacheDirectoryPath',
       if (packagesFile != null) '--packages=${packagesFile.path}',
     ];
 
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 8664577..96f0fbe 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -45,6 +45,12 @@
 
       // Options hidden by default.
       ..addOption(
+        'cache',
+        valueHelp: 'path',
+        help: 'Override the location of the analysis cache.',
+        hide: !verbose,
+      )
+      ..addOption(
         'format',
         valueHelp: 'value',
         help: 'Specifies the format to display errors.',
@@ -107,6 +113,7 @@
       _packagesFile(),
       io.Directory(sdk.sdkPath),
       targets,
+      cacheDirectoryPath: argResults['cache'],
       commandName: 'analyze',
       argResults: argResults,
     );
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index ed11a45..af8984c 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -424,6 +424,22 @@
     });
   });
 
+  test('--cache', () {
+    var cache = project(name: 'cache');
+
+    p = project(mainSrc: 'var v = 0;');
+    var result = p.runSync([
+      'analyze',
+      '--cache=${cache.dirPath}',
+      p.mainPath,
+    ]);
+
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains('No issues found!'));
+    expect(cache.findDirectory('.analysis-driver'), isNotNull);
+  });
+
   group('display mode', () {
     final sampleInfoJson = {
       'severity': 'INFO',
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index 5a64ced..ae6be55 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -141,6 +141,11 @@
   String get absolutePathToDartdevFile =>
       path.join(sdkRootPath, 'pkg', 'dartdev', 'bin', 'dartdev.dart');
 
+  Directory findDirectory(String name) {
+    var directory = Directory(path.join(dir.path, name));
+    return directory.existsSync() ? directory : null;
+  }
+
   File findFile(String name) {
     var file = File(path.join(dir.path, name));
     return file.existsSync() ? file : null;
diff --git a/pkg/dev_compiler/lib/src/compiler/js_utils.dart b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
index f6feb7d..73aeddc 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_utils.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
@@ -44,3 +44,12 @@
     super.visitAssignment(node);
   }
 }
+
+/// Recursively clears all source information from all visited nodes.
+class SourceInformationClearer extends BaseVisitor<void> {
+  @override
+  void visitNode(Node node) {
+    node.visitChildren(this);
+    node.sourceInformation = null;
+  }
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 4f3d3c5..102b0e8 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -8,6 +8,8 @@
 import 'dart:convert';
 import 'dart:math' show max, min;
 
+import 'package:front_end/src/fasta/kernel/constructor_tearoff_lowering.dart'
+    show isTearOffLowering;
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
@@ -1934,11 +1936,20 @@
       fn = _emitFunction(member.function, member.name.text);
     }
 
-    return js_ast.Method(_declareMemberName(member), fn,
+    var method = js_ast.Method(_declareMemberName(member), fn,
         isGetter: member.isGetter,
         isSetter: member.isSetter,
-        isStatic: member.isStatic)
-      ..sourceInformation = _nodeEnd(member.fileEndOffset);
+        isStatic: member.isStatic);
+
+    if (isTearOffLowering(member)) {
+      // Remove all source information from static methods introduced by the
+      // constructor tearoff CFE lowering.
+      method.accept(js_ast.SourceInformationClearer());
+    } else {
+      method.sourceInformation = _nodeEnd(member.fileEndOffset);
+    }
+
+    return method;
   }
 
   js_ast.Fun _emitNativeFunctionBody(Procedure node) {
@@ -2398,7 +2409,11 @@
     // Static members skip the rename steps and may require JS interop renames.
     if (isStatic) {
       var memberName = _emitStaticMemberName(name, member);
-      memberNames[member] = memberName.valueWithoutQuotes;
+      if (!isTearOffLowering(member)) {
+        // No need to track the names of methods that were created by the CFE
+        // lowering and don't exist in the original source code.
+        memberNames[member] = memberName.valueWithoutQuotes;
+      }
       return memberName;
     }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart b/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
index acb2bcd..7c77325e 100644
--- a/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
+++ b/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
@@ -4,6 +4,8 @@
 
 // @dart = 2.9
 
+import 'package:front_end/src/fasta/kernel/constructor_tearoff_lowering.dart'
+    show isTearOffLowering;
 import 'package:kernel/kernel.dart';
 
 import 'module_symbols.dart';
@@ -143,7 +145,10 @@
   void visitProcedure(Procedure node) {
     // Legacy libraries contain procedures with no bodies for all Object methods
     // in every class. We can ignore these unless they actually contain a body.
-    if (node.function.body == null) return;
+    //
+    // Also avoid adding information for the static methods introduced by the
+    // CFE lowering for constructor tearoffs.
+    if (node.function.body == null || isTearOffLowering(node)) return;
     var functionSymbol = FunctionSymbol(
         name: node.name.text,
         // TODO(nshahan) typeId - probably should canonicalize but keep original
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 1beb7d8..8468f28 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -48,7 +48,7 @@
   bool get supportsExplicitGetterCalls => false;
 
   @override
-  int get enabledConstructorTearOffLowerings => ConstructorTearOffLowering.none;
+  int get enabledConstructorTearOffLowerings => ConstructorTearOffLowering.all;
 
   @override
   String get name => 'dartdevc';
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index e63b928..47f9e8d 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -65,7 +65,8 @@
   });
 
   test('this', () async {
-    await expectNotNull('class C { m() { return this; } }', 'this');
+    await expectNotNull(
+        'library a; class C { m() { return this; } }', 'this, new a::C()');
   });
 
   test('is', () async {
@@ -80,7 +81,7 @@
 
   test('constructor', () async {
     await expectNotNull(
-        'library a; class C {} main() { new C(); }', 'new a::C()');
+        'library a; class C {} main() { new C(); }', 'new a::C(), new a::C()');
   });
 
   group('operator', () {
@@ -490,7 +491,7 @@
       await expectNotNull(
           'library b; $imports class C { @notNull m() {} } '
               'main() { var c = new C(); c.m(); }',
-          'new b::C(), c.{b::C.m}(), c');
+          'new b::C(), new b::C(), c.{b::C.m}(), c');
     });
   });
 }
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 2b0b76f..3f1b27e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -6345,6 +6345,13 @@
       TypeLiteral node, DartType typeContext) {
     DartType inferredType =
         inferrer.coreTypes.typeRawType(inferrer.library.nonNullable);
+    if (inferrer.library.enableConstructorTearOffsInLibrary) {
+      inferrer.library.checkBoundsInType(
+          node.type,
+          inferrer.typeSchemaEnvironment,
+          inferrer.library.fileUri,
+          node.fileOffset);
+    }
     return new ExpressionInferenceResult(inferredType, node);
   }
 
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart
new file mode 100644
index 0000000..a5c95ac
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.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.
+
+class C<T extends num> {}
+
+test() => C<Object>;
+
+test2([Type t = C<Object>]) {}
+
+var test3 = (() => C<Object>)();
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.expect
new file mode 100644
index 0000000..28d6f05
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:11:20: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// var test3 = (() => C<Object>)();
+//                    ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:7:11: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test() => C<Object>;
+//           ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:9:17: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test2([Type t = C<Object>]) {}
+//                 ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::num> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T>
+    : super core::Object::•()
+    ;
+}
+static field core::Type test3 = (() → core::Type => #C1)(){() → core::Type};
+static method test() → dynamic
+  return #C1;
+static method test2([core::Type t = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C<core::Object>)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.transformed.expect
new file mode 100644
index 0000000..28d6f05
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.strong.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:11:20: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// var test3 = (() => C<Object>)();
+//                    ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:7:11: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test() => C<Object>;
+//           ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:9:17: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test2([Type t = C<Object>]) {}
+//                 ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::num> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T>
+    : super core::Object::•()
+    ;
+}
+static field core::Type test3 = (() → core::Type => #C1)(){() → core::Type};
+static method test() → dynamic
+  return #C1;
+static method test2([core::Type t = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C<core::Object>)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline.expect
new file mode 100644
index 0000000..c95931c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+class C<T extends num> {}
+
+test() => C<Object>;
+test2([Type t = C<Object>]) {}
+var test3 = (() => C<Object>)();
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3256518
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.textual_outline_modelled.expect
@@ -0,0 +1,6 @@
+class C<T extends num> {}
+
+main() {}
+test() => C<Object>;
+test2([Type t = C<Object>]) {}
+var test3 = (() => C<Object>)();
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.expect
new file mode 100644
index 0000000..0494323
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:11:20: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// var test3 = (() => C<Object>)();
+//                    ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:7:11: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test() => C<Object>;
+//           ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:9:17: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test2([Type t = C<Object>]) {}
+//                 ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::num> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T>
+    : super core::Object::•()
+    ;
+}
+static field core::Type test3 = (() → core::Type => #C1)(){() → core::Type};
+static method test() → dynamic
+  return #C1;
+static method test2([core::Type t = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C<core::Object*>*)
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.outline.expect
new file mode 100644
index 0000000..337fe9c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.outline.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:11:20: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// var test3 = (() => C<Object>)();
+//                    ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::num> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T>
+    ;
+}
+static field core::Type test3;
+static method test() → dynamic
+  ;
+static method test2([core::Type t]) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.transformed.expect
new file mode 100644
index 0000000..0494323
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart.weak.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:11:20: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// var test3 = (() => C<Object>)();
+//                    ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:7:11: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test() => C<Object>;
+//           ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:9:17: Error: Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+//  - 'Object' is from 'dart:core'.
+// Try changing type arguments so that they conform to the bounds.
+// test2([Type t = C<Object>]) {}
+//                 ^
+// pkg/front_end/testcases/constructor_tearoffs/bound_checks_in_type_literals.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class C<T extends num> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::num> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T>
+    : super core::Object::•()
+    ;
+}
+static field core::Type test3 = (() → core::Type => #C1)(){() → core::Type};
+static method test() → dynamic
+  return #C1;
+static method test2([core::Type t = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C<core::Object*>*)
+}
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
index 203b0cf..3eaf932 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
@@ -24,9 +24,15 @@
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
     return new test::Class::_internal(defaultValue: defaultValue);
+  static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::fact(defaultValue: defaultValue);
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
     return throw "unsupported";
+  static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::constFact(defaultValue: defaultValue);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
+    return new test::Class::_internal(defaultValue: defaultValue);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
index 203b0cf..3eaf932 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
@@ -24,9 +24,15 @@
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
     return new test::Class::_internal(defaultValue: defaultValue);
+  static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::fact(defaultValue: defaultValue);
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
     return throw "unsupported";
+  static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::constFact(defaultValue: defaultValue);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
+    return new test::Class::_internal(defaultValue: defaultValue);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
index 203b0cf..3eaf932 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
@@ -24,9 +24,15 @@
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
     return new test::Class::_internal(defaultValue: defaultValue);
+  static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::fact(defaultValue: defaultValue);
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
     return throw "unsupported";
+  static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::constFact(defaultValue: defaultValue);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
+    return new test::Class::_internal(defaultValue: defaultValue);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.outline.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.outline.expect
index fe1495b..5ab22e6 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.outline.expect
@@ -21,8 +21,14 @@
     ;
   @_js::patch
   external static factory fact({core::bool defaultValue}) → self2::Class;
+  static method _#fact#tearOff({core::bool defaultValue}) → self2::Class
+    return self2::Class::fact(defaultValue: defaultValue);
   @_js::patch
   external static factory constFact({core::bool defaultValue = true}) → self2::Class;
+  static method _#constFact#tearOff({core::bool defaultValue}) → self2::Class
+    return self2::Class::constFact(defaultValue: defaultValue);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue}) → self2::Class
+    return new self2::Class::_internal(defaultValue: defaultValue);
 }
 
 
@@ -30,4 +36,4 @@
 Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:50 -> InstanceConstant(const _Patch{})
 Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:8:28 -> InstanceConstant(const _Patch{})
 Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
-Extra constant evaluation: evaluated: 4, effectively constant: 3
+Extra constant evaluation: evaluated: 10, effectively constant: 3
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
index 203b0cf..3eaf932 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
@@ -24,9 +24,15 @@
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
     return new test::Class::_internal(defaultValue: defaultValue);
+  static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::fact(defaultValue: defaultValue);
   @#C1
   static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
     return throw "unsupported";
+  static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+    return test::Class::constFact(defaultValue: defaultValue);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
+    return new test::Class::_internal(defaultValue: defaultValue);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect
index d463dc9..d249938 100644
--- a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect
@@ -10,6 +10,8 @@
     return #C1;
   get dynFunction() → dynamic
     return #C1;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect
index 977003e..e06ef9e 100644
--- a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect
@@ -10,6 +10,8 @@
     return #C1;
   get dynFunction() → dynamic
     return #C1;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
@@ -28,4 +30,4 @@
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
-Extra constant evaluation: evaluated: 20, effectively constant: 3
+Extra constant evaluation: evaluated: 21, effectively constant: 3
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect
index d463dc9..d249938 100644
--- a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect
@@ -10,6 +10,8 @@
     return #C1;
   get dynFunction() → dynamic
     return #C1;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect
index 85f75fa..41de7ee 100644
--- a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect
@@ -9,6 +9,8 @@
     ;
   get dynFunction() → dynamic
     ;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   ;
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect
index 977003e..e06ef9e 100644
--- a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect
@@ -10,6 +10,8 @@
     return #C1;
   get dynFunction() → dynamic
     return #C1;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
@@ -28,4 +30,4 @@
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
 Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
-Extra constant evaluation: evaluated: 20, effectively constant: 3
+Extra constant evaluation: evaluated: 21, effectively constant: 3
diff --git a/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.expect b/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.expect
index 3fed750..d99381b 100644
--- a/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.expect
+++ b/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.expect
@@ -7,6 +7,8 @@
     : super core::Object::•()
     ;
   method _privateMethod(covariant core::int i) → dynamic {}
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method main() → dynamic {
   new self::Class::•().{self::Class::_privateMethod}(0){(core::int) → dynamic};
diff --git a/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.transformed.expect
index 965d2e1..0941b67 100644
--- a/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/private_covariant.dart.strong.transformed.expect
@@ -7,6 +7,8 @@
     : super core::Object::•()
     ;
   method _privateMethod(core::int i) → dynamic {}
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method main() → dynamic {
   new self::Class::•().{self::Class::_privateMethod}(0){(core::int) → dynamic};
diff --git a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.expect b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.expect
index 3fed750..d99381b 100644
--- a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.expect
+++ b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.expect
@@ -7,6 +7,8 @@
     : super core::Object::•()
     ;
   method _privateMethod(covariant core::int i) → dynamic {}
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method main() → dynamic {
   new self::Class::•().{self::Class::_privateMethod}(0){(core::int) → dynamic};
diff --git a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.outline.expect b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.outline.expect
index 3a09c94..7c99f9e 100644
--- a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.outline.expect
@@ -7,6 +7,8 @@
     ;
   method _privateMethod(covariant core::int i) → dynamic
     ;
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.transformed.expect
index 965d2e1..0941b67 100644
--- a/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/private_covariant.dart.weak.transformed.expect
@@ -7,6 +7,8 @@
     : super core::Object::•()
     ;
   method _privateMethod(core::int i) → dynamic {}
+  static method _#new#tearOff() → self::Class
+    return new self::Class::•();
 }
 static method main() → dynamic {
   new self::Class::•().{self::Class::_privateMethod}(0){(core::int) → dynamic};
diff --git a/pkg/front_end/testcases/incremental/crash_01.yaml.world.1.expect b/pkg/front_end/testcases/incremental/crash_01.yaml.world.1.expect
index 137fbff..6951e96 100644
--- a/pkg/front_end/testcases/incremental/crash_01.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/crash_01.yaml.world.1.expect
@@ -12,6 +12,8 @@
     synthetic constructor •() → int::CupertinoUserInterfaceLevel
       : super fra::InheritedWidget::•()
       ;
+    static method _#new#tearOff() → int::CupertinoUserInterfaceLevel
+      return new int::CupertinoUserInterfaceLevel::•();
   }
 }
 library from "package:flutter/src/widgets/framework.dart" as fra {
diff --git a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.1.expect
index 596001e..15ee75b 100644
--- a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.1.expect
@@ -37,21 +37,29 @@
     synthetic constructor •() → fra::State2
       : super fra::State::•()
       ;
+    static method _#new#tearOff() → fra::State2
+      return new fra::State2::•();
   }
   class StatefulWidget extends dart.core::Object {
     synthetic constructor •() → fra::StatefulWidget
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::StatefulWidget
+      return new fra::StatefulWidget::•();
   }
   class Widget extends dart.core::Object {
     synthetic constructor •() → fra::Widget
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::Widget
+      return new fra::Widget::•();
   }
   class BuildContext extends dart.core::Object {
     synthetic constructor •() → fra::BuildContext
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::BuildContext
+      return new fra::BuildContext::•();
   }
   static final field fra::State<fra::StatefulWidget> state = new fra::State2::•();
   static method foo() → void {
@@ -81,11 +89,15 @@
       ;
     method build(fra::BuildContext* context) → fra::Widget* {}
     method afterFirstLayout(fra::BuildContext* context) → void {}
+    static method _#new#tearOff() → main::_HotReloadIssueState*
+      return new main::_HotReloadIssueState::•();
   }
   class HotReloadIssue extends fra::StatefulWidget {
     synthetic constructor •() → main::HotReloadIssue*
       : super fra::StatefulWidget::•()
       ;
+    static method _#new#tearOff() → main::HotReloadIssue*
+      return new main::HotReloadIssue::•();
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
     abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
diff --git a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.2.expect
index f1cc6fa..4ba21fd 100644
--- a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml.world.2.expect
@@ -37,21 +37,29 @@
     synthetic constructor •() → fra::State2
       : super fra::State::•()
       ;
+    static method _#new#tearOff() → fra::State2
+      return new fra::State2::•();
   }
   class StatefulWidget extends dart.core::Object {
     synthetic constructor •() → fra::StatefulWidget
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::StatefulWidget
+      return new fra::StatefulWidget::•();
   }
   class Widget extends dart.core::Object {
     synthetic constructor •() → fra::Widget
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::Widget
+      return new fra::Widget::•();
   }
   class BuildContext extends dart.core::Object {
     synthetic constructor •() → fra::BuildContext
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → fra::BuildContext
+      return new fra::BuildContext::•();
   }
   static final field fra::State<fra::StatefulWidget> state = new fra::State2::•();
   static method foo() → void {
@@ -81,11 +89,15 @@
       ;
     method build(fra::BuildContext* context) → fra::Widget* {}
     method afterFirstLayout(fra::BuildContext* context) → void {}
+    static method _#new#tearOff() → main::_HotReloadIssueState*
+      return new main::_HotReloadIssueState::•();
   }
   class HotReloadIssue extends fra::StatefulWidget {
     synthetic constructor •() → main::HotReloadIssue*
       : super fra::StatefulWidget::•()
       ;
+    static method _#new#tearOff() → main::HotReloadIssue*
+      return new main::HotReloadIssue::•();
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
     abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.1.expect
index aaba95f..4000948 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.1.expect
@@ -40,6 +40,8 @@
     const constructor •({dart.core::String* file = #C1, dart.core::int* line = #C1, dart.core::int* column = #C1, dart.core::String* name = #C1, dart.core::List<wid::_Location*>* parameterLocations = #C1}) → wid::_Location*
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({dart.core::String* file = #C1, dart.core::int* line = #C1, dart.core::int* column = #C1, dart.core::String* name = #C1, dart.core::List<wid::_Location*>* parameterLocations = #C1}) → wid::_Location*
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
     abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
@@ -56,8 +58,15 @@
     synthetic constructor •({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → main::Foo*
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff() → main::Foo*
+      return new main::Foo::•($creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 constants  {
   #C1 = null
+  #C2 = "org-dartlang-test:///main.dart"
+  #C3 = 5.0
+  #C4 = 7.0
+  #C5 = "Foo"
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.2.expect
index aaba95f..4000948 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml.world.2.expect
@@ -40,6 +40,8 @@
     const constructor •({dart.core::String* file = #C1, dart.core::int* line = #C1, dart.core::int* column = #C1, dart.core::String* name = #C1, dart.core::List<wid::_Location*>* parameterLocations = #C1}) → wid::_Location*
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({dart.core::String* file = #C1, dart.core::int* line = #C1, dart.core::int* column = #C1, dart.core::String* name = #C1, dart.core::List<wid::_Location*>* parameterLocations = #C1}) → wid::_Location*
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
     abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
@@ -56,8 +58,15 @@
     synthetic constructor •({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → main::Foo*
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff() → main::Foo*
+      return new main::Foo::•($creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 constants  {
   #C1 = null
+  #C2 = "org-dartlang-test:///main.dart"
+  #C3 = 5.0
+  #C4 = 7.0
+  #C5 = "Foo"
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.1.expect
index e334a8f..41475f6 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.1.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -43,6 +45,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       return #C7;
+    static method _#new#tearOff() → foo::Foo
+      return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C9);
+    static method _#_#tearOff() → foo::Foo
+      return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C12);
   }
   class Bar extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isLegacy*/;
@@ -51,6 +57,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Bar
       return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#new#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C16);
+    static method _#_#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
   }
   class Baz extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isLegacy*/;
@@ -58,9 +68,15 @@
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
-      return #C11;
+      return #C22;
+    static method _#new#tearOff() → foo::Baz
+      return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C23);
     static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
       return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#_#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C25);
+    static method _#__#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
   }
   class Boz extends fra::Widget /*hasConstConstructor*/  {
     const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Boz
@@ -71,21 +87,25 @@
         return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
       }
       else {
-        return #C16;
+        return #C32;
       }
     }
+    static method _#new#tearOff({required dart.core::bool createNew = #C1}) → foo::Boz
+      return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C33);
+    static method _#_#tearOff() → foo::Boz
+      return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C35);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
 
   import "org-dartlang-test:///foo.dart";
 
-  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C19);
-  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C22);
-  static field foo::Bar constBar = #C26;
-  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C28);
-  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C29);
-  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C32);
+  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C38);
+  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C39);
+  static field foo::Bar constBar = #C42;
+  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C43);
+  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C44);
+  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C46);
 }
 constants  {
   #C1 = null
@@ -95,29 +115,43 @@
   #C5 = "Foo"
   #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
   #C7 = foo::Foo {_location:#C6}
-  #C8 = 6.0
-  #C9 = "Baz"
-  #C10 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C9, parameterLocations:#C1}
-  #C11 = foo::Baz {_location:#C10}
-  #C12 = 9.0
-  #C13 = 128.0
-  #C14 = "Boz"
-  #C15 = wid::_Location {file:#C2, line:#C12, column:#C13, name:#C14, parameterLocations:#C1}
-  #C16 = foo::Boz {_location:#C15}
-  #C17 = "org-dartlang-test:///main.dart"
-  #C18 = 18.0
-  #C19 = wid::_Location {file:#C17, line:#C3, column:#C18, name:#C5, parameterLocations:#C1}
-  #C20 = 3.0
-  #C21 = "Bar"
-  #C22 = wid::_Location {file:#C17, line:#C20, column:#C18, name:#C21, parameterLocations:#C1}
-  #C23 = 4.0
-  #C24 = 22.0
-  #C25 = wid::_Location {file:#C17, line:#C23, column:#C24, name:#C21, parameterLocations:#C1}
-  #C26 = foo::Bar {_location:#C25}
-  #C27 = 5.0
-  #C28 = wid::_Location {file:#C17, line:#C27, column:#C18, name:#C9, parameterLocations:#C1}
-  #C29 = wid::_Location {file:#C17, line:#C8, column:#C18, name:#C14, parameterLocations:#C1}
-  #C30 = 7.0
-  #C31 = 20.0
-  #C32 = wid::_Location {file:#C17, line:#C30, column:#C31, name:#C14, parameterLocations:#C1}
+  #C8 = 36.0
+  #C9 = wid::_Location {file:#C2, line:#C3, column:#C8, name:#C5, parameterLocations:#C1}
+  #C10 = 3.0
+  #C11 = 7.0
+  #C12 = wid::_Location {file:#C2, line:#C10, column:#C11, name:#C5, parameterLocations:#C1}
+  #C13 = 4.0
+  #C14 = 42.0
+  #C15 = "Bar"
+  #C16 = wid::_Location {file:#C2, line:#C13, column:#C14, name:#C15, parameterLocations:#C1}
+  #C17 = 5.0
+  #C18 = wid::_Location {file:#C2, line:#C17, column:#C11, name:#C15, parameterLocations:#C1}
+  #C19 = 6.0
+  #C20 = "Baz"
+  #C21 = wid::_Location {file:#C2, line:#C19, column:#C4, name:#C20, parameterLocations:#C1}
+  #C22 = foo::Baz {_location:#C21}
+  #C23 = wid::_Location {file:#C2, line:#C19, column:#C8, name:#C20, parameterLocations:#C1}
+  #C24 = 15.0
+  #C25 = wid::_Location {file:#C2, line:#C11, column:#C24, name:#C20, parameterLocations:#C1}
+  #C26 = 8.0
+  #C27 = wid::_Location {file:#C2, line:#C26, column:#C11, name:#C20, parameterLocations:#C1}
+  #C28 = 9.0
+  #C29 = 128.0
+  #C30 = "Boz"
+  #C31 = wid::_Location {file:#C2, line:#C28, column:#C29, name:#C30, parameterLocations:#C1}
+  #C32 = foo::Boz {_location:#C31}
+  #C33 = wid::_Location {file:#C2, line:#C28, column:#C8, name:#C30, parameterLocations:#C1}
+  #C34 = 10.0
+  #C35 = wid::_Location {file:#C2, line:#C34, column:#C11, name:#C30, parameterLocations:#C1}
+  #C36 = "org-dartlang-test:///main.dart"
+  #C37 = 18.0
+  #C38 = wid::_Location {file:#C36, line:#C3, column:#C37, name:#C5, parameterLocations:#C1}
+  #C39 = wid::_Location {file:#C36, line:#C10, column:#C37, name:#C15, parameterLocations:#C1}
+  #C40 = 22.0
+  #C41 = wid::_Location {file:#C36, line:#C13, column:#C40, name:#C15, parameterLocations:#C1}
+  #C42 = foo::Bar {_location:#C41}
+  #C43 = wid::_Location {file:#C36, line:#C17, column:#C37, name:#C20, parameterLocations:#C1}
+  #C44 = wid::_Location {file:#C36, line:#C19, column:#C37, name:#C30, parameterLocations:#C1}
+  #C45 = 20.0
+  #C46 = wid::_Location {file:#C36, line:#C11, column:#C45, name:#C30, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.2.expect
index c1f530e..6f610b2 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.2.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -43,6 +45,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       return #C7;
+    static method _#new#tearOff() → foo::Foo
+      return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C9);
+    static method _#_#tearOff() → foo::Foo
+      return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C12);
   }
   class Bar extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isLegacy*/;
@@ -51,6 +57,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Bar
       return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#new#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C16);
+    static method _#_#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
   }
   class Baz extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isLegacy*/;
@@ -58,9 +68,15 @@
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
-      return #C11;
+      return #C22;
+    static method _#new#tearOff() → foo::Baz
+      return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C23);
     static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
       return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#_#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C25);
+    static method _#__#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
   }
   class Boz extends fra::Widget /*hasConstConstructor*/  {
     const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Boz
@@ -71,9 +87,13 @@
         return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
       }
       else {
-        return #C16;
+        return #C32;
       }
     }
+    static method _#new#tearOff({required dart.core::bool createNew = #C1}) → foo::Boz
+      return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C33);
+    static method _#_#tearOff() → foo::Boz
+      return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C35);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -89,13 +109,32 @@
   #C5 = "Foo"
   #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
   #C7 = foo::Foo {_location:#C6}
-  #C8 = 6.0
-  #C9 = "Baz"
-  #C10 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C9, parameterLocations:#C1}
-  #C11 = foo::Baz {_location:#C10}
-  #C12 = 9.0
-  #C13 = 128.0
-  #C14 = "Boz"
-  #C15 = wid::_Location {file:#C2, line:#C12, column:#C13, name:#C14, parameterLocations:#C1}
-  #C16 = foo::Boz {_location:#C15}
+  #C8 = 36.0
+  #C9 = wid::_Location {file:#C2, line:#C3, column:#C8, name:#C5, parameterLocations:#C1}
+  #C10 = 3.0
+  #C11 = 7.0
+  #C12 = wid::_Location {file:#C2, line:#C10, column:#C11, name:#C5, parameterLocations:#C1}
+  #C13 = 4.0
+  #C14 = 42.0
+  #C15 = "Bar"
+  #C16 = wid::_Location {file:#C2, line:#C13, column:#C14, name:#C15, parameterLocations:#C1}
+  #C17 = 5.0
+  #C18 = wid::_Location {file:#C2, line:#C17, column:#C11, name:#C15, parameterLocations:#C1}
+  #C19 = 6.0
+  #C20 = "Baz"
+  #C21 = wid::_Location {file:#C2, line:#C19, column:#C4, name:#C20, parameterLocations:#C1}
+  #C22 = foo::Baz {_location:#C21}
+  #C23 = wid::_Location {file:#C2, line:#C19, column:#C8, name:#C20, parameterLocations:#C1}
+  #C24 = 15.0
+  #C25 = wid::_Location {file:#C2, line:#C11, column:#C24, name:#C20, parameterLocations:#C1}
+  #C26 = 8.0
+  #C27 = wid::_Location {file:#C2, line:#C26, column:#C11, name:#C20, parameterLocations:#C1}
+  #C28 = 9.0
+  #C29 = 128.0
+  #C30 = "Boz"
+  #C31 = wid::_Location {file:#C2, line:#C28, column:#C29, name:#C30, parameterLocations:#C1}
+  #C32 = foo::Boz {_location:#C31}
+  #C33 = wid::_Location {file:#C2, line:#C28, column:#C8, name:#C30, parameterLocations:#C1}
+  #C34 = 10.0
+  #C35 = wid::_Location {file:#C2, line:#C34, column:#C11, name:#C30, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.3.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.3.expect
index e334a8f..41475f6 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml.world.3.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -43,6 +45,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       return #C7;
+    static method _#new#tearOff() → foo::Foo
+      return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C9);
+    static method _#_#tearOff() → foo::Foo
+      return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C12);
   }
   class Bar extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isLegacy*/;
@@ -51,6 +57,10 @@
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Bar
       return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#new#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C16);
+    static method _#_#tearOff() → foo::Bar
+      return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
   }
   class Baz extends fra::Widget /*hasConstConstructor*/  {
     static final field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isLegacy*/;
@@ -58,9 +68,15 @@
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
     static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
-      return #C11;
+      return #C22;
+    static method _#new#tearOff() → foo::Baz
+      return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C23);
     static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Baz
       return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+    static method _#_#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C25);
+    static method _#__#tearOff() → foo::Baz
+      return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
   }
   class Boz extends fra::Widget /*hasConstConstructor*/  {
     const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Boz
@@ -71,21 +87,25 @@
         return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
       }
       else {
-        return #C16;
+        return #C32;
       }
     }
+    static method _#new#tearOff({required dart.core::bool createNew = #C1}) → foo::Boz
+      return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C33);
+    static method _#_#tearOff() → foo::Boz
+      return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C35);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
 
   import "org-dartlang-test:///foo.dart";
 
-  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C19);
-  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C22);
-  static field foo::Bar constBar = #C26;
-  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C28);
-  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C29);
-  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C32);
+  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C38);
+  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C39);
+  static field foo::Bar constBar = #C42;
+  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C43);
+  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C44);
+  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C46);
 }
 constants  {
   #C1 = null
@@ -95,29 +115,43 @@
   #C5 = "Foo"
   #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
   #C7 = foo::Foo {_location:#C6}
-  #C8 = 6.0
-  #C9 = "Baz"
-  #C10 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C9, parameterLocations:#C1}
-  #C11 = foo::Baz {_location:#C10}
-  #C12 = 9.0
-  #C13 = 128.0
-  #C14 = "Boz"
-  #C15 = wid::_Location {file:#C2, line:#C12, column:#C13, name:#C14, parameterLocations:#C1}
-  #C16 = foo::Boz {_location:#C15}
-  #C17 = "org-dartlang-test:///main.dart"
-  #C18 = 18.0
-  #C19 = wid::_Location {file:#C17, line:#C3, column:#C18, name:#C5, parameterLocations:#C1}
-  #C20 = 3.0
-  #C21 = "Bar"
-  #C22 = wid::_Location {file:#C17, line:#C20, column:#C18, name:#C21, parameterLocations:#C1}
-  #C23 = 4.0
-  #C24 = 22.0
-  #C25 = wid::_Location {file:#C17, line:#C23, column:#C24, name:#C21, parameterLocations:#C1}
-  #C26 = foo::Bar {_location:#C25}
-  #C27 = 5.0
-  #C28 = wid::_Location {file:#C17, line:#C27, column:#C18, name:#C9, parameterLocations:#C1}
-  #C29 = wid::_Location {file:#C17, line:#C8, column:#C18, name:#C14, parameterLocations:#C1}
-  #C30 = 7.0
-  #C31 = 20.0
-  #C32 = wid::_Location {file:#C17, line:#C30, column:#C31, name:#C14, parameterLocations:#C1}
+  #C8 = 36.0
+  #C9 = wid::_Location {file:#C2, line:#C3, column:#C8, name:#C5, parameterLocations:#C1}
+  #C10 = 3.0
+  #C11 = 7.0
+  #C12 = wid::_Location {file:#C2, line:#C10, column:#C11, name:#C5, parameterLocations:#C1}
+  #C13 = 4.0
+  #C14 = 42.0
+  #C15 = "Bar"
+  #C16 = wid::_Location {file:#C2, line:#C13, column:#C14, name:#C15, parameterLocations:#C1}
+  #C17 = 5.0
+  #C18 = wid::_Location {file:#C2, line:#C17, column:#C11, name:#C15, parameterLocations:#C1}
+  #C19 = 6.0
+  #C20 = "Baz"
+  #C21 = wid::_Location {file:#C2, line:#C19, column:#C4, name:#C20, parameterLocations:#C1}
+  #C22 = foo::Baz {_location:#C21}
+  #C23 = wid::_Location {file:#C2, line:#C19, column:#C8, name:#C20, parameterLocations:#C1}
+  #C24 = 15.0
+  #C25 = wid::_Location {file:#C2, line:#C11, column:#C24, name:#C20, parameterLocations:#C1}
+  #C26 = 8.0
+  #C27 = wid::_Location {file:#C2, line:#C26, column:#C11, name:#C20, parameterLocations:#C1}
+  #C28 = 9.0
+  #C29 = 128.0
+  #C30 = "Boz"
+  #C31 = wid::_Location {file:#C2, line:#C28, column:#C29, name:#C30, parameterLocations:#C1}
+  #C32 = foo::Boz {_location:#C31}
+  #C33 = wid::_Location {file:#C2, line:#C28, column:#C8, name:#C30, parameterLocations:#C1}
+  #C34 = 10.0
+  #C35 = wid::_Location {file:#C2, line:#C34, column:#C11, name:#C30, parameterLocations:#C1}
+  #C36 = "org-dartlang-test:///main.dart"
+  #C37 = 18.0
+  #C38 = wid::_Location {file:#C36, line:#C3, column:#C37, name:#C5, parameterLocations:#C1}
+  #C39 = wid::_Location {file:#C36, line:#C10, column:#C37, name:#C15, parameterLocations:#C1}
+  #C40 = 22.0
+  #C41 = wid::_Location {file:#C36, line:#C13, column:#C40, name:#C15, parameterLocations:#C1}
+  #C42 = foo::Bar {_location:#C41}
+  #C43 = wid::_Location {file:#C36, line:#C17, column:#C37, name:#C20, parameterLocations:#C1}
+  #C44 = wid::_Location {file:#C36, line:#C19, column:#C37, name:#C30, parameterLocations:#C1}
+  #C45 = 20.0
+  #C46 = wid::_Location {file:#C36, line:#C11, column:#C45, name:#C30, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.1.expect
index bf659ac..f4d0275 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.1.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -41,6 +43,8 @@
     const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff() → foo::Foo
+      return new foo::Foo::•($creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -50,4 +54,9 @@
 }
 constants  {
   #C1 = null
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 2.0
+  #C4 = 34.0
+  #C5 = "Foo"
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.2.expect
index 178186e..3fdfb87 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml.world.2.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -41,20 +43,26 @@
     const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff() → foo::Foo
+      return new foo::Foo::•($creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
 
   import "org-dartlang-test:///foo.dart";
 
-  static field foo::Foo foo = #C7;
+  static field foo::Foo foo = #C11;
 }
 constants  {
   #C1 = null
-  #C2 = "org-dartlang-test:///main.dart"
-  #C3 = 3.0
-  #C4 = 17.0
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 2.0
+  #C4 = 34.0
   #C5 = "Foo"
   #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
-  #C7 = foo::Foo {_location:#C6}
+  #C7 = "org-dartlang-test:///main.dart"
+  #C8 = 3.0
+  #C9 = 17.0
+  #C10 = wid::_Location {file:#C7, line:#C8, column:#C9, name:#C5, parameterLocations:#C1}
+  #C11 = foo::Foo {_location:#C10}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.1.expect
index 2c443b6..6704d7b 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.1.expect
@@ -36,6 +36,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -47,6 +49,8 @@
     const constructor •([dart.core::Object* key = #C1]) → foo::Foo*
       : super fra::StatelessWidget::•(key: key)
       ;
+    static method _#new#tearOff([dart.core::Object* key = #C1]) → foo::Foo*
+      return new foo::Foo::•(key);
     abstract member-signature get key() → dart.core::Object*; -> fra::Widget::key
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.2.expect
index a13a232..64a1fbd 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml.world.2.expect
@@ -36,6 +36,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -47,6 +49,8 @@
     const constructor •([dart.core::Object* key = #C1]) → foo::Foo*
       : super fra::StatelessWidget::•(key: key)
       ;
+    static method _#new#tearOff([dart.core::Object* key = #C1]) → foo::Foo*
+      return new foo::Foo::•(key);
     abstract member-signature get key() → dart.core::Object*; -> fra::Widget::key
     abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
     abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.1.expect
index 67d2066..a6fb1d9 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.1.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -42,6 +44,8 @@
     constructor •({required dart.core::String name = #C1, wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       : foo::Foo::name = name, super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff({required dart.core::String name = #C1}) → foo::Foo
+      return new foo::Foo::•(name: name, $creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -51,4 +55,9 @@
 }
 constants  {
   #C1 = null
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 3.0
+  #C4 = 1.0
+  #C5 = "Foo"
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.2.expect
index 8d1b8cf..e6b030d 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml.world.2.expect
@@ -30,6 +30,8 @@
     const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
       : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
       ;
+    static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations);
   }
 }
 library from "org-dartlang-test:///foo.dart" as foo {
@@ -42,19 +44,25 @@
     constructor •({required dart.core::String name = #C1, wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo
       : foo::Foo::name = name, super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
       ;
+    static method _#new#tearOff({required dart.core::String name = #C1}) → foo::Foo
+      return new foo::Foo::•(name: name, $creationLocationd_0dea112b090073317d4: #C6);
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
 
   import "org-dartlang-test:///foo.dart";
 
-  static field foo::Foo foo = new foo::Foo::•(name: "foo", $creationLocationd_0dea112b090073317d4: #C6);
+  static field foo::Foo foo = new foo::Foo::•(name: "foo", $creationLocationd_0dea112b090073317d4: #C10);
 }
 constants  {
   #C1 = null
-  #C2 = "org-dartlang-test:///main.dart"
-  #C3 = 2.0
-  #C4 = 15.0
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 3.0
+  #C4 = 1.0
   #C5 = "Foo"
   #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C5, parameterLocations:#C1}
+  #C7 = "org-dartlang-test:///main.dart"
+  #C8 = 2.0
+  #C9 = 15.0
+  #C10 = wid::_Location {file:#C7, line:#C8, column:#C9, name:#C5, parameterLocations:#C1}
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.1.expect
index 394b66f..b92e29e 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.1.expect
@@ -21,6 +21,8 @@
     synthetic constructor •() → wid::_Location
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → wid::_Location
+      return new wid::_Location::•();
   }
 }
 library from "org-dartlang-test:///flutter_gallery/lib/main.dart" as main {
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.2.expect
index 394b66f..b92e29e 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml.world.2.expect
@@ -21,6 +21,8 @@
     synthetic constructor •() → wid::_Location
       : super dart.core::Object::•()
       ;
+    static method _#new#tearOff() → wid::_Location
+      return new wid::_Location::•();
   }
 }
 library from "org-dartlang-test:///flutter_gallery/lib/main.dart" as main {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f900fc0..5dfb8b8 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -21,6 +21,7 @@
 #include "vm/message_handler.h"
 #include "vm/message_snapshot.h"
 #include "vm/object.h"
+#include "vm/object_graph_copy.h"
 #include "vm/object_store.h"
 #include "vm/port.h"
 #include "vm/resolver.h"
@@ -319,6 +320,7 @@
                     Dart_Port origin_id,
                     const char* script_url,
                     const Function& func,
+                    PersistentHandle* closure_tuple_handle,
                     SerializedObjectBuffer* message_buffer,
                     const char* package_config,
                     bool paused,
@@ -353,10 +355,16 @@
   const char* class_name() const { return class_name_; }
   const char* function_name() const { return function_name_; }
   const char* debug_name() const { return debug_name_; }
-  bool is_spawn_uri() const { return library_url_ == nullptr; }
+  bool is_spawn_uri() const {
+    return library_url_ == nullptr &&         // No top-level entrypoint.
+           closure_tuple_handle_ == nullptr;  // No closure entrypoint.
+  }
   bool paused() const { return paused_; }
   bool errors_are_fatal() const { return errors_are_fatal_; }
   Dart_IsolateFlags* isolate_flags() { return &isolate_flags_; }
+  PersistentHandle* closure_tuple_handle() const {
+    return closure_tuple_handle_;
+  }
 
   ObjectPtr ResolveFunction();
   ObjectPtr BuildArgs(Thread* thread);
@@ -376,6 +384,7 @@
   const char* class_name_ = nullptr;
   const char* function_name_ = nullptr;
   const char* debug_name_;
+  PersistentHandle* closure_tuple_handle_ = nullptr;
   IsolateGroup* isolate_group_;
   std::unique_ptr<Message> serialized_args_;
   std::unique_ptr<Message> serialized_message_;
@@ -396,6 +405,7 @@
                                      Dart_Port origin_id,
                                      const char* script_url,
                                      const Function& func,
+                                     PersistentHandle* closure_tuple_handle,
                                      SerializedObjectBuffer* message_buffer,
                                      const char* package_config,
                                      bool paused,
@@ -411,25 +421,34 @@
       script_url_(script_url),
       package_config_(package_config),
       debug_name_(debug_name),
+      closure_tuple_handle_(closure_tuple_handle),
       isolate_group_(isolate_group),
       serialized_args_(nullptr),
       serialized_message_(message_buffer->StealMessage()),
       paused_(paused),
       errors_are_fatal_(errors_are_fatal) {
+  // Either we have a top-level function or we have a closure.
+  ASSERT((closure_tuple_handle_ != nullptr) == func.IsNull());
+
   auto thread = Thread::Current();
   auto isolate = thread->isolate();
-  auto zone = thread->zone();
-  const auto& cls = Class::Handle(zone, func.Owner());
-  const auto& lib = Library::Handle(zone, cls.library());
-  const auto& lib_url = String::Handle(zone, lib.url());
-  library_url_ = NewConstChar(lib_url.ToCString());
 
-  String& func_name = String::Handle(zone);
-  func_name = func.name();
-  function_name_ = NewConstChar(String::ScrubName(func_name));
-  if (!cls.IsTopLevel()) {
-    const auto& class_name = String::Handle(zone, cls.Name());
-    class_name_ = NewConstChar(class_name.ToCString());
+  if (!func.IsNull()) {
+    auto zone = thread->zone();
+    const auto& cls = Class::Handle(zone, func.Owner());
+    const auto& lib = Library::Handle(zone, cls.library());
+    const auto& lib_url = String::Handle(zone, lib.url());
+    library_url_ = NewConstChar(lib_url.ToCString());
+
+    String& func_name = String::Handle(zone);
+    func_name = func.name();
+    function_name_ = NewConstChar(String::ScrubName(func_name));
+    if (!cls.IsTopLevel()) {
+      const auto& class_name = String::Handle(zone, cls.Name());
+      class_name_ = NewConstChar(class_name.ToCString());
+    }
+  } else {
+    ASSERT(closure_tuple_handle != nullptr);
   }
 
   // Inherit flags from spawning isolate.
@@ -446,14 +465,14 @@
                                      Dart_Port on_exit_port,
                                      Dart_Port on_error_port,
                                      const char* debug_name,
-                                     IsolateGroup* group)
+                                     IsolateGroup* isolate_group)
     : parent_port_(parent_port),
       on_exit_port_(on_exit_port),
       on_error_port_(on_error_port),
       script_url_(script_url),
       package_config_(package_config),
       debug_name_(debug_name),
-      isolate_group_(group),
+      isolate_group_(isolate_group),
       serialized_args_(args_buffer->StealMessage()),
       serialized_message_(message_buffer->StealMessage()),
       isolate_flags_(),
@@ -734,20 +753,32 @@
   bool EnqueueEntrypointInvocationAndNotifySpawner(Thread* thread) {
     auto isolate = thread->isolate();
     auto zone = thread->zone();
+    const bool is_spawn_uri = state_->is_spawn_uri();
 
     // Step 1) Resolve the entrypoint function.
-    auto& result = Object::Handle(zone, state_->ResolveFunction());
-    const bool is_spawn_uri = state_->is_spawn_uri();
-    if (result.IsError()) {
-      ASSERT(is_spawn_uri);
-      ReportError("Failed to resolve entrypoint function.");
-      return false;
+    auto& entrypoint_closure = Closure::Handle(zone);
+    if (state_->closure_tuple_handle() != nullptr) {
+      const auto& result = Object::Handle(
+          zone,
+          ReadObjectGraphCopyMessage(thread, state_->closure_tuple_handle()));
+      if (result.IsError()) {
+        ReportError(
+            "Failed to deserialize the passed entrypoint to the new isolate.");
+        return false;
+      }
+      entrypoint_closure = Closure::RawCast(result.ptr());
+    } else {
+      const auto& result = Object::Handle(zone, state_->ResolveFunction());
+      if (result.IsError()) {
+        ASSERT(is_spawn_uri);
+        ReportError("Failed to resolve entrypoint function.");
+        return false;
+      }
+      ASSERT(result.IsFunction());
+      auto& func = Function::Handle(zone, Function::Cast(result).ptr());
+      func = func.ImplicitClosureFunction();
+      entrypoint_closure = func.ImplicitStaticClosure();
     }
-    ASSERT(result.IsFunction());
-    auto& func = Function::Handle(zone, Function::Cast(result).ptr());
-    func = func.ImplicitClosureFunction();
-    const auto& entrypoint_closure =
-        Object::Handle(zone, func.ImplicitStaticClosure());
 
     // Step 2) Enqueue delayed invocation of entrypoint callback.
     const auto& args_obj = Object::Handle(zone, state_->BuildArgs(thread));
@@ -776,7 +807,8 @@
     const auto& entry_point =
         Function::Handle(zone, lib.LookupLocalFunction(entry_name));
     ASSERT(entry_point.IsFunction() && !entry_point.IsNull());
-    result = DartEntry::InvokeFunction(entry_point, args);
+    const auto& result =
+        Object::Handle(zone, DartEntry::InvokeFunction(entry_point, args));
     if (result.IsError()) {
       ReportError("Failed to enqueue delayed entrypoint invocation.");
       return false;
@@ -858,10 +890,23 @@
   return result;
 }
 
+static FunctionPtr GetTopLevelFunction(Zone* zone, const Instance& closure) {
+  if (closure.IsClosure()) {
+    auto& func = Function::Handle(zone);
+    func = Closure::Cast(closure).function();
+    if (func.IsImplicitClosureFunction() && func.is_static()) {
+      ASSERT(Closure::Cast(closure).context() == Context::null());
+      // Get the parent function so that we get the right function name.
+      return func.parent_function();
+    }
+  }
+  return Function::null();
+}
+
 DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 0, 10) {
   GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, script_uri, arguments->NativeArgAt(1));
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(2));
+  GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(2));
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3));
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
   GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(5));
@@ -870,51 +915,62 @@
   GET_NATIVE_ARGUMENT(String, packageConfig, arguments->NativeArgAt(8));
   GET_NATIVE_ARGUMENT(String, debugName, arguments->NativeArgAt(9));
 
-  if (closure.IsClosure()) {
-    Function& func = Function::Handle();
-    func = Closure::Cast(closure).function();
-    if (func.IsImplicitClosureFunction() && func.is_static()) {
-#if defined(DEBUG)
-      Context& ctx = Context::Handle();
-      ctx = Closure::Cast(closure).context();
-      ASSERT(ctx.IsNull());
-#endif
-      // Get the parent function so that we get the right function name.
-      func = func.parent_function();
-
-      bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
-      Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
-      Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
-
-      // We first try to serialize the message.  In case the message is not
-      // serializable this will throw an exception.
-      SerializedObjectBuffer message_buffer;
-      message_buffer.set_message(WriteMessage(
-          /* can_send_any_object */ true,
-          /* same_group */ FLAG_enable_isolate_groups, message, ILLEGAL_PORT,
-          Message::kNormalPriority));
-
-      const char* utf8_package_config =
-          packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
-      const char* utf8_debug_name =
-          debugName.IsNull() ? NULL : String2UTF8(debugName);
-
-      std::unique_ptr<IsolateSpawnState> state(new IsolateSpawnState(
-          port.Id(), isolate->origin_id(), String2UTF8(script_uri), func,
-          &message_buffer, utf8_package_config, paused.value(), fatal_errors,
-          on_exit_port, on_error_port, utf8_debug_name, isolate->group()));
-
-      // Since this is a call to Isolate.spawn, copy the parent isolate's code.
-      state->isolate_flags()->copy_parent_code = true;
-
-      isolate->group()->thread_pool()->Run<SpawnIsolateTask>(isolate,
-                                                             std::move(state));
-      return Object::null();
+  const auto& func = Function::Handle(zone, GetTopLevelFunction(zone, closure));
+  PersistentHandle* closure_tuple_handle = nullptr;
+  if (func.IsNull()) {
+    if (!FLAG_enable_isolate_groups) {
+      const String& msg = String::Handle(String::New(
+          "Isolate.spawn expects to be passed a static or top-level function"));
+      Exceptions::ThrowArgumentError(msg);
+    } else {
+      // We have a non-toplevel closure that we might need to copy.
+      // Result will be [<closure-copy>, <objects-in-msg-to-rehash>]
+      const auto& closure_copy_tuple = Object::Handle(
+          zone, CopyMutableObjectGraph(closure));  // Throws if it fails.
+      ASSERT(closure_copy_tuple.IsArray());
+      ASSERT(Object::Handle(zone, Array::Cast(closure_copy_tuple).At(0))
+                 .IsClosure());
+      closure_tuple_handle =
+          isolate->group()->api_state()->AllocatePersistentHandle();
+      closure_tuple_handle->set_ptr(closure_copy_tuple.ptr());
     }
   }
-  const String& msg = String::Handle(String::New(
-      "Isolate.spawn expects to be passed a static or top-level function"));
-  Exceptions::ThrowArgumentError(msg);
+
+  bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
+  Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
+  Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
+
+  // We first try to serialize the message.  In case the message is not
+  // serializable this will throw an exception.
+  SerializedObjectBuffer message_buffer;
+  message_buffer.set_message(WriteMessage(
+      /* can_send_any_object */ true,
+      /* same_group */ FLAG_enable_isolate_groups, message, ILLEGAL_PORT,
+      Message::kNormalPriority));
+
+  const char* utf8_package_config =
+      packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
+  const char* utf8_debug_name =
+      debugName.IsNull() ? NULL : String2UTF8(debugName);
+  if (closure_tuple_handle != nullptr && utf8_debug_name == nullptr) {
+    ASSERT(func.IsNull());
+
+    const auto& closure_function = Function::Handle(zone, closure.function());
+    utf8_debug_name =
+        NewConstChar(closure_function.QualifiedUserVisibleNameCString());
+  }
+
+  std::unique_ptr<IsolateSpawnState> state(new IsolateSpawnState(
+      port.Id(), isolate->origin_id(), String2UTF8(script_uri), func,
+      closure_tuple_handle, &message_buffer, utf8_package_config,
+      paused.value(), fatal_errors, on_exit_port, on_error_port,
+      utf8_debug_name, isolate->group()));
+
+  // Since this is a call to Isolate.spawn, copy the parent isolate's code.
+  state->isolate_flags()->copy_parent_code = true;
+
+  isolate->group()->thread_pool()->Run<SpawnIsolateTask>(isolate,
+                                                         std::move(state));
   return Object::null();
 }
 
diff --git a/runtime/tests/vm/dart/isolates/closure_entrypoint_test.dart b/runtime/tests/vm/dart/isolates/closure_entrypoint_test.dart
new file mode 100644
index 0000000..b855c4f
--- /dev/null
+++ b/runtime/tests/vm/dart/isolates/closure_entrypoint_test.dart
@@ -0,0 +1,111 @@
+// 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.
+
+// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy
+// VMOptions=--enable-isolate-groups --enable-fast-object-copy
+// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation
+// VMOptions=--enable-isolate-groups --enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation
+
+// The tests in this file will only succeed when isolate groups are enabled
+// (hence the VMOptions above).
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:expect/expect.dart';
+
+import 'fast_object_copy_test.dart' show ClassWithNativeFields;
+
+class HashThrower {
+  static bool throwOnHashCode = true;
+
+  const HashThrower();
+
+  int get hashCode => throwOnHashCode ? throw 'failing' : 2;
+  bool operator ==(other) => identical(this, other);
+}
+
+Future testWithClosure<T>(
+    void Function(SendPort) entrypoint, T expectedResult) async {
+  final rp = ReceivePort();
+  try {
+    await Isolate.spawn(entrypoint, rp.sendPort);
+    Expect.equals(expectedResult, await rp.first);
+  } finally {
+    rp.close();
+  }
+}
+
+class ClosureEntrypointTester {
+  int instanceValue = 42;
+
+  void send42(SendPort sendPort) => sendPort.send(42);
+
+  Future run() async {
+    await noCapturedVariablesTest();
+    await capturedInt();
+    await capturedInstanceInt();
+    await captureThisViaMethodTearOff();
+    await captureInvalidObject();
+    await captureRehashThrower();
+  }
+
+  Future noCapturedVariablesTest() async {
+    print('noCapturedVariablesTest');
+    await testWithClosure((SendPort s) => s.send(42), 42);
+  }
+
+  Future capturedInt() async {
+    print('capturedInt');
+    int value = 42;
+    await testWithClosure((SendPort s) => s.send(value), 42);
+  }
+
+  Future capturedInstanceInt() async {
+    print('capturedInstanceValue');
+    await testWithClosure((SendPort s) => s.send(this.instanceValue), 42);
+  }
+
+  Future captureThisViaMethodTearOff() async {
+    print('captureThisViaMethodTearOff');
+    await testWithClosure(send42, 42);
+  }
+
+  Future captureInvalidObject() async {
+    print('captureInvalidObject');
+    final invalidObject = ClassWithNativeFields();
+    send42(SendPort sendPort) {
+      '$invalidObject'; // Use an object that cannot be copied.
+      sendPort.send(42);
+    }
+
+    throwsAsync<ArgumentError>(() => testWithClosure(send42, 42));
+  }
+
+  Future captureRehashThrower() async {
+    print('captureRehashThrower');
+    HashThrower.throwOnHashCode = false;
+    final hashThrower = {HashThrower()};
+    send42(SendPort sendPort) {
+      '$hashThrower'; // Use an object that cannot be deserialized.
+      sendPort.send(42);
+    }
+
+    throwsAsync<IsolateSpawnException>(() => testWithClosure(send42, 42));
+  }
+
+  Future throwsAsync<T>(Future Function() fun) async {
+    try {
+      await fun();
+    } catch (e) {
+      if (e is T) return;
+      rethrow;
+    }
+    throw 'Function failed to throw ArgumentError';
+  }
+}
+
+main() async {
+  await ClosureEntrypointTester().run();
+}
diff --git a/runtime/tests/vm/dart_2/isolates/closure_entrypoint_test.dart b/runtime/tests/vm/dart_2/isolates/closure_entrypoint_test.dart
new file mode 100644
index 0000000..4fa05c9
--- /dev/null
+++ b/runtime/tests/vm/dart_2/isolates/closure_entrypoint_test.dart
@@ -0,0 +1,113 @@
+// 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.
+
+// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy
+// VMOptions=--enable-isolate-groups --enable-fast-object-copy
+// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation
+// VMOptions=--enable-isolate-groups --enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation
+
+// The tests in this file will only succeed when isolate groups are enabled
+// (hence the VMOptions above).
+
+// @dart = 2.9
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:expect/expect.dart';
+
+import 'fast_object_copy_test.dart' show ClassWithNativeFields;
+
+class HashThrower {
+  static bool throwOnHashCode = true;
+
+  const HashThrower();
+
+  int get hashCode => throwOnHashCode ? throw 'failing' : 2;
+  bool operator ==(other) => identical(this, other);
+}
+
+Future testWithClosure<T>(
+    void Function(SendPort) entrypoint, T expectedResult) async {
+  final rp = ReceivePort();
+  try {
+    await Isolate.spawn(entrypoint, rp.sendPort);
+    Expect.equals(expectedResult, await rp.first);
+  } finally {
+    rp.close();
+  }
+}
+
+class ClosureEntrypointTester {
+  int instanceValue = 42;
+
+  void send42(SendPort sendPort) => sendPort.send(42);
+
+  Future run() async {
+    await noCapturedVariablesTest();
+    await capturedInt();
+    await capturedInstanceInt();
+    await captureThisViaMethodTearOff();
+    await captureInvalidObject();
+    await captureRehashThrower();
+  }
+
+  Future noCapturedVariablesTest() async {
+    print('noCapturedVariablesTest');
+    await testWithClosure((SendPort s) => s.send(42), 42);
+  }
+
+  Future capturedInt() async {
+    print('capturedInt');
+    int value = 42;
+    await testWithClosure((SendPort s) => s.send(value), 42);
+  }
+
+  Future capturedInstanceInt() async {
+    print('capturedInstanceValue');
+    await testWithClosure((SendPort s) => s.send(this.instanceValue), 42);
+  }
+
+  Future captureThisViaMethodTearOff() async {
+    print('captureThisViaMethodTearOff');
+    await testWithClosure(send42, 42);
+  }
+
+  Future captureInvalidObject() async {
+    print('captureInvalidObject');
+    final invalidObject = ClassWithNativeFields();
+    send42(SendPort sendPort) {
+      '$invalidObject'; // Use an object that cannot be copied.
+      sendPort.send(42);
+    }
+
+    throwsAsync<ArgumentError>(() => testWithClosure(send42, 42));
+  }
+
+  Future captureRehashThrower() async {
+    print('captureRehashThrower');
+    HashThrower.throwOnHashCode = false;
+    final hashThrower = {HashThrower()};
+    send42(SendPort sendPort) {
+      '$hashThrower'; // Use an object that cannot be deserialized.
+      sendPort.send(42);
+    }
+
+    throwsAsync<IsolateSpawnException>(() => testWithClosure(send42, 42));
+  }
+
+  Future throwsAsync<T>(Future Function() fun) async {
+    try {
+      await fun();
+    } catch (e) {
+      if (e is T) return;
+      rethrow;
+    }
+    throw 'Function failed to throw ArgumentError';
+  }
+}
+
+main() async {
+  await ClosureEntrypointTester().run();
+}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index aadc7a4..46cf7f1 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2681,12 +2681,6 @@
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&ic_miss_code_));
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&tag_table_));
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&sticky_error_));
-  if (isolate_group_ != nullptr) {
-    if (isolate_group_->source()->loaded_blobs_ != nullptr) {
-      visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(
-          &(isolate_group_->source()->loaded_blobs_)));
-    }
-  }
 #if !defined(PRODUCT)
   visitor->VisitPointer(
       reinterpret_cast<ObjectPtr*>(&pending_service_extension_calls_));
@@ -2889,6 +2883,11 @@
         visitor);
   }
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+
+  if (source()->loaded_blobs_ != nullptr) {
+    visitor->VisitPointer(
+        reinterpret_cast<ObjectPtr*>(&(source()->loaded_blobs_)));
+  }
 }
 
 void IsolateGroup::VisitStackPointers(ObjectPointerVisitor* visitor,
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index 076f612..b2ff598 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -3722,40 +3722,43 @@
   return serializer.Finish(dest_port, priority);
 }
 
+ObjectPtr ReadObjectGraphCopyMessage(Thread* thread, PersistentHandle* handle) {
+  // msg_array = [
+  //     <message>,
+  //     <collection-lib-objects-to-rehash>,
+  //     <core-lib-objects-to-rehash>,
+  // ]
+  Zone* zone = thread->zone();
+  Object& msg_obj = Object::Handle(zone);
+  const auto& msg_array = Array::Handle(zone, Array::RawCast(handle->ptr()));
+  ASSERT(msg_array.Length() == 3);
+  msg_obj = msg_array.At(0);
+  if (msg_array.At(1) != Object::null()) {
+    const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(1));
+    auto& result = Object::Handle(zone);
+    result = DartLibraryCalls::RehashObjectsInDartCollection(thread,
+                                                             objects_to_rehash);
+    if (result.ptr() != Object::null()) {
+      msg_obj = result.ptr();
+    }
+  }
+  if (msg_array.At(2) != Object::null()) {
+    const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(2));
+    auto& result = Object::Handle(zone);
+    result =
+        DartLibraryCalls::RehashObjectsInDartCore(thread, objects_to_rehash);
+    if (result.ptr() != Object::null()) {
+      msg_obj = result.ptr();
+    }
+  }
+  return msg_obj.ptr();
+}
+
 ObjectPtr ReadMessage(Thread* thread, Message* message) {
   if (message->IsRaw()) {
     return message->raw_obj();
   } else if (message->IsPersistentHandle()) {
-    // msg_array = [
-    //     <message>,
-    //     <collection-lib-objects-to-rehash>,
-    //     <core-lib-objects-to-rehash>,
-    // ]
-    Zone* zone = thread->zone();
-    Object& msg_obj = Object::Handle(zone);
-    const auto& msg_array = Array::Handle(
-        zone, Array::RawCast(message->persistent_handle()->ptr()));
-    ASSERT(msg_array.Length() == 3);
-    msg_obj = msg_array.At(0);
-    if (msg_array.At(1) != Object::null()) {
-      const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(1));
-      auto& result = Object::Handle(zone);
-      result = DartLibraryCalls::RehashObjectsInDartCollection(
-          thread, objects_to_rehash);
-      if (result.ptr() != Object::null()) {
-        msg_obj = result.ptr();
-      }
-    }
-    if (msg_array.At(2) != Object::null()) {
-      const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(2));
-      auto& result = Object::Handle(zone);
-      result =
-          DartLibraryCalls::RehashObjectsInDartCore(thread, objects_to_rehash);
-      if (result.ptr() != Object::null()) {
-        msg_obj = result.ptr();
-      }
-    }
-    return msg_obj.ptr();
+    return ReadObjectGraphCopyMessage(thread, message->persistent_handle());
   } else {
     RELEASE_ASSERT(message->IsSnapshot());
     MessageDeserializer deserializer(thread, message);
diff --git a/runtime/vm/message_snapshot.h b/runtime/vm/message_snapshot.h
index be7eb8a..a584748 100644
--- a/runtime/vm/message_snapshot.h
+++ b/runtime/vm/message_snapshot.h
@@ -24,6 +24,8 @@
                                          Dart_Port dest_port,
                                          Message::Priority priority);
 
+ObjectPtr ReadObjectGraphCopyMessage(Thread* thread, PersistentHandle* handle);
+
 ObjectPtr ReadMessage(Thread* thread, Message* message);
 
 Dart_CObject* ReadApiMessage(Zone* zone, Message* message);
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index 52c680f..f5d8bc5 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -1710,7 +1710,12 @@
     thread_->isolate()->set_forward_table_old(nullptr);
   }
 
-  // Result will be [<msg>, <objects-in-msg-to-rehash>]
+  // Result will be
+  //   [
+  //     <message>,
+  //     <collection-lib-objects-to-rehash>,
+  //     <core-lib-objects-to-rehash>,
+  //   ]
   ObjectPtr CopyObjectGraph(const Object& root) {
     const char* volatile exception_msg = nullptr;
     auto& result = Object::Handle(zone_);
diff --git a/runtime/vm/object_graph_copy.h b/runtime/vm/object_graph_copy.h
index b33c3e4..e7efa5a 100644
--- a/runtime/vm/object_graph_copy.h
+++ b/runtime/vm/object_graph_copy.h
@@ -13,9 +13,13 @@
 // Makes a transitive copy of the object graph referenced by [object]. Will not
 // copy objects that can be safely shared - due to being immutable.
 //
-// The result will be an array of length 2 of the format
+// The result will be an array of length 3 of the format
 //
-//   [<copy-of-root>, <array-of-objects-to-rehash / null>]
+//   [
+//     <message>,
+//     <collection-lib-objects-to-rehash>,
+//     <core-lib-objects-to-rehash>,
+//   ]
 //
 // If the array of objects to rehash is not `null` the receiver should re-hash
 // those objects.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
index fdc771d..01921c0 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -178,18 +178,68 @@
         dart.typeName(dart.getReifiedType(this)), this);
   }
 
-  // TODO(jmesserly): remove these once we canonicalize tearoffs.
+  // TODO(nshahan): We can remove these if we canonicalize all tearoffs and no
+  // longer support weak null safety "same type" equality.
   operator ==(other) {
-    if (other == null) return false;
-    var boundObj = JS<Object?>('', '#._boundObject', this);
-    if (boundObj == null) return JS<bool>('!', '# === #', this, other);
-    return JS(
-        'bool',
+    // Basic function values (no generics, no bound instances) are represented
+    // as the original functions so reference equality is sufficient.
+    if (JS<bool>('!', '# === #', this, other)) return true;
+
+    dynamic boundObj;
+    dynamic otherFn;
+    var originalFn = JS('', '#._originalFn', this);
+
+    if (originalFn == null) {
+      // No generic instantiation present.
+      boundObj = JS('', '#._boundObject', this);
+      if (boundObj == null) return false;
+      originalFn = this;
+      otherFn = other;
+    } else {
+      // Generic instantiation was present.
+      var typeArgs = JS('!', '#._typeArgs', this);
+      var otherTypeArgs = JS('', '#._typeArgs', other);
+      // Test if all instantiated type arguments are equal.
+      if (dart.compileTimeFlag('soundNullSafety')) {
+        // The list has been canonicalized on creation so reference equality
+        // is sufficient.
+        if (JS<bool>('!', '# !== #', typeArgs, otherTypeArgs)) return false;
+      } else {
+        // In weak null safety all types arguments must be compared in a way
+        // that is agnostic to legacy.
+        var typeArgCount = JS<int>('!', '#.length', typeArgs);
+        if (JS<bool>('!', '!#', otherTypeArgs) ||
+            typeArgCount != JS('', '#.length', otherTypeArgs)) {
+          return false;
+        }
+        for (var i = 0; i < typeArgCount; i++) {
+          var typeArg = JS('!', '#[#]', typeArgs, i);
+          var otherTypeArg = JS('!', '#[#]', otherTypeArgs, i);
+          // TODO(nshahan) Replace wrapType() with a lighter weight legacy
+          // erasure.
+          if (JS<bool>('!', '# !== #', dart.wrapType(typeArg),
+              dart.wrapType(otherTypeArg))) {
+            return false;
+          }
+        }
+      }
+      boundObj = JS('', '#._boundObject', originalFn);
+      otherFn = JS('', '#._originalFn', other);
+      if (boundObj == null) {
+        // This isn't an instance tearoff, test if the original uninstantiated
+        // methods are equal.
+        return JS<bool>('!', '# === #', originalFn, otherFn);
+      }
+    }
+    // This is an instance tearoff, test if the bound instances and methods
+    // are equal.
+    return JS<bool>(
+        '!',
         '# === #._boundObject && #._boundMethod === #._boundMethod',
         boundObj,
-        other,
-        this,
-        other);
+        otherFn,
+        originalFn,
+        otherFn);
   }
 
   get hashCode {
diff --git a/tools/VERSION b/tools/VERSION
index b52e166..4a2ce87 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 79
+PRERELEASE 80
 PRERELEASE_PATCH 0
\ No newline at end of file