Version 2.18.0-57.0.dev

Merge commit '76387a9c5b3d89035be13a84b5303e2780e94e6e' into 'dev'
diff --git a/OWNERS b/OWNERS
index 911f0bb..b179edd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -17,7 +17,7 @@
 per-file CONTRIBUTING.md,LICENSE,PATENT_GRANT,README.*,SECURITY.md=file:/tools/OWNERS_PRODUCT
 
 # Top level build files
-per-file .clang-format,BUILD.gn,sdk_args.gni=file:/tools/OWNERS_VM
+per-file .clang-format,BUILD.gn,sdk_args.gni=file:/tools/OWNERS_BUILD
 
 # Generated file
 per-file .packages=*
diff --git a/benchmarks/Startup/dart/Startup.dart b/benchmarks/Startup/dart/Startup.dart
index 7beaede..03bd22e 100644
--- a/benchmarks/Startup/dart/Startup.dart
+++ b/benchmarks/Startup/dart/Startup.dart
@@ -76,7 +76,7 @@
       print(ends.toList());
       throw '$name is missing or ambiguous';
     }
-    print('Startup.$name(RunTimeRaw): $micros us.');
+    print('Startup.$name(StartupTime): $micros us.');
   }
 
   report('CreateIsolateGroupAndSetupHelper', null);
diff --git a/benchmarks/Startup/dart2/Startup.dart b/benchmarks/Startup/dart2/Startup.dart
index 3220928..b79e3a3 100644
--- a/benchmarks/Startup/dart2/Startup.dart
+++ b/benchmarks/Startup/dart2/Startup.dart
@@ -78,7 +78,7 @@
       print(ends.toList());
       throw '$name is missing or ambiguous';
     }
-    print('Startup.$name(RunTimeRaw): $micros us.');
+    print('Startup.$name(StartupTime): $micros us.');
   }
 
   report('CreateIsolateGroupAndSetupHelper', null);
diff --git a/build/OWNERS b/build/OWNERS
index 2b67506..24995df 100644
--- a/build/OWNERS
+++ b/build/OWNERS
@@ -1 +1 @@
-file:/tools/OWNERS_ENG
+file:/tools/OWNERS_BUILD
diff --git a/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart b/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
index e7ed68c..36caada 100644
--- a/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
+++ b/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
@@ -36,11 +36,7 @@
     }
 
     final executablePath = io.Platform.resolvedExecutable;
-    final binPath = package_path.dirname(executablePath);
-    final sdkPath = package_path.dirname(binPath);
-
-    final frontEndSnapshotPath = package_path.join(
-        binPath, 'snapshots', 'frontend_server.dart.snapshot');
+    final sdkPaths = _computeSdkPaths();
 
     final socketCompleter = Completer<io.Socket>();
     final serverSocket = await _loopbackServerSocket();
@@ -52,7 +48,7 @@
     final addressStr = '$host:${serverSocket.port}';
 
     final process = await io.Process.start(executablePath, [
-      frontEndSnapshotPath,
+      sdkPaths.frontEndSnapshot,
       '--binary-protocol-address=$addressStr',
     ]);
 
@@ -66,8 +62,7 @@
     final requestChannel = RequestChannel(socket);
 
     // Put the platform dill.
-    final platformDillPath = package_path.join(
-        sdkPath, 'lib', '_internal', 'vm_platform_strong.dill');
+    final platformDillPath = sdkPaths.platformDill;
     final platformDillBytes = io.File(platformDillPath).readAsBytesSync();
     await requestChannel.sendRequest<void>('dill.put', {
       'uri': 'dill:vm',
@@ -149,6 +144,30 @@
     });
   }
 
+  static _SdkPaths _computeSdkPaths() {
+    // Check for google3.
+    final runFiles = io.Platform.environment['RUNFILES'];
+    if (runFiles != null) {
+      final frontServerPath = io.Platform.environment['FRONTEND_SERVER_PATH']!;
+      final platformDillPath = io.Platform.environment['PLATFORM_DILL_PATH']!;
+      return _SdkPaths(
+        frontEndSnapshot: package_path.join(runFiles, frontServerPath),
+        platformDill: package_path.join(runFiles, platformDillPath),
+      );
+    }
+
+    final executablePath = io.Platform.resolvedExecutable;
+    final binPath = package_path.dirname(executablePath);
+    final sdkPath = package_path.dirname(binPath);
+
+    return _SdkPaths(
+      frontEndSnapshot: package_path.join(
+          binPath, 'snapshots', 'frontend_server.dart.snapshot'),
+      platformDill: package_path.join(
+          sdkPath, 'lib', '_internal', 'vm_platform_strong.dill'),
+    );
+  }
+
   static Future<io.ServerSocket> _loopbackServerSocket() async {
     try {
       return await io.ServerSocket.bind(io.InternetAddress.loopbackIPv6, 0);
@@ -199,3 +218,13 @@
     }
   }
 }
+
+class _SdkPaths {
+  final String frontEndSnapshot;
+  final String platformDill;
+
+  _SdkPaths({
+    required this.frontEndSnapshot,
+    required this.platformDill,
+  });
+}
diff --git a/pkg/analyzer_utilities/lib/package_root.dart b/pkg/analyzer_utilities/lib/package_root.dart
index aa3d27c..61a3c96 100644
--- a/pkg/analyzer_utilities/lib/package_root.dart
+++ b/pkg/analyzer_utilities/lib/package_root.dart
@@ -25,5 +25,13 @@
   if (pkgIndex != -1) {
     return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
   }
+  // Try google3 environment. We expect that all packages that will be
+  // accessed via this root are configured in the BUILD file, and located
+  // inside this single root.
+  final runFiles = Platform.environment['RUNFILES'];
+  final analyzerPackagesRoot = Platform.environment['ANALYZER_PACKAGES_ROOT'];
+  if (runFiles != null && analyzerPackagesRoot != null) {
+    return pathos.join(runFiles, analyzerPackagesRoot);
+  }
   throw StateError('Unable to find sdk/pkg/ in $scriptPath');
 }
diff --git a/pkg/compiler/lib/src/ir/impact_data.dart b/pkg/compiler/lib/src/ir/impact_data.dart
index 1d9aefd..462b6c3 100644
--- a/pkg/compiler/lib/src/ir/impact_data.dart
+++ b/pkg/compiler/lib/src/ir/impact_data.dart
@@ -575,6 +575,12 @@
 
   @override
   void handleConstantExpression(ir.ConstantExpression node) {
+    // Evaluate any [ir.UnevaluatedConstant]s to ensure they are processed for
+    // impacts correctly.
+    // TODO(joshualitt): Remove this when we have CFE constants.
+    if (node.constant is ir.UnevaluatedConstant) {
+      _elementMap.constantEvaluator.evaluate(staticTypeContext, node);
+    }
     ir.LibraryDependency import = getDeferredImport(node);
     ConstantImpactVisitor(this, import, node, staticTypeContext)
         .visitConstant(node.constant);
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 6a45f08..cb44cf3 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -67,6 +67,8 @@
     path: ../meta
   dart2js_info:
     path: ../dart2js_info
+  smith:
+    path: ../smith
 
   # Packages brought in via DEPS
   args:
diff --git a/pkg/compiler/test/impact/data/issue230108748.dart b/pkg/compiler/test/impact/data/issue230108748.dart
new file mode 100644
index 0000000..ea16c2f
--- /dev/null
+++ b/pkg/compiler/test/impact/data/issue230108748.dart
@@ -0,0 +1,75 @@
+class B {
+  /*member: B.x:
+   static=[
+    Rti._bind(1),
+    Rti._eval(1),
+    _arrayInstanceType(1),
+    _asBool(1),
+    _asBoolQ(1),
+    _asBoolS(1),
+    _asDouble(1),
+    _asDoubleQ(1),
+    _asDoubleS(1),
+    _asInt(1),
+    _asIntQ(1),
+    _asIntS(1),
+    _asNum(1),
+    _asNumQ(1),
+    _asNumS(1),
+    _asObject(1),
+    _asString(1),
+    _asStringQ(1),
+    _asStringS(1),
+    _asTop(1),
+    _generalAsCheckImplementation(1),
+    _generalIsTestImplementation(1),
+    _generalNullableAsCheckImplementation(1),
+    _generalNullableIsTestImplementation(1),
+    _installSpecializedAsCheck(1),
+    _installSpecializedIsTest(1),
+    _instanceType(1),
+    _isBool(1),
+    _isInt(1),
+    _isNum(1),
+    _isObject(1),
+    _isString(1),
+    _isTop(1),
+    findType(1),
+    instanceType(1)],
+   type=[
+    inst:Closure,
+    inst:JSBool,
+    inst:JSNull,
+    param:int]
+  */
+  final int x;
+  const B(this.x);
+}
+
+/*member: case3:
+ static=[B.x=IntConstant(1)],
+ type=[
+  const:B,
+  inst:JSInt,
+  inst:JSNull,
+  inst:JSNumNotInt,
+  inst:JSNumber,
+  inst:JSPositiveInt,
+  inst:JSUInt31,
+  inst:JSUInt32]
+*/
+int case3() {
+  switch (null as dynamic) {
+    case B(const bool.fromEnvironment('x') ? 0 : 1):
+      return 1;
+    default:
+      return 2;
+  }
+}
+
+/*member: main:static=[
+  case3(0),
+  print(1)]*/
+void main() {
+  print(case3());
+}
diff --git a/pkg/dart2wasm/lib/class_info.dart b/pkg/dart2wasm/lib/class_info.dart
index c94c023..27986fc 100644
--- a/pkg/dart2wasm/lib/class_info.dart
+++ b/pkg/dart2wasm/lib/class_info.dart
@@ -25,6 +25,7 @@
   static const hashBaseData = 4;
   static const closureContext = 2;
   static const closureFunction = 3;
+  static const typeTypeArguments = 3;
   static const typedListBaseLength = 2;
   static const typedListArray = 3;
   static const typedListViewTypedData = 3;
@@ -50,6 +51,7 @@
     check(translator.hashFieldBaseClass, "_index", FieldIndex.hashBaseIndex);
     check(translator.hashFieldBaseClass, "_data", FieldIndex.hashBaseData);
     check(translator.functionClass, "context", FieldIndex.closureContext);
+    check(translator.typeClass, "typeArguments", FieldIndex.typeTypeArguments);
   }
 }
 
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index d12efbd..2489dfb 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -9,6 +9,7 @@
 import 'package:dart2wasm/param_info.dart';
 import 'package:dart2wasm/reference_extensions.dart';
 import 'package:dart2wasm/translator.dart';
+import 'package:dart2wasm/types.dart';
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
@@ -77,6 +78,8 @@
 
   w.ValueType get voidMarker => translator.voidMarker;
 
+  Types get types => translator.types;
+
   w.ValueType translateType(DartType type) => translator.translateType(type);
 
   w.Local addLocal(w.ValueType type) {
@@ -87,7 +90,7 @@
     return exp.getStaticType(typeContext);
   }
 
-  void _unimplemented(
+  void unimplemented(
       TreeNode node, Object message, List<w.ValueType> expectedTypes) {
     final text = "Not implemented: $message at ${node.location}";
     print(text);
@@ -99,18 +102,18 @@
 
   @override
   void defaultInitializer(Initializer node) {
-    _unimplemented(node, node.runtimeType, const []);
+    unimplemented(node, node.runtimeType, const []);
   }
 
   @override
   w.ValueType defaultExpression(Expression node, w.ValueType expectedType) {
-    _unimplemented(node, node.runtimeType, [expectedType]);
+    unimplemented(node, node.runtimeType, [expectedType]);
     return expectedType;
   }
 
   @override
   void defaultStatement(Statement node) {
-    _unimplemented(node, node.runtimeType, const []);
+    unimplemented(node, node.runtimeType, const []);
   }
 
   /// Generate code for the body of the member.
@@ -460,7 +463,8 @@
       b.ref_as_non_null();
     }
     for (TypeParameter typeParam in cls.typeParameters) {
-      _makeType(TypeParameterType(typeParam, Nullability.nonNullable), node);
+      types.makeType(
+          this, TypeParameterType(typeParam, Nullability.nonNullable), node);
     }
     _visitArguments(node.arguments, node.targetReference, 1);
     _call(node.targetReference);
@@ -478,7 +482,7 @@
       b.ref_as_non_null();
     }
     for (DartType typeArg in supertype!.typeArguments) {
-      _makeType(typeArg, node);
+      types.makeType(this, typeArg, node);
     }
     _visitArguments(node.arguments, node.targetReference,
         1 + supertype.typeArguments.length);
@@ -594,8 +598,8 @@
       // Only emit the type test if the guard is not [Object].
       if (guard != translator.coreTypes.objectNonNullableRawType) {
         b.local_get(thrownException);
-        emitTypeTest(
-            guard, translator.coreTypes.objectNonNullableRawType, node);
+        types.emitTypeTest(
+            this, guard, translator.coreTypes.objectNonNullableRawType, node);
         b.i32_eqz();
         b.br_if(catchBlock);
       }
@@ -982,10 +986,10 @@
   @override
   w.ValueType visitThisExpression(
       ThisExpression node, w.ValueType expectedType) {
-    return _visitThis(expectedType);
+    return visitThis(expectedType);
   }
 
