Complete the null safety migration of test_core (#1443)

Requires all null safety deps and migrates all remaining libraries.

Also includes a sound null safety fix for test_api.
diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md
index b88f803..fade26f 100644
--- a/pkgs/test/CHANGELOG.md
+++ b/pkgs/test/CHANGELOG.md
@@ -1,3 +1,5 @@
+## 1.16.6-dev
+
 ## 1.16.5
 
 * Expand several deps to allow the latest versions.
diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml
index e0f74ca..ce998f8 100644
--- a/pkgs/test/pubspec.yaml
+++ b/pkgs/test/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test
-version: 1.16.5
+version: 1.16.6-dev
 description: A full featured library for writing and running Dart tests.
 repository: https://github.com/dart-lang/test/blob/master/pkgs/test
 
@@ -31,7 +31,7 @@
   webkit_inspection_protocol: '>=0.5.0 <2.0.0'
   yaml: '>=2.0.0 <4.0.0'
   # Use an exact version until the test_api and test_core package are stable.
-  test_api: 0.2.19
+  test_api: 0.2.20
   test_core: 0.3.15
 
 dev_dependencies:
diff --git a/pkgs/test/test/common.dart b/pkgs/test/test/common.dart
index 4d397da..abdb5e5 100644
--- a/pkgs/test/test/common.dart
+++ b/pkgs/test/test/common.dart
@@ -1,8 +1,6 @@
 // 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 'package:test/test.dart';
 
-dynamic myTest(String name, Function() testFn) => test(name, testFn);
+void myTest(String name, Function() testFn) => test(name, testFn);
diff --git a/pkgs/test/test/io.dart b/pkgs/test/test/io.dart
index 5e12407..1820980 100644
--- a/pkgs/test/test/io.dart
+++ b/pkgs/test/test/io.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 import 'dart:async';
 import 'dart:io';
@@ -18,7 +16,7 @@
 final Future<String> packageDir =
     Isolate.resolvePackageUri(Uri(scheme: 'package', path: 'test/'))
         .then((uri) {
-  var dir = p.dirname(uri.path);
+  var dir = p.dirname(uri!.path);
   if (dir.startsWith('/C:')) dir = dir.substring(1);
   return dir;
 });
@@ -42,8 +40,8 @@
 /// The port of a pub serve instance run via [runPubServe].
 ///
 /// This is only set after [runPubServe] is called.
-int get pubServePort => _pubServePort;
-int _pubServePort;
+int get pubServePort => _pubServePort!;
+int? _pubServePort;
 
 /// Expects that the entire stdout stream of [test] equals [expected].
 void expectStdoutEquals(TestProcess test, String expected) =>
@@ -71,13 +69,13 @@
 
 /// Runs the test executable with the package root set properly.
 Future<TestProcess> runTest(Iterable<String> args,
-    {String reporter,
-    String fileReporter,
-    int concurrency,
-    Map<String, String> environment,
+    {String? reporter,
+    String? fileReporter,
+    int? concurrency,
+    Map<String, String>? environment,
     bool forwardStdio = false,
-    String packageConfig,
-    Iterable<String> vmArgs}) async {
+    String? packageConfig,
+    Iterable<String>? vmArgs}) async {
   concurrency ??= 1;
 
   var allArgs = [
@@ -86,7 +84,7 @@
     '--concurrency=$concurrency',
     if (reporter != null) '--reporter=$reporter',
     if (fileReporter != null) '--file-reporter=$fileReporter',
-    ...?args,
+    ...args,
   ];
 
   environment ??= {};
@@ -104,10 +102,10 @@
 /// If [packageConfig] is provided then that is passed for the `--packages`
 /// arg, otherwise the current isolate config is passed.
 Future<TestProcess> runDart(Iterable<String> args,
-    {Map<String, String> environment,
-    String description,
+    {Map<String, String>? environment,
+    String? description,
     bool forwardStdio = false,
-    String packageConfig}) async {
+    String? packageConfig}) async {
   var allArgs = <String>[
     ...Platform.executableArguments.where((arg) =>
         !arg.startsWith('--package-root=') && !arg.startsWith('--packages=')),
@@ -125,7 +123,7 @@
 
 /// Runs Pub.
 Future<TestProcess> runPub(Iterable<String> args,
-    {Map<String, String> environment}) {
+    {Map<String, String>? environment}) {
   return TestProcess.start(_pubPath, args,
       workingDirectory: d.sandbox,
       environment: environment,
@@ -137,19 +135,19 @@
 /// This returns assigns [_pubServePort] to a future that will complete to the
 /// port of the "pub serve" instance.
 Future<TestProcess> runPubServe(
-    {Iterable<String> args,
-    String workingDirectory,
-    Map<String, String> environment}) async {
+    {Iterable<String>? args,
+    String? workingDirectory,
+    Map<String, String>? environment}) async {
   var allArgs = ['serve', '--port', '0'];
   if (args != null) allArgs.addAll(args);
 
   var pub = await runPub(allArgs, environment: environment);
 
-  Match match;
+  Match? match;
   while (match == null) {
     match = _servingRegExp.firstMatch(await pub.stdout.next);
   }
-  _pubServePort = int.parse(match[1]);
+  _pubServePort = int.parse(match[1]!);
 
   return pub;
 }
diff --git a/pkgs/test/test/runner/browser/code_server.dart b/pkgs/test/test/runner/browser/code_server.dart
index 55ed281..384f871 100644
--- a/pkgs/test/test/runner/browser/code_server.dart
+++ b/pkgs/test/test/runner/browser/code_server.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 import 'dart:async';
 
diff --git a/pkgs/test/test/runner/browser/compact_reporter_test.dart b/pkgs/test/test/runner/browser/compact_reporter_test.dart
index 3539007..4a65f92 100644
--- a/pkgs/test/test/runner/browser/compact_reporter_test.dart
+++ b/pkgs/test/test/runner/browser/compact_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/browser/expanded_reporter_test.dart b/pkgs/test/test/runner/browser/expanded_reporter_test.dart
index fbb4d28..c334843 100644
--- a/pkgs/test/test/runner/browser/expanded_reporter_test.dart
+++ b/pkgs/test/test/runner/browser/expanded_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/browser/firefox_html_test.dart b/pkgs/test/test/runner/browser/firefox_html_test.dart
index 48fb79b..e4b9941 100644
--- a/pkgs/test/test/runner/browser/firefox_html_test.dart
+++ b/pkgs/test/test/runner/browser/firefox_html_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('firefox')
 import 'dart:html';
@@ -14,6 +12,6 @@
   // iframes (https://bugzilla.mozilla.org/show_bug.cgi?id=548397), so we have
   // to do some special stuff to make sure tests that care about that work.
   test('getComputedStyle() works', () {
-    expect(document.body.getComputedStyle(), isNotNull);
+    expect(document.body!.getComputedStyle(), isNotNull);
   });
 }
diff --git a/pkgs/test/test/runner/browser/runner_test.dart b/pkgs/test/test/runner/browser/runner_test.dart
index 577e8a5..ccd12ce 100644
--- a/pkgs/test/test/runner/browser/runner_test.dart
+++ b/pkgs/test/test/runner/browser/runner_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:convert';
diff --git a/pkgs/test/test/runner/compact_reporter_test.dart b/pkgs/test/test/runner/compact_reporter_test.dart
index 1c62a86..8090d24 100644
--- a/pkgs/test/test/runner/compact_reporter_test.dart
+++ b/pkgs/test/test/runner/compact_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -416,7 +414,7 @@
 }
 
 Future<void> _expectReport(String tests, String expected,
-    {List<String> args}) async {
+    {List<String>? args}) async {
   await d.file('test.dart', '''
     import 'dart:async';
 
@@ -435,7 +433,7 @@
 
   // Skip the first CR, remove excess trailing whitespace, and trim off
   // timestamps.
-  String lastLine;
+  String? lastLine;
   var actual = stdoutLines.skip(1).map((line) {
     if (line.startsWith('  ') || line.isEmpty) return line.trimRight();
 
diff --git a/pkgs/test/test/runner/configuration/configuration_test.dart b/pkgs/test/test/runner/configuration/configuration_test.dart
index dc06315..33e44b8 100644
--- a/pkgs/test/test/runner/configuration/configuration_test.dart
+++ b/pkgs/test/test/runner/configuration/configuration_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:path/path.dart' as p;
@@ -57,7 +55,7 @@
         expect(merged.dart2jsPath, equals('/tmp/dart2js'));
         expect(merged.reporter, equals('json'));
         expect(merged.fileReporters, equals({'json': 'out.json'}));
-        expect(merged.pubServeUrl.port, equals(1234));
+        expect(merged.pubServeUrl!.port, equals(1234));
         expect(merged.shardIndex, equals(3));
         expect(merged.totalShards, equals(10));
         expect(merged.paths, equals(['bar']));
@@ -88,7 +86,7 @@
         expect(merged.dart2jsPath, equals('/tmp/dart2js'));
         expect(merged.reporter, equals('json'));
         expect(merged.fileReporters, equals({'json': 'out.json'}));
-        expect(merged.pubServeUrl.port, equals(1234));
+        expect(merged.pubServeUrl!.port, equals(1234));
         expect(merged.shardIndex, equals(3));
         expect(merged.totalShards, equals(10));
         expect(merged.paths, equals(['bar']));
@@ -136,7 +134,7 @@
         expect(merged.dart2jsPath, equals('../dart2js'));
         expect(merged.reporter, equals('compact'));
         expect(merged.fileReporters, equals({'json': 'new.json'}));
-        expect(merged.pubServeUrl.port, equals(5678));
+        expect(merged.pubServeUrl!.port, equals(5678));
         expect(merged.shardIndex, equals(3));
         expect(merged.totalShards, equals(10));
         expect(merged.paths, equals(['blech']));
@@ -178,9 +176,9 @@
           'zap': Configuration(help: true)
         }));
 
-        expect(merged.presets['bang'].pauseAfterLoad, isTrue);
-        expect(merged.presets['qux'].color, isFalse);
-        expect(merged.presets['zap'].help, isTrue);
+        expect(merged.presets['bang']!.pauseAfterLoad, isTrue);
+        expect(merged.presets['qux']!.color, isFalse);
+        expect(merged.presets['zap']!.help, isTrue);
       });
 
       test('automatically resolves a matching chosen preset', () {
diff --git a/pkgs/test/test/runner/configuration/global_test.dart b/pkgs/test/test/runner/configuration/global_test.dart
index 9a59523..e8e73c0 100644
--- a/pkgs/test/test/runner/configuration/global_test.dart
+++ b/pkgs/test/test/runner/configuration/global_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:convert';
diff --git a/pkgs/test/test/runner/configuration/include_test.dart b/pkgs/test/test/runner/configuration/include_test.dart
index 92495ee..63bed87 100644
--- a/pkgs/test/test/runner/configuration/include_test.dart
+++ b/pkgs/test/test/runner/configuration/include_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:path/path.dart' as p;
@@ -108,7 +106,7 @@
 
     var path = p.join(d.sandbox, 'repo', 'pkg', 'dart_test.yaml');
     var config = Configuration.load(path);
-    var presetBar = config.presets['bar'];
+    var presetBar = config.presets['bar']!;
     expect(presetBar.pauseAfterLoad, isTrue);
     expect(presetBar.reporter, 'expanded');
   });
diff --git a/pkgs/test/test/runner/configuration/platform_test.dart b/pkgs/test/test/runner/configuration/platform_test.dart
index 0244d47..d9bcede 100644
--- a/pkgs/test/test/runner/configuration/platform_test.dart
+++ b/pkgs/test/test/runner/configuration/platform_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:convert';
diff --git a/pkgs/test/test/runner/configuration/presets_test.dart b/pkgs/test/test/runner/configuration/presets_test.dart
index fca9bf4..e802a87 100644
--- a/pkgs/test/test/runner/configuration/presets_test.dart
+++ b/pkgs/test/test/runner/configuration/presets_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:convert';
diff --git a/pkgs/test/test/runner/configuration/randomize_order_test.dart b/pkgs/test/test/runner/configuration/randomize_order_test.dart
index b6ff6e5..6aaf8c4 100644
--- a/pkgs/test/test/runner/configuration/randomize_order_test.dart
+++ b/pkgs/test/test/runner/configuration/randomize_order_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/configuration/suite_test.dart b/pkgs/test/test/runner/configuration/suite_test.dart
index bd54b4b..ded40c5 100644
--- a/pkgs/test/test/runner/configuration/suite_test.dart
+++ b/pkgs/test/test/runner/configuration/suite_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:boolean_selector/boolean_selector.dart';
@@ -194,16 +192,16 @@
               SuiteConfiguration(runSkipped: true)
         }));
 
-        expect(merged.tags[BooleanSelector.parse('foo')].precompiledPath,
+        expect(merged.tags[BooleanSelector.parse('foo')]!.precompiledPath,
             equals('path/'));
-        expect(merged.tags[BooleanSelector.parse('bar')].jsTrace, isFalse);
-        expect(merged.tags[BooleanSelector.parse('baz')].runSkipped, isTrue);
+        expect(merged.tags[BooleanSelector.parse('bar')]!.jsTrace, isFalse);
+        expect(merged.tags[BooleanSelector.parse('baz')]!.runSkipped, isTrue);
 
-        expect(merged.onPlatform[PlatformSelector.parse('vm')].precompiledPath,
+        expect(merged.onPlatform[PlatformSelector.parse('vm')]!.precompiledPath,
             'path/');
-        expect(merged.onPlatform[PlatformSelector.parse('chrome')].jsTrace,
+        expect(merged.onPlatform[PlatformSelector.parse('chrome')]!.jsTrace,
             isFalse);
-        expect(merged.onPlatform[PlatformSelector.parse('firefox')].runSkipped,
+        expect(merged.onPlatform[PlatformSelector.parse('firefox')]!.runSkipped,
             isTrue);
       });
     });
diff --git a/pkgs/test/test/runner/configuration/tags_test.dart b/pkgs/test/test/runner/configuration/tags_test.dart
index 3eb6834..b9e9255 100644
--- a/pkgs/test/test/runner/configuration/tags_test.dart
+++ b/pkgs/test/test/runner/configuration/tags_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/configuration/top_level_error_test.dart b/pkgs/test/test/runner/configuration/top_level_error_test.dart
index ce4c3c8..eb08350 100644
--- a/pkgs/test/test/runner/configuration/top_level_error_test.dart
+++ b/pkgs/test/test/runner/configuration/top_level_error_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:convert';
diff --git a/pkgs/test/test/runner/configuration/top_level_test.dart b/pkgs/test/test/runner/configuration/top_level_test.dart
index 26705d1..5e7208c 100644
--- a/pkgs/test/test/runner/configuration/top_level_test.dart
+++ b/pkgs/test/test/runner/configuration/top_level_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/coverage_test.dart b/pkgs/test/test/runner/coverage_test.dart
index 4b200f7..9298be3 100644
--- a/pkgs/test/test/runner/coverage_test.dart
+++ b/pkgs/test/test/runner/coverage_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -19,7 +17,7 @@
 
 void main() {
   group('with the --coverage flag,', () {
-    Directory coverageDirectory;
+    late Directory coverageDirectory;
 
     Future<void> _validateCoverage(
         TestProcess test, String coveragePath) async {
diff --git a/pkgs/test/test/runner/engine_test.dart b/pkgs/test/test/runner/engine_test.dart
index f85745e..b70e2a6 100644
--- a/pkgs/test/test/runner/engine_test.dart
+++ b/pkgs/test/test/runner/engine_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 import 'dart:async';
 import 'dart:math';
diff --git a/pkgs/test/test/runner/expanded_reporter_test.dart b/pkgs/test/test/runner/expanded_reporter_test.dart
index 4c0bc8c..e50e5ac 100644
--- a/pkgs/test/test/runner/expanded_reporter_test.dart
+++ b/pkgs/test/test/runner/expanded_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -319,7 +317,7 @@
 }
 
 Future<void> _expectReport(String tests, String expected,
-    {List<String> args}) async {
+    {List<String>? args}) async {
   await d.file('test.dart', '''
     import 'dart:async';
 
diff --git a/pkgs/test/test/runner/hybrid_test.dart b/pkgs/test/test/runner/hybrid_test.dart
index 8bc7327..cc38ecd 100644
--- a/pkgs/test/test/runner/hybrid_test.dart
+++ b/pkgs/test/test/runner/hybrid_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -17,7 +15,7 @@
 import '../io.dart';
 
 void main() {
-  String packageRoot;
+  late String packageRoot;
   setUpAll(() async {
     packageRoot = p.absolute(p.dirname(p
         .fromUri(await Isolate.resolvePackageUri(Uri.parse('package:test/')))));
@@ -431,9 +429,7 @@
 ///
 /// If [arguments] is given, it's passed on to the invocation of the test
 /// runner.
-void _spawnHybridUriTests([Iterable<String> arguments]) {
-  arguments ??= [];
-
+void _spawnHybridUriTests([Iterable<String> arguments = const []]) {
   test('loads a file in a separate isolate connected via StreamChannel',
       () async {
     await d.file('test.dart', '''
@@ -701,7 +697,7 @@
     // Adds the sandbox dir as a new package to the existing config,
     // opting it out.
     var originalPackageConfig =
-        await loadPackageConfigUri(await Isolate.packageConfig);
+        await loadPackageConfigUri((await Isolate.packageConfig)!);
     var extraPackage = Package('_test', Uri.file('${d.sandbox}/'),
         languageVersion: LanguageVersion(2, 9));
     var newConfig = PackageConfig([
diff --git a/pkgs/test/test/runner/json_file_reporter_test.dart b/pkgs/test/test/runner/json_file_reporter_test.dart
index 12d6992..f5ed413 100644
--- a/pkgs/test/test/runner/json_file_reporter_test.dart
+++ b/pkgs/test/test/runner/json_file_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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
 
 @TestOn('vm')
 
@@ -109,9 +107,9 @@
 Future<void> _expectReports(
     String tests,
     String stdoutExpected,
-    List<List<dynamic /*Map|Matcher*/ >> jsonFileExpected,
+    List<List<Object /*Map|Matcher*/ >> jsonFileExpected,
     Map<Object, Object> jsonFileDone,
-    {List<String> args}) async {
+    {List<String>? args}) async {
   await d.file('test.dart', '''
     import 'dart:async';
 
diff --git a/pkgs/test/test/runner/json_reporter_test.dart b/pkgs/test/test/runner/json_reporter_test.dart
index eb6bf7d..6db4383 100644
--- a/pkgs/test/test/runner/json_reporter_test.dart
+++ b/pkgs/test/test/runner/json_reporter_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -578,10 +576,9 @@
 /// paths to contents. All libraries will be added as imports to the test, and
 /// files will be created for them.
 Future<void> _expectReport(String tests,
-    List<List<dynamic /*Map|Matcher*/ >> expected, Map<Object, Object> done,
-    {List<String> args, Map<String, String> externalLibraries}) async {
-  args ??= [];
-  externalLibraries ??= {};
+    List<List<Object /*Map|Matcher*/ >> expected, Map<Object, Object> done,
+    {List<String> args = const [],
+    Map<String, String> externalLibraries = const {}}) async {
   var testContent = StringBuffer('''
 import 'dart:async';
 
diff --git a/pkgs/test/test/runner/json_reporter_utils.dart b/pkgs/test/test/runner/json_reporter_utils.dart
index 67133da..ce30701 100644
--- a/pkgs/test/test/runner/json_reporter_utils.dart
+++ b/pkgs/test/test/runner/json_reporter_utils.dart
@@ -1,8 +1,6 @@
 // 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:convert';
 
@@ -20,11 +18,12 @@
 Future<void> expectJsonReport(
     List<String> outputLines,
     int testPid,
-    List<List<dynamic /*Map|Matcher*/ >> expected,
+    List<List<Object /*Map|Matcher*/ >> expected,
     Map<Object, Object> done) async {
   // Ensure the output is of the same length, including start, done and all
   // suites messages.
-  expect(outputLines.length, equals(expected.fold(3, (a, m) => a + m.length)),
+  expect(
+      outputLines.length, equals(expected.fold(3, (int a, m) => a + m.length)),
       reason: 'Expected $outputLines to match $expected.');
 
   dynamic decodeLine(String l) =>
@@ -54,21 +53,22 @@
 /// all suites.
 ///
 /// The [count] defaults to 1.
-Map<String, Object> allSuitesJson({int count}) {
-  return {'type': 'allSuites', 'count': count ?? 1};
+Map<String, Object> allSuitesJson({int count = 1}) {
+  return {'type': 'allSuites', 'count': count};
 }
 
 /// Returns the event emitted by the JSON reporter indicating that a suite has
 /// begun running.
 ///
 /// The [platform] defaults to `"vm"`, the [path] defaults to `"test.dart"`.
-Map<String, Object> suiteJson(int id, {String platform, String path}) {
+Map<String, Object> suiteJson(int id,
+    {String platform = 'vm', String path = 'test.dart'}) {
   return {
     'type': 'suite',
     'suite': {
       'id': id,
-      'platform': platform ?? 'vm',
-      'path': path ?? 'test.dart'
+      'platform': platform,
+      'path': path,
     }
   };
 }
@@ -83,13 +83,13 @@
 /// The [testCount] parameter indicates the number of tests in the group. It
 /// defaults to 1.
 Map<String, Object> groupJson(int id,
-    {String name,
-    int suiteID,
-    int parentID,
-    skip,
-    int testCount,
-    int line,
-    int column}) {
+    {String? name,
+    int? suiteID,
+    int? parentID,
+    Object? skip,
+    int? testCount,
+    int? line,
+    int? column}) {
   if ((line == null) != (column == null)) {
     throw ArgumentError(
         'line and column must either both be null or both be passed');
@@ -121,15 +121,15 @@
 /// reason. If it's a [String], the test is expected to be marked as skipped
 /// with that reason.
 Map<String, Object> testStartJson(int id, String name,
-    {int suiteID,
-    Iterable<int> groupIDs,
-    int line,
-    int column,
-    String url,
-    skip,
-    int root_line,
-    int root_column,
-    String root_url}) {
+    {int? suiteID,
+    Iterable<int>? groupIDs,
+    int? line,
+    int? column,
+    String? url,
+    Object? skip,
+    int? root_line,
+    int? root_column,
+    String? root_url}) {
   if ((line == null) != (column == null)) {
     throw ArgumentError(
         'line and column must either both be null or both be passed');
@@ -165,13 +165,14 @@
 
 /// Returns the event emitted by the JSON reporter indicating that a test
 /// printed [message].
-Matcher printJson(int id, dynamic /*String|Matcher*/ message, {String type}) {
+Matcher printJson(int id, dynamic /*String|Matcher*/ message,
+    {String type = 'print'}) {
   return allOf(
     hasLength(4),
     containsPair('type', 'print'),
     containsPair('testID', id),
     containsPair('message', message),
-    containsPair('messageType', type ?? 'print'),
+    containsPair('messageType', type),
   );
 }
 
@@ -199,8 +200,7 @@
 /// after finishing. The [skipped] parameter indicates whether the test was
 /// skipped.
 Map<String, Object> testDoneJson(int id,
-    {String result, bool hidden = false, bool skipped = false}) {
-  result ??= 'success';
+    {String result = 'success', bool hidden = false, bool skipped = false}) {
   return {
     'type': 'testDone',
     'testID': id,
@@ -216,7 +216,7 @@
     {'type': 'done', 'success': success};
 
 /// Returns the serialized metadata corresponding to [skip].
-Map<String, Object> metadataJson({skip}) {
+Map<String, Object?> metadataJson({skip}) {
   if (skip == true) {
     return {'skip': true, 'skipReason': null};
   } else if (skip is String) {
diff --git a/pkgs/test/test/runner/load_suite_test.dart b/pkgs/test/test/runner/load_suite_test.dart
index 4129d8d..1dd46e6 100644
--- a/pkgs/test/test/runner/load_suite_test.dart
+++ b/pkgs/test/test/runner/load_suite_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:async';
@@ -20,7 +18,7 @@
 import '../utils.dart';
 
 void main() {
-  RunnerSuite innerSuite;
+  late RunnerSuite innerSuite;
   setUp(() {
     innerSuite = runnerSuite(Group.root([]));
   });
diff --git a/pkgs/test/test/runner/loader_test.dart b/pkgs/test/test/runner/loader_test.dart
index 18f3cdf..3469d4e 100644
--- a/pkgs/test/test/runner/loader_test.dart
+++ b/pkgs/test/test/runner/loader_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'dart:async';
@@ -22,7 +20,7 @@
 
 import '../utils.dart';
 
-Loader _loader;
+late Loader _loader;
 
 final _tests = '''
 import 'dart:async';
@@ -44,7 +42,7 @@
   tearDown(() => _loader.close());
 
   group('.loadFile()', () {
-    RunnerSuite suite;
+    late RunnerSuite suite;
     setUp(() async {
       await d.file('a_test.dart', _tests).create();
       var suites = await _loader
@@ -52,7 +50,7 @@
           .toList();
       expect(suites, hasLength(1));
       var loadSuite = suites.first;
-      suite = await loadSuite.getSuite();
+      suite = (await loadSuite.getSuite())!;
     });
 
     test('returns a suite with the file path and platform', () {
@@ -106,7 +104,7 @@
     });
 
     group('with suites loaded from a directory', () {
-      List<RunnerSuite> suites;
+      late List<RunnerSuite> suites;
       setUp(() async {
         await d.file('a_test.dart', _tests).create();
         await d.file('another_test.dart', _tests).create();
@@ -114,7 +112,7 @@
 
         suites = await _loader
             .loadDir(d.sandbox, SuiteConfiguration.empty)
-            .asyncMap((loadSuite) => loadSuite.getSuite())
+            .asyncMap((loadSuite) async => (await loadSuite.getSuite())!)
             .toList();
       });
 
@@ -129,7 +127,8 @@
       });
 
       test('can run tests in those suites', () {
-        var suite = suites.firstWhere((suite) => suite.path.contains('a_test'));
+        var suite =
+            suites.firstWhere((suite) => suite.path!.contains('a_test'));
         var liveTest = (suite.group.entries[1] as RunnerTest).load(suite);
         expectSingleFailure(liveTest);
         return liveTest.run().whenComplete(() => liveTest.close());
@@ -182,7 +181,7 @@
             .toList();
         expect(suites, hasLength(1));
         var loadSuite = suites.first;
-        var suite = await loadSuite.getSuite();
+        var suite = (await loadSuite.getSuite())!;
         expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart')));
         expect(suite.platform.runtime, equals(Runtime.vm));
       }, zoneSpecification:
diff --git a/pkgs/test/test/runner/name_test.dart b/pkgs/test/test/runner/name_test.dart
index 2717fca..ffe92ed 100644
--- a/pkgs/test/test/runner/name_test.dart
+++ b/pkgs/test/test/runner/name_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/node/runner_test.dart b/pkgs/test/test/runner/node/runner_test.dart
index 16d8a6c..d732497 100644
--- a/pkgs/test/test/runner/node/runner_test.dart
+++ b/pkgs/test/test/runner/node/runner_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 @Tags(['node'])
diff --git a/pkgs/test/test/runner/parse_metadata_test.dart b/pkgs/test/test/runner/parse_metadata_test.dart
index c26500e..635d881 100644
--- a/pkgs/test/test/runner/parse_metadata_test.dart
+++ b/pkgs/test/test/runner/parse_metadata_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:test/test.dart';
diff --git a/pkgs/test/test/runner/pause_after_load_test.dart b/pkgs/test/test/runner/pause_after_load_test.dart
index 810f7e7..dcc5402 100644
--- a/pkgs/test/test/runner/pause_after_load_test.dart
+++ b/pkgs/test/test/runner/pause_after_load_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/pub_serve_test.dart b/pkgs/test/test/runner/pub_serve_test.dart
index 22b0d21..744385c 100644
--- a/pkgs/test/test/runner/pub_serve_test.dart
+++ b/pkgs/test/test/runner/pub_serve_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 @Tags(['pub'])
diff --git a/pkgs/test/test/runner/retry_test.dart b/pkgs/test/test/runner/retry_test.dart
index c49902f..8a3585f 100644
--- a/pkgs/test/test/runner/retry_test.dart
+++ b/pkgs/test/test/runner/retry_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:test_descriptor/test_descriptor.dart' as d;
diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart
index c116f22..2423a15 100644
--- a/pkgs/test/test/runner/runner_test.dart
+++ b/pkgs/test/test/runner/runner_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -784,11 +782,11 @@
     });
 
     group('defaults', () {
-      PackageConfig currentPackageConfig;
+      late PackageConfig currentPackageConfig;
 
       setUpAll(() async {
         currentPackageConfig =
-            await loadPackageConfigUri(await Isolate.packageConfig);
+            await loadPackageConfigUri((await Isolate.packageConfig)!);
       });
 
       setUp(() async {
diff --git a/pkgs/test/test/runner/set_up_all_test.dart b/pkgs/test/test/runner/set_up_all_test.dart
index 21f5dad..5b19afa 100644
--- a/pkgs/test/test/runner/set_up_all_test.dart
+++ b/pkgs/test/test/runner/set_up_all_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/shard_test.dart b/pkgs/test/test/runner/shard_test.dart
index a174d33..05603d1 100644
--- a/pkgs/test/test/runner/shard_test.dart
+++ b/pkgs/test/test/runner/shard_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/signal_test.dart b/pkgs/test/test/runner/signal_test.dart
index 2335af8..15133f2 100644
--- a/pkgs/test/test/runner/signal_test.dart
+++ b/pkgs/test/test/runner/signal_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 // Windows doesn't support sending signals.
 @TestOn('vm && !windows')
diff --git a/pkgs/test/test/runner/skip_expect_test.dart b/pkgs/test/test/runner/skip_expect_test.dart
index d342511..e728827 100644
--- a/pkgs/test/test/runner/skip_expect_test.dart
+++ b/pkgs/test/test/runner/skip_expect_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/solo_test.dart b/pkgs/test/test/runner/solo_test.dart
index f87740f..4bdb199 100644
--- a/pkgs/test/test/runner/solo_test.dart
+++ b/pkgs/test/test/runner/solo_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/tag_test.dart b/pkgs/test/test/runner/tag_test.dart
index 39088d6..2136d86 100644
--- a/pkgs/test/test/runner/tag_test.dart
+++ b/pkgs/test/test/runner/tag_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/tear_down_all_test.dart b/pkgs/test/test/runner/tear_down_all_test.dart
index 10982b3..60dd1d9 100644
--- a/pkgs/test/test/runner/tear_down_all_test.dart
+++ b/pkgs/test/test/runner/tear_down_all_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/test_chain_test.dart b/pkgs/test/test/runner/test_chain_test.dart
index 314c739..5b83acb 100644
--- a/pkgs/test/test/runner/test_chain_test.dart
+++ b/pkgs/test/test/runner/test_chain_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/runner/test_on_test.dart b/pkgs/test/test/runner/test_on_test.dart
index 23258fa..f1d9574 100644
--- a/pkgs/test/test/runner/test_on_test.dart
+++ b/pkgs/test/test/runner/test_on_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
@@ -179,9 +177,9 @@
 /// selector that's suite-, group-, and test-level respectively. If [loadable]
 /// is `false`, the test file will be made unloadable on the Dart VM.
 Future<void> _writeTestFile(String filename,
-    {String suiteTestOn,
-    String groupTestOn,
-    String testTestOn,
+    {String? suiteTestOn,
+    String? groupTestOn,
+    String? testTestOn,
     bool loadable = true}) {
   var buffer = StringBuffer();
   if (suiteTestOn != null) buffer.writeln("@TestOn('$suiteTestOn')");
diff --git a/pkgs/test/test/runner/timeout_test.dart b/pkgs/test/test/runner/timeout_test.dart
index 5620e84..a9756da 100644
--- a/pkgs/test/test/runner/timeout_test.dart
+++ b/pkgs/test/test/runner/timeout_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 
diff --git a/pkgs/test/test/util/string_literal_iterator_test.dart b/pkgs/test/test/util/string_literal_iterator_test.dart
index 73963d7..4bb5aa0 100644
--- a/pkgs/test/test/util/string_literal_iterator_test.dart
+++ b/pkgs/test/test/util/string_literal_iterator_test.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 @TestOn('vm')
 import 'package:analyzer/dart/analysis/utilities.dart';
@@ -17,7 +15,7 @@
     test('a single simple string', () {
       var iter = _parse('"abc"');
 
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset));
 
       expect(iter.moveNext(), isTrue);
@@ -33,14 +31,14 @@
       expect(iter.offset, equals(_offset + 3));
 
       expect(iter.moveNext(), isFalse);
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 4));
     });
 
     test('a raw string', () {
       var iter = _parse('r"abc"');
 
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 1));
 
       expect(iter.moveNext(), isTrue);
@@ -56,14 +54,14 @@
       expect(iter.offset, equals(_offset + 4));
 
       expect(iter.moveNext(), isFalse);
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 5));
     });
 
     test('a multiline string', () {
       var iter = _parse('"""ab\ncd"""');
 
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 2));
 
       expect(iter.moveNext(), isTrue);
@@ -87,14 +85,14 @@
       expect(iter.offset, equals(_offset + 7));
 
       expect(iter.moveNext(), isFalse);
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 8));
     });
 
     test('a raw multiline string', () {
       var iter = _parse('r"""ab\ncd"""');
 
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 3));
 
       expect(iter.moveNext(), isTrue);
@@ -118,14 +116,14 @@
       expect(iter.offset, equals(_offset + 8));
 
       expect(iter.moveNext(), isFalse);
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 9));
     });
 
     test('adjacent strings', () {
       var iter = _parse('"ab" r"cd" """ef\ngh"""');
 
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset));
 
       expect(iter.moveNext(), isTrue);
@@ -165,7 +163,7 @@
       expect(iter.offset, equals(_offset + 18));
 
       expect(iter.moveNext(), isFalse);
-      expect(iter.current, isNull);
+      expect(() => iter.current, throwsA(isA<TypeError>()));
       expect(iter.offset, equals(_offset + 19));
     });
   });
@@ -211,7 +209,7 @@
 void _expectEscape(String escape, String value) {
   var iter = _parse('"a${escape}b"');
 
-  expect(iter.current, isNull);
+  expect(() => iter.current, throwsA(isA<TypeError>()));
   expect(iter.offset, equals(_offset));
 
   expect(iter.moveNext(), isTrue);
@@ -227,7 +225,7 @@
   expect(iter.offset, equals(_offset + escape.length + 2));
 
   expect(iter.moveNext(), isFalse);
-  expect(iter.current, isNull);
+  expect(() => iter.current, throwsA(isA<TypeError>()));
   expect(iter.offset, equals(_offset + escape.length + 3));
 }
 
diff --git a/pkgs/test/test/utils.dart b/pkgs/test/test/utils.dart
index 8668c4d..2ae4be4 100644
--- a/pkgs/test/test/utils.dart
+++ b/pkgs/test/test/utils.dart
@@ -1,8 +1,6 @@
 // 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.7
 
 import 'dart:async';
 import 'dart:collection';
@@ -29,7 +27,7 @@
 final suitePlatform = SuitePlatform(Runtime.vm);
 
 // The last state change detected via [expectStates].
-State lastState;
+State? lastState;
 
 /// Asserts that exactly [states] will be emitted via [liveTest.onStateChange].
 ///
@@ -60,7 +58,7 @@
 
   expectErrors(liveTest, [
     (error) {
-      expect(lastState.status, equals(Status.complete));
+      expect(lastState!.status, equals(Status.complete));
       expect(error, isTestFailure('oh no'));
     }
   ]);
@@ -75,7 +73,7 @@
 
   expectErrors(liveTest, [
     (error) {
-      expect(lastState.status, equals(Status.complete));
+      expect(lastState!.status, equals(Status.complete));
       expect(error, equals('oh no'));
     }
   ]);
@@ -149,8 +147,8 @@
 /// [stopBlocking] is passed the return value of [test].
 Future<void> expectTestBlocks(
     dynamic Function() test, dynamic Function(dynamic) stopBlocking) async {
-  LiveTest liveTest;
-  Future<void> future;
+  late LiveTest liveTest;
+  late Future<void> future;
   liveTest = createTest(() {
     var value = test();
     future = pumpEventQueue().then((_) {
@@ -190,7 +188,7 @@
 
 /// Runs [body] with a declarer and returns an engine that runs those tests.
 Engine declareEngine(void Function() body,
-    {bool runSkipped = false, String coverage}) {
+    {bool runSkipped = false, String? coverage}) {
   var declarer = Declarer()..declare(body);
   return Engine.withSuites([
     RunnerSuite(
diff --git a/pkgs/test_api/CHANGELOG.md b/pkgs/test_api/CHANGELOG.md
index eede7a6..3365c58 100644
--- a/pkgs/test_api/CHANGELOG.md
+++ b/pkgs/test_api/CHANGELOG.md
@@ -1,5 +1,7 @@
 ## 0.2.20-dev
 
+* Fix some strong null safety mode errors in the original migration.
+
 ## 0.2.19
 
 * Stable release for null safety.
diff --git a/pkgs/test_api/lib/src/util/remote_exception.dart b/pkgs/test_api/lib/src/util/remote_exception.dart
index 996bb35..c768ff8 100644
--- a/pkgs/test_api/lib/src/util/remote_exception.dart
+++ b/pkgs/test_api/lib/src/util/remote_exception.dart
@@ -67,7 +67,7 @@
     final type = serialized['type'] as String;
     final toString = serialized['toString'] as String;
 
-    switch (serialized['supertype'] as String) {
+    switch (serialized['supertype'] as String?) {
       case 'TestFailure':
         return _RemoteTestFailure(message, type, toString);
       default:
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 51e170e..bb0369b 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,4 +1,8 @@
-## 0.3.15
+## 0.3.17-dev
+
+* Complete the null safety migration for backend libs.
+
+## 0.3.16
 
 * Allow package:io version 1.0.0.
 
diff --git a/pkgs/test_core/lib/backend.dart b/pkgs/test_core/lib/backend.dart
index dca038f..3a1506b 100644
--- a/pkgs/test_core/lib/backend.dart
+++ b/pkgs/test_core/lib/backend.dart
@@ -1,8 +1,6 @@
 // Copyright (c) 2019, 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.8
 
 @Deprecated('package:test_core is not intended for general use. '
     'Please use package:test.')
diff --git a/pkgs/test_core/lib/src/direct_run.dart b/pkgs/test_core/lib/src/direct_run.dart
index c4f7612..126ee49 100644
--- a/pkgs/test_core/lib/src/direct_run.dart
+++ b/pkgs/test_core/lib/src/direct_run.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -31,7 +29,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.
@@ -49,13 +47,12 @@
 /// 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);
@@ -72,7 +69,8 @@
   reporterFactory(engine);
 
   final success = await runZoned(() => Invoker.guard(engine.run),
-      zoneValues: {#test.declarer: declarer});
+          zoneValues: {#test.declarer: declarer}) ??
+      false;
 
   if (fullTestName != null) {
     final testCount = engine.liveTests.length;
diff --git a/pkgs/test_core/lib/src/executable.dart b/pkgs/test_core/lib/src/executable.dart
index 991c740..5272a66 100644
--- a/pkgs/test_core/lib/src/executable.dart
+++ b/pkgs/test_core/lib/src/executable.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -20,15 +18,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'];
+    return Platform.environment['DART_TEST_CONFIG']!;
   } else if (Platform.operatingSystem == 'windows') {
-    return p.join(Platform.environment['LOCALAPPDATA'], 'DartTest.yaml');
+    return p.join(Platform.environment['LOCALAPPDATA']!, 'DartTest.yaml');
   } else {
     return '${Platform.environment['HOME']}/.dart_test.yaml';
   }
@@ -46,7 +44,7 @@
 void completeShutdown() {
   if (isShutdown) return;
   if (signalSubscription != null) {
-    signalSubscription.cancel();
+    signalSubscription!.cancel();
     signalSubscription = null;
   }
   isShutdown = true;
@@ -137,7 +135,7 @@
     return;
   }
 
-  Runner /*?*/ runner;
+  Runner? runner;
 
   signalSubscription ??= _signals.listen((signal) async {
     completeShutdown();
@@ -180,7 +178,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/pkgs/test_core/lib/src/platform.dart b/pkgs/test_core/lib/src/platform.dart
index 24d8fb4..f1fc22b 100644
--- a/pkgs/test_core/lib/src/platform.dart
+++ b/pkgs/test_core/lib/src/platform.dart
@@ -1,8 +1,6 @@
 // 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;
diff --git a/pkgs/test_core/lib/src/runner.dart b/pkgs/test_core/lib/src/runner.dart
index 69b1ac5..b1e8be9 100644
--- a/pkgs/test_core/lib/src/runner.dart
+++ b/pkgs/test_core/lib/src/runner.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -52,7 +50,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.
@@ -64,7 +62,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();
@@ -83,17 +81,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,
         );
@@ -115,21 +113,20 @@
         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 subscription =
+              _suiteSubscription = suites.listen(_engine.suiteSink.add);
           var results = await Future.wait(<Future>[
-            _suiteSubscription
-                .asFuture()
-                .then((_) => _engine.suiteSink.close()),
+            subscription.asFuture().then((_) => _engine.suiteSink.close()),
             _engine.run()
           ], eagerError: true);
-          success = results.last as bool /*?*/;
+          success = results.last as bool?;
         }
 
         if (_closed) return false;
@@ -208,7 +205,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.
@@ -289,7 +286,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;
@@ -341,10 +338,9 @@
       }
 
       if (entry is! Group) return;
-      var group = entry as Group;
 
       currentTags.addAll(newTags);
-      for (var child in group.entries) {
+      for (var child in entry.entries) {
         collect(child);
       }
       currentTags.removeAll(newTags);
@@ -371,8 +367,8 @@
   RunnerSuite _shardSuite(RunnerSuite 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,13 +384,13 @@
   /// Loads each suite in [suites] in order, pausing after load for runtimes
   /// that support debugging.
   Future<bool> _loadThenPause(Stream<LoadSuite> suites) async {
-    _suiteSubscription = suites.asyncMap((loadSuite) async {
-      _debugOperation = debug(_engine, _reporter, loadSuite);
-      await _debugOperation.valueOrCancellation();
+    var subscription = _suiteSubscription = suites.asyncMap((loadSuite) async {
+      var operation = _debugOperation = debug(_engine, _reporter, loadSuite);
+      await operation.valueOrCancellation();
     }).listen(null);
 
     var results = await Future.wait(<Future>[
-      _suiteSubscription.asFuture().then((_) => _engine.suiteSink.close()),
+      subscription.asFuture().then((_) => _engine.suiteSink.close()),
       _engine.run()
     ], eagerError: true);
     return results.last as bool;
diff --git a/pkgs/test_core/lib/src/runner/compiler_pool.dart b/pkgs/test_core/lib/src/runner/compiler_pool.dart
index 50cf577..1c34f6a 100644
--- a/pkgs/test_core/lib/src/runner/compiler_pool.dart
+++ b/pkgs/test_core/lib/src/runner/compiler_pool.dart
@@ -1,20 +1,18 @@
 // 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:io';
-import 'dart:isolate';
 
 import 'package:async/async.dart';
 import 'package:path/path.dart' as p;
 import 'package:pool/pool.dart';
 
 import '../util/io.dart';
-import 'suite.dart';
+import '../util/package_config.dart';
 import 'configuration.dart';
+import 'suite.dart';
 
 /// A regular expression matching the first status line printed by dart2js.
 final _dart2jsStatus =
@@ -43,7 +41,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 [];
 
@@ -70,7 +68,7 @@
           '--enable-asserts',
           wrapperPath,
           '--out=$jsPath',
-          '--packages=${await Isolate.packageConfig}',
+          '--packages=${await packageConfigUri}',
           ..._extraArgs,
           ...suiteConfig.dart2jsArgs
         ];
diff --git a/pkgs/test_core/lib/src/runner/configuration.dart b/pkgs/test_core/lib/src/runner/configuration.dart
index b5a6ee8..332faeb 100644
--- a/pkgs/test_core/lib/src/runner/configuration.dart
+++ b/pkgs/test_core/lib/src/runner/configuration.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -43,40 +41,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.
@@ -84,20 +82,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.
@@ -113,25 +111,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;
@@ -140,7 +138,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.
   ///
@@ -155,7 +153,7 @@
         ...suiteDefaults.knownTags,
         for (var configuration in presets.values) ...configuration.knownTags
       });
-  Set<String> /*?*/ _knownTags;
+  Set<String>? _knownTags;
 
   /// Configuration presets.
   ///
@@ -174,7 +172,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;
@@ -190,7 +188,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].
   ///
@@ -217,57 +215,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,
@@ -319,8 +317,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,
@@ -332,31 +330,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,
@@ -385,10 +383,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)) {
@@ -396,7 +394,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');
     }
   }
 
@@ -409,7 +407,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;
@@ -419,7 +417,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;
@@ -427,7 +425,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);
   }
@@ -472,15 +470,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!);
       }
     }
 
@@ -529,50 +527,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/pkgs/test_core/lib/src/runner/configuration/args.dart b/pkgs/test_core/lib/src/runner/configuration/args.dart
index ab7b79f..253924b 100644
--- a/pkgs/test_core/lib/src/runner/configuration/args.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/args.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -118,7 +116,7 @@
 
   var reporterDescriptions = <String, String>{};
   for (var reporter in allReporters.keys) {
-    reporterDescriptions[reporter] = allReporters[reporter].description;
+    reporterDescriptions[reporter] = allReporters[reporter]!.description;
   }
 
   parser.addSeparator('Output:');
@@ -185,8 +183,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) {
@@ -194,9 +192,8 @@
       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) {
@@ -212,7 +209,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.');
       }
@@ -232,7 +229,7 @@
 
     var platform = _ifParsed<List<String>>('platform')
         ?.map((runtime) => RuntimeSelection(runtime))
-        ?.toList();
+        .toList();
     if (platform
             ?.any((runtime) => runtime.name == Runtime.phantomJS.identifier) ??
         false) {
@@ -279,12 +276,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];
@@ -293,7 +290,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/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart b/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart
index 65384ba..0c99191 100644
--- a/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart
@@ -1,8 +1,6 @@
 // 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/pkgs/test_core/lib/src/runner/configuration/load.dart b/pkgs/test_core/lib/src/runner/configuration/load.dart
index 8c5419b..f69cb76 100644
--- a/pkgs/test_core/lib/src/runner/configuration/load.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/load.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -58,7 +56,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;
@@ -187,14 +185,14 @@
     }
 
     var skipRaw = _getValue('skip', 'boolean or string',
-        (value) => (value is bool /*?*/) || value is String /*?*/);
-    String /*?*/ skipReason;
-    bool skip;
+        (value) => (value is bool?) || value is String?);
+    String? skipReason;
+    bool? skip;
     if (skipRaw is String) {
       skipReason = skipRaw;
       skip = true;
     } else {
-      skip = skipRaw as bool;
+      skip = skipRaw as bool?;
     }
 
     var testOn = _parsePlatformSelector('test_on');
@@ -297,7 +295,7 @@
   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>{};
@@ -415,7 +413,7 @@
   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>{};
@@ -454,7 +452,7 @@
   ///
   /// 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 (value == null || typeTest(value)) return value;
@@ -467,7 +465,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;
@@ -476,32 +474,30 @@
   }
 
   /// 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();
   }
@@ -511,8 +507,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) {
@@ -530,7 +526,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,
@@ -543,11 +539,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(
@@ -575,7 +571,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);
@@ -586,8 +582,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);
@@ -652,6 +648,6 @@
   @alwaysThrows
   void _error(String message, String field) {
     throw SourceSpanFormatException(
-        message, _document.nodes[field].span, _source);
+        message, _document.nodes[field]!.span, _source);
   }
 }
diff --git a/pkgs/test_core/lib/src/runner/configuration/reporters.dart b/pkgs/test_core/lib/src/runner/configuration/reporters.dart
index 231b7ba..331a113 100644
--- a/pkgs/test_core/lib/src/runner/configuration/reporters.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/reporters.dart
@@ -1,8 +1,6 @@
 // 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/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart b/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart
index a798499..6e910a3 100644
--- a/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart
@@ -1,8 +1,6 @@
 // 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/pkgs/test_core/lib/src/runner/configuration/values.dart b/pkgs/test_core/lib/src/runner/configuration/values.dart
index 360a503..6e2f50a 100644
--- a/pkgs/test_core/lib/src/runner/configuration/values.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/values.dart
@@ -1,8 +1,6 @@
 // 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/pkgs/test_core/lib/src/runner/debugger.dart b/pkgs/test_core/lib/src/runner/debugger.dart
index 86c763c..5e902d6 100644
--- a/pkgs/test_core/lib/src/runner/debugger.dart
+++ b/pkgs/test_core/lib/src/runner/debugger.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -29,7 +27,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
@@ -47,7 +45,7 @@
     canceled = true;
     // Make sure the load test finishes so the engine can close.
     engine.resume();
-    if (debugger != null) debugger.close();
+    debugger?.close();
   });
 }
 
