[roll] Update third-party dart packages

Roller-URL: https://ci.chromium.org/b/8863799278408418976
Cq-Cl-Tag: roller-builder:flutter-with-deps-roller
Cq-Cl-Tag: roller-bid:8863799278408418976
CQ-Do-Not-Cancel-Tryjobs: true
Change-Id: I6a7231f3af06b002f5049aadcaa4bc7bf47b0afd
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/dart-pkg/+/449982
Reviewed-by: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
Commit-Queue: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/package_config.json b/package_config.json
index cb7a34b..180af4d 100644
--- a/package_config.json
+++ b/package_config.json
@@ -591,7 +591,7 @@
       "rootUri": "./source_maps/"
     }, 
     {
-      "languageVersion": "2.11", 
+      "languageVersion": "2.12", 
       "name": "source_span", 
       "packageUri": "lib/", 
       "rootUri": "./source_span/"
diff --git a/protoc_plugin/BUILD.gn b/protoc_plugin/BUILD.gn
index ddbc3cc..cb19022 100644
--- a/protoc_plugin/BUILD.gn
+++ b/protoc_plugin/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for protoc_plugin-19.1.0
+# This file is generated by importer.py for protoc_plugin-19.2.0+1
 
 import("//build/dart/dart_library.gni")
 
diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md
index ce5e25e..c5a0df6 100644
--- a/protoc_plugin/CHANGELOG.md
+++ b/protoc_plugin/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 19.2.0+1
+
+* Fix syntax error introduced by gRPC client interceptor changes.
+
+## 19.2.0
+
+* Support client interceptors for gRPC. Requires grpc package 2.8.0 or newer.
+
 ## 19.1.0
 
 * Emit depreciation of generated `copyWith` and `clone` methods.
diff --git a/protoc_plugin/lib/file_generator.dart b/protoc_plugin/lib/file_generator.dart
index 069907f..f3fe706 100644
--- a/protoc_plugin/lib/file_generator.dart
+++ b/protoc_plugin/lib/file_generator.dart
@@ -406,7 +406,7 @@
     if (enumCount > 0) {
       // Make sure any other symbols in dart:core don't cause name conflicts
       // with enums that have the same name.
-      out.println("// ignore_for_file: UNDEFINED_SHOWN_NAME,UNUSED_SHOWN_NAME");
+      out.println("// ignore_for_file: UNDEFINED_SHOWN_NAME");
       out.println(_coreImport);
       out.println(_protobufImport);
       out.println();
diff --git a/protoc_plugin/lib/grpc_generator.dart b/protoc_plugin/lib/grpc_generator.dart
index b8dc11c..1d67d72 100644
--- a/protoc_plugin/lib/grpc_generator.dart
+++ b/protoc_plugin/lib/grpc_generator.dart
@@ -111,9 +111,12 @@
         method.generateClientMethodDescriptor(out);
       }
       out.println();
+      out.println('$_clientClassname($_clientChannel channel,');
+      out.println('    {$_callOptions options,');
       out.println(
-          '$_clientClassname($_clientChannel channel, {$_callOptions options})');
-      out.println('    : super(channel, options: options);');
+          '    $_coreImportPrefix.Iterable<$_interceptor> interceptors})');
+      out.println('    : super(channel, options: options,');
+      out.println('      interceptors: interceptors);');
       for (final method in _methods) {
         method.generateClientStub(out);
       }
@@ -142,6 +145,7 @@
   }
 
   static final String _callOptions = '$_grpcImportPrefix.CallOptions';
+  static final String _interceptor = '$_grpcImportPrefix.ClientInterceptor';
   static final String _client = '$_grpcImportPrefix.Client';
   static final String _clientChannel = '$_grpcImportPrefix.ClientChannel';
   static final String _service = '$_grpcImportPrefix.Service';
@@ -224,14 +228,18 @@
     out.addBlock(
         '$_clientReturnType $_dartName($_argumentType request, {${GrpcServiceGenerator._callOptions} options}) {',
         '}', () {
-      final requestStream =
-          _clientStreaming ? 'request' : '$_stream.fromIterable([request])';
-      out.println(
-          'final call = \$createCall(_\$$_dartName, $requestStream, options: options);');
-      if (_serverStreaming) {
-        out.println('return $_responseStream(call);');
+      if (_clientStreaming && _serverStreaming) {
+        out.println(
+            'return \$createStreamingCall(_\$$_dartName, request, options: options);');
+      } else if (_clientStreaming && !_serverStreaming) {
+        out.println(
+            'return \$createStreamingCall(_\$$_dartName, request, options: options).single;');
+      } else if (!_clientStreaming && _serverStreaming) {
+        out.println(
+            'return \$createStreamingCall(_\$$_dartName, $_stream.fromIterable([request]), options: options);');
       } else {
-        out.println('return $_responseFuture(call);');
+        out.println(
+            'return \$createUnaryCall(_\$$_dartName, request, options: options);');
       }
     });
   }
diff --git a/protoc_plugin/lib/src/descriptor.pbenum.dart b/protoc_plugin/lib/src/descriptor.pbenum.dart
index 08b35b1..5dc79eb 100644
--- a/protoc_plugin/lib/src/descriptor.pbenum.dart
+++ b/protoc_plugin/lib/src/descriptor.pbenum.dart
@@ -5,7 +5,7 @@
 // @dart = 2.3
 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
 
-// ignore_for_file: UNDEFINED_SHOWN_NAME,UNUSED_SHOWN_NAME
+// ignore_for_file: UNDEFINED_SHOWN_NAME
 import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml
index 676874b..a72497d 100644
--- a/protoc_plugin/pubspec.yaml
+++ b/protoc_plugin/pubspec.yaml
@@ -1,5 +1,5 @@
 name: protoc_plugin
-version: 19.1.0
+version: 19.2.0+1
 description: Protoc compiler plugin to generate Dart code
 homepage: https://github.com/dart-lang/protobuf
 
diff --git a/quiver/.gitignore b/quiver/.gitignore
index 497436f..d412bb1 100644
--- a/quiver/.gitignore
+++ b/quiver/.gitignore
@@ -14,3 +14,4 @@
 
 # Temp files
 *~
+*.sw?
diff --git a/quiver/BUILD.gn b/quiver/BUILD.gn
index 2690fe1..12c9d19 100644
--- a/quiver/BUILD.gn
+++ b/quiver/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for quiver-2.1.4+1
+# This file is generated by importer.py for quiver-2.1.5
 
 import("//build/dart/dart_library.gni")
 
diff --git a/quiver/CHANGELOG.md b/quiver/CHANGELOG.md
index ef2aefc..e4bb88d 100644
--- a/quiver/CHANGELOG.md
+++ b/quiver/CHANGELOG.md
@@ -1,3 +1,10 @@
+#### 2.1.5 - 2020-11-05
+
+  * Deprecate `forEachAsync`, `reduceAsync`. Existing callers should
+    migrate to `Future.forEach`. Migration examples have been added to
+    the documentation for these methods. This will be removed in Quiver
+    3.0.0.
+
 #### 2.1.4+1 - 2020-10-26
 
   * Fix: Add dart:async import to async/string.dart. Stream wasn't
diff --git a/quiver/lib/src/async/iteration.dart b/quiver/lib/src/async/iteration.dart
index 601eee0..250ca0c 100644
--- a/quiver/lib/src/async/iteration.dart
+++ b/quiver/lib/src/async/iteration.dart
@@ -18,7 +18,7 @@
 typedef AsyncAction<T, E> = Future<T> Function(E e);
 
 /// An asynchronous funcuntion that combines an element [e] with a previous
-/// value [previous], for use with [reduceAsync].
+/// value [previous].
 typedef AsyncCombiner<T, E> = Future<T> Function(T previous, E e);
 
 /// Calls [action] for each item in [iterable] in turn, waiting for the Future
@@ -28,6 +28,25 @@
 ///
 /// The Future returned completes to [true] if the entire iterable was
 /// processed, otherwise [false].
+///
+/// This is deprecated and will be removed in Quiver 3.0.0. It can be replaced
+/// by [Future.doWhile]. For example:
+///
+///     List<int> myList = ...
+///     await doWhileAsync(myList, (int i) {
+///       return i != 5;
+///     });
+///
+/// can be replaced by the following code:
+///
+///     List<int> myList = ...
+///     Iterator<int> it = myList.iterator;
+///     await Future.doWhile(() {
+///       if (it.moveNext()) {
+///         return it.current != 5;
+///       }
+///       return false;
+///     });
 @Deprecated('Use Future.doWhile from dart:async. Will be removed in 3.0.0.')
 Future<bool> doWhileAsync<T>(
         Iterable<T> iterable, AsyncAction<bool, T> action) =>
@@ -47,6 +66,23 @@
 /// the collection using the provided [combine] function. Similar to
 /// [Iterable.reduce], except that [combine] is an async function that returns
 /// a [Future].
+///
+/// This is deprecated and will be removed in Quiver 3.0.0. It can be replaced
+/// with [Future.forEach] as follows:
+///
+///     List<int> myList = ...
+///     int sum = await reduceAsync(myList, 0, (int a, int b) {
+///       return a + b;
+///     });
+///
+/// can be replaced by the following code:
+///
+///     List<int> myList = ...
+///     int sum = 0;
+///     await Future.forEach(myList, (int i) {
+///       sum += i;
+///     });
+@Deprecated('Use Future.doWhile from dart:async. Will be removed in 3.0.0.')
 Future<S> reduceAsync<S, T>(
         Iterable<T> iterable, S initialValue, AsyncCombiner<S, T> combine) =>
     _reduceAsync(iterable.iterator, initialValue, combine);
@@ -62,6 +98,26 @@
 
 /// Schedules calls to [action] for each element in [iterable]. No more than
 /// [maxTasks] calls to [action] will be pending at once.
+///
+/// This is deprecated and will be removed in Quiver 3.0.0. When the [maxTasks]
+/// argument is left defaulted, it can be replaced with [Future.forEach] as
+/// follows:
+///
+///     List<int> myList = ...
+///     await forEachAsync(myList, (int i) {
+///       // do something
+///     });
+///
+/// can be replaced by the following code:
+///
+///     List<int> myList = ...
+///     await Future.forEach(myList, (int i) {
+///       // do something
+///     });
+///
+/// In cases where [maxTasks] is specified, package:pool is recommended.
+/// See: https://pub.dev/packages/pool
+@Deprecated('Use Future.forEach or package:pool. Will be removed in 3.0.0.')
 Future<Null> forEachAsync<T>(Iterable<T> iterable, AsyncAction<Null, T> action,
     {int maxTasks = 1}) {
   if (maxTasks == null || maxTasks < 1) {
diff --git a/quiver/pubspec.yaml b/quiver/pubspec.yaml
index a38670c..378fd0e 100644
--- a/quiver/pubspec.yaml
+++ b/quiver/pubspec.yaml
@@ -3,7 +3,7 @@
   Quiver is a set of utility libraries for Dart that makes using many Dart
   libraries easier and more convenient, or adds additional functionality.
 homepage: https://github.com/google/quiver-dart
-version: 2.1.4+1
+version: 2.1.5
 environment:
   sdk: '>=2.0.0-dev.61 <3.0.0'
 dependencies:
diff --git a/source_span/BUILD.gn b/source_span/BUILD.gn
index b7bdcf4..2e723f0 100644
--- a/source_span/BUILD.gn
+++ b/source_span/BUILD.gn
@@ -1,11 +1,11 @@
-# This file is generated by importer.py for source_span-1.8.0-nullsafety.3
+# This file is generated by importer.py for source_span-1.8.0-nullsafety.4
 
 import("//build/dart/dart_library.gni")
 
 dart_library("source_span") {
   package_name = "source_span"
 
-  language_version = "2.11"
+  language_version = "2.12"
 
   disable_analysis = true
 
diff --git a/source_span/CHANGELOG.md b/source_span/CHANGELOG.md
index de8e4ca..2c81256 100644
--- a/source_span/CHANGELOG.md
+++ b/source_span/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 1.8.0-nullsafety.4
+
+* Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release
+  guidelines.
+
 # 1.8.0-nullsafety.3
 
 * Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is
diff --git a/source_span/pubspec.yaml b/source_span/pubspec.yaml
index 2932d11..a5db06e 100644
--- a/source_span/pubspec.yaml
+++ b/source_span/pubspec.yaml
@@ -1,12 +1,11 @@
 name: source_span
-version: 1.8.0-nullsafety.3
+version: 1.8.0-nullsafety.4
 
 description: A library for identifying source spans and locations.
 homepage: https://github.com/dart-lang/source_span
 
 environment:
-  # This must remain a tight constraint until nnbd is stable
-  sdk: '>=2.11.0-0.0 <2.12.0'
+  sdk: ">=2.12.0-0.0 <3.0.0"
 
 dependencies:
   charcode: '>=1.2.0-nullsafety <1.2.0'
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 99dc647..dce5e23 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for test-1.16.0-nullsafety.8
+# This file is generated by importer.py for test-1.16.0-nullsafety.9
 
 import("//build/dart/dart_library.gni")
 
diff --git a/test/CHANGELOG.md b/test/CHANGELOG.md
index 410f4f1..ded0c39 100644
--- a/test/CHANGELOG.md
+++ b/test/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.16.0-nullsafety.9
+
+* Fix `spawnHybridUri` to respect language versioning of the spawned uri.
+
 ## 1.16.0-nullsafety.8
 
 * Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release
diff --git a/test/lib/src/runner/browser/platform.dart b/test/lib/src/runner/browser/platform.dart
index ee5924c..d0e88a0 100644
--- a/test/lib/src/runner/browser/platform.dart
+++ b/test/lib/src/runner/browser/platform.dart
@@ -7,7 +7,6 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
-import 'dart:isolate';
 
 import 'package:async/async.dart';
 import 'package:http_multi_server/http_multi_server.dart';
@@ -32,6 +31,7 @@
 import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
 import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
 import 'package:test_core/src/util/io.dart'; // ignore: implementation_imports
+import 'package:test_core/src/util/package_config.dart'; // ignore: implementation_imports
 import 'package:test_core/src/util/stack_trace_mapper.dart'; // ignore: implementation_imports
 import 'package:web_socket_channel/web_socket_channel.dart';
 import 'package:yaml/yaml.dart';
@@ -51,12 +51,13 @@
   /// the working directory.
   static Future<BrowserPlatform> start({String root}) async {
     var server = shelf_io.IOServer(await HttpMultiServer.loopback(0));
+    var packageConfig = await currentPackageConfig;
     return BrowserPlatform._(
         server,
         Configuration.current,
-        p.fromUri(await Isolate.resolvePackageUri(
+        p.fromUri(packageConfig.resolve(
             Uri.parse('package:test/src/runner/browser/static/favicon.ico'))),
-        p.fromUri(await Isolate.resolvePackageUri(Uri.parse(
+        p.fromUri(packageConfig.resolve(Uri.parse(
             'package:test/src/runner/browser/static/default.html.tpl'))),
         root: root);
   }
diff --git a/test/lib/src/runner/node/platform.dart b/test/lib/src/runner/node/platform.dart
index 4e9eecb..a677fa6 100644
--- a/test/lib/src/runner/node/platform.dart
+++ b/test/lib/src/runner/node/platform.dart
@@ -24,6 +24,7 @@
 import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
 import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
 import 'package:test_core/src/util/io.dart'; // ignore: implementation_imports
+import 'package:test_core/src/util/package_config.dart'; // ignore: implementation_imports
 import 'package:test_core/src/util/stack_trace_mapper.dart'; // ignore: implementation_imports
 import 'package:test_core/src/runner/application_exception.dart'; // ignore: implementation_imports
 import 'package:test_core/src/runner/compiler_pool.dart'; // ignore: implementation_imports
diff --git a/test/lib/src/util/package_map.dart b/test/lib/src/util/package_map.dart
index 8874c99..fd39842 100644
--- a/test/lib/src/util/package_map.dart
+++ b/test/lib/src/util/package_map.dart
@@ -4,15 +4,8 @@
 //
 // @dart=2.7
 
-import 'dart:isolate';
-
 import 'package:package_config/package_config.dart';
 
-/// The [PackageConfig] parsed from the current isolates package config file.
-final Future<PackageConfig> currentPackageConfig = () async {
-  return loadPackageConfigUri(await Isolate.packageConfig);
-}();
-
 /// Adds methods to convert to a package map on [PackageConfig].
 extension PackageMap on PackageConfig {
   /// A package map exactly matching the current package config
diff --git a/test/pubspec.yaml b/test/pubspec.yaml
index aea124b..1c6975a 100644
--- a/test/pubspec.yaml
+++ b/test/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test
-version: 1.16.0-nullsafety.8
+version: 1.16.0-nullsafety.9
 description: A full featured library for writing and running Dart tests.
 homepage: https://github.com/dart-lang/test/blob/master/pkgs/test
 
@@ -31,17 +31,11 @@
   webkit_inspection_protocol: ">=0.5.0 <0.8.0"
   yaml: ^2.0.0
   # Use an exact version until the test_api and test_core package are stable.
-  test_api: 0.2.19-nullsafety.5
-  test_core: 0.3.12-nullsafety.8
+  test_api: 0.2.19-nullsafety.6
+  test_core: 0.3.12-nullsafety.9
 
 dev_dependencies:
   fake_async: ^1.0.0
   shelf_test_handler: ^1.0.0
   test_descriptor: ^1.0.0
   test_process: ^1.0.0
-
-# dependency_overrides:
-#   test_api:
-#     path: ../test_api
-#   test_core:
-#     path: ../test_core
diff --git a/test_api/BUILD.gn b/test_api/BUILD.gn
index 9ce90a3..235f267 100644
--- a/test_api/BUILD.gn
+++ b/test_api/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for test_api-0.2.19-nullsafety.5
+# This file is generated by importer.py for test_api-0.2.19-nullsafety.6
 
 import("//build/dart/dart_library.gni")
 
diff --git a/test_api/CHANGELOG.md b/test_api/CHANGELOG.md
index 1694a52..7370d4e 100644
--- a/test_api/CHANGELOG.md
+++ b/test_api/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.19-nullsafety.6
+
+* Fix `spawnHybridUri` to respect language versioning of the spawned uri.
+
 ## 0.2.19-nullsafety.5
 
 * Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release
diff --git a/test_api/lib/src/frontend/spawn_hybrid.dart b/test_api/lib/src/frontend/spawn_hybrid.dart
index 4dde7b7..102298e 100644
--- a/test_api/lib/src/frontend/spawn_hybrid.dart
+++ b/test_api/lib/src/frontend/spawn_hybrid.dart
@@ -6,11 +6,9 @@
 import 'dart:convert';
 
 import 'package:async/async.dart';
-import 'package:path/path.dart' as p;
 import 'package:stream_channel/stream_channel.dart';
 
 import '../../test_api.dart';
-import '../backend/invoker.dart';
 import '../util/remote_exception.dart';
 import '../utils.dart';
 
@@ -92,52 +90,13 @@
 /// **Note**: If you use this API, be sure to add a dependency on the
 /// **`stream_channel` package, since you're using its API as well!
 StreamChannel spawnHybridUri(uri, {Object? message, bool stayAlive = false}) {
-  Uri parsedUrl;
-  if (uri is Uri) {
-    parsedUrl = uri;
-  } else if (uri is String) {
-    parsedUrl = Uri.parse(uri);
-  } else {
+  if (uri is String) {
+    // Ensure that it can be parsed as a uri.
+    Uri.parse(uri);
+  } else if (uri is! Uri) {
     throw ArgumentError.value(uri, 'uri', 'must be a Uri or a String.');
   }
-
-  String absoluteUri;
-  if (parsedUrl.scheme.isEmpty) {
-    var isRootRelative = parsedUrl.path.startsWith('/');
-
-    // If we're running in a browser context, the working directory is already
-    // relative to the test file, whereas on the VM the working directory is the
-    // root of the package.
-    if (p.style == p.Style.url) {
-      if (isRootRelative) {
-        // A root-relative URL is interpreted as relative to the package root,
-        // which means placing it beneath the URL secret.
-        var secret = Uri.encodeComponent(Uri.base.pathSegments[0]);
-        absoluteUri = p.absolute('/$secret$parsedUrl');
-        print('Uri.base: ${Uri.base}');
-        print('absoluteUri: ${absoluteUri}');
-      } else {
-        absoluteUri = p.absolute(parsedUrl.toString());
-      }
-    } else {
-      if (isRootRelative) {
-        // We assume that the current path is the package root. `pub run`
-        // enforces this currently, but at some point it would probably be good
-        // to pass in an explicit root.
-        absoluteUri = p.url
-            .join(p.toUri(p.current).toString(), parsedUrl.path.substring(1));
-      } else {
-        var suitePath = Invoker.current!.liveTest.suite.path!;
-        absoluteUri = p.url.join(
-            p.url.dirname(p.toUri(p.absolute(suitePath)).toString()),
-            parsedUrl.toString());
-      }
-    }
-  } else {
-    absoluteUri = uri.toString();
-  }
-
-  return _spawn(absoluteUri, message, stayAlive: stayAlive);
+  return _spawn(uri.toString(), message, stayAlive: stayAlive);
 }
 
 /// Spawns a VM isolate that runs the given [dartCode], which is loaded as the
@@ -187,8 +146,7 @@
   return _spawn(uri.toString(), message, stayAlive: stayAlive);
 }
 
-/// Like [spawnHybridUri], but doesn't take [Uri] objects and doesn't handle
-/// relative URLs.
+/// Like [spawnHybridUri], but doesn't take [Uri] objects.
 StreamChannel _spawn(String uri, Object? message, {bool stayAlive = false}) {
   var channel = Zone.current[#test.runner.test_channel] as MultiChannel?;
   if (channel == null) {
diff --git a/test_api/pubspec.yaml b/test_api/pubspec.yaml
index ebe1d24..9e1db0e 100644
--- a/test_api/pubspec.yaml
+++ b/test_api/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test_api
-version: 0.2.19-nullsafety.5
+version: 0.2.19-nullsafety.6
 description: A library for writing Dart tests.
 homepage: https://github.com/dart-lang/test/blob/master/pkgs/test_api
 
@@ -28,9 +28,3 @@
   test_process: ^1.0.0
   test: any
   test_core: any
-
-dependency_overrides:
-  test:
-    path: ../test
-  test_core:
-    path: ../test_core
diff --git a/test_core/BUILD.gn b/test_core/BUILD.gn
index ebacd4d..c790e20 100644
--- a/test_core/BUILD.gn
+++ b/test_core/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for test_core-0.3.12-nullsafety.8
+# This file is generated by importer.py for test_core-0.3.12-nullsafety.9
 
 import("//build/dart/dart_library.gni")
 
@@ -88,6 +88,7 @@
     "src/util/exit_codes.dart",
     "src/util/io.dart",
     "src/util/io_stub.dart",
+    "src/util/package_config.dart",
     "src/util/print_sink.dart",
     "src/util/stack_trace_mapper.dart",
     "src/util/string_literal_iterator.dart",
diff --git a/test_core/CHANGELOG.md b/test_core/CHANGELOG.md
index aba6648..6726a5a 100644
--- a/test_core/CHANGELOG.md
+++ b/test_core/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.12-nullsafety.9
+
+* Fix `spawnHybridUri` to respect language versioning of the spawned uri.
+* Pre-emptively fix legacy library import lint violations, and unmigrate some
+  libraries as necessary.
+
 ## 0.3.12-nullsafety.8
 
 * Fix a bug where the test runner could crash when printing the elapsed time.
diff --git a/test_core/lib/src/direct_run.dart b/test_core/lib/src/direct_run.dart
index 3ed0b12..c4f7612 100644
--- a/test_core/lib/src/direct_run.dart
+++ b/test_core/lib/src/direct_run.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2020, 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.9
 
 import 'dart:async';
 import 'dart:collection';
@@ -29,7 +31,7 @@
 /// is applied except for the filtering defined by `solo` or `skip` arguments to
 /// `group` and `test`. Returns [true] if all tests passed.
 Future<bool> directRunTests(FutureOr<void> Function() testMain,
-        {Reporter Function(Engine)? reporterFactory}) =>
+        {Reporter Function(Engine) /*?*/ reporterFactory}) =>
     _directRunTests(testMain, reporterFactory: reporterFactory);
 
 /// Runs a single test declared in [testMain] matched by it's full test name.
@@ -47,12 +49,13 @@
 /// will both be run, then a [DuplicateTestnameException] will be thrown.
 Future<bool> directRunSingleTest(
         FutureOr<void> Function() testMain, String fullTestName,
-        {Reporter Function(Engine)? reporterFactory}) =>
+        {Reporter Function(Engine) /*?*/ reporterFactory}) =>
     _directRunTests(testMain,
         reporterFactory: reporterFactory, fullTestName: fullTestName);
 
 Future<bool> _directRunTests(FutureOr<void> Function() testMain,
-    {Reporter Function(Engine)? reporterFactory, String? fullTestName}) async {
+    {Reporter Function(Engine) /*?*/ reporterFactory,
+    String /*?*/ fullTestName}) async {
   reporterFactory ??= (engine) => ExpandedReporter.watch(engine, PrintSink(),
       color: Configuration.empty.color, printPath: false, printPlatform: false);
   final declarer = Declarer(fullTestName: fullTestName);
@@ -80,7 +83,7 @@
       throw MissingTestException(fullTestName);
     }
   }
-  return success!;
+  return success;
 }
 
 /// Runs [testMain] and returns the names of all declared tests.
diff --git a/test_core/lib/src/executable.dart b/test_core/lib/src/executable.dart
index 5d82aaf..c054674 100644
--- a/test_core/lib/src/executable.dart
+++ b/test_core/lib/src/executable.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 import 'dart:io';
@@ -18,16 +20,15 @@
 import 'util/exit_codes.dart' as exit_codes;
 import 'util/io.dart';
 
-StreamSubscription? signalSubscription;
+StreamSubscription /*?*/ signalSubscription;
 bool isShutdown = false;
 
 /// Returns the path to the global test configuration file.
 final String _globalConfigPath = () {
   if (Platform.environment.containsKey('DART_TEST_CONFIG')) {
-    return Platform.environment['DART_TEST_CONFIG'] as String;
+    return Platform.environment['DART_TEST_CONFIG'];
   } else if (Platform.operatingSystem == 'windows') {
-    return p.join(
-        Platform.environment['LOCALAPPDATA'] as String, 'DartTest.yaml');
+    return p.join(Platform.environment['LOCALAPPDATA'], 'DartTest.yaml');
   } else {
     return '${Platform.environment['HOME']}/.dart_test.yaml';
   }
@@ -45,7 +46,7 @@
 void completeShutdown() {
   if (isShutdown) return;
   if (signalSubscription != null) {
-    signalSubscription!.cancel();
+    signalSubscription.cancel();
     signalSubscription = null;
   }
   isShutdown = true;
@@ -136,7 +137,7 @@
     return;
   }
 
-  Runner? runner;
+  Runner /*?*/ runner;
 
   signalSubscription ??= _signals.listen((signal) async {
     completeShutdown();
@@ -179,7 +180,7 @@
 ///
 /// If [error] is passed, it's used in place of the usage message and the whole
 /// thing is printed to stderr instead of stdout.
-void _printUsage([String? error]) {
+void _printUsage([String /*?*/ error]) {
   var output = stdout;
 
   var message = 'Runs tests in this package.';
diff --git a/test_core/lib/src/platform.dart b/test_core/lib/src/platform.dart
index eef5a2c..24d8fb4 100644
--- a/test_core/lib/src/platform.dart
+++ b/test_core/lib/src/platform.dart
@@ -1,3 +1,9 @@
+// Copyright (c) 2020, 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.9
+
 // ignore: deprecated_member_use
 export 'package:test_api/backend.dart' show SuitePlatform, Runtime;
 export 'package:test_core/src/runner/configuration.dart' show Configuration;
diff --git a/test_core/lib/src/runner.dart b/test_core/lib/src/runner.dart
index 9d93f28..ede16c1 100644
--- a/test_core/lib/src/runner.dart
+++ b/test_core/lib/src/runner.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 import 'dart:io';
@@ -50,7 +52,7 @@
   final Reporter _reporter;
 
   /// The subscription to the stream returned by [_loadSuites].
-  StreamSubscription? _suiteSubscription;
+  StreamSubscription /*?*/ _suiteSubscription;
 
   /// The set of suite paths for which [_warnForUnknownTags] has already been
   /// called.
@@ -62,7 +64,7 @@
   /// The current debug operation, if any.
   ///
   /// This is stored so that we can cancel it when the runner is closed.
-  CancelableOperation? _debugOperation;
+  CancelableOperation /*?*/ _debugOperation;
 
   /// The memoizer for ensuring [close] only runs once.
   final _closeMemo = AsyncMemoizer();
@@ -81,17 +83,17 @@
           final sink =
               (File(filepath)..createSync(recursive: true)).openWrite();
           sinks.add(sink);
-          return allReporters[reporterName]!.factory(config, engine, sink);
+          return allReporters[reporterName].factory(config, engine, sink);
         }
 
         return Runner._(
           engine,
           MultiplexReporter([
             // Standard reporter.
-            allReporters[config.reporter]!.factory(config, engine, stdout),
+            allReporters[config.reporter].factory(config, engine, stdout),
             // File reporters.
             for (var reporter in config.fileReporters.keys)
-              createFileReporter(reporter, config.fileReporters[reporter]!),
+              createFileReporter(reporter, config.fileReporters[reporter]),
           ]),
           sinks,
         );
@@ -113,21 +115,21 @@
         var suites = _loadSuites();
 
         if (_config.coverage != null) {
-          await Directory(_config.coverage!).create(recursive: true);
+          await Directory(_config.coverage).create(recursive: true);
         }
 
-        bool? success;
+        bool /*?*/ success;
         if (_config.pauseAfterLoad) {
           success = await _loadThenPause(suites);
         } else {
           _suiteSubscription = suites.listen(_engine.suiteSink.add);
           var results = await Future.wait(<Future>[
-            _suiteSubscription!
+            _suiteSubscription
                 .asFuture()
                 .then((_) => _engine.suiteSink.close()),
             _engine.run()
           ], eagerError: true);
-          success = results.last as bool?;
+          success = results.last as bool /*?*/;
         }
 
         if (_closed) return false;
@@ -206,7 +208,7 @@
   /// currently-running VM tests, in case they have stuff to clean up on the
   /// filesystem.
   Future close() => _closeMemo.runOnce(() async {
-        Timer? timer;
+        Timer /*?*/ timer;
         if (!_engine.isIdle) {
           // Wait a bit to print this message, since printing it eagerly looks weird
           // if the tests then finish immediately.
@@ -287,7 +289,7 @@
   /// children.
   void _warnForUnknownTags(Suite suite) {
     if (_tagWarningSuites.contains(suite.path)) return;
-    _tagWarningSuites.add(suite.path!);
+    _tagWarningSuites.add(suite.path);
 
     var unknownTags = _collectUnknownTags(suite);
     if (unknownTags.isEmpty) return;
@@ -339,7 +341,7 @@
       }
 
       if (entry is! Group) return;
-      var group = entry;
+      var group = entry as Group;
 
       currentTags.addAll(newTags);
       for (var child in group.entries) {
@@ -369,8 +371,8 @@
   T _shardSuite<T extends Suite>(T suite) {
     if (_config.totalShards == null) return suite;
 
-    var shardSize = suite.group.testCount / _config.totalShards!;
-    var shardIndex = _config.shardIndex!;
+    var shardSize = suite.group.testCount / _config.totalShards;
+    var shardIndex = _config.shardIndex;
     var shardStart = (shardSize * shardIndex).round();
     var shardEnd = (shardSize * (shardIndex + 1)).round();
 
@@ -388,11 +390,11 @@
   Future<bool> _loadThenPause(Stream<LoadSuite> suites) async {
     _suiteSubscription = suites.asyncMap((loadSuite) async {
       _debugOperation = debug(_engine, _reporter, loadSuite);
-      await _debugOperation!.valueOrCancellation();
+      await _debugOperation.valueOrCancellation();
     }).listen(null);
 
     var results = await Future.wait(<Future>[
-      _suiteSubscription!.asFuture().then((_) => _engine.suiteSink.close()),
+      _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()),
       _engine.run()
     ], eagerError: true);
     return results.last as bool;
diff --git a/test_core/lib/src/runner/compiler_pool.dart b/test_core/lib/src/runner/compiler_pool.dart
index 2617fd4..9bc4f7b 100644
--- a/test_core/lib/src/runner/compiler_pool.dart
+++ b/test_core/lib/src/runner/compiler_pool.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 import 'dart:convert';
@@ -42,7 +44,7 @@
   final List<String> _extraArgs;
 
   /// Creates a compiler pool that multiple instances of `dart2js` at once.
-  CompilerPool([Iterable<String>? extraArgs])
+  CompilerPool([Iterable<String> /*?*/ extraArgs])
       : _pool = Pool(Configuration.current.concurrency),
         _extraArgs = extraArgs?.toList() ?? const [];
 
diff --git a/test_core/lib/src/runner/configuration.dart b/test_core/lib/src/runner/configuration.dart
index 332faeb..b5a6ee8 100644
--- a/test_core/lib/src/runner/configuration.dart
+++ b/test_core/lib/src/runner/configuration.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 
@@ -41,40 +43,40 @@
 
   /// Whether `--help` was passed.
   bool get help => _help ?? false;
-  final bool? _help;
+  final bool /*?*/ _help;
 
   /// Custom HTML template file.
-  final String? customHtmlTemplatePath;
+  final String /*?*/ customHtmlTemplatePath;
 
   /// Whether `--version` was passed.
   bool get version => _version ?? false;
-  final bool? _version;
+  final bool /*?*/ _version;
 
   /// Whether to pause for debugging after loading each test suite.
   bool get pauseAfterLoad => _pauseAfterLoad ?? false;
-  final bool? _pauseAfterLoad;
+  final bool /*?*/ _pauseAfterLoad;
 
   /// Whether to run browsers in their respective debug modes
   bool get debug => pauseAfterLoad || (_debug ?? false) || _coverage != null;
-  final bool? _debug;
+  final bool /*?*/ _debug;
 
   /// The output folder for coverage gathering
-  String? get coverage => _coverage;
-  final String? _coverage;
+  String /*?*/ get coverage => _coverage;
+  final String /*?*/ _coverage;
 
   /// The path to the file from which to load more configuration information.
   ///
   /// This is *not* resolved automatically.
   String get configurationPath => _configurationPath ?? 'dart_test.yaml';
-  final String? _configurationPath;
+  final String /*?*/ _configurationPath;
 
   /// The path to dart2js.
   String get dart2jsPath => _dart2jsPath ?? p.join(sdkDir, 'bin', 'dart2js');
-  final String? _dart2jsPath;
+  final String /*?*/ _dart2jsPath;
 
   /// The name of the reporter to use to display results.
   String get reporter => _reporter ?? defaultReporter;
-  final String? _reporter;
+  final String /*?*/ _reporter;
 
   /// The map of file reporters where the key is the name of the reporter and
   /// the value is the filepath to which its output should be written.
@@ -82,20 +84,20 @@
 
   /// Whether to disable retries of tests.
   bool get noRetry => _noRetry ?? false;
-  final bool? _noRetry;
+  final bool /*?*/ _noRetry;
 
   /// The URL for the `pub serve` instance from which to load tests, or `null`
   /// if tests should be loaded from the filesystem.
-  final Uri? pubServeUrl;
+  final Uri /*?*/ pubServeUrl;
 
   /// Whether to use command-line color escapes.
   bool get color => _color ?? canUseSpecialChars;
-  final bool? _color;
+  final bool /*?*/ _color;
 
   /// How many tests to run concurrently.
   int get concurrency =>
       pauseAfterLoad ? 1 : (_concurrency ?? defaultConcurrency);
-  final int? _concurrency;
+  final int /*?*/ _concurrency;
 
   /// The index of the current shard, if sharding is in use, or `null` if it's
   /// not.
@@ -111,25 +113,25 @@
   /// * Across all shards, each test must be run exactly once.
   ///
   /// In addition, tests should be balanced across shards as much as possible.
-  final int? shardIndex;
+  final int /*?*/ shardIndex;
 
   /// The total number of shards, if sharding is in use, or `null` if it's not.
   ///
   /// See [shardIndex] for details.
-  final int? totalShards;
+  final int /*?*/ totalShards;
 
   /// The list of packages to fold when producing [StackTrace]s.
   Set<String> get foldTraceExcept => _foldTraceExcept ?? {};
-  final Set<String>? _foldTraceExcept;
+  final Set<String> /*?*/ _foldTraceExcept;
 
   /// If non-empty, all packages not in this list will be folded when producing
   /// [StackTrace]s.
   Set<String> get foldTraceOnly => _foldTraceOnly ?? {};
-  final Set<String>? _foldTraceOnly;
+  final Set<String> /*?*/ _foldTraceOnly;
 
   /// The paths from which to load tests.
   List<String> get paths => _paths ?? ['test'];
-  final List<String>? _paths;
+  final List<String> /*?*/ _paths;
 
   /// Whether the load paths were passed explicitly or the default was used.
   bool get explicitPaths => _paths != null;
@@ -138,7 +140,7 @@
   ///
   /// This is used to find tests within a directory.
   Glob get filename => _filename ?? defaultFilename;
-  final Glob? _filename;
+  final Glob /*?*/ _filename;
 
   /// The set of presets to use.
   ///
@@ -153,7 +155,7 @@
         ...suiteDefaults.knownTags,
         for (var configuration in presets.values) ...configuration.knownTags
       });
-  Set<String>? _knownTags;
+  Set<String> /*?*/ _knownTags;
 
   /// Configuration presets.
   ///
@@ -172,7 +174,7 @@
         ...presets.keys,
         for (var configuration in presets.values) ...configuration.knownPresets
       });
-  Set<String>? _knownPresets;
+  Set<String> /*?*/ _knownPresets;
 
   /// Built-in runtimes whose settings are overridden by the user.
   final Map<String, RuntimeSettings> overrideRuntimes;
@@ -188,7 +190,7 @@
   ///
   /// The current configuration is set using [asCurrent].
   static Configuration get current =>
-      Zone.current[_currentKey] as Configuration? ?? Configuration();
+      Zone.current[_currentKey] as Configuration /*?*/ ?? Configuration();
 
   /// Parses the configuration from [args].
   ///
@@ -215,57 +217,57 @@
   ///
   /// Throws a [FormatException] if its contents are invalid.
   factory Configuration.loadFromString(String source,
-          {bool global = false, Uri? sourceUrl}) =>
+          {bool global = false, Uri /*?*/ sourceUrl}) =>
       loadFromString(source, global: global, sourceUrl: sourceUrl);
 
   factory Configuration(
-      {bool? help,
-      String? customHtmlTemplatePath,
-      bool? version,
-      bool? pauseAfterLoad,
-      bool? debug,
-      bool? color,
-      String? configurationPath,
-      String? dart2jsPath,
-      String? reporter,
-      Map<String, String>? fileReporters,
-      String? coverage,
-      int? pubServePort,
-      int? concurrency,
-      int? shardIndex,
-      int? totalShards,
-      Iterable<String>? paths,
-      Iterable<String>? foldTraceExcept,
-      Iterable<String>? foldTraceOnly,
-      Glob? filename,
-      Iterable<String>? chosenPresets,
-      Map<String, Configuration>? presets,
-      Map<String, RuntimeSettings>? overrideRuntimes,
-      Map<String, CustomRuntime>? defineRuntimes,
-      bool? noRetry,
+      {bool /*?*/ help,
+      String /*?*/ customHtmlTemplatePath,
+      bool /*?*/ version,
+      bool /*?*/ pauseAfterLoad,
+      bool /*?*/ debug,
+      bool /*?*/ color,
+      String /*?*/ configurationPath,
+      String /*?*/ dart2jsPath,
+      String /*?*/ reporter,
+      Map<String, String> /*?*/ fileReporters,
+      String /*?*/ coverage,
+      int /*?*/ pubServePort,
+      int /*?*/ concurrency,
+      int /*?*/ shardIndex,
+      int /*?*/ totalShards,
+      Iterable<String> /*?*/ paths,
+      Iterable<String> /*?*/ foldTraceExcept,
+      Iterable<String> /*?*/ foldTraceOnly,
+      Glob /*?*/ filename,
+      Iterable<String> /*?*/ chosenPresets,
+      Map<String, Configuration> /*?*/ presets,
+      Map<String, RuntimeSettings> /*?*/ overrideRuntimes,
+      Map<String, CustomRuntime> /*?*/ defineRuntimes,
+      bool /*?*/ noRetry,
 
       // Suite-level configuration
-      bool? jsTrace,
-      bool? runSkipped,
-      Iterable<String>? dart2jsArgs,
-      String? precompiledPath,
-      Iterable<Pattern>? patterns,
-      Iterable<RuntimeSelection>? runtimes,
-      BooleanSelector? includeTags,
-      BooleanSelector? excludeTags,
-      Map<BooleanSelector, SuiteConfiguration>? tags,
-      Map<PlatformSelector, SuiteConfiguration>? onPlatform,
-      int? testRandomizeOrderingSeed,
+      bool /*?*/ jsTrace,
+      bool /*?*/ runSkipped,
+      Iterable<String> /*?*/ dart2jsArgs,
+      String /*?*/ precompiledPath,
+      Iterable<Pattern> /*?*/ patterns,
+      Iterable<RuntimeSelection> /*?*/ runtimes,
+      BooleanSelector /*?*/ includeTags,
+      BooleanSelector /*?*/ excludeTags,
+      Map<BooleanSelector, SuiteConfiguration> /*?*/ tags,
+      Map<PlatformSelector, SuiteConfiguration> /*?*/ onPlatform,
+      int /*?*/ testRandomizeOrderingSeed,
 
       // Test-level configuration
-      Timeout? timeout,
-      bool? verboseTrace,
-      bool? chainStackTraces,
-      bool? skip,
-      int? retry,
-      String? skipReason,
-      PlatformSelector? testOn,
-      Iterable<String>? addTags}) {
+      Timeout /*?*/ timeout,
+      bool /*?*/ verboseTrace,
+      bool /*?*/ chainStackTraces,
+      bool /*?*/ skip,
+      int /*?*/ retry,
+      String /*?*/ skipReason,
+      PlatformSelector /*?*/ testOn,
+      Iterable<String> /*?*/ addTags}) {
     var chosenPresetSet = chosenPresets?.toSet();
     var configuration = Configuration._(
         help: help,
@@ -317,8 +319,8 @@
     return configuration._resolvePresets();
   }
 
-  static Map<String, Configuration>? _withChosenPresets(
-      Map<String, Configuration>? map, Set<String>? chosenPresets) {
+  static Map<String, Configuration> /*?*/ _withChosenPresets(
+      Map<String, Configuration> /*?*/ map, Set<String> /*?*/ chosenPresets) {
     if (map == null || chosenPresets == null) return map;
     return map.map((key, config) => MapEntry(
         key,
@@ -330,31 +332,31 @@
   ///
   /// Unlike [new Configuration], this assumes [presets] is already resolved.
   Configuration._(
-      {bool? help,
-      String? customHtmlTemplatePath,
-      bool? version,
-      bool? pauseAfterLoad,
-      bool? debug,
-      bool? color,
-      String? configurationPath,
-      String? dart2jsPath,
-      String? reporter,
-      Map<String, String>? fileReporters,
-      String? coverage,
-      int? pubServePort,
-      int? concurrency,
+      {bool /*?*/ help,
+      String /*?*/ customHtmlTemplatePath,
+      bool /*?*/ version,
+      bool /*?*/ pauseAfterLoad,
+      bool /*?*/ debug,
+      bool /*?*/ color,
+      String /*?*/ configurationPath,
+      String /*?*/ dart2jsPath,
+      String /*?*/ reporter,
+      Map<String, String> /*?*/ fileReporters,
+      String /*?*/ coverage,
+      int /*?*/ pubServePort,
+      int /*?*/ concurrency,
       this.shardIndex,
       this.totalShards,
-      Iterable<String>? paths,
-      Iterable<String>? foldTraceExcept,
-      Iterable<String>? foldTraceOnly,
-      Glob? filename,
-      Iterable<String>? chosenPresets,
-      Map<String, Configuration>? presets,
-      Map<String, RuntimeSettings>? overrideRuntimes,
-      Map<String, CustomRuntime>? defineRuntimes,
-      bool? noRetry,
-      SuiteConfiguration? suiteDefaults})
+      Iterable<String> /*?*/ paths,
+      Iterable<String> /*?*/ foldTraceExcept,
+      Iterable<String> /*?*/ foldTraceOnly,
+      Glob /*?*/ filename,
+      Iterable<String> /*?*/ chosenPresets,
+      Map<String, Configuration> /*?*/ presets,
+      Map<String, RuntimeSettings> /*?*/ overrideRuntimes,
+      Map<String, CustomRuntime> /*?*/ defineRuntimes,
+      bool /*?*/ noRetry,
+      SuiteConfiguration /*?*/ suiteDefaults})
       : _help = help,
         customHtmlTemplatePath = customHtmlTemplatePath,
         _version = version,
@@ -383,10 +385,10 @@
             ? suiteDefaults?.change(timeout: Timeout.none) ??
                 SuiteConfiguration(timeout: Timeout.none)
             : suiteDefaults ?? SuiteConfiguration.empty {
-    if (_filename != null && _filename!.context.style != p.style) {
+    if (_filename != null && _filename.context.style != p.style) {
       throw ArgumentError(
           "filename's context must match the current operating system, was "
-          '${_filename!.context.style}.');
+          '${_filename.context.style}.');
     }
 
     if ((shardIndex == null) != (totalShards == null)) {
@@ -394,7 +396,7 @@
           'shardIndex and totalShards may only be passed together.');
     } else if (shardIndex != null) {
       RangeError.checkValueInInterval(
-          shardIndex!, 0, totalShards! - 1, 'shardIndex');
+          shardIndex, 0, totalShards - 1, 'shardIndex');
     }
   }
 
@@ -407,7 +409,7 @@
   /// Returns an unmodifiable copy of [input].
   ///
   /// If [input] is `null` or empty, this returns `null`.
-  static List<T>? _list<T>(Iterable<T>? input) {
+  static List<T> /*?*/ _list<T>(Iterable<T> /*?*/ input) {
     if (input == null) return null;
     var list = List<T>.unmodifiable(input);
     if (list.isEmpty) return null;
@@ -417,7 +419,7 @@
   /// Returns a set from [input].
   ///
   /// If [input] is `null` or empty, this returns `null`.
-  static Set<T>? _set<T>(Iterable<T>? input) {
+  static Set<T> /*?*/ _set<T>(Iterable<T> /*?*/ input) {
     if (input == null) return null;
     var set = Set<T>.from(input);
     if (set.isEmpty) return null;
@@ -425,7 +427,7 @@
   }
 
   /// Returns an unmodifiable copy of [input] or an empty unmodifiable map.
-  static Map<K, V> _map<K, V>(Map<K, V>? input) {
+  static Map<K, V> _map<K, V>(Map<K, V> /*?*/ input) {
     input ??= {};
     return Map.unmodifiable(input);
   }
@@ -470,15 +472,15 @@
     var foldTraceExcept = other._foldTraceExcept ?? _foldTraceExcept;
     if (_foldTraceOnly != null) {
       if (other._foldTraceExcept != null) {
-        foldTraceOnly = _foldTraceOnly!.difference(other._foldTraceExcept!);
+        foldTraceOnly = _foldTraceOnly.difference(other._foldTraceExcept);
       } else if (other._foldTraceOnly != null) {
-        foldTraceOnly = other._foldTraceOnly!.intersection(_foldTraceOnly!);
+        foldTraceOnly = other._foldTraceOnly.intersection(_foldTraceOnly);
       }
     } else if (_foldTraceExcept != null) {
       if (other._foldTraceOnly != null) {
-        foldTraceOnly = other._foldTraceOnly!.difference(_foldTraceExcept!);
+        foldTraceOnly = other._foldTraceOnly.difference(_foldTraceExcept);
       } else if (other._foldTraceExcept != null) {
-        foldTraceExcept = other._foldTraceExcept!.union(_foldTraceExcept!);
+        foldTraceExcept = other._foldTraceExcept.union(_foldTraceExcept);
       }
     }
 
@@ -527,50 +529,50 @@
   /// Note that unlike [merge], this has no merging behavior—the old value is
   /// always replaced by the new one.
   Configuration change(
-      {bool? help,
-      String? customHtmlTemplatePath,
-      bool? version,
-      bool? pauseAfterLoad,
-      bool? color,
-      String? configurationPath,
-      String? dart2jsPath,
-      String? reporter,
-      Map<String, String>? fileReporters,
-      int? pubServePort,
-      int? concurrency,
-      int? shardIndex,
-      int? totalShards,
-      Iterable<String>? paths,
-      Iterable<String>? exceptPackages,
-      Iterable<String>? onlyPackages,
-      Glob? filename,
-      Iterable<String>? chosenPresets,
-      Map<String, Configuration>? presets,
-      Map<String, RuntimeSettings>? overrideRuntimes,
-      Map<String, CustomRuntime>? defineRuntimes,
-      bool? noRetry,
+      {bool /*?*/ help,
+      String /*?*/ customHtmlTemplatePath,
+      bool /*?*/ version,
+      bool /*?*/ pauseAfterLoad,
+      bool /*?*/ color,
+      String /*?*/ configurationPath,
+      String /*?*/ dart2jsPath,
+      String /*?*/ reporter,
+      Map<String, String> /*?*/ fileReporters,
+      int /*?*/ pubServePort,
+      int /*?*/ concurrency,
+      int /*?*/ shardIndex,
+      int /*?*/ totalShards,
+      Iterable<String> /*?*/ paths,
+      Iterable<String> /*?*/ exceptPackages,
+      Iterable<String> /*?*/ onlyPackages,
+      Glob /*?*/ filename,
+      Iterable<String> /*?*/ chosenPresets,
+      Map<String, Configuration> /*?*/ presets,
+      Map<String, RuntimeSettings> /*?*/ overrideRuntimes,
+      Map<String, CustomRuntime> /*?*/ defineRuntimes,
+      bool /*?*/ noRetry,
 
       // Suite-level configuration
-      bool? jsTrace,
-      bool? runSkipped,
-      Iterable<String>? dart2jsArgs,
-      String? precompiledPath,
-      Iterable<Pattern>? patterns,
-      Iterable<RuntimeSelection>? runtimes,
-      BooleanSelector? includeTags,
-      BooleanSelector? excludeTags,
-      Map<BooleanSelector, SuiteConfiguration>? tags,
-      Map<PlatformSelector, SuiteConfiguration>? onPlatform,
-      int? testRandomizeOrderingSeed,
+      bool /*?*/ jsTrace,
+      bool /*?*/ runSkipped,
+      Iterable<String> /*?*/ dart2jsArgs,
+      String /*?*/ precompiledPath,
+      Iterable<Pattern> /*?*/ patterns,
+      Iterable<RuntimeSelection> /*?*/ runtimes,
+      BooleanSelector /*?*/ includeTags,
+      BooleanSelector /*?*/ excludeTags,
+      Map<BooleanSelector, SuiteConfiguration> /*?*/ tags,
+      Map<PlatformSelector, SuiteConfiguration> /*?*/ onPlatform,
+      int /*?*/ testRandomizeOrderingSeed,
 
       // Test-level configuration
-      Timeout? timeout,
-      bool? verboseTrace,
-      bool? chainStackTraces,
-      bool? skip,
-      String? skipReason,
-      PlatformSelector? testOn,
-      Iterable<String>? addTags}) {
+      Timeout /*?*/ timeout,
+      bool /*?*/ verboseTrace,
+      bool /*?*/ chainStackTraces,
+      bool /*?*/ skip,
+      String /*?*/ skipReason,
+      PlatformSelector /*?*/ testOn,
+      Iterable<String> /*?*/ addTags}) {
     var config = Configuration._(
         help: help ?? _help,
         customHtmlTemplatePath:
diff --git a/test_core/lib/src/runner/configuration/args.dart b/test_core/lib/src/runner/configuration/args.dart
index 253924b..ab7b79f 100644
--- a/test_core/lib/src/runner/configuration/args.dart
+++ b/test_core/lib/src/runner/configuration/args.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:io';
 import 'dart:math';
@@ -116,7 +118,7 @@
 
   var reporterDescriptions = <String, String>{};
   for (var reporter in allReporters.keys) {
-    reporterDescriptions[reporter] = allReporters[reporter]!.description;
+    reporterDescriptions[reporter] = allReporters[reporter].description;
   }
 
   parser.addSeparator('Output:');
@@ -183,8 +185,8 @@
         .toList()
           ..addAll(_options['plain-name'] as List<String>);
 
-    var includeTagSet = Set.from(_options['tags'] as Iterable? ?? [])
-      ..addAll(_options['tag'] as Iterable? ?? []);
+    var includeTagSet = Set.from(_options['tags'] as Iterable /*?*/ ?? [])
+      ..addAll(_options['tag'] as Iterable /*?*/ ?? []);
 
     var includeTags = includeTagSet.fold(BooleanSelector.all,
         (BooleanSelector selector, tag) {
@@ -192,8 +194,9 @@
       return selector.intersection(tagSelector);
     });
 
-    var excludeTagSet = Set.from(_options['exclude-tags'] as Iterable? ?? [])
-      ..addAll(_options['exclude-tag'] as Iterable? ?? []);
+    var excludeTagSet =
+        Set.from(_options['exclude-tags'] as Iterable /*?*/ ?? [])
+          ..addAll(_options['exclude-tag'] as Iterable /*?*/ ?? []);
 
     var excludeTags = excludeTagSet.fold(BooleanSelector.none,
         (BooleanSelector selector, tag) {
@@ -209,7 +212,7 @@
     } else if (shardIndex != null) {
       if (shardIndex < 0) {
         throw FormatException('--shard-index may not be negative.');
-      } else if (shardIndex >= totalShards!) {
+      } else if (shardIndex >= totalShards) {
         throw FormatException(
             '--shard-index must be less than --total-shards.');
       }
@@ -229,7 +232,7 @@
 
     var platform = _ifParsed<List<String>>('platform')
         ?.map((runtime) => RuntimeSelection(runtime))
-        .toList();
+        ?.toList();
     if (platform
             ?.any((runtime) => runtime.name == Runtime.phantomJS.identifier) ??
         false) {
@@ -276,12 +279,12 @@
   /// If the user hasn't explicitly chosen a value, we want to pass null values
   /// to [new Configuration] so that it considers those fields unset when
   /// merging with configuration from the config file.
-  T? _ifParsed<T>(String name) =>
+  T /*?*/ _ifParsed<T>(String name) =>
       _options.wasParsed(name) ? _options[name] as T : null;
 
   /// Runs [parse] on the value of the option [name], and wraps any
   /// [FormatException] it throws with additional information.
-  T? _parseOption<T>(String name, T Function(String) parse) {
+  T /*?*/ _parseOption<T>(String name, T Function(String) parse) {
     if (!_options.wasParsed(name)) return null;
 
     var value = _options[name];
@@ -290,7 +293,7 @@
     return _wrapFormatException(name, () => parse(value as String));
   }
 
-  Map<String, String>? _parseFileReporterOption() =>
+  Map<String, String> /*?*/ _parseFileReporterOption() =>
       _parseOption('file-reporter', (value) {
         if (!value.contains(':')) {
           throw FormatException(
diff --git a/test_core/lib/src/runner/configuration/custom_runtime.dart b/test_core/lib/src/runner/configuration/custom_runtime.dart
index 0c99191..65384ba 100644
--- a/test_core/lib/src/runner/configuration/custom_runtime.dart
+++ b/test_core/lib/src/runner/configuration/custom_runtime.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2017, 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.9
 
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
diff --git a/test_core/lib/src/runner/configuration/load.dart b/test_core/lib/src/runner/configuration/load.dart
index fe7b497..8c5419b 100644
--- a/test_core/lib/src/runner/configuration/load.dart
+++ b/test_core/lib/src/runner/configuration/load.dart
@@ -1,11 +1,14 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:io';
 
 import 'package:boolean_selector/boolean_selector.dart';
 import 'package:glob/glob.dart';
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as p;
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
@@ -55,7 +58,7 @@
 ///
 /// Throws a [FormatException] if the configuration is invalid.
 Configuration loadFromString(String source,
-    {bool global = false, Uri? sourceUrl}) {
+    {bool global = false, Uri /*?*/ sourceUrl}) {
   var document = loadYamlNode(source, sourceUrl: sourceUrl);
 
   if (document.value == null) return Configuration.empty;
@@ -184,8 +187,8 @@
     }
 
     var skipRaw = _getValue('skip', 'boolean or string',
-        (value) => (value is bool?) || value is String?);
-    String? skipReason;
+        (value) => (value is bool /*?*/) || value is String /*?*/);
+    String /*?*/ skipReason;
     bool skip;
     if (skipRaw is String) {
       skipReason = skipRaw;
@@ -294,13 +297,13 @@
   Map<String, RuntimeSettings> _loadOverrideRuntimes() {
     var runtimesNode =
         _getNode('override_platforms', 'map', (value) => value is Map)
-            as YamlMap?;
+            as YamlMap /*?*/;
     if (runtimesNode == null) return const {};
 
     var runtimes = <String, RuntimeSettings>{};
     runtimesNode.nodes.forEach((identifierNode, valueNode) {
-      var identifier = _parseIdentifierLike(
-          identifierNode as YamlNode, 'Platform identifier');
+      var yamlNode = identifierNode as YamlNode;
+      var identifier = _parseIdentifierLike(yamlNode, 'Platform identifier');
 
       _validate(valueNode, 'Platform definition must be a map.',
           (value) => value is Map);
@@ -309,8 +312,8 @@
       var settings = _expect(map, 'settings');
       _validate(settings, 'Must be a map.', (value) => value is Map);
 
-      runtimes[identifier] = RuntimeSettings(
-          identifier, identifierNode.span, [settings as YamlMap]);
+      runtimes[identifier] =
+          RuntimeSettings(identifier, yamlNode.span, [settings as YamlMap]);
     });
     return runtimes;
   }
@@ -412,13 +415,13 @@
   Map<String, CustomRuntime> _loadDefineRuntimes() {
     var runtimesNode =
         _getNode('define_platforms', 'map', (value) => value is Map)
-            as YamlMap?;
+            as YamlMap /*?*/;
     if (runtimesNode == null) return const {};
 
     var runtimes = <String, CustomRuntime>{};
     runtimesNode.nodes.forEach((identifierNode, valueNode) {
-      var identifier = _parseIdentifierLike(
-          identifierNode as YamlNode, 'Platform identifier');
+      var yamlNode = identifierNode as YamlNode;
+      var identifier = _parseIdentifierLike(yamlNode, 'Platform identifier');
 
       _validate(valueNode, 'Platform definition must be a map.',
           (value) => value is Map);
@@ -435,7 +438,7 @@
       _validate(settings, 'Must be a map.', (value) => value is Map);
 
       runtimes[identifier] = CustomRuntime(name, nameNode.span, identifier,
-          identifierNode.span, parent, parentNode.span, settings as YamlMap);
+          yamlNode.span, parent, parentNode.span, settings as YamlMap);
     });
     return runtimes;
   }
@@ -451,10 +454,10 @@
   ///
   /// If [typeTest] returns `false` for that value, instead throws an error
   /// complaining that the field is not a [typeName].
-  Object? _getValue(
+  Object /*?*/ _getValue(
       String field, String typeName, bool Function(dynamic) typeTest) {
     var value = _document[field];
-    if (typeTest(value)) return value;
+    if (value == null || typeTest(value)) return value;
     _error('$field must be ${a(typeName)}.', field);
   }
 
@@ -464,7 +467,7 @@
   /// error complaining that the field is not a [typeName].
   ///
   /// Returns `null` if [field] does not have a node in [_document].
-  YamlNode? _getNode(
+  YamlNode /*?*/ _getNode(
       String field, String typeName, bool Function(dynamic) typeTest) {
     var node = _document.nodes[field];
     if (node == null) return null;
@@ -473,30 +476,32 @@
   }
 
   /// Asserts that [field] is an int and returns its value.
-  int? _getInt(String field) =>
-      _getValue(field, 'int', (value) => value is int?) as int?;
+  int /*?*/ _getInt(String field) =>
+      _getValue(field, 'int', (value) => value is int /*?*/) as int /*?*/;
 
   /// Asserts that [field] is a non-negative int and returns its value.
-  int? _getNonNegativeInt(String field) =>
+  int /*?*/ _getNonNegativeInt(String field) =>
       _getValue(field, 'non-negative int', (value) {
         if (value == null) return true;
         return value is int && value >= 0;
-      }) as int?;
+      }) as int /*?*/;
 
   /// Asserts that [field] is a boolean and returns its value.
-  bool? _getBool(String field) =>
-      _getValue(field, 'boolean', (value) => value is bool?) as bool?;
+  bool /*?*/ _getBool(String field) =>
+      _getValue(field, 'boolean', (value) => value is bool /*?*/) as bool /*?*/;
 
   /// Asserts that [field] is a string and returns its value.
-  String? _getString(String field) =>
-      _getValue(field, 'string', (value) => value is String?) as String?;
+  String /*?*/ _getString(String field) =>
+      _getValue(field, 'string', (value) => value is String /*?*/)
+          as String /*?*/;
 
   /// Asserts that [field] is a list and runs [forElement] for each element it
   /// contains.
   ///
   /// Returns a list of values returned by [forElement].
   List<T> _getList<T>(String field, T Function(YamlNode) forElement) {
-    var node = _getNode(field, 'list', (value) => value is List) as YamlList?;
+    var node =
+        _getNode(field, 'list', (value) => value is List) as YamlList /*?*/;
     if (node == null) return [];
     return node.nodes.map(forElement).toList();
   }
@@ -506,8 +511,8 @@
   /// Returns a map with the keys and values returned by [key] and [value]. Each
   /// of these defaults to asserting that the value is a string.
   Map<K, V> _getMap<K, V>(String field,
-      {K Function(YamlNode)? key, V Function(YamlNode)? value}) {
-    var node = _getNode(field, 'map', (value) => value is Map) as YamlMap?;
+      {K Function(YamlNode) /*?*/ key, V Function(YamlNode) /*?*/ value}) {
+    var node = _getNode(field, 'map', (value) => value is Map) as YamlMap /*?*/;
     if (node == null) return {};
 
     key ??= (keyNode) {
@@ -525,7 +530,7 @@
     };
 
     return node.nodes.map((keyNode, valueNode) =>
-        MapEntry(key!(keyNode as YamlNode), value!(valueNode)));
+        MapEntry(key(keyNode as YamlNode), value(valueNode)));
   }
 
   /// Verifies that [node]'s value is an optionally hyphenated Dart identifier,
@@ -538,11 +543,11 @@
   }
 
   /// Parses [node]'s value as a boolean selector.
-  BooleanSelector? _parseBooleanSelector(String name) =>
+  BooleanSelector /*?*/ _parseBooleanSelector(String name) =>
       _parseValue(name, (value) => BooleanSelector.parse(value));
 
   /// Parses [node]'s value as a platform selector.
-  PlatformSelector? _parsePlatformSelector(String field) {
+  PlatformSelector /*?*/ _parsePlatformSelector(String field) {
     var node = _document.nodes[field];
     if (node == null) return null;
     return _parseNode(
@@ -570,7 +575,7 @@
   ///
   /// If [parse] throws a [FormatException], it's wrapped to include [field]'s
   /// span.
-  T? _parseValue<T>(String field, T Function(String) parse) {
+  T /*?*/ _parseValue<T>(String field, T Function(String) parse) {
     var node = _document.nodes[field];
     if (node == null) return null;
     return _parseNode(node, field, parse);
@@ -581,8 +586,8 @@
   /// [name] is the name of the field, which is used for error-handling.
   /// [runnerConfig] controls whether runner configuration is allowed in the
   /// nested configuration. It defaults to [_runnerConfig].
-  Configuration _nestedConfig(YamlNode? node, String name,
-      {bool? runnerConfig}) {
+  Configuration _nestedConfig(YamlNode /*?*/ node, String name,
+      {bool /*?*/ runnerConfig}) {
     if (node == null || node.value == null) return Configuration.empty;
 
     _validate(node, '$name must be a map.', (value) => value is Map);
@@ -644,8 +649,9 @@
   }
 
   /// Throws a [SourceSpanFormatException] with [message] about [field].
+  @alwaysThrows
   void _error(String message, String field) {
     throw SourceSpanFormatException(
-        message, _document.nodes[field]!.span, _source);
+        message, _document.nodes[field].span, _source);
   }
 }
diff --git a/test_core/lib/src/runner/configuration/reporters.dart b/test_core/lib/src/runner/configuration/reporters.dart
index 331a113..231b7ba 100644
--- a/test_core/lib/src/runner/configuration/reporters.dart
+++ b/test_core/lib/src/runner/configuration/reporters.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2017, 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.9
 
 import 'dart:collection';
 import 'dart:io';
diff --git a/test_core/lib/src/runner/configuration/runtime_settings.dart b/test_core/lib/src/runner/configuration/runtime_settings.dart
index 6e910a3..a798499 100644
--- a/test_core/lib/src/runner/configuration/runtime_settings.dart
+++ b/test_core/lib/src/runner/configuration/runtime_settings.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2017, 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.9
 
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
diff --git a/test_core/lib/src/runner/configuration/values.dart b/test_core/lib/src/runner/configuration/values.dart
index 6e2f50a..360a503 100644
--- a/test_core/lib/src/runner/configuration/values.dart
+++ b/test_core/lib/src/runner/configuration/values.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:io';
 import 'dart:math' as math;
diff --git a/test_core/lib/src/runner/debugger.dart b/test_core/lib/src/runner/debugger.dart
index f4f1552..30daef7 100644
--- a/test_core/lib/src/runner/debugger.dart
+++ b/test_core/lib/src/runner/debugger.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:async';
 
@@ -27,7 +29,7 @@
 /// any resources it allocated.
 CancelableOperation debug(
     Engine engine, Reporter reporter, LoadSuite loadSuite) {
-  _Debugger? debugger;
+  _Debugger /*?*/ debugger;
   var canceled = false;
   return CancelableOperation.fromFuture(() async {
     // Make the underlying suite null so that the engine doesn't start running
@@ -45,7 +47,7 @@
     canceled = true;
     // Make sure the load test finishes so the engine can close.
     engine.resume();
-    if (debugger != null) debugger!.close();
+    if (debugger != null) debugger.close();
   });
 }
 
@@ -76,10 +78,10 @@
   final _pauseCompleter = CancelableCompleter();
 
   /// The subscription to [_suite.onDebugging].
-  StreamSubscription<bool>? _onDebuggingSubscription;
+  StreamSubscription<bool> /*?*/ _onDebuggingSubscription;
 
   /// The subscription to [_suite.environment.onRestart].
-  late final StreamSubscription _onRestartSubscription;
+  /*late final*/ StreamSubscription _onRestartSubscription;
 
   /// Whether [close] has been called.
   bool _closed = false;
diff --git a/test_core/lib/src/runner/loader.dart b/test_core/lib/src/runner/loader.dart
index 660c2e2..9e93945 100644
--- a/test_core/lib/src/runner/loader.dart
+++ b/test_core/lib/src/runner/loader.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 import 'dart:io';
@@ -107,8 +109,8 @@
       }
 
       var runtime = parent.extend(customRuntime.name, customRuntime.identifier);
-      _platformPlugins[runtime] = _platformPlugins[parent]!;
-      _platformCallbacks[runtime] = _platformCallbacks[parent]!;
+      _platformPlugins[runtime] = _platformPlugins[parent];
+      _platformCallbacks[runtime] = _platformCallbacks[parent];
       _runtimesByIdentifier[runtime.identifier] = runtime;
 
       _runtimeSettings[runtime] = [customRuntime.settings];
@@ -119,15 +121,14 @@
   void _registerRuntimeOverrides() {
     for (var settings in _config.overrideRuntimes.values) {
       var runtime = _runtimesByIdentifier[settings.identifier];
-      _runtimeSettings
-          .putIfAbsent(runtime!, () => [])
-          .addAll(settings.settings);
+      _runtimeSettings.putIfAbsent(runtime, () => []).addAll(settings.settings);
     }
   }
 
   /// Returns the [Runtime] registered with this loader that's identified
   /// by [identifier], or `null` if none can be found.
-  Runtime? findRuntime(String identifier) => _runtimesByIdentifier[identifier];
+  Runtime /*?*/ findRuntime(String identifier) =>
+      _runtimesByIdentifier[identifier];
 
   /// Loads all test suites in [dir] according to [suiteConfig].
   ///
@@ -188,7 +189,7 @@
       var runtime = findRuntime(runtimeName);
       assert(runtime != null, 'Unknown platform "$runtimeName".');
 
-      var platform = currentPlatform(runtime!);
+      var platform = currentPlatform(runtime);
       if (!suiteConfig.metadata.testOn.evaluate(platform)) {
         continue;
       }
@@ -213,13 +214,13 @@
                   : 'loading ') +
               path;
       yield LoadSuite(name, platformConfig, platform, () async {
-        var memo = _platformPlugins[platform.runtime]!;
+        var memo = _platformPlugins[platform.runtime];
 
         var retriesLeft = suiteConfig.metadata.retry;
         while (true) {
           try {
             var plugin =
-                await memo.runOnce(_platformCallbacks[platform.runtime]!);
+                await memo.runOnce(_platformCallbacks[platform.runtime]);
             _customizePlatform(plugin, platform.runtime);
             var suite = await plugin.load(path, platform, platformConfig,
                 {'platformVariables': _runtimeVariables.toList()});
@@ -259,16 +260,16 @@
           .map(plugin.parsePlatformSettings)
           .reduce(plugin.mergePlatformSettings);
       plugin.customizePlatform(runtime, parsed);
-      _parsedRuntimeSettings[runtime] = parsed!;
+      _parsedRuntimeSettings[runtime] = parsed;
     } else {
       String identifier;
       SourceSpan span;
       if (runtime.isChild) {
-        identifier = runtime.parent!.identifier;
-        span = _config.defineRuntimes[runtime.identifier]!.parentSpan;
+        identifier = runtime.parent.identifier;
+        span = _config.defineRuntimes[runtime.identifier].parentSpan;
       } else {
         identifier = runtime.identifier;
-        span = _config.overrideRuntimes[runtime.identifier]!.identifierSpan;
+        span = _config.overrideRuntimes[runtime.identifier].identifierSpan;
       }
 
       throw SourceSpanFormatException(
diff --git a/test_core/lib/src/runner/plugin/customizable_platform.dart b/test_core/lib/src/runner/plugin/customizable_platform.dart
index 354a2ca..058eb95 100644
--- a/test_core/lib/src/runner/plugin/customizable_platform.dart
+++ b/test_core/lib/src/runner/plugin/customizable_platform.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2017, 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.9
 
 import 'package:yaml/yaml.dart';
 
diff --git a/test_core/lib/src/runner/plugin/platform_helpers.dart b/test_core/lib/src/runner/plugin/platform_helpers.dart
index 8ecbcfe..6a8ee9e 100644
--- a/test_core/lib/src/runner/plugin/platform_helpers.dart
+++ b/test_core/lib/src/runner/plugin/platform_helpers.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:async';
 import 'dart:io';
@@ -44,7 +46,7 @@
     Environment environment,
     StreamChannel channel,
     Object message,
-    {Future<Map<String, dynamic>> Function()? gatherCoverage}) {
+    {Future<Map<String, dynamic>> Function() /*?*/ gatherCoverage}) {
   var disconnector = Disconnector();
   var suiteChannel = MultiChannel(channel.transform(disconnector));
 
@@ -132,7 +134,7 @@
         (group['entries'] as List).map((entry) {
           var map = entry as Map;
           if (map['type'] == 'group') return deserializeGroup(map);
-          return _deserializeTest(map)!;
+          return _deserializeTest(map);
         }),
         metadata: metadata,
         trace: group['trace'] == null
@@ -145,7 +147,7 @@
   /// Deserializes [test] into a concrete [Test] class.
   ///
   /// Returns `null` if [test] is `null`.
-  Test? _deserializeTest(Map? test) {
+  Test /*?*/ _deserializeTest(Map /*?*/ test) {
     if (test == null) return null;
 
     var metadata = Metadata.deserialize(test['metadata']);
diff --git a/test_core/lib/src/runner/reporter/json.dart b/test_core/lib/src/runner/reporter/json.dart
index b179407..11710da 100644
--- a/test_core/lib/src/runner/reporter/json.dart
+++ b/test_core/lib/src/runner/reporter/json.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:async';
 import 'dart:convert';
@@ -143,7 +145,7 @@
           },
           liveTest.test,
           liveTest.suite.platform.runtime,
-          liveTest.suite.path!)
+          liveTest.suite.path)
     });
 
     // Convert the future to a stream so that the subscription can be paused or
@@ -168,7 +170,7 @@
   /// If [suite] doesn't have an ID yet, this assigns one and emits a new event
   /// for that suite.
   int _idForSuite(Suite suite) {
-    if (_suiteIDs.containsKey(suite)) return _suiteIDs[suite]!;
+    if (_suiteIDs.containsKey(suite)) return _suiteIDs[suite];
 
     var id = _nextID++;
     _suiteIDs[suite] = id;
@@ -193,7 +195,7 @@
     }
 
     _emit('suite', {
-      'suite': <String, Object?>{
+      'suite': <String, Object /*?*/ >{
         'id': id,
         'platform': suite.platform.runtime.identifier,
         'path': suite.path
@@ -208,11 +210,11 @@
   /// If a group doesn't have an ID yet, this assigns one and emits a new event
   /// for that group.
   List<int> _idsForGroups(Iterable<Group> groups, Suite suite) {
-    int? parentID;
+    int /*?*/ parentID;
     return groups.map((group) {
       if (_groupIDs.containsKey(group)) {
-        parentID = _groupIDs[group]!;
-        return parentID!;
+        parentID = _groupIDs[group];
+        return parentID;
       }
 
       var id = _nextID++;
@@ -232,7 +234,7 @@
             },
             group,
             suite.platform.runtime,
-            suite.path!)
+            suite.path)
       });
       parentID = id;
       return id;
@@ -272,7 +274,7 @@
   ///
   /// [success] will be `true` if all tests passed, `false` if some tests
   /// failed, and `null` if the engine was closed prematurely.
-  void _onDone(bool? success) {
+  void _onDone(bool /*?*/ success) {
     _cancel();
     _stopwatch.stop();
 
@@ -303,8 +305,8 @@
       GroupEntry entry,
       Runtime runtime,
       String suitePath) {
-    var frame = entry.trace?.frames.first;
-    Frame? rootFrame;
+    var frame = entry.trace?.frames?.first;
+    Frame /*?*/ rootFrame;
     for (var frame in entry.trace?.frames ?? <Frame>[]) {
       if (frame.uri.scheme == 'file' &&
           frame.uri.toFilePath() == p.absolute(suitePath)) {
@@ -320,7 +322,7 @@
 
     map['line'] = frame?.line;
     map['column'] = frame?.column;
-    map['url'] = frame?.uri.toString();
+    map['url'] = frame?.uri?.toString();
     if (rootFrame != null && rootFrame != frame) {
       map['root_line'] = rootFrame.line;
       map['root_column'] = rootFrame.column;
diff --git a/test_core/lib/src/runner/runner_test.dart b/test_core/lib/src/runner/runner_test.dart
index 2093212..156e528 100644
--- a/test_core/lib/src/runner/runner_test.dart
+++ b/test_core/lib/src/runner/runner_test.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'package:pedantic/pedantic.dart';
 import 'package:stack_trace/stack_trace.dart';
@@ -25,7 +27,7 @@
   @override
   final Metadata metadata;
   @override
-  final Trace? trace;
+  final Trace /*?*/ trace;
 
   /// The channel used to communicate with the test's [IframeListener].
   final MultiChannel _channel;
@@ -35,9 +37,9 @@
   RunnerTest._(this.name, this.metadata, this.trace, this._channel);
 
   @override
-  LiveTest load(Suite suite, {Iterable<Group>? groups}) {
-    late final LiveTestController controller;
-    late final VirtualChannel testChannel;
+  LiveTest load(Suite suite, {Iterable<Group> /*?*/ groups}) {
+    /*late final*/ LiveTestController controller;
+    /*late final*/ VirtualChannel testChannel;
     controller = LiveTestController(suite, this, () {
       controller.setState(const State(Status.running, Result.success));
 
@@ -71,7 +73,7 @@
             // When we kill the isolate that the test lives in, that will close
             // this virtual channel and cause the spawned isolate to close as
             // well.
-            spawnHybridUri(message['url'] as String, message['message'])
+            spawnHybridUri(message['url'] as String, message['message'], suite)
                 .pipe(testChannel.virtualChannel(message['channel'] as int));
             break;
         }
@@ -101,7 +103,7 @@
   }
 
   @override
-  Test? forPlatform(SuitePlatform platform) {
+  Test /*?*/ forPlatform(SuitePlatform platform) {
     if (!metadata.testOn.evaluate(platform)) return null;
     return RunnerTest._(name, metadata.forPlatform(platform), trace, _channel);
   }
diff --git a/test_core/lib/src/runner/spawn_hybrid.dart b/test_core/lib/src/runner/spawn_hybrid.dart
index 768146b..14b537c 100644
--- a/test_core/lib/src/runner/spawn_hybrid.dart
+++ b/test_core/lib/src/runner/spawn_hybrid.dart
@@ -1,16 +1,23 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:async';
+import 'dart:io';
 import 'dart:isolate';
 
+import 'package:analyzer/dart/analysis/utilities.dart';
 import 'package:async/async.dart';
+import 'package:path/path.dart' as p;
 import 'package:stream_channel/isolate_channel.dart';
 import 'package:stream_channel/stream_channel.dart';
 
 import '../util/dart.dart' as dart;
+import '../util/package_config.dart';
 
+import 'package:test_api/src/backend/suite.dart'; // ignore: implementation_imports
 import 'package:test_api/src/util/remote_exception.dart'; // ignore: implementation_imports
 
 /// Spawns a hybrid isolate from [url] with the given [message], and returns a
@@ -19,12 +26,23 @@
 /// This connects the main isolate to the hybrid isolate, whereas
 /// `lib/src/frontend/spawn_hybrid.dart` connects the test isolate to the main
 /// isolate.
-StreamChannel spawnHybridUri(String url, Object? message) {
+///
+/// If [uri] is relative, it will be interpreted relative to the `file:` URL
+/// for [suite]. If it's root-relative (that is, if it begins with `/`) it will
+/// be interpreted relative to the root of the package (the directory that
+/// contains `pubspec.yaml`, *not* the `test/` directory). If it's a `package:`
+/// URL, it will be resolved using the current package's dependency
+/// constellation.
+StreamChannel /*!*/ spawnHybridUri(
+    String url, Object /*?*/ message, Suite suite) {
+  url = _normalizeUrl(url, suite);
   return StreamChannelCompleter.fromFuture(() async {
     var port = ReceivePort();
     var onExitPort = ReceivePort();
     try {
       var code = '''
+        ${await _languageVersionCommentFor(url)}
+
         import "package:test_core/src/runner/hybrid_listener.dart";
 
         import "${url.replaceAll(r'$', '%24')}" as lib;
@@ -64,3 +82,75 @@
     }
   }());
 }
+
+/// Normalizes [url] to an absolute url, or returns it as is if it has a
+/// scheme.
+///
+/// Follows the rules for relatives/absolute paths outlit
+String _normalizeUrl(String url, Suite suite) {
+  final parsedUri = Uri.parse(url);
+
+  if (parsedUri.scheme.isEmpty) {
+    var isRootRelative = parsedUri.path.startsWith('/');
+
+    if (isRootRelative) {
+      // We assume that the current path is the package root. `pub run`
+      // enforces this currently, but at some point it would probably be good
+      // to pass in an explicit root.
+      return p.url
+          .join(p.toUri(p.current).toString(), parsedUri.path.substring(1));
+    } else {
+      var suitePath = suite.path;
+      return p.url.join(
+          p.url.dirname(p.toUri(p.absolute(suitePath)).toString()),
+          parsedUri.toString());
+    }
+  } else {
+    return url;
+  }
+}
+
+/// Computes the a language version comment for the library at [uri].
+///
+/// If there is a language version comment in the file, that is returned.
+///
+/// Otherwise a comment representing the default version from the
+/// [currentPackageConfig] is returned.
+///
+/// If no default language version is known (data: uri for instance), then
+/// an empty string is returned.
+Future<String> _languageVersionCommentFor(String url) async {
+  var parsedUri = Uri.parse(url);
+
+  // Returns the explicit language version comment if one exists.
+  var result = parseString(
+      content: await _readUri(parsedUri),
+      path: parsedUri.path,
+      throwIfDiagnostics: false);
+  var languageVersionComment = result.unit.languageVersionToken?.value();
+  if (languageVersionComment != null) return languageVersionComment.toString();
+
+  // Returns the default language version for the package if one exists.
+  if (parsedUri.scheme.isEmpty || parsedUri.scheme == 'file') {
+    var packageConfig = await currentPackageConfig;
+    var package = packageConfig.packageOf(parsedUri);
+    var version = package?.languageVersion;
+    if (version != null) return '// @dart=${version}';
+  }
+
+  // Fall back on no language comment.
+  return '';
+}
+
+Future<String> _readUri(Uri uri) async {
+  switch (uri.scheme) {
+    case '':
+    case 'file':
+      return File.fromUri(uri).readAsString();
+    case 'data':
+      return uri.data.contentAsString();
+    default:
+      throw ArgumentError.value(uri, 'uri',
+          'Only data and file uris (as well as relative paths) are supported');
+  }
+}
diff --git a/test_core/lib/src/runner/version.dart b/test_core/lib/src/runner/version.dart
index 3eab242..5c617cf 100644
--- a/test_core/lib/src/runner/version.dart
+++ b/test_core/lib/src/runner/version.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:io';
 
@@ -10,7 +12,7 @@
 ///
 /// This is a semantic version, optionally followed by a space and additional
 /// data about its source.
-final String? testVersion = (() {
+final String /*?*/ testVersion = (() {
   dynamic lockfile;
   try {
     lockfile = loadYaml(File('pubspec.lock').readAsStringSync());
@@ -29,7 +31,7 @@
   var source = package['source'];
   if (source is! String) return null;
 
-  switch (source) {
+  switch (source as String) {
     case 'hosted':
       var version = package['version'];
       return (version is String) ? version : null;
diff --git a/test_core/lib/src/runner/vm/environment.dart b/test_core/lib/src/runner/vm/environment.dart
index 8313916..fb75c66 100644
--- a/test_core/lib/src/runner/vm/environment.dart
+++ b/test_core/lib/src/runner/vm/environment.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+//
+// @dart=2.9
 
 import 'dart:async';
 
@@ -22,7 +24,7 @@
   VMEnvironment(this.observatoryUrl, this._isolate, this._client);
 
   @override
-  Uri? get remoteDebuggerUrl => null;
+  Uri /*?*/ get remoteDebuggerUrl => null;
 
   @override
   Stream get onRestart => StreamController.broadcast().stream;
diff --git a/test_core/lib/src/runner/vm/platform.dart b/test_core/lib/src/runner/vm/platform.dart
index 0401738..dcdb849 100644
--- a/test_core/lib/src/runner/vm/platform.dart
+++ b/test_core/lib/src/runner/vm/platform.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.9
 
 import 'dart:async';
 import 'dart:developer';
@@ -54,8 +56,8 @@
       rethrow;
     }
 
-    VmService? client;
-    StreamSubscription<Event>? eventSub;
+    VmService /*?*/ client;
+    StreamSubscription<Event> /*?*/ eventSub;
     var channel = IsolateChannel.connectReceive(receivePort)
         .transformStream(StreamTransformer.fromHandlers(handleDone: (sink) {
       isolate.kill();
@@ -64,12 +66,12 @@
       sink.close();
     }));
 
-    Environment? environment;
-    IsolateRef? isolateRef;
+    Environment /*?*/ environment;
+    IsolateRef /*?*/ isolateRef;
     if (_config.debug) {
       var info =
           await Service.controlWebServer(enable: true, silenceOutput: true);
-      var isolateID = Service.getIsolateID(isolate)!;
+      var isolateID = Service.getIsolateID(isolate);
 
       var libraryPath = p.toUri(p.absolute(path)).toString();
       client = await vmServiceConnectUri(_wsUriFor(info.serverUri.toString()));
@@ -90,10 +92,10 @@
 
     var controller = deserializeSuite(
         path, platform, suiteConfig, environment, channel, message,
-        gatherCoverage: () => _gatherCoverage(environment!));
+        gatherCoverage: () => _gatherCoverage(environment));
 
     if (isolateRef != null) {
-      await client!.streamListen('Debug');
+      await client.streamListen('Debug');
       eventSub = client.onDebugEvent.listen((event) {
         if (event.kind == EventKind.kResume) {
           controller.setDebugging(false);
@@ -118,7 +120,7 @@
     if (precompiledPath != null) {
       return _spawnPrecompiledIsolate(path, message, precompiledPath);
     } else if (_config.pubServeUrl != null) {
-      return _spawnPubServeIsolate(path, message, _config.pubServeUrl!);
+      return _spawnPubServeIsolate(path, message, _config.pubServeUrl);
     } else {
       return _spawnDataIsolate(path, message, suiteMetadata);
     }
@@ -155,8 +157,8 @@
 }
 
 Future<Map<String, dynamic>> _gatherCoverage(Environment environment) async {
-  final isolateId = Uri.parse(environment.observatoryUrl!.fragment)
-      .queryParameters['isolateId']!;
+  final isolateId = Uri.parse(environment.observatoryUrl.fragment)
+      .queryParameters['isolateId'];
   return await collect(environment.observatoryUrl, false, false, false, {},
       isolateIds: {isolateId});
 }
diff --git a/test_core/lib/src/util/dart.dart b/test_core/lib/src/util/dart.dart
index a3e83ef..fd8aeed 100644
--- a/test_core/lib/src/util/dart.dart
+++ b/test_core/lib/src/util/dart.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:convert';
 import 'dart:isolate';
@@ -17,7 +19,7 @@
 /// passed to the [main] method of the code being run; the caller is responsible
 /// for using this to establish communication with the isolate.
 Future<Isolate> runInIsolate(String code, Object message,
-        {SendPort? onExit}) async =>
+        {SendPort /*?*/ onExit}) async =>
     Isolate.spawnUri(
         Uri.dataFromString(code, mimeType: 'application/dart', encoding: utf8),
         [],
@@ -51,7 +53,7 @@
 ///
 /// This will return `null` if [context] contains an invalid string or does not
 /// contain [span].
-SourceSpan? contextualizeSpan(
+SourceSpan /*?*/ contextualizeSpan(
     SourceSpan span, StringLiteral context, SourceFile file) {
   var contextRunes = StringLiteralIterator(context)..moveNext();
 
diff --git a/test_core/lib/src/util/package_config.dart b/test_core/lib/src/util/package_config.dart
new file mode 100644
index 0000000..b3743f8
--- /dev/null
+++ b/test_core/lib/src/util/package_config.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, 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.7
+
+import 'dart:isolate';
+
+import 'package:package_config/package_config.dart';
+
+/// The [PackageConfig] parsed from the current isolates package config file.
+final Future<PackageConfig> currentPackageConfig = () async {
+  return loadPackageConfigUri(await Isolate.packageConfig);
+}();
diff --git a/test_core/lib/src/util/string_literal_iterator.dart b/test_core/lib/src/util/string_literal_iterator.dart
index beeac22..5058028 100644
--- a/test_core/lib/src/util/string_literal_iterator.dart
+++ b/test_core/lib/src/util/string_literal_iterator.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, 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.9
 
 import 'dart:collection';
 
@@ -38,23 +40,23 @@
 /// exposes the offset of the current rune in the Dart source file.
 class StringLiteralIterator extends Iterator<int> {
   @override
-  int get current => _current!;
-  int? _current;
+  int get current => _current;
+  int /*?*/ _current;
 
   /// The offset of the beginning of [current] in the Dart source file that
   /// contains the string literal.
   ///
   /// Before iteration begins, this points to the character before the first
   /// rune.
-  int get offset => _offset!;
-  int? _offset;
+  int get offset => _offset;
+  int /*?*/ _offset;
 
   /// The offset of the next rune.
   ///
   /// This isn't necessarily just `offset + 1`, since a single rune may be
   /// represented by multiple characters in the source file, or a string literal
   /// may be composed of several adjacent string literals.
-  int? _nextOffset;
+  int /*?*/ _nextOffset;
 
   /// All [SimpleStringLiteral]s that compose the input literal.
   ///
@@ -66,13 +68,13 @@
   /// Whether this is a raw string that begins with `r`.
   ///
   /// This is necessary for knowing how to parse escape sequences.
-  bool? _isRaw;
+  bool /*?*/ _isRaw;
 
   /// The iterator over the runes in the Dart source file.
   ///
   /// When switching to a new string in [_strings], this is updated to point to
   /// that string's component runes.
-  Iterator<int>? _runes;
+  Iterator<int> /*?*/ _runes;
 
   /// Creates a new [StringLiteralIterator] iterating over the contents of
   /// [literal].
@@ -101,7 +103,7 @@
   bool moveNext() {
     // If we're at beginning of a [SimpleStringLiteral], move forward until
     // there's actually text to consume.
-    while (_runes == null || _runes!.current == -1) {
+    while (_runes == null || _runes.current == -1) {
       if (_strings.isEmpty) {
         // Move the offset past the end of the text.
         _offset = _nextOffset;
@@ -122,7 +124,7 @@
       _nextOffset = string.contentsOffset;
       _isRaw = string.isRaw;
       _runes = text.runes.iterator;
-      _runes!.moveNext();
+      _runes.moveNext();
     }
 
     _offset = _nextOffset;
@@ -135,9 +137,9 @@
   }
 
   /// Consume and return the next rune.
-  int? _nextRune() {
-    if (_isRaw! || _runes!.current != _backslash) {
-      var rune = _runes!.current;
+  int /*?*/ _nextRune() {
+    if (_isRaw || _runes.current != _backslash) {
+      var rune = _runes.current;
       _moveRunesNext();
       return (rune < 0) ? null : rune;
     }
@@ -150,8 +152,8 @@
   ///
   /// This assumes that a backslash has already been consumed. It leaves the
   /// [_runes] cursor on the first character after the escape sequence.
-  int? _parseEscapeSequence() {
-    switch (_runes!.current) {
+  int /*?*/ _parseEscapeSequence() {
+    switch (_runes.current) {
       case _n:
         _moveRunesNext();
         return _newline;
@@ -175,15 +177,15 @@
         return _parseHex(2);
       case _u:
         if (!_moveRunesNext()) return null;
-        if (_runes!.current != _openCurly) return _parseHex(4);
+        if (_runes.current != _openCurly) return _parseHex(4);
         if (!_moveRunesNext()) return null;
 
         var number = _parseHexSequence();
-        if (_runes!.current != _closeCurly) return null;
+        if (_runes.current != _closeCurly) return null;
         if (!_moveRunesNext()) return null;
         return number;
       default:
-        var rune = _runes!.current;
+        var rune = _runes.current;
         _moveRunesNext();
         return rune;
     }
@@ -194,15 +196,15 @@
   ///
   /// This parses digits as they appear in a unicode escape sequence: one to six
   /// hex digits.
-  int? _parseHexSequence() {
-    var number = _parseHexDigit(_runes!.current);
+  int /*?*/ _parseHexSequence() {
+    var number = _parseHexDigit(_runes.current);
     if (number == null) return null;
     if (!_moveRunesNext()) return null;
 
     for (var i = 0; i < 5; i++) {
-      var digit = _parseHexDigit(_runes!.current);
+      var digit = _parseHexDigit(_runes.current);
       if (digit == null) break;
-      number = number! * 16 + digit;
+      number = number * 16 + digit;
       if (!_moveRunesNext()) return null;
     }
 
@@ -210,11 +212,11 @@
   }
 
   /// Parses [digits] hexadecimal digits and returns their value as an [int].
-  int? _parseHex(int digits) {
+  int /*?*/ _parseHex(int digits) {
     var number = 0;
     for (var i = 0; i < digits; i++) {
-      if (_runes!.current == -1) return null;
-      var digit = _parseHexDigit(_runes!.current);
+      if (_runes.current == -1) return null;
+      var digit = _parseHexDigit(_runes.current);
       if (digit == null) return null;
       number = number * 16 + digit;
       _moveRunesNext();
@@ -223,7 +225,7 @@
   }
 
   /// Parses a single hexadecimal digit.
-  int? _parseHexDigit(int rune) {
+  int /*?*/ _parseHexDigit(int rune) {
     if (rune < _zero) return null;
     if (rune <= _nine) return rune - _zero;
     if (rune < _capitalA) return null;
@@ -235,8 +237,8 @@
 
   /// Move [_runes] to the next rune and update [_nextOffset].
   bool _moveRunesNext() {
-    var result = _runes!.moveNext();
-    _nextOffset = _nextOffset! + 1;
+    var result = _runes.moveNext();
+    _nextOffset = _nextOffset + 1;
     return result;
   }
 }
diff --git a/test_core/pubspec.yaml b/test_core/pubspec.yaml
index eca9cd3..5951615 100644
--- a/test_core/pubspec.yaml
+++ b/test_core/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test_core
-version: 0.3.12-nullsafety.8
+version: 0.3.12-nullsafety.9
 description: A basic library for writing tests and running them on the VM.
 homepage: https://github.com/dart-lang/test/blob/master/pkgs/test_core
 
@@ -30,8 +30,4 @@
   # matcher is tightly constrained by test_api
   matcher: any
   # Use an exact version until the test_api package is stable.
-  test_api: 0.2.19-nullsafety.5
-
-# dependency_overrides:
-#   test_api:
-#     path: ../test_api
+  test_api: 0.2.19-nullsafety.6
diff --git a/webkit_inspection_protocol/BUILD.gn b/webkit_inspection_protocol/BUILD.gn
index 7f4f83f..e956047 100644
--- a/webkit_inspection_protocol/BUILD.gn
+++ b/webkit_inspection_protocol/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for webkit_inspection_protocol-0.7.3
+# This file is generated by importer.py for webkit_inspection_protocol-0.7.4
 
 import("//build/dart/dart_library.gni")
 
diff --git a/webkit_inspection_protocol/changelog.md b/webkit_inspection_protocol/changelog.md
index bbc1c03..67f7f92 100644
--- a/webkit_inspection_protocol/changelog.md
+++ b/webkit_inspection_protocol/changelog.md
@@ -1,5 +1,8 @@
 # webkit_inspection_protocol.dart
 
+## 0.7.4
+- Support `params` to `stepInto` and `stepOver`. 
+
 ## 0.7.3
 - Fix a type issue with `GlobalObjectClearedEvent`s 
 
diff --git a/webkit_inspection_protocol/lib/src/debugger.dart b/webkit_inspection_protocol/lib/src/debugger.dart
index e9abe65..a98f2c9 100644
--- a/webkit_inspection_protocol/lib/src/debugger.dart
+++ b/webkit_inspection_protocol/lib/src/debugger.dart
@@ -32,11 +32,13 @@
 
   Future<WipResponse> resume() => sendCommand('Debugger.resume');
 
-  Future<WipResponse> stepInto() => sendCommand('Debugger.stepInto');
+  Future<WipResponse> stepInto({Map<String, dynamic> params}) =>
+      sendCommand('Debugger.stepInto', params: params);
 
   Future<WipResponse> stepOut() => sendCommand('Debugger.stepOut');
 
-  Future<WipResponse> stepOver() => sendCommand('Debugger.stepOver');
+  Future<WipResponse> stepOver({Map<String, dynamic> params}) =>
+      sendCommand('Debugger.stepOver', params: params);
 
   Future<WipResponse> setPauseOnExceptions(PauseState state) {
     return sendCommand('Debugger.setPauseOnExceptions',
diff --git a/webkit_inspection_protocol/pubspec.yaml b/webkit_inspection_protocol/pubspec.yaml
index 5a601ca..99fa1a9 100644
--- a/webkit_inspection_protocol/pubspec.yaml
+++ b/webkit_inspection_protocol/pubspec.yaml
@@ -1,5 +1,5 @@
 name: webkit_inspection_protocol
-version: 0.7.3
+version: 0.7.4
 description: A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol).
 homepage: https://github.com/google/webkit_inspection_protocol.dart