-  w.ValueType _visitThis(w.ValueType expectedType) {
+  w.ValueType visitThis(w.ValueType expectedType) {
     w.ValueType thisType = thisLocal!.type.withNullability(false);
     w.ValueType preciseThisType = preciseThisLocal!.type.withNullability(false);
     if (!thisType.isSubtypeOf(expectedType) &&
@@ -1049,7 +1053,7 @@
         _lookupSuperTarget(node.interfaceTarget!, setter: false).reference;
     w.BaseFunction targetFunction = translator.functions.getFunction(target);
     w.ValueType receiverType = targetFunction.type.inputs.first;
-    w.ValueType thisType = _visitThis(receiverType);
+    w.ValueType thisType = visitThis(receiverType);
     translator.convertType(function, thisType, receiverType);
     _visitArguments(node.arguments, target, 1);
     return _call(target);
@@ -1080,7 +1084,7 @@
           b.end();
           return resultType;
         default:
-          _unimplemented(node, "Nullable invocation of ${target.name.text}",
+          unimplemented(node, "Nullable invocation of ${target.name.text}",
               [if (expectedType != voidMarker) expectedType]);
           return expectedType;
       }
@@ -1103,7 +1107,7 @@
   w.ValueType visitDynamicInvocation(
       DynamicInvocation node, w.ValueType expectedType) {
     if (node.name.text != "call") {
-      _unimplemented(node, "Dynamic invocation of ${node.name.text}",
+      unimplemented(node, "Dynamic invocation of ${node.name.text}",
           [if (expectedType != voidMarker) expectedType]);
       return expectedType;
     }
@@ -1460,7 +1464,7 @@
           wrap(ConstantExpression(TypeLiteralConstant(NullType())), resultType);
           break;
         default:
-          _unimplemented(
+          unimplemented(
               node, "Nullable get of ${target.name.text}", [resultType]);
           break;
       }
@@ -1773,7 +1777,7 @@
     final w.FunctionType signature = translator.signatureFor(target);
     final ParameterInfo paramInfo = translator.paramInfoFor(target);
     for (int i = 0; i < node.types.length; i++) {
-      _makeType(node.types[i], node);
+      types.makeType(this, node.types[i], node);
     }
     signatureOffset += node.types.length;
     for (int i = 0; i < node.positional.length; i++) {
@@ -1812,7 +1816,7 @@
   @override
   w.ValueType visitStringConcatenation(
       StringConcatenation node, w.ValueType expectedType) {
-    _makeList(
+    makeList(
         node.expressions,
         translator.fixedLengthListClass,
         InterfaceType(translator.stringBaseClass, Nullability.nonNullable),
@@ -1884,11 +1888,11 @@
 
   @override
   w.ValueType visitListLiteral(ListLiteral node, w.ValueType expectedType) {
-    return _makeList(node.expressions, translator.growableListClass,
+    return makeList(node.expressions, translator.growableListClass,
         node.typeArgument, node);
   }
 
-  w.ValueType _makeList(List<Expression> expressions, Class cls,
+  w.ValueType makeList(List<Expression> expressions, Class cls,
       DartType typeArg, TreeNode node) {
     ClassInfo info = translator.classInfo[cls]!;
     translator.functions.allocateClass(info.classId);
@@ -1899,7 +1903,7 @@
 
     b.i32_const(info.classId);
     b.i32_const(initialIdentityHash);
-    _makeType(typeArg, node);
+    types.makeType(this, typeArg, node);
     b.i64_const(length);
     if (options.lazyConstants) {
       // Avoid array.init instruction in lazy constants mode
@@ -1935,8 +1939,8 @@
     w.BaseFunction mapFactory =
         translator.functions.getFunction(translator.mapFactory.reference);
     w.ValueType factoryReturnType = mapFactory.type.outputs.single;
-    _makeType(node.keyType, node);
-    _makeType(node.valueType, node);
+    types.makeType(this, node.keyType, node);
+    types.makeType(this, node.valueType, node);
     b.call(mapFactory);
     if (node.entries.isEmpty) {
       return factoryReturnType;
@@ -1962,167 +1966,16 @@
 
   @override
   w.ValueType visitTypeLiteral(TypeLiteral node, w.ValueType expectedType) {
-    return _makeType(node.type, node);
-  }
-
-  w.ValueType _makeType(DartType type, TreeNode node) {
-    w.ValueType typeType =
-        translator.classInfo[translator.typeClass]!.nullableType;
-    if (_isTypeConstant(type)) {
-      return wrap(ConstantExpression(TypeLiteralConstant(type)), typeType);
-    }
-    if (type is TypeParameterType) {
-      if (type.parameter.parent is FunctionNode) {
-        // Type argument to function
-        w.Local? local = typeLocals[type.parameter];
-        if (local != null) {
-          b.local_get(local);
-          return local.type;
-        } else {
-          _unimplemented(
-              node, "Type parameter access inside lambda", [typeType]);
-          return typeType;
-        }
-      }
-      // Type argument of class
-      Class cls = type.parameter.parent as Class;
-      ClassInfo info = translator.classInfo[cls]!;
-      int fieldIndex = translator.typeParameterIndex[type.parameter]!;
-      w.ValueType thisType = _visitThis(info.nullableType);
-      translator.convertType(function, thisType, info.nullableType);
-      b.struct_get(info.struct, fieldIndex);
-      return typeType;
-    }
-    ClassInfo info = translator.classInfo[translator.typeClass]!;
-    translator.functions.allocateClass(info.classId);
-    if (type is FutureOrType) {
-      // TODO(askesc): Have an actual representation of FutureOr types
-      b.ref_null(info.nullableType.heapType);
-      return info.nullableType;
-    }
-    if (type is! InterfaceType) {
-      _unimplemented(node, type, [info.nullableType]);
-      return info.nullableType;
-    }
-    ClassInfo typeInfo = translator.classInfo[type.classNode]!;
-    w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
-    b.i32_const(info.classId);
-    b.i32_const(initialIdentityHash);
-    b.i64_const(typeInfo.classId);
-    if (type.typeArguments.isEmpty) {
-      b.global_get(translator.constants.emptyTypeList);
-      translator.convertType(function,
-          translator.constants.emptyTypeList.type.type, typeListExpectedType);
-    } else if (type.typeArguments.every(_isTypeConstant)) {
-      ListConstant typeArgs = ListConstant(
-          InterfaceType(translator.typeClass, Nullability.nonNullable),
-          type.typeArguments.map((t) => TypeLiteralConstant(t)).toList());
-      translator.constants
-          .instantiateConstant(function, b, typeArgs, typeListExpectedType);
-    } else {
-      w.ValueType listType = _makeList(
-          type.typeArguments.map((t) => TypeLiteral(t)).toList(),
-          translator.fixedLengthListClass,
-          InterfaceType(translator.typeClass, Nullability.nonNullable),
-          node);
-      translator.convertType(function, listType, typeListExpectedType);
-    }
-    translator.struct_new(b, info);
-    return info.nullableType;
-  }
-
-  bool _isTypeConstant(DartType type) {
-    return type is DynamicType ||
-        type is VoidType ||
-        type is NeverType ||
-        type is NullType ||
-        type is FunctionType ||
-        type is InterfaceType && type.typeArguments.every(_isTypeConstant);
+    return types.makeType(this, node.type, node);
   }
 
   @override
   w.ValueType visitIsExpression(IsExpression node, w.ValueType expectedType) {
     wrap(node.operand, translator.topInfo.nullableType);
-    emitTypeTest(node.type, dartTypeOf(node.operand), node);
+    types.emitTypeTest(this, node.type, dartTypeOf(node.operand), node);
     return w.NumType.i32;
   }
 
-  /// Test value against a Dart type. Expects the value on the stack as a
-  /// (ref null #Top) and leaves the result on the stack as an i32.
-  void emitTypeTest(DartType type, DartType operandType, TreeNode node) {
-    if (type is! InterfaceType) {
-      // TODO(askesc): Implement type test for remaining types
-      print("Not implemented: Type test with non-interface type $type"
-          " at ${node.location}");
-      b.drop();
-      b.i32_const(1);
-      return;
-    }
-    bool isNullable = operandType.isPotentiallyNullable;
-    w.Label? resultLabel;
-    if (isNullable) {
-      // Store operand in a temporary variable, since Binaryen does not support
-      // block inputs.
-      w.Local operand = addLocal(translator.topInfo.nullableType);
-      b.local_set(operand);
-      resultLabel = b.block(const [], const [w.NumType.i32]);
-      w.Label nullLabel = b.block(const [], const []);
-      b.local_get(operand);
-      b.br_on_null(nullLabel);
-    }
-    if (type.typeArguments.any((t) => t is! DynamicType)) {
-      // If the tested-against type as an instance of the static operand type
-      // has the same type arguments as the static operand type, it is not
-      // necessary to test the type arguments.
-      Class cls = translator.classForType(operandType);
-      InterfaceType? base = translator.hierarchy
-          .getTypeAsInstanceOf(type, cls, member.enclosingLibrary)
-          ?.withDeclaredNullability(operandType.declaredNullability);
-      if (base != operandType) {
-        print("Not implemented: Type test with type arguments"
-            " at ${node.location}");
-      }
-    }
-    List<Class> concrete = translator.subtypes
-        .getSubtypesOf(type.classNode)
-        .where((c) => !c.isAbstract)
-        .toList();
-    if (type.classNode == translator.coreTypes.functionClass) {
-      ClassInfo functionInfo = translator.classInfo[translator.functionClass]!;
-      translator.ref_test(b, functionInfo);
-    } else if (concrete.isEmpty) {
-      b.drop();
-      b.i32_const(0);
-    } else if (concrete.length == 1) {
-      ClassInfo info = translator.classInfo[concrete.single]!;
-      b.struct_get(translator.topInfo.struct, FieldIndex.classId);
-      b.i32_const(info.classId);
-      b.i32_eq();
-    } else {
-      w.Local idLocal = addLocal(w.NumType.i32);
-      b.struct_get(translator.topInfo.struct, FieldIndex.classId);
-      b.local_set(idLocal);
-      w.Label done = b.block(const [], const [w.NumType.i32]);
-      b.i32_const(1);
-      for (Class cls in concrete) {
-        ClassInfo info = translator.classInfo[cls]!;
-        b.i32_const(info.classId);
-        b.local_get(idLocal);
-        b.i32_eq();
-        b.br_if(done);
-      }
-      b.drop();
-      b.i32_const(0);
-      b.end(); // done
-    }
-    if (isNullable) {
-      b.br(resultLabel!);
-      b.end(); // nullLabel
-      b.i32_const(type.declaredNullability == Nullability.nullable ? 1 : 0);
-      b.end(); // resultLabel
-    }
-  }
-
   @override
   w.ValueType visitAsExpression(AsExpression node, w.ValueType expectedType) {
     w.Label asCheckBlock = b.block();
@@ -2132,10 +1985,10 @@
 
     // We lower an `as` expression to a type test, throwing a [TypeError] if
     // the type test fails.
-    emitTypeTest(node.type, dartTypeOf(node.operand), node);
+    types.emitTypeTest(this, node.type, dartTypeOf(node.operand), node);
     b.br_if(asCheckBlock);
     b.local_get(operand);
-    _makeType(node.type, node);
+    types.makeType(this, node.type, node);
     _call(translator.stackTraceCurrent.reference);
     _call(translator.throwAsCheckError.reference);
     b.unreachable();
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 2744ea7..7a1a84a 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -670,7 +670,8 @@
     translator.functions.allocateClass(info.classId);
     return createConstant(constant, info.nonNullableType, (function, b) {
       ClassInfo typeInfo = translator.classInfo[type.classNode]!;
-      w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
+      w.ValueType typeListExpectedType =
+          info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
 
       b.i32_const(info.classId);
       b.i32_const(initialIdentityHash);
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index 7fb0cf5..bb31c61 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -976,7 +976,8 @@
       w.Local receiver = paramLocals[0];
       ClassInfo info = translator.classInfo[translator.typeClass]!;
       translator.functions.allocateClass(info.classId);
-      w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
+      w.ValueType typeListExpectedType =
+          info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
 
       b.i32_const(info.classId);
       b.i32_const(initialIdentityHash);
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index ecb5a41..d6711a2 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -13,6 +13,7 @@
 import 'package:dart2wasm/globals.dart';
 import 'package:dart2wasm/param_info.dart';
 import 'package:dart2wasm/reference_extensions.dart';
+import 'package:dart2wasm/types.dart';
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart'
@@ -113,6 +114,7 @@
   late final DispatchTable dispatchTable;
   late final Globals globals;
   late final Constants constants;
+  late final Types types;
   late final FunctionCollector functions;
 
   // Information about the program used and updated by the various phases.
@@ -259,6 +261,7 @@
 
     globals = Globals(this);
     constants = Constants(this);
+    types = Types(this);
 
     dispatchTable.build();
 
diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart
new file mode 100644
index 0000000..f9ee6a4
--- /dev/null
+++ b/pkg/dart2wasm/lib/types.dart
@@ -0,0 +1,179 @@
+// Copyright (c) 2022, 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 'package:dart2wasm/class_info.dart';
+import 'package:dart2wasm/code_generator.dart';
+import 'package:dart2wasm/translator.dart';
+
+import 'package:kernel/ast.dart';
+
+import 'package:wasm_builder/wasm_builder.dart' as w;
+
+/// Helper class for building runtime types.
+class Types {
+  final Translator translator;
+
+  Types(this.translator);
+
+  List<Class> _getConcreteSubtypes(Class cls) => translator.subtypes
+      .getSubtypesOf(cls)
+      .where((c) => !c.isAbstract)
+      .toList();
+
+  bool _isTypeConstant(DartType type) {
+    return type is DynamicType ||
+        type is VoidType ||
+        type is NeverType ||
+        type is NullType ||
+        type is FunctionType ||
+        type is InterfaceType && type.typeArguments.every(_isTypeConstant);
+  }
+
+  /// Makes a `_Type` object on the stack.
+  w.ValueType makeType(CodeGenerator codeGen, DartType type, TreeNode node) {
+    w.ValueType typeType =
+        translator.classInfo[translator.typeClass]!.nullableType;
+    w.Instructions b = codeGen.b;
+    if (_isTypeConstant(type)) {
+      translator.constants.instantiateConstant(
+          codeGen.function, b, TypeLiteralConstant(type), typeType);
+      return typeType;
+    }
+    if (type is TypeParameterType) {
+      if (type.parameter.parent is FunctionNode) {
+        // Type argument to function
+        w.Local? local = codeGen.typeLocals[type.parameter];
+        if (local != null) {
+          b.local_get(local);
+          return local.type;
+        } else {
+          codeGen.unimplemented(
+              node, "Type parameter access inside lambda", [typeType]);
+          return typeType;
+        }
+      }
+      // Type argument of class
+      Class cls = type.parameter.parent as Class;
+      ClassInfo info = translator.classInfo[cls]!;
+      int fieldIndex = translator.typeParameterIndex[type.parameter]!;
+      w.ValueType thisType = codeGen.visitThis(info.nullableType);
+      translator.convertType(codeGen.function, thisType, info.nullableType);
+      b.struct_get(info.struct, fieldIndex);
+      return typeType;
+    }
+    ClassInfo info = translator.classInfo[translator.typeClass]!;
+    translator.functions.allocateClass(info.classId);
+    if (type is FutureOrType) {
+      // TODO(askesc): Have an actual representation of FutureOr types
+      b.ref_null(info.nullableType.heapType);
+      return info.nullableType;
+    }
+    if (type is! InterfaceType) {
+      codeGen.unimplemented(node, type, [info.nullableType]);
+      return info.nullableType;
+    }
+    ClassInfo typeInfo = translator.classInfo[type.classNode]!;
+    w.ValueType typeListExpectedType =
+        info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
+    b.i32_const(info.classId);
+    b.i32_const(initialIdentityHash);
+    b.i64_const(typeInfo.classId);
+    w.DefinedFunction function = codeGen.function;
+    if (type.typeArguments.isEmpty) {
+      b.global_get(translator.constants.emptyTypeList);
+      translator.convertType(function,
+          translator.constants.emptyTypeList.type.type, typeListExpectedType);
+    } else if (type.typeArguments.every(_isTypeConstant)) {
+      ListConstant typeArgs = ListConstant(
+          InterfaceType(translator.typeClass, Nullability.nonNullable),
+          type.typeArguments.map((t) => TypeLiteralConstant(t)).toList());
+      translator.constants
+          .instantiateConstant(function, b, typeArgs, typeListExpectedType);
+    } else {
+      w.ValueType listType = codeGen.makeList(
+          type.typeArguments.map((t) => TypeLiteral(t)).toList(),
+          translator.fixedLengthListClass,
+          InterfaceType(translator.typeClass, Nullability.nonNullable),
+          node);
+      translator.convertType(function, listType, typeListExpectedType);
+    }
+    translator.struct_new(b, info);
+    return info.nullableType;
+  }
+
+  /// Test value against a Dart type. Expects the value on the stack as a
+  /// (ref null #Top) and leaves the result on the stack as an i32.
+  void emitTypeTest(CodeGenerator codeGen, DartType type, DartType operandType,
+      TreeNode node) {
+    w.Instructions b = codeGen.b;
+    if (type is! InterfaceType) {
+      // TODO(askesc): Implement type test for remaining types
+      print("Not implemented: Type test with non-interface type $type"
+          " at ${node.location}");
+      b.drop();
+      b.i32_const(1);
+      return;
+    }
+    bool isNullable = operandType.isPotentiallyNullable;
+    w.Label? resultLabel;
+    if (isNullable) {
+      // Store operand in a temporary variable, since Binaryen does not support
+      // block inputs.
+      w.Local operand = codeGen.addLocal(translator.topInfo.nullableType);
+      b.local_set(operand);
+      resultLabel = b.block(const [], const [w.NumType.i32]);
+      w.Label nullLabel = b.block(const [], const []);
+      b.local_get(operand);
+      b.br_on_null(nullLabel);
+    }
+    if (type.typeArguments.any((t) => t is! DynamicType)) {
+      // If the tested-against type as an instance of the static operand type
+      // has the same type arguments as the static operand type, it is not
+      // necessary to test the type arguments.
+      Class cls = translator.classForType(operandType);
+      InterfaceType? base = translator.hierarchy
+          .getTypeAsInstanceOf(type, cls, codeGen.member.enclosingLibrary)
+          ?.withDeclaredNullability(operandType.declaredNullability);
+      if (base != operandType) {
+        print("Not implemented: Type test with type arguments"
+            " at ${node.location}");
+      }
+    }
+    List<Class> concrete = _getConcreteSubtypes(type.classNode);
+    if (type.classNode == translator.coreTypes.functionClass) {
+      ClassInfo functionInfo = translator.classInfo[translator.functionClass]!;
+      translator.ref_test(b, functionInfo);
+    } else if (concrete.isEmpty) {
+      b.drop();
+      b.i32_const(0);
+    } else if (concrete.length == 1) {
+      ClassInfo info = translator.classInfo[concrete.single]!;
+      b.struct_get(translator.topInfo.struct, FieldIndex.classId);
+      b.i32_const(info.classId);
+      b.i32_eq();
+    } else {
+      w.Local idLocal = codeGen.addLocal(w.NumType.i32);
+      b.struct_get(translator.topInfo.struct, FieldIndex.classId);
+      b.local_set(idLocal);
+      w.Label done = b.block(const [], const [w.NumType.i32]);
+      b.i32_const(1);
+      for (Class cls in concrete) {
+        ClassInfo info = translator.classInfo[cls]!;
+        b.i32_const(info.classId);
+        b.local_get(idLocal);
+        b.i32_eq();
+        b.br_if(done);
+      }
+      b.drop();
+      b.i32_const(0);
+      b.end(); // done
+    }
+    if (isNullable) {
+      b.br(resultLabel!);
+      b.end(); // nullLabel
+      b.i32_const(type.declaredNullability == Nullability.nullable ? 1 : 0);
+      b.end(); // resultLabel
+    }
+  }
+}
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 9b497f6..3645c43 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -349,9 +349,9 @@
             abbr: 'p',
             valueHelp: 'path',
             help:
-                '''Get package locations from the specified file instead of .packages.
+                '''Get package locations from the specified file instead of .dart_tool/package_config.json.
 <path> can be relative or absolute.
-For example: dart compile $name --packages=/tmp/pkgs main.dart'''),
+For example: dart compile $name --packages=/tmp/pkgs.json main.dart'''),
         super(name, description, verbose, hidden: hidden);
 }
 
diff --git a/pkg/dds/lib/src/devtools/handler.dart b/pkg/dds/lib/src/devtools/handler.dart
index d323f9d..817ff17 100644
--- a/pkg/dds/lib/src/devtools/handler.dart
+++ b/pkg/dds/lib/src/devtools/handler.dart
@@ -3,8 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
 
 import 'package:devtools_shared/devtools_server.dart';
+import 'package:path/path.dart' as path;
 import 'package:shelf/shelf.dart';
 import 'package:shelf_static/shelf_static.dart';
 import 'package:sse/server/sse_handler.dart';
@@ -29,21 +32,51 @@
   ClientManager? clientManager,
   Handler? notFoundHandler,
 }) {
-  // Serves the web assets for DevTools.
-  final devtoolsAssetHandler = createStaticHandler(
+  // When served through DDS, the app root is /devtools/.
+  // This variable is used in base href and must start and end with `/`.
+  var appRoot = dds != null ? '/devtools/' : '/';
+  if (dds?.authCodesEnabled ?? false) {
+    appRoot = '/${dds!.authCode}$appRoot';
+  }
+
+  const defaultDocument = 'index.html';
+  final indexFile = File(path.join(buildDir, defaultDocument));
+
+  // Serves the static web assets for DevTools.
+  final devtoolsStaticAssetHandler = createStaticHandler(
     buildDir,
-    defaultDocument: 'index.html',
+    defaultDocument: defaultDocument,
   );
 
+  /// A wrapper around [devtoolsStaticAssetHandler] that handles serving
+  /// index.html up for / and non-file requests like /memory, /inspector, etc.
+  /// with the correct base href for the DevTools root.
+  final devtoolsAssetHandler = (Request request) {
+    // To avoid hard-coding a set of page names here (or needing access to one
+    // from DevTools, assume any single-segment path with no extension is a
+    // DevTools page that needs to serve up index.html).
+    final pathSegments = request.url.pathSegments;
+    final isValidRootPage = pathSegments.isEmpty ||
+        (pathSegments.length == 1 && !pathSegments[0].contains('.'));
+    if (isValidRootPage) {
+      return _serveStaticFile(
+        request,
+        indexFile,
+        'text/html',
+        baseHref: appRoot,
+      );
+    }
+
+    return devtoolsStaticAssetHandler(request);
+  };
+
   // Support DevTools client-server interface via SSE.
   // Note: the handler path needs to match the full *original* path, not the
   // current request URL (we remove '/devtools' in the initial router but we
   // need to include it here).
-  final devToolsSseHandlerPath = dds != null ? '/devtools/api/sse' : '/api/sse';
+  final devToolsSseHandlerPath = '${appRoot}api/sse';
   final devToolsApiHandler = SseHandler(
-    (dds?.authCodesEnabled ?? false)
-        ? Uri.parse('/${dds!.authCode}$devToolsSseHandlerPath')
-        : Uri.parse(devToolsSseHandlerPath),
+    Uri.parse(devToolsSseHandlerPath),
     keepAlive: sseKeepAlive,
   );
 
@@ -78,7 +111,7 @@
     return ServerApi.handle(request);
   };
 
-  return (request) {
+  return (Request request) {
     if (notFoundHandler != null) {
       final pathSegments = request.url.pathSegments;
       if (pathSegments.isEmpty || pathSegments.first != 'devtools') {
@@ -90,3 +123,30 @@
     return devtoolsHandler(request);
   };
 }
+
+/// Serves [file] for all requests.
+///
+/// If [baseHref] is provided, any existing `<base href="">` tag will be
+/// rewritten with this path.
+Future<Response> _serveStaticFile(
+  Request request,
+  File file,
+  String contentType, {
+  String? baseHref,
+}) async {
+  final headers = {HttpHeaders.contentTypeHeader: contentType};
+  var contents = file.readAsStringSync();
+
+  if (baseHref != null) {
+    assert(baseHref.startsWith('/'));
+    assert(baseHref.endsWith('/'));
+    // Replace the base href to match where the app is being served from.
+    final baseHrefPattern = RegExp(r'<base href="\/"\s?\/?>');
+    contents = contents.replaceFirst(
+      baseHrefPattern,
+      '<base href="${htmlEscape.convert(baseHref)}">',
+    );
+  }
+
+  return Response.ok(contents, headers: headers);
+}
diff --git a/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart b/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart
new file mode 100644
index 0000000..78baa0c
--- /dev/null
+++ b/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart
@@ -0,0 +1,77 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+import 'utils/server_driver.dart';
+
+late final DevToolsServerTestController testController;
+
+void main() {
+  const testScriptContents =
+      'Future<void> main() => Future.delayed(const Duration(minutes: 10));';
+  final tempDir = Directory.systemTemp.createTempSync('devtools_server.');
+  final devToolsBannerRegex =
+      RegExp(r'DevTools[\w\s]+at: (https?:.*\/devtools\/)');
+
+  test('serves index.html contents for /token/devtools/inspector', () async {
+    final testFile = File(path.join(tempDir.path, 'foo.dart'));
+    testFile.writeAsStringSync(testScriptContents);
+
+    final proc = await Process.start(
+        Platform.resolvedExecutable, ['--observe=0', testFile.path]);
+    try {
+      final completer = Completer<String>();
+      proc.stderr
+          .transform(utf8.decoder)
+          .transform(LineSplitter())
+          .listen(print);
+      proc.stdout.transform(utf8.decoder).transform(LineSplitter()).listen(
+        (String line) {
+          print(line);
+          final match = devToolsBannerRegex.firstMatch(line);
+          if (match != null) {
+            completer.complete(match.group(1));
+          }
+        },
+        onDone: () {
+          if (!completer.isCompleted) {
+            completer.completeError(
+                'Process ended without emitting DevTools banner');
+          }
+        },
+        onError: (e) {
+          if (!completer.isCompleted) {
+            completer.completeError(e);
+          }
+        },
+      );
+
+      final devToolsUrl = Uri.parse(await completer.future);
+      final httpClient = HttpClient();
+      late HttpClientResponse resp;
+      try {
+        final req = await httpClient.get(
+            devToolsUrl.host, devToolsUrl.port, '${devToolsUrl.path}inspector');
+        resp = await req.close();
+        expect(resp.statusCode, 200);
+        final bodyContent = await resp.transform(utf8.decoder).join();
+        expect(bodyContent, contains('Dart DevTools'));
+        final expectedBaseHref = htmlEscape.convert(devToolsUrl.path);
+        expect(bodyContent, contains('<base href="$expectedBaseHref">'));
+      } finally {
+        httpClient.close();
+      }
+    } finally {
+      proc.kill();
+    }
+    // TODO(dantup): Unskip this test once DevTools has rolled into
+    //   the SDK so that contains the (newly-added) base href tag.
+  }, timeout: const Timeout.factor(10), skip: true);
+}
diff --git a/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart b/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart
new file mode 100644
index 0000000..9185c15
--- /dev/null
+++ b/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart
@@ -0,0 +1,72 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:test/test.dart';
+
+import 'utils/server_driver.dart';
+
+late final DevToolsServerTestController testController;
+
+void main() {
+  testController = DevToolsServerTestController();
+
+  setUp(() async {
+    await testController.setUp();
+  });
+
+  tearDown(() async {
+    await testController.tearDown();
+  });
+
+  test('serves index.html contents for /inspector', () async {
+    final server = await DevToolsServerDriver.create();
+    final httpClient = HttpClient();
+    late HttpClientResponse resp;
+    try {
+      final startedEvent = (await server.stdout.firstWhere(
+        (map) => map!['event'] == 'server.started',
+      ))!;
+      final host = startedEvent['params']['host'];
+      final port = startedEvent['params']['port'];
+
+      final req = await httpClient.get(host, port, '/inspector');
+      resp = await req.close();
+      expect(resp.statusCode, 200);
+      final bodyContent = await resp.transform(utf8.decoder).join();
+      expect(bodyContent, contains('Dart DevTools'));
+      final expectedBaseHref = htmlEscape.convert('/');
+      expect(bodyContent, contains('<base href="$expectedBaseHref">'));
+    } finally {
+      httpClient.close();
+      server.kill();
+    }
+    // TODO(dantup): Unskip this test once DevTools has rolled into
+    //   the SDK so that contains the (newly-added) base href tag.
+  }, timeout: const Timeout.factor(10), skip: true);
+
+  test('serves 404 contents for requests that are not pages', () async {
+    final server = await DevToolsServerDriver.create();
+    final httpClient = HttpClient();
+    late HttpClientResponse resp;
+    try {
+      final startedEvent = (await server.stdout.firstWhere(
+        (map) => map!['event'] == 'server.started',
+      ))!;
+      final host = startedEvent['params']['host'];
+      final port = startedEvent['params']['port'];
+
+      // The index page is only served up for extension-less requests.
+      final req = await httpClient.get(host, port, '/inspector.html');
+      resp = await req.close();
+      expect(resp.statusCode, 404);
+    } finally {
+      httpClient.close();
+      await resp.drain();
+      server.kill();
+    }
+  }, timeout: const Timeout.factor(10));
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index 1edef57..77159ce 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -159,22 +159,41 @@
       reference);
 }
 
-/// Creates the parameters and body for [tearOff] based on [constructor] in
-/// [enclosingClass].
-void buildConstructorTearOffProcedure(Procedure tearOff, Member constructor,
-    Class enclosingClass, SourceLibraryBuilder libraryBuilder) {
+/// Creates the parameters and body for [tearOff] based on
+/// [declarationConstructor] in [enclosingClass].
+///
+/// The [declarationConstructor] is the origin constructor and
+/// [implementationConstructor] is the patch constructor, if patched, otherwise
+/// it is the [declarationConstructor].
+void buildConstructorTearOffProcedure(
+    {required Procedure tearOff,
+    required Member declarationConstructor,
+    required Member implementationConstructor,
+    required Class enclosingClass,
+    required SourceLibraryBuilder libraryBuilder}) {
   assert(
-      constructor is Constructor ||
-          (constructor is Procedure && constructor.isFactory) ||
-          (constructor is Procedure && constructor.isStatic),
-      "Unexpected constructor tear off target $constructor "
-      "(${constructor.runtimeType}).");
+      declarationConstructor is Constructor ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isFactory) ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isStatic),
+      "Unexpected constructor tear off target $declarationConstructor "
+      "(${declarationConstructor.runtimeType}).");
+  assert(
+      declarationConstructor is Constructor ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isFactory) ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isStatic),
+      "Unexpected constructor tear off target $declarationConstructor "
+      "(${declarationConstructor.runtimeType}).");
+
+  FunctionNode function = implementationConstructor.function!;
 
   int fileOffset = tearOff.fileOffset;
 
-  FunctionNode function = constructor.function!;
   List<TypeParameter> classTypeParameters;
-  if (constructor is Constructor) {
+  if (declarationConstructor is Constructor) {
     // Generative constructors implicitly have the type parameters of the
     // enclosing class.
     classTypeParameters = enclosingClass.typeParameters;
@@ -189,37 +208,54 @@
 
   List<DartType> typeArguments = freshTypeParameters.freshTypeArguments;
   Substitution substitution = freshTypeParameters.substitution;
-  _createParameters(tearOff, constructor, substitution, libraryBuilder);
+  _createParameters(tearOff, implementationConstructor, function, substitution,
+      libraryBuilder);
   Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
-  _createTearOffBody(tearOff, constructor, arguments);
+  _createTearOffBody(tearOff, declarationConstructor, arguments);
   tearOff.function.fileOffset = tearOff.fileOffset;
   tearOff.function.fileEndOffset = tearOff.fileOffset;
   updatePrivateMemberName(tearOff, libraryBuilder);
 }
 
 /// Creates the parameters and body for [tearOff] for a typedef tearoff of
-/// [constructor] in [enclosingClass] with [typeParameters] as the typedef
-/// parameters and [typeArguments] as the arguments passed to the
+/// [declarationConstructor] in [enclosingClass] with [typeParameters] as the
+/// typedef parameters and [typeArguments] as the arguments passed to the
 /// [enclosingClass].
+///
+/// The [declarationConstructor] is the origin constructor and
+/// [implementationConstructor] is the patch constructor, if patched, otherwise
+/// it is the [declarationConstructor].
 void buildTypedefTearOffProcedure(
-    Procedure tearOff,
-    Member constructor,
-    Class enclosingClass,
-    List<TypeParameter> typeParameters,
-    List<DartType> typeArguments,
-    SourceLibraryBuilder libraryBuilder) {
+    {required Procedure tearOff,
+    required Member declarationConstructor,
+    required Member implementationConstructor,
+    required Class enclosingClass,
+    required List<TypeParameter> typeParameters,
+    required List<DartType> typeArguments,
+    required SourceLibraryBuilder libraryBuilder}) {
   assert(
-      constructor is Constructor ||
-          (constructor is Procedure && constructor.isFactory) ||
-          (constructor is Procedure && constructor.isStatic),
-      "Unexpected constructor tear off target $constructor "
-      "(${constructor.runtimeType}).");
+      declarationConstructor is Constructor ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isFactory) ||
+          (declarationConstructor is Procedure &&
+              declarationConstructor.isStatic),
+      "Unexpected constructor tear off target $declarationConstructor "
+      "(${declarationConstructor.runtimeType}).");
+  assert(
+      implementationConstructor is Constructor ||
+          (implementationConstructor is Procedure &&
+              implementationConstructor.isFactory) ||
+          (implementationConstructor is Procedure &&
+              implementationConstructor.isStatic),
+      "Unexpected constructor tear off target $implementationConstructor "
+      "(${declarationConstructor.runtimeType}).");
+
+  FunctionNode function = implementationConstructor.function!;
 
   int fileOffset = tearOff.fileOffset;
 
-  FunctionNode function = constructor.function!;
   List<TypeParameter> classTypeParameters;
-  if (constructor is Constructor) {
+  if (declarationConstructor is Constructor) {
     // Generative constructors implicitly have the type parameters of the
     // enclosing class.
     classTypeParameters = enclosingClass.typeParameters;
@@ -242,37 +278,43 @@
   }
   _createParameters(
       tearOff,
-      constructor,
+      implementationConstructor,
+      function,
       Substitution.fromPairs(classTypeParameters, typeArguments),
       libraryBuilder);
   Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
-  _createTearOffBody(tearOff, constructor, arguments);
+  _createTearOffBody(tearOff, declarationConstructor, arguments);
   tearOff.function.fileOffset = tearOff.fileOffset;
   tearOff.function.fileEndOffset = tearOff.fileOffset;
   updatePrivateMemberName(tearOff, libraryBuilder);
 }
 
 /// Creates the parameters for the redirecting factory [tearOff] based on the
-/// [redirectingConstructor] declaration.
+/// [declarationConstructor] declaration.
+///
+/// The [declarationConstructor] is the [Procedure] for the origin constructor
+/// and [implementationConstructorFunctionNode] is the [FunctionNode] for the
+/// implementation constructor. If the constructor is patched, these are not
+/// connected until [Builder.finishPatch].
 FreshTypeParameters buildRedirectingFactoryTearOffProcedureParameters(
-    Procedure tearOff,
-    Procedure redirectingConstructor,
-    SourceLibraryBuilder libraryBuilder) {
-  assert(redirectingConstructor.isRedirectingFactory);
-  FunctionNode function = redirectingConstructor.function;
+    {required Procedure tearOff,
+    required Procedure implementationConstructor,
+    required SourceLibraryBuilder libraryBuilder}) {
+  assert(implementationConstructor.isRedirectingFactory);
+  FunctionNode function = implementationConstructor.function;
   FreshTypeParameters freshTypeParameters =
       _createFreshTypeParameters(function.typeParameters, tearOff.function);
   Substitution substitution = freshTypeParameters.substitution;
-  _createParameters(
-      tearOff, redirectingConstructor, substitution, libraryBuilder);
+  _createParameters(tearOff, implementationConstructor, function, substitution,
+      libraryBuilder);
   tearOff.function.fileOffset = tearOff.fileOffset;
   tearOff.function.fileEndOffset = tearOff.fileOffset;
   updatePrivateMemberName(tearOff, libraryBuilder);
   return freshTypeParameters;
 }
 
-/// Creates the body for the redirecting factory [tearOff] with the target
-/// [constructor] and [typeArguments].
+/// Creates the body for the redirecting factory [tearOff] with the [target]
+/// constructor and [typeArguments].
 ///
 /// Returns the [DelayedDefaultValueCloner] object need to perform default value
 /// computation.
@@ -355,9 +397,12 @@
 /// Creates the parameters for the [tearOff] lowering based of the parameters
 /// in [constructor] and using the [substitution] to compute the parameter and
 /// return types.
-void _createParameters(Procedure tearOff, Member constructor,
-    Substitution substitution, SourceLibraryBuilder libraryBuilder) {
-  FunctionNode function = constructor.function!;
+void _createParameters(
+    Procedure tearOff,
+    Member constructor,
+    FunctionNode function,
+    Substitution substitution,
+    SourceLibraryBuilder libraryBuilder) {
   for (VariableDeclaration constructorParameter
       in function.positionalParameters) {
     VariableDeclaration tearOffParameter = new VariableDeclaration(
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
index 75a94cf..ffbbab7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
@@ -300,3 +300,39 @@
     _hasBeenInferred = true;
   }
 }
+
+/// Copies properties, function parameters and body from the [patch] constructor
+/// to its [origin].
+void finishConstructorPatch(Constructor origin, Constructor patch) {
+  // TODO(ahe): restore file-offset once we track both origin and patch file
+  // URIs. See https://github.com/dart-lang/sdk/issues/31579
+  origin.fileUri = patch.fileUri;
+  origin.startFileOffset = patch.startFileOffset;
+  origin.fileOffset = patch.fileOffset;
+  origin.fileEndOffset = patch.fileEndOffset;
+  origin.annotations.forEach((m) => m.fileOffset = patch.fileOffset);
+
+  origin.isExternal = patch.isExternal;
+  origin.function = patch.function;
+  origin.function.parent = origin;
+  origin.initializers = patch.initializers;
+  setParents(origin.initializers, origin);
+}
+
+/// Copies properties, function parameters and body from the [patch] procedure
+/// to its [origin].
+void finishProcedurePatch(Procedure origin, Procedure patch) {
+  // TODO(ahe): restore file-offset once we track both origin and patch file
+  // URIs. See https://github.com/dart-lang/sdk/issues/31579
+  origin.fileUri = patch.fileUri;
+  origin.startFileOffset = patch.startFileOffset;
+  origin.fileOffset = patch.fileOffset;
+  origin.fileEndOffset = patch.fileEndOffset;
+  origin.annotations.forEach((m) => m.fileOffset = patch.fileOffset);
+
+  origin.isAbstract = patch.isAbstract;
+  origin.isExternal = patch.isExternal;
+  origin.function = patch.function;
+  origin.function.parent = origin;
+  origin.isRedirectingFactory = patch.isRedirectingFactory;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 5794d25..c80faa19 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1092,8 +1092,12 @@
         forAbstractClassOrEnum: classBuilder.isAbstract);
 
     if (constructorTearOff != null) {
-      buildConstructorTearOffProcedure(constructorTearOff, constructor,
-          classBuilder.cls, classBuilder.libraryBuilder);
+      buildConstructorTearOffProcedure(
+          tearOff: constructorTearOff,
+          declarationConstructor: constructor,
+          implementationConstructor: constructor,
+          enclosingClass: classBuilder.cls,
+          libraryBuilder: classBuilder.libraryBuilder);
     }
     SyntheticSourceConstructorBuilder constructorBuilder =
         new SyntheticSourceConstructorBuilder(
@@ -1170,8 +1174,12 @@
         forAbstractClassOrEnum:
             enclosingClass.isAbstract || enclosingClass.isEnum);
     if (constructorTearOff != null) {
-      buildConstructorTearOffProcedure(constructorTearOff, constructor,
-          classBuilder.cls, classBuilder.libraryBuilder);
+      buildConstructorTearOffProcedure(
+          tearOff: constructorTearOff,
+          declarationConstructor: constructor,
+          implementationConstructor: constructor,
+          enclosingClass: classBuilder.cls,
+          libraryBuilder: classBuilder.libraryBuilder);
     }
     return new SyntheticSourceConstructorBuilder(
         classBuilder, constructor, constructorTearOff);
diff --git a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
index 3aa7702..c0dadf6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
@@ -27,7 +27,11 @@
 import '../kernel/expression_generator_helper.dart';
 import '../kernel/hierarchy/class_member.dart' show ClassMember;
 import '../kernel/kernel_helper.dart'
-    show DelayedDefaultValueCloner, TypeDependency;
+    show
+        DelayedDefaultValueCloner,
+        TypeDependency,
+        finishConstructorPatch,
+        finishProcedurePatch;
 import '../kernel/utils.dart'
     show isRedirectingGenerativeConstructorImplementation;
 import '../messages.dart'
@@ -202,8 +206,12 @@
       updatePrivateMemberName(_constructor, libraryBuilder);
 
       if (_constructorTearOff != null) {
-        buildConstructorTearOffProcedure(_constructorTearOff!, _constructor,
-            classBuilder.cls, libraryBuilder);
+        buildConstructorTearOffProcedure(
+            tearOff: _constructorTearOff!,
+            declarationConstructor: constructor,
+            implementationConstructor: _constructor,
+            enclosingClass: classBuilder.cls,
+            libraryBuilder: libraryBuilder);
       }
 
       _hasBeenBuilt = true;
@@ -660,20 +668,11 @@
   }
 
   void _finishPatch() {
-    // TODO(ahe): restore file-offset once we track both origin and patch file
-    // URIs. See https://github.com/dart-lang/sdk/issues/31579
-    origin.constructor.fileUri = fileUri;
-    origin.constructor.startFileOffset = _constructor.startFileOffset;
-    origin.constructor.fileOffset = _constructor.fileOffset;
-    origin.constructor.fileEndOffset = _constructor.fileEndOffset;
-    origin.constructor.annotations
-        .forEach((m) => m.fileOffset = _constructor.fileOffset);
+    finishConstructorPatch(origin.constructor, _constructor);
 
-    origin.constructor.isExternal = _constructor.isExternal;
-    origin.constructor.function = _constructor.function;
-    origin.constructor.function.parent = origin.constructor;
-    origin.constructor.initializers = _constructor.initializers;
-    setParents(origin.constructor.initializers, origin.constructor);
+    if (_constructorTearOff != null) {
+      finishProcedurePatch(origin._constructorTearOff!, _constructorTearOff!);
+    }
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
index cef67f3..09523b6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
@@ -151,8 +151,12 @@
     _procedureInternal.isStatic = isStatic;
 
     if (_factoryTearOff != null) {
-      buildConstructorTearOffProcedure(_factoryTearOff!, _procedureInternal,
-          classBuilder!.cls, libraryBuilder);
+      buildConstructorTearOffProcedure(
+          tearOff: _factoryTearOff!,
+          declarationConstructor: _procedure,
+          implementationConstructor: _procedureInternal,
+          enclosingClass: classBuilder!.cls,
+          libraryBuilder: libraryBuilder);
     }
     return _procedureInternal;
   }
@@ -224,21 +228,11 @@
   }
 
   void _finishPatch() {
-    // TODO(ahe): restore file-offset once we track both origin and patch file
-    // URIs. See https://github.com/dart-lang/sdk/issues/31579
-    origin._procedure.fileUri = fileUri;
-    origin._procedure.startFileOffset = _procedureInternal.startFileOffset;
-    origin._procedure.fileOffset = _procedureInternal.fileOffset;
-    origin._procedure.fileEndOffset = _procedureInternal.fileEndOffset;
-    origin._procedure.annotations
-        .forEach((m) => m.fileOffset = _procedureInternal.fileOffset);
+    finishProcedurePatch(origin._procedure, _procedureInternal);
 
-    origin._procedure.isAbstract = _procedureInternal.isAbstract;
-    origin._procedure.isExternal = _procedureInternal.isExternal;
-    origin._procedure.function = _procedureInternal.function;
-    origin._procedure.function.parent = origin._procedure;
-    origin._procedure.isRedirectingFactory =
-        _procedureInternal.isRedirectingFactory;
+    if (_factoryTearOff != null) {
+      finishProcedurePatch(origin._factoryTearOff!, _factoryTearOff!);
+    }
   }
 
   @override
@@ -373,7 +367,9 @@
     if (_factoryTearOff != null) {
       _tearOffTypeParameters =
           buildRedirectingFactoryTearOffProcedureParameters(
-              _factoryTearOff!, _procedureInternal, libraryBuilder);
+              tearOff: _factoryTearOff!,
+              implementationConstructor: _procedureInternal,
+              libraryBuilder: libraryBuilder);
     }
     return _procedureInternal;
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
index 89731b6..1a7fe1f 100644
--- a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
@@ -16,6 +16,7 @@
 import '../builder/type_variable_builder.dart';
 import '../kernel/hierarchy/class_member.dart';
 import '../kernel/hierarchy/members_builder.dart';
+import '../kernel/kernel_helper.dart';
 import '../kernel/member_covariance.dart';
 import '../source/name_scheme.dart';
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
@@ -470,20 +471,7 @@
   int finishPatch() {
     if (!isPatch) return 0;
 
-    // TODO(ahe): restore file-offset once we track both origin and patch file
-    // URIs. See https://github.com/dart-lang/sdk/issues/31579
-    origin.procedure.fileUri = fileUri;
-    origin.procedure.startFileOffset = _procedure.startFileOffset;
-    origin.procedure.fileOffset = _procedure.fileOffset;
-    origin.procedure.fileEndOffset = _procedure.fileEndOffset;
-    origin.procedure.annotations
-        .forEach((m) => m.fileOffset = _procedure.fileOffset);
-
-    origin.procedure.isAbstract = _procedure.isAbstract;
-    origin.procedure.isExternal = _procedure.isExternal;
-    origin.procedure.function = _procedure.function;
-    origin.procedure.function.parent = origin.procedure;
-    origin.procedure.isRedirectingFactory = _procedure.isRedirectingFactory;
+    finishProcedurePatch(origin.procedure, _procedure);
     return 1;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
index 720a1b4..c24455e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
@@ -4,7 +4,6 @@
 
 library fasta.source_type_alias_builder;
 
-import 'package:front_end/src/fasta/kernel/expression_generator_helper.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/type_environment.dart';
@@ -24,6 +23,7 @@
 import '../fasta_codes.dart'
     show noLength, templateCyclicTypedef, templateTypeArgumentMismatch;
 import '../kernel/constructor_tearoff_lowering.dart';
+import '../kernel/expression_generator_helper.dart';
 import '../kernel/kernel_helper.dart';
 import '../problems.dart' show unhandled;
 import '../scope.dart';
@@ -275,14 +275,14 @@
   Map<Procedure, Member>? _tearOffDependencies;
 
   void buildTypedefTearOffs(
-      SourceLibraryBuilder library, void Function(Procedure) f) {
+      SourceLibraryBuilder libraryBuilder, void Function(Procedure) f) {
     TypeDeclarationBuilder? declaration = unaliasDeclaration(null);
     DartType? targetType = typedef.type;
     if (declaration is ClassBuilder &&
         targetType is InterfaceType &&
         typedef.typeParameters.isNotEmpty &&
-        !isProperRenameForClass(
-            library.loader.typeEnvironment, typedef, library.library)) {
+        !isProperRenameForClass(libraryBuilder.loader.typeEnvironment, typedef,
+            libraryBuilder.library)) {
       tearOffs = {};
       _tearOffDependencies = {};
       declaration
@@ -295,19 +295,31 @@
           Name targetName =
               new Name(constructorName, declaration.libraryBuilder.library);
           Reference? tearOffReference;
-          if (library.referencesFromIndexed != null) {
-            tearOffReference = library.referencesFromIndexed!
+          if (libraryBuilder.referencesFromIndexed != null) {
+            tearOffReference = libraryBuilder.referencesFromIndexed!
                 .lookupGetterReference(typedefTearOffName(name, constructorName,
-                    library.referencesFromIndexed!.library));
+                    libraryBuilder.referencesFromIndexed!.library));
           }
 
           Procedure tearOff = tearOffs![targetName] =
-              createTypedefTearOffProcedure(name, constructorName, library,
-                  target.fileUri, target.fileOffset, tearOffReference);
+              createTypedefTearOffProcedure(
+                  name,
+                  constructorName,
+                  libraryBuilder,
+                  target.fileUri,
+                  target.fileOffset,
+                  tearOffReference);
           _tearOffDependencies![tearOff] = target;
 
-          buildTypedefTearOffProcedure(tearOff, target, declaration.cls,
-              typedef.typeParameters, targetType.typeArguments, library);
+          buildTypedefTearOffProcedure(
+              tearOff: tearOff,
+              declarationConstructor: target,
+              // TODO(johnniwinther): Handle patched constructors.
+              implementationConstructor: target,
+              enclosingClass: declaration.cls,
+              typeParameters: typedef.typeParameters,
+              typeArguments: targetType.typeArguments,
+              libraryBuilder: libraryBuilder);
           f(tearOff);
         }
       });
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart b/pkg/front_end/testcases/dart2js/issue48776.dart
new file mode 100644
index 0000000..5bad3b1
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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.
+
+main() {
+  BigInt.from;
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect
new file mode 100644
index 0000000..e2cba6b
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect
@@ -0,0 +1,5 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json b/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json
new file mode 100644
index 0000000..154c73c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json
@@ -0,0 +1,12 @@
+{
+  "none": {
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch_lib.dart"
+        ],
+        "uri": "origin_lib.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart
new file mode 100644
index 0000000..676f68a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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 'dart:test';
+
+main() {
+  Class.new;
+  Class.fact;
+  Class.redirect;
+  Class.redirect2;
+  ClassImpl.new;
+  ClassImpl.patched;
+  Alias.new;
+  Alias.fact;
+  Alias.redirect;
+  Alias.redirect2;
+  AliasImpl.new;
+  AliasImpl.patched;
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect
new file mode 100644
index 0000000..49786e9
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect
@@ -0,0 +1,77 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+  ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = self2::Class<T>;
+typedef AliasImpl<T extends core::num> = self2::ClassImpl<T>;
+@_js::patch
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self2::Class::redirect, self2::Class::redirect2]/*isLegacy*/;
+  @_js::patch
+  external constructor •({core::bool defaultValue = true, required self2::Class::T% value = null}) → self2::Class<self2::Class::T%>
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::_#new#tearOff::T% value}) → self2::Class<self2::Class::_#new#tearOff::T%>
+    return new self2::Class::•<self2::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @_js::patch
+  external static factory fact<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::fact::T% value}) → self2::Class<self2::Class::fact::T%>;
+  static method _#fact#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::_#fact#tearOff::T% value}) → self2::Class<self2::Class::_#fact#tearOff::T%>
+    return self2::Class::fact<self2::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @_js::patch
+  external static factory redirect<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect::T% value}) → self2::Class<self2::Class::redirect::T%>
+    return new self2::ClassImpl::•<self2::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::_#redirect#tearOff::T% value}) → self2::Class<self2::Class::_#redirect#tearOff::T%>
+    return self2::Class::redirect<self2::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @_js::patch
+  external static factory redirect2<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect2::T% value}) → self2::Class<self2::Class::redirect2::T%>
+    return new self2::ClassImpl::patched<self2::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::_#redirect2#tearOff::T% value}) → self2::Class<self2::Class::_#redirect2#tearOff::T%>
+    return self2::Class::redirect2<self2::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@_js::patch
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements self2::Class<self2::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+    ;
+  @_js::patch
+  external constructor patched({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::ClassImpl::_#new#tearOff::T% value}) → self2::ClassImpl<self2::ClassImpl::_#new#tearOff::T%>
+    return new self2::ClassImpl::•<self2::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method _#patched#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::ClassImpl::_#patched#tearOff::T% value}) → self2::ClassImpl<self2::ClassImpl::_#patched#tearOff::T%>
+    return new self2::ClassImpl::patched<self2::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#new#tearOff::T value}) → self2::Class<self2::_#Alias#new#tearOff::T>
+  return new self2::Class::•<self2::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#fact#tearOff::T value}) → self2::Class<self2::_#Alias#fact#tearOff::T>
+  return self2::Class::fact<self2::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect#tearOff::T value}) → self2::Class<self2::_#Alias#redirect#tearOff::T>
+  return self2::Class::_#redirect#tearOff<self2::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect2#tearOff::T value}) → self2::Class<self2::_#Alias#redirect2#tearOff::T>
+  return self2::Class::_#redirect2#tearOff<self2::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#new#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#new#tearOff::T>
+  return new self2::ClassImpl::•<self2::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#patched#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#patched#tearOff::T>
+  return new self2::ClassImpl::patched<self2::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:47 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:7:10 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:8:29 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:12:22 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:15:12 -> InstanceConstant(const _Patch{})
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect)
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect2)
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:39 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:19:48 -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 52, effectively constant: 9
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart
new file mode 100644
index 0000000..c29cf6f
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2022, 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 Class<T> {
+  external Class({bool defaultValue: true, required T value});
+  external factory Class.fact({bool defaultValue: true, required T value});
+  external factory Class.redirect({bool defaultValue, required T value});
+  external factory Class.redirect2({bool defaultValue, required T value});
+}
+
+class ClassImpl<T> implements Class<T> {
+  ClassImpl({bool defaultValue: true, required T value});
+
+  external ClassImpl.patched({bool defaultValue: true, required T value});
+}
+
+typedef Alias<T extends num> = Class<T>;
+typedef AliasImpl<T extends num> = ClassImpl<T>;
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart
new file mode 100644
index 0000000..77fdfb0
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, 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.
+
+// ignore: import_internal_library
+import 'dart:_js_helper';
+
+@patch
+class Class<T> {
+  @patch
+  Class({bool defaultValue: true, required T value}) {
+    print('patch Class');
+  }
+
+  @patch
+  factory Class.fact({bool defaultValue: true, required T value}) =>
+      new ClassImpl<T>(defaultValue: defaultValue, value: value);
+
+  @patch
+  factory Class.redirect({bool defaultValue, required T value}) = ClassImpl<T>;
+
+  @patch
+  factory Class.redirect2({bool defaultValue, required T value}) =
+      ClassImpl<T>.patched;
+}
+
+@patch
+class ClassImpl<T> implements Class<T> {
+  @patch
+  ClassImpl.patched({bool defaultValue: true, required T value}) {
+    print('patch ClassImpl');
+  }
+}
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 3eaf932..af74037 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,12 +24,12 @@
   @#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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);
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 3eaf932..af74037 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,12 +24,12 @@
   @#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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);
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 3eaf932..af74037 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,12 +24,12 @@
   @#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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);
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
@@ -24,12 +24,12 @@
   @#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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);
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 3eaf932..af74037 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,12 +24,12 @@
   @#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#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);
diff --git a/pkg/front_end/testcases/general/tear_off_patch/libraries.json b/pkg/front_end/testcases/general/tear_off_patch/libraries.json
new file mode 100644
index 0000000..154c73c
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/libraries.json
@@ -0,0 +1,12 @@
+{
+  "none": {
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch_lib.dart"
+        ],
+        "uri": "origin_lib.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart b/pkg/front_end/testcases/general/tear_off_patch/main.dart
new file mode 100644
index 0000000..676f68a
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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 'dart:test';
+
+main() {
+  Class.new;
+  Class.fact;
+  Class.redirect;
+  Class.redirect2;
+  ClassImpl.new;
+  ClassImpl.patched;
+  Alias.new;
+  Alias.fact;
+  Alias.redirect;
+  Alias.redirect2;
+  AliasImpl.new;
+  AliasImpl.patched;
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+    return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+    return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+    return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+    return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+  static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+    return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+  static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+    return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = static-tearoff test::Class::_#new#tearOff
+  #C2 = static-tearoff test::Class::_#fact#tearOff
+  #C3 = static-tearoff test::Class::_#redirect#tearOff
+  #C4 = static-tearoff test::Class::_#redirect2#tearOff
+  #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+  #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _js::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = constructor-tearoff test::Class::•
+  #C2 = constructor-tearoff test::Class::fact
+  #C3 = redirecting-factory-tearoff test::Class::redirect
+  #C4 = redirecting-factory-tearoff test::Class::redirect2
+  #C5 = constructor-tearoff test::ClassImpl::•
+  #C6 = constructor-tearoff test::ClassImpl::patched
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _in::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = constructor-tearoff test::Class::•
+  #C2 = constructor-tearoff test::Class::fact
+  #C3 = redirecting-factory-tearoff test::Class::redirect
+  #C4 = redirecting-factory-tearoff test::Class::redirect2
+  #C5 = constructor-tearoff test::ClassImpl::•
+  #C6 = constructor-tearoff test::ClassImpl::patched
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _in::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect
new file mode 100644
index 0000000..40d29d3
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+  ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = self2::Class<T>;
+typedef AliasImpl<T extends core::num> = self2::ClassImpl<T>;
+@_in::patch
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self2::Class::redirect, self2::Class::redirect2]/*isLegacy*/;
+  @_in::patch
+  external constructor •({core::bool defaultValue = true, required self2::Class::T% value = null}) → self2::Class<self2::Class::T%>
+    ;
+  @_in::patch
+  external static factory fact<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::fact::T% value}) → self2::Class<self2::Class::fact::T%>;
+  @_in::patch
+  external static factory redirect<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect::T% value}) → self2::Class<self2::Class::redirect::T%>
+    return new self2::ClassImpl::•<self2::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  @_in::patch
+  external static factory redirect2<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect2::T% value}) → self2::Class<self2::Class::redirect2::T%>
+    return new self2::ClassImpl::patched<self2::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@_in::patch
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements self2::Class<self2::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+    ;
+  @_in::patch
+  external constructor patched({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+    ;
+}
+static method _#Alias#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#new#tearOff::T value}) → self2::Class<self2::_#Alias#new#tearOff::T>
+  return new self2::Class::•<self2::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#fact#tearOff::T value}) → self2::Class<self2::_#Alias#fact#tearOff::T>
+  return self2::Class::fact<self2::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect#tearOff::T value}) → self2::Class<self2::_#Alias#redirect#tearOff::T>
+  return self2::Class::redirect<self2::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect2#tearOff::T value}) → self2::Class<self2::_#Alias#redirect2#tearOff::T>
+  return self2::Class::redirect2<self2::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#new#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#new#tearOff::T>
+  return new self2::ClassImpl::•<self2::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#patched#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#patched#tearOff::T>
+  return new self2::ClassImpl::patched<self2::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:46 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:7:9 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:8:28 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:12:21 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:15:11 -> InstanceConstant(const _Patch{})
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect)
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect2)
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:38 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:19:47 -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 34, effectively constant: 9
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+  #C1;
+  #C2;
+  #C3;
+  #C4;
+  #C5;
+  #C6;
+  #C7;
+  #C8;
+  #C9;
+  #C10;
+  #C11;
+  #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+  @#C13
+  constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+    : super core::Object::•() {
+    core::print("patch Class");
+  }
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+    return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+    return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+  @#C13
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+    return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+  constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•()
+    ;
+  @#C13
+  constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+    : super core::Object::•() {
+    core::print("patch ClassImpl");
+  }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+  return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+  return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+  return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+  return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+  return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+  return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants  {
+  #C1 = constructor-tearoff test::Class::•
+  #C2 = constructor-tearoff test::Class::fact
+  #C3 = redirecting-factory-tearoff test::Class::redirect
+  #C4 = redirecting-factory-tearoff test::Class::redirect2
+  #C5 = constructor-tearoff test::ClassImpl::•
+  #C6 = constructor-tearoff test::ClassImpl::patched
+  #C7 = static-tearoff test::_#Alias#new#tearOff
+  #C8 = static-tearoff test::_#Alias#fact#tearOff
+  #C9 = static-tearoff test::_#Alias#redirect#tearOff
+  #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+  #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+  #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+  #C13 = _in::_Patch {}
+  #C14 = constructor-tearoff test::Class::redirect
+  #C15 = constructor-tearoff test::Class::redirect2
+  #C16 = true
+  #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart b/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart
new file mode 100644
index 0000000..c29cf6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2022, 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 Class<T> {
+  external Class({bool defaultValue: true, required T value});
+  external factory Class.fact({bool defaultValue: true, required T value});
+  external factory Class.redirect({bool defaultValue, required T value});
+  external factory Class.redirect2({bool defaultValue, required T value});
+}
+
+class ClassImpl<T> implements Class<T> {
+  ClassImpl({bool defaultValue: true, required T value});
+
+  external ClassImpl.patched({bool defaultValue: true, required T value});
+}
+
+typedef Alias<T extends num> = Class<T>;
+typedef AliasImpl<T extends num> = ClassImpl<T>;
diff --git a/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart b/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart
new file mode 100644
index 0000000..7265272
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, 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.
+
+// ignore: import_internal_library
+import 'dart:_internal';
+
+@patch
+class Class<T> {
+  @patch
+  Class({bool defaultValue: true, required T value}) {
+    print('patch Class');
+  }
+
+  @patch
+  factory Class.fact({bool defaultValue: true, required T value}) =>
+      new ClassImpl<T>(defaultValue: defaultValue, value: value);
+
+  @patch
+  factory Class.redirect({bool defaultValue, required T value}) = ClassImpl<T>;
+
+  @patch
+  factory Class.redirect2({bool defaultValue, required T value}) =
+      ClassImpl<T>.patched;
+}
+
+@patch
+class ClassImpl<T> implements Class<T> {
+  @patch
+  ClassImpl.patched({bool defaultValue: true, required T value}) {
+    print('patch ClassImpl');
+  }
+}
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 11fc5c8..bd73e56 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -331,6 +331,7 @@
   /// ```
   String toString() {
     var microseconds = inMicroseconds;
+    var sign = (microseconds < 0) ? "-" : "";
 
     var hours = microseconds ~/ microsecondsPerHour;
     microseconds = microseconds.remainder(microsecondsPerHour);
@@ -348,7 +349,7 @@
     var secondsPadding = seconds < 10 ? "0" : "";
 
     var paddedMicroseconds = microseconds.toString().padLeft(6, "0");
-    return "$hours:"
+    return "$sign${hours.abs()}:"
         "$minutesPadding$minutes:"
         "$secondsPadding$seconds.$paddedMicroseconds";
   }
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index 9dccd22..a9990a3 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -4,6 +4,9 @@
 
 part of dart.developer;
 
+// Examples can assume:
+// void doSomething() {}
+
 const bool _hasTimeline =
     const bool.fromEnvironment("dart.developer.timeline", defaultValue: true);
 
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index 3f740d5..5106021 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.dart
@@ -9,7 +9,7 @@
 /// A dynamically loaded library is a mapping from symbols to memory addresses.
 /// These memory addresses can be accessed through [lookup].
 class DynamicLibrary {
-  /// Creates a dynamic library holding all global symbols.
+  /// Creates a [DynamicLibrary] holding all global symbols.
   ///
   /// Any symbol in a library currently loaded with global visibility
   /// (including the executable itself) may be resolved through this library.
@@ -17,8 +17,10 @@
   /// This feature is not available on Windows.
   external factory DynamicLibrary.process();
 
-  /// Creates a dynamic library containing all the symbols of the running
+  /// Creates a [DynamicLibrary] containing all the symbols of the running
   /// executable.
+  ///
+  /// This is useful for using dart:ffi with static libraries.
   external factory DynamicLibrary.executable();
 
   /// Loads a library file and provides access to its symbols.
diff --git a/sdk/lib/js_util/js_util.dart b/sdk/lib/js_util/js_util.dart
index d0db609..081bcb8 100644
--- a/sdk/lib/js_util/js_util.dart
+++ b/sdk/lib/js_util/js_util.dart
@@ -17,6 +17,10 @@
 import 'dart:_js_helper'
     show convertDartClosureToJS, assertInterop, assertInteropArgs;
 
+// Examples can assume:
+// class JS { const JS(); }
+// class Promise<T> {}
+
 /// Recursively converts a JSON-like collection to JavaScript compatible
 /// representation.
 ///
@@ -305,9 +309,11 @@
 /// @JS()
 /// external Promise<num> get threePromise; // Resolves to 3
 ///
-/// final Future<num> threeFuture = promiseToFuture(threePromise);
+/// void main() async {
+///   final Future<num> threeFuture = promiseToFuture(threePromise);
 ///
-/// final three = await threeFuture; // == 3
+///   final three = await threeFuture; // == 3
+/// }
 /// ```
 Future<T> promiseToFuture<T>(Object jsPromise) {
   final completer = Completer<T>();
diff --git a/tests/corelib/duration_test.dart b/tests/corelib/duration_test.dart
index 7080723..e60efb8 100644
--- a/tests/corelib/duration_test.dart
+++ b/tests/corelib/duration_test.dart
@@ -298,4 +298,21 @@
 
   Expect.equals(d2, -d1);
   Expect.equals(d1, -d2);
+
+  // Regression test for http://dartbug.com/48841
+  d = const Duration(minutes: -1);
+  Expect.equals("-0:01:00.000000", d.toString());
+  d = const Duration(seconds: -1);
+  Expect.equals("-0:00:01.000000", d.toString());
+  d = const Duration(milliseconds: -1);
+  Expect.equals("-0:00:00.001000", d.toString());
+  d = const Duration(microseconds: -1);
+  Expect.equals("-0:00:00.000001", d.toString());
+  d = const Duration(microseconds: -9223372036854775808); // Min 64-bit int.
+  // Not checking precise values, because they will be off on the web.
+  Expect.equals("-2562047788:00:54.775808", d.toString());
+  Expect.isTrue(d.toString().startsWith("-"));
+  Expect.isFalse(d.toString().startsWith("--"));
+  d = const Duration(minutes: -0); // is -0.0 on web.
+  Expect.equals("0:00:00.000000", d.toString());
 }
diff --git a/tests/corelib_2/duration_test.dart b/tests/corelib_2/duration_test.dart
index fb80464..33ebf1f 100644
--- a/tests/corelib_2/duration_test.dart
+++ b/tests/corelib_2/duration_test.dart
@@ -300,4 +300,21 @@
 
   Expect.equals(d2, -d1);
   Expect.equals(d1, -d2);
+
+  // Regression test for http://dartbug.com/48841
+  d = const Duration(minutes: -1);
+  Expect.equals("-0:01:00.000000", d.toString());
+  d = const Duration(seconds: -1);
+  Expect.equals("-0:00:01.000000", d.toString());
+  d = const Duration(milliseconds: -1);
+  Expect.equals("-0:00:00.001000", d.toString());
+  d = const Duration(microseconds: -1);
+  Expect.equals("-0:00:00.000001", d.toString());
+  d = const Duration(microseconds: -9223372036854775808); // Min 64-bit int.
+  // Not checking precise values, because they will be off on the web.
+  Expect.equals("-2562047788:00:54.775808", d.toString());
+  Expect.isTrue(d.toString().startsWith("-"));
+  Expect.isFalse(d.toString().startsWith("--"));
+  d = const Duration(minutes: -0); // is -0.0 on web.
+  Expect.equals("0:00:00.000000", d.toString());
 }
diff --git a/tests/language/constructor/patch_tear_off_test.dart b/tests/language/constructor/patch_tear_off_test.dart
new file mode 100644
index 0000000..632a208
--- /dev/null
+++ b/tests/language/constructor/patch_tear_off_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/48776
+
+main() {
+  /// BigInt.from is a patched constructor.
+  BigInt.from;
+}
diff --git a/tests/web/regress/issue/230108748_test.dart b/tests/web/regress/issue/230108748_test.dart
new file mode 100644
index 0000000..c90c6b6
--- /dev/null
+++ b/tests/web/regress/issue/230108748_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, 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.
+// SharedOptions=-Da=true -Db=false
+
+import 'package:expect/expect.dart';
+
+class Base {
+  final int x;
+  const Base(this.x);
+}
+
+class Child extends Base {
+  static const Child A = Child._(const bool.fromEnvironment('a') ? 0 : 1);
+  static const Child B = Child._(const bool.fromEnvironment('b') ? 0 : 2);
+
+  const Child._(int x) : super(x);
+}
+
+int case1() {
+  switch (null as dynamic) {
+    case Child.A:
+      return 1;
+    default:
+      return 2;
+  }
+}
+
+class A {
+  final int x;
+  const A(this.x);
+
+  static const A a1 = A(const bool.fromEnvironment('x') ? 0 : 1);
+  static const A a2 = A(const bool.fromEnvironment('x') ? 0 : 2);
+}
+
+int case2() {
+  switch (null as dynamic) {
+    case A.a1:
+      return 1;
+    default:
+      return 2;
+  }
+}
+
+class B {
+  final int x;
+  const B(this.x);
+}
+
+int case3() {
+  switch (null as dynamic) {
+    case B(const bool.fromEnvironment('x') ? 0 : 1):
+      return 1;
+    default:
+      return 2;
+  }
+}
+
+void main() {
+  Expect.equals(case1(), 2);
+  Expect.equals(case2(), 2);
+  Expect.equals(case3(), 2);
+}
diff --git a/tools/OWNERS b/tools/OWNERS
index 8d66888..fa2dc56 100644
--- a/tools/OWNERS
+++ b/tools/OWNERS
@@ -2,6 +2,7 @@
 
 # Groups administrate themselves.
 per-file OWNERS_ANALYZER=file:OWNERS_ANALYZER
+per-file OWNERS_BUILD=file:OWNERS_BUILD
 per-file OWNERS_CFE=file:OWNERS_CFE
 per-file OWNERS_ECOSYSTEM=file:OWNERS_ECOSYSTEM
 per-file OWNERS_FOUNDATION=file:OWNERS_FOUNDATION
@@ -11,3 +12,6 @@
 per-file OWNERS_PUB=file:OWNERS_PUB
 per-file OWNERS_VM=file:OWNERS_VM
 per-file OWNERS_WEB=file:OWNERS_WEB
+
+# Changed along with build files
+per-file *.py=file:OWNERS_BUILD
diff --git a/tools/OWNERS_BUILD b/tools/OWNERS_BUILD
new file mode 100644
index 0000000..2d5cb00
--- /dev/null
+++ b/tools/OWNERS_BUILD
@@ -0,0 +1,2 @@
+file:OWNERS_INFRA
+file:OWNERS_VM
diff --git a/tools/VERSION b/tools/VERSION
index 2648abd..a15f79a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 56
+PRERELEASE 57
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 459362c..7bab851 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -3682,14 +3682,17 @@
           "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
             "tools/verify_docs/bin/verify_docs.dart",
-            "sdk/lib/_http",
-            "sdk/lib/_internal",
-            "sdk/lib/cli",
-            "sdk/lib/convert",
-            "sdk/lib/ffi",
-            "sdk/lib/js",
-            "sdk/lib/math",
-            "sdk/lib/mirrors"
+            "dart:_http",
+            "dart:_internal",
+            "dart:cli",
+            "dart:convert",
+            "dart:developer",
+            "dart:ffi",
+            "dart:js",
+            "dart:js_util",
+            "dart:math",
+            "dart:mirrors",
+            "dart:wasm"
           ]
         },
         {