@@ -78,10 +76,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/pkgs/test_core/lib/src/runner/load_suite.dart b/pkgs/test_core/lib/src/runner/load_suite.dart
index d975e31..6e0966e 100644
--- a/pkgs/test_core/lib/src/runner/load_suite.dart
+++ b/pkgs/test_core/lib/src/runner/load_suite.dart
@@ -88,7 +88,7 @@
   factory LoadSuite(String name, SuiteConfiguration config,
       SuitePlatform platform, FutureOr<RunnerSuite?> Function() body,
       {String? path}) {
-    var completer = Completer<Pair<RunnerSuite, Zone>>.sync();
+    var completer = Completer<Pair<RunnerSuite, Zone>?>.sync();
     return LoadSuite._(name, config, platform, () {
       var invoker = Invoker.current;
       invoker!.addOutstandingCallback();
@@ -167,7 +167,7 @@
   /// If [suite] completes to `null`, [change] won't be run. [change] is run
   /// within the load test's zone, so any errors or prints it emits will be
   /// associated with that test.
-  LoadSuite changeSuite(RunnerSuite Function(RunnerSuite) change) {
+  LoadSuite changeSuite(RunnerSuite? Function(RunnerSuite) change) {
     return LoadSuite._changeSuite(this, _suiteAndZone.then((pair) {
       if (pair == null) return null;
 
diff --git a/pkgs/test_core/lib/src/runner/loader.dart b/pkgs/test_core/lib/src/runner/loader.dart
index 9e93945..fc39648 100644
--- a/pkgs/test_core/lib/src/runner/loader.dart
+++ b/pkgs/test_core/lib/src/runner/loader.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -109,8 +107,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];
@@ -121,14 +119,15 @@
   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].
   ///
@@ -189,7 +188,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;
       }
@@ -214,13 +213,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()});
@@ -265,11 +264,11 @@
       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/pkgs/test_core/lib/src/runner/package_version.dart b/pkgs/test_core/lib/src/runner/package_version.dart
index 788e7de..5f4d622 100644
--- a/pkgs/test_core/lib/src/runner/package_version.dart
+++ b/pkgs/test_core/lib/src/runner/package_version.dart
@@ -1,15 +1,12 @@
 // 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.8
-
-import 'dart:isolate';
 
 import 'package:package_config/package_config.dart';
 import 'package:path/path.dart' as p;
 
 import '../util/detaching_future.dart';
+import '../util/package_config.dart';
 
 /// A comment which forces the language version to be that of the current
 /// packages default.
@@ -19,7 +16,7 @@
 Future<String> get rootPackageLanguageVersionComment =>
     _rootPackageLanguageVersionComment.asFuture;
 final _rootPackageLanguageVersionComment = DetachingFuture(() async {
-  var packageConfig = await loadPackageConfigUri(await Isolate.packageConfig);
+  var packageConfig = await loadPackageConfigUri(await packageConfigUri);
   var rootPackage = packageConfig.packageOf(Uri.file(p.absolute('foo.dart')));
   if (rootPackage == null) return '';
   return '// @dart=${rootPackage.languageVersion}';
diff --git a/pkgs/test_core/lib/src/runner/parse_metadata.dart b/pkgs/test_core/lib/src/runner/parse_metadata.dart
index 43a76cc..e3a3029 100644
--- a/pkgs/test_core/lib/src/runner/parse_metadata.dart
+++ b/pkgs/test_core/lib/src/runner/parse_metadata.dart
@@ -1,8 +1,6 @@
 // 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.8
 
 import 'package:analyzer/dart/analysis/utilities.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -37,16 +35,16 @@
   final Set<String> _platformVariables;
 
   /// All annotations at the top of the file.
-  List<Annotation> _annotations;
+  late final List<Annotation> _annotations;
 
   /// All prefixes defined by imports in this file.
-  Set<String> _prefixes;
+  late final Set<String> _prefixes;
 
   /// The actual contents of the file.
   final String _contents;
 
   /// The language version override comment if one was present, otherwise null.
-  String _languageVersionComment;
+  String? _languageVersionComment;
 
   _Parser(this._path, this._contents, this._platformVariables) {
     var result =
@@ -71,12 +69,12 @@
 
   /// Parses the metadata.
   Metadata parse() {
-    Timeout timeout;
-    PlatformSelector testOn;
-    dynamic /*String|bool*/ skip;
-    Map<PlatformSelector, Metadata> onPlatform;
-    Set<String> tags;
-    int retry;
+    Timeout? timeout;
+    PlatformSelector? testOn;
+    Object? /*String|bool*/ skip;
+    Map<PlatformSelector, Metadata>? onPlatform;
+    Set<String>? tags;
+    int? retry;
 
     for (var annotation in _annotations) {
       var pair =
@@ -119,7 +117,7 @@
   ///
   /// [annotation] is the annotation.
   PlatformSelector _parseTestOn(Annotation annotation) =>
-      _parsePlatformSelector(annotation.arguments.arguments.first);
+      _parsePlatformSelector(annotation.arguments!.arguments.first);
 
   /// Parses an [expression] that should contain a string representing a
   /// [PlatformSelector].
@@ -127,7 +125,7 @@
     var literal = _parseString(expression);
     return _contextualize(
         literal,
-        () => PlatformSelector.parse(literal.stringValue)
+        () => PlatformSelector.parse(literal.stringValue!)
           ..validate(_platformVariables));
   }
 
@@ -135,18 +133,18 @@
   ///
   /// [annotation] is the annotation.
   int _parseRetry(Annotation annotation) =>
-      _parseInt(annotation.arguments.arguments.first);
+      _parseInt(annotation.arguments!.arguments.first);
 
   /// Parses a `@Timeout` annotation.
   ///
   /// [annotation] is the annotation. [constructorName] is the name of the named
   /// constructor for the annotation, if any.
-  Timeout _parseTimeout(Annotation annotation, String constructorName) {
+  Timeout _parseTimeout(Annotation annotation, String? constructorName) {
     if (constructorName == 'none') {
       return Timeout.none;
     }
 
-    var args = annotation.arguments.arguments;
+    var args = annotation.arguments!.arguments;
     if (constructorName == null) return Timeout(_parseDuration(args.first));
     return Timeout.factor(_parseNum(args.first));
   }
@@ -166,7 +164,7 @@
   ///
   /// Returns either `true` or a reason string.
   dynamic _parseSkip(Annotation annotation) {
-    var args = annotation.arguments.arguments;
+    var args = annotation.arguments!.arguments;
     return args.isEmpty ? true : _parseString(args.first).stringValue;
   }
 
@@ -183,9 +181,9 @@
   ///
   /// [annotation] is the annotation.
   Set<String> _parseTags(Annotation annotation) {
-    return _parseList(annotation.arguments.arguments.first)
+    return _parseList(annotation.arguments!.arguments.first)
         .map((tagExpression) {
-      var name = _parseString(tagExpression).stringValue;
+      var name = _parseString(tagExpression).stringValue!;
       if (name.contains(anchoredHyphenatedIdentifier)) return name;
 
       throw SourceSpanFormatException(
@@ -199,7 +197,7 @@
   ///
   /// [annotation] is the annotation.
   Map<PlatformSelector, Metadata> _parseOnPlatform(Annotation annotation) {
-    return _parseMap(annotation.arguments.arguments.first, key: (key) {
+    return _parseMap(annotation.arguments!.arguments.first, key: (key) {
       return _parsePlatformSelector(key);
     }, value: (value) {
       var expressions = <AstNode>[];
@@ -214,8 +212,8 @@
             'Expected a Timeout, Skip, or List of those.', _spanFor(value));
       }
 
-      Timeout timeout;
-      dynamic skip;
+      Timeout? timeout;
+      Object? skip;
       for (var expression in expressions) {
         if (expression is InstanceCreationExpression) {
           var className = _resolveConstructor(
@@ -292,7 +290,7 @@
   ///
   /// [name] is the name of the annotation and [node] is its location, used for
   /// error reporting.
-  void _assertSingle(Object existing, String name, AstNode node) {
+  void _assertSingle(Object? existing, String name, AstNode node) {
     if (existing == null) return;
     throw SourceSpanFormatException(
         'Only a single $name may be used.', _spanFor(node));
@@ -314,15 +312,15 @@
   ///
   /// Since the parsed file isn't fully resolved, this is necessary to
   /// disambiguate between prefixed names and named constructors.
-  Pair<String, String> _resolveConstructor(
-      Identifier identifier, SimpleIdentifier constructorName) {
+  Pair<String, String?> _resolveConstructor(
+      Identifier identifier, SimpleIdentifier? constructorName) {
     // The syntax is ambiguous between named constructors and prefixed
     // annotations, so we need to resolve that ambiguity using the known
     // prefixes. The analyzer parses "new x.y()" as prefix "x", annotation "y",
     // and named constructor null. It parses "new x.y.z()" as prefix "x",
     // annotation "y", and named constructor "z".
     String className;
-    String namedConstructor;
+    String? namedConstructor;
     if (identifier is PrefixedIdentifier &&
         !_prefixes.contains(identifier.prefix.name) &&
         constructorName == null) {
@@ -342,7 +340,7 @@
   /// Returns the name of the named constructor used, or null if the default
   /// constructor is used.
   /// If [expression] is not an instantiation of a [className] throws.
-  String _findConstructorName(Expression expression, String className) {
+  String? _findConstructorName(Expression expression, String className) {
     if (expression is InstanceCreationExpression) {
       return _findConstructornameFromInstantiation(expression, className);
     }
@@ -353,7 +351,7 @@
         'Expected a $className.', _spanFor(expression));
   }
 
-  String _findConstructornameFromInstantiation(
+  String? _findConstructornameFromInstantiation(
       InstanceCreationExpression constructor, String className) {
     var pair = _resolveConstructor(constructor.constructorName.type.name,
         constructor.constructorName.name);
@@ -368,7 +366,7 @@
     return constructorName;
   }
 
-  String _findConstructorNameFromMethod(
+  String? _findConstructorNameFromMethod(
       MethodInvocation constructor, String className) {
     var target = constructor.target;
     if (target != null) {
@@ -379,7 +377,7 @@
       if (constructor.methodName.name == className) return null;
       // target is an optionally prefixed class, method is named constructor
       // Examples: `Timeout.factor(2)`, `test.Timeout.factor(2)`
-      String parsedName;
+      String? parsedName;
       if (target is SimpleIdentifier) parsedName = target.name;
       if (target is PrefixedIdentifier) parsedName = target.identifier.name;
       if (parsedName != className) {
@@ -408,7 +406,7 @@
   /// Similarly `Baz.another` may look like the named constructor invocation of
   /// a `Baz`even though it is a prefixed instantiation of an `another`, or a
   /// method invocation on a variable `Baz`, or ...
-  String _typeNameFromMethodInvocation(
+  String? _typeNameFromMethodInvocation(
       MethodInvocation constructor, List<String> candidates) {
     var methodName = constructor.methodName.name;
     // Examples: `Timeout()`, `test.Timeout()`
@@ -436,7 +434,7 @@
   /// By default, returns [Expression] keys and values. These can be overridden
   /// with the [key] and [value] parameters.
   Map<K, V> _parseMap<K, V>(Expression expression,
-      {K Function(Expression) key, V Function(Expression) value}) {
+      {K Function(Expression)? key, V Function(Expression)? value}) {
     key ??= (expression) => expression as K;
     value ??= (expression) => expression as V;
 
@@ -445,7 +443,7 @@
     }
 
     var map = <K, V>{};
-    for (var element in (expression as SetOrMapLiteral).elements) {
+    for (var element in expression.elements) {
       if (element is MapLiteralEntry) {
         map[key(element.key)] = value(element.value);
       } else {
@@ -462,27 +460,31 @@
       throw SourceSpanFormatException('Expected a List.', _spanFor(expression));
     }
 
-    var list = expression as ListLiteral;
+    var list = expression;
 
     return list.elements.map((e) {
       if (e is! Expression) {
         throw SourceSpanFormatException(
             'Expected only literal elements.', _spanFor(e));
       }
-      return e as Expression;
+      return e;
     }).toList();
   }
 
   /// Parses a constant number literal.
   num _parseNum(Expression expression) {
-    if (expression is IntegerLiteral) return expression.value;
+    if (expression is IntegerLiteral && expression.value != null) {
+      return expression.value!;
+    }
     if (expression is DoubleLiteral) return expression.value;
     throw SourceSpanFormatException('Expected a number.', _spanFor(expression));
   }
 
   /// Parses a constant int literal.
   int _parseInt(Expression expression) {
-    if (expression is IntegerLiteral) return expression.value;
+    if (expression is IntegerLiteral && expression.value != null) {
+      return expression.value!;
+    }
     throw SourceSpanFormatException(
         'Expected an integer.', _spanFor(expression));
   }
@@ -511,7 +513,7 @@
       return fn();
     } on SourceSpanFormatException catch (error) {
       var file = SourceFile.fromString(_contents, url: p.toUri(_path));
-      var span = contextualizeSpan(error.span, literal, file);
+      var span = contextualizeSpan(error.span!, literal, file);
       if (span == null) rethrow;
       throw SourceSpanFormatException(error.message, span);
     }
diff --git a/pkgs/test_core/lib/src/runner/plugin/customizable_platform.dart b/pkgs/test_core/lib/src/runner/plugin/customizable_platform.dart
index 058eb95..065e315 100644
--- a/pkgs/test_core/lib/src/runner/plugin/customizable_platform.dart
+++ b/pkgs/test_core/lib/src/runner/plugin/customizable_platform.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -23,7 +21,7 @@
 ///
 /// Plugins that implement this **must** support children of recognized runtimes
 /// (created by [Runtime.extend]) in their [loadChannel] or [load] methods.
-abstract class CustomizablePlatform<T> extends PlatformPlugin {
+abstract class CustomizablePlatform<T extends Object> extends PlatformPlugin {
   /// Parses user-provided [settings] for a custom platform into a
   /// plugin-defined format.
   ///
diff --git a/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart b/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart
index 6a8ee9e..fbd0b73 100644
--- a/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart
+++ b/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -46,7 +44,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));
 
@@ -134,20 +132,20 @@
         (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
             ? null
             : Trace.parse(group['trace'] as String),
-        setUpAll: _deserializeTest(group['setUpAll'] as Map),
-        tearDownAll: _deserializeTest(group['tearDownAll'] as Map));
+        setUpAll: _deserializeTest(group['setUpAll'] as Map?),
+        tearDownAll: _deserializeTest(group['tearDownAll'] as Map?));
   }
 
   /// 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/pkgs/test_core/lib/src/runner/reporter/json.dart b/pkgs/test_core/lib/src/runner/reporter/json.dart
index f31f185..4be3734 100644
--- a/pkgs/test_core/lib/src/runner/reporter/json.dart
+++ b/pkgs/test_core/lib/src/runner/reporter/json.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -140,7 +138,7 @@
         'groupIDs': groupIDs,
         'metadata': _serializeMetadata(suiteConfig, liveTest.test.metadata),
         ..._frameInfo(suiteConfig, liveTest.test.trace,
-            liveTest.suite.platform.runtime, liveTest.suite.path),
+            liveTest.suite.platform.runtime, liveTest.suite.path!),
       }
     });
 
@@ -166,7 +164,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;
@@ -191,7 +189,7 @@
     }
 
     _emit('suite', {
-      'suite': <String, Object /*?*/ >{
+      'suite': <String, Object?>{
         'id': id,
         'platform': suite.platform.runtime.identifier,
         'path': suite.path
@@ -206,11 +204,10 @@
   /// 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;
+        return parentID = _groupIDs[group]!;
       }
 
       var id = _nextID++;
@@ -226,7 +223,7 @@
           'metadata': _serializeMetadata(suiteConfig, group.metadata),
           'testCount': group.testCount,
           ..._frameInfo(
-              suiteConfig, group.trace, suite.platform.runtime, suite.path)
+              suiteConfig, group.trace, suite.platform.runtime, suite.path!)
         }
       });
       parentID = id;
@@ -267,7 +264,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();
 
@@ -294,15 +291,15 @@
   /// If javascript traces are enabled and the test is on a javascript platform,
   /// or if the [trace] is null or empty, then the line, column, and url will
   /// all be `null`.
-  Map<String, dynamic> _frameInfo(SuiteConfiguration suiteConfig,
-      Trace /*?*/ trace, Runtime runtime, String suitePath) {
+  Map<String, dynamic> _frameInfo(SuiteConfiguration suiteConfig, Trace? trace,
+      Runtime runtime, String suitePath) {
     var absoluteSuitePath = p.absolute(suitePath);
-    var frame = trace?.frames?.first;
+    var frame = trace?.frames.first;
     if (frame == null || (suiteConfig.jsTrace && runtime.isJS)) {
       return {'line': null, 'column': null, 'url': null};
     }
 
-    var rootFrame = trace?.frames?.firstWhereOrNull((frame) =>
+    var rootFrame = trace?.frames.firstWhereOrNull((frame) =>
         frame.uri.scheme == 'file' &&
         frame.uri.toFilePath() == absoluteSuitePath);
     return {
diff --git a/pkgs/test_core/lib/src/runner/runner_test.dart b/pkgs/test_core/lib/src/runner/runner_test.dart
index 156e528..5f3b0f7 100644
--- a/pkgs/test_core/lib/src/runner/runner_test.dart
+++ b/pkgs/test_core/lib/src/runner/runner_test.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -27,7 +25,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;
@@ -37,9 +35,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));
 
@@ -103,7 +101,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/pkgs/test_core/lib/src/runner/spawn_hybrid.dart b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
index e5043af..16e4fbd 100644
--- a/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
+++ b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
@@ -1,8 +1,6 @@
 // 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:isolate';
@@ -32,8 +30,7 @@
 /// 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) {
+StreamChannel spawnHybridUri(String url, Object? message, Suite suite) {
   url = _normalizeUrl(url, suite);
   return StreamChannelCompleter.fromFuture(() async {
     var port = ReceivePort();
@@ -99,7 +96,7 @@
       return p.url
           .join(p.toUri(p.current).toString(), parsedUri.path.substring(1));
     } else {
-      var suitePath = suite.path;
+      var suitePath = suite.path!;
       return p.url.join(
           p.url.dirname(p.toUri(p.absolute(suitePath)).toString()),
           parsedUri.toString());
@@ -147,7 +144,7 @@
     case 'file':
       return File.fromUri(uri).readAsString();
     case 'data':
-      return uri.data.contentAsString();
+      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/pkgs/test_core/lib/src/runner/version.dart b/pkgs/test_core/lib/src/runner/version.dart
index 5c617cf..3eab242 100644
--- a/pkgs/test_core/lib/src/runner/version.dart
+++ b/pkgs/test_core/lib/src/runner/version.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -12,7 +10,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());
@@ -31,7 +29,7 @@
   var source = package['source'];
   if (source is! String) return null;
 
-  switch (source as String) {
+  switch (source) {
     case 'hosted':
       var version = package['version'];
       return (version is String) ? version : null;
diff --git a/pkgs/test_core/lib/src/runner/vm/environment.dart b/pkgs/test_core/lib/src/runner/vm/environment.dart
index fb75c66..6fb1caa 100644
--- a/pkgs/test_core/lib/src/runner/vm/environment.dart
+++ b/pkgs/test_core/lib/src/runner/vm/environment.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -24,7 +22,7 @@
   VMEnvironment(this.observatoryUrl, this._isolate, this._client);
 
   @override
-  Uri /*?*/ get remoteDebuggerUrl => null;
+  Uri? get remoteDebuggerUrl => null;
 
   @override
   Stream get onRestart => StreamController.broadcast().stream;
@@ -32,9 +30,9 @@
   @override
   CancelableOperation displayPause() {
     var completer =
-        CancelableCompleter(onCancel: () => _client.resume(_isolate.id));
+        CancelableCompleter(onCancel: () => _client.resume(_isolate.id!));
 
-    completer.complete(_client.pause(_isolate.id).then((_) => _client
+    completer.complete(_client.pause(_isolate.id!).then((_) => _client
         .onDebugEvent
         .firstWhere((event) => event.kind == EventKind.kResume)));
 
diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart
index 3d2c745..e79ee7a 100644
--- a/pkgs/test_core/lib/src/runner/vm/platform.dart
+++ b/pkgs/test_core/lib/src/runner/vm/platform.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -56,8 +54,8 @@
       rethrow;
     }
 
-    VmService /*?*/ client;
-    StreamSubscription<Event> /*?*/ eventSub;
+    VmService? client;
+    StreamSubscription<Event>? eventSub;
     var channel = IsolateChannel.connectReceive(receivePort)
         .transformStream(StreamTransformer.fromHandlers(handleDone: (sink) {
       isolate.kill();
@@ -66,25 +64,25 @@
       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()));
       var isolateNumber = int.parse(isolateID.split('/').last);
       isolateRef = (await client.getVM())
-          .isolates
+          .isolates!
           .firstWhere((isolate) => isolate.number == isolateNumber.toString());
-      await client.setName(isolateRef.id, path);
-      var libraryRef = (await client.getIsolate(isolateRef.id))
-          .libraries
+      await client.setName(isolateRef.id!, path);
+      var libraryRef = (await client.getIsolate(isolateRef.id!))
+          .libraries!
           .firstWhere((library) => library.uri == libraryPath);
       var url = _observatoryUrlFor(
-          info.serverUri.toString(), isolateRef.id, libraryRef.id);
+          info.serverUri.toString(), isolateRef.id!, libraryRef.id!);
       environment = VMEnvironment(url, isolateRef, client);
     }
 
@@ -92,10 +90,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);
@@ -120,7 +118,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);
     }
@@ -157,10 +155,10 @@
 }
 
 Future<Map<String, dynamic>> _gatherCoverage(Environment environment) async {
-  final isolateId = Uri.parse(environment.observatoryUrl.fragment)
+  final isolateId = Uri.parse(environment.observatoryUrl!.fragment)
       .queryParameters['isolateId'];
-  return await collect(environment.observatoryUrl, false, false, false, {},
-      isolateIds: {isolateId});
+  return await collect(environment.observatoryUrl!, false, false, false, {},
+      isolateIds: {isolateId!});
 }
 
 Future<Isolate> _spawnPubServeIsolate(
diff --git a/pkgs/test_core/lib/src/util/dart.dart b/pkgs/test_core/lib/src/util/dart.dart
index fd8aeed..e6c3753 100644
--- a/pkgs/test_core/lib/src/util/dart.dart
+++ b/pkgs/test_core/lib/src/util/dart.dart
@@ -1,8 +1,6 @@
 // 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';
@@ -10,6 +8,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:source_span/source_span.dart';
 
+import '../util/package_config.dart';
 import 'string_literal_iterator.dart';
 
 /// Runs [code] in an isolate.
@@ -19,12 +18,12 @@
 /// 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),
         [],
         message,
-        packageConfig: await Isolate.packageConfig,
+        packageConfig: await packageConfigUri,
         checked: true,
         onExit: onExit);
 
@@ -53,7 +52,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/pkgs/test_core/lib/src/util/package_config.dart b/pkgs/test_core/lib/src/util/package_config.dart
index b3743f8..d6067f3 100644
--- a/pkgs/test_core/lib/src/util/package_config.dart
+++ b/pkgs/test_core/lib/src/util/package_config.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -10,5 +8,13 @@
 
 /// The [PackageConfig] parsed from the current isolates package config file.
 final Future<PackageConfig> currentPackageConfig = () async {
-  return loadPackageConfigUri(await Isolate.packageConfig);
+  return loadPackageConfigUri(await packageConfigUri);
+}();
+
+final Future<Uri> packageConfigUri = () async {
+  var uri = await Isolate.packageConfig;
+  if (uri == null) {
+    throw StateError('Unable to find a package config');
+  }
+  return uri;
 }();
diff --git a/pkgs/test_core/lib/src/util/string_literal_iterator.dart b/pkgs/test_core/lib/src/util/string_literal_iterator.dart
index 5058028..2a8b118 100644
--- a/pkgs/test_core/lib/src/util/string_literal_iterator.dart
+++ b/pkgs/test_core/lib/src/util/string_literal_iterator.dart
@@ -1,8 +1,6 @@
 // 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';
 
@@ -40,8 +38,8 @@
 /// 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.
@@ -49,14 +47,14 @@
   /// Before iteration begins, this points to the character before the first
   /// rune.
   int get offset => _offset;
-  int /*?*/ _offset;
+  late 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.
   ///
@@ -68,13 +66,16 @@
   /// 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;
+
+  /// The result of the last call to `_runes.moveNext`.
+  bool _runesHasCurrent = false;
 
   /// Creates a new [StringLiteralIterator] iterating over the contents of
   /// [literal].
@@ -103,10 +104,10 @@
   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 || !_runesHasCurrent) {
       if (_strings.isEmpty) {
         // Move the offset past the end of the text.
-        _offset = _nextOffset;
+        _offset = _nextOffset!;
         _current = null;
         return false;
       }
@@ -124,10 +125,10 @@
       _nextOffset = string.contentsOffset;
       _isRaw = string.isRaw;
       _runes = text.runes.iterator;
-      _runes.moveNext();
+      _runesHasCurrent = _runes!.moveNext();
     }
 
-    _offset = _nextOffset;
+    _offset = _nextOffset!;
     _current = _nextRune();
     if (_current != null) return true;
 
@@ -137,9 +138,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;
     }
@@ -152,8 +153,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;
@@ -177,15 +178,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;
     }
@@ -196,15 +197,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;
     }
 
@@ -212,11 +213,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();
@@ -225,7 +226,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;
@@ -237,8 +238,8 @@
 
   /// Move [_runes] to the next rune and update [_nextOffset].
   bool _moveRunesNext() {
-    var result = _runes.moveNext();
-    _nextOffset = _nextOffset + 1;
+    var result = _runesHasCurrent = _runes!.moveNext();
+    _nextOffset = _nextOffset! + 1;
     return result;
   }
 }
diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml
index 11a5380..c76599a 100644
--- a/pkgs/test_core/pubspec.yaml
+++ b/pkgs/test_core/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test_core
-version: 0.3.15
+version: 0.3.17-dev
 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
 
@@ -7,16 +7,16 @@
   sdk: '>=2.12.0-0 <3.0.0'
 
 dependencies:
-  analyzer: '>=0.39.5 <2.0.0'
+  analyzer: ^1.0.0
   async: ^2.5.0
-  args: '>=1.4.0 <3.0.0'
+  args: ^2.0.0
   boolean_selector: ^2.1.0
   collection: ^1.15.0
-  coverage: '>=0.13.3 <2.0.0'
-  glob: '>=1.0.0 <3.0.0'
-  io: '>=0.3.0 <2.0.0'
+  coverage: ^1.0.0
+  glob: ^2.0.0
+  io: ^1.0.0
   meta: ^1.3.0
-  package_config: '>=1.9.2 <3.0.0'
+  package_config: ^2.0.0
   path: ^1.8.0
   pedantic: ^1.10.0
   pool: ^1.5.0
@@ -25,12 +25,12 @@
   source_span: ^1.8.0
   stack_trace: ^1.10.0
   stream_channel: ^2.1.0
-  vm_service: '>=1.0.0 <7.0.0'
-  yaml: '>=2.0.0 <4.0.0'
+  vm_service: ^6.0.0
+  yaml: ^3.0.0
   # 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
+  test_api: 0.2.20
 
 dependency_overrides:
   test_api: