Version 2.18.0-113.0.dev

Merge commit '44f85834256ea00ebad401b54934f18028ff3101' into 'dev'
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index 54a7d17..d65c266 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'dart:collection';
 
 import 'package:kernel/kernel.dart';
@@ -55,7 +53,7 @@
   if (type is InterfaceType) {
     var name = '${type.classNode.name}$nullability';
     var typeArgs = type.typeArguments;
-    if (typeArgs == null) return name;
+    if (typeArgs.isEmpty) return name;
     if (typeArgs.every((p) => p == const DynamicType())) return name;
     return "${name}Of${typeArgs.map(_typeString).join("\$")}";
   }
@@ -67,7 +65,7 @@
   if (type is TypedefType) {
     var name = '${type.typedefNode.name}$nullability';
     var typeArgs = type.typeArguments;
-    if (typeArgs == null) return name;
+    if (typeArgs.isEmpty) return name;
     if (typeArgs.every((p) => p == const DynamicType())) return name;
     return "${name}Of${typeArgs.map(_typeString).join("\$")}";
   }
@@ -110,7 +108,7 @@
 
   /// Holds JS type generators keyed by their underlying DartType.
   final typeContainer = ModuleItemContainer<DartType>.asObject('T',
-      keyToString: (DartType t) => escapeIdentifier(_typeString(t)));
+      keyToString: (DartType t) => escapeIdentifier(_typeString(t))!);
 
   final js_ast.Expression Function(String, [List<Object>]) _runtimeCall;
 
@@ -151,8 +149,8 @@
 
   js_ast.Statement _dischargeFreeType(DartType type) {
     typeContainer.setNoEmit(type);
-    var init = typeContainer[type];
-    var id = _unboundTypeIds[type];
+    var init = typeContainer[type]!;
+    var id = _unboundTypeIds[type]!;
     // TODO(vsm): Change back to `let`.
     // See https://github.com/dart-lang/sdk/issues/40380.
     return js.statement('var # = () => ((# = #)());', [
@@ -167,7 +165,8 @@
   ///
   /// If [formals] is present, only emit the definitions which depend on the
   /// formals.
-  List<js_ast.Statement> dischargeFreeTypes([Iterable<TypeParameter> formals]) {
+  List<js_ast.Statement> dischargeFreeTypes(
+      [Iterable<TypeParameter>? formals]) {
     var decls = <js_ast.Statement>[];
     var types = formals == null
         ? typeContainer.keys.where((p) => freeTypeParameters(p).isNotEmpty)
@@ -175,7 +174,7 @@
 
     for (var t in types) {
       var stmt = _dischargeFreeType(t);
-      if (stmt != null) decls.add(stmt);
+      decls.add(stmt);
     }
     return decls;
   }
@@ -221,7 +220,7 @@
       // TODO(40273) Remove prepended text when we have a better way to hide
       // these names from debug tools.
       _unboundTypeIds[type] =
-          js_ast.TemporaryId(escapeIdentifier('__t\$${_typeString(type)}'));
+          js_ast.TemporaryId(escapeIdentifier('__t\$${_typeString(type)}')!);
     }
 
     for (var free in freeVariables) {
diff --git a/pkg/dev_compiler/test/modular_suite.dart b/pkg/dev_compiler/test/modular_suite.dart
index 1d540ba..1a53fcd 100644
--- a/pkg/dev_compiler/test/modular_suite.dart
+++ b/pkg/dev_compiler/test/modular_suite.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 /// Test the modular compilation pipeline of ddc.
 ///
 /// This is a shell that runs multiple tests, one per folder under `data/`.
@@ -18,9 +16,9 @@
 String packageConfigJsonPath = '.dart_tool/package_config.json';
 Uri sdkRoot = Platform.script.resolve('../../../');
 Uri packageConfigUri = sdkRoot.resolve(packageConfigJsonPath);
-Options _options;
-String _dartdevcScript;
-String _kernelWorkerScript;
+late Options _options;
+late String _dartdevcScript;
+late String _kernelWorkerScript;
 
 void main(List<String> args) async {
   _options = Options.parse(args);
@@ -89,8 +87,7 @@
       extraArgs = [
         '--libraries-file',
         '$rootScheme:///sdk/lib/libraries.json',
-        '--enable-experiment',
-        'non-nullable',
+        '--no-sound-null-safety',
       ];
       assert(transitiveDependencies.isEmpty);
     } else {
@@ -175,8 +172,7 @@
         '--compile-sdk',
         '--libraries-file',
         '$rootScheme:///sdk/lib/libraries.json',
-        '--enable-experiment',
-        'non-nullable',
+        '--no-sound-null-safety',
       ];
       assert(transitiveDependencies.isEmpty);
     } else {
@@ -319,7 +315,7 @@
 
 String _sourceToImportUri(Module module, String rootScheme, Uri relativeUri) {
   if (module.isPackage) {
-    var basePath = module.packageBase.path;
+    var basePath = module.packageBase!.path;
     var packageRelativePath = basePath == './'
         ? relativeUri.path
         : relativeUri.path.substring(basePath.length);
diff --git a/pkg/dev_compiler/test/modular_suite_nnbd.dart b/pkg/dev_compiler/test/modular_suite_nnbd.dart
index 4a19cfb..c5c0567 100644
--- a/pkg/dev_compiler/test/modular_suite_nnbd.dart
+++ b/pkg/dev_compiler/test/modular_suite_nnbd.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 /// Test the modular compilation pipeline of ddc.
 ///
 /// This is a shell that runs multiple tests, one per folder under `data/`.
@@ -18,9 +16,9 @@
 String packageConfigJsonPath = '.dart_tool/package_config.json';
 Uri sdkRoot = Platform.script.resolve('../../../');
 Uri packageConfigUri = sdkRoot.resolve(packageConfigJsonPath);
-Options _options;
-String _dartdevcScript;
-String _kernelWorkerScript;
+late Options _options;
+late String _dartdevcScript;
+late String _kernelWorkerScript;
 
 void main(List<String> args) async {
   _options = Options.parse(args);
@@ -120,10 +118,7 @@
           .where((m) => !m.isSdk)
           .expand((m) => ['--input-summary', '${toUri(m, dillId)}']),
       ...sources.expand((String uri) => ['--source', uri]),
-      // TODO(40266) After unfork of dart:_runtime only need experiment when
-      // compiling SDK. For now always use the Null Safety experiment.
-      '--enable-experiment',
-      'non-nullable',
+      '--sound-null-safety',
       ...flags.expand((String flag) => ['--enable-experiment', flag]),
     ];
 
@@ -206,10 +201,7 @@
       rootScheme,
       ...sources,
       ...extraArgs,
-      // TODO(40266) After unfork of dart:_runtime only need experiment when
-      // compiling SDK. For now always use the Null Safety experiment.
-      '--enable-experiment',
-      'non-nullable',
+      '--sound-null-safety',
       for (String flag in flags) '--enable-experiment=$flag',
       ...transitiveDependencies
           .where((m) => !m.isSdk)
@@ -323,7 +315,7 @@
 
 String _sourceToImportUri(Module module, String rootScheme, Uri relativeUri) {
   if (module.isPackage) {
-    var basePath = module.packageBase.path;
+    var basePath = module.packageBase!.path;
     var packageRelativePath = basePath == './'
         ? relativeUri.path
         : relativeUri.path.substring(basePath.length);
diff --git a/pkg/test_runner/bin/http_server.dart b/pkg/test_runner/bin/http_server.dart
index b034e72..a6eeacc 100644
--- a/pkg/test_runner/bin/http_server.dart
+++ b/pkg/test_runner/bin/http_server.dart
@@ -2,10 +2,10 @@
 // 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:args/args.dart';
 import 'package:test_runner/src/configuration.dart';
 import 'package:test_runner/src/testing_servers.dart';
 import 'package:test_runner/src/utils.dart';
-import 'package:test_runner/src/vendored_pkg/args/args.dart';
 
 void main(List<String> arguments) {
   var parser = ArgParser();
@@ -30,7 +30,7 @@
 
   var args = parser.parse(arguments);
   if (args['help'] as bool) {
-    print(parser.getUsage());
+    print(parser.usage);
   } else {
     var servers = TestingServers(
         args['build-directory'] as String,
diff --git a/pkg/test_runner/lib/src/vendored_pkg/README.txt b/pkg/test_runner/lib/src/vendored_pkg/README.txt
deleted file mode 100644
index 0d4c1a7..0000000
--- a/pkg/test_runner/lib/src/vendored_pkg/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-The files in this folder are copies of libraries in the pkg directory. We have
-copies here to prevent a bootstrapping issue when running the test.dart binary
-in case breaking changes are made to the language in future revisions, we can
-still test with a known stable version.
diff --git a/pkg/test_runner/lib/src/vendored_pkg/args/args.dart b/pkg/test_runner/lib/src/vendored_pkg/args/args.dart
deleted file mode 100644
index d36be63..0000000
--- a/pkg/test_runner/lib/src/vendored_pkg/args/args.dart
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// This library lets you define parsers for parsing raw command-line arguments
-/// into a set of options and values using [GNU][] and [POSIX][] style options.
-///
-/// ## Defining options ##
-///
-/// To use this library, you create an [ArgParser] object which will contain
-/// the set of options you support:
-///
-///     var parser = new ArgParser();
-///
-/// Then you define a set of options on that parser using [addOption()] and
-/// [addFlag()]. The minimal way to create an option is:
-///
-///     parser.addOption('name');
-///
-/// This creates an option named "name". Options must be given a value on the
-/// command line. If you have a simple on/off flag, you can instead use:
-///
-///     parser.addFlag('name');
-///
-/// Flag options will, by default, accept a 'no-' prefix to negate the option.
-/// This can be disabled like so:
-///
-///     parser.addFlag('name', negatable: false);
-///
-/// (From here on out "option" will refer to both "regular" options and flags.
-/// In cases where the distinction matters, we'll use "non-flag option".)
-///
-/// Options may have an optional single-character abbreviation:
-///
-///     parser.addOption('mode', abbr: 'm');
-///     parser.addFlag('verbose', abbr: 'v');
-///
-/// They may also specify a default value. The default value will be used if the
-/// option isn't provided:
-///
-///     parser.addOption('mode', defaultsTo: 'debug');
-///     parser.addFlag('verbose', defaultsTo: false);
-///
-/// The default value for non-flag options can be any [String]. For flags, it
-/// must be a [bool].
-///
-/// To validate non-flag options, you may provide an allowed set of values. When
-/// you do, it will throw a [FormatException] when you parse the arguments if
-/// the value for an option is not in the allowed set:
-///
-///     parser.addOption('mode', allowed: ['debug', 'release']);
-///
-/// You can provide a callback when you define an option. When you later parse
-/// a set of arguments, the callback for that option will be invoked with the
-/// value provided for it:
-///
-///     parser.addOption('mode', callback: (mode) => print('Got mode $mode));
-///     parser.addFlag('verbose', callback: (verbose) {
-///       if (verbose) print('Verbose');
-///     });
-///
-/// The callback for each option will *always* be called when you parse a set of
-/// arguments. If the option isn't provided in the args, the callback will be
-/// passed the default value, or `null` if there is none set.
-///
-/// ## Parsing arguments ##
-///
-/// Once you have an [ArgParser] set up with some options and flags, you use it
-/// by calling [ArgParser.parse()] with a set of arguments:
-///
-///     var results = parser.parse(['some', 'command', 'line', 'args']);
-///
-/// These will usually come from `new Options().arguments`, but you can pass in
-/// any list of strings. It returns an instance of [ArgResults]. This is a
-/// map-like object that will return the value of any parsed option.
-///
-///     var parser = new ArgParser();
-///     parser.addOption('mode');
-///     parser.addFlag('verbose', defaultsTo: true);
-///     var results = parser.parse('['--mode', 'debug', 'something', 'else']);
-///
-///     print(results['mode']); // debug
-///     print(results['verbose']); // true
-///
-/// The [parse()] method will stop as soon as it reaches `--` or anything that
-/// it doesn't recognize as an option, flag, or option value. If there are still
-/// arguments left, they will be provided to you in
-/// [ArgResults.rest].
-///
-///     print(results.rest); // ['something', 'else']
-///
-/// ## Specifying options ##
-///
-/// To actually pass in options and flags on the command line, use GNU or POSIX
-/// style. If you define an option like:
-///
-///     parser.addOption('name', abbr: 'n');
-///
-/// Then a value for it can be specified on the command line using any of:
-///
-///     --name=somevalue
-///     --name somevalue
-///     -nsomevalue
-///     -n somevalue
-///
-/// Given this flag:
-///
-///     parser.addFlag('name', abbr: 'n');
-///
-/// You can set it on using one of:
-///
-///     --name
-///     -n
-///
-/// Or set it off using:
-///
-///     --no-name
-///
-/// Multiple flag abbreviation can also be collapsed into a single argument. If
-/// you define:
-///
-///     parser.addFlag('verbose', abbr: 'v');
-///     parser.addFlag('french', abbr: 'f');
-///     parser.addFlag('iambic-pentameter', abbr: 'i');
-///
-/// Then all three flags could be set using:
-///
-///     -vfi
-///
-/// By default, an option has only a single value, with later option values
-/// overriding earlier ones; for example:
-///
-///     var parser = new ArgParser();
-///     parser.addOption('mode');
-///     var results = parser.parse(['--mode', 'on', '--mode', 'off']);
-///     print(results['mode']); // prints 'off'
-///
-/// If you need multiple values, set the `allowMultiple` flag. In that
-/// case the option can occur multiple times and when parsing arguments a
-/// List of values will be returned:
-///
-///     var parser = new ArgParser();
-///     parser.addOption('mode', allowMultiple: true);
-///     var results = parser.parse(['--mode', 'on', '--mode', 'off']);
-///     print(results['mode']); // prints '[on, off]'
-///
-/// ## Defining commands ##
-///
-/// In addition to *options*, you can also define *commands*. A command is a
-/// named argument that has its own set of options. For example, when you run:
-///
-///     $ git commit -a
-///
-/// The executable is `git`, the command is `commit`, and the `-a` option is an
-/// option passed to the command. You can add a command like so:
-///
-///     var parser = new ArgParser();
-///     var command = parser.addCommand("commit");
-///     command.addFlag('all', abbr: 'a');
-///
-/// It returns another [ArgParser] which you can use to define options and
-/// subcommands on that command. When an argument list is parsed, you can then
-/// determine which command was entered and what options were provided for it.
-///
-///     var results = parser.parse(['commit', '-a']);
-///     print(results.command.name); // "commit"
-///     print(results.command['a']); // true
-///
-/// ## Displaying usage ##
-///
-/// This library can also be used to automatically generate nice usage help
-/// text like you get when you run a program with `--help`. To use this, you
-/// will also want to provide some help text when you create your options. To
-/// define help text for the entire option, do:
-///
-///     parser.addOption('mode', help: 'The compiler configuration',
-///         allowed: ['debug', 'release']);
-///     parser.addFlag('verbose', help: 'Show additional diagnostic info');
-///
-/// For non-flag options, you can also provide detailed help for each expected
-/// value using a map:
-///
-///     parser.addOption('arch', help: 'The architecture to compile for',
-///         allowedHelp: {
-///           'ia32': 'Intel x86',
-///           'arm': 'ARM Holding 32-bit chip'
-///         });
-///
-/// If you define a set of options like the above, then calling this:
-///
-///     print(parser.getUsage());
-///
-/// Will display something like:
-///
-///     --mode            The compiler configuration
-///                       [debug, release]
-///
-///     --[no-]verbose    Show additional diagnostic info
-///     --arch            The architecture to compile for
-///
-///           [arm]       ARM Holding 32-bit chip
-///           [ia32]      Intel x86
-///
-/// To assist the formatting of the usage help, single line help text will
-/// be followed by a single new line. Options with multi-line help text
-/// will be followed by two new lines. This provides spatial diversity between
-/// options.
-///
-/// [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
-/// [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces
-library args;
-
-import 'src/parser.dart';
-import 'src/usage.dart';
-
-/// A class for taking a list of raw command line arguments and parsing out
-/// options and flags from them.
-class ArgParser {
-  /// The options that have been defined for this parser.
-  final Map<String, Option> options = <String, Option>{};
-
-  /// The commands that have been defined for this parser.
-  final Map<String, ArgParser> commands = <String, ArgParser>{};
-
-  /// Creates a new ArgParser.
-  ArgParser();
-
-  /// Defines a command. A command is a named argument which may in turn
-  /// define its own options and subcommands. Returns an [ArgParser] that can
-  /// be used to define the command's options.
-  ArgParser addCommand(String name) {
-    // Make sure the name isn't in use.
-    if (commands.containsKey(name)) {
-      throw ArgumentError('Duplicate command "$name".');
-    }
-
-    var command = ArgParser();
-    commands[name] = command;
-    return command;
-  }
-
-  /// Defines a flag. Throws an [ArgumentError] if:
-  ///
-  /// * There is already an option named [name].
-  /// * There is already an option using abbreviation [abbr].
-  void addFlag(String name,
-      {String abbr,
-      String help,
-      bool defaultsTo = false,
-      bool negatable = true,
-      void callback(bool value)}) {
-    _addOption(name, abbr, help, null, null, defaultsTo,
-        callback == null ? null : (value) => callback(value as bool),
-        isFlag: true, negatable: negatable);
-  }
-
-  /// Defines a value-taking option. Throws an [ArgumentError] if:
-  ///
-  /// * There is already an option with name [name].
-  /// * There is already an option using abbreviation [abbr].
-  void addOption(String name,
-      {String abbr,
-      String help,
-      List<String> allowed,
-      Map<String, String> allowedHelp,
-      String defaultsTo,
-      void callback(dynamic value),
-      bool allowMultiple = false}) {
-    _addOption(name, abbr, help, allowed, allowedHelp, defaultsTo, callback,
-        isFlag: false, allowMultiple: allowMultiple);
-  }
-
-  void _addOption(
-      String name,
-      String abbr,
-      String help,
-      List<String> allowed,
-      Map<String, String> allowedHelp,
-      dynamic defaultsTo,
-      void callback(dynamic value),
-      {bool isFlag,
-      bool negatable = false,
-      bool allowMultiple = false}) {
-    // Make sure the name isn't in use.
-    if (options.containsKey(name)) {
-      throw ArgumentError('Duplicate option "$name".');
-    }
-
-    // Make sure the abbreviation isn't too long or in use.
-    if (abbr != null) {
-      if (abbr.length > 1) {
-        throw ArgumentError(
-            'Abbreviation "$abbr" is longer than one character.');
-      }
-
-      var existing = findByAbbreviation(abbr);
-      if (existing != null) {
-        throw ArgumentError(
-            'Abbreviation "$abbr" is already used by "${existing.name}".');
-      }
-    }
-
-    options[name] = Option(
-        name, abbr, help, allowed, allowedHelp, defaultsTo, callback,
-        isFlag: isFlag, negatable: negatable, allowMultiple: allowMultiple);
-  }
-
-  /// Parses [args], a list of command-line arguments, matches them against the
-  /// flags and options defined by this parser, and returns the result.
-  ArgResults parse(List<String> args) =>
-      Parser(null, this, args.toList()).parse();
-
-  /// Generates a string displaying usage information for the defined options.
-  /// This is basically the help text shown on the command line.
-  String getUsage() => Usage(this).generate();
-
-  /// Get the default value for an option. Useful after parsing to test
-  /// if the user specified something other than the default.
-  dynamic getDefault(String option) {
-    if (!options.containsKey(option)) {
-      throw ArgumentError('No option named $option');
-    }
-    return options[option].defaultValue;
-  }
-
-  /// Finds the option whose abbreviation is [abbr], or `null` if no option has
-  /// that abbreviation.
-  Option findByAbbreviation(String abbr) {
-    return options.values.firstWhere((option) => option.abbreviation == abbr,
-        orElse: () => null);
-  }
-}
-
-/// A command-line option. Includes both flags and options which take a value.
-class Option {
-  final String name;
-  final String abbreviation;
-  final List allowed;
-  final dynamic defaultValue;
-  final Function callback;
-  final String help;
-  final Map<String, String> allowedHelp;
-  final bool isFlag;
-  final bool negatable;
-  final bool allowMultiple;
-
-  Option(this.name, this.abbreviation, this.help, this.allowed,
-      this.allowedHelp, this.defaultValue, this.callback,
-      {this.isFlag, this.negatable, this.allowMultiple = false});
-}
-
-/// The results of parsing a series of command line arguments using
-/// [ArgParser.parse()]. Includes the parsed options and any remaining unparsed
-/// command line arguments.
-class ArgResults {
-  final Map<String, dynamic> _options;
-
-  /// If these are the results for parsing a command's options, this will be
-  /// the name of the command. For top-level results, this returns `null`.
-  final String name;
-
-  /// The command that was selected, or `null` if none was. This will contain
-  /// the options that were selected for that command.
-  final ArgResults command;
-
-  /// The remaining command-line arguments that were not parsed as options or
-  /// flags. If `--` was used to separate the options from the remaining
-  /// arguments, it will not be included in this list.
-  final List<String> rest;
-
-  /// Creates a new [ArgResults].
-  ArgResults(this._options, this.name, this.command, this.rest);
-
-  /// Gets the parsed command-line option named [name].
-  dynamic operator [](String name) {
-    if (!_options.containsKey(name)) {
-      throw ArgumentError('Could not find an option named "$name".');
-    }
-
-    return _options[name];
-  }
-
-  List<String> get options => _options.keys.toList();
-}
diff --git a/pkg/test_runner/lib/src/vendored_pkg/args/src/parser.dart b/pkg/test_runner/lib/src/vendored_pkg/args/src/parser.dart
deleted file mode 100644
index 990dbf7..0000000
--- a/pkg/test_runner/lib/src/vendored_pkg/args/src/parser.dart
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library args.src.parser;
-
-import '../args.dart';
-
-final _SOLO_OPT = RegExp(r'^-([a-zA-Z0-9])$');
-final _ABBR_OPT = RegExp(r'^-([a-zA-Z0-9]+)(.*)$');
-final _LONG_OPT = RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$');
-
-/// The actual parsing class. Unlike [ArgParser] which is really more an "arg
-/// grammar", this is the class that does the parsing and holds the mutable
-/// state required during a parse.
-class Parser {
-  /// If parser is parsing a command's options, this will be the name of the
-  /// command. For top-level results, this returns `null`.
-  final String commandName;
-
-  /// The parser for the supercommand of this command parser, or `null` if this
-  /// is the top-level parser.
-  final Parser parent;
-
-  /// The grammar being parsed.
-  final ArgParser grammar;
-
-  /// The arguments being parsed.
-  final List<String> args;
-
-  /// The accumulated parsed options.
-  final Map<String, dynamic> results = {};
-
-  Parser(this.commandName, this.grammar, this.args, [this.parent]);
-
-  /// The current argument being parsed.
-  String get current => args[0];
-
-  /// Parses the arguments. This can only be called once.
-  ArgResults parse() {
-    ArgResults commandResults;
-
-    // Initialize flags to their defaults.
-    grammar.options.forEach((name, option) {
-      if (option.allowMultiple) {
-        results[name] = [];
-      } else {
-        results[name] = option.defaultValue;
-      }
-    });
-
-    // Parse the args.
-    while (args.isNotEmpty) {
-      if (current == '--') {
-        // Reached the argument terminator, so stop here.
-        args.removeAt(0);
-        break;
-      }
-
-      // Try to parse the current argument as a command. This happens before
-      // options so that commands can have option-like names.
-      var command = grammar.commands[current];
-      if (command != null) {
-        var commandName = args.removeAt(0);
-        var commandParser = Parser(commandName, command, args, this);
-        commandResults = commandParser.parse();
-        continue;
-      }
-
-      // Try to parse the current argument as an option. Note that the order
-      // here matters.
-      if (parseSoloOption()) continue;
-      if (parseAbbreviation(this)) continue;
-      if (parseLongOption()) continue;
-
-      // If we got here, the argument doesn't look like an option, so stop.
-      break;
-    }
-
-    // Set unspecified multivalued arguments to their default value,
-    // if any, and invoke the callbacks.
-    grammar.options.forEach((name, option) {
-      if (option.allowMultiple &&
-          results[name].length == 0 &&
-          option.defaultValue != null) {
-        results[name].add(option.defaultValue);
-      }
-      if (option.callback != null) option.callback(results[name]);
-    });
-
-    // Add in the leftover arguments we didn't parse to the innermost command.
-    var rest = args.toList();
-    args.clear();
-    return ArgResults(results, commandName, commandResults, rest);
-  }
-
-  /// Pulls the value for [option] from the second argument in [args]. Validates
-  /// that there is a valid value there.
-  void readNextArgAsValue(Option option) {
-    // Take the option argument from the next command line arg.
-    validate(args.isNotEmpty, 'Missing argument for "${option.name}".');
-
-    // Make sure it isn't an option itself.
-    validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current),
-        'Missing argument for "${option.name}".');
-
-    setOption(results, option, current);
-    args.removeAt(0);
-  }
-
-  /// Tries to parse the current argument as a "solo" option, which is a single
-  /// hyphen followed by a single letter. We treat this differently than
-  /// collapsed abbreviations (like "-abc") to handle the possible value that
-  /// may follow it.
-  bool parseSoloOption() {
-    var soloOpt = _SOLO_OPT.firstMatch(current);
-    if (soloOpt == null) return false;
-
-    var option = grammar.findByAbbreviation(soloOpt[1]);
-    if (option == null) {
-      // Walk up to the parent command if possible.
-      validate(
-          parent != null, 'Could not find an option or flag "-${soloOpt[1]}".');
-      return parent.parseSoloOption();
-    }
-
-    args.removeAt(0);
-
-    if (option.isFlag) {
-      setOption(results, option, true);
-    } else {
-      readNextArgAsValue(option);
-    }
-
-    return true;
-  }
-
-  /// Tries to parse the current argument as a series of collapsed abbreviations
-  /// (like "-abc") or a single abbreviation with the value directly attached
-  /// to it (like "-mrelease").
-  bool parseAbbreviation(Parser innermostCommand) {
-    var abbrOpt = _ABBR_OPT.firstMatch(current);
-    if (abbrOpt == null) return false;
-
-    // If the first character is the abbreviation for a non-flag option, then
-    // the rest is the value.
-    var c = abbrOpt[1].substring(0, 1);
-    var first = grammar.findByAbbreviation(c);
-    if (first == null) {
-      // Walk up to the parent command if possible.
-      validate(
-          parent != null, 'Could not find an option with short name "-$c".');
-      return parent.parseAbbreviation(innermostCommand);
-    } else if (!first.isFlag) {
-      // The first character is a non-flag option, so the rest must be the
-      // value.
-      var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}';
-      setOption(results, first, value);
-    } else {
-      // If we got some non-flag characters, then it must be a value, but
-      // if we got here, it's a flag, which is wrong.
-      validate(
-          abbrOpt[2] == '',
-          'Option "-$c" is a flag and cannot handle value '
-          '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".');
-
-      // Not an option, so all characters should be flags.
-      // We use "innermostCommand" here so that if a parent command parses the
-      // *first* letter, subcommands can still be found to parse the other
-      // letters.
-      for (var i = 0; i < abbrOpt[1].length; i++) {
-        var c = abbrOpt[1].substring(i, i + 1);
-        innermostCommand.parseShortFlag(c);
-      }
-    }
-
-    args.removeAt(0);
-    return true;
-  }
-
-  void parseShortFlag(String c) {
-    var option = grammar.findByAbbreviation(c);
-    if (option == null) {
-      // Walk up to the parent command if possible.
-      validate(
-          parent != null, 'Could not find an option with short name "-$c".');
-      parent.parseShortFlag(c);
-      return;
-    }
-
-    // In a list of short options, only the first can be a non-flag. If
-    // we get here we've checked that already.
-    validate(
-        option.isFlag, 'Option "-$c" must be a flag to be in a collapsed "-".');
-
-    setOption(results, option, true);
-  }
-
-  /// Tries to parse the current argument as a long-form named option, which
-  /// may include a value like "--mode=release" or "--mode release".
-  bool parseLongOption() {
-    var longOpt = _LONG_OPT.firstMatch(current);
-    if (longOpt == null) return false;
-
-    var name = longOpt[1];
-    var option = grammar.options[name];
-    if (option != null) {
-      args.removeAt(0);
-      if (option.isFlag) {
-        validate(longOpt[3] == null,
-            'Flag option "$name" should not be given a value.');
-
-        setOption(results, option, true);
-      } else if (longOpt[3] != null) {
-        // We have a value like --foo=bar.
-        setOption(results, option, longOpt[3]);
-      } else {
-        // Option like --foo, so look for the value as the next arg.
-        readNextArgAsValue(option);
-      }
-    } else if (name.startsWith('no-')) {
-      // See if it's a negated flag.
-      name = name.substring('no-'.length);
-      option = grammar.options[name];
-      if (option == null) {
-        // Walk up to the parent command if possible.
-        validate(parent != null, 'Could not find an option named "$name".');
-        return parent.parseLongOption();
-      }
-
-      args.removeAt(0);
-      validate(option.isFlag, 'Cannot negate non-flag option "$name".');
-      validate(option.negatable, 'Cannot negate option "$name".');
-
-      setOption(results, option, false);
-    } else {
-      // Walk up to the parent command if possible.
-      validate(parent != null, 'Could not find an option named "$name".');
-      return parent.parseLongOption();
-    }
-
-    return true;
-  }
-
-  /// Called during parsing to validate the arguments. Throws a
-  /// [FormatException] if [condition] is `false`.
-  void validate(bool condition, String message) {
-    if (!condition) throw FormatException(message);
-  }
-
-  /// Validates and stores [value] as the value for [option].
-  void setOption(Map results, Option option, dynamic value) {
-    // See if it's one of the allowed values.
-    if (option.allowed != null) {
-      validate(option.allowed.any((allow) => allow == value),
-          '"$value" is not an allowed value for option "${option.name}".');
-    }
-
-    if (option.allowMultiple) {
-      results[option.name].add(value);
-    } else {
-      results[option.name] = value;
-    }
-  }
-}
diff --git a/pkg/test_runner/lib/src/vendored_pkg/args/src/usage.dart b/pkg/test_runner/lib/src/vendored_pkg/args/src/usage.dart
deleted file mode 100644
index 60d4a9e..0000000
--- a/pkg/test_runner/lib/src/vendored_pkg/args/src/usage.dart
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library args.src.usage;
-
-import 'dart:math';
-
-import '../args.dart';
-
-/// Takes an [ArgParser] and generates a string of usage (i.e. help) text for its
-/// defined options. Internally, it works like a tabular printer. The output is
-/// divided into three horizontal columns, like so:
-///
-///     -h, --help  Prints the usage information
-///     |  |        |                                 |
-///
-/// It builds the usage text up one column at a time and handles padding with
-/// spaces and wrapping to the next line to keep the cells correctly lined up.
-class Usage {
-  static const numColumns = 3; // Abbreviation, long name, help.
-
-  /// The parser this is generating usage for.
-  final ArgParser args;
-
-  /// The working buffer for the generated usage text.
-  StringBuffer buffer;
-
-  /// The column that the "cursor" is currently on. If the next call to
-  /// [write()] is not for this column, it will correctly handle advancing to
-  /// the next column (and possibly the next row).
-  int currentColumn = 0;
-
-  /// The width in characters of each column.
-  List<int> columnWidths;
-
-  /// The number of sequential lines of text that have been written to the last
-  /// column (which shows help info). We track this so that help text that spans
-  /// multiple lines can be padded with a blank line after it for separation.
-  /// Meanwhile, sequential options with single-line help will be compacted next
-  /// to each other.
-  int numHelpLines = 0;
-
-  /// How many newlines need to be rendered before the next bit of text can be
-  /// written. We do this lazily so that the last bit of usage doesn't have
-  /// dangling newlines. We only write newlines right *before* we write some
-  /// real content.
-  int newlinesNeeded = 0;
-
-  Usage(this.args);
-
-  /// Generates a string displaying usage information for the defined options.
-  /// This is basically the help text shown on the command line.
-  String generate() {
-    buffer = StringBuffer();
-
-    calculateColumnWidths();
-
-    args.options.forEach((name, option) {
-      write(0, getAbbreviation(option));
-      write(1, getLongOption(option));
-
-      if (option.help != null) write(2, option.help);
-
-      if (option.allowedHelp != null) {
-        var allowedNames = option.allowedHelp.keys.toList();
-        allowedNames.sort();
-        newline();
-        for (var name in allowedNames) {
-          write(1, getAllowedTitle(name));
-          write(2, option.allowedHelp[name]);
-        }
-        newline();
-      } else if (option.allowed != null) {
-        write(2, buildAllowedList(option));
-      } else if (option.defaultValue != null) {
-        if (option.isFlag && option.defaultValue == true) {
-          write(2, '(defaults to on)');
-        } else if (!option.isFlag) {
-          write(2, '(defaults to "${option.defaultValue}")');
-        }
-      }
-
-      // If any given option displays more than one line of text on the right
-      // column (i.e. help, default value, allowed options, etc.) then put a
-      // blank line after it. This gives space where it's useful while still
-      // keeping simple one-line options clumped together.
-      if (numHelpLines > 1) newline();
-    });
-
-    return buffer.toString();
-  }
-
-  String getAbbreviation(Option option) {
-    if (option.abbreviation != null) {
-      return '-${option.abbreviation}, ';
-    } else {
-      return '';
-    }
-  }
-
-  String getLongOption(Option option) {
-    if (option.negatable) {
-      return '--[no-]${option.name}';
-    } else {
-      return '--${option.name}';
-    }
-  }
-
-  String getAllowedTitle(String allowed) {
-    return '      [$allowed]';
-  }
-
-  void calculateColumnWidths() {
-    var abbr = 0;
-    var title = 0;
-    args.options.forEach((name, option) {
-      // Make room in the first column if there are abbreviations.
-      abbr = max(abbr, getAbbreviation(option).length);
-
-      // Make room for the option.
-      title = max(title, getLongOption(option).length);
-
-      // Make room for the allowed help.
-      if (option.allowedHelp != null) {
-        for (var allowed in option.allowedHelp.keys) {
-          title = max(title, getAllowedTitle(allowed).length);
-        }
-      }
-    });
-
-    // Leave a gutter between the columns.
-    title += 4;
-    columnWidths = [abbr, title];
-  }
-
-  void newline() {
-    newlinesNeeded++;
-    currentColumn = 0;
-    numHelpLines = 0;
-  }
-
-  void write(int column, String text) {
-    var lines = text.split('\n');
-
-    // Strip leading and trailing empty lines.
-    while (lines.isNotEmpty && lines[0].trim() == '') {
-      lines.removeRange(0, 1);
-    }
-
-    while (lines.isNotEmpty && lines[lines.length - 1].trim() == '') {
-      lines.removeLast();
-    }
-
-    for (var line in lines) {
-      writeLine(column, line);
-    }
-  }
-
-  void writeLine(int column, String text) {
-    // Write any pending newlines.
-    while (newlinesNeeded > 0) {
-      buffer.writeln('');
-      newlinesNeeded--;
-    }
-
-    // Advance until we are at the right column (which may mean wrapping around
-    // to the next line.
-    while (currentColumn != column) {
-      if (currentColumn < numColumns - 1) {
-        buffer.write(padRight('', columnWidths[currentColumn]));
-      } else {
-        buffer.writeln('');
-      }
-      currentColumn = (currentColumn + 1) % numColumns;
-    }
-
-    if (column < columnWidths.length) {
-      // Fixed-size column, so pad it.
-      buffer.write(padRight(text, columnWidths[column]));
-    } else {
-      // The last column, so just write it.
-      buffer.write(text);
-    }
-
-    // Advance to the next column.
-    currentColumn = (currentColumn + 1) % numColumns;
-
-    // If we reached the last column, we need to wrap to the next line.
-    if (column == numColumns - 1) newlinesNeeded++;
-
-    // Keep track of how many consecutive lines we've written in the last
-    // column.
-    if (column == numColumns - 1) {
-      numHelpLines++;
-    } else {
-      numHelpLines = 0;
-    }
-  }
-
-  String buildAllowedList(Option option) {
-    var allowedBuffer = StringBuffer();
-    allowedBuffer.write('[');
-    var first = true;
-    for (var allowed in option.allowed) {
-      if (!first) allowedBuffer.write(', ');
-      allowedBuffer.write(allowed);
-      if (allowed == option.defaultValue) {
-        allowedBuffer.write(' (default)');
-      }
-      first = false;
-    }
-    allowedBuffer.write(']');
-    return allowedBuffer.toString();
-  }
-}
-
-/// Pads [source] to [length] by adding spaces at the end.
-String padRight(String source, int length) {
-  var result = StringBuffer();
-  result.write(source);
-
-  while (result.length < length) {
-    result.write(' ');
-  }
-
-  return result.toString();
-}
diff --git a/pkg/test_runner/tool/convert_multitest.dart b/pkg/test_runner/tool/convert_multitest.dart
index 0647876..0bc1a3a 100644
--- a/pkg/test_runner/tool/convert_multitest.dart
+++ b/pkg/test_runner/tool/convert_multitest.dart
@@ -10,13 +10,13 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:args/args.dart';
 import 'package:path/path.dart';
 import 'package:test_runner/src/multitest.dart';
 import 'package:test_runner/src/path.dart';
 import 'package:test_runner/src/static_error.dart';
 import 'package:test_runner/src/test_file.dart';
 import 'package:test_runner/src/update_errors.dart';
-import 'package:test_runner/src/vendored_pkg/args/args.dart';
 
 import 'update_static_error_tests.dart' show runAnalyzer, runCfe;
 
@@ -247,13 +247,13 @@
   var parser = ArgParser();
   parser.addFlag("verbose", abbr: "v", help: "print additional information");
   parser.addFlag("write", abbr: "w", help: "write output to input file");
-  parser.addOption("enable-experiment",
-      help: "Enable one or more experimental features", allowMultiple: true);
+  parser.addMultiOption("enable-experiment",
+      help: "Enable one or more experimental features");
 
   var results = parser.parse(arguments);
   if (results.rest.isEmpty) {
     print("Usage: convert_multi_test.dart [-v] [-w] <input files>");
-    print(parser.getUsage());
+    print(parser.usage);
     exitCode = 1;
     return;
   }
diff --git a/pkg/vm/testcases/transformations/ffi/finalizable_late.dart b/pkg/vm/testcases/transformations/ffi/finalizable_late.dart
new file mode 100644
index 0000000..048ae94
--- /dev/null
+++ b/pkg/vm/testcases/transformations/ffi/finalizable_late.dart
@@ -0,0 +1,17 @@
+// 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.
+
+// @dart=2.16
+
+import 'dart:ffi';
+
+class Foo implements Finalizable {}
+
+void main() {
+  late Foo foo;
+  // Generates a reachability fence between the constructor call and assignment.
+  // That reachability fence should not trigger a late initialization error.
+  foo = Foo();
+  print(foo);
+}
diff --git a/pkg/vm/testcases/transformations/ffi/finalizable_late.dart.expect b/pkg/vm/testcases/transformations/ffi/finalizable_late.dart.expect
new file mode 100644
index 0000000..45321de
--- /dev/null
+++ b/pkg/vm/testcases/transformations/ffi/finalizable_late.dart.expect
@@ -0,0 +1,22 @@
+library #lib /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:ffi" as ffi;
+import "dart:_internal" as _in;
+
+import "dart:ffi";
+
+class Foo extends core::Object implements ffi::Finalizable {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+static method main() → void {
+  late self::Foo foo;
+  foo = block {
+    final self::Foo :expressionValueWrappedFinalizable = new self::Foo::•();
+    _in::reachabilityFence(foo);
+  } =>:expressionValueWrappedFinalizable;
+  core::print(foo);
+  _in::reachabilityFence(foo);
+}
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 6bbd861..abfc8a7 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -2095,28 +2095,35 @@
   return Fragment();
 }
 
-Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) {
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(
+    TokenPosition* position,
+    bool allow_late_uninitialized) {
   const TokenPosition pos = ReadPosition();
   if (position != nullptr) *position = pos;
   intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
   ReadUInt();              // read relative variable index.
   SkipOptionalDartType();  // read promoted type.
-  return BuildVariableGetImpl(variable_kernel_position, pos);
+  return BuildVariableGetImpl(variable_kernel_position, pos,
+                              allow_late_uninitialized);
 }
 
-Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload,
-                                                     TokenPosition* position) {
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(
+    uint8_t payload,
+    TokenPosition* position,
+    bool allow_late_uninitialized) {
   const TokenPosition pos = ReadPosition();
   if (position != nullptr) *position = pos;
   intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
-  return BuildVariableGetImpl(variable_kernel_position, pos);
+  return BuildVariableGetImpl(variable_kernel_position, pos,
+                              allow_late_uninitialized);
 }
 
 Fragment StreamingFlowGraphBuilder::BuildVariableGetImpl(
     intptr_t variable_kernel_position,
-    TokenPosition position) {
+    TokenPosition position,
+    bool allow_late_uninitialized) {
   LocalVariable* variable = LookupVariable(variable_kernel_position);
-  if (!variable->is_late()) {
+  if (!variable->is_late() || allow_late_uninitialized) {
     return LoadLocal(variable);
   }
 
@@ -3479,6 +3486,8 @@
   switch (recognized_kind) {
     case MethodRecognizer::kNativeEffect:
       return BuildNativeEffect();
+    case MethodRecognizer::kReachabilityFence:
+      return BuildReachabilityFence();
     case MethodRecognizer::kFfiAsFunctionInternal:
       return BuildFfiAsFunctionInternal();
     case MethodRecognizer::kFfiNativeCallbackFunction:
@@ -5722,6 +5731,45 @@
   return code;
 }
 
+Fragment StreamingFlowGraphBuilder::BuildReachabilityFence() {
+  const intptr_t argc = ReadUInt();               // Read argument count.
+  ASSERT(argc == 1);                              // LoadField, can be late.
+  const intptr_t list_length = ReadListLength();  // Read types list length.
+  ASSERT(list_length == 0);
+
+  const intptr_t positional_count = ReadListLength();
+  ASSERT(positional_count == 1);
+
+  // The CFE transform only generates a subset of argument expressions:
+  // either variable get or `this`.
+  uint8_t payload = 0;
+  Tag tag = ReadTag(&payload);
+  TokenPosition* position = nullptr;
+  const bool allow_late_uninitialized = true;
+  Fragment code;
+  switch (tag) {
+    case kVariableGet:
+      code = BuildVariableGet(position, allow_late_uninitialized);
+      break;
+    case kSpecializedVariableGet:
+      code = BuildVariableGet(payload, position, allow_late_uninitialized);
+      break;
+    case kThisExpression:
+      code = BuildThisExpression(position);
+      break;
+    default:
+      // The transformation should not be generating anything else.
+      FATAL1("Unexpected tag %i", tag);
+  }
+
+  const intptr_t named_args_len = ReadListLength();
+  ASSERT(named_args_len == 0);
+
+  code <<= new (Z) ReachabilityFenceInstr(Pop());
+  code += NullConstant();  // Return type is void.
+  return code;
+}
+
 static void ReportIfNotNull(const char* error) {
   if (error != nullptr) {
     const auto& language_error = Error::Handle(
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index cd5ccb6..4547f0e 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -274,10 +274,14 @@
   Fragment BuildArgumentsFromActualArguments(Array* argument_names);
 
   Fragment BuildInvalidExpression(TokenPosition* position);
-  Fragment BuildVariableGet(TokenPosition* position);
-  Fragment BuildVariableGet(uint8_t payload, TokenPosition* position);
+  Fragment BuildVariableGet(TokenPosition* position,
+                            bool allow_late_uninitialized = false);
+  Fragment BuildVariableGet(uint8_t payload,
+                            TokenPosition* position,
+                            bool allow_late_uninitialized = false);
   Fragment BuildVariableGetImpl(intptr_t variable_kernel_position,
-                                TokenPosition position);
+                                TokenPosition position,
+                                bool allow_late_uninitialized = false);
   Fragment BuildVariableSet(TokenPosition* position);
   Fragment BuildVariableSet(uint8_t payload, TokenPosition* position);
   Fragment BuildVariableSetImpl(TokenPosition position,
@@ -368,6 +372,10 @@
   // Build flow graph for '_nativeEffect'.
   Fragment BuildNativeEffect();
 
+  // Build the call-site manually, to avoid doing initialization checks
+  // for late fields.
+  Fragment BuildReachabilityFence();
+
   // Build flow graph for '_loadAbiSpecificInt' and
   // '_loadAbiSpecificIntAtIndex', '_storeAbiSpecificInt', and
   // '_storeAbiSpecificIntAtIndex' call sites.
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index d516d3f..fe6b416 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -955,7 +955,6 @@
     case MethodRecognizer::kCopyRangeFromUint8ListToOneByteString:
     case MethodRecognizer::kImmutableLinkedHashBase_setIndexStoreRelease:
     case MethodRecognizer::kFfiAbi:
-    case MethodRecognizer::kReachabilityFence:
     case MethodRecognizer::kUtf8DecoderScan:
     case MethodRecognizer::kHas63BitSmis:
     case MethodRecognizer::kExtensionStreamHasListener:
@@ -1293,12 +1292,6 @@
       body += Utf8Scan();
       body += Box(kUnboxedIntPtr);
       break;
-    case MethodRecognizer::kReachabilityFence:
-      ASSERT_EQUAL(function.NumParameters(), 1);
-      body += LoadLocal(parsed_function_->RawParameterVariable(0));
-      body += ReachabilityFence();
-      body += NullConstant();
-      break;
     case MethodRecognizer::kFfiAbi:
       ASSERT_EQUAL(function.NumParameters(), 0);
       body += IntConstant(static_cast<int64_t>(compiler::ffi::TargetAbi()));
diff --git a/tests/language/vm/regress_49005_test.dart b/tests/language/vm/regress_49005_test.dart
new file mode 100644
index 0000000..619aa12
--- /dev/null
+++ b/tests/language/vm/regress_49005_test.dart
@@ -0,0 +1,13 @@
+// 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:ffi';
+
+class Foo implements Finalizable {}
+
+void main() {
+  late Foo foo;
+  foo = Foo();
+  print(foo);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 7d7058c..b892b81 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 112
+PRERELEASE 113
 PRERELEASE_PATCH 0
\ No newline at end